diff --git a/bytecode_migration_plan.md b/bytecode_migration_plan.md index 1791c5f..4d240c7 100644 --- a/bytecode_migration_plan.md +++ b/bytecode_migration_plan.md @@ -129,6 +129,7 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te - [ ] Delete `BytecodeConst.ValueFn`, `CmdMakeValueFn`, and `MAKE_VALUE_FN` (blocked: some lambdas still fall back to non-bytecode bodies). - [x] Delete `BytecodeConst.StatementVal`, `CmdEvalStmt`, and `EVAL_STMT`. - [x] Add bytecode-backed `::class` via `ClassOperatorRef` + `GET_OBJ_CLASS` to avoid ValueFn for class operator. + - [x] Add a bytecode fallback reporter hook for lambdas to locate remaining non-bytecode cases. - [ ] Remove `emitStatementCall`/`emitStatementEval` once unused. - [ ] Step 28: Scope as facade only. - [ ] Audit bytecode execution paths for `Statement.execute` usage and remove remaining calls. diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt index 5c80a57..92a8a65 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt @@ -1040,6 +1040,7 @@ class Compiler( class Settings( val miniAstSink: MiniAstSink? = null, val resolutionSink: ResolutionSink? = null, + val bytecodeFallbackReporter: ((Pos, String) -> Unit)? = null, val useBytecodeStatements: Boolean = true, val strictSlotRefs: Boolean = true, val allowUnresolvedRefs: Boolean = false, @@ -1050,6 +1051,7 @@ class Compiler( // Optional sink for mini-AST streaming (null by default, zero overhead when not used) private val miniSink: MiniAstSink? = settings.miniAstSink private val resolutionSink: ResolutionSink? = settings.resolutionSink + private val bytecodeFallbackReporter: ((Pos, String) -> Unit)? = settings.bytecodeFallbackReporter private val seedScope: Scope? = settings.seedScope private val useFastLocalRefs: Boolean = settings.useFastLocalRefs private var resolutionScriptDepth = 0 @@ -2907,14 +2909,27 @@ class Compiler( paramKnownClasses[param.name] = cls } val returnLabels = label?.let { setOf(it) } ?: emptySet() - val fnStatements = if (useBytecodeStatements && !containsUnsupportedForBytecode(body)) { - returnLabelStack.addLast(returnLabels) - try { - wrapFunctionBytecode(body, "", paramKnownClasses) - } catch (e: net.sergeych.lyng.bytecode.BytecodeCompileException) { + val fnStatements = if (useBytecodeStatements) { + if (containsUnsupportedForBytecode(body)) { + bytecodeFallbackReporter?.invoke( + body.pos, + "lambda contains unsupported bytecode statements" + ) body - } finally { - returnLabelStack.removeLast() + } else { + returnLabelStack.addLast(returnLabels) + try { + wrapFunctionBytecode(body, "", paramKnownClasses) + } catch (e: net.sergeych.lyng.bytecode.BytecodeCompileException) { + val pos = e.pos ?: body.pos + bytecodeFallbackReporter?.invoke( + pos, + "lambda bytecode compile failed: ${e.message}" + ) + body + } finally { + returnLabelStack.removeLast() + } } } else { body