Add bytecode support for delegated var decls

This commit is contained in:
sergeych committed 2026-02-08 21:47:36 +03:00
1 parent 3391da595f
commit eb58720365
7 files changed
+99 -5

No files matched your search

@@ -99,7 +99,7 @@ class BytecodeCompiler(
is net.sergeych.lyng.InlineBlockStatement -> compileInlineBlock(name, stmt)
is VarDeclStatement -> compileVarDecl(name, stmt)
is DelegatedVarDeclStatement -> {
val value = emitStatementEval(stmt)
val value = emitDelegatedVarDecl(stmt) ?: return null
builder.emit(Opcode.RET, value.slot)
val localCount = maxOf(nextSlot, value.slot + 1) - scopeSlotCount
builder.build(
@@ -3281,7 +3281,7 @@ class BytecodeCompiler(
}
is BlockStatement -> emitBlock(target, true)
is VarDeclStatement -> emitVarDecl(target)
is DelegatedVarDeclStatement -> emitStatementEval(target)
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
is DestructuringVarDeclStatement -> emitStatementEval(target)
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target)
is net.sergeych.lyng.ClassDeclStatement -> emitStatementEval(target)
@@ -3308,7 +3308,7 @@ class BytecodeCompiler(
}
}
is VarDeclStatement -> emitVarDecl(target)
is DelegatedVarDeclStatement -> emitStatementEval(target)
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
is IfStatement -> compileIfStatement(target)
is net.sergeych.lyng.ForInStatement -> {
val resultSlot = emitForIn(target, false) ?: return null
@@ -3576,6 +3576,21 @@ class BytecodeCompiler(
return value
}
private fun emitDelegatedVarDecl(stmt: DelegatedVarDeclStatement): CompiledValue? {
val value = compileStatementValueOrFallback(stmt.initializer) ?: return null
val declId = builder.addConst(
BytecodeConst.DelegatedDecl(
stmt.name,
stmt.isMutable,
stmt.visibility,
stmt.isTransient
)
)
builder.emit(Opcode.DECL_DELEGATED, declId, value.slot)
updateSlotType(value.slot, SlotType.OBJ)
return CompiledValue(value.slot, SlotType.OBJ)
}
private fun updateNameObjClass(name: String, initializer: Statement?, initializerObjClass: ObjClass? = null) {
val cls = initializerObjClass ?: objClassForInitializer(initializer)
if (cls != null) {
@@ -46,6 +46,12 @@ sealed class BytecodeConst {
val visibility: Visibility,
val isTransient: Boolean,
) : BytecodeConst()
data class DelegatedDecl(
val name: String,
val isMutable: Boolean,
val visibility: Visibility,
val isTransient: Boolean,
) : BytecodeConst()
data class CallArgsPlan(val tailBlock: Boolean, val specs: List<CallArgSpec>) : BytecodeConst()
data class CallArgSpec(val name: String?, val isSplat: Boolean)
}
@@ -144,7 +144,7 @@ class CmdBuilder {
listOf(OperandKind.CONST, OperandKind.SLOT)
Opcode.PUSH_SCOPE, Opcode.PUSH_SLOT_PLAN ->
listOf(OperandKind.CONST)
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY ->
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED ->
listOf(OperandKind.CONST, OperandKind.SLOT)
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
@@ -377,6 +377,7 @@ class CmdBuilder {
Opcode.PUSH_SLOT_PLAN -> CmdPushSlotPlan(operands[0])
Opcode.POP_SLOT_PLAN -> CmdPopSlotPlan()
Opcode.DECL_LOCAL -> CmdDeclLocal(operands[0], operands[1])
Opcode.DECL_DELEGATED -> CmdDeclDelegated(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_MEMBER_SLOT -> CmdCallMemberSlot(operands[0], operands[1], operands[2], operands[3], operands[4])
@@ -185,6 +185,7 @@ object CmdDisassembler {
is CmdPushSlotPlan -> Opcode.PUSH_SLOT_PLAN to intArrayOf(cmd.planId)
is CmdPopSlotPlan -> Opcode.POP_SLOT_PLAN to intArrayOf()
is CmdDeclLocal -> Opcode.DECL_LOCAL to intArrayOf(cmd.constId, cmd.slot)
is CmdDeclDelegated -> Opcode.DECL_DELEGATED 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 CmdCallMemberSlot -> Opcode.CALL_MEMBER_SLOT to intArrayOf(cmd.recvSlot, cmd.methodId, cmd.argBase, cmd.argCount, cmd.dst)
@@ -240,7 +241,7 @@ object CmdDisassembler {
listOf(OperandKind.CONST, OperandKind.SLOT)
Opcode.PUSH_SCOPE, Opcode.PUSH_SLOT_PLAN ->
listOf(OperandKind.CONST)
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY ->
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED ->
listOf(OperandKind.CONST, OperandKind.SLOT)
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
@@ -1187,6 +1187,35 @@ class CmdDeclLocal(internal val constId: Int, internal val slot: Int) : Cmd() {
}
}
class CmdDeclDelegated(internal val constId: Int, internal val slot: Int) : Cmd() {
override suspend fun perform(frame: CmdFrame) {
val decl = frame.fn.constants[constId] as? BytecodeConst.DelegatedDecl
?: error("DECL_DELEGATED expects DelegatedDecl at $constId")
val initValue = frame.slotToObj(slot)
val accessType = ObjString(if (decl.isMutable) "Var" else "Val")
val finalDelegate = try {
initValue.invokeInstanceMethod(
frame.ensureScope(),
"bind",
Arguments(ObjString(decl.name), accessType, ObjNull)
)
} catch (_: Exception) {
initValue
}
val rec = frame.ensureScope().addItem(
decl.name,
decl.isMutable,
ObjNull,
decl.visibility,
recordType = ObjRecord.Type.Delegated,
isTransient = decl.isTransient
)
rec.delegate = finalDelegate
frame.storeObjResult(slot, finalDelegate)
return
}
}
class CmdDeclExtProperty(internal val constId: Int, internal val slot: Int) : Cmd() {
override suspend fun perform(frame: CmdFrame) {
val decl = frame.fn.constants[constId] as? BytecodeConst.ExtensionPropertyDecl
@@ -125,6 +125,7 @@ enum class Opcode(val code: Int) {
POP_SLOT_PLAN(0x88),
DECL_LOCAL(0x89),
DECL_EXT_PROPERTY(0x8A),
DECL_DELEGATED(0x8B),
CALL_DIRECT(0x90),
CALL_MEMBER_SLOT(0x92),