From 938503fdd4b1b7ec97d21a4a439b1b23abf199bb Mon Sep 17 00:00:00 2001 From: sergeych Date: Wed, 28 Jan 2026 22:42:21 +0300 Subject: [PATCH] Add bytecode opcodes for implicit this member access --- .../lyng/bytecode/BytecodeCompiler.kt | 14 +++++++- .../net/sergeych/lyng/bytecode/CmdBuilder.kt | 6 ++++ .../sergeych/lyng/bytecode/CmdDisassembler.kt | 6 ++++ .../net/sergeych/lyng/bytecode/CmdRuntime.kt | 36 +++++++++++++++++++ .../net/sergeych/lyng/bytecode/Opcode.kt | 2 ++ 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt index f4cc1b1..a4adade 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt @@ -202,7 +202,13 @@ class BytecodeCompiler( is CallRef -> compileCall(ref) is MethodCallRef -> compileMethodCall(ref) is FieldRef -> compileFieldRef(ref) - is ImplicitThisMemberRef -> compileEvalRef(ref) + is ImplicitThisMemberRef -> { + val nameId = builder.addConst(BytecodeConst.StringVal(ref.name)) + val slot = allocSlot() + builder.emit(Opcode.GET_THIS_MEMBER, nameId, slot) + updateSlotType(slot, SlotType.OBJ) + CompiledValue(slot, SlotType.OBJ) + } is ImplicitThisMethodCallRef -> compileEvalRef(ref) is IndexRef -> compileIndexRef(ref) else -> null @@ -880,6 +886,12 @@ class BytecodeCompiler( } return value } + if (target is ImplicitThisMemberRef) { + val nameId = builder.addConst(BytecodeConst.StringVal(target.name)) + if (nameId > 0xFFFF) return null + builder.emit(Opcode.SET_THIS_MEMBER, nameId, value.slot) + return value + } if (target is IndexRef) { val receiver = compileRefWithFallback(target.targetRef, null, Pos.builtIn) ?: return null if (!target.optionalRef) { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdBuilder.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdBuilder.kt index da12b38..1f342dc 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdBuilder.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdBuilder.kt @@ -184,6 +184,10 @@ class CmdBuilder { listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT) Opcode.LIST_LITERAL -> listOf(OperandKind.CONST, OperandKind.SLOT, OperandKind.COUNT, OperandKind.SLOT) + Opcode.GET_THIS_MEMBER -> + listOf(OperandKind.ID, OperandKind.SLOT) + Opcode.SET_THIS_MEMBER -> + listOf(OperandKind.ID, OperandKind.SLOT) Opcode.EVAL_FALLBACK, Opcode.EVAL_REF, Opcode.EVAL_STMT, Opcode.EVAL_VALUE_FN -> listOf(OperandKind.ID, OperandKind.SLOT) } @@ -374,6 +378,8 @@ class CmdBuilder { Opcode.GET_INDEX -> CmdGetIndex(operands[0], operands[1], operands[2]) Opcode.SET_INDEX -> CmdSetIndex(operands[0], operands[1], operands[2]) Opcode.LIST_LITERAL -> CmdListLiteral(operands[0], operands[1], operands[2], operands[3]) + Opcode.GET_THIS_MEMBER -> CmdGetThisMember(operands[0], operands[1]) + Opcode.SET_THIS_MEMBER -> CmdSetThisMember(operands[0], operands[1]) Opcode.EVAL_FALLBACK -> CmdEvalFallback(operands[0], operands[1]) Opcode.EVAL_REF -> CmdEvalRef(operands[0], operands[1]) Opcode.EVAL_STMT -> CmdEvalStmt(operands[0], operands[1]) diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdDisassembler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdDisassembler.kt index 7c42bc1..5b5fc09 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdDisassembler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdDisassembler.kt @@ -184,6 +184,8 @@ object CmdDisassembler { is CmdGetIndex -> Opcode.GET_INDEX to intArrayOf(cmd.targetSlot, cmd.indexSlot, cmd.dst) is CmdSetIndex -> Opcode.SET_INDEX to intArrayOf(cmd.targetSlot, cmd.indexSlot, cmd.valueSlot) is CmdListLiteral -> Opcode.LIST_LITERAL to intArrayOf(cmd.planId, cmd.baseSlot, cmd.count, cmd.dst) + is CmdGetThisMember -> Opcode.GET_THIS_MEMBER to intArrayOf(cmd.nameId, cmd.dst) + is CmdSetThisMember -> Opcode.SET_THIS_MEMBER to intArrayOf(cmd.nameId, cmd.valueSlot) is CmdEvalFallback -> Opcode.EVAL_FALLBACK to intArrayOf(cmd.id, cmd.dst) is CmdEvalRef -> Opcode.EVAL_REF to intArrayOf(cmd.id, cmd.dst) is CmdEvalStmt -> Opcode.EVAL_STMT to intArrayOf(cmd.id, cmd.dst) @@ -269,6 +271,10 @@ object CmdDisassembler { listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT) Opcode.LIST_LITERAL -> listOf(OperandKind.CONST, OperandKind.SLOT, OperandKind.COUNT, OperandKind.SLOT) + Opcode.GET_THIS_MEMBER -> + listOf(OperandKind.ID, OperandKind.SLOT) + Opcode.SET_THIS_MEMBER -> + listOf(OperandKind.ID, OperandKind.SLOT) Opcode.EVAL_FALLBACK, Opcode.EVAL_REF, Opcode.EVAL_STMT, Opcode.EVAL_VALUE_FN -> listOf(OperandKind.ID, OperandKind.SLOT) } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt index a642d79..4324ca0 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt @@ -1252,6 +1252,42 @@ class CmdListLiteral( } } +class CmdGetThisMember( + internal val nameId: Int, + internal val dst: Int, +) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + if (frame.fn.localSlotNames.isNotEmpty()) { + frame.syncFrameToScope() + } + val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal + ?: error("GET_THIS_MEMBER expects StringVal at $nameId") + val ref = net.sergeych.lyng.obj.ImplicitThisMemberRef(nameConst.value, frame.scope.pos) + val result = ref.evalValue(frame.scope) + frame.storeObjResult(dst, result) + return + } +} + +class CmdSetThisMember( + internal val nameId: Int, + internal val valueSlot: Int, +) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + if (frame.fn.localSlotNames.isNotEmpty()) { + frame.syncFrameToScope() + } + val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal + ?: error("SET_THIS_MEMBER expects StringVal at $nameId") + val ref = net.sergeych.lyng.obj.ImplicitThisMemberRef(nameConst.value, frame.scope.pos) + ref.setAt(frame.scope.pos, frame.scope, frame.slotToObj(valueSlot)) + if (frame.fn.localSlotNames.isNotEmpty()) { + frame.syncScopeToFrame() + } + return + } +} + class CmdSetField( internal val recvSlot: Int, internal val fieldId: Int, diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/Opcode.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/Opcode.kt index 23bc8c2..91f20ea 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/Opcode.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/Opcode.kt @@ -131,6 +131,8 @@ enum class Opcode(val code: Int) { SET_INDEX(0xA3), GET_NAME(0xA4), LIST_LITERAL(0xA5), + GET_THIS_MEMBER(0xA6), + SET_THIS_MEMBER(0xA7), EVAL_FALLBACK(0xB0), RESOLVE_SCOPE_SLOT(0xB1),