Step 6: support map spread in bytecode
This commit is contained in:
parent
026b023892
commit
3a46e59ec8
@ -23,8 +23,8 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
|
|||||||
- [x] Revisit `containsDelegatedRefs` guard for `DelegatedVarDeclStatement`.
|
- [x] Revisit `containsDelegatedRefs` guard for `DelegatedVarDeclStatement`.
|
||||||
- [x] Ensure delegate binding uses explicit `Statement` objects (no inline suspend lambdas).
|
- [x] Ensure delegate binding uses explicit `Statement` objects (no inline suspend lambdas).
|
||||||
- [x] Keep JVM tests green before commit.
|
- [x] Keep JVM tests green before commit.
|
||||||
- [ ] Step 6: Map literal spread in bytecode.
|
- [x] Step 6: Map literal spread in bytecode.
|
||||||
- [ ] Replace `MapLiteralEntry.Spread` bytecode exception with runtime `putAll`/merge logic.
|
- [x] Replace `MapLiteralEntry.Spread` bytecode exception with runtime `putAll`/merge logic.
|
||||||
- [ ] Step 7: Class-scope member refs in bytecode.
|
- [ ] Step 7: Class-scope member refs in bytecode.
|
||||||
- [ ] Support `ClassScopeMemberRef` without scope-map fallback.
|
- [ ] Support `ClassScopeMemberRef` without scope-map fallback.
|
||||||
- [ ] Step 8: ObjDynamic member access in bytecode.
|
- [ ] Step 8: ObjDynamic member access in bytecode.
|
||||||
|
|||||||
@ -529,7 +529,35 @@ class BytecodeCompiler(
|
|||||||
builder.emit(Opcode.SET_INDEX, dst, keySlot, value.slot)
|
builder.emit(Opcode.SET_INDEX, dst, keySlot, value.slot)
|
||||||
}
|
}
|
||||||
is net.sergeych.lyng.obj.MapLiteralEntry.Spread -> {
|
is net.sergeych.lyng.obj.MapLiteralEntry.Spread -> {
|
||||||
throw BytecodeCompileException("Map spread is not supported in bytecode", Pos.builtIn)
|
if (entry.ref is ListLiteralRef) {
|
||||||
|
throw BytecodeCompileException(
|
||||||
|
"spread element in map literal must be a Map",
|
||||||
|
Pos.builtIn
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val value = compileRefWithFallback(entry.ref, null, Pos.builtIn) ?: return null
|
||||||
|
val mapClassId = builder.addConst(BytecodeConst.ObjRef(ObjMap.type))
|
||||||
|
val mapClassSlot = allocSlot()
|
||||||
|
builder.emit(Opcode.CONST_OBJ, mapClassId, mapClassSlot)
|
||||||
|
val checkSlot = allocSlot()
|
||||||
|
builder.emit(Opcode.CHECK_IS, value.slot, mapClassSlot, checkSlot)
|
||||||
|
val okLabel = builder.label()
|
||||||
|
val endLabel = builder.label()
|
||||||
|
builder.emit(
|
||||||
|
Opcode.JMP_IF_TRUE,
|
||||||
|
listOf(CmdBuilder.Operand.IntVal(checkSlot), CmdBuilder.Operand.LabelRef(okLabel))
|
||||||
|
)
|
||||||
|
val msgId = builder.addConst(BytecodeConst.StringVal("spread element in map literal must be a Map"))
|
||||||
|
val msgSlot = allocSlot()
|
||||||
|
builder.emit(Opcode.CONST_OBJ, msgId, msgSlot)
|
||||||
|
val posId = builder.addConst(BytecodeConst.PosVal(Pos.builtIn))
|
||||||
|
builder.emit(Opcode.THROW, posId, msgSlot)
|
||||||
|
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
||||||
|
builder.mark(okLabel)
|
||||||
|
val mergedSlot = allocSlot()
|
||||||
|
builder.emit(Opcode.ADD_OBJ, dst, value.slot, mergedSlot)
|
||||||
|
builder.emit(Opcode.MOVE_OBJ, mergedSlot, dst)
|
||||||
|
builder.mark(endLabel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user