fixed some type checks

This commit is contained in:
Irmen de Jong
2018-10-07 02:05:26 +02:00
parent 30b58c8567
commit 34d26e42e1
6 changed files with 60 additions and 59 deletions

View File

@@ -4,46 +4,13 @@
~ main { ~ main {
byte mainb = 44 byte[2] barray = 0
byte[2] barray2 =0
sub start() { sub start() {
test() X=barray[0]
test()
}
sub test() {
; @todo test assigning values to array vars
; @todo test creating const array vars
byte subb=42
for byte i in 0 to 2 {
float ff=3.3
byte bb=99
word ww=1999
_vm_write_num(ff)
_vm_write_char('\n')
_vm_write_num(bb)
_vm_write_char('\n')
_vm_write_num(ww)
_vm_write_char('\n')
_vm_write_num(subb)
_vm_write_char('\n')
_vm_write_num(mainb)
_vm_write_char('\n')
_vm_write_char('\n')
ff += 3
bb += 3
ww += 3
subb += 3
mainb += 3
}
return return
} }
} }

View File

@@ -254,9 +254,19 @@ class AstChecker(private val namespace: INameScope,
} }
} }
// it is not possible to assign a new array to something.
// currently, it's also not possible to assign a new string to a string variable.
when(assignment.value.resultingDatatype(namespace, heap)) {
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS ->
checkResult.add(SyntaxError("it's not possible to reassign a string", assignment.position)) // todo allow reassigning strings
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX ->
checkResult.add(SyntaxError("it's not possible to reassign an array", assignment.position))
else -> {}
}
if(assignment.aug_op!=null) { if(assignment.aug_op!=null) {
// check augmented assignment: // check augmented assignment:
// A /= 3 -> check is if it was A = A / 3 // A /= 3 -> check as if it was A = A / 3
val target: IExpression = val target: IExpression =
if(assignment.target.register!=null) if(assignment.target.register!=null)
RegisterExpr(assignment.target.register!!, assignment.target.position) RegisterExpr(assignment.target.register!!, assignment.target.position)
@@ -278,7 +288,13 @@ class AstChecker(private val namespace: INameScope,
if(targetDatatype!=null) { if(targetDatatype!=null) {
val constVal = assignment.value.constValue(namespace, heap) val constVal = assignment.value.constValue(namespace, heap)
if(constVal!=null) { if(constVal!=null) {
checkValueTypeAndRange(targetDatatype, null, constVal, heap) val arrayspec = if(assignment.target.identifier!=null) {
val targetVar = namespace.lookup(assignment.target.identifier!!.nameInSource, assignment) as? VarDecl
targetVar?.arrayspec
} else null
checkValueTypeAndRange(targetDatatype,
arrayspec ?: ArraySpec(LiteralValue.optimalInteger(-1, assignment.position), null, assignment.position),
constVal, heap)
} else { } else {
val sourceDatatype: DataType? = assignment.value.resultingDatatype(namespace, heap) val sourceDatatype: DataType? = assignment.value.resultingDatatype(namespace, heap)
if(sourceDatatype==null) { if(sourceDatatype==null) {
@@ -312,6 +328,12 @@ class AstChecker(private val namespace: INameScope,
err("recursive var declaration") err("recursive var declaration")
} }
// CONST can only occur on simple types (byte, word, float)
if(decl.type==VarDeclType.CONST) {
if (decl.datatype != DataType.BYTE && decl.datatype != DataType.WORD && decl.datatype != DataType.FLOAT)
err("const modifier can only be used on simple types (byte, word, float)")
}
when(decl.type) { when(decl.type) {
VarDeclType.VAR, VarDeclType.CONST -> { VarDeclType.VAR, VarDeclType.CONST -> {
if (decl.value == null) { if (decl.value == null) {
@@ -328,7 +350,9 @@ class AstChecker(private val namespace: INameScope,
} }
when { when {
decl.value is RangeExpr -> checkValueTypeAndRange(decl.datatype, decl.arrayspec, decl.value as RangeExpr) decl.value is RangeExpr -> checkValueTypeAndRange(decl.datatype, decl.arrayspec, decl.value as RangeExpr)
decl.value is LiteralValue -> checkValueTypeAndRange(decl.datatype, decl.arrayspec, decl.value as LiteralValue, heap) decl.value is LiteralValue -> checkValueTypeAndRange(decl.datatype,
decl.arrayspec ?: ArraySpec(LiteralValue.optimalInteger(-2, decl.position), null, decl.position),
decl.value as LiteralValue, heap)
else -> { else -> {
err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!::class.simpleName}") err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!::class.simpleName}")
return super.process(decl) return super.process(decl)
@@ -421,7 +445,9 @@ class AstChecker(private val namespace: INameScope,
if(!compilerOptions.floats && literalValue.type==DataType.FLOAT) { if(!compilerOptions.floats && literalValue.type==DataType.FLOAT) {
checkResult.add(SyntaxError("floating point value used, but floating point is not enabled via options", literalValue.position)) checkResult.add(SyntaxError("floating point value used, but floating point is not enabled via options", literalValue.position))
} }
checkValueTypeAndRange(literalValue.type, null, literalValue, heap) checkValueTypeAndRange(literalValue.type,
ArraySpec(LiteralValue.optimalInteger(-3, literalValue.position), null, literalValue.position),
literalValue, heap)
val lv = super.process(literalValue) val lv = super.process(literalValue)
when(lv.type) { when(lv.type) {
@@ -632,7 +658,7 @@ class AstChecker(private val namespace: INameScope,
} }
} }
private fun checkValueTypeAndRange(targetDt: DataType, arrayspec: ArraySpec?, value: LiteralValue, heap: HeapValues) : Boolean { private fun checkValueTypeAndRange(targetDt: DataType, arrayspec: ArraySpec, value: LiteralValue, heap: HeapValues) : Boolean {
fun err(msg: String) : Boolean { fun err(msg: String) : Boolean {
checkResult.add(ExpressionError(msg, value.position)) checkResult.add(ExpressionError(msg, value.position))
return false return false
@@ -673,7 +699,8 @@ class AstChecker(private val namespace: INameScope,
// value may be either a single byte, or a byte array (of all constant values) // value may be either a single byte, or a byte array (of all constant values)
if(value.type==DataType.ARRAY) { if(value.type==DataType.ARRAY) {
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).array!!.size val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).array!!.size
if(arrayspec!=null) { val arraySpecSize = arrayspec.size()
if(arraySpecSize!=null && arraySpecSize>0) {
val constX = arrayspec.x.constValue(namespace, heap) val constX = arrayspec.x.constValue(namespace, heap)
if(constX?.asIntegerValue==null) if(constX?.asIntegerValue==null)
return err("array size specifier must be constant integer value") return err("array size specifier must be constant integer value")
@@ -696,7 +723,8 @@ class AstChecker(private val namespace: INameScope,
// value may be either a single word, or a word array // value may be either a single word, or a word array
if(value.type==DataType.ARRAY || value.type==DataType.ARRAY_W) { if(value.type==DataType.ARRAY || value.type==DataType.ARRAY_W) {
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).array!!.size val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).array!!.size
if(arrayspec!=null) { val arraySpecSize = arrayspec.size()
if(arraySpecSize!=null && arraySpecSize>0) {
// arrayspec is not always known when checking // arrayspec is not always known when checking
val constX = arrayspec.x.constValue(namespace, heap) val constX = arrayspec.x.constValue(namespace, heap)
if(constX?.asIntegerValue==null) if(constX?.asIntegerValue==null)
@@ -717,8 +745,9 @@ class AstChecker(private val namespace: INameScope,
DataType.ARRAY_F -> { DataType.ARRAY_F -> {
// value may be either a single float, or a float array // value may be either a single float, or a float array
if(value.type==DataType.ARRAY || value.type==DataType.ARRAY_W || value.type==DataType.ARRAY_F) { if(value.type==DataType.ARRAY || value.type==DataType.ARRAY_W || value.type==DataType.ARRAY_F) {
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).doubleArray!!.size val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).arraysize
if(arrayspec!=null) { val arraySpecSize = arrayspec.size()
if(arraySpecSize!=null && arraySpecSize>0) {
// arrayspec is not always known when checking // arrayspec is not always known when checking
val constX = arrayspec.x.constValue(namespace, heap) val constX = arrayspec.x.constValue(namespace, heap)
if(constX?.asIntegerValue==null) if(constX?.asIntegerValue==null)
@@ -728,16 +757,18 @@ class AstChecker(private val namespace: INameScope,
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)") return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
} }
} else { } else {
val number = value.asNumericValue!!.toDouble() val number = value.asNumericValue?.toDouble()
if (number < FLOAT_MAX_NEGATIVE || number > FLOAT_MAX_POSITIVE) if(number==null)
return err("expected numerical value")
else if (number < FLOAT_MAX_NEGATIVE || number > FLOAT_MAX_POSITIVE)
return err("value '$number' out of range for mfplt5 floating point") return err("value '$number' out of range for mfplt5 floating point")
} }
} }
DataType.MATRIX -> { DataType.MATRIX -> {
// value can only be a single byte, or a byte array (which represents the matrix) // value can only be a single byte, or a byte array (which represents the matrix)
if(value.type==DataType.ARRAY || value.type==DataType.MATRIX) { if(value.type==DataType.ARRAY || value.type==DataType.MATRIX) {
if(arrayspec!=null) { val arraySpecSize = arrayspec.size()
// arrayspec is not always known when checking if(arraySpecSize!=null && arraySpecSize>0) {
val constX = arrayspec.x.constValue(namespace, heap) val constX = arrayspec.x.constValue(namespace, heap)
val constY = arrayspec.y!!.constValue(namespace, heap) val constY = arrayspec.y!!.constValue(namespace, heap)
if (constX?.asIntegerValue == null || constY?.asIntegerValue == null) if (constX?.asIntegerValue == null || constY?.asIntegerValue == null)

View File

@@ -66,6 +66,8 @@ class HeapValues {
result = 31 * result + (doubleArray?.let { Arrays.hashCode(it) } ?: 0) result = 31 * result + (doubleArray?.let { Arrays.hashCode(it) } ?: 0)
return result return result
} }
val arraysize: Int = array?.size ?: doubleArray?.size ?: 0
} }
private val heap = mutableListOf<HeapValue>() private val heap = mutableListOf<HeapValue>()
@@ -1204,10 +1206,10 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
} }
} }
// todo: maybe if you assign byte or word to array/matrix, clear it with that value?
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
null -> throw CompilerException("could not determine targetdt") null -> throw CompilerException("could not determine targetdt")
// todo: maybe if you assign byte or word to array/matrix, clear it with that value?
} }
} }

View File

@@ -105,14 +105,17 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
} }
/** /**
* replace identifiers that refer to const value, with the value itself * replace identifiers that refer to const value, with the value itself (if it's a simple type)
*/ */
override fun process(identifier: IdentifierReference): IExpression { override fun process(identifier: IdentifierReference): IExpression {
return try { return try {
val cval = identifier.constValue(namespace, heap) ?: return identifier val cval = identifier.constValue(namespace, heap) ?: return identifier
val copy = LiteralValue(cval.type, cval.bytevalue, cval.wordvalue, cval.floatvalue, cval.strvalue, cval.arrayvalue, position=identifier.position) return if(cval.isNumeric) {
val copy = LiteralValue(cval.type, cval.bytevalue, cval.wordvalue, cval.floatvalue, cval.strvalue, cval.arrayvalue, position = identifier.position)
copy.parent = identifier.parent copy.parent = identifier.parent
return copy copy
} else
identifier
} catch (ax: AstException) { } catch (ax: AstException) {
addError(ax) addError(ax)
identifier identifier

View File

@@ -233,7 +233,7 @@ Special types: const and memory-mapped
When using ``const``, the value of the 'variable' can no longer be changed. When using ``const``, the value of the 'variable' can no longer be changed.
You'll have to specify the initial value expression. This value is then used You'll have to specify the initial value expression. This value is then used
by the compiler everywhere you refer to the constant (and no storage is allocated by the compiler everywhere you refer to the constant (and no storage is allocated
for the constant itself). for the constant itself). This is only valid for the simple numeric types (byte, word, float).
When using ``memory``, the variable will point to specific location in memory, When using ``memory``, the variable will point to specific location in memory,
rather than being newly allocated. The initial value (mandatory) must be a valid rather than being newly allocated. The initial value (mandatory) must be a valid

View File

@@ -288,11 +288,9 @@ Constants
All variables can be assigned new values unless you use the ``const`` keyword. All variables can be assigned new values unless you use the ``const`` keyword.
The initial value will now be evaluated at compile time (it must be a compile time constant expression). The initial value will now be evaluated at compile time (it must be a compile time constant expression).
Storage is allocated only for the constant values that remain a the end of this process and that This is only valid for the simple numeric types (byte, word, float)::
require it (floats, strings, arrays, matrices)::
const byte max_age = 99 const byte max_age = 99
const str someName = "Peter"
Reserved names Reserved names