mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +00:00
enforce const on array/matrix values
This commit is contained in:
parent
6b89bb7be5
commit
5ee427b72b
@ -1070,7 +1070,7 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
||||
?: throw UndefinedSymbolError(this)
|
||||
val vardecl = node as? VarDecl
|
||||
if(vardecl==null) {
|
||||
throw ExpressionError("name should be a constant, instead of: ${node::class.simpleName}", position)
|
||||
throw ExpressionError("name must be a constant, instead of: ${node::class.simpleName}", position)
|
||||
} else if(vardecl.type!=VarDeclType.CONST) {
|
||||
return null
|
||||
}
|
||||
|
@ -184,14 +184,14 @@ class AstChecker(private val namespace: INameScope,
|
||||
|
||||
val uniqueNames = subroutine.parameters.asSequence().map { it.name }.toSet()
|
||||
if(uniqueNames.size!=subroutine.parameters.size)
|
||||
err("parameter names should be unique")
|
||||
err("parameter names must be unique")
|
||||
val uniqueParamRegs = subroutine.parameters.asSequence().map {it.register}.toSet()
|
||||
if(uniqueParamRegs.size!=subroutine.parameters.size)
|
||||
err("parameter registers should be unique")
|
||||
err("parameter registers must be unique")
|
||||
val uniqueResultRegisters = subroutine.returnvalues.asSequence().filter{it.register!=null}.map {it.register.toString()}.toMutableSet()
|
||||
uniqueResultRegisters.addAll(subroutine.returnvalues.asSequence().filter{it.statusflag!=null}.map{it.statusflag.toString()}.toList())
|
||||
if(uniqueResultRegisters.size!=subroutine.returnvalues.size)
|
||||
err("return registers should be unique")
|
||||
err("return registers must be unique")
|
||||
|
||||
super.process(subroutine)
|
||||
checkSubroutinesPrecededByReturnOrJumpAndFollowedByLabelOrSub(subroutine.statements)
|
||||
@ -227,7 +227,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
for (stmt in statements) {
|
||||
if(checkNext) {
|
||||
if(stmt !is Label && stmt !is Subroutine)
|
||||
checkResult.add(SyntaxError("preceding subroutine definition at line ${preceding.position.line} should be followed here by a label, another subroutine statement, or nothing", stmt.position))
|
||||
checkResult.add(SyntaxError("preceding subroutine definition at line ${preceding.position.line} must be followed here by a label, another subroutine statement, or nothing", stmt.position))
|
||||
return
|
||||
}
|
||||
if(stmt is Subroutine) {
|
||||
@ -236,7 +236,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
&& preceding !is Subroutine
|
||||
&& preceding !is VarDecl
|
||||
&& preceding !is BuiltinFunctionStatementPlaceholder) {
|
||||
checkResult.add(SyntaxError("subroutine definition should be preceded by a return, jump, vardecl, or another subroutine statement", stmt.position))
|
||||
checkResult.add(SyntaxError("subroutine definition must be preceded by a return, jump, vardecl, or another subroutine statement", stmt.position))
|
||||
}
|
||||
checkNext=true
|
||||
}
|
||||
@ -437,7 +437,20 @@ class AstChecker(private val namespace: INameScope,
|
||||
checkResult.add(SyntaxError("floating point value used, but floating point is not enabled via options", literalValue.position))
|
||||
}
|
||||
checkValueTypeAndRange(literalValue.type, null, literalValue, heap)
|
||||
return super.process(literalValue)
|
||||
|
||||
val lv = super.process(literalValue)
|
||||
when(lv.type) {
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||
if(lv.heapId==null)
|
||||
throw FatalAstException("string should have been moved to heap at ${lv.position}")
|
||||
}
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
||||
if(lv.heapId==null)
|
||||
throw FatalAstException("array/matrix should have been moved to heap at ${lv.position}")
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
return lv
|
||||
}
|
||||
|
||||
override fun process(expr: BinaryExpression): IExpression {
|
||||
@ -639,14 +652,14 @@ class AstChecker(private val namespace: INameScope,
|
||||
DataType.ARRAY -> {
|
||||
// value may be either a single byte, or a byte array (of all constant values)
|
||||
if(value.type==DataType.ARRAY) {
|
||||
val array = heap.get(value.heapId!!).array!!
|
||||
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).array!!.size
|
||||
if(arrayspec!=null) {
|
||||
val constX = arrayspec.x.constValue(namespace, heap)
|
||||
if(constX?.asIntegerValue==null)
|
||||
return err("array size specifier must be constant integer value")
|
||||
val expectedSize = constX.asIntegerValue
|
||||
if (array.size != expectedSize)
|
||||
return err("initializer array size mismatch (expecting $expectedSize, got ${array.size})")
|
||||
if (arraySize != expectedSize)
|
||||
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
|
||||
}
|
||||
} else if(value.type==DataType.ARRAY_W) {
|
||||
return err("initialization value must be an array of bytes")
|
||||
@ -662,15 +675,15 @@ class AstChecker(private val namespace: INameScope,
|
||||
DataType.ARRAY_W -> {
|
||||
// value may be either a single word, or a word array
|
||||
if(value.type==DataType.ARRAY || value.type==DataType.ARRAY_W) {
|
||||
val array = heap.get(value.heapId!!).array!!
|
||||
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).array!!.size
|
||||
if(arrayspec!=null) {
|
||||
// arrayspec is not always known when checking
|
||||
val constX = arrayspec.x.constValue(namespace, heap)
|
||||
if(constX?.asIntegerValue==null)
|
||||
return err("array size specifier must be constant integer value")
|
||||
val expectedSize = constX.asIntegerValue
|
||||
if (array.size != expectedSize)
|
||||
return err("initializer array size mismatch (expecting $expectedSize, got ${array.size})")
|
||||
if (arraySize != expectedSize)
|
||||
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
|
||||
}
|
||||
} else {
|
||||
val number = value.asIntegerValue ?: return if (value.floatvalue!=null)
|
||||
|
@ -415,8 +415,16 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
DataType.BYTE -> stackvmProg.instr(Opcode.PUSH, Value(DataType.BYTE, lv.bytevalue!!))
|
||||
DataType.WORD -> stackvmProg.instr(Opcode.PUSH, Value(DataType.WORD, lv.wordvalue!!))
|
||||
DataType.FLOAT -> stackvmProg.instr(Opcode.PUSH, Value(DataType.FLOAT, lv.floatvalue!!))
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> stackvmProg.instr(Opcode.PUSH, Value(lv.type, lv.heapId!!))
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||
if(lv.heapId==null)
|
||||
throw CompilerException("string should have been moved into heap ${lv.position}")
|
||||
stackvmProg.instr(Opcode.PUSH, Value(lv.type, lv.heapId))
|
||||
}
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
||||
if(lv.heapId==null)
|
||||
throw CompilerException("array/matrix should have been moved into heap ${lv.position}")
|
||||
stackvmProg.instr(Opcode.PUSH, Value(lv.type, lv.heapId))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
val newArray = Array<IExpression>(size) { _ -> LiteralValue(DataType.BYTE, bytevalue = intvalue.toShort(), position = it.position) }
|
||||
decl.value = LiteralValue(DataType.ARRAY, arrayvalue = newArray, position = it.position)
|
||||
} else {
|
||||
addError(SyntaxError("matrix size spec should be constant integer values", it.position))
|
||||
addError(SyntaxError("matrix size spec must be constant integer values", it.position))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -79,7 +79,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
}
|
||||
decl.value = LiteralValue(decl.datatype, arrayvalue = newArray, position=it.position)
|
||||
} else {
|
||||
addError(SyntaxError("array size should be a constant integer value", it.position))
|
||||
addError(SyntaxError("array size must be a constant integer value", it.position))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -317,7 +317,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
val array = newArray.map {
|
||||
val litval = it as? LiteralValue
|
||||
if(litval==null) {
|
||||
addError(ExpressionError("array elements must all be constants", literalValue.position))
|
||||
addError(ExpressionError("array/matrix can contain only constant values", literalValue.position))
|
||||
return super.process(literalValue)
|
||||
}
|
||||
if(litval.bytevalue==null && litval.wordvalue==null) {
|
||||
@ -340,6 +340,8 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
val heapId = heap.add(arrayDt, array)
|
||||
val newValue = LiteralValue(arrayDt, heapId=heapId, position = literalValue.position)
|
||||
return super.process(newValue)
|
||||
} else {
|
||||
addError(ExpressionError("array/matrix can contain only constant values", literalValue.position))
|
||||
}
|
||||
|
||||
val newValue = LiteralValue(arrayDt, arrayvalue = newArray, position = literalValue.position)
|
||||
|
@ -477,15 +477,9 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
val value = evalstack.pop()
|
||||
when(value.type){
|
||||
DataType.BYTE, DataType.WORD, DataType.FLOAT -> print(value.numericValue())
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||
TODO("print stringvalue")
|
||||
}
|
||||
DataType.ARRAY, DataType.ARRAY_W -> {
|
||||
TODO("print array value")
|
||||
}
|
||||
DataType.MATRIX -> {
|
||||
TODO("print matrix value")
|
||||
}
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> print(heap.get(value.heapId).str)
|
||||
DataType.ARRAY, DataType.ARRAY_W -> print(heap.get(value.heapId).array!!.toList())
|
||||
DataType.MATRIX -> print(heap.get(value.heapId).array!!.toList())
|
||||
}
|
||||
}
|
||||
Syscall.INPUT_STR -> {
|
||||
@ -513,17 +507,7 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
Syscall.FUNC_RND -> evalstack.push(Value(DataType.BYTE, rnd.nextInt() and 255))
|
||||
Syscall.FUNC_RNDW -> evalstack.push(Value(DataType.WORD, rnd.nextInt() and 65535))
|
||||
Syscall.FUNC_RNDF -> evalstack.push(Value(DataType.FLOAT, rnd.nextDouble()))
|
||||
Syscall.FUNC_LEN -> {
|
||||
val value = evalstack.pop()
|
||||
TODO("func_len")
|
||||
// when(value.type) {
|
||||
// DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS ->
|
||||
// evalstack.push(Value(DataType.WORD, value.stringvalue!!.length))
|
||||
// DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX ->
|
||||
// evalstack.push(Value(DataType.WORD, value.arrayvalue!!.size))
|
||||
// else -> throw VmExecutionException("cannot get length of $value")
|
||||
// }
|
||||
}
|
||||
Syscall.FUNC_LEN -> throw VmExecutionException("len() should have been const-folded away everywhere (it's not possible on non-const values)")
|
||||
Syscall.FUNC_SIN -> evalstack.push(Value(DataType.FLOAT, sin(evalstack.pop().numericValue().toDouble())))
|
||||
Syscall.FUNC_COS -> evalstack.push(Value(DataType.FLOAT, cos(evalstack.pop().numericValue().toDouble())))
|
||||
Syscall.FUNC_ROUND -> evalstack.push(Value(DataType.WORD, evalstack.pop().numericValue().toDouble().roundToInt()))
|
||||
|
Loading…
Reference in New Issue
Block a user