Fix module scope resolution in cmd runtime

This commit is contained in:
Sergey Chernov 2026-01-30 14:00:02 +03:00
parent 9319add9c0
commit 89cf2c1612
3 changed files with 72 additions and 12 deletions

View File

@ -701,6 +701,12 @@ class BytecodeCompiler(
builder.emit(Opcode.CMP_EQ_OBJ, left.slot, right.slot, out) builder.emit(Opcode.CMP_EQ_OBJ, left.slot, right.slot, out)
return CompiledValue(out, SlotType.BOOL) return CompiledValue(out, SlotType.BOOL)
} }
if (a.type == SlotType.OBJ || b.type == SlotType.OBJ) {
val left = ensureObjSlot(a)
val right = ensureObjSlot(b)
builder.emit(Opcode.CMP_EQ_OBJ, left.slot, right.slot, out)
return CompiledValue(out, SlotType.BOOL)
}
return when { return when {
a.type == SlotType.INT && b.type == SlotType.INT -> { a.type == SlotType.INT && b.type == SlotType.INT -> {
builder.emit(Opcode.CMP_EQ_INT, a.slot, b.slot, out) builder.emit(Opcode.CMP_EQ_INT, a.slot, b.slot, out)
@ -737,6 +743,12 @@ class BytecodeCompiler(
builder.emit(Opcode.CMP_NEQ_OBJ, left.slot, right.slot, out) builder.emit(Opcode.CMP_NEQ_OBJ, left.slot, right.slot, out)
return CompiledValue(out, SlotType.BOOL) return CompiledValue(out, SlotType.BOOL)
} }
if (a.type == SlotType.OBJ || b.type == SlotType.OBJ) {
val left = ensureObjSlot(a)
val right = ensureObjSlot(b)
builder.emit(Opcode.CMP_NEQ_OBJ, left.slot, right.slot, out)
return CompiledValue(out, SlotType.BOOL)
}
return when { return when {
a.type == SlotType.INT && b.type == SlotType.INT -> { a.type == SlotType.INT && b.type == SlotType.INT -> {
builder.emit(Opcode.CMP_NEQ_INT, a.slot, b.slot, out) builder.emit(Opcode.CMP_NEQ_INT, a.slot, b.slot, out)
@ -773,6 +785,12 @@ class BytecodeCompiler(
builder.emit(Opcode.CMP_LT_OBJ, left.slot, right.slot, out) builder.emit(Opcode.CMP_LT_OBJ, left.slot, right.slot, out)
return CompiledValue(out, SlotType.BOOL) return CompiledValue(out, SlotType.BOOL)
} }
if (a.type == SlotType.OBJ || b.type == SlotType.OBJ) {
val left = ensureObjSlot(a)
val right = ensureObjSlot(b)
builder.emit(Opcode.CMP_LT_OBJ, left.slot, right.slot, out)
return CompiledValue(out, SlotType.BOOL)
}
return when { return when {
a.type == SlotType.INT && b.type == SlotType.INT -> { a.type == SlotType.INT && b.type == SlotType.INT -> {
builder.emit(Opcode.CMP_LT_INT, a.slot, b.slot, out) builder.emit(Opcode.CMP_LT_INT, a.slot, b.slot, out)
@ -805,6 +823,12 @@ class BytecodeCompiler(
builder.emit(Opcode.CMP_LTE_OBJ, left.slot, right.slot, out) builder.emit(Opcode.CMP_LTE_OBJ, left.slot, right.slot, out)
return CompiledValue(out, SlotType.BOOL) return CompiledValue(out, SlotType.BOOL)
} }
if (a.type == SlotType.OBJ || b.type == SlotType.OBJ) {
val left = ensureObjSlot(a)
val right = ensureObjSlot(b)
builder.emit(Opcode.CMP_LTE_OBJ, left.slot, right.slot, out)
return CompiledValue(out, SlotType.BOOL)
}
return when { return when {
a.type == SlotType.INT && b.type == SlotType.INT -> { a.type == SlotType.INT && b.type == SlotType.INT -> {
builder.emit(Opcode.CMP_LTE_INT, a.slot, b.slot, out) builder.emit(Opcode.CMP_LTE_INT, a.slot, b.slot, out)
@ -837,6 +861,12 @@ class BytecodeCompiler(
builder.emit(Opcode.CMP_GT_OBJ, left.slot, right.slot, out) builder.emit(Opcode.CMP_GT_OBJ, left.slot, right.slot, out)
return CompiledValue(out, SlotType.BOOL) return CompiledValue(out, SlotType.BOOL)
} }
if (a.type == SlotType.OBJ || b.type == SlotType.OBJ) {
val left = ensureObjSlot(a)
val right = ensureObjSlot(b)
builder.emit(Opcode.CMP_GT_OBJ, left.slot, right.slot, out)
return CompiledValue(out, SlotType.BOOL)
}
return when { return when {
a.type == SlotType.INT && b.type == SlotType.INT -> { a.type == SlotType.INT && b.type == SlotType.INT -> {
builder.emit(Opcode.CMP_GT_INT, a.slot, b.slot, out) builder.emit(Opcode.CMP_GT_INT, a.slot, b.slot, out)
@ -869,6 +899,12 @@ class BytecodeCompiler(
builder.emit(Opcode.CMP_GTE_OBJ, left.slot, right.slot, out) builder.emit(Opcode.CMP_GTE_OBJ, left.slot, right.slot, out)
return CompiledValue(out, SlotType.BOOL) return CompiledValue(out, SlotType.BOOL)
} }
if (a.type == SlotType.OBJ || b.type == SlotType.OBJ) {
val left = ensureObjSlot(a)
val right = ensureObjSlot(b)
builder.emit(Opcode.CMP_GTE_OBJ, left.slot, right.slot, out)
return CompiledValue(out, SlotType.BOOL)
}
return when { return when {
a.type == SlotType.INT && b.type == SlotType.INT -> { a.type == SlotType.INT && b.type == SlotType.INT -> {
builder.emit(Opcode.CMP_GTE_INT, a.slot, b.slot, out) builder.emit(Opcode.CMP_GTE_INT, a.slot, b.slot, out)
@ -2978,6 +3014,11 @@ class BytecodeCompiler(
scopeSlotIndexByName[ref.name]?.let { return it } scopeSlotIndexByName[ref.name]?.let { return it }
} }
if (ref.captureOwnerScopeId != null) { if (ref.captureOwnerScopeId != null) {
val ownerKey = ScopeSlotKey(ref.captureOwnerScopeId, ref.captureOwnerSlot ?: refSlot(ref))
val ownerLocal = localSlotIndexByKey[ownerKey]
if (ownerLocal != null) {
return scopeSlotCount + ownerLocal
}
val scopeKey = ScopeSlotKey(refScopeId(ref), refSlot(ref)) val scopeKey = ScopeSlotKey(refScopeId(ref), refSlot(ref))
return scopeSlotMap[scopeKey] return scopeSlotMap[scopeKey]
} }
@ -3530,7 +3571,17 @@ class BytecodeCompiler(
if (stmt == null) return null if (stmt == null) return null
val target = if (stmt is BytecodeStatement) stmt.original else stmt val target = if (stmt is BytecodeStatement) stmt.original else stmt
val expr = target as? ExpressionStatement ?: return null val expr = target as? ExpressionStatement ?: return null
return expr.ref as? RangeRef val ref = expr.ref
if (ref is RangeRef) return ref
if (ref is ConstRef) {
val range = ref.constValue as? ObjRange ?: return null
val start = range.start as? ObjInt ?: return null
val end = range.end as? ObjInt ?: return null
val left = ConstRef(start.asReadonly)
val right = ConstRef(end.asReadonly)
return RangeRef(left, right, range.isEndInclusive)
}
return null
} }
private fun extractRangeFromLocal(source: Statement): RangeRef? { private fun extractRangeFromLocal(source: Statement): RangeRef? {

View File

@ -18,6 +18,7 @@ package net.sergeych.lyng.bytecode
import net.sergeych.lyng.Arguments import net.sergeych.lyng.Arguments
import net.sergeych.lyng.ExecutionError import net.sergeych.lyng.ExecutionError
import net.sergeych.lyng.ModuleScope
import net.sergeych.lyng.PerfFlags import net.sergeych.lyng.PerfFlags
import net.sergeych.lyng.PerfStats import net.sergeych.lyng.PerfStats
import net.sergeych.lyng.Pos import net.sergeych.lyng.Pos
@ -1498,7 +1499,7 @@ class CmdFrame(
var ip: Int = 0 var ip: Int = 0
var scope: Scope = scope0 var scope: Scope = scope0
private val moduleScope: Scope = scope0 private val moduleScope: Scope = resolveModuleScope(scope0)
val methodCallSites: MutableMap<Int, MethodCallSite> = CmdCallSiteCache.methodCallSites(fn) val methodCallSites: MutableMap<Int, MethodCallSite> = CmdCallSiteCache.methodCallSites(fn)
internal val scopeStack = ArrayDeque<Scope>() internal val scopeStack = ArrayDeque<Scope>()
@ -1521,6 +1522,18 @@ class CmdFrame(
} }
} }
private fun resolveModuleScope(scope: Scope): Scope {
var current: Scope? = scope
var last: Scope = scope
while (current != null) {
if (current is ModuleScope) return current
if (current.parent is ModuleScope) return current
last = current
current = current.parent
}
return last
}
fun pushScope(plan: Map<String, Int>, captures: List<String>) { fun pushScope(plan: Map<String, Int>, captures: List<String>) {
val parentScope = scope val parentScope = scope
val captureRecords = if (captures.isNotEmpty()) { val captureRecords = if (captures.isNotEmpty()) {
@ -1989,15 +2002,15 @@ class CmdFrame(
return index return index
} }
target.applySlotPlan(mapOf(name to index)) target.applySlotPlan(mapOf(name to index))
val existing = target.getLocalRecordDirect(name) val existing = target.getLocalRecordDirect(name) ?: target.localBindings[name]
if (existing != null) { if (existing != null) {
target.updateSlotFor(name, existing) target.updateSlotFor(name, existing)
} else { return index
val resolved = target.get(name) }
val resolved = target.parent?.get(name) ?: target.get(name)
if (resolved != null) { if (resolved != null) {
target.updateSlotFor(name, resolved) target.updateSlotFor(name, resolved)
} }
}
return index return index
} }

View File

@ -1406,7 +1406,6 @@ class ScriptTest {
) )
} }
@Ignore("incremental enable")
@Test @Test
fun testOpenEndRanges3() = runTest { fun testOpenEndRanges3() = runTest {
eval( eval(
@ -1419,7 +1418,6 @@ class ScriptTest {
) )
} }
@Ignore("incremental enable")
@Test @Test
fun testCharacterRange() = runTest { fun testCharacterRange() = runTest {
eval( eval(
@ -1434,7 +1432,6 @@ class ScriptTest {
) )
} }
@Ignore("incremental enable")
@Test @Test
fun testIs() = runTest { fun testIs() = runTest {
eval( eval(
@ -1450,7 +1447,6 @@ class ScriptTest {
) )
} }
@Ignore("incremental enable")
@Test @Test
fun testForRange() = runTest { fun testForRange() = runTest {
eval( eval(