Step 25B: bytecode function declarations
This commit is contained in:
parent
4db0a7fbab
commit
b32a937636
@ -114,9 +114,11 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
|
|||||||
|
|
||||||
- [ ] Step 25: Replace Statement-based declaration calls in bytecode.
|
- [ ] Step 25: Replace Statement-based declaration calls in bytecode.
|
||||||
- [x] Add bytecode const/op for enum declarations (no `Statement` objects in constants).
|
- [x] Add bytecode const/op for enum declarations (no `Statement` objects in constants).
|
||||||
- [ ] Add bytecode const/op for class/function declarations (no `Statement` objects in constants).
|
- [ ] Add bytecode const/op for class declarations (no `Statement` objects in constants).
|
||||||
|
- [x] Add bytecode const/op for function declarations (no `Statement` objects in constants).
|
||||||
- [x] Replace `emitStatementCall` usage for `EnumDeclStatement`.
|
- [x] Replace `emitStatementCall` usage for `EnumDeclStatement`.
|
||||||
- [ ] Replace `emitStatementCall` usage for `ClassDeclStatement` and `FunctionDeclStatement`.
|
- [ ] Replace `emitStatementCall` usage for `ClassDeclStatement`.
|
||||||
|
- [x] Replace `emitStatementCall` usage for `FunctionDeclStatement`.
|
||||||
- [ ] Add JVM disasm coverage to ensure module init has no `CALL_SLOT` to `Callable@...` for declarations.
|
- [ ] Add JVM disasm coverage to ensure module init has no `CALL_SLOT` to `Callable@...` for declarations.
|
||||||
- [ ] Step 26: Bytecode-backed lambdas (remove `ValueFnRef` runtime execution).
|
- [ ] Step 26: Bytecode-backed lambdas (remove `ValueFnRef` runtime execution).
|
||||||
- [ ] Compile lambda bodies to bytecode and emit an opcode to create a callable from bytecode + capture plan.
|
- [ ] Compile lambda bodies to bytecode and emit an opcode to create a callable from bytecode + capture plan.
|
||||||
|
|||||||
@ -7000,8 +7000,7 @@ class Compiler(
|
|||||||
// Capture and pop the local declarations count for this function
|
// Capture and pop the local declarations count for this function
|
||||||
val fnLocalDecls = localDeclCountStack.removeLastOrNull() ?: 0
|
val fnLocalDecls = localDeclCountStack.removeLastOrNull() ?: 0
|
||||||
|
|
||||||
var closure: Scope? = null
|
val closureBox = FunctionClosureBox()
|
||||||
var captureContext: Scope? = null
|
|
||||||
|
|
||||||
val paramSlotPlanSnapshot = slotPlanIndices(paramSlotPlan)
|
val paramSlotPlanSnapshot = slotPlanIndices(paramSlotPlan)
|
||||||
val captureSlots = capturePlan.captures.toList()
|
val captureSlots = capturePlan.captures.toList()
|
||||||
@ -7014,14 +7013,14 @@ class Compiler(
|
|||||||
// restore closure where the function was defined, and making a copy of it
|
// restore closure where the function was defined, and making a copy of it
|
||||||
// for local space. If there is no closure, we are in, say, class context where
|
// for local space. If there is no closure, we are in, say, class context where
|
||||||
// the closure is in the class initialization and we needn't more:
|
// the closure is in the class initialization and we needn't more:
|
||||||
val context = closure?.let { ClosureScope(callerContext, it) }
|
val context = closureBox.closure?.let { ClosureScope(callerContext, it) }
|
||||||
?: callerContext
|
?: callerContext
|
||||||
|
|
||||||
// Capacity hint: parameters + declared locals + small overhead
|
// Capacity hint: parameters + declared locals + small overhead
|
||||||
val capacityHint = paramNames.size + fnLocalDecls + 4
|
val capacityHint = paramNames.size + fnLocalDecls + 4
|
||||||
context.hintLocalCapacity(capacityHint)
|
context.hintLocalCapacity(capacityHint)
|
||||||
if (paramSlotPlanSnapshot.isNotEmpty()) context.applySlotPlan(paramSlotPlanSnapshot)
|
if (paramSlotPlanSnapshot.isNotEmpty()) context.applySlotPlan(paramSlotPlanSnapshot)
|
||||||
val captureBase = captureContext ?: closure
|
val captureBase = closureBox.captureContext ?: closureBox.closure
|
||||||
if (captureBase != null && captureSlots.isNotEmpty()) {
|
if (captureBase != null && captureSlots.isNotEmpty()) {
|
||||||
for (capture in captureSlots) {
|
for (capture in captureSlots) {
|
||||||
// Interpreter-only capture resolution; bytecode functions do not use resolveCaptureRecord.
|
// Interpreter-only capture resolution; bytecode functions do not use resolveCaptureRecord.
|
||||||
@ -7047,172 +7046,29 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
cc.labels.remove(name)
|
cc.labels.remove(name)
|
||||||
outerLabel?.let { cc.labels.remove(it) }
|
outerLabel?.let { cc.labels.remove(it) }
|
||||||
// parentContext
|
val spec = FunctionDeclSpec(
|
||||||
val fnCreateStatement = object : Statement() {
|
name = name,
|
||||||
override val pos: Pos = start
|
|
||||||
override suspend fun execute(context: Scope): Obj {
|
|
||||||
if (actualExtern && extTypeName == null && parentContext !is CodeContext.ClassBody) {
|
|
||||||
val existing = context.get(name)
|
|
||||||
if (existing != null) {
|
|
||||||
context.addItem(
|
|
||||||
name,
|
|
||||||
false,
|
|
||||||
existing.value,
|
|
||||||
visibility,
|
|
||||||
callSignature = existing.callSignature
|
|
||||||
)
|
|
||||||
return existing.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isDelegated) {
|
|
||||||
val accessType = ObjString("Callable")
|
|
||||||
val initValue = delegateExpression!!.execute(context)
|
|
||||||
val finalDelegate = try {
|
|
||||||
initValue.invokeInstanceMethod(context, "bind", Arguments(ObjString(name), accessType, context.thisObj))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
initValue
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extTypeName != null) {
|
|
||||||
val type = context[extTypeName]?.value ?: context.raiseSymbolNotFound("class $extTypeName not found")
|
|
||||||
if (type !is ObjClass) context.raiseClassCastError("$extTypeName is not the class instance")
|
|
||||||
context.addExtension(type, name, ObjRecord(ObjUnset, isMutable = false, visibility = visibility, declaringClass = null, type = ObjRecord.Type.Delegated).apply {
|
|
||||||
delegate = finalDelegate
|
|
||||||
})
|
|
||||||
return ObjVoid
|
|
||||||
}
|
|
||||||
|
|
||||||
val th = context.thisObj
|
|
||||||
if (isStatic) {
|
|
||||||
(th as ObjClass).createClassField(name, ObjUnset, false, visibility, null, start, isTransient = isTransient, type = ObjRecord.Type.Delegated).apply {
|
|
||||||
delegate = finalDelegate
|
|
||||||
}
|
|
||||||
context.addItem(name, false, ObjUnset, visibility, recordType = ObjRecord.Type.Delegated, isTransient = isTransient).apply {
|
|
||||||
delegate = finalDelegate
|
|
||||||
}
|
|
||||||
} else if (th is ObjClass) {
|
|
||||||
val cls: ObjClass = th
|
|
||||||
val storageName = "${cls.className}::$name"
|
|
||||||
cls.createField(
|
|
||||||
name,
|
|
||||||
ObjUnset,
|
|
||||||
false,
|
|
||||||
visibility,
|
|
||||||
null,
|
|
||||||
start,
|
|
||||||
declaringClass = cls,
|
|
||||||
isAbstract = isAbstract,
|
|
||||||
isClosed = isClosed,
|
|
||||||
isOverride = isOverride,
|
|
||||||
isTransient = isTransient,
|
|
||||||
type = ObjRecord.Type.Delegated,
|
|
||||||
methodId = memberMethodId
|
|
||||||
)
|
|
||||||
cls.instanceInitializers += object : Statement() {
|
|
||||||
override val pos: Pos = start
|
|
||||||
override suspend fun execute(scp: Scope): Obj {
|
|
||||||
val accessType2 = ObjString("Callable")
|
|
||||||
val initValue2 = delegateExpression.execute(scp)
|
|
||||||
val finalDelegate2 = try {
|
|
||||||
initValue2.invokeInstanceMethod(scp, "bind", Arguments(ObjString(name), accessType2, scp.thisObj))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
initValue2
|
|
||||||
}
|
|
||||||
scp.addItem(storageName, false, ObjUnset, visibility, null, recordType = ObjRecord.Type.Delegated, isAbstract = isAbstract, isClosed = isClosed, isOverride = isOverride, isTransient = isTransient).apply {
|
|
||||||
delegate = finalDelegate2
|
|
||||||
}
|
|
||||||
return ObjVoid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
context.addItem(name, false, ObjUnset, visibility, recordType = ObjRecord.Type.Delegated, isTransient = isTransient).apply {
|
|
||||||
delegate = finalDelegate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ObjVoid
|
|
||||||
}
|
|
||||||
|
|
||||||
// we added fn in the context. now we must save closure
|
|
||||||
// for the function, unless we're in the class scope:
|
|
||||||
if (isStatic || parentContext !is CodeContext.ClassBody)
|
|
||||||
closure = context
|
|
||||||
if (parentContext is CodeContext.ClassBody && captureSlots.isNotEmpty())
|
|
||||||
captureContext = context
|
|
||||||
|
|
||||||
val annotatedFnBody = annotation?.invoke(context, ObjString(name), fnBody)
|
|
||||||
?: fnBody
|
|
||||||
val compiledFnBody = annotatedFnBody
|
|
||||||
|
|
||||||
extTypeName?.let { typeName ->
|
|
||||||
// class extension method
|
|
||||||
val type = context[typeName]?.value ?: context.raiseSymbolNotFound("class $typeName not found")
|
|
||||||
if (type !is ObjClass) context.raiseClassCastError("$typeName is not the class instance")
|
|
||||||
val stmt = object : Statement() {
|
|
||||||
override val pos: Pos = start
|
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
|
||||||
// ObjInstance has a fixed instance scope, so we need to build a closure
|
|
||||||
val result = (scope.thisObj as? ObjInstance)?.let { i ->
|
|
||||||
compiledFnBody.execute(ClosureScope(scope, i.instanceScope))
|
|
||||||
}
|
|
||||||
// other classes can create one-time scope for this rare case:
|
|
||||||
?: compiledFnBody.execute(scope.thisObj.autoInstanceScope(scope))
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
context.addExtension(type, name, ObjRecord(stmt, isMutable = false, visibility = visibility, declaringClass = null))
|
|
||||||
val wrapperName = extensionWrapperName ?: extensionCallableName(typeName, name)
|
|
||||||
val wrapper = ObjExtensionMethodCallable(name, stmt)
|
|
||||||
context.addItem(wrapperName, false, wrapper, visibility, recordType = ObjRecord.Type.Fun)
|
|
||||||
}
|
|
||||||
// regular function/method
|
|
||||||
?: run {
|
|
||||||
val th = context.thisObj
|
|
||||||
if (!isStatic && th is ObjClass) {
|
|
||||||
// Instance method declared inside a class body: register on the class
|
|
||||||
val cls: ObjClass = th
|
|
||||||
cls.addFn(
|
|
||||||
name,
|
|
||||||
isMutable = true,
|
|
||||||
visibility = visibility,
|
visibility = visibility,
|
||||||
isAbstract = isAbstract,
|
isAbstract = isAbstract,
|
||||||
isClosed = isClosed,
|
isClosed = isClosed,
|
||||||
isOverride = isOverride,
|
isOverride = isOverride,
|
||||||
pos = start,
|
isStatic = isStatic,
|
||||||
methodId = memberMethodId
|
isTransient = isTransient,
|
||||||
) {
|
isDelegated = isDelegated,
|
||||||
// Execute with the instance as receiver; set caller lexical class for visibility
|
delegateExpression = delegateExpression,
|
||||||
val savedCtx = this.currentClassCtx
|
extTypeName = extTypeName,
|
||||||
this.currentClassCtx = cls
|
extensionWrapperName = extensionWrapperName,
|
||||||
try {
|
memberMethodId = memberMethodId,
|
||||||
(thisObj as? ObjInstance)?.let { i ->
|
actualExtern = actualExtern,
|
||||||
val execScope = i.instanceScope.createChildScope(
|
parentIsClassBody = parentContext is CodeContext.ClassBody,
|
||||||
pos = this.pos,
|
externCallSignature = externCallSignature,
|
||||||
args = this.args,
|
annotation = annotation,
|
||||||
newThisObj = i
|
fnBody = fnBody,
|
||||||
|
closureBox = closureBox,
|
||||||
|
captureSlots = captureSlots,
|
||||||
|
startPos = start
|
||||||
)
|
)
|
||||||
execScope.currentClassCtx = cls
|
val declaredFn = FunctionDeclStatement(spec)
|
||||||
compiledFnBody.execute(execScope)
|
|
||||||
} ?: run {
|
|
||||||
compiledFnBody.execute(thisObj.autoInstanceScope(this))
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
this.currentClassCtx = savedCtx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// also expose the symbol in the class scope for possible references
|
|
||||||
context.addItem(name, false, compiledFnBody, visibility, callSignature = externCallSignature)
|
|
||||||
compiledFnBody
|
|
||||||
} else {
|
|
||||||
// top-level or nested function
|
|
||||||
context.addItem(name, false, compiledFnBody, visibility, callSignature = externCallSignature)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// as the function can be called from anywhere, we have
|
|
||||||
// saved the proper context in the closure
|
|
||||||
return annotatedFnBody
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val declaredFn = FunctionDeclStatement(StatementDeclExecutable(fnCreateStatement), start)
|
|
||||||
if (isStatic) {
|
if (isStatic) {
|
||||||
currentInitScope += declaredFn
|
currentInitScope += declaredFn
|
||||||
NopStatement
|
NopStatement
|
||||||
|
|||||||
@ -17,19 +17,240 @@
|
|||||||
package net.sergeych.lyng
|
package net.sergeych.lyng
|
||||||
|
|
||||||
import net.sergeych.lyng.obj.Obj
|
import net.sergeych.lyng.obj.Obj
|
||||||
|
import net.sergeych.lyng.obj.ObjClass
|
||||||
|
import net.sergeych.lyng.obj.ObjExtensionMethodCallable
|
||||||
|
import net.sergeych.lyng.obj.ObjInstance
|
||||||
|
import net.sergeych.lyng.obj.ObjRecord
|
||||||
|
import net.sergeych.lyng.obj.ObjString
|
||||||
|
import net.sergeych.lyng.obj.ObjUnset
|
||||||
|
import net.sergeych.lyng.obj.ObjVoid
|
||||||
|
|
||||||
|
class FunctionClosureBox(
|
||||||
|
var closure: Scope? = null,
|
||||||
|
var captureContext: Scope? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class FunctionDeclSpec(
|
||||||
|
val name: String,
|
||||||
|
val visibility: Visibility,
|
||||||
|
val isAbstract: Boolean,
|
||||||
|
val isClosed: Boolean,
|
||||||
|
val isOverride: Boolean,
|
||||||
|
val isStatic: Boolean,
|
||||||
|
val isTransient: Boolean,
|
||||||
|
val isDelegated: Boolean,
|
||||||
|
val delegateExpression: Statement?,
|
||||||
|
val extTypeName: String?,
|
||||||
|
val extensionWrapperName: String?,
|
||||||
|
val memberMethodId: Int?,
|
||||||
|
val actualExtern: Boolean,
|
||||||
|
val parentIsClassBody: Boolean,
|
||||||
|
val externCallSignature: CallSignature?,
|
||||||
|
val annotation: (suspend (Scope, ObjString, Statement) -> Statement)?,
|
||||||
|
val fnBody: Statement,
|
||||||
|
val closureBox: FunctionClosureBox,
|
||||||
|
val captureSlots: List<CaptureSlot>,
|
||||||
|
val startPos: Pos,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal suspend fun executeFunctionDecl(scope: Scope, spec: FunctionDeclSpec): Obj {
|
||||||
|
if (spec.actualExtern && spec.extTypeName == null && !spec.parentIsClassBody) {
|
||||||
|
val existing = scope.get(spec.name)
|
||||||
|
if (existing != null) {
|
||||||
|
scope.addItem(
|
||||||
|
spec.name,
|
||||||
|
false,
|
||||||
|
existing.value,
|
||||||
|
spec.visibility,
|
||||||
|
callSignature = existing.callSignature
|
||||||
|
)
|
||||||
|
return existing.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spec.isDelegated) {
|
||||||
|
val delegateExpr = spec.delegateExpression ?: scope.raiseError("delegated function missing delegate")
|
||||||
|
val accessType = ObjString("Callable")
|
||||||
|
val initValue = delegateExpr.execute(scope)
|
||||||
|
val finalDelegate = try {
|
||||||
|
initValue.invokeInstanceMethod(scope, "bind", Arguments(ObjString(spec.name), accessType, scope.thisObj))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
initValue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spec.extTypeName != null) {
|
||||||
|
val type = scope[spec.extTypeName]?.value ?: scope.raiseSymbolNotFound("class ${spec.extTypeName} not found")
|
||||||
|
if (type !is ObjClass) scope.raiseClassCastError("${spec.extTypeName} is not the class instance")
|
||||||
|
scope.addExtension(
|
||||||
|
type,
|
||||||
|
spec.name,
|
||||||
|
ObjRecord(ObjUnset, isMutable = false, visibility = spec.visibility, declaringClass = null, type = ObjRecord.Type.Delegated).apply {
|
||||||
|
delegate = finalDelegate
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return ObjVoid
|
||||||
|
}
|
||||||
|
|
||||||
|
val th = scope.thisObj
|
||||||
|
if (spec.isStatic) {
|
||||||
|
(th as ObjClass).createClassField(
|
||||||
|
spec.name,
|
||||||
|
ObjUnset,
|
||||||
|
false,
|
||||||
|
spec.visibility,
|
||||||
|
null,
|
||||||
|
spec.startPos,
|
||||||
|
isTransient = spec.isTransient,
|
||||||
|
type = ObjRecord.Type.Delegated
|
||||||
|
).apply {
|
||||||
|
delegate = finalDelegate
|
||||||
|
}
|
||||||
|
scope.addItem(
|
||||||
|
spec.name,
|
||||||
|
false,
|
||||||
|
ObjUnset,
|
||||||
|
spec.visibility,
|
||||||
|
recordType = ObjRecord.Type.Delegated,
|
||||||
|
isTransient = spec.isTransient
|
||||||
|
).apply {
|
||||||
|
delegate = finalDelegate
|
||||||
|
}
|
||||||
|
} else if (th is ObjClass) {
|
||||||
|
val cls: ObjClass = th
|
||||||
|
val storageName = "${cls.className}::${spec.name}"
|
||||||
|
cls.createField(
|
||||||
|
spec.name,
|
||||||
|
ObjUnset,
|
||||||
|
false,
|
||||||
|
spec.visibility,
|
||||||
|
null,
|
||||||
|
spec.startPos,
|
||||||
|
declaringClass = cls,
|
||||||
|
isAbstract = spec.isAbstract,
|
||||||
|
isClosed = spec.isClosed,
|
||||||
|
isOverride = spec.isOverride,
|
||||||
|
isTransient = spec.isTransient,
|
||||||
|
type = ObjRecord.Type.Delegated,
|
||||||
|
methodId = spec.memberMethodId
|
||||||
|
)
|
||||||
|
cls.instanceInitializers += object : Statement() {
|
||||||
|
override val pos: Pos = spec.startPos
|
||||||
|
override suspend fun execute(scp: Scope): Obj {
|
||||||
|
val accessType2 = ObjString("Callable")
|
||||||
|
val initValue2 = delegateExpr.execute(scp)
|
||||||
|
val finalDelegate2 = try {
|
||||||
|
initValue2.invokeInstanceMethod(scp, "bind", Arguments(ObjString(spec.name), accessType2, scp.thisObj))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
initValue2
|
||||||
|
}
|
||||||
|
scp.addItem(
|
||||||
|
storageName,
|
||||||
|
false,
|
||||||
|
ObjUnset,
|
||||||
|
spec.visibility,
|
||||||
|
null,
|
||||||
|
recordType = ObjRecord.Type.Delegated,
|
||||||
|
isAbstract = spec.isAbstract,
|
||||||
|
isClosed = spec.isClosed,
|
||||||
|
isOverride = spec.isOverride,
|
||||||
|
isTransient = spec.isTransient
|
||||||
|
).apply {
|
||||||
|
delegate = finalDelegate2
|
||||||
|
}
|
||||||
|
return ObjVoid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scope.addItem(
|
||||||
|
spec.name,
|
||||||
|
false,
|
||||||
|
ObjUnset,
|
||||||
|
spec.visibility,
|
||||||
|
recordType = ObjRecord.Type.Delegated,
|
||||||
|
isTransient = spec.isTransient
|
||||||
|
).apply {
|
||||||
|
delegate = finalDelegate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ObjVoid
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spec.isStatic || !spec.parentIsClassBody) {
|
||||||
|
spec.closureBox.closure = scope
|
||||||
|
}
|
||||||
|
if (spec.parentIsClassBody && spec.captureSlots.isNotEmpty()) {
|
||||||
|
spec.closureBox.captureContext = scope
|
||||||
|
}
|
||||||
|
|
||||||
|
val annotatedFnBody = spec.annotation?.invoke(scope, ObjString(spec.name), spec.fnBody) ?: spec.fnBody
|
||||||
|
val compiledFnBody = annotatedFnBody
|
||||||
|
|
||||||
|
spec.extTypeName?.let { typeName ->
|
||||||
|
val type = scope[typeName]?.value ?: scope.raiseSymbolNotFound("class $typeName not found")
|
||||||
|
if (type !is ObjClass) scope.raiseClassCastError("$typeName is not the class instance")
|
||||||
|
val stmt = object : Statement() {
|
||||||
|
override val pos: Pos = spec.startPos
|
||||||
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
|
val result = (scope.thisObj as? ObjInstance)?.let { i ->
|
||||||
|
compiledFnBody.execute(ClosureScope(scope, i.instanceScope))
|
||||||
|
} ?: compiledFnBody.execute(scope.thisObj.autoInstanceScope(scope))
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scope.addExtension(type, spec.name, ObjRecord(stmt, isMutable = false, visibility = spec.visibility, declaringClass = null))
|
||||||
|
val wrapperName = spec.extensionWrapperName ?: extensionCallableName(typeName, spec.name)
|
||||||
|
val wrapper = ObjExtensionMethodCallable(spec.name, stmt)
|
||||||
|
scope.addItem(wrapperName, false, wrapper, spec.visibility, recordType = ObjRecord.Type.Fun)
|
||||||
|
} ?: run {
|
||||||
|
val th = scope.thisObj
|
||||||
|
if (!spec.isStatic && th is ObjClass) {
|
||||||
|
val cls: ObjClass = th
|
||||||
|
cls.addFn(
|
||||||
|
spec.name,
|
||||||
|
isMutable = true,
|
||||||
|
visibility = spec.visibility,
|
||||||
|
isAbstract = spec.isAbstract,
|
||||||
|
isClosed = spec.isClosed,
|
||||||
|
isOverride = spec.isOverride,
|
||||||
|
pos = spec.startPos,
|
||||||
|
methodId = spec.memberMethodId
|
||||||
|
) {
|
||||||
|
val savedCtx = this.currentClassCtx
|
||||||
|
this.currentClassCtx = cls
|
||||||
|
try {
|
||||||
|
(thisObj as? ObjInstance)?.let { i ->
|
||||||
|
val execScope = i.instanceScope.createChildScope(
|
||||||
|
pos = this.pos,
|
||||||
|
args = this.args,
|
||||||
|
newThisObj = i
|
||||||
|
)
|
||||||
|
execScope.currentClassCtx = cls
|
||||||
|
compiledFnBody.execute(execScope)
|
||||||
|
} ?: compiledFnBody.execute(thisObj.autoInstanceScope(this))
|
||||||
|
} finally {
|
||||||
|
this.currentClassCtx = savedCtx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scope.addItem(spec.name, false, compiledFnBody, spec.visibility, callSignature = spec.externCallSignature)
|
||||||
|
compiledFnBody
|
||||||
|
} else {
|
||||||
|
scope.addItem(spec.name, false, compiledFnBody, spec.visibility, callSignature = spec.externCallSignature)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return annotatedFnBody
|
||||||
|
}
|
||||||
|
|
||||||
class FunctionDeclStatement(
|
class FunctionDeclStatement(
|
||||||
val executable: DeclExecutable,
|
val spec: FunctionDeclSpec,
|
||||||
private val startPos: Pos,
|
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override val pos: Pos = startPos
|
override val pos: Pos = spec.startPos
|
||||||
|
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return executable.execute(scope)
|
return executeFunctionDecl(scope, spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun callOn(scope: Scope): Obj {
|
override suspend fun callOn(scope: Scope): Obj {
|
||||||
val target = scope.parent ?: scope
|
val target = scope.parent ?: scope
|
||||||
return executable.execute(target)
|
return executeFunctionDecl(target, spec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -178,7 +178,7 @@ class BytecodeCompiler(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
is net.sergeych.lyng.FunctionDeclStatement -> {
|
is net.sergeych.lyng.FunctionDeclStatement -> {
|
||||||
val value = emitStatementCall(stmt)
|
val value = emitDeclFunction(stmt)
|
||||||
builder.emit(Opcode.RET, value.slot)
|
builder.emit(Opcode.RET, value.slot)
|
||||||
val localCount = maxOf(nextSlot, value.slot + 1) - scopeSlotCount
|
val localCount = maxOf(nextSlot, value.slot + 1) - scopeSlotCount
|
||||||
builder.build(
|
builder.build(
|
||||||
@ -4109,7 +4109,6 @@ class BytecodeCompiler(
|
|||||||
private fun emitDeclExec(stmt: Statement): CompiledValue {
|
private fun emitDeclExec(stmt: Statement): CompiledValue {
|
||||||
val executable = when (stmt) {
|
val executable = when (stmt) {
|
||||||
is net.sergeych.lyng.ClassDeclStatement -> stmt.executable
|
is net.sergeych.lyng.ClassDeclStatement -> stmt.executable
|
||||||
is net.sergeych.lyng.FunctionDeclStatement -> stmt.executable
|
|
||||||
else -> throw BytecodeCompileException(
|
else -> throw BytecodeCompileException(
|
||||||
"Bytecode compile error: unsupported declaration ${stmt::class.simpleName}",
|
"Bytecode compile error: unsupported declaration ${stmt::class.simpleName}",
|
||||||
stmt.pos
|
stmt.pos
|
||||||
@ -4137,6 +4136,14 @@ class BytecodeCompiler(
|
|||||||
return CompiledValue(dst, SlotType.OBJ)
|
return CompiledValue(dst, SlotType.OBJ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun emitDeclFunction(stmt: net.sergeych.lyng.FunctionDeclStatement): CompiledValue {
|
||||||
|
val constId = builder.addConst(BytecodeConst.FunctionDecl(stmt.spec))
|
||||||
|
val dst = allocSlot()
|
||||||
|
builder.emit(Opcode.DECL_FUNCTION, constId, dst)
|
||||||
|
updateSlotType(dst, SlotType.OBJ)
|
||||||
|
return CompiledValue(dst, SlotType.OBJ)
|
||||||
|
}
|
||||||
|
|
||||||
private fun compileStatementValueOrFallback(stmt: Statement, needResult: Boolean = true): CompiledValue? {
|
private fun compileStatementValueOrFallback(stmt: Statement, needResult: Boolean = true): CompiledValue? {
|
||||||
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
||||||
setPos(target.pos)
|
setPos(target.pos)
|
||||||
@ -4171,7 +4178,7 @@ class BytecodeCompiler(
|
|||||||
is DestructuringVarDeclStatement -> emitDestructuringVarDecl(target)
|
is DestructuringVarDeclStatement -> emitDestructuringVarDecl(target)
|
||||||
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target)
|
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target)
|
||||||
is net.sergeych.lyng.ClassDeclStatement -> emitDeclExec(target)
|
is net.sergeych.lyng.ClassDeclStatement -> emitDeclExec(target)
|
||||||
is net.sergeych.lyng.FunctionDeclStatement -> emitDeclExec(target)
|
is net.sergeych.lyng.FunctionDeclStatement -> emitDeclFunction(target)
|
||||||
is net.sergeych.lyng.EnumDeclStatement -> emitDeclEnum(target)
|
is net.sergeych.lyng.EnumDeclStatement -> emitDeclEnum(target)
|
||||||
is net.sergeych.lyng.TryStatement -> emitTry(target, true)
|
is net.sergeych.lyng.TryStatement -> emitTry(target, true)
|
||||||
is net.sergeych.lyng.WhenStatement -> compileWhen(target, true)
|
is net.sergeych.lyng.WhenStatement -> compileWhen(target, true)
|
||||||
@ -4204,7 +4211,7 @@ class BytecodeCompiler(
|
|||||||
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
|
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
|
||||||
is IfStatement -> compileIfStatement(target)
|
is IfStatement -> compileIfStatement(target)
|
||||||
is net.sergeych.lyng.ClassDeclStatement -> emitDeclExec(target)
|
is net.sergeych.lyng.ClassDeclStatement -> emitDeclExec(target)
|
||||||
is net.sergeych.lyng.FunctionDeclStatement -> emitDeclExec(target)
|
is net.sergeych.lyng.FunctionDeclStatement -> emitDeclFunction(target)
|
||||||
is net.sergeych.lyng.EnumDeclStatement -> emitDeclEnum(target)
|
is net.sergeych.lyng.EnumDeclStatement -> emitDeclEnum(target)
|
||||||
is net.sergeych.lyng.ForInStatement -> {
|
is net.sergeych.lyng.ForInStatement -> {
|
||||||
val resultSlot = emitForIn(target, false) ?: return null
|
val resultSlot = emitForIn(target, false) ?: return null
|
||||||
|
|||||||
@ -44,6 +44,9 @@ sealed class BytecodeConst {
|
|||||||
val entries: List<String>,
|
val entries: List<String>,
|
||||||
val lifted: Boolean,
|
val lifted: Boolean,
|
||||||
) : BytecodeConst()
|
) : BytecodeConst()
|
||||||
|
data class FunctionDecl(
|
||||||
|
val spec: net.sergeych.lyng.FunctionDeclSpec,
|
||||||
|
) : BytecodeConst()
|
||||||
data class SlotPlan(val plan: Map<String, Int>, val captures: List<String> = emptyList()) : BytecodeConst()
|
data class SlotPlan(val plan: Map<String, Int>, val captures: List<String> = emptyList()) : BytecodeConst()
|
||||||
data class CaptureTable(val entries: List<BytecodeCaptureEntry>) : BytecodeConst()
|
data class CaptureTable(val entries: List<BytecodeCaptureEntry>) : BytecodeConst()
|
||||||
data class ExtensionPropertyDecl(
|
data class ExtensionPropertyDecl(
|
||||||
|
|||||||
@ -157,7 +157,7 @@ class CmdBuilder {
|
|||||||
Opcode.PUSH_TRY ->
|
Opcode.PUSH_TRY ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
||||||
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE,
|
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE,
|
||||||
Opcode.DECL_EXEC, Opcode.DECL_ENUM,
|
Opcode.DECL_EXEC, Opcode.DECL_ENUM, Opcode.DECL_FUNCTION,
|
||||||
Opcode.ASSIGN_DESTRUCTURE ->
|
Opcode.ASSIGN_DESTRUCTURE ->
|
||||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
||||||
@ -412,6 +412,7 @@ class CmdBuilder {
|
|||||||
Opcode.DECL_DESTRUCTURE -> CmdDeclDestructure(operands[0], operands[1])
|
Opcode.DECL_DESTRUCTURE -> CmdDeclDestructure(operands[0], operands[1])
|
||||||
Opcode.DECL_EXEC -> CmdDeclExec(operands[0], operands[1])
|
Opcode.DECL_EXEC -> CmdDeclExec(operands[0], operands[1])
|
||||||
Opcode.DECL_ENUM -> CmdDeclEnum(operands[0], operands[1])
|
Opcode.DECL_ENUM -> CmdDeclEnum(operands[0], operands[1])
|
||||||
|
Opcode.DECL_FUNCTION -> CmdDeclFunction(operands[0], operands[1])
|
||||||
Opcode.DECL_EXT_PROPERTY -> CmdDeclExtProperty(operands[0], operands[1])
|
Opcode.DECL_EXT_PROPERTY -> CmdDeclExtProperty(operands[0], operands[1])
|
||||||
Opcode.CALL_DIRECT -> CmdCallDirect(operands[0], operands[1], operands[2], operands[3])
|
Opcode.CALL_DIRECT -> CmdCallDirect(operands[0], operands[1], operands[2], operands[3])
|
||||||
Opcode.ASSIGN_DESTRUCTURE -> CmdAssignDestructure(operands[0], operands[1])
|
Opcode.ASSIGN_DESTRUCTURE -> CmdAssignDestructure(operands[0], operands[1])
|
||||||
|
|||||||
@ -213,6 +213,7 @@ object CmdDisassembler {
|
|||||||
is CmdDeclDestructure -> Opcode.DECL_DESTRUCTURE to intArrayOf(cmd.constId, cmd.slot)
|
is CmdDeclDestructure -> Opcode.DECL_DESTRUCTURE to intArrayOf(cmd.constId, cmd.slot)
|
||||||
is CmdDeclExec -> Opcode.DECL_EXEC to intArrayOf(cmd.constId, cmd.slot)
|
is CmdDeclExec -> Opcode.DECL_EXEC to intArrayOf(cmd.constId, cmd.slot)
|
||||||
is CmdDeclEnum -> Opcode.DECL_ENUM to intArrayOf(cmd.constId, cmd.slot)
|
is CmdDeclEnum -> Opcode.DECL_ENUM to intArrayOf(cmd.constId, cmd.slot)
|
||||||
|
is CmdDeclFunction -> Opcode.DECL_FUNCTION to intArrayOf(cmd.constId, cmd.slot)
|
||||||
is CmdDeclExtProperty -> Opcode.DECL_EXT_PROPERTY to intArrayOf(cmd.constId, cmd.slot)
|
is CmdDeclExtProperty -> Opcode.DECL_EXT_PROPERTY to intArrayOf(cmd.constId, cmd.slot)
|
||||||
is CmdCallDirect -> Opcode.CALL_DIRECT to intArrayOf(cmd.id, cmd.argBase, cmd.argCount, cmd.dst)
|
is CmdCallDirect -> Opcode.CALL_DIRECT to intArrayOf(cmd.id, cmd.argBase, cmd.argCount, cmd.dst)
|
||||||
is CmdAssignDestructure -> Opcode.ASSIGN_DESTRUCTURE to intArrayOf(cmd.constId, cmd.slot)
|
is CmdAssignDestructure -> Opcode.ASSIGN_DESTRUCTURE to intArrayOf(cmd.constId, cmd.slot)
|
||||||
@ -284,7 +285,7 @@ object CmdDisassembler {
|
|||||||
Opcode.PUSH_TRY ->
|
Opcode.PUSH_TRY ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
||||||
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE,
|
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE,
|
||||||
Opcode.DECL_EXEC, Opcode.DECL_ENUM,
|
Opcode.DECL_EXEC, Opcode.DECL_ENUM, Opcode.DECL_FUNCTION,
|
||||||
Opcode.ASSIGN_DESTRUCTURE ->
|
Opcode.ASSIGN_DESTRUCTURE ->
|
||||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
||||||
|
|||||||
@ -1344,6 +1344,16 @@ class CmdDeclEnum(internal val constId: Int, internal val slot: Int) : Cmd() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CmdDeclFunction(internal val constId: Int, internal val slot: Int) : Cmd() {
|
||||||
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
|
val decl = frame.fn.constants[constId] as? BytecodeConst.FunctionDecl
|
||||||
|
?: error("DECL_FUNCTION expects FunctionDecl at $constId")
|
||||||
|
val result = executeFunctionDecl(frame.ensureScope(), decl.spec)
|
||||||
|
frame.storeObjResult(slot, result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class CmdDeclDestructure(internal val constId: Int, internal val slot: Int) : Cmd() {
|
class CmdDeclDestructure(internal val constId: Int, internal val slot: Int) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
val decl = frame.fn.constants[constId] as? BytecodeConst.DestructureDecl
|
val decl = frame.fn.constants[constId] as? BytecodeConst.DestructureDecl
|
||||||
|
|||||||
@ -166,6 +166,7 @@ enum class Opcode(val code: Int) {
|
|||||||
DELEGATED_GET_LOCAL(0xC2),
|
DELEGATED_GET_LOCAL(0xC2),
|
||||||
DELEGATED_SET_LOCAL(0xC3),
|
DELEGATED_SET_LOCAL(0xC3),
|
||||||
BIND_DELEGATE_LOCAL(0xC4),
|
BIND_DELEGATE_LOCAL(0xC4),
|
||||||
|
DECL_FUNCTION(0xC5),
|
||||||
;
|
;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user