Add bytecode opcode for ValueFnRef

This commit is contained in:
Sergey Chernov 2026-01-28 22:38:01 +03:00
parent a4fc5ac6d5
commit 81d86f4c3a
7 changed files with 31 additions and 3 deletions

View File

@ -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 -> {

View File

@ -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<Boolean>) : BytecodeConst()
data class ValueFn(val fn: suspend (net.sergeych.lyng.Scope) -> net.sergeych.lyng.obj.ObjRecord) : BytecodeConst()
data class SlotPlan(val plan: Map<String, Int>) : BytecodeConst()
data class ExtensionPropertyDecl(
val extTypeName: String,

View File

@ -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])
}
}
}

View File

@ -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)
}
}

View File

@ -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,

View File

@ -145,6 +145,7 @@ enum class Opcode(val code: Int) {
THROW(0xBB),
EVAL_REF(0xBC),
EVAL_STMT(0xBD),
EVAL_VALUE_FN(0xBE),
;
companion object {

View File

@ -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)
}