Enforce bytecode-only compilation in tests
This commit is contained in:
1 parent
490faea2ba
commit
9a15470cdb
45 files changed
+152
-62
No files matched your search
@@ -1332,11 +1332,10 @@ class BytecodeCompiler(
|
||||
return when (stmt) {
|
||||
is ExpressionStatement -> compileRefWithFallback(stmt.ref, null, stmt.pos)
|
||||
else -> {
|
||||
val slot = allocSlot()
|
||||
val id = builder.addFallback(stmt)
|
||||
builder.emit(Opcode.EVAL_FALLBACK, id, slot)
|
||||
updateSlotType(slot, SlotType.OBJ)
|
||||
CompiledValue(slot, SlotType.OBJ)
|
||||
throw BytecodeFallbackException(
|
||||
"Bytecode fallback: unsupported argument expression",
|
||||
stmt.pos
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1490,12 +1489,10 @@ class BytecodeCompiler(
|
||||
}
|
||||
|
||||
private fun emitFallbackStatement(stmt: Statement): CompiledValue {
|
||||
val slot = allocSlot()
|
||||
val id = builder.addFallback(stmt)
|
||||
builder.emit(Opcode.EVAL_FALLBACK, id, slot)
|
||||
builder.emit(Opcode.BOX_OBJ, slot, slot)
|
||||
updateSlotType(slot, SlotType.OBJ)
|
||||
return CompiledValue(slot, SlotType.OBJ)
|
||||
throw BytecodeFallbackException(
|
||||
"Bytecode fallback: unsupported statement",
|
||||
stmt.pos
|
||||
)
|
||||
}
|
||||
|
||||
private fun compileStatementValueOrFallback(stmt: Statement, needResult: Boolean = true): CompiledValue? {
|
||||
@@ -1808,10 +1805,10 @@ class BytecodeCompiler(
|
||||
val rangeObj = ensureObjSlot(rangeValue)
|
||||
val okSlot = allocSlot()
|
||||
builder.emit(Opcode.RANGE_INT_BOUNDS, rangeObj.slot, iSlot, endSlot, okSlot)
|
||||
val fallbackLabel = builder.label()
|
||||
val badRangeLabel = builder.label()
|
||||
builder.emit(
|
||||
Opcode.JMP_IF_FALSE,
|
||||
listOf(CmdBuilder.Operand.IntVal(okSlot), CmdBuilder.Operand.LabelRef(fallbackLabel))
|
||||
listOf(CmdBuilder.Operand.IntVal(okSlot), CmdBuilder.Operand.LabelRef(badRangeLabel))
|
||||
)
|
||||
val breakFlagSlot = allocSlot()
|
||||
val falseId = builder.addConst(BytecodeConst.Bool(false))
|
||||
@@ -1863,9 +1860,11 @@ class BytecodeCompiler(
|
||||
builder.mark(afterElse)
|
||||
}
|
||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(doneLabel)))
|
||||
builder.mark(fallbackLabel)
|
||||
val fallbackId = builder.addFallback(stmt)
|
||||
builder.emit(Opcode.EVAL_FALLBACK, fallbackId, resultSlot)
|
||||
builder.mark(badRangeLabel)
|
||||
val msgId = builder.addConst(BytecodeConst.StringVal("expected Int range"))
|
||||
builder.emit(Opcode.CONST_OBJ, msgId, resultSlot)
|
||||
val posId = builder.addConst(BytecodeConst.PosVal(stmt.pos))
|
||||
builder.emit(Opcode.THROW, posId, resultSlot)
|
||||
builder.mark(doneLabel)
|
||||
return resultSlot
|
||||
}
|
||||
@@ -2081,11 +2080,10 @@ class BytecodeCompiler(
|
||||
return when (stmt) {
|
||||
is ExpressionStatement -> compileRefWithFallback(stmt.ref, SlotType.BOOL, stmt.pos)
|
||||
else -> {
|
||||
val slot = allocSlot()
|
||||
val id = builder.addFallback(ToBoolStatement(stmt, pos))
|
||||
builder.emit(Opcode.EVAL_FALLBACK, id, slot)
|
||||
updateSlotType(slot, SlotType.BOOL)
|
||||
CompiledValue(slot, SlotType.BOOL)
|
||||
throw BytecodeFallbackException(
|
||||
"Bytecode fallback: unsupported condition",
|
||||
pos
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2237,21 +2235,10 @@ class BytecodeCompiler(
|
||||
compiled = null
|
||||
}
|
||||
}
|
||||
val slot = allocSlot()
|
||||
val stmt = if (forceType == SlotType.BOOL) {
|
||||
ToBoolStatement(ExpressionStatement(ref, pos), pos)
|
||||
} else {
|
||||
ExpressionStatement(ref, pos)
|
||||
}
|
||||
val id = builder.addFallback(stmt)
|
||||
builder.emit(Opcode.EVAL_FALLBACK, id, slot)
|
||||
if (forceType == null) {
|
||||
builder.emit(Opcode.BOX_OBJ, slot, slot)
|
||||
updateSlotType(slot, SlotType.OBJ)
|
||||
return CompiledValue(slot, SlotType.OBJ)
|
||||
}
|
||||
updateSlotType(slot, forceType)
|
||||
return CompiledValue(slot, forceType)
|
||||
throw BytecodeFallbackException(
|
||||
"Bytecode fallback: unsupported expression",
|
||||
pos
|
||||
)
|
||||
}
|
||||
|
||||
private fun refSlot(ref: LocalSlotRef): Int = ref.slot
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2026 Sergey S. Chernov
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.sergeych.lyng.bytecode
|
||||
|
||||
import net.sergeych.lyng.Pos
|
||||
|
||||
class BytecodeFallbackException(
|
||||
message: String,
|
||||
val pos: Pos? = null,
|
||||
) : RuntimeException(message) {
|
||||
override fun toString(): String =
|
||||
pos?.let { "${super.toString()} at $it" } ?: super.toString()
|
||||
}
|
||||
@@ -44,7 +44,12 @@ class BytecodeStatement private constructor(
|
||||
): Statement {
|
||||
if (statement is BytecodeStatement) return statement
|
||||
val hasUnsupported = containsUnsupportedStatement(statement)
|
||||
if (hasUnsupported) return unwrapDeep(statement)
|
||||
if (hasUnsupported) {
|
||||
throw BytecodeFallbackException(
|
||||
"Bytecode fallback: unsupported statement in '$nameHint'",
|
||||
statement.pos
|
||||
)
|
||||
}
|
||||
val safeLocals = allowLocalSlots
|
||||
val compiler = BytecodeCompiler(
|
||||
allowLocalSlots = safeLocals,
|
||||
@@ -52,22 +57,10 @@ class BytecodeStatement private constructor(
|
||||
rangeLocalNames = rangeLocalNames
|
||||
)
|
||||
val compiled = compiler.compileStatement(nameHint, statement)
|
||||
val fn = compiled ?: run {
|
||||
val builder = CmdBuilder()
|
||||
val slot = 0
|
||||
val id = builder.addFallback(statement)
|
||||
builder.emit(Opcode.EVAL_FALLBACK, id, slot)
|
||||
builder.emit(Opcode.RET, slot)
|
||||
builder.build(
|
||||
nameHint,
|
||||
localCount = 1,
|
||||
addrCount = 0,
|
||||
returnLabels = returnLabels,
|
||||
localSlotNames = emptyArray(),
|
||||
localSlotMutables = BooleanArray(0),
|
||||
localSlotDepths = IntArray(0)
|
||||
)
|
||||
}
|
||||
val fn = compiled ?: throw BytecodeFallbackException(
|
||||
"Bytecode fallback: failed to compile '$nameHint'",
|
||||
statement.pos
|
||||
)
|
||||
return BytecodeStatement(statement, fn)
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user