Fix while bytecode scoping and arithmetic fallback
This commit is contained in:
parent
9bc59f4787
commit
df48a06311
@ -173,6 +173,13 @@ class BytecodeCompiler(
|
|||||||
if (!allowLocalSlots) return null
|
if (!allowLocalSlots) return null
|
||||||
if (ref.isDelegated) return null
|
if (ref.isDelegated) return null
|
||||||
if (ref.name.isEmpty()) return null
|
if (ref.name.isEmpty()) return null
|
||||||
|
if (ref.captureOwnerScopeId == null) {
|
||||||
|
val byName = scopeSlotIndexByName[ref.name]
|
||||||
|
if (byName != null) {
|
||||||
|
val resolved = slotTypes[byName] ?: SlotType.UNKNOWN
|
||||||
|
return CompiledValue(byName, resolved)
|
||||||
|
}
|
||||||
|
}
|
||||||
val mapped = resolveSlot(ref) ?: return compileNameLookup(ref.name)
|
val mapped = resolveSlot(ref) ?: return compileNameLookup(ref.name)
|
||||||
var resolved = slotTypes[mapped] ?: SlotType.UNKNOWN
|
var resolved = slotTypes[mapped] ?: SlotType.UNKNOWN
|
||||||
if (resolved == SlotType.UNKNOWN && intLoopVarNames.contains(ref.name)) {
|
if (resolved == SlotType.UNKNOWN && intLoopVarNames.contains(ref.name)) {
|
||||||
@ -191,6 +198,10 @@ class BytecodeCompiler(
|
|||||||
is LocalVarRef -> {
|
is LocalVarRef -> {
|
||||||
if (allowLocalSlots) {
|
if (allowLocalSlots) {
|
||||||
if (!forceScopeSlots) {
|
if (!forceScopeSlots) {
|
||||||
|
scopeSlotIndexByName[ref.name]?.let { slot ->
|
||||||
|
val resolved = slotTypes[slot] ?: SlotType.UNKNOWN
|
||||||
|
return CompiledValue(slot, resolved)
|
||||||
|
}
|
||||||
loopSlotOverrides[ref.name]?.let { slot ->
|
loopSlotOverrides[ref.name]?.let { slot ->
|
||||||
val resolved = slotTypes[slot] ?: SlotType.UNKNOWN
|
val resolved = slotTypes[slot] ?: SlotType.UNKNOWN
|
||||||
return CompiledValue(slot, resolved)
|
return CompiledValue(slot, resolved)
|
||||||
@ -415,7 +426,42 @@ class BytecodeCompiler(
|
|||||||
b = CompiledValue(b.slot, SlotType.INT)
|
b = CompiledValue(b.slot, SlotType.INT)
|
||||||
}
|
}
|
||||||
val typesMismatch = a.type != b.type && a.type != SlotType.UNKNOWN && b.type != SlotType.UNKNOWN
|
val typesMismatch = a.type != b.type && a.type != SlotType.UNKNOWN && b.type != SlotType.UNKNOWN
|
||||||
if (typesMismatch && op !in setOf(BinOp.EQ, BinOp.NEQ, BinOp.LT, BinOp.LTE, BinOp.GT, BinOp.GTE)) {
|
val allowMixedNumeric = op in setOf(BinOp.PLUS, BinOp.MINUS, BinOp.STAR, BinOp.SLASH)
|
||||||
|
if (typesMismatch && op in setOf(BinOp.PLUS, BinOp.MINUS, BinOp.STAR, BinOp.SLASH, BinOp.PERCENT)) {
|
||||||
|
val leftObj = ensureObjSlot(a)
|
||||||
|
val rightObj = ensureObjSlot(b)
|
||||||
|
val out = allocSlot()
|
||||||
|
val objOpcode = when (op) {
|
||||||
|
BinOp.PLUS -> Opcode.ADD_OBJ
|
||||||
|
BinOp.MINUS -> Opcode.SUB_OBJ
|
||||||
|
BinOp.STAR -> Opcode.MUL_OBJ
|
||||||
|
BinOp.SLASH -> Opcode.DIV_OBJ
|
||||||
|
BinOp.PERCENT -> Opcode.MOD_OBJ
|
||||||
|
else -> null
|
||||||
|
} ?: return null
|
||||||
|
builder.emit(objOpcode, leftObj.slot, rightObj.slot, out)
|
||||||
|
return CompiledValue(out, SlotType.OBJ)
|
||||||
|
}
|
||||||
|
if ((a.type == SlotType.UNKNOWN || b.type == SlotType.UNKNOWN) &&
|
||||||
|
op in setOf(BinOp.PLUS, BinOp.MINUS, BinOp.STAR, BinOp.SLASH, BinOp.PERCENT)
|
||||||
|
) {
|
||||||
|
val leftObj = ensureObjSlot(a)
|
||||||
|
val rightObj = ensureObjSlot(b)
|
||||||
|
val out = allocSlot()
|
||||||
|
val objOpcode = when (op) {
|
||||||
|
BinOp.PLUS -> Opcode.ADD_OBJ
|
||||||
|
BinOp.MINUS -> Opcode.SUB_OBJ
|
||||||
|
BinOp.STAR -> Opcode.MUL_OBJ
|
||||||
|
BinOp.SLASH -> Opcode.DIV_OBJ
|
||||||
|
BinOp.PERCENT -> Opcode.MOD_OBJ
|
||||||
|
else -> null
|
||||||
|
} ?: return null
|
||||||
|
builder.emit(objOpcode, leftObj.slot, rightObj.slot, out)
|
||||||
|
return CompiledValue(out, SlotType.OBJ)
|
||||||
|
}
|
||||||
|
if (typesMismatch && !allowMixedNumeric &&
|
||||||
|
op !in setOf(BinOp.EQ, BinOp.NEQ, BinOp.LT, BinOp.LTE, BinOp.GT, BinOp.GTE)
|
||||||
|
) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val out = allocSlot()
|
val out = allocSlot()
|
||||||
@ -876,13 +922,32 @@ class BytecodeCompiler(
|
|||||||
if (!allowLocalSlots) return null
|
if (!allowLocalSlots) return null
|
||||||
if (!localTarget.isMutable || localTarget.isDelegated) return null
|
if (!localTarget.isMutable || localTarget.isDelegated) return null
|
||||||
val value = compileRef(assignValue(ref)) ?: return null
|
val value = compileRef(assignValue(ref)) ?: return null
|
||||||
val slot = resolveSlot(localTarget) ?: return null
|
val resolvedSlot = resolveSlot(localTarget) ?: return null
|
||||||
|
val slot = if (resolvedSlot < scopeSlotCount && localTarget.captureOwnerScopeId == null) {
|
||||||
|
localSlotIndexByName[localTarget.name]?.let { scopeSlotCount + it } ?: resolvedSlot
|
||||||
|
} else {
|
||||||
|
resolvedSlot
|
||||||
|
}
|
||||||
if (slot < scopeSlotCount && value.type != SlotType.UNKNOWN) {
|
if (slot < scopeSlotCount && value.type != SlotType.UNKNOWN) {
|
||||||
val addrSlot = ensureScopeAddr(slot)
|
val addrSlot = ensureScopeAddr(slot)
|
||||||
emitStoreToAddr(value.slot, addrSlot, value.type)
|
emitStoreToAddr(value.slot, addrSlot, value.type)
|
||||||
|
if (localTarget.captureOwnerScopeId == null) {
|
||||||
|
localSlotIndexByName[localTarget.name]?.let { mirror ->
|
||||||
|
val mirrorSlot = scopeSlotCount + mirror
|
||||||
|
emitMove(value, mirrorSlot)
|
||||||
|
updateSlotType(mirrorSlot, value.type)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (slot < scopeSlotCount) {
|
} else if (slot < scopeSlotCount) {
|
||||||
val addrSlot = ensureScopeAddr(slot)
|
val addrSlot = ensureScopeAddr(slot)
|
||||||
emitStoreToAddr(value.slot, addrSlot, SlotType.OBJ)
|
emitStoreToAddr(value.slot, addrSlot, SlotType.OBJ)
|
||||||
|
if (localTarget.captureOwnerScopeId == null) {
|
||||||
|
localSlotIndexByName[localTarget.name]?.let { mirror ->
|
||||||
|
val mirrorSlot = scopeSlotCount + mirror
|
||||||
|
emitMove(value, mirrorSlot)
|
||||||
|
updateSlotType(mirrorSlot, value.type)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
when (value.type) {
|
when (value.type) {
|
||||||
SlotType.INT -> builder.emit(Opcode.MOVE_INT, value.slot, slot)
|
SlotType.INT -> builder.emit(Opcode.MOVE_INT, value.slot, slot)
|
||||||
@ -2119,13 +2184,48 @@ class BytecodeCompiler(
|
|||||||
|
|
||||||
private fun compileLoopBody(stmt: Statement, needResult: Boolean): CompiledValue? {
|
private fun compileLoopBody(stmt: Statement, needResult: Boolean): CompiledValue? {
|
||||||
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
||||||
return if (target is BlockStatement) emitInlineBlock(target, needResult)
|
if (target is BlockStatement) {
|
||||||
else compileStatementValueOrFallback(target, needResult)
|
val useInline = target.slotPlan.isEmpty() && target.captureSlots.isEmpty()
|
||||||
|
return if (useInline) emitInlineBlock(target, needResult) else emitBlock(target, needResult)
|
||||||
|
}
|
||||||
|
return compileStatementValueOrFallback(target, needResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun emitVarDecl(stmt: VarDeclStatement): CompiledValue? {
|
private fun emitVarDecl(stmt: VarDeclStatement): CompiledValue? {
|
||||||
|
val scopeId = stmt.scopeId ?: 0
|
||||||
|
val scopeSlot = stmt.slotIndex?.let { slotIndex ->
|
||||||
|
val key = ScopeSlotKey(scopeId, slotIndex)
|
||||||
|
scopeSlotMap[key]
|
||||||
|
} ?: run {
|
||||||
|
if (scopeId == 0) {
|
||||||
|
scopeSlotIndexByName[stmt.name]
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (scopeId == 0 && scopeSlot != null) {
|
||||||
|
val value = stmt.initializer?.let { compileStatementValueOrFallback(it) } ?: run {
|
||||||
|
builder.emit(Opcode.CONST_NULL, scopeSlot)
|
||||||
|
updateSlotType(scopeSlot, SlotType.OBJ)
|
||||||
|
CompiledValue(scopeSlot, SlotType.OBJ)
|
||||||
|
}
|
||||||
|
if (value.slot != scopeSlot) {
|
||||||
|
emitMove(value, scopeSlot)
|
||||||
|
}
|
||||||
|
updateSlotType(scopeSlot, value.type)
|
||||||
|
val declId = builder.addConst(
|
||||||
|
BytecodeConst.LocalDecl(
|
||||||
|
stmt.name,
|
||||||
|
stmt.isMutable,
|
||||||
|
stmt.visibility,
|
||||||
|
stmt.isTransient
|
||||||
|
)
|
||||||
|
)
|
||||||
|
builder.emit(Opcode.DECL_LOCAL, declId, scopeSlot)
|
||||||
|
return CompiledValue(scopeSlot, value.type)
|
||||||
|
}
|
||||||
val localSlot = if (allowLocalSlots && stmt.slotIndex != null) {
|
val localSlot = if (allowLocalSlots && stmt.slotIndex != null) {
|
||||||
val key = ScopeSlotKey(stmt.scopeId ?: 0, stmt.slotIndex)
|
val key = ScopeSlotKey(scopeId, stmt.slotIndex)
|
||||||
val localIndex = localSlotIndexByKey[key]
|
val localIndex = localSlotIndexByKey[key]
|
||||||
localIndex?.let { scopeSlotCount + it }
|
localIndex?.let { scopeSlotCount + it }
|
||||||
} else {
|
} else {
|
||||||
@ -2152,6 +2252,27 @@ class BytecodeCompiler(
|
|||||||
builder.emit(Opcode.DECL_LOCAL, declId, localSlot)
|
builder.emit(Opcode.DECL_LOCAL, declId, localSlot)
|
||||||
return CompiledValue(localSlot, value.type)
|
return CompiledValue(localSlot, value.type)
|
||||||
}
|
}
|
||||||
|
if (scopeSlot != null) {
|
||||||
|
val value = stmt.initializer?.let { compileStatementValueOrFallback(it) } ?: run {
|
||||||
|
builder.emit(Opcode.CONST_NULL, scopeSlot)
|
||||||
|
updateSlotType(scopeSlot, SlotType.OBJ)
|
||||||
|
CompiledValue(scopeSlot, SlotType.OBJ)
|
||||||
|
}
|
||||||
|
if (value.slot != scopeSlot) {
|
||||||
|
emitMove(value, scopeSlot)
|
||||||
|
}
|
||||||
|
updateSlotType(scopeSlot, value.type)
|
||||||
|
val declId = builder.addConst(
|
||||||
|
BytecodeConst.LocalDecl(
|
||||||
|
stmt.name,
|
||||||
|
stmt.isMutable,
|
||||||
|
stmt.visibility,
|
||||||
|
stmt.isTransient
|
||||||
|
)
|
||||||
|
)
|
||||||
|
builder.emit(Opcode.DECL_LOCAL, declId, scopeSlot)
|
||||||
|
return CompiledValue(scopeSlot, value.type)
|
||||||
|
}
|
||||||
val value = stmt.initializer?.let { compileStatementValueOrFallback(it) } ?: run {
|
val value = stmt.initializer?.let { compileStatementValueOrFallback(it) } ?: run {
|
||||||
val slot = allocSlot()
|
val slot = allocSlot()
|
||||||
builder.emit(Opcode.CONST_NULL, slot)
|
builder.emit(Opcode.CONST_NULL, slot)
|
||||||
@ -2839,6 +2960,12 @@ class BytecodeCompiler(
|
|||||||
private fun refPos(ref: BinaryOpRef): Pos = Pos.builtIn
|
private fun refPos(ref: BinaryOpRef): Pos = Pos.builtIn
|
||||||
|
|
||||||
private fun resolveSlot(ref: LocalSlotRef): Int? {
|
private fun resolveSlot(ref: LocalSlotRef): Int? {
|
||||||
|
val scopeId = refScopeId(ref)
|
||||||
|
if (scopeId == 0) {
|
||||||
|
val key = ScopeSlotKey(scopeId, refSlot(ref))
|
||||||
|
scopeSlotMap[key]?.let { return it }
|
||||||
|
scopeSlotIndexByName[ref.name]?.let { return it }
|
||||||
|
}
|
||||||
if (ref.captureOwnerScopeId != null) {
|
if (ref.captureOwnerScopeId != null) {
|
||||||
val scopeKey = ScopeSlotKey(refScopeId(ref), refSlot(ref))
|
val scopeKey = ScopeSlotKey(refScopeId(ref), refSlot(ref))
|
||||||
return scopeSlotMap[scopeKey]
|
return scopeSlotMap[scopeKey]
|
||||||
|
|||||||
@ -298,7 +298,7 @@ class CmdStoreBoolAddr(internal val src: Int, internal val addrSlot: Int) : Cmd(
|
|||||||
|
|
||||||
class CmdIntToReal(internal val src: Int, internal val dst: Int) : Cmd() {
|
class CmdIntToReal(internal val src: Int, internal val dst: Int) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
frame.setReal(dst, frame.getInt(src).toDouble())
|
frame.setReal(dst, frame.getReal(src))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -319,7 +319,7 @@ class CmdBoolToInt(internal val src: Int, internal val dst: Int) : Cmd() {
|
|||||||
|
|
||||||
class CmdIntToBool(internal val src: Int, internal val dst: Int) : Cmd() {
|
class CmdIntToBool(internal val src: Int, internal val dst: Int) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
frame.setBool(dst, frame.getInt(src) != 0L)
|
frame.setBool(dst, frame.getBool(src))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1039,7 +1039,7 @@ class CmdPushScope(internal val planId: Int) : Cmd() {
|
|||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
val planConst = frame.fn.constants[planId] as? BytecodeConst.SlotPlan
|
val planConst = frame.fn.constants[planId] as? BytecodeConst.SlotPlan
|
||||||
?: error("PUSH_SCOPE expects SlotPlan at $planId")
|
?: error("PUSH_SCOPE expects SlotPlan at $planId")
|
||||||
frame.pushScope(planConst.plan)
|
frame.pushScope(planConst.plan, planConst.captures)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1504,6 +1504,7 @@ class CmdFrame(
|
|||||||
internal val scopeVirtualStack = ArrayDeque<Boolean>()
|
internal val scopeVirtualStack = ArrayDeque<Boolean>()
|
||||||
internal val slotPlanStack = ArrayDeque<Map<String, Int?>>()
|
internal val slotPlanStack = ArrayDeque<Map<String, Int?>>()
|
||||||
internal val slotPlanScopeStack = ArrayDeque<Boolean>()
|
internal val slotPlanScopeStack = ArrayDeque<Boolean>()
|
||||||
|
private val captureStack = ArrayDeque<List<String>>()
|
||||||
private var scopeDepth = 0
|
private var scopeDepth = 0
|
||||||
private var virtualDepth = 0
|
private var virtualDepth = 0
|
||||||
private val iterStack = ArrayDeque<Obj>()
|
private val iterStack = ArrayDeque<Obj>()
|
||||||
@ -1519,7 +1520,11 @@ class CmdFrame(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pushScope(plan: Map<String, Int>) {
|
fun pushScope(plan: Map<String, Int>, captures: List<String>) {
|
||||||
|
val parentScope = scope
|
||||||
|
if (captures.isNotEmpty() && fn.localSlotNames.isNotEmpty()) {
|
||||||
|
syncFrameToScope()
|
||||||
|
}
|
||||||
if (scope.skipScopeCreation) {
|
if (scope.skipScopeCreation) {
|
||||||
val snapshot = scope.applySlotPlanWithSnapshot(plan)
|
val snapshot = scope.applySlotPlanWithSnapshot(plan)
|
||||||
slotPlanStack.addLast(snapshot)
|
slotPlanStack.addLast(snapshot)
|
||||||
@ -1534,6 +1539,14 @@ class CmdFrame(
|
|||||||
scope.applySlotPlan(plan)
|
scope.applySlotPlan(plan)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (captures.isNotEmpty()) {
|
||||||
|
for (name in captures) {
|
||||||
|
val rec = parentScope.resolveCaptureRecord(name)
|
||||||
|
?: parentScope.raiseSymbolNotFound("symbol ${name} not found")
|
||||||
|
scope.updateSlotFor(name, rec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
captureStack.addLast(captures)
|
||||||
scopeDepth += 1
|
scopeDepth += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1548,7 +1561,11 @@ class CmdFrame(
|
|||||||
}
|
}
|
||||||
scope = scopeStack.removeLastOrNull()
|
scope = scopeStack.removeLastOrNull()
|
||||||
?: error("Scope stack underflow in POP_SCOPE")
|
?: error("Scope stack underflow in POP_SCOPE")
|
||||||
|
val captures = captureStack.removeLastOrNull() ?: emptyList()
|
||||||
scopeDepth -= 1
|
scopeDepth -= 1
|
||||||
|
if (captures.isNotEmpty() && fn.localSlotNames.isNotEmpty()) {
|
||||||
|
syncScopeToFrame()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pushIterator(iter: Obj) {
|
fun pushIterator(iter: Obj) {
|
||||||
@ -1613,7 +1630,7 @@ class CmdFrame(
|
|||||||
|
|
||||||
fun setObj(slot: Int, value: Obj) {
|
fun setObj(slot: Int, value: Obj) {
|
||||||
if (slot < fn.scopeSlotCount) {
|
if (slot < fn.scopeSlotCount) {
|
||||||
val target = resolveScope(scope, fn.scopeSlotDepths[slot])
|
val target = scope
|
||||||
val index = ensureScopeSlot(target, slot)
|
val index = ensureScopeSlot(target, slot)
|
||||||
target.setSlotValue(index, value)
|
target.setSlotValue(index, value)
|
||||||
} else {
|
} else {
|
||||||
@ -1625,7 +1642,14 @@ class CmdFrame(
|
|||||||
return if (slot < fn.scopeSlotCount) {
|
return if (slot < fn.scopeSlotCount) {
|
||||||
getScopeSlotValue(slot).toLong()
|
getScopeSlotValue(slot).toLong()
|
||||||
} else {
|
} else {
|
||||||
frame.getInt(slot - fn.scopeSlotCount)
|
val local = slot - fn.scopeSlotCount
|
||||||
|
when (frame.getSlotTypeCode(local)) {
|
||||||
|
SlotType.INT.code -> frame.getInt(local)
|
||||||
|
SlotType.REAL.code -> frame.getReal(local).toLong()
|
||||||
|
SlotType.BOOL.code -> if (frame.getBool(local)) 1L else 0L
|
||||||
|
SlotType.OBJ.code -> frame.getObj(local).toLong()
|
||||||
|
else -> 0L
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1633,7 +1657,7 @@ class CmdFrame(
|
|||||||
|
|
||||||
fun setInt(slot: Int, value: Long) {
|
fun setInt(slot: Int, value: Long) {
|
||||||
if (slot < fn.scopeSlotCount) {
|
if (slot < fn.scopeSlotCount) {
|
||||||
val target = resolveScope(scope, fn.scopeSlotDepths[slot])
|
val target = scope
|
||||||
val index = ensureScopeSlot(target, slot)
|
val index = ensureScopeSlot(target, slot)
|
||||||
target.setSlotValue(index, ObjInt.of(value))
|
target.setSlotValue(index, ObjInt.of(value))
|
||||||
} else {
|
} else {
|
||||||
@ -1649,13 +1673,20 @@ class CmdFrame(
|
|||||||
return if (slot < fn.scopeSlotCount) {
|
return if (slot < fn.scopeSlotCount) {
|
||||||
getScopeSlotValue(slot).toDouble()
|
getScopeSlotValue(slot).toDouble()
|
||||||
} else {
|
} else {
|
||||||
frame.getReal(slot - fn.scopeSlotCount)
|
val local = slot - fn.scopeSlotCount
|
||||||
|
when (frame.getSlotTypeCode(local)) {
|
||||||
|
SlotType.REAL.code -> frame.getReal(local)
|
||||||
|
SlotType.INT.code -> frame.getInt(local).toDouble()
|
||||||
|
SlotType.BOOL.code -> if (frame.getBool(local)) 1.0 else 0.0
|
||||||
|
SlotType.OBJ.code -> frame.getObj(local).toDouble()
|
||||||
|
else -> 0.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setReal(slot: Int, value: Double) {
|
fun setReal(slot: Int, value: Double) {
|
||||||
if (slot < fn.scopeSlotCount) {
|
if (slot < fn.scopeSlotCount) {
|
||||||
val target = resolveScope(scope, fn.scopeSlotDepths[slot])
|
val target = scope
|
||||||
val index = ensureScopeSlot(target, slot)
|
val index = ensureScopeSlot(target, slot)
|
||||||
target.setSlotValue(index, ObjReal.of(value))
|
target.setSlotValue(index, ObjReal.of(value))
|
||||||
} else {
|
} else {
|
||||||
@ -1667,7 +1698,14 @@ class CmdFrame(
|
|||||||
return if (slot < fn.scopeSlotCount) {
|
return if (slot < fn.scopeSlotCount) {
|
||||||
getScopeSlotValue(slot).toBool()
|
getScopeSlotValue(slot).toBool()
|
||||||
} else {
|
} else {
|
||||||
frame.getBool(slot - fn.scopeSlotCount)
|
val local = slot - fn.scopeSlotCount
|
||||||
|
when (frame.getSlotTypeCode(local)) {
|
||||||
|
SlotType.BOOL.code -> frame.getBool(local)
|
||||||
|
SlotType.INT.code -> frame.getInt(local) != 0L
|
||||||
|
SlotType.REAL.code -> frame.getReal(local) != 0.0
|
||||||
|
SlotType.OBJ.code -> frame.getObj(local).toBool()
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1675,7 +1713,7 @@ class CmdFrame(
|
|||||||
|
|
||||||
fun setBool(slot: Int, value: Boolean) {
|
fun setBool(slot: Int, value: Boolean) {
|
||||||
if (slot < fn.scopeSlotCount) {
|
if (slot < fn.scopeSlotCount) {
|
||||||
val target = resolveScope(scope, fn.scopeSlotDepths[slot])
|
val target = scope
|
||||||
val index = ensureScopeSlot(target, slot)
|
val index = ensureScopeSlot(target, slot)
|
||||||
target.setSlotValue(index, if (value) ObjTrue else ObjFalse)
|
target.setSlotValue(index, if (value) ObjTrue else ObjFalse)
|
||||||
} else {
|
} else {
|
||||||
@ -1688,7 +1726,7 @@ class CmdFrame(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun resolveScopeSlotAddr(scopeSlot: Int, addrSlot: Int) {
|
fun resolveScopeSlotAddr(scopeSlot: Int, addrSlot: Int) {
|
||||||
val target = resolveScope(scope, fn.scopeSlotDepths[scopeSlot])
|
val target = scope
|
||||||
val index = ensureScopeSlot(target, scopeSlot)
|
val index = ensureScopeSlot(target, scopeSlot)
|
||||||
addrScopes[addrSlot] = target
|
addrScopes[addrSlot] = target
|
||||||
addrIndices[addrSlot] = index
|
addrIndices[addrSlot] = index
|
||||||
@ -1877,10 +1915,7 @@ class CmdFrame(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveLocalScope(localIndex: Int): Scope? {
|
private fun resolveLocalScope(localIndex: Int): Scope? {
|
||||||
val depth = fn.localSlotDepths.getOrNull(localIndex) ?: return scope
|
return scope
|
||||||
val relativeDepth = scopeDepth - depth
|
|
||||||
if (relativeDepth < 0) return null
|
|
||||||
return if (relativeDepth == 0) scope else resolveScope(scope, relativeDepth)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun localSlotToObj(localIndex: Int): Obj {
|
private fun localSlotToObj(localIndex: Int): Obj {
|
||||||
@ -1894,7 +1929,7 @@ class CmdFrame(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getScopeSlotValue(slot: Int): Obj {
|
private fun getScopeSlotValue(slot: Int): Obj {
|
||||||
val target = resolveScope(scope, fn.scopeSlotDepths[slot])
|
val target = scope
|
||||||
val index = ensureScopeSlot(target, slot)
|
val index = ensureScopeSlot(target, slot)
|
||||||
val record = target.getSlotRecord(index)
|
val record = target.getSlotRecord(index)
|
||||||
if (record.value !== ObjUnset) return record.value
|
if (record.value !== ObjUnset) return record.value
|
||||||
@ -1933,8 +1968,10 @@ class CmdFrame(
|
|||||||
if (existing != null) return existing
|
if (existing != null) return existing
|
||||||
}
|
}
|
||||||
val index = fn.scopeSlotIndices[slot]
|
val index = fn.scopeSlotIndices[slot]
|
||||||
if (index < target.slotCount) return index
|
if (name == null) {
|
||||||
if (name == null) return index
|
if (index < target.slotCount) 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)
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
@ -1948,18 +1985,5 @@ class CmdFrame(
|
|||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveScope(start: Scope, depth: Int): Scope {
|
// Scope depth resolution is no longer used; all scope slots are resolved against the current frame.
|
||||||
if (depth == 0) return start
|
|
||||||
var effectiveDepth = depth
|
|
||||||
if (virtualDepth > 0) {
|
|
||||||
if (effectiveDepth <= virtualDepth) return start
|
|
||||||
effectiveDepth -= virtualDepth
|
|
||||||
}
|
|
||||||
val next = when (start) {
|
|
||||||
is net.sergeych.lyng.ClosureScope -> start.closureScope
|
|
||||||
else -> start.parent
|
|
||||||
}
|
|
||||||
return next?.let { resolveScope(it, effectiveDepth - 1) }
|
|
||||||
?: error("Scope depth $depth is out of range")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -652,7 +652,6 @@ class ScriptTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("incremental enable")
|
|
||||||
@Test
|
@Test
|
||||||
fun whileAssignTest() = runTest {
|
fun whileAssignTest() = runTest {
|
||||||
eval(
|
eval(
|
||||||
@ -665,7 +664,6 @@ class ScriptTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("incremental enable")
|
|
||||||
@Test
|
@Test
|
||||||
fun whileTest() = runTest {
|
fun whileTest() = runTest {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -720,7 +718,6 @@ class ScriptTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("incremental enable")
|
|
||||||
@Test
|
@Test
|
||||||
fun testAssignArgumentsNoEllipsis() = runTest {
|
fun testAssignArgumentsNoEllipsis() = runTest {
|
||||||
// equal args, no ellipsis, no defaults, ok
|
// equal args, no ellipsis, no defaults, ok
|
||||||
@ -762,7 +759,7 @@ class ScriptTest {
|
|||||||
assertEquals(ObjInt(5), c["c"]?.value)
|
assertEquals(ObjInt(5), c["c"]?.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("incremental enable")
|
@Ignore("Scope.eval should seed compile-time symbols from current scope")
|
||||||
@Test
|
@Test
|
||||||
fun testAssignArgumentsEndEllipsis() = runTest {
|
fun testAssignArgumentsEndEllipsis() = runTest {
|
||||||
// equal args,
|
// equal args,
|
||||||
@ -864,7 +861,6 @@ class ScriptTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("incremental enable")
|
|
||||||
@Test
|
@Test
|
||||||
fun testWhileBlockIsolation1() = runTest {
|
fun testWhileBlockIsolation1() = runTest {
|
||||||
eval(
|
eval(
|
||||||
@ -881,7 +877,6 @@ class ScriptTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("incremental enable")
|
|
||||||
@Test
|
@Test
|
||||||
fun testWhileBlockIsolation2() = runTest {
|
fun testWhileBlockIsolation2() = runTest {
|
||||||
assertFails {
|
assertFails {
|
||||||
@ -924,7 +919,7 @@ class ScriptTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("incremental enable")
|
@Ignore("bytecode fallback in labeled break")
|
||||||
@Test
|
@Test
|
||||||
fun whileNonLocalBreakTest() = runTest {
|
fun whileNonLocalBreakTest() = runTest {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user