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 {
byte mainb = 44
byte[2] barray = 0
byte[2] barray2 =0
sub start() {
test()
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
}
X=barray[0]
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) {
// 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 =
if(assignment.target.register!=null)
RegisterExpr(assignment.target.register!!, assignment.target.position)
@ -278,7 +288,13 @@ class AstChecker(private val namespace: INameScope,
if(targetDatatype!=null) {
val constVal = assignment.value.constValue(namespace, heap)
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 {
val sourceDatatype: DataType? = assignment.value.resultingDatatype(namespace, heap)
if(sourceDatatype==null) {
@ -312,6 +328,12 @@ class AstChecker(private val namespace: INameScope,
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) {
VarDeclType.VAR, VarDeclType.CONST -> {
if (decl.value == null) {
@ -328,7 +350,9 @@ class AstChecker(private val namespace: INameScope,
}
when {
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 -> {
err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!::class.simpleName}")
return super.process(decl)
@ -421,7 +445,9 @@ class AstChecker(private val namespace: INameScope,
if(!compilerOptions.floats && literalValue.type==DataType.FLOAT) {
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)
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 {
checkResult.add(ExpressionError(msg, value.position))
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)
if(value.type==DataType.ARRAY) {
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)
if(constX?.asIntegerValue==null)
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
if(value.type==DataType.ARRAY || value.type==DataType.ARRAY_W) {
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
val constX = arrayspec.x.constValue(namespace, heap)
if(constX?.asIntegerValue==null)
@ -717,8 +745,9 @@ class AstChecker(private val namespace: INameScope,
DataType.ARRAY_F -> {
// 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) {
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).doubleArray!!.size
if(arrayspec!=null) {
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).arraysize
val arraySpecSize = arrayspec.size()
if(arraySpecSize!=null && arraySpecSize>0) {
// arrayspec is not always known when checking
val constX = arrayspec.x.constValue(namespace, heap)
if(constX?.asIntegerValue==null)
@ -728,16 +757,18 @@ class AstChecker(private val namespace: INameScope,
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
}
} else {
val number = value.asNumericValue!!.toDouble()
if (number < FLOAT_MAX_NEGATIVE || number > FLOAT_MAX_POSITIVE)
val number = value.asNumericValue?.toDouble()
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")
}
}
DataType.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(arrayspec!=null) {
// arrayspec is not always known when checking
val arraySpecSize = arrayspec.size()
if(arraySpecSize!=null && arraySpecSize>0) {
val constX = arrayspec.x.constValue(namespace, heap)
val constY = arrayspec.y!!.constValue(namespace, heap)
if (constX?.asIntegerValue == null || constY?.asIntegerValue == null)

View File

@ -66,6 +66,8 @@ class HeapValues {
result = 31 * result + (doubleArray?.let { Arrays.hashCode(it) } ?: 0)
return result
}
val arraysize: Int = array?.size ?: doubleArray?.size ?: 0
}
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")
}
}
// 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.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")
// 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 {
return try {
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)
copy.parent = identifier.parent
return copy
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
} else
identifier
} catch (ax: AstException) {
addError(ax)
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.
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
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,
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.
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
require it (floats, strings, arrays, matrices)::
This is only valid for the simple numeric types (byte, word, float)::
const byte max_age = 99
const str someName = "Peter"
Reserved names