Compile this-slot method calls to bytecode
This commit is contained in:
parent
951ce989a6
commit
aebe0890d8
@ -176,8 +176,8 @@ class BytecodeCompiler(
|
||||
}
|
||||
is LocalVarRef -> compileNameLookup(ref.name)
|
||||
is ValueFnRef -> compileEvalRef(ref)
|
||||
is ListLiteralRef -> compileEvalRef(ref)
|
||||
is ThisMethodSlotCallRef -> compileEvalRef(ref)
|
||||
is ListLiteralRef -> compileListLiteral(ref)
|
||||
is ThisMethodSlotCallRef -> compileThisMethodSlotCall(ref)
|
||||
is StatementRef -> {
|
||||
val constId = builder.addConst(BytecodeConst.StatementVal(ref.statement))
|
||||
val slot = allocSlot()
|
||||
@ -246,6 +246,29 @@ class BytecodeCompiler(
|
||||
return CompiledValue(slot, SlotType.OBJ)
|
||||
}
|
||||
|
||||
private fun compileListLiteral(ref: ListLiteralRef): CompiledValue? {
|
||||
val entries = ref.entries()
|
||||
val count = entries.size
|
||||
val baseSlot = nextSlot
|
||||
val entrySlots = IntArray(count) { allocSlot() }
|
||||
val spreads = ArrayList<Boolean>(count)
|
||||
for ((index, entry) in entries.withIndex()) {
|
||||
val value = when (entry) {
|
||||
is net.sergeych.lyng.ListEntry.Element ->
|
||||
compileRefWithFallback(entry.ref, null, Pos.builtIn)
|
||||
is net.sergeych.lyng.ListEntry.Spread ->
|
||||
compileRefWithFallback(entry.ref, null, Pos.builtIn)
|
||||
} ?: return null
|
||||
emitMove(value, entrySlots[index])
|
||||
spreads.add(entry is net.sergeych.lyng.ListEntry.Spread)
|
||||
}
|
||||
val planId = builder.addConst(BytecodeConst.ListLiteralPlan(spreads))
|
||||
val dst = allocSlot()
|
||||
builder.emit(Opcode.LIST_LITERAL, planId, baseSlot, count, dst)
|
||||
updateSlotType(dst, SlotType.OBJ)
|
||||
return CompiledValue(dst, SlotType.OBJ)
|
||||
}
|
||||
|
||||
private fun compileUnary(ref: UnaryOpRef): CompiledValue? {
|
||||
val a = compileRef(unaryOperand(ref)) ?: return null
|
||||
val out = allocSlot()
|
||||
@ -1484,6 +1507,37 @@ class BytecodeCompiler(
|
||||
return CompiledValue(dst, SlotType.OBJ)
|
||||
}
|
||||
|
||||
private fun compileThisMethodSlotCall(ref: ThisMethodSlotCallRef): CompiledValue? {
|
||||
val receiver = compileNameLookup("this")
|
||||
val methodId = builder.addConst(BytecodeConst.StringVal(ref.methodName()))
|
||||
if (methodId > 0xFFFF) return null
|
||||
val dst = allocSlot()
|
||||
if (!ref.optionalInvoke()) {
|
||||
val args = compileCallArgs(ref.arguments(), ref.hasTailBlock()) ?: return null
|
||||
val encodedCount = encodeCallArgCount(args) ?: return null
|
||||
builder.emit(Opcode.CALL_VIRTUAL, receiver.slot, methodId, args.base, encodedCount, dst)
|
||||
return CompiledValue(dst, SlotType.OBJ)
|
||||
}
|
||||
val nullSlot = allocSlot()
|
||||
builder.emit(Opcode.CONST_NULL, nullSlot)
|
||||
val cmpSlot = allocSlot()
|
||||
builder.emit(Opcode.CMP_REF_EQ_OBJ, receiver.slot, nullSlot, cmpSlot)
|
||||
val nullLabel = builder.label()
|
||||
val endLabel = builder.label()
|
||||
builder.emit(
|
||||
Opcode.JMP_IF_TRUE,
|
||||
listOf(CmdBuilder.Operand.IntVal(cmpSlot), CmdBuilder.Operand.LabelRef(nullLabel))
|
||||
)
|
||||
val args = compileCallArgs(ref.arguments(), ref.hasTailBlock()) ?: return null
|
||||
val encodedCount = encodeCallArgCount(args) ?: return null
|
||||
builder.emit(Opcode.CALL_VIRTUAL, receiver.slot, methodId, args.base, encodedCount, dst)
|
||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
||||
builder.mark(nullLabel)
|
||||
builder.emit(Opcode.CONST_NULL, dst)
|
||||
builder.mark(endLabel)
|
||||
return CompiledValue(dst, SlotType.OBJ)
|
||||
}
|
||||
|
||||
private data class CallArgs(val base: Int, val count: Int, val planId: Int?)
|
||||
|
||||
private fun compileCallArgs(args: List<ParsedArgument>, tailBlock: Boolean): CallArgs? {
|
||||
|
||||
@ -1865,6 +1865,11 @@ class ThisMethodSlotCallRef(
|
||||
private val tailBlock: Boolean,
|
||||
private val isOptional: Boolean
|
||||
) : ObjRef {
|
||||
internal fun methodName(): String = name
|
||||
internal fun arguments(): List<ParsedArgument> = args
|
||||
internal fun hasTailBlock(): Boolean = tailBlock
|
||||
internal fun optionalInvoke(): Boolean = isOptional
|
||||
|
||||
override suspend fun get(scope: Scope): ObjRecord = evalValue(scope).asReadonly
|
||||
|
||||
override suspend fun evalValue(scope: Scope): Obj {
|
||||
@ -2516,6 +2521,8 @@ class LocalSlotRef(
|
||||
}
|
||||
|
||||
class ListLiteralRef(private val entries: List<ListEntry>) : ObjRef {
|
||||
internal fun entries(): List<ListEntry> = entries
|
||||
|
||||
override fun forEachVariable(block: (String) -> Unit) {
|
||||
for (e in entries) {
|
||||
when (e) {
|
||||
@ -2665,9 +2672,9 @@ class RangeRef(
|
||||
|
||||
/** Assignment if null op: target ?= value */
|
||||
class AssignIfNullRef(
|
||||
private val target: ObjRef,
|
||||
private val value: ObjRef,
|
||||
private val atPos: Pos,
|
||||
internal val target: ObjRef,
|
||||
internal val value: ObjRef,
|
||||
internal val atPos: Pos,
|
||||
) : ObjRef {
|
||||
override suspend fun get(scope: Scope): ObjRecord {
|
||||
return evalValue(scope).asReadonly
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user