From 4db0a7fbab2d4744a3821887b890bd5d816c91cf Mon Sep 17 00:00:00 2001 From: sergeych Date: Tue, 10 Feb 2026 08:04:28 +0300 Subject: [PATCH] Step 25A: bytecode enum declarations --- bytecode_migration_plan.md | 6 +++-- .../kotlin/net/sergeych/lyng/Compiler.kt | 24 ++++++------------- .../net/sergeych/lyng/EnumDeclStatement.kt | 21 +++++++++++++--- .../lyng/bytecode/BytecodeCompiler.kt | 22 +++++++++++++---- .../sergeych/lyng/bytecode/BytecodeConst.kt | 6 +++++ .../net/sergeych/lyng/bytecode/CmdBuilder.kt | 3 ++- .../sergeych/lyng/bytecode/CmdDisassembler.kt | 3 ++- .../net/sergeych/lyng/bytecode/CmdRuntime.kt | 20 ++++++++++++++++ .../net/sergeych/lyng/bytecode/Opcode.kt | 1 + 9 files changed, 78 insertions(+), 28 deletions(-) diff --git a/bytecode_migration_plan.md b/bytecode_migration_plan.md index a94fa85..2e0a9e5 100644 --- a/bytecode_migration_plan.md +++ b/bytecode_migration_plan.md @@ -113,8 +113,10 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te ## Interpreter Removal (next) - [ ] Step 25: Replace Statement-based declaration calls in bytecode. - - [ ] Add bytecode const/op for class/enum/function declarations (no `Statement` objects in constants). - - [ ] Replace `emitStatementCall` usage for `ClassDeclStatement`, `FunctionDeclStatement`, `EnumDeclStatement`. + - [x] Add bytecode const/op for enum declarations (no `Statement` objects in constants). + - [ ] Add bytecode const/op for class/function declarations (no `Statement` objects in constants). + - [x] Replace `emitStatementCall` usage for `EnumDeclStatement`. + - [ ] Replace `emitStatementCall` usage for `ClassDeclStatement` and `FunctionDeclStatement`. - [ ] Add JVM disasm coverage to ensure module init has no `CALL_SLOT` to `Callable@...` for declarations. - [ ] Step 26: Bytecode-backed lambdas (remove `ValueFnRef` runtime execution). - [ ] Compile lambda bodies to bytecode and emit an opcode to create a callable from bytecode + capture plan. diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt index 36eb73e..5ab9ddc 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt @@ -5803,23 +5803,13 @@ class Compiler( } val stmtPos = startPos - val enumDeclStatement = object : Statement() { - override val pos: Pos = stmtPos - override suspend fun execute(scope: Scope): Obj { - val enumClass = ObjEnumClass.createSimpleEnum(qualifiedName, names) - scope.addItem(declaredName, false, enumClass, recordType = ObjRecord.Type.Enum) - if (lifted) { - for (entry in names) { - val rec = enumClass.getInstanceMemberOrNull(entry, includeAbstract = false, includeStatic = true) - if (rec != null) { - scope.addItem(entry, false, rec.value) - } - } - } - return enumClass - } - } - return EnumDeclStatement(StatementDeclExecutable(enumDeclStatement), stmtPos) + return EnumDeclStatement( + declaredName = declaredName, + qualifiedName = qualifiedName, + entries = names.toList(), + lifted = lifted, + startPos = stmtPos + ) } private suspend fun parseObjectDeclaration(isExtern: Boolean = false): Statement { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/EnumDeclStatement.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/EnumDeclStatement.kt index 9a209ef..1fe5a60 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/EnumDeclStatement.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/EnumDeclStatement.kt @@ -17,19 +17,34 @@ package net.sergeych.lyng import net.sergeych.lyng.obj.Obj +import net.sergeych.lyng.obj.ObjEnumClass +import net.sergeych.lyng.obj.ObjRecord class EnumDeclStatement( - val executable: DeclExecutable, + val declaredName: String, + val qualifiedName: String, + val entries: List, + val lifted: Boolean, private val startPos: Pos, ) : Statement() { override val pos: Pos = startPos override suspend fun execute(scope: Scope): Obj { - return executable.execute(scope) + val enumClass = ObjEnumClass.createSimpleEnum(qualifiedName, entries) + scope.addItem(declaredName, false, enumClass, recordType = ObjRecord.Type.Enum) + if (lifted) { + for (entry in entries) { + val rec = enumClass.getInstanceMemberOrNull(entry, includeAbstract = false, includeStatic = true) + if (rec != null) { + scope.addItem(entry, false, rec.value) + } + } + } + return enumClass } override suspend fun callOn(scope: Scope): Obj { val target = scope.parent ?: scope - return executable.execute(target) + return execute(target) } } 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 e3964bd..2378917 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt @@ -195,7 +195,7 @@ class BytecodeCompiler( ) } is net.sergeych.lyng.EnumDeclStatement -> { - val value = emitStatementCall(stmt) + val value = emitDeclEnum(stmt) builder.emit(Opcode.RET, value.slot) val localCount = maxOf(nextSlot, value.slot + 1) - scopeSlotCount builder.build( @@ -4110,7 +4110,6 @@ class BytecodeCompiler( val executable = when (stmt) { is net.sergeych.lyng.ClassDeclStatement -> stmt.executable is net.sergeych.lyng.FunctionDeclStatement -> stmt.executable - is net.sergeych.lyng.EnumDeclStatement -> stmt.executable else -> throw BytecodeCompileException( "Bytecode compile error: unsupported declaration ${stmt::class.simpleName}", stmt.pos @@ -4123,6 +4122,21 @@ class BytecodeCompiler( return CompiledValue(dst, SlotType.OBJ) } + private fun emitDeclEnum(stmt: net.sergeych.lyng.EnumDeclStatement): CompiledValue { + val constId = builder.addConst( + BytecodeConst.EnumDecl( + declaredName = stmt.declaredName, + qualifiedName = stmt.qualifiedName, + entries = stmt.entries, + lifted = stmt.lifted + ) + ) + val dst = allocSlot() + builder.emit(Opcode.DECL_ENUM, constId, dst) + updateSlotType(dst, SlotType.OBJ) + return CompiledValue(dst, SlotType.OBJ) + } + private fun compileStatementValueOrFallback(stmt: Statement, needResult: Boolean = true): CompiledValue? { val target = if (stmt is BytecodeStatement) stmt.original else stmt setPos(target.pos) @@ -4158,7 +4172,7 @@ class BytecodeCompiler( is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target) is net.sergeych.lyng.ClassDeclStatement -> emitDeclExec(target) is net.sergeych.lyng.FunctionDeclStatement -> emitDeclExec(target) - is net.sergeych.lyng.EnumDeclStatement -> emitDeclExec(target) + is net.sergeych.lyng.EnumDeclStatement -> emitDeclEnum(target) is net.sergeych.lyng.TryStatement -> emitTry(target, true) is net.sergeych.lyng.WhenStatement -> compileWhen(target, true) is net.sergeych.lyng.BreakStatement -> compileBreak(target) @@ -4191,7 +4205,7 @@ class BytecodeCompiler( is IfStatement -> compileIfStatement(target) is net.sergeych.lyng.ClassDeclStatement -> emitDeclExec(target) is net.sergeych.lyng.FunctionDeclStatement -> emitDeclExec(target) - is net.sergeych.lyng.EnumDeclStatement -> emitDeclExec(target) + is net.sergeych.lyng.EnumDeclStatement -> emitDeclEnum(target) is net.sergeych.lyng.ForInStatement -> { val resultSlot = emitForIn(target, false) ?: return null CompiledValue(resultSlot, SlotType.OBJ) 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 7c162bf..40aa5f6 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeConst.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeConst.kt @@ -38,6 +38,12 @@ sealed class BytecodeConst { val captureTableId: Int? = null, ) : BytecodeConst() data class DeclExec(val executable: net.sergeych.lyng.DeclExecutable) : BytecodeConst() + data class EnumDecl( + val declaredName: String, + val qualifiedName: String, + val entries: List, + val lifted: Boolean, + ) : BytecodeConst() data class SlotPlan(val plan: Map, val captures: List = emptyList()) : BytecodeConst() data class CaptureTable(val entries: List) : BytecodeConst() data class ExtensionPropertyDecl( 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 e2f446a..c46e7ba 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdBuilder.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdBuilder.kt @@ -157,7 +157,7 @@ class CmdBuilder { Opcode.PUSH_TRY -> listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP) Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE, - Opcode.DECL_EXEC, + Opcode.DECL_EXEC, Opcode.DECL_ENUM, Opcode.ASSIGN_DESTRUCTURE -> listOf(OperandKind.CONST, OperandKind.SLOT) Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT, @@ -411,6 +411,7 @@ class CmdBuilder { Opcode.DECL_DELEGATED -> CmdDeclDelegated(operands[0], operands[1]) Opcode.DECL_DESTRUCTURE -> CmdDeclDestructure(operands[0], operands[1]) Opcode.DECL_EXEC -> CmdDeclExec(operands[0], operands[1]) + Opcode.DECL_ENUM -> CmdDeclEnum(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.ASSIGN_DESTRUCTURE -> CmdAssignDestructure(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 610e508..f91d3d5 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdDisassembler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdDisassembler.kt @@ -212,6 +212,7 @@ object CmdDisassembler { is CmdDeclDelegated -> Opcode.DECL_DELEGATED to intArrayOf(cmd.constId, cmd.slot) is CmdDeclDestructure -> Opcode.DECL_DESTRUCTURE to intArrayOf(cmd.constId, cmd.slot) is CmdDeclExec -> Opcode.DECL_EXEC to intArrayOf(cmd.constId, cmd.slot) + is CmdDeclEnum -> Opcode.DECL_ENUM 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 CmdAssignDestructure -> Opcode.ASSIGN_DESTRUCTURE to intArrayOf(cmd.constId, cmd.slot) @@ -283,7 +284,7 @@ object CmdDisassembler { Opcode.PUSH_TRY -> listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP) Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE, - Opcode.DECL_EXEC, + Opcode.DECL_EXEC, Opcode.DECL_ENUM, Opcode.ASSIGN_DESTRUCTURE -> listOf(OperandKind.CONST, OperandKind.SLOT) Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT, 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 ad07ef9..92ee8b3 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/CmdRuntime.kt @@ -1324,6 +1324,26 @@ class CmdDeclExec(internal val constId: Int, internal val slot: Int) : Cmd() { } } +class CmdDeclEnum(internal val constId: Int, internal val slot: Int) : Cmd() { + override suspend fun perform(frame: CmdFrame) { + val decl = frame.fn.constants[constId] as? BytecodeConst.EnumDecl + ?: error("DECL_ENUM expects EnumDecl at $constId") + val scope = frame.ensureScope() + val enumClass = ObjEnumClass.createSimpleEnum(decl.qualifiedName, decl.entries) + scope.addItem(decl.declaredName, false, enumClass, recordType = ObjRecord.Type.Enum) + if (decl.lifted) { + for (entry in decl.entries) { + val rec = enumClass.getInstanceMemberOrNull(entry, includeAbstract = false, includeStatic = true) + if (rec != null) { + scope.addItem(entry, false, rec.value) + } + } + } + frame.storeObjResult(slot, enumClass) + return + } +} + 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 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 151fe9a..44e54a7 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/Opcode.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/Opcode.kt @@ -159,6 +159,7 @@ enum class Opcode(val code: Int) { THROW(0xBB), RETHROW_PENDING(0xBC), DECL_EXEC(0xBD), + DECL_ENUM(0xBE), ITER_PUSH(0xBF), ITER_POP(0xC0), ITER_CANCEL(0xC1),