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 43db0a8..31a836a 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt @@ -114,6 +114,22 @@ class BytecodeCompiler( localSlotMutables ) } + is DestructuringVarDeclStatement -> { + val value = emitDestructuringVarDecl(stmt) ?: return null + builder.emit(Opcode.RET, value.slot) + val localCount = maxOf(nextSlot, value.slot + 1) - scopeSlotCount + builder.build( + name, + localCount, + addrCount = nextAddrSlot, + returnLabels = returnLabels, + scopeSlotIndices, + scopeSlotNames, + scopeSlotIsModule, + localSlotNames, + localSlotMutables + ) + } is net.sergeych.lyng.ThrowStatement -> compileThrowStatement(name, stmt) is net.sergeych.lyng.ExtensionPropertyDeclStatement -> compileExtensionPropertyDecl(name, stmt) is net.sergeych.lyng.TryStatement -> { @@ -3282,7 +3298,7 @@ class BytecodeCompiler( is BlockStatement -> emitBlock(target, true) is VarDeclStatement -> emitVarDecl(target) is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target) - is DestructuringVarDeclStatement -> emitStatementEval(target) + is DestructuringVarDeclStatement -> emitDestructuringVarDecl(target) is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target) is net.sergeych.lyng.ClassDeclStatement -> emitStatementEval(target) is net.sergeych.lyng.FunctionDeclStatement -> emitStatementEval(target) @@ -3329,7 +3345,7 @@ class BytecodeCompiler( } } is BlockStatement -> emitBlock(target, false) - is DestructuringVarDeclStatement -> emitStatementEval(target) + is DestructuringVarDeclStatement -> emitDestructuringVarDecl(target) is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target) is net.sergeych.lyng.BreakStatement -> compileBreak(target) is net.sergeych.lyng.ContinueStatement -> compileContinue(target) @@ -3591,6 +3607,23 @@ class BytecodeCompiler( return CompiledValue(value.slot, SlotType.OBJ) } + private fun emitDestructuringVarDecl(stmt: DestructuringVarDeclStatement): CompiledValue? { + val value = compileStatementValueOrFallback(stmt.initializer) ?: return null + val declId = builder.addConst( + BytecodeConst.DestructureDecl( + stmt.pattern, + stmt.names, + stmt.isMutable, + stmt.visibility, + stmt.isTransient, + stmt.pos + ) + ) + builder.emit(Opcode.DECL_DESTRUCTURE, 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) { 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 21368c9..2d6cf0b 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeConst.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeConst.kt @@ -18,6 +18,7 @@ package net.sergeych.lyng.bytecode import net.sergeych.lyng.Pos import net.sergeych.lyng.Visibility +import net.sergeych.lyng.obj.ListLiteralRef import net.sergeych.lyng.obj.Obj import net.sergeych.lyng.obj.ObjProperty @@ -52,6 +53,14 @@ sealed class BytecodeConst { val visibility: Visibility, val isTransient: Boolean, ) : BytecodeConst() + data class DestructureDecl( + val pattern: ListLiteralRef, + val names: List, + val isMutable: Boolean, + val visibility: Visibility, + val isTransient: Boolean, + val pos: Pos, + ) : BytecodeConst() data class CallArgsPlan(val tailBlock: Boolean, val specs: List) : BytecodeConst() data class CallArgSpec(val name: String?, val isSplat: Boolean) } 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 5e14230..a8bc970 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdBuilder.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdBuilder.kt @@ -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_DELEGATED -> + Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE -> 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, @@ -378,6 +378,7 @@ class CmdBuilder { Opcode.POP_SLOT_PLAN -> CmdPopSlotPlan() Opcode.DECL_LOCAL -> CmdDeclLocal(operands[0], operands[1]) Opcode.DECL_DELEGATED -> CmdDeclDelegated(operands[0], operands[1]) + Opcode.DECL_DESTRUCTURE -> CmdDeclDestructure(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]) 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 16777c1..4d1a552 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdDisassembler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdDisassembler.kt @@ -186,6 +186,7 @@ object CmdDisassembler { 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 CmdDeclDestructure -> Opcode.DECL_DESTRUCTURE 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) @@ -241,7 +242,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_DELEGATED -> + Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE -> 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, 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 0ff55a8..73e42ef 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt @@ -1216,6 +1216,30 @@ class CmdDeclDelegated(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) { + val decl = frame.fn.constants[constId] as? BytecodeConst.DestructureDecl + ?: error("DECL_DESTRUCTURE expects DestructureDecl at $constId") + val value = frame.slotToObj(slot) + val scope = frame.ensureScope() + for (name in decl.names) { + scope.addItem(name, true, ObjVoid, decl.visibility, isTransient = decl.isTransient) + } + decl.pattern.setAt(decl.pos, scope, value) + if (!decl.isMutable) { + for (name in decl.names) { + val rec = scope.objects[name] ?: continue + val immutableRec = rec.copy(isMutable = false) + scope.objects[name] = immutableRec + scope.localBindings[name] = immutableRec + scope.updateSlotFor(name, immutableRec) + } + } + frame.storeObjResult(slot, ObjVoid) + 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 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 a774055..2db9731 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/Opcode.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/Opcode.kt @@ -126,6 +126,7 @@ enum class Opcode(val code: Int) { DECL_LOCAL(0x89), DECL_EXT_PROPERTY(0x8A), DECL_DELEGATED(0x8B), + DECL_DESTRUCTURE(0x8C), CALL_DIRECT(0x90), CALL_MEMBER_SLOT(0x92),