enforce const on array/matrix values

This commit is contained in:
Irmen de Jong 2018-09-29 18:05:35 +02:00
parent 6b89bb7be5
commit 5ee427b72b
5 changed files with 45 additions and 38 deletions

View File

@ -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
}

View File

@ -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)

View File

@ -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))
}
}
}
}

View File

@ -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)

View File

@ -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()))