Add bytecode destructuring assignment
This commit is contained in:
parent
780227a229
commit
694d15c69d
@ -36,8 +36,8 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
|
||||
- [x] Support `ClassDeclStatement`, `FunctionDeclStatement`, `EnumDeclStatement` in bytecode compilation.
|
||||
- [x] Keep a mixed execution path for declarations (module bytecode calls statement bodies via `CALL_SLOT`).
|
||||
- [x] Ensure module object member refs compile as instance access (not class-scope).
|
||||
- [ ] Step 11: Destructuring assignment bytecode.
|
||||
- [ ] Handle `[a, b] = expr` (AssignRef target `ListLiteralRef`) without interpreter fallback.
|
||||
- [x] Step 11: Destructuring assignment bytecode.
|
||||
- [x] Handle `[a, b] = expr` (AssignRef target `ListLiteralRef`) without interpreter fallback.
|
||||
- [ ] Step 12: Optional member assign-ops and inc/dec in bytecode.
|
||||
- [ ] Support `a?.b += 1` and `a?.b++` for `FieldRef` targets.
|
||||
- [x] Fix post-inc return value for object slots stored in scope frames.
|
||||
|
||||
@ -1949,9 +1949,12 @@ class Compiler(
|
||||
is CastRef -> containsUnsupportedRef(ref.castValueRef()) || containsUnsupportedRef(ref.castTypeRef())
|
||||
is net.sergeych.lyng.obj.TypeDeclRef -> false
|
||||
is AssignRef -> {
|
||||
if (ref.target is ListLiteralRef) return true
|
||||
val target = ref.target as? LocalSlotRef
|
||||
(target?.isDelegated == true) || containsUnsupportedRef(ref.value)
|
||||
if (target != null) {
|
||||
(target.isDelegated) || containsUnsupportedRef(ref.value)
|
||||
} else {
|
||||
containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
||||
}
|
||||
}
|
||||
is AssignOpRef -> containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
||||
is AssignIfNullRef -> containsUnsupportedRef(ref.target) || containsUnsupportedRef(ref.value)
|
||||
|
||||
@ -1700,6 +1700,15 @@ class BytecodeCompiler(
|
||||
updateNameObjClassFromSlot(nameTarget, slot)
|
||||
return value
|
||||
}
|
||||
val listTarget = ref.target as? ListLiteralRef
|
||||
if (listTarget != null) {
|
||||
val value = compileRef(assignValue(ref)) ?: return null
|
||||
val valueObj = ensureObjSlot(value)
|
||||
val declId = builder.addConst(BytecodeConst.DestructureAssign(listTarget, callSitePos()))
|
||||
builder.emit(Opcode.ASSIGN_DESTRUCTURE, declId, valueObj.slot)
|
||||
updateSlotType(valueObj.slot, SlotType.OBJ)
|
||||
return CompiledValue(valueObj.slot, SlotType.OBJ)
|
||||
}
|
||||
val value = compileRef(assignValue(ref)) ?: return null
|
||||
val target = ref.target
|
||||
if (target is ClassScopeMemberRef) {
|
||||
@ -6252,7 +6261,11 @@ class BytecodeCompiler(
|
||||
is CastRef -> containsValueFnRef(ref.castValueRef()) || containsValueFnRef(ref.castTypeRef())
|
||||
is AssignRef -> {
|
||||
val target = assignTarget(ref)
|
||||
(target != null && containsValueFnRef(target)) || containsValueFnRef(assignValue(ref))
|
||||
if (target != null) {
|
||||
containsValueFnRef(target) || containsValueFnRef(assignValue(ref))
|
||||
} else {
|
||||
containsValueFnRef(ref.target) || containsValueFnRef(assignValue(ref))
|
||||
}
|
||||
}
|
||||
is AssignOpRef -> containsValueFnRef(ref.target) || containsValueFnRef(ref.value)
|
||||
is AssignIfNullRef -> containsValueFnRef(ref.target) || containsValueFnRef(ref.value)
|
||||
|
||||
@ -61,6 +61,10 @@ sealed class BytecodeConst {
|
||||
val isTransient: Boolean,
|
||||
val pos: Pos,
|
||||
) : BytecodeConst()
|
||||
data class DestructureAssign(
|
||||
val pattern: ListLiteralRef,
|
||||
val pos: Pos,
|
||||
) : BytecodeConst()
|
||||
data class CallArgsPlan(val tailBlock: Boolean, val specs: List<CallArgSpec>) : BytecodeConst()
|
||||
data class CallArgSpec(val name: String?, val isSplat: Boolean)
|
||||
}
|
||||
|
||||
@ -147,7 +147,8 @@ class CmdBuilder {
|
||||
listOf(OperandKind.CONST)
|
||||
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_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE,
|
||||
Opcode.ASSIGN_DESTRUCTURE ->
|
||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
||||
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
|
||||
@ -398,6 +399,7 @@ class CmdBuilder {
|
||||
Opcode.DECL_DESTRUCTURE -> CmdDeclDestructure(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])
|
||||
Opcode.CALL_MEMBER_SLOT -> CmdCallMemberSlot(operands[0], operands[1], operands[2], operands[3], operands[4])
|
||||
Opcode.CALL_SLOT -> CmdCallSlot(operands[0], operands[1], operands[2], operands[3])
|
||||
Opcode.CALL_DYNAMIC_MEMBER -> CmdCallDynamicMember(operands[0], operands[1], operands[2], operands[3], operands[4])
|
||||
|
||||
@ -193,6 +193,7 @@ object CmdDisassembler {
|
||||
is CmdDeclDestructure -> Opcode.DECL_DESTRUCTURE 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)
|
||||
is CmdCallMemberSlot -> Opcode.CALL_MEMBER_SLOT to intArrayOf(cmd.recvSlot, cmd.methodId, cmd.argBase, cmd.argCount, cmd.dst)
|
||||
is CmdCallSlot -> Opcode.CALL_SLOT to intArrayOf(cmd.calleeSlot, cmd.argBase, cmd.argCount, cmd.dst)
|
||||
is CmdCallDynamicMember -> Opcode.CALL_DYNAMIC_MEMBER to intArrayOf(cmd.recvSlot, cmd.nameId, cmd.argBase, cmd.argCount, cmd.dst)
|
||||
@ -254,7 +255,8 @@ object CmdDisassembler {
|
||||
listOf(OperandKind.CONST)
|
||||
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_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE,
|
||||
Opcode.ASSIGN_DESTRUCTURE ->
|
||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
||||
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
|
||||
|
||||
@ -1272,7 +1272,26 @@ class CmdDeclDestructure(internal val constId: Int, internal val slot: Int) : Cm
|
||||
scope.updateSlotFor(name, immutableRec)
|
||||
}
|
||||
}
|
||||
if (slot >= frame.fn.scopeSlotCount) {
|
||||
frame.storeObjResult(slot, ObjVoid)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
class CmdAssignDestructure(internal val constId: Int, internal val slot: Int) : Cmd() {
|
||||
override suspend fun perform(frame: CmdFrame) {
|
||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
||||
frame.syncFrameToScope(useRefs = true)
|
||||
}
|
||||
val decl = frame.fn.constants[constId] as? BytecodeConst.DestructureAssign
|
||||
?: error("ASSIGN_DESTRUCTURE expects DestructureAssign at $constId")
|
||||
val value = frame.slotToObj(slot)
|
||||
decl.pattern.setAt(decl.pos, frame.ensureScope(), value)
|
||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
||||
frame.syncScopeToFrame()
|
||||
}
|
||||
frame.storeObjResult(slot, value)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,6 +132,7 @@ enum class Opcode(val code: Int) {
|
||||
CLEAR_PENDING_THROWABLE(0x8F),
|
||||
|
||||
CALL_DIRECT(0x90),
|
||||
ASSIGN_DESTRUCTURE(0x91),
|
||||
CALL_MEMBER_SLOT(0x92),
|
||||
CALL_SLOT(0x93),
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user