Add bytecode opcode for statement eval
This commit is contained in:
parent
9a15470cdb
commit
951ce989a6
@ -40,11 +40,14 @@ class BytecodeCompiler(
|
||||
private var scopeSlotNames = emptyArray<String?>()
|
||||
private val scopeSlotMap = LinkedHashMap<ScopeSlotKey, Int>()
|
||||
private val scopeSlotNameMap = LinkedHashMap<ScopeSlotKey, String>()
|
||||
private val scopeSlotIndexByName = LinkedHashMap<String, Int>()
|
||||
private val pendingScopeNameRefs = LinkedHashSet<String>()
|
||||
private val addrSlotByScopeSlot = LinkedHashMap<Int, Int>()
|
||||
private data class LocalSlotInfo(val name: String, val isMutable: Boolean, val depth: Int)
|
||||
private val localSlotInfoMap = LinkedHashMap<ScopeSlotKey, LocalSlotInfo>()
|
||||
private val localSlotIndexByKey = LinkedHashMap<ScopeSlotKey, Int>()
|
||||
private val localSlotIndexByName = LinkedHashMap<String, Int>()
|
||||
private val loopSlotOverrides = LinkedHashMap<String, Int>()
|
||||
private var localSlotNames = emptyArray<String?>()
|
||||
private var localSlotMutables = BooleanArray(0)
|
||||
private var localSlotDepths = IntArray(0)
|
||||
@ -70,12 +73,54 @@ class BytecodeCompiler(
|
||||
is net.sergeych.lyng.IfStatement -> compileIf(name, stmt)
|
||||
is net.sergeych.lyng.ForInStatement -> compileForIn(name, stmt)
|
||||
is net.sergeych.lyng.DoWhileStatement -> compileDoWhile(name, stmt)
|
||||
is net.sergeych.lyng.WhileStatement -> compileWhile(name, stmt)
|
||||
is BlockStatement -> compileBlock(name, stmt)
|
||||
is VarDeclStatement -> compileVarDecl(name, stmt)
|
||||
is net.sergeych.lyng.ThrowStatement -> compileThrowStatement(name, stmt)
|
||||
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> compileExtensionPropertyDecl(name, stmt)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun compileThrowStatement(name: String, stmt: net.sergeych.lyng.ThrowStatement): CmdFunction? {
|
||||
prepareCompilation(stmt)
|
||||
compileThrow(stmt) ?: return null
|
||||
return builder.build(
|
||||
name,
|
||||
localCount = nextSlot - scopeSlotCount,
|
||||
addrCount = nextAddrSlot,
|
||||
returnLabels = returnLabels,
|
||||
scopeSlotDepths,
|
||||
scopeSlotIndices,
|
||||
scopeSlotNames,
|
||||
localSlotNames,
|
||||
localSlotMutables,
|
||||
localSlotDepths
|
||||
)
|
||||
}
|
||||
|
||||
private fun compileExtensionPropertyDecl(
|
||||
name: String,
|
||||
stmt: net.sergeych.lyng.ExtensionPropertyDeclStatement,
|
||||
): CmdFunction? {
|
||||
prepareCompilation(stmt)
|
||||
val value = emitExtensionPropertyDecl(stmt)
|
||||
builder.emit(Opcode.RET, value.slot)
|
||||
val localCount = maxOf(nextSlot, value.slot + 1) - scopeSlotCount
|
||||
return builder.build(
|
||||
name,
|
||||
localCount,
|
||||
addrCount = nextAddrSlot,
|
||||
returnLabels = returnLabels,
|
||||
scopeSlotDepths,
|
||||
scopeSlotIndices,
|
||||
scopeSlotNames,
|
||||
localSlotNames,
|
||||
localSlotMutables,
|
||||
localSlotDepths
|
||||
)
|
||||
}
|
||||
|
||||
fun compileExpression(name: String, stmt: ExpressionStatement): CmdFunction? {
|
||||
prepareCompilation(stmt)
|
||||
val value = compileRefWithFallback(stmt.ref, null, stmt.pos) ?: return null
|
||||
@ -99,6 +144,14 @@ class BytecodeCompiler(
|
||||
|
||||
private fun allocSlot(): Int = nextSlot++
|
||||
|
||||
private fun compileNameLookup(name: String): CompiledValue {
|
||||
val nameId = builder.addConst(BytecodeConst.StringVal(name))
|
||||
val slot = allocSlot()
|
||||
builder.emit(Opcode.GET_NAME, nameId, slot)
|
||||
updateSlotType(slot, SlotType.OBJ)
|
||||
return CompiledValue(slot, SlotType.OBJ)
|
||||
}
|
||||
|
||||
private fun compileRef(ref: ObjRef): CompiledValue? {
|
||||
return when (ref) {
|
||||
is ConstRef -> compileConst(ref.constValue)
|
||||
@ -106,7 +159,7 @@ class BytecodeCompiler(
|
||||
if (!allowLocalSlots) return null
|
||||
if (ref.isDelegated) return null
|
||||
if (ref.name.isEmpty()) return null
|
||||
val mapped = resolveSlot(ref) ?: return null
|
||||
val mapped = resolveSlot(ref) ?: return compileNameLookup(ref.name)
|
||||
var resolved = slotTypes[mapped] ?: SlotType.UNKNOWN
|
||||
if (resolved == SlotType.UNKNOWN && intLoopVarNames.contains(ref.name)) {
|
||||
updateSlotType(mapped, SlotType.INT)
|
||||
@ -121,16 +174,30 @@ class BytecodeCompiler(
|
||||
}
|
||||
CompiledValue(mapped, resolved)
|
||||
}
|
||||
is BinaryOpRef -> compileBinary(ref)
|
||||
is LocalVarRef -> compileNameLookup(ref.name)
|
||||
is ValueFnRef -> compileEvalRef(ref)
|
||||
is ListLiteralRef -> compileEvalRef(ref)
|
||||
is ThisMethodSlotCallRef -> compileEvalRef(ref)
|
||||
is StatementRef -> {
|
||||
val constId = builder.addConst(BytecodeConst.StatementVal(ref.statement))
|
||||
val slot = allocSlot()
|
||||
builder.emit(Opcode.EVAL_STMT, constId, slot)
|
||||
updateSlotType(slot, SlotType.OBJ)
|
||||
CompiledValue(slot, SlotType.OBJ)
|
||||
}
|
||||
is BinaryOpRef -> compileBinary(ref) ?: compileEvalRef(ref)
|
||||
is UnaryOpRef -> compileUnary(ref)
|
||||
is AssignRef -> compileAssign(ref)
|
||||
is AssignOpRef -> compileAssignOp(ref)
|
||||
is AssignRef -> compileAssign(ref) ?: compileEvalRef(ref)
|
||||
is AssignOpRef -> compileAssignOp(ref) ?: compileEvalRef(ref)
|
||||
is AssignIfNullRef -> compileAssignIfNull(ref)
|
||||
is IncDecRef -> compileIncDec(ref, true)
|
||||
is ConditionalRef -> compileConditional(ref)
|
||||
is ElvisRef -> compileElvis(ref)
|
||||
is CallRef -> compileCall(ref)
|
||||
is MethodCallRef -> compileMethodCall(ref)
|
||||
is FieldRef -> compileFieldRef(ref)
|
||||
is ImplicitThisMemberRef -> compileEvalRef(ref)
|
||||
is ImplicitThisMethodCallRef -> compileEvalRef(ref)
|
||||
is IndexRef -> compileIndexRef(ref)
|
||||
else -> null
|
||||
}
|
||||
@ -171,6 +238,14 @@ class BytecodeCompiler(
|
||||
}
|
||||
}
|
||||
|
||||
private fun compileEvalRef(ref: ObjRef): CompiledValue? {
|
||||
val slot = allocSlot()
|
||||
val id = builder.addConst(BytecodeConst.Ref(ref))
|
||||
builder.emit(Opcode.EVAL_REF, id, slot)
|
||||
updateSlotType(slot, SlotType.OBJ)
|
||||
return CompiledValue(slot, SlotType.OBJ)
|
||||
}
|
||||
|
||||
private fun compileUnary(ref: UnaryOpRef): CompiledValue? {
|
||||
val a = compileRef(unaryOperand(ref)) ?: return null
|
||||
val out = allocSlot()
|
||||
@ -187,8 +262,21 @@ class BytecodeCompiler(
|
||||
else -> null
|
||||
}
|
||||
UnaryOp.NOT -> {
|
||||
if (a.type != SlotType.BOOL) return null
|
||||
builder.emit(Opcode.NOT_BOOL, a.slot, out)
|
||||
when (a.type) {
|
||||
SlotType.BOOL -> builder.emit(Opcode.NOT_BOOL, a.slot, out)
|
||||
SlotType.INT -> {
|
||||
val tmp = allocSlot()
|
||||
builder.emit(Opcode.INT_TO_BOOL, a.slot, tmp)
|
||||
builder.emit(Opcode.NOT_BOOL, tmp, out)
|
||||
}
|
||||
SlotType.OBJ, SlotType.UNKNOWN -> {
|
||||
val obj = ensureObjSlot(a)
|
||||
val tmp = allocSlot()
|
||||
builder.emit(Opcode.OBJ_TO_BOOL, obj.slot, tmp)
|
||||
builder.emit(Opcode.NOT_BOOL, tmp, out)
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
CompiledValue(out, SlotType.BOOL)
|
||||
}
|
||||
UnaryOp.BITNOT -> {
|
||||
@ -790,11 +878,12 @@ class BytecodeCompiler(
|
||||
private fun compileAssignOp(ref: AssignOpRef): CompiledValue? {
|
||||
val localTarget = ref.target as? LocalSlotRef
|
||||
if (localTarget != null) {
|
||||
if (!allowLocalSlots) return null
|
||||
if (!localTarget.isMutable || localTarget.isDelegated) return null
|
||||
if (!allowLocalSlots) return compileEvalRef(ref)
|
||||
if (localTarget.isDelegated) return compileEvalRef(ref)
|
||||
if (!localTarget.isMutable) return compileEvalRef(ref)
|
||||
val slot = resolveSlot(localTarget) ?: return null
|
||||
val targetType = slotTypes[slot] ?: SlotType.OBJ
|
||||
var rhs = compileRef(ref.value) ?: return null
|
||||
var rhs = compileRef(ref.value) ?: return compileEvalRef(ref)
|
||||
if (targetType == SlotType.OBJ && rhs.type != SlotType.OBJ) {
|
||||
rhs = ensureObjSlot(rhs)
|
||||
}
|
||||
@ -826,6 +915,10 @@ class BytecodeCompiler(
|
||||
updateSlotType(out, result.type)
|
||||
return CompiledValue(out, result.type)
|
||||
}
|
||||
val varTarget = ref.target as? LocalVarRef
|
||||
if (varTarget != null) {
|
||||
return compileEvalRef(ref)
|
||||
}
|
||||
val objOp = when (ref.op) {
|
||||
BinOp.PLUS -> Opcode.ADD_OBJ
|
||||
BinOp.MINUS -> Opcode.SUB_OBJ
|
||||
@ -833,16 +926,16 @@ class BytecodeCompiler(
|
||||
BinOp.SLASH -> Opcode.DIV_OBJ
|
||||
BinOp.PERCENT -> Opcode.MOD_OBJ
|
||||
else -> null
|
||||
} ?: return null
|
||||
} ?: return compileEvalRef(ref)
|
||||
val fieldTarget = ref.target as? FieldRef
|
||||
if (fieldTarget != null) {
|
||||
val receiver = compileRefWithFallback(fieldTarget.target, null, Pos.builtIn) ?: return null
|
||||
val nameId = builder.addConst(BytecodeConst.StringVal(fieldTarget.name))
|
||||
if (nameId > 0xFFFF) return null
|
||||
if (nameId > 0xFFFF) return compileEvalRef(ref)
|
||||
val current = allocSlot()
|
||||
val result = allocSlot()
|
||||
if (!fieldTarget.isOptional) {
|
||||
val rhs = compileRef(ref.value) ?: return null
|
||||
val rhs = compileRef(ref.value) ?: return compileEvalRef(ref)
|
||||
builder.emit(Opcode.GET_FIELD, receiver.slot, nameId, current)
|
||||
builder.emit(objOp, current, rhs.slot, result)
|
||||
builder.emit(Opcode.SET_FIELD, receiver.slot, nameId, result)
|
||||
@ -859,13 +952,13 @@ class BytecodeCompiler(
|
||||
Opcode.JMP_IF_TRUE,
|
||||
listOf(CmdBuilder.Operand.IntVal(cmpSlot), CmdBuilder.Operand.LabelRef(nullLabel))
|
||||
)
|
||||
val rhs = compileRef(ref.value) ?: return null
|
||||
val rhs = compileRef(ref.value) ?: return compileEvalRef(ref)
|
||||
builder.emit(Opcode.GET_FIELD, receiver.slot, nameId, current)
|
||||
builder.emit(objOp, current, rhs.slot, result)
|
||||
builder.emit(Opcode.SET_FIELD, receiver.slot, nameId, result)
|
||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
||||
builder.mark(nullLabel)
|
||||
val rhsNull = compileRef(ref.value) ?: return null
|
||||
val rhsNull = compileRef(ref.value) ?: return compileEvalRef(ref)
|
||||
builder.emit(Opcode.CONST_NULL, current)
|
||||
builder.emit(objOp, current, rhsNull.slot, result)
|
||||
builder.mark(endLabel)
|
||||
@ -879,7 +972,7 @@ class BytecodeCompiler(
|
||||
val result = allocSlot()
|
||||
if (!indexTarget.optionalRef) {
|
||||
val index = compileRefWithFallback(indexTarget.indexRef, null, Pos.builtIn) ?: return null
|
||||
val rhs = compileRef(ref.value) ?: return null
|
||||
val rhs = compileRef(ref.value) ?: return compileEvalRef(ref)
|
||||
builder.emit(Opcode.GET_INDEX, receiver.slot, index.slot, current)
|
||||
builder.emit(objOp, current, rhs.slot, result)
|
||||
builder.emit(Opcode.SET_INDEX, receiver.slot, index.slot, result)
|
||||
@ -897,20 +990,107 @@ class BytecodeCompiler(
|
||||
listOf(CmdBuilder.Operand.IntVal(cmpSlot), CmdBuilder.Operand.LabelRef(nullLabel))
|
||||
)
|
||||
val index = compileRefWithFallback(indexTarget.indexRef, null, Pos.builtIn) ?: return null
|
||||
val rhs = compileRef(ref.value) ?: return null
|
||||
val rhs = compileRef(ref.value) ?: return compileEvalRef(ref)
|
||||
builder.emit(Opcode.GET_INDEX, receiver.slot, index.slot, current)
|
||||
builder.emit(objOp, current, rhs.slot, result)
|
||||
builder.emit(Opcode.SET_INDEX, receiver.slot, index.slot, result)
|
||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
||||
builder.mark(nullLabel)
|
||||
val rhsNull = compileRef(ref.value) ?: return null
|
||||
val rhsNull = compileRef(ref.value) ?: return compileEvalRef(ref)
|
||||
builder.emit(Opcode.CONST_NULL, current)
|
||||
builder.emit(objOp, current, rhsNull.slot, result)
|
||||
builder.mark(endLabel)
|
||||
updateSlotType(result, SlotType.OBJ)
|
||||
return CompiledValue(result, SlotType.OBJ)
|
||||
}
|
||||
return null
|
||||
return compileEvalRef(ref)
|
||||
}
|
||||
|
||||
private fun compileAssignIfNull(ref: AssignIfNullRef): CompiledValue? {
|
||||
val target = ref.target
|
||||
val currentValue = compileRefWithFallback(target, null, Pos.builtIn) ?: return null
|
||||
val currentObj = ensureObjSlot(currentValue)
|
||||
val resultSlot = allocSlot()
|
||||
val nullSlot = allocSlot()
|
||||
builder.emit(Opcode.CONST_NULL, nullSlot)
|
||||
val cmpSlot = allocSlot()
|
||||
builder.emit(Opcode.CMP_REF_EQ_OBJ, currentObj.slot, nullSlot, cmpSlot)
|
||||
val assignLabel = builder.label()
|
||||
val endLabel = builder.label()
|
||||
builder.emit(
|
||||
Opcode.JMP_IF_TRUE,
|
||||
listOf(CmdBuilder.Operand.IntVal(cmpSlot), CmdBuilder.Operand.LabelRef(assignLabel))
|
||||
)
|
||||
builder.emit(Opcode.MOVE_OBJ, currentObj.slot, resultSlot)
|
||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
||||
builder.mark(assignLabel)
|
||||
|
||||
val newValue = compileRefWithFallback(ref.value, null, Pos.builtIn) ?: return null
|
||||
when (target) {
|
||||
is LocalSlotRef -> {
|
||||
if (!allowLocalSlots || !target.isMutable || target.isDelegated) return null
|
||||
val slot = resolveSlot(target) ?: return null
|
||||
if (slot < scopeSlotCount) {
|
||||
val addrSlot = ensureScopeAddr(slot)
|
||||
val storeType = if (newValue.type == SlotType.UNKNOWN) SlotType.OBJ else newValue.type
|
||||
emitStoreToAddr(newValue.slot, addrSlot, storeType)
|
||||
} else {
|
||||
when (newValue.type) {
|
||||
SlotType.INT -> builder.emit(Opcode.MOVE_INT, newValue.slot, slot)
|
||||
SlotType.REAL -> builder.emit(Opcode.MOVE_REAL, newValue.slot, slot)
|
||||
SlotType.BOOL -> builder.emit(Opcode.MOVE_BOOL, newValue.slot, slot)
|
||||
else -> builder.emit(Opcode.MOVE_OBJ, newValue.slot, slot)
|
||||
}
|
||||
}
|
||||
updateSlotType(slot, newValue.type)
|
||||
}
|
||||
is FieldRef -> {
|
||||
val receiver = compileRefWithFallback(target.target, null, Pos.builtIn) ?: return null
|
||||
val nameId = builder.addConst(BytecodeConst.StringVal(target.name))
|
||||
if (nameId > 0xFFFF) return null
|
||||
if (!target.isOptional) {
|
||||
builder.emit(Opcode.SET_FIELD, receiver.slot, nameId, newValue.slot)
|
||||
} else {
|
||||
val recvNull = allocSlot()
|
||||
builder.emit(Opcode.CONST_NULL, recvNull)
|
||||
val recvCmp = allocSlot()
|
||||
builder.emit(Opcode.CMP_REF_EQ_OBJ, receiver.slot, recvNull, recvCmp)
|
||||
val skipLabel = builder.label()
|
||||
builder.emit(
|
||||
Opcode.JMP_IF_TRUE,
|
||||
listOf(CmdBuilder.Operand.IntVal(recvCmp), CmdBuilder.Operand.LabelRef(skipLabel))
|
||||
)
|
||||
builder.emit(Opcode.SET_FIELD, receiver.slot, nameId, newValue.slot)
|
||||
builder.mark(skipLabel)
|
||||
}
|
||||
}
|
||||
is IndexRef -> {
|
||||
val receiver = compileRefWithFallback(target.targetRef, null, Pos.builtIn) ?: return null
|
||||
if (!target.optionalRef) {
|
||||
val index = compileRefWithFallback(target.indexRef, null, Pos.builtIn) ?: return null
|
||||
builder.emit(Opcode.SET_INDEX, receiver.slot, index.slot, newValue.slot)
|
||||
} else {
|
||||
val recvNull = allocSlot()
|
||||
builder.emit(Opcode.CONST_NULL, recvNull)
|
||||
val recvCmp = allocSlot()
|
||||
builder.emit(Opcode.CMP_REF_EQ_OBJ, receiver.slot, recvNull, recvCmp)
|
||||
val skipLabel = builder.label()
|
||||
builder.emit(
|
||||
Opcode.JMP_IF_TRUE,
|
||||
listOf(CmdBuilder.Operand.IntVal(recvCmp), CmdBuilder.Operand.LabelRef(skipLabel))
|
||||
)
|
||||
val index = compileRefWithFallback(target.indexRef, null, Pos.builtIn) ?: return null
|
||||
builder.emit(Opcode.SET_INDEX, receiver.slot, index.slot, newValue.slot)
|
||||
builder.mark(skipLabel)
|
||||
}
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
val newObj = ensureObjSlot(newValue)
|
||||
builder.emit(Opcode.MOVE_OBJ, newObj.slot, resultSlot)
|
||||
builder.mark(endLabel)
|
||||
updateSlotType(resultSlot, SlotType.OBJ)
|
||||
return CompiledValue(resultSlot, SlotType.OBJ)
|
||||
}
|
||||
|
||||
private fun compileFieldRef(ref: FieldRef): CompiledValue? {
|
||||
@ -1347,7 +1527,12 @@ class BytecodeCompiler(
|
||||
}
|
||||
|
||||
private fun compileIf(name: String, stmt: IfStatement): CmdFunction? {
|
||||
val conditionStmt = stmt.condition as? ExpressionStatement ?: return null
|
||||
val conditionTarget = if (stmt.condition is BytecodeStatement) {
|
||||
stmt.condition.original
|
||||
} else {
|
||||
stmt.condition
|
||||
}
|
||||
val conditionStmt = conditionTarget as? ExpressionStatement ?: return null
|
||||
val condValue = compileRefWithFallback(conditionStmt.ref, SlotType.BOOL, stmt.pos) ?: return null
|
||||
if (condValue.type != SlotType.BOOL) return null
|
||||
|
||||
@ -1359,13 +1544,13 @@ class BytecodeCompiler(
|
||||
Opcode.JMP_IF_FALSE,
|
||||
listOf(CmdBuilder.Operand.IntVal(condValue.slot), CmdBuilder.Operand.LabelRef(elseLabel))
|
||||
)
|
||||
val thenValue = compileStatementValue(stmt.ifBody) ?: return null
|
||||
val thenValue = compileStatementValueOrFallback(stmt.ifBody) ?: return null
|
||||
emitMove(thenValue, resultSlot)
|
||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
||||
|
||||
builder.mark(elseLabel)
|
||||
if (stmt.elseBody != null) {
|
||||
val elseValue = compileStatementValue(stmt.elseBody) ?: return null
|
||||
val elseValue = compileStatementValueOrFallback(stmt.elseBody) ?: return null
|
||||
emitMove(elseValue, resultSlot)
|
||||
} else {
|
||||
val id = builder.addConst(BytecodeConst.ObjRef(ObjVoid))
|
||||
@ -1524,6 +1709,7 @@ class BytecodeCompiler(
|
||||
}
|
||||
is BlockStatement -> emitBlock(target, true)
|
||||
is VarDeclStatement -> emitVarDecl(target)
|
||||
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target)
|
||||
is net.sergeych.lyng.BreakStatement -> compileBreak(target)
|
||||
is net.sergeych.lyng.ContinueStatement -> compileContinue(target)
|
||||
is net.sergeych.lyng.ReturnStatement -> compileReturn(target)
|
||||
@ -1563,6 +1749,7 @@ class BytecodeCompiler(
|
||||
}
|
||||
is BlockStatement -> emitBlock(target, false)
|
||||
is VarDeclStatement -> emitVarDecl(target)
|
||||
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target)
|
||||
is net.sergeych.lyng.BreakStatement -> compileBreak(target)
|
||||
is net.sergeych.lyng.ContinueStatement -> compileContinue(target)
|
||||
is net.sergeych.lyng.ReturnStatement -> compileReturn(target)
|
||||
@ -1583,7 +1770,16 @@ class BytecodeCompiler(
|
||||
for ((index, statement) in statements.withIndex()) {
|
||||
val isLast = index == statements.lastIndex
|
||||
val wantResult = needResult && isLast
|
||||
val value = compileStatementValueOrFallback(statement, wantResult) ?: return null
|
||||
val value = compileStatementValueOrFallback(statement, wantResult)
|
||||
?: run {
|
||||
val original = (statement as? BytecodeStatement)?.original
|
||||
val name = original?.let { "${statement::class.simpleName}(${it::class.simpleName})" }
|
||||
?: statement::class.simpleName
|
||||
throw BytecodeFallbackException(
|
||||
"Bytecode fallback: failed to compile block statement ($name)",
|
||||
statement.pos
|
||||
)
|
||||
}
|
||||
if (wantResult) {
|
||||
lastValue = value
|
||||
}
|
||||
@ -1705,9 +1901,26 @@ class BytecodeCompiler(
|
||||
rangeRef = extractRangeFromLocal(stmt.source)
|
||||
}
|
||||
val typedRangeLocal = if (range == null && rangeRef == null) extractTypedRangeLocal(stmt.source) else null
|
||||
val loopLocalIndex = localSlotIndexByName[stmt.loopVarName] ?: return null
|
||||
val loopSlotId = scopeSlotCount + loopLocalIndex
|
||||
val loopLocalIndex = localSlotIndexByName[stmt.loopVarName]
|
||||
var usedOverride = false
|
||||
val loopSlotId = when {
|
||||
loopLocalIndex != null -> scopeSlotCount + loopLocalIndex
|
||||
else -> {
|
||||
val localKey = localSlotInfoMap.entries.firstOrNull { it.value.name == stmt.loopVarName }?.key
|
||||
val localIndex = localKey?.let { localSlotIndexByKey[it] }
|
||||
when {
|
||||
localIndex != null -> scopeSlotCount + localIndex
|
||||
else -> scopeSlotIndexByName[stmt.loopVarName]
|
||||
}
|
||||
}
|
||||
} ?: run {
|
||||
val slot = allocSlot()
|
||||
loopSlotOverrides[stmt.loopVarName] = slot
|
||||
usedOverride = true
|
||||
slot
|
||||
}
|
||||
|
||||
try {
|
||||
if (range == null && rangeRef == null && typedRangeLocal == null) {
|
||||
val sourceValue = compileStatementValueOrFallback(stmt.source) ?: return null
|
||||
val sourceObj = ensureObjSlot(sourceValue)
|
||||
@ -1919,6 +2132,11 @@ class BytecodeCompiler(
|
||||
builder.mark(afterElse)
|
||||
}
|
||||
return resultSlot
|
||||
} finally {
|
||||
if (usedOverride) {
|
||||
loopSlotOverrides.remove(stmt.loopVarName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun emitWhile(stmt: net.sergeych.lyng.WhileStatement, wantResult: Boolean): Int? {
|
||||
@ -2077,8 +2295,9 @@ class BytecodeCompiler(
|
||||
}
|
||||
|
||||
private fun compileCondition(stmt: Statement, pos: Pos): CompiledValue? {
|
||||
return when (stmt) {
|
||||
is ExpressionStatement -> compileRefWithFallback(stmt.ref, SlotType.BOOL, stmt.pos)
|
||||
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
||||
return when (target) {
|
||||
is ExpressionStatement -> compileRefWithFallback(target.ref, SlotType.BOOL, target.pos)
|
||||
else -> {
|
||||
throw BytecodeFallbackException(
|
||||
"Bytecode fallback: unsupported condition",
|
||||
@ -2150,6 +2369,23 @@ class BytecodeCompiler(
|
||||
return objValue
|
||||
}
|
||||
|
||||
private fun emitExtensionPropertyDecl(
|
||||
stmt: net.sergeych.lyng.ExtensionPropertyDeclStatement
|
||||
): CompiledValue {
|
||||
val constId = builder.addConst(
|
||||
BytecodeConst.ExtensionPropertyDecl(
|
||||
stmt.extTypeName,
|
||||
stmt.property,
|
||||
stmt.visibility,
|
||||
stmt.setterVisibility
|
||||
)
|
||||
)
|
||||
val slot = allocSlot()
|
||||
builder.emit(Opcode.DECL_EXT_PROPERTY, constId, slot)
|
||||
updateSlotType(slot, SlotType.OBJ)
|
||||
return CompiledValue(slot, SlotType.OBJ)
|
||||
}
|
||||
|
||||
private fun resetAddrCache() {
|
||||
addrSlotByScopeSlot.clear()
|
||||
}
|
||||
@ -2235,8 +2471,20 @@ class BytecodeCompiler(
|
||||
compiled = null
|
||||
}
|
||||
}
|
||||
val refInfo = when (ref) {
|
||||
is LocalVarRef -> "LocalVarRef(${ref.name})"
|
||||
is LocalSlotRef -> "LocalSlotRef(${ref.name})"
|
||||
is FieldRef -> "FieldRef(${ref.name})"
|
||||
else -> ref::class.simpleName ?: "UnknownRef"
|
||||
}
|
||||
val extra = if (ref is LocalVarRef) {
|
||||
val names = scopeSlotNameMap.values.joinToString(prefix = "[", postfix = "]")
|
||||
" scopeSlots=$names"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
throw BytecodeFallbackException(
|
||||
"Bytecode fallback: unsupported expression",
|
||||
"Bytecode fallback: unsupported expression ($refInfo)$extra",
|
||||
pos
|
||||
)
|
||||
}
|
||||
@ -2254,6 +2502,7 @@ class BytecodeCompiler(
|
||||
private fun refPos(ref: BinaryOpRef): Pos = Pos.builtIn
|
||||
|
||||
private fun resolveSlot(ref: LocalSlotRef): Int? {
|
||||
loopSlotOverrides[ref.name]?.let { return it }
|
||||
val localKey = ScopeSlotKey(refScopeDepth(ref), refSlot(ref))
|
||||
val localIndex = localSlotIndexByKey[localKey]
|
||||
if (localIndex != null) return scopeSlotCount + localIndex
|
||||
@ -2277,9 +2526,13 @@ class BytecodeCompiler(
|
||||
nextAddrSlot = 0
|
||||
slotTypes.clear()
|
||||
scopeSlotMap.clear()
|
||||
scopeSlotNameMap.clear()
|
||||
localSlotInfoMap.clear()
|
||||
localSlotIndexByKey.clear()
|
||||
localSlotIndexByName.clear()
|
||||
loopSlotOverrides.clear()
|
||||
scopeSlotIndexByName.clear()
|
||||
pendingScopeNameRefs.clear()
|
||||
localSlotNames = emptyArray()
|
||||
localSlotMutables = BooleanArray(0)
|
||||
localSlotDepths = IntArray(0)
|
||||
@ -2291,10 +2544,23 @@ class BytecodeCompiler(
|
||||
virtualScopeDepths.clear()
|
||||
if (allowLocalSlots) {
|
||||
collectLoopVarNames(stmt)
|
||||
collectVirtualScopeDepths(stmt, 0)
|
||||
collectScopeSlots(stmt)
|
||||
}
|
||||
collectVirtualScopeDepths(stmt, 0)
|
||||
collectScopeSlots(stmt)
|
||||
if (allowLocalSlots) {
|
||||
collectLoopSlotPlans(stmt, 0)
|
||||
}
|
||||
if (pendingScopeNameRefs.isNotEmpty()) {
|
||||
val existingNames = HashSet<String>(scopeSlotNameMap.values)
|
||||
var maxSlotIndex = scopeSlotMap.keys.maxOfOrNull { it.slot } ?: -1
|
||||
for (name in pendingScopeNameRefs) {
|
||||
if (!existingNames.add(name)) continue
|
||||
maxSlotIndex += 1
|
||||
val key = ScopeSlotKey(0, maxSlotIndex)
|
||||
scopeSlotMap[key] = scopeSlotMap.size
|
||||
scopeSlotNameMap[key] = name
|
||||
}
|
||||
}
|
||||
scopeSlotCount = scopeSlotMap.size
|
||||
scopeSlotDepths = IntArray(scopeSlotCount)
|
||||
scopeSlotIndices = IntArray(scopeSlotCount)
|
||||
@ -2324,6 +2590,14 @@ class BytecodeCompiler(
|
||||
localSlotMutables = mutables
|
||||
localSlotDepths = depths
|
||||
}
|
||||
if (scopeSlotCount > 0) {
|
||||
for ((key, index) in scopeSlotMap) {
|
||||
val name = scopeSlotNameMap[key] ?: continue
|
||||
if (!scopeSlotIndexByName.containsKey(name)) {
|
||||
scopeSlotIndexByName[name] = index
|
||||
}
|
||||
}
|
||||
}
|
||||
nextSlot = scopeSlotCount + localSlotNames.size
|
||||
}
|
||||
|
||||
@ -2563,6 +2837,7 @@ class BytecodeCompiler(
|
||||
scopeSlotNameMap[key] = ref.name
|
||||
}
|
||||
}
|
||||
is LocalVarRef -> {}
|
||||
is BinaryOpRef -> {
|
||||
collectScopeSlotsRef(binaryLeft(ref))
|
||||
collectScopeSlotsRef(binaryRight(ref))
|
||||
@ -2594,6 +2869,10 @@ class BytecodeCompiler(
|
||||
collectScopeSlotsRef(ref.target)
|
||||
collectScopeSlotsRef(ref.value)
|
||||
}
|
||||
is AssignIfNullRef -> {
|
||||
collectScopeSlotsRef(ref.target)
|
||||
collectScopeSlotsRef(ref.value)
|
||||
}
|
||||
is IncDecRef -> collectScopeSlotsRef(ref.target)
|
||||
is ConditionalRef -> {
|
||||
collectScopeSlotsRef(ref.condition)
|
||||
|
||||
@ -19,6 +19,7 @@ package net.sergeych.lyng.bytecode
|
||||
import net.sergeych.lyng.Pos
|
||||
import net.sergeych.lyng.Visibility
|
||||
import net.sergeych.lyng.obj.Obj
|
||||
import net.sergeych.lyng.obj.ObjProperty
|
||||
|
||||
sealed class BytecodeConst {
|
||||
object Null : BytecodeConst()
|
||||
@ -28,7 +29,15 @@ sealed class BytecodeConst {
|
||||
data class StringVal(val value: String) : BytecodeConst()
|
||||
data class PosVal(val pos: Pos) : BytecodeConst()
|
||||
data class ObjRef(val value: Obj) : BytecodeConst()
|
||||
data class Ref(val value: net.sergeych.lyng.obj.ObjRef) : BytecodeConst()
|
||||
data class StatementVal(val statement: net.sergeych.lyng.Statement) : BytecodeConst()
|
||||
data class SlotPlan(val plan: Map<String, Int>) : BytecodeConst()
|
||||
data class ExtensionPropertyDecl(
|
||||
val extTypeName: String,
|
||||
val property: ObjProperty,
|
||||
val visibility: Visibility,
|
||||
val setterVisibility: Visibility?,
|
||||
) : BytecodeConst()
|
||||
data class LocalDecl(
|
||||
val name: String,
|
||||
val isMutable: Boolean,
|
||||
|
||||
@ -142,7 +142,7 @@ class CmdBuilder {
|
||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||
Opcode.PUSH_SCOPE, Opcode.PUSH_SLOT_PLAN ->
|
||||
listOf(OperandKind.CONST)
|
||||
Opcode.DECL_LOCAL ->
|
||||
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY ->
|
||||
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,
|
||||
@ -176,11 +176,13 @@ class CmdBuilder {
|
||||
listOf(OperandKind.SLOT, OperandKind.ID, OperandKind.SLOT)
|
||||
Opcode.SET_FIELD ->
|
||||
listOf(OperandKind.SLOT, OperandKind.ID, OperandKind.SLOT)
|
||||
Opcode.GET_NAME ->
|
||||
listOf(OperandKind.ID, OperandKind.SLOT)
|
||||
Opcode.GET_INDEX ->
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||
Opcode.SET_INDEX ->
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||
Opcode.EVAL_FALLBACK ->
|
||||
Opcode.EVAL_FALLBACK, Opcode.EVAL_REF, Opcode.EVAL_STMT ->
|
||||
listOf(OperandKind.ID, OperandKind.SLOT)
|
||||
}
|
||||
}
|
||||
@ -359,15 +361,19 @@ class CmdBuilder {
|
||||
Opcode.PUSH_SLOT_PLAN -> CmdPushSlotPlan(operands[0])
|
||||
Opcode.POP_SLOT_PLAN -> CmdPopSlotPlan()
|
||||
Opcode.DECL_LOCAL -> CmdDeclLocal(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.CALL_VIRTUAL -> CmdCallVirtual(operands[0], operands[1], operands[2], operands[3], operands[4])
|
||||
Opcode.CALL_FALLBACK -> CmdCallFallback(operands[0], operands[1], operands[2], operands[3])
|
||||
Opcode.CALL_SLOT -> CmdCallSlot(operands[0], operands[1], operands[2], operands[3])
|
||||
Opcode.GET_FIELD -> CmdGetField(operands[0], operands[1], operands[2])
|
||||
Opcode.SET_FIELD -> CmdSetField(operands[0], operands[1], operands[2])
|
||||
Opcode.GET_NAME -> CmdGetName(operands[0], operands[1])
|
||||
Opcode.GET_INDEX -> CmdGetIndex(operands[0], operands[1], operands[2])
|
||||
Opcode.SET_INDEX -> CmdSetIndex(operands[0], operands[1], operands[2])
|
||||
Opcode.EVAL_FALLBACK -> CmdEvalFallback(operands[0], operands[1])
|
||||
Opcode.EVAL_REF -> CmdEvalRef(operands[0], operands[1])
|
||||
Opcode.EVAL_STMT -> CmdEvalStmt(operands[0], operands[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,15 +173,19 @@ object CmdDisassembler {
|
||||
is CmdPushSlotPlan -> Opcode.PUSH_SLOT_PLAN to intArrayOf(cmd.planId)
|
||||
is CmdPopSlotPlan -> Opcode.POP_SLOT_PLAN to intArrayOf()
|
||||
is CmdDeclLocal -> Opcode.DECL_LOCAL 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 CmdCallVirtual -> Opcode.CALL_VIRTUAL to intArrayOf(cmd.recvSlot, cmd.methodId, cmd.argBase, cmd.argCount, cmd.dst)
|
||||
is CmdCallFallback -> Opcode.CALL_FALLBACK to intArrayOf(cmd.id, cmd.argBase, cmd.argCount, cmd.dst)
|
||||
is CmdCallSlot -> Opcode.CALL_SLOT to intArrayOf(cmd.calleeSlot, cmd.argBase, cmd.argCount, cmd.dst)
|
||||
is CmdGetField -> Opcode.GET_FIELD to intArrayOf(cmd.recvSlot, cmd.fieldId, cmd.dst)
|
||||
is CmdSetField -> Opcode.SET_FIELD to intArrayOf(cmd.recvSlot, cmd.fieldId, cmd.valueSlot)
|
||||
is CmdGetName -> Opcode.GET_NAME to intArrayOf(cmd.nameId, cmd.dst)
|
||||
is CmdGetIndex -> Opcode.GET_INDEX to intArrayOf(cmd.targetSlot, cmd.indexSlot, cmd.dst)
|
||||
is CmdSetIndex -> Opcode.SET_INDEX to intArrayOf(cmd.targetSlot, cmd.indexSlot, cmd.valueSlot)
|
||||
is CmdEvalFallback -> Opcode.EVAL_FALLBACK to intArrayOf(cmd.id, cmd.dst)
|
||||
is CmdEvalRef -> Opcode.EVAL_REF to intArrayOf(cmd.id, cmd.dst)
|
||||
is CmdEvalStmt -> Opcode.EVAL_STMT to intArrayOf(cmd.id, cmd.dst)
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,7 +225,7 @@ object CmdDisassembler {
|
||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||
Opcode.PUSH_SCOPE, Opcode.PUSH_SLOT_PLAN ->
|
||||
listOf(OperandKind.CONST)
|
||||
Opcode.DECL_LOCAL ->
|
||||
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY ->
|
||||
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,
|
||||
@ -255,11 +259,13 @@ object CmdDisassembler {
|
||||
listOf(OperandKind.SLOT, OperandKind.ID, OperandKind.SLOT)
|
||||
Opcode.SET_FIELD ->
|
||||
listOf(OperandKind.SLOT, OperandKind.ID, OperandKind.SLOT)
|
||||
Opcode.GET_NAME ->
|
||||
listOf(OperandKind.ID, OperandKind.SLOT)
|
||||
Opcode.GET_INDEX ->
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||
Opcode.SET_INDEX ->
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||
Opcode.EVAL_FALLBACK ->
|
||||
Opcode.EVAL_FALLBACK, Opcode.EVAL_REF, Opcode.EVAL_STMT ->
|
||||
listOf(OperandKind.ID, OperandKind.SLOT)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1031,6 +1031,32 @@ class CmdDeclLocal(internal val constId: Int, internal val slot: Int) : Cmd() {
|
||||
}
|
||||
}
|
||||
|
||||
class CmdDeclExtProperty(internal val constId: Int, internal val slot: Int) : Cmd() {
|
||||
override suspend fun perform(frame: CmdFrame) {
|
||||
val decl = frame.fn.constants[constId] as? BytecodeConst.ExtensionPropertyDecl
|
||||
?: error("DECL_EXT_PROPERTY expects ExtensionPropertyDecl at $constId")
|
||||
val type = frame.scope[decl.extTypeName]?.value
|
||||
?: frame.scope.raiseSymbolNotFound("class ${decl.extTypeName} not found")
|
||||
if (type !is ObjClass) {
|
||||
frame.scope.raiseClassCastError("${decl.extTypeName} is not the class instance")
|
||||
}
|
||||
frame.scope.addExtension(
|
||||
type,
|
||||
decl.property.name,
|
||||
ObjRecord(
|
||||
decl.property,
|
||||
isMutable = false,
|
||||
visibility = decl.visibility,
|
||||
writeVisibility = decl.setterVisibility,
|
||||
declaringClass = null,
|
||||
type = ObjRecord.Type.Property
|
||||
)
|
||||
)
|
||||
frame.setObj(slot, decl.property)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
class CmdCallDirect(
|
||||
internal val id: Int,
|
||||
internal val argBase: Int,
|
||||
@ -1120,6 +1146,17 @@ class CmdCallSlot(
|
||||
frame.syncFrameToScope()
|
||||
}
|
||||
val callee = frame.slotToObj(calleeSlot)
|
||||
if (callee === ObjUnset) {
|
||||
val name = if (calleeSlot < frame.fn.scopeSlotCount) {
|
||||
frame.fn.scopeSlotNames[calleeSlot]
|
||||
} else {
|
||||
val localIndex = calleeSlot - frame.fn.scopeSlotCount
|
||||
frame.fn.localSlotNames.getOrNull(localIndex)
|
||||
}
|
||||
val message = name?.let { "property '$it' is unset (not initialized)" }
|
||||
?: "property is unset (not initialized)"
|
||||
frame.scope.raiseUnset(message)
|
||||
}
|
||||
val args = frame.buildArguments(argBase, argCount)
|
||||
val canPool = PerfFlags.SCOPE_POOL && callee !is Statement
|
||||
val result = if (canPool) {
|
||||
@ -1170,6 +1207,22 @@ class CmdGetField(
|
||||
}
|
||||
}
|
||||
|
||||
class CmdGetName(
|
||||
internal val nameId: Int,
|
||||
internal val dst: Int,
|
||||
) : Cmd() {
|
||||
override suspend fun perform(frame: CmdFrame) {
|
||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
||||
frame.syncFrameToScope()
|
||||
}
|
||||
val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal
|
||||
?: error("GET_NAME expects StringVal at $nameId")
|
||||
val result = frame.scope.get(nameConst.value)?.value ?: ObjUnset
|
||||
frame.storeObjResult(dst, result)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
class CmdSetField(
|
||||
internal val recvSlot: Int,
|
||||
internal val fieldId: Int,
|
||||
@ -1238,6 +1291,38 @@ class CmdEvalFallback(internal val id: Int, internal val dst: Int) : Cmd() {
|
||||
}
|
||||
}
|
||||
|
||||
class CmdEvalRef(internal val id: Int, internal val dst: Int) : Cmd() {
|
||||
override suspend fun perform(frame: CmdFrame) {
|
||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
||||
frame.syncFrameToScope()
|
||||
}
|
||||
val ref = frame.fn.constants[id] as? BytecodeConst.Ref
|
||||
?: error("EVAL_REF expects Ref at $id")
|
||||
val result = ref.value.evalValue(frame.scope)
|
||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
||||
frame.syncScopeToFrame()
|
||||
}
|
||||
frame.storeObjResult(dst, result)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
class CmdEvalStmt(internal val id: Int, internal val dst: Int) : Cmd() {
|
||||
override suspend fun perform(frame: CmdFrame) {
|
||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
||||
frame.syncFrameToScope()
|
||||
}
|
||||
val stmt = frame.fn.constants.getOrNull(id) as? BytecodeConst.StatementVal
|
||||
?: error("EVAL_STMT expects StatementVal at $id")
|
||||
val result = stmt.statement.execute(frame.scope)
|
||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
||||
frame.syncScopeToFrame()
|
||||
}
|
||||
frame.storeObjResult(dst, result)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
class CmdFrame(
|
||||
val vm: CmdVm,
|
||||
val fn: CmdFunction,
|
||||
@ -1659,9 +1744,14 @@ class CmdFrame(
|
||||
}
|
||||
|
||||
private fun ensureScopeSlot(target: Scope, slot: Int): Int {
|
||||
val name = fn.scopeSlotNames[slot]
|
||||
if (name != null) {
|
||||
val existing = target.getSlotIndexOf(name)
|
||||
if (existing != null) return existing
|
||||
}
|
||||
val index = fn.scopeSlotIndices[slot]
|
||||
if (index < target.slotCount) return index
|
||||
val name = fn.scopeSlotNames[slot] ?: return index
|
||||
if (name == null) return index
|
||||
target.applySlotPlan(mapOf(name to index))
|
||||
val existing = target.getLocalRecordDirect(name)
|
||||
if (existing != null) {
|
||||
|
||||
@ -118,6 +118,7 @@ enum class Opcode(val code: Int) {
|
||||
PUSH_SLOT_PLAN(0x87),
|
||||
POP_SLOT_PLAN(0x88),
|
||||
DECL_LOCAL(0x89),
|
||||
DECL_EXT_PROPERTY(0x8A),
|
||||
|
||||
CALL_DIRECT(0x90),
|
||||
CALL_VIRTUAL(0x91),
|
||||
@ -128,6 +129,7 @@ enum class Opcode(val code: Int) {
|
||||
SET_FIELD(0xA1),
|
||||
GET_INDEX(0xA2),
|
||||
SET_INDEX(0xA3),
|
||||
GET_NAME(0xA4),
|
||||
|
||||
EVAL_FALLBACK(0xB0),
|
||||
RESOLVE_SCOPE_SLOT(0xB1),
|
||||
@ -140,6 +142,8 @@ enum class Opcode(val code: Int) {
|
||||
LOAD_BOOL_ADDR(0xB8),
|
||||
STORE_BOOL_ADDR(0xB9),
|
||||
THROW(0xBB),
|
||||
EVAL_REF(0xBC),
|
||||
EVAL_STMT(0xBD),
|
||||
;
|
||||
|
||||
companion object {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user