From 81d86f4c3aa1a64df87c97567cd74041018334be Mon Sep 17 00:00:00 2001 From: sergeych Date: Wed, 28 Jan 2026 22:38:01 +0300 Subject: [PATCH] Add bytecode opcode for ValueFnRef --- .../sergeych/lyng/bytecode/BytecodeCompiler.kt | 8 +++++++- .../net/sergeych/lyng/bytecode/BytecodeConst.kt | 1 + .../net/sergeych/lyng/bytecode/CmdBuilder.kt | 3 ++- .../sergeych/lyng/bytecode/CmdDisassembler.kt | 3 ++- .../net/sergeych/lyng/bytecode/CmdRuntime.kt | 16 ++++++++++++++++ .../kotlin/net/sergeych/lyng/bytecode/Opcode.kt | 1 + .../kotlin/net/sergeych/lyng/obj/ObjRef.kt | 2 ++ 7 files changed, 31 insertions(+), 3 deletions(-) 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 491143c..f4cc1b1 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt @@ -175,7 +175,13 @@ class BytecodeCompiler( CompiledValue(mapped, resolved) } is LocalVarRef -> compileNameLookup(ref.name) - is ValueFnRef -> compileEvalRef(ref) + is ValueFnRef -> { + val constId = builder.addConst(BytecodeConst.ValueFn(ref.valueFn())) + val slot = allocSlot() + builder.emit(Opcode.EVAL_VALUE_FN, constId, slot) + updateSlotType(slot, SlotType.OBJ) + CompiledValue(slot, SlotType.OBJ) + } is ListLiteralRef -> compileListLiteral(ref) is ThisMethodSlotCallRef -> compileThisMethodSlotCall(ref) is StatementRef -> { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeConst.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeConst.kt index 127659e..0f2f33d 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeConst.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeConst.kt @@ -32,6 +32,7 @@ sealed class BytecodeConst { data class Ref(val value: net.sergeych.lyng.obj.ObjRef) : BytecodeConst() data class StatementVal(val statement: net.sergeych.lyng.Statement) : BytecodeConst() data class ListLiteralPlan(val spreads: List) : BytecodeConst() + data class ValueFn(val fn: suspend (net.sergeych.lyng.Scope) -> net.sergeych.lyng.obj.ObjRecord) : BytecodeConst() data class SlotPlan(val plan: Map) : BytecodeConst() data class ExtensionPropertyDecl( val extTypeName: String, 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 285a98e..da12b38 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdBuilder.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdBuilder.kt @@ -184,7 +184,7 @@ class CmdBuilder { listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT) Opcode.LIST_LITERAL -> listOf(OperandKind.CONST, OperandKind.SLOT, OperandKind.COUNT, OperandKind.SLOT) - Opcode.EVAL_FALLBACK, Opcode.EVAL_REF, Opcode.EVAL_STMT -> + Opcode.EVAL_FALLBACK, Opcode.EVAL_REF, Opcode.EVAL_STMT, Opcode.EVAL_VALUE_FN -> listOf(OperandKind.ID, OperandKind.SLOT) } } @@ -377,6 +377,7 @@ class CmdBuilder { Opcode.EVAL_FALLBACK -> CmdEvalFallback(operands[0], operands[1]) Opcode.EVAL_REF -> CmdEvalRef(operands[0], operands[1]) Opcode.EVAL_STMT -> CmdEvalStmt(operands[0], operands[1]) + Opcode.EVAL_VALUE_FN -> CmdEvalValueFn(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 d6d327d..7c42bc1 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdDisassembler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdDisassembler.kt @@ -187,6 +187,7 @@ object CmdDisassembler { 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) + is CmdEvalValueFn -> Opcode.EVAL_VALUE_FN to intArrayOf(cmd.id, cmd.dst) } } @@ -268,7 +269,7 @@ object CmdDisassembler { listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT) Opcode.LIST_LITERAL -> listOf(OperandKind.CONST, OperandKind.SLOT, OperandKind.COUNT, OperandKind.SLOT) - Opcode.EVAL_FALLBACK, Opcode.EVAL_REF, Opcode.EVAL_STMT -> + 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 8fc7387..a642d79 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt @@ -1352,6 +1352,22 @@ class CmdEvalStmt(internal val id: Int, internal val dst: Int) : Cmd() { } } +class CmdEvalValueFn(internal val id: Int, internal val dst: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + if (frame.fn.localSlotNames.isNotEmpty()) { + frame.syncFrameToScope() + } + val valueFn = frame.fn.constants.getOrNull(id) as? BytecodeConst.ValueFn + ?: error("EVAL_VALUE_FN expects ValueFn at $id") + val result = valueFn.fn(frame.scope).value + if (frame.fn.localSlotNames.isNotEmpty()) { + frame.syncScopeToFrame() + } + frame.storeObjResult(dst, result) + return + } +} + class CmdFrame( val vm: CmdVm, val fn: CmdFunction, 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 2d252a8..23bc8c2 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/Opcode.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/Opcode.kt @@ -145,6 +145,7 @@ enum class Opcode(val code: Int) { THROW(0xBB), EVAL_REF(0xBC), EVAL_STMT(0xBD), + EVAL_VALUE_FN(0xBE), ; companion object { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt index f593315..68b8691 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt @@ -66,6 +66,8 @@ sealed interface ObjRef { /** Runtime-computed read-only reference backed by a lambda. */ class ValueFnRef(private val fn: suspend (Scope) -> ObjRecord) : ObjRef { + internal fun valueFn(): suspend (Scope) -> ObjRecord = fn + override suspend fun get(scope: Scope): ObjRecord = fn(scope) }