mirror of
https://github.com/irmen/prog8.git
synced 2024-10-01 22:56:10 +00:00
made position required to avoid some bugs where it was not specified
fixed some type checking bugs
This commit is contained in:
parent
ba81f32080
commit
28aaf38f22
@ -469,8 +469,8 @@ sum(x)
|
|||||||
Sum of the values in the non-scalar (array or matrix) value x
|
Sum of the values in the non-scalar (array or matrix) value x
|
||||||
|
|
||||||
len(x)
|
len(x)
|
||||||
Number of values in the non-scalar (array or matrix) value x.
|
Number of values in the array or matrix value x, or the number of characters in a string (excluding the size or 0-byte).
|
||||||
(This is different from the number of *bytes* in memory if the datatype isn't byte)
|
Note: this can be different from the number of *bytes* in memory if the datatype isn't a byte.
|
||||||
|
|
||||||
lsb(x)
|
lsb(x)
|
||||||
Get the least significant byte of the word x.
|
Get the least significant byte of the word x.
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
~ not_main $d000 {
|
~ not_main $d000 {
|
||||||
byte [100] array1 = 0
|
byte [100] array1 = 0
|
||||||
word [100] array2 = 1
|
word [100] array2 = 1
|
||||||
|
word [4] array2b = [1,2,3,4]
|
||||||
byte [2,3] matrix1 = 2
|
byte [2,3] matrix1 = 2
|
||||||
byte [2,3] matrix2 = [1,2,3,4,5,6]
|
byte [2,3] matrix2 = [1,2,3,4,5,6]
|
||||||
|
|
||||||
@ -113,7 +114,7 @@
|
|||||||
equalQQ= len("abcdef")
|
equalQQ= len("abcdef")
|
||||||
equalQQ= len([1,2,3])
|
equalQQ= len([1,2,3])
|
||||||
equalQQ= len(string1)
|
equalQQ= len(string1)
|
||||||
equalQQ= len(string2) ; @todo len function call on str type ALSO ADD ALL THIS TO DOCS OF FUNCTION LEN!
|
equalQQ= len(string2)
|
||||||
P_carry(1)
|
P_carry(1)
|
||||||
P_irqd(0)
|
P_irqd(0)
|
||||||
|
|
||||||
@ -140,10 +141,10 @@
|
|||||||
|
|
||||||
if(6==6) {
|
if(6==6) {
|
||||||
A=sin(X) ; @todo should give error of float loss of precision
|
A=sin(X) ; @todo should give error of float loss of precision
|
||||||
X=max([1,2,Y]) ; @todo must be byte so should be ok
|
X=max([1,233,Y])
|
||||||
X=min([1,2,Y]) ; @todo must be byte so should be ok
|
X=min([1,2,Y])
|
||||||
X=lsl(12)
|
X=lsl(12)
|
||||||
X=lsl(Y) ; @todo must be byte so should be ok
|
X=lsl(Y)
|
||||||
P_carry(0)
|
P_carry(0)
|
||||||
P_carry(1)
|
P_carry(1)
|
||||||
P_carry(1-1)
|
P_carry(1-1)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
IL65_LIBDIR=../lib65
|
IL65_LIBDIR=../lib65
|
||||||
IL65CLASSPATH=out/production/il65
|
IL65CLASSPATH=out/production/il65
|
||||||
|
@ -42,8 +42,7 @@ fun main(args: Array<String>) {
|
|||||||
if(outputType==null) OutputType.PRG else OutputType.valueOf(outputType),
|
if(outputType==null) OutputType.PRG else OutputType.valueOf(outputType),
|
||||||
if(launcherType==null) LauncherType.BASIC else LauncherType.valueOf(launcherType),
|
if(launcherType==null) LauncherType.BASIC else LauncherType.valueOf(launcherType),
|
||||||
if(zpType==null) ZeropageType.KERNALSAFE else ZeropageType.valueOf(zpType),
|
if(zpType==null) ZeropageType.KERNALSAFE else ZeropageType.valueOf(zpType),
|
||||||
options.contains(DirectiveArg(null, "enable_floats", null))
|
options.any{ it.name=="enable_floats"})
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
// perform syntax checks and optimizations
|
// perform syntax checks and optimizations
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -163,7 +163,7 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
|||||||
val targetDatatype = assignment.target.determineDatatype(namespace, assignment)
|
val targetDatatype = assignment.target.determineDatatype(namespace, assignment)
|
||||||
val constVal = assignment.value.constValue(namespace)
|
val constVal = assignment.value.constValue(namespace)
|
||||||
if(constVal!=null) {
|
if(constVal!=null) {
|
||||||
checkValueTypeAndRange(targetDatatype, null, assignment.value as LiteralValue, assignment.position)
|
checkValueTypeAndRange(targetDatatype, null, assignment.value as LiteralValue)
|
||||||
} else {
|
} else {
|
||||||
val sourceDatatype: DataType? = assignment.value.resultingDatatype(namespace)
|
val sourceDatatype: DataType? = assignment.value.resultingDatatype(namespace)
|
||||||
if(sourceDatatype==null) {
|
if(sourceDatatype==null) {
|
||||||
@ -212,7 +212,7 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
|||||||
return super.process(decl)
|
return super.process(decl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkValueTypeAndRange(decl.datatype, decl.arrayspec, decl.value as LiteralValue, decl.position)
|
checkValueTypeAndRange(decl.datatype, decl.arrayspec, decl.value as LiteralValue)
|
||||||
}
|
}
|
||||||
VarDeclType.MEMORY -> {
|
VarDeclType.MEMORY -> {
|
||||||
if(decl.value !is LiteralValue) {
|
if(decl.value !is LiteralValue) {
|
||||||
@ -310,14 +310,10 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun process(literalValue: LiteralValue): LiteralValue {
|
override fun process(literalValue: LiteralValue): LiteralValue {
|
||||||
if(!compilerOptions.floats && literalValue.isFloat) {
|
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))
|
||||||
}
|
}
|
||||||
when {
|
checkValueTypeAndRange(literalValue.type, null, literalValue)
|
||||||
literalValue.isByte -> checkValueTypeAndRange(DataType.BYTE, null, literalValue, literalValue.position)
|
|
||||||
literalValue.isWord -> checkValueTypeAndRange(DataType.WORD, null, literalValue, literalValue.position)
|
|
||||||
literalValue.isFloat -> checkValueTypeAndRange(DataType.FLOAT, null, literalValue, literalValue.position)
|
|
||||||
}
|
|
||||||
return super.process(literalValue)
|
return super.process(literalValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,7 +385,7 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkBuiltinFunctionCall(call: IFunctionCall, position: Position?) {
|
private fun checkBuiltinFunctionCall(call: IFunctionCall, position: Position) {
|
||||||
if(call.target.nameInSource.size==1 && BuiltinFunctionNames.contains(call.target.nameInSource[0])) {
|
if(call.target.nameInSource.size==1 && BuiltinFunctionNames.contains(call.target.nameInSource[0])) {
|
||||||
val functionName = call.target.nameInSource[0]
|
val functionName = call.target.nameInSource[0]
|
||||||
if(functionName=="P_carry" || functionName=="P_irqd") {
|
if(functionName=="P_carry" || functionName=="P_irqd") {
|
||||||
@ -406,9 +402,9 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkValueTypeAndRange(datatype: DataType, arrayspec: ArraySpec?, value: LiteralValue, position: Position?) : Boolean {
|
private fun checkValueTypeAndRange(datatype: DataType, arrayspec: ArraySpec?, value: LiteralValue) : Boolean {
|
||||||
fun err(msg: String) : Boolean {
|
fun err(msg: String) : Boolean {
|
||||||
checkResult.add(ExpressionError(msg, position))
|
checkResult.add(ExpressionError(msg, value.position))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
when (datatype) {
|
when (datatype) {
|
||||||
@ -442,17 +438,27 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
|||||||
}
|
}
|
||||||
DataType.ARRAY -> {
|
DataType.ARRAY -> {
|
||||||
// value may be either a single byte, or a byte array
|
// value may be either a single byte, or a byte array
|
||||||
if(value.isArray) {
|
if(value.type==DataType.ARRAY) {
|
||||||
for (av in value.arrayvalue!!) {
|
for (av in value.arrayvalue!!) {
|
||||||
val number = (av as LiteralValue).bytevalue
|
if(arrayspec!=null) {
|
||||||
?: return err("array must be all bytes")
|
// arrayspec is not always known when checking
|
||||||
|
val expectedSize = arrayspec.x.constValue(namespace)?.asIntegerValue
|
||||||
|
if (value.arrayvalue.size != expectedSize)
|
||||||
|
return err("initializer array size mismatch (expecting $expectedSize, got ${value.arrayvalue.size})")
|
||||||
|
}
|
||||||
|
|
||||||
val expectedSize = arrayspec?.x?.constValue(namespace)?.asIntegerValue
|
if(av is LiteralValue) {
|
||||||
if (value.arrayvalue.size != expectedSize)
|
val number = av.bytevalue
|
||||||
return err("initializer array size mismatch (expecting $expectedSize, got ${value.arrayvalue.size})")
|
?: return err("array must be all bytes")
|
||||||
|
if (number < 0 || number > 255)
|
||||||
|
return err("value '$number' in byte array is out of range for unsigned byte")
|
||||||
|
} else if(av is RegisterExpr) {
|
||||||
|
if(av.register!=Register.A && av.register!=Register.X && av.register!=Register.Y)
|
||||||
|
return err("register '$av' in byte array is not a single register")
|
||||||
|
} else {
|
||||||
|
TODO("array value $av")
|
||||||
|
}
|
||||||
|
|
||||||
if (number < 0 || number > 255)
|
|
||||||
return err("value '$number' in byte array is out of range for unsigned byte")
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val number = value.bytevalue ?: return if (value.floatvalue!=null)
|
val number = value.bytevalue ?: return if (value.floatvalue!=null)
|
||||||
@ -465,14 +471,17 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
|||||||
}
|
}
|
||||||
DataType.ARRAY_W -> {
|
DataType.ARRAY_W -> {
|
||||||
// value may be either a single word, or a word array
|
// value may be either a single word, or a word array
|
||||||
if(value.isArray) {
|
if(value.type==DataType.ARRAY || value.type==DataType.ARRAY_W) {
|
||||||
for (av in value.arrayvalue!!) {
|
for (av in value.arrayvalue!!) {
|
||||||
val number = (av as LiteralValue).asIntegerValue // both byte and word are acceptable
|
val number = (av as LiteralValue).asIntegerValue // both byte and word are acceptable
|
||||||
?: return err("array must be all words")
|
?: return err("array must be all words")
|
||||||
|
|
||||||
val expectedSize = arrayspec!!.x.constValue(namespace)?.asIntegerValue
|
if(arrayspec!=null) {
|
||||||
if (value.arrayvalue.size != expectedSize)
|
// arrayspec is not always known when checking
|
||||||
return err("initializer array size mismatch (expecting $expectedSize, got ${value.arrayvalue.size})")
|
val expectedSize = arrayspec.x.constValue(namespace)?.asIntegerValue
|
||||||
|
if (value.arrayvalue.size != expectedSize)
|
||||||
|
return err("initializer array size mismatch (expecting $expectedSize, got ${value.arrayvalue.size})")
|
||||||
|
}
|
||||||
|
|
||||||
if (number < 0 || number > 65535)
|
if (number < 0 || number > 65535)
|
||||||
return err("value '$number' in word array is out of range for unsigned word")
|
return err("value '$number' in word array is out of range for unsigned word")
|
||||||
@ -489,7 +498,7 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
|||||||
}
|
}
|
||||||
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.isArray) {
|
if(value.type==DataType.ARRAY) {
|
||||||
for (av in value.arrayvalue!!) {
|
for (av in value.arrayvalue!!) {
|
||||||
val number = (av as LiteralValue).bytevalue
|
val number = (av as LiteralValue).bytevalue
|
||||||
?: return err("array must be all bytes")
|
?: return err("array must be all bytes")
|
||||||
@ -514,7 +523,7 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkAssignmentCompatible(targetDatatype: DataType, sourceDatatype: DataType, position: Position?) : Boolean {
|
private fun checkAssignmentCompatible(targetDatatype: DataType, sourceDatatype: DataType, position: Position) : Boolean {
|
||||||
val result = when(targetDatatype) {
|
val result = when(targetDatatype) {
|
||||||
DataType.BYTE -> sourceDatatype==DataType.BYTE
|
DataType.BYTE -> sourceDatatype==DataType.BYTE
|
||||||
DataType.WORD -> sourceDatatype==DataType.BYTE || sourceDatatype==DataType.WORD
|
DataType.WORD -> sourceDatatype==DataType.BYTE || sourceDatatype==DataType.WORD
|
||||||
|
@ -32,8 +32,8 @@ class AstIdentifiersChecker : IAstProcessor {
|
|||||||
return checkResult
|
return checkResult
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nameError(name: String, position: Position?, existing: IStatement) {
|
private fun nameError(name: String, position: Position, existing: IStatement) {
|
||||||
checkResult.add(NameError("name conflict '$name', first defined in ${existing.position?.file} line ${existing.position?.line}", position))
|
checkResult.add(NameError("name conflict '$name', first defined in ${existing.position.file} line ${existing.position.line}", position))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun process(block: Block): IStatement {
|
override fun process(block: Block): IStatement {
|
||||||
@ -48,12 +48,8 @@ class AstIdentifiersChecker : IAstProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun process(decl: VarDecl): IStatement {
|
override fun process(decl: VarDecl): IStatement {
|
||||||
// first, set the datatype
|
// first, check if there are datatype errors on the vardecl
|
||||||
try {
|
decl.datatypeErrors.forEach { checkResult.add(it) }
|
||||||
decl.setDatatype()
|
|
||||||
} catch(ax: AstException) {
|
|
||||||
checkResult.add(ax)
|
|
||||||
}
|
|
||||||
|
|
||||||
// now check the identifier
|
// now check the identifier
|
||||||
if(BuiltinFunctionNames.contains(decl.name))
|
if(BuiltinFunctionNames.contains(decl.name))
|
||||||
|
@ -96,7 +96,7 @@ class AstRecursionChecker(private val namespace: INameScope) : IAstProcessor {
|
|||||||
if(cycle.isEmpty())
|
if(cycle.isEmpty())
|
||||||
return emptyList()
|
return emptyList()
|
||||||
val chain = cycle.joinToString(" <-- ") { "${it.name} at ${it.position}" }
|
val chain = cycle.joinToString(" <-- ") { "${it.name} at ${it.position}" }
|
||||||
return listOf(AstException("Program contains recursive subroutine calls, this is not supported. Recursive chain:\n (a subroutine call in) "+chain))
|
return listOf(AstException("Program contains recursive subroutine calls, this is not supported. Recursive chain:\n (a subroutine call in) $chain"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun process(functionCall: FunctionCallStatement): IStatement {
|
override fun process(functionCall: FunctionCallStatement): IStatement {
|
||||||
|
@ -109,7 +109,7 @@ class Compiler(private val options: CompilationOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class VarGatherer(val stackvmProg: StackVmProgram): IAstProcessor {
|
class VarGatherer(private val stackvmProg: StackVmProgram): IAstProcessor {
|
||||||
// collect all the VarDecls to make them into one global list
|
// collect all the VarDecls to make them into one global list
|
||||||
override fun process(decl: VarDecl): IStatement {
|
override fun process(decl: VarDecl): IStatement {
|
||||||
if(decl.type == VarDeclType.MEMORY)
|
if(decl.type == VarDeclType.MEMORY)
|
||||||
@ -122,7 +122,7 @@ class Compiler(private val options: CompilationOptions) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StatementTranslator(val stackvmProg: StackVmProgram, val namespace: INameScope): IAstProcessor {
|
class StatementTranslator(private val stackvmProg: StackVmProgram, private val namespace: INameScope): IAstProcessor {
|
||||||
var stmtUniqueSequenceNr = 0
|
var stmtUniqueSequenceNr = 0
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@ -269,16 +269,16 @@ class Compiler(private val options: CompilationOptions) {
|
|||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val lv = expr.constValue(namespace) ?: throw CompilerException("constant expression required, not $expr")
|
val lv = expr.constValue(namespace) ?: throw CompilerException("constant expression required, not $expr")
|
||||||
when {
|
when(lv.type) {
|
||||||
lv.isString -> stackvmProg.instruction("push \"${lv.strvalue}\"")
|
DataType.BYTE -> stackvmProg.instruction("push b:${lv.bytevalue!!.toString(16)}")
|
||||||
lv.isByte -> stackvmProg.instruction("push b:${lv.bytevalue!!.toString(16)}")
|
DataType.WORD -> stackvmProg.instruction("push w:${lv.wordvalue!!.toString(16)}")
|
||||||
lv.isWord -> stackvmProg.instruction("push w:${lv.wordvalue!!.toString(16)}")
|
DataType.FLOAT -> stackvmProg.instruction("push f:${lv.floatvalue}")
|
||||||
lv.isFloat -> stackvmProg.instruction("push f:${lv.floatvalue}")
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> stackvmProg.instruction("push \"${lv.strvalue}\"")
|
||||||
lv.isArray -> {
|
DataType.ARRAY, DataType.ARRAY_W -> {
|
||||||
lv.arrayvalue?.forEach { translate(it) }
|
lv.arrayvalue?.forEach { translate(it) }
|
||||||
stackvmProg.instruction("array w:${lv.arrayvalue!!.size.toString(16)}")
|
stackvmProg.instruction("array w:${lv.arrayvalue!!.size.toString(16)}")
|
||||||
}
|
}
|
||||||
else -> throw CompilerException("expression constvalue invalid type $lv")
|
DataType.MATRIX -> TODO("matrix type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -448,11 +448,11 @@ class StackVmProgram(val name: String) {
|
|||||||
throw AssertionError("Should be only VAR or CONST variables")
|
throw AssertionError("Should be only VAR or CONST variables")
|
||||||
}
|
}
|
||||||
val litval = v.value.value as LiteralValue
|
val litval = v.value.value as LiteralValue
|
||||||
val litvalStr = when {
|
val litvalStr = when(litval.type) {
|
||||||
litval.isByte -> litval.bytevalue!!.toString(16)
|
DataType.BYTE -> litval.bytevalue!!.toString(16)
|
||||||
litval.isWord -> litval.wordvalue!!.toString(16)
|
DataType.WORD -> litval.wordvalue!!.toString(16)
|
||||||
litval.isFloat -> litval.floatvalue.toString()
|
DataType.FLOAT -> litval.floatvalue.toString()
|
||||||
litval.isString -> "\"${litval.strvalue}\""
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> "\"${litval.strvalue}\""
|
||||||
else -> TODO("non-scalar value")
|
else -> TODO("non-scalar value")
|
||||||
}
|
}
|
||||||
val line = "${v.key} ${v.value.datatype.toString().toLowerCase()} $litvalStr"
|
val line = "${v.key} ${v.value.datatype.toString().toLowerCase()} $litvalStr"
|
||||||
|
@ -17,40 +17,40 @@ val BuiltinFunctionsWithoutSideEffects = BuiltinFunctionNames - setOf("P_carry",
|
|||||||
class NotConstArgumentException: AstException("not a const argument to a built-in function")
|
class NotConstArgumentException: AstException("not a const argument to a built-in function")
|
||||||
|
|
||||||
|
|
||||||
private fun oneDoubleArg(args: List<IExpression>, position: Position?, namespace:INameScope, function: (arg: Double)->Number): LiteralValue {
|
private fun oneDoubleArg(args: List<IExpression>, position: Position, namespace:INameScope, function: (arg: Double)->Number): LiteralValue {
|
||||||
if(args.size!=1)
|
if(args.size!=1)
|
||||||
throw SyntaxError("built-in function requires one floating point argument", position)
|
throw SyntaxError("built-in function requires one floating point argument", position)
|
||||||
val constval = args[0].constValue(namespace) ?: throw NotConstArgumentException()
|
val constval = args[0].constValue(namespace) ?: throw NotConstArgumentException()
|
||||||
if(!constval.isFloat)
|
if(constval.type!=DataType.FLOAT)
|
||||||
throw SyntaxError("built-in function requires one floating point argument", position)
|
throw SyntaxError("built-in function requires one floating point argument", position)
|
||||||
|
|
||||||
val float = constval.asNumericValue?.toDouble()!!
|
val float = constval.asNumericValue?.toDouble()!!
|
||||||
return numericLiteral(function(float), args[0].position)
|
return numericLiteral(function(float), args[0].position)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun oneDoubleArgOutputInt(args: List<IExpression>, position: Position?, namespace:INameScope, function: (arg: Double)->Number): LiteralValue {
|
private fun oneDoubleArgOutputInt(args: List<IExpression>, position: Position, namespace:INameScope, function: (arg: Double)->Number): LiteralValue {
|
||||||
if(args.size!=1)
|
if(args.size!=1)
|
||||||
throw SyntaxError("built-in function requires one floating point argument", position)
|
throw SyntaxError("built-in function requires one floating point argument", position)
|
||||||
val constval = args[0].constValue(namespace) ?: throw NotConstArgumentException()
|
val constval = args[0].constValue(namespace) ?: throw NotConstArgumentException()
|
||||||
if(!constval.isFloat)
|
if(constval.type!=DataType.FLOAT)
|
||||||
throw SyntaxError("built-in function requires one floating point argument", position)
|
throw SyntaxError("built-in function requires one floating point argument", position)
|
||||||
|
|
||||||
val float = constval.asNumericValue?.toDouble()!!
|
val float = constval.asNumericValue?.toDouble()!!
|
||||||
return numericLiteral(function(float).toInt(), args[0].position)
|
return numericLiteral(function(float).toInt(), args[0].position)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun oneIntArgOutputInt(args: List<IExpression>, position: Position?, namespace:INameScope, function: (arg: Int)->Number): LiteralValue {
|
private fun oneIntArgOutputInt(args: List<IExpression>, position: Position, namespace:INameScope, function: (arg: Int)->Number): LiteralValue {
|
||||||
if(args.size!=1)
|
if(args.size!=1)
|
||||||
throw SyntaxError("built-in function requires one integer argument", position)
|
throw SyntaxError("built-in function requires one integer argument", position)
|
||||||
val constval = args[0].constValue(namespace) ?: throw NotConstArgumentException()
|
val constval = args[0].constValue(namespace) ?: throw NotConstArgumentException()
|
||||||
if(!constval.isInteger)
|
if(constval.type!=DataType.BYTE && constval.type!=DataType.WORD)
|
||||||
throw SyntaxError("built-in function requires one integer argument", position)
|
throw SyntaxError("built-in function requires one integer argument", position)
|
||||||
|
|
||||||
val integer = constval.asNumericValue?.toInt()!!
|
val integer = constval.asNumericValue?.toInt()!!
|
||||||
return numericLiteral(function(integer).toInt(), args[0].position)
|
return numericLiteral(function(integer).toInt(), args[0].position)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun collectionArgOutputNumber(args: List<IExpression>, position: Position?, namespace:INameScope,
|
private fun collectionArgOutputNumber(args: List<IExpression>, position: Position, namespace:INameScope,
|
||||||
function: (arg: Collection<Double>)->Number): LiteralValue {
|
function: (arg: Collection<Double>)->Number): LiteralValue {
|
||||||
if(args.size!=1)
|
if(args.size!=1)
|
||||||
throw SyntaxError("builtin function requires one non-scalar argument", position)
|
throw SyntaxError("builtin function requires one non-scalar argument", position)
|
||||||
@ -64,7 +64,7 @@ private fun collectionArgOutputNumber(args: List<IExpression>, position: Positio
|
|||||||
return numericLiteral(result, args[0].position)
|
return numericLiteral(result, args[0].position)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun collectionArgOutputBoolean(args: List<IExpression>, position: Position?, namespace:INameScope,
|
private fun collectionArgOutputBoolean(args: List<IExpression>, position: Position, namespace:INameScope,
|
||||||
function: (arg: Collection<Double>)->Boolean): LiteralValue {
|
function: (arg: Collection<Double>)->Boolean): LiteralValue {
|
||||||
if(args.size!=1)
|
if(args.size!=1)
|
||||||
throw SyntaxError("builtin function requires one non-scalar argument", position)
|
throw SyntaxError("builtin function requires one non-scalar argument", position)
|
||||||
@ -75,52 +75,52 @@ private fun collectionArgOutputBoolean(args: List<IExpression>, position: Positi
|
|||||||
if(constants.contains(null))
|
if(constants.contains(null))
|
||||||
throw NotConstArgumentException()
|
throw NotConstArgumentException()
|
||||||
val result = function(constants.map { it?.toDouble()!! })
|
val result = function(constants.map { it?.toDouble()!! })
|
||||||
return LiteralValue(bytevalue = if(result) 1 else 0)
|
return LiteralValue.fromBoolean(result, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun builtinRound(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinRound(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneDoubleArgOutputInt(args, position, namespace, Math::round)
|
= oneDoubleArgOutputInt(args, position, namespace, Math::round)
|
||||||
|
|
||||||
fun builtinFloor(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinFloor(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneDoubleArgOutputInt(args, position, namespace, Math::floor)
|
= oneDoubleArgOutputInt(args, position, namespace, Math::floor)
|
||||||
|
|
||||||
fun builtinCeil(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinCeil(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneDoubleArgOutputInt(args, position, namespace, Math::ceil)
|
= oneDoubleArgOutputInt(args, position, namespace, Math::ceil)
|
||||||
|
|
||||||
fun builtinSin(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinSin(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneDoubleArg(args, position, namespace, Math::sin)
|
= oneDoubleArg(args, position, namespace, Math::sin)
|
||||||
|
|
||||||
fun builtinCos(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinCos(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneDoubleArg(args, position, namespace, Math::cos)
|
= oneDoubleArg(args, position, namespace, Math::cos)
|
||||||
|
|
||||||
fun builtinAcos(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinAcos(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneDoubleArg(args, position, namespace, Math::acos)
|
= oneDoubleArg(args, position, namespace, Math::acos)
|
||||||
|
|
||||||
fun builtinAsin(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinAsin(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneDoubleArg(args, position, namespace, Math::asin)
|
= oneDoubleArg(args, position, namespace, Math::asin)
|
||||||
|
|
||||||
fun builtinTan(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinTan(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneDoubleArg(args, position, namespace, Math::tan)
|
= oneDoubleArg(args, position, namespace, Math::tan)
|
||||||
|
|
||||||
fun builtinAtan(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinAtan(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneDoubleArg(args, position, namespace, Math::atan)
|
= oneDoubleArg(args, position, namespace, Math::atan)
|
||||||
|
|
||||||
fun builtinLog(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinLog(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneDoubleArg(args, position, namespace, Math::log)
|
= oneDoubleArg(args, position, namespace, Math::log)
|
||||||
|
|
||||||
fun builtinLog10(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinLog10(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneDoubleArg(args, position, namespace, Math::log10)
|
= oneDoubleArg(args, position, namespace, Math::log10)
|
||||||
|
|
||||||
fun builtinSqrt(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinSqrt(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneDoubleArg(args, position, namespace, Math::sqrt)
|
= oneDoubleArg(args, position, namespace, Math::sqrt)
|
||||||
|
|
||||||
fun builtinRad(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinRad(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneDoubleArg(args, position, namespace, Math::toRadians)
|
= oneDoubleArg(args, position, namespace, Math::toRadians)
|
||||||
|
|
||||||
fun builtinDeg(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinDeg(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneDoubleArg(args, position, namespace, Math::toDegrees)
|
= oneDoubleArg(args, position, namespace, Math::toDegrees)
|
||||||
|
|
||||||
fun builtinAbs(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue {
|
fun builtinAbs(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue {
|
||||||
// 1 arg, type = float or int, result type= same as argument type
|
// 1 arg, type = float or int, result type= same as argument type
|
||||||
if(args.size!=1)
|
if(args.size!=1)
|
||||||
throw SyntaxError("abs requires one numeric argument", position)
|
throw SyntaxError("abs requires one numeric argument", position)
|
||||||
@ -136,28 +136,28 @@ fun builtinAbs(args: List<IExpression>, position: Position?, namespace:INameScop
|
|||||||
|
|
||||||
|
|
||||||
// todo different functions for byte/word params/results?
|
// todo different functions for byte/word params/results?
|
||||||
fun builtinLsb(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinLsb(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneIntArgOutputInt(args, position, namespace) { x: Int -> x and 255 }
|
= oneIntArgOutputInt(args, position, namespace) { x: Int -> x and 255 }
|
||||||
|
|
||||||
fun builtinMsb(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinMsb(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneIntArgOutputInt(args, position, namespace) { x: Int -> x ushr 8 and 255}
|
= oneIntArgOutputInt(args, position, namespace) { x: Int -> x ushr 8 and 255}
|
||||||
|
|
||||||
fun builtinLsl(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinLsl(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneIntArgOutputInt(args, position, namespace) { x: Int -> x shl 1 }
|
= oneIntArgOutputInt(args, position, namespace) { x: Int -> x shl 1 }
|
||||||
|
|
||||||
fun builtinLsr(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinLsr(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= oneIntArgOutputInt(args, position, namespace) { x: Int -> x ushr 1 }
|
= oneIntArgOutputInt(args, position, namespace) { x: Int -> x ushr 1 }
|
||||||
|
|
||||||
fun builtinMin(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinMin(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= collectionArgOutputNumber(args, position, namespace) { it.min()!! }
|
= collectionArgOutputNumber(args, position, namespace) { it.min()!! }
|
||||||
|
|
||||||
fun builtinMax(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinMax(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= collectionArgOutputNumber(args, position, namespace) { it.max()!! }
|
= collectionArgOutputNumber(args, position, namespace) { it.max()!! }
|
||||||
|
|
||||||
fun builtinSum(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinSum(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= collectionArgOutputNumber(args, position, namespace) { it.sum() }
|
= collectionArgOutputNumber(args, position, namespace) { it.sum() }
|
||||||
|
|
||||||
fun builtinAvg(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue {
|
fun builtinAvg(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue {
|
||||||
if(args.size!=1)
|
if(args.size!=1)
|
||||||
throw SyntaxError("avg requires one non-scalar argument", position)
|
throw SyntaxError("avg requires one non-scalar argument", position)
|
||||||
val iterable = args[0].constValue(namespace)
|
val iterable = args[0].constValue(namespace)
|
||||||
@ -170,25 +170,25 @@ fun builtinAvg(args: List<IExpression>, position: Position?, namespace:INameScop
|
|||||||
return numericLiteral(result, args[0].position)
|
return numericLiteral(result, args[0].position)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun builtinLen(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue {
|
fun builtinLen(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue {
|
||||||
if(args.size!=1)
|
if(args.size!=1)
|
||||||
throw SyntaxError("len requires one argument", position)
|
throw SyntaxError("len requires one argument", position)
|
||||||
val argument = args[0].constValue(namespace) ?: throw NotConstArgumentException()
|
val argument = args[0].constValue(namespace) ?: throw NotConstArgumentException()
|
||||||
return when {
|
return when(argument.type) {
|
||||||
argument.isArray -> numericLiteral(argument.arrayvalue!!.size, args[0].position)
|
DataType.ARRAY, DataType.ARRAY_W -> numericLiteral(argument.arrayvalue!!.size, args[0].position)
|
||||||
argument.isString -> numericLiteral(argument.strvalue!!.length, args[0].position)
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> numericLiteral(argument.strvalue!!.length, args[0].position)
|
||||||
else -> throw FatalAstException("len of weird argument ${args[0]}")
|
else -> throw FatalAstException("len of weird argument ${args[0]}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun builtinAny(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinAny(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= collectionArgOutputBoolean(args, position, namespace) { it.any { v -> v != 0.0} }
|
= collectionArgOutputBoolean(args, position, namespace) { it.any { v -> v != 0.0} }
|
||||||
|
|
||||||
fun builtinAll(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
fun builtinAll(args: List<IExpression>, position: Position, namespace:INameScope): LiteralValue
|
||||||
= collectionArgOutputBoolean(args, position, namespace) { it.all { v -> v != 0.0} }
|
= collectionArgOutputBoolean(args, position, namespace) { it.all { v -> v != 0.0} }
|
||||||
|
|
||||||
|
|
||||||
private fun numericLiteral(value: Number, position: Position?): LiteralValue {
|
private fun numericLiteral(value: Number, position: Position): LiteralValue {
|
||||||
val floatNum=value.toDouble()
|
val floatNum=value.toDouble()
|
||||||
val tweakedValue: Number =
|
val tweakedValue: Number =
|
||||||
if(floatNum==floor(floatNum) && floatNum in -32768..65535)
|
if(floatNum==floor(floatNum) && floatNum in -32768..65535)
|
||||||
@ -196,14 +196,12 @@ private fun numericLiteral(value: Number, position: Position?): LiteralValue {
|
|||||||
else
|
else
|
||||||
floatNum
|
floatNum
|
||||||
|
|
||||||
val result = when(tweakedValue) {
|
return when(tweakedValue) {
|
||||||
is Int -> LiteralValue.optimalNumeric(value.toInt())
|
is Int -> LiteralValue.optimalNumeric(value.toInt(), position)
|
||||||
is Short -> LiteralValue.optimalNumeric(value.toInt())
|
is Short -> LiteralValue.optimalNumeric(value.toInt(), position)
|
||||||
is Byte -> LiteralValue(bytevalue = value.toShort())
|
is Byte -> LiteralValue(DataType.BYTE, bytevalue = value.toShort(), position = position)
|
||||||
is Double -> LiteralValue(floatvalue = value.toDouble())
|
is Double -> LiteralValue(DataType.FLOAT, floatvalue = value.toDouble(), position = position)
|
||||||
is Float -> LiteralValue(floatvalue = value.toDouble())
|
is Float -> LiteralValue(DataType.FLOAT, floatvalue = value.toDouble(), position = position)
|
||||||
else -> throw FatalAstException("invalid number type ${value::class}")
|
else -> throw FatalAstException("invalid number type ${value::class}")
|
||||||
}
|
}
|
||||||
result.position = position
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
@ -82,9 +82,8 @@ class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcess
|
|||||||
decl.datatype == DataType.FLOAT -> {
|
decl.datatype == DataType.FLOAT -> {
|
||||||
// vardecl: for float vars, promote constant integer initialization values to floats
|
// vardecl: for float vars, promote constant integer initialization values to floats
|
||||||
val literal = decl.value as? LiteralValue
|
val literal = decl.value as? LiteralValue
|
||||||
if (literal != null && literal.isInteger) {
|
if (literal != null && (literal.type == DataType.BYTE || literal.type==DataType.WORD)) {
|
||||||
val newValue = LiteralValue(floatvalue = literal.asNumericValue!!.toDouble())
|
val newValue = LiteralValue(DataType.FLOAT, floatvalue = literal.asNumericValue!!.toDouble(), position = literal.position)
|
||||||
newValue.position = literal.position
|
|
||||||
decl.value = newValue
|
decl.value = newValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,8 +92,7 @@ class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcess
|
|||||||
val literal = decl.value as? LiteralValue
|
val literal = decl.value as? LiteralValue
|
||||||
if (literal != null && literal.isString && literal.strvalue?.length == 1) {
|
if (literal != null && literal.isString && literal.strvalue?.length == 1) {
|
||||||
val petscii = Petscii.encodePetscii(literal.strvalue)[0]
|
val petscii = Petscii.encodePetscii(literal.strvalue)[0]
|
||||||
val newValue = LiteralValue(bytevalue = petscii)
|
val newValue = LiteralValue(DataType.BYTE, bytevalue = petscii, position = literal.position)
|
||||||
newValue.position = literal.position
|
|
||||||
decl.value = newValue
|
decl.value = newValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,41 +135,39 @@ class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcess
|
|||||||
val subexpr = expr.expression
|
val subexpr = expr.expression
|
||||||
if (subexpr is LiteralValue) {
|
if (subexpr is LiteralValue) {
|
||||||
// process prefixed literal values (such as -3, not true)
|
// process prefixed literal values (such as -3, not true)
|
||||||
val result = when {
|
return when {
|
||||||
expr.operator == "+" -> subexpr
|
expr.operator == "+" -> subexpr
|
||||||
expr.operator == "-" -> when {
|
expr.operator == "-" -> when {
|
||||||
subexpr.asIntegerValue!= null -> {
|
subexpr.asIntegerValue!= null -> {
|
||||||
optimizationsDone++
|
optimizationsDone++
|
||||||
LiteralValue.optimalNumeric(-subexpr.asIntegerValue)
|
LiteralValue.optimalNumeric(-subexpr.asIntegerValue, subexpr.position)
|
||||||
}
|
}
|
||||||
subexpr.floatvalue != null -> {
|
subexpr.floatvalue != null -> {
|
||||||
optimizationsDone++
|
optimizationsDone++
|
||||||
LiteralValue(floatvalue = -subexpr.floatvalue)
|
LiteralValue(DataType.FLOAT, floatvalue = -subexpr.floatvalue, position = subexpr.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError("can only take negative of int or float", subexpr.position)
|
else -> throw ExpressionError("can only take negative of int or float", subexpr.position)
|
||||||
}
|
}
|
||||||
expr.operator == "~" -> when {
|
expr.operator == "~" -> when {
|
||||||
subexpr.asIntegerValue != null -> {
|
subexpr.asIntegerValue != null -> {
|
||||||
optimizationsDone++
|
optimizationsDone++
|
||||||
LiteralValue.optimalNumeric(subexpr.asIntegerValue.inv())
|
LiteralValue.optimalNumeric(subexpr.asIntegerValue.inv(), subexpr.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError("can only take bitwise inversion of int", subexpr.position)
|
else -> throw ExpressionError("can only take bitwise inversion of int", subexpr.position)
|
||||||
}
|
}
|
||||||
expr.operator == "not" -> when {
|
expr.operator == "not" -> when {
|
||||||
subexpr.asIntegerValue != null -> {
|
subexpr.asIntegerValue != null -> {
|
||||||
optimizationsDone++
|
optimizationsDone++
|
||||||
LiteralValue(bytevalue = if (subexpr.asIntegerValue == 0) 1 else 0)
|
LiteralValue.fromBoolean(subexpr.asIntegerValue == 0, subexpr.position)
|
||||||
}
|
}
|
||||||
subexpr.floatvalue != null -> {
|
subexpr.floatvalue != null -> {
|
||||||
optimizationsDone++
|
optimizationsDone++
|
||||||
LiteralValue(bytevalue = if (subexpr.floatvalue == 0.0) 1 else 0)
|
LiteralValue.fromBoolean(subexpr.floatvalue == 0.0, subexpr.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError("can not take logical not of $subexpr", subexpr.position)
|
else -> throw ExpressionError("can not take logical not of $subexpr", subexpr.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(expr.operator, subexpr.position)
|
else -> throw ExpressionError(expr.operator, subexpr.position)
|
||||||
}
|
}
|
||||||
result.position = subexpr.position
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
return expr
|
return expr
|
||||||
} catch (ax: AstException) {
|
} catch (ax: AstException) {
|
||||||
@ -212,31 +208,29 @@ class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcess
|
|||||||
val to = range.to.constValue(globalNamespace)
|
val to = range.to.constValue(globalNamespace)
|
||||||
if (from != null && to != null) {
|
if (from != null && to != null) {
|
||||||
when {
|
when {
|
||||||
from.isWord || to.isWord -> {
|
from.type==DataType.WORD || to.type==DataType.WORD -> {
|
||||||
// range on word value boundaries
|
// range on word value boundaries
|
||||||
val rangeValue = from.asIntegerValue!!.rangeTo(to.asIntegerValue!!)
|
val rangeValue = from.asIntegerValue!!.rangeTo(to.asIntegerValue!!)
|
||||||
if (rangeValue.last - rangeValue.first > 65535) {
|
if (rangeValue.last - rangeValue.first > 65535) {
|
||||||
throw ExpressionError("amount of values in range exceeds 65535", range.position)
|
throw ExpressionError("amount of values in range exceeds 65535", range.position)
|
||||||
}
|
}
|
||||||
return LiteralValue(arrayvalue = rangeValue.map {
|
return LiteralValue(DataType.ARRAY_W, arrayvalue = rangeValue.map {
|
||||||
val v = LiteralValue(wordvalue = it)
|
val v = LiteralValue(DataType.WORD, wordvalue = it, position = range.position)
|
||||||
v.position = range.position
|
|
||||||
v.parent = range.parent
|
v.parent = range.parent
|
||||||
v
|
v
|
||||||
}.toMutableList())
|
}.toMutableList(), position = from.position)
|
||||||
}
|
}
|
||||||
from.isByte && to.isByte -> {
|
from.type==DataType.BYTE && to.type==DataType.BYTE -> {
|
||||||
// range on byte value boundaries
|
// range on byte value boundaries
|
||||||
val rangeValue = from.bytevalue!!.rangeTo(to.bytevalue!!)
|
val rangeValue = from.bytevalue!!.rangeTo(to.bytevalue!!)
|
||||||
if (rangeValue.last - rangeValue.first > 65535) {
|
if (rangeValue.last - rangeValue.first > 65535) {
|
||||||
throw ExpressionError("amount of values in range exceeds 65535", range.position)
|
throw ExpressionError("amount of values in range exceeds 65535", range.position)
|
||||||
}
|
}
|
||||||
return LiteralValue(arrayvalue = rangeValue.map {
|
return LiteralValue(DataType.ARRAY, arrayvalue = rangeValue.map {
|
||||||
val v = LiteralValue(bytevalue = it.toShort())
|
val v = LiteralValue(DataType.BYTE, bytevalue = it.toShort(), position = range.position)
|
||||||
v.position = range.position
|
|
||||||
v.parent = range.parent
|
v.parent = range.parent
|
||||||
v
|
v
|
||||||
}.toMutableList())
|
}.toMutableList(), position = from.position)
|
||||||
}
|
}
|
||||||
from.strvalue != null && to.strvalue != null -> {
|
from.strvalue != null && to.strvalue != null -> {
|
||||||
// char range
|
// char range
|
||||||
@ -244,8 +238,7 @@ class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcess
|
|||||||
if (rangevalue.last - rangevalue.first > 65535) {
|
if (rangevalue.last - rangevalue.first > 65535) {
|
||||||
throw ExpressionError("amount of characters in range exceeds 65535", range.position)
|
throw ExpressionError("amount of characters in range exceeds 65535", range.position)
|
||||||
}
|
}
|
||||||
val newval = LiteralValue(strvalue = rangevalue.toList().joinToString(""))
|
val newval = LiteralValue(DataType.STR, strvalue = rangevalue.toList().joinToString(""), position = range.position)
|
||||||
newval.position = range.position
|
|
||||||
newval.parent = range.parent
|
newval.parent = range.parent
|
||||||
return newval
|
return newval
|
||||||
}
|
}
|
||||||
@ -297,9 +290,7 @@ class ConstExprEvaluator {
|
|||||||
|
|
||||||
private fun comparenotequal(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun comparenotequal(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
val leq = compareequal(left, right)
|
val leq = compareequal(left, right)
|
||||||
val litval = LiteralValue(bytevalue = if (leq.bytevalue == 1.toShort()) 0 else 1)
|
return LiteralValue.fromBoolean(leq.bytevalue == 1.toShort(), left.position)
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compareequal(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun compareequal(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
@ -319,186 +310,138 @@ class ConstExprEvaluator {
|
|||||||
right.arrayvalue!=null -> right.arrayvalue
|
right.arrayvalue!=null -> right.arrayvalue
|
||||||
else -> throw FatalAstException("missing literal value")
|
else -> throw FatalAstException("missing literal value")
|
||||||
}
|
}
|
||||||
val litval = LiteralValue(bytevalue = if (leftvalue == rightvalue) 1 else 0)
|
return LiteralValue.fromBoolean(leftvalue == rightvalue, left.position)
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun comparegreaterequal(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun comparegreaterequal(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
val error = "cannot compute $left >= $right"
|
val error = "cannot compute $left >= $right"
|
||||||
val litval = when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(
|
right.asIntegerValue!=null -> LiteralValue.fromBoolean(left.asIntegerValue >= right.asIntegerValue, left.position)
|
||||||
bytevalue = if (left.asIntegerValue >= right.asIntegerValue) 1 else 0)
|
right.floatvalue!=null -> LiteralValue.fromBoolean(left.asIntegerValue >= right.floatvalue, left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(
|
|
||||||
bytevalue = if (left.asIntegerValue >= right.floatvalue) 1 else 0)
|
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.floatvalue!=null -> when {
|
left.floatvalue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(
|
right.asIntegerValue!=null -> LiteralValue.fromBoolean(left.floatvalue >= right.asIntegerValue, left.position)
|
||||||
bytevalue = if (left.floatvalue >= right.asIntegerValue) 1 else 0)
|
right.floatvalue!=null -> LiteralValue.fromBoolean(left.floatvalue >= right.floatvalue, left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(
|
|
||||||
bytevalue = if (left.floatvalue >= right.floatvalue) 1 else 0)
|
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun comparelessequal(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun comparelessequal(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
val error = "cannot compute $left >= $right"
|
val error = "cannot compute $left >= $right"
|
||||||
val litval = when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(
|
right.asIntegerValue!=null -> LiteralValue.fromBoolean(left.asIntegerValue <= right.asIntegerValue, left.position)
|
||||||
bytevalue = if (left.asIntegerValue <= right.asIntegerValue) 1 else 0)
|
right.floatvalue!=null -> LiteralValue.fromBoolean(left.asIntegerValue <= right.floatvalue, left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(
|
|
||||||
bytevalue = if (left.asIntegerValue <= right.floatvalue) 1 else 0)
|
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.floatvalue!=null -> when {
|
left.floatvalue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(
|
right.asIntegerValue!=null -> LiteralValue.fromBoolean(left.floatvalue <= right.asIntegerValue, left.position)
|
||||||
bytevalue = if (left.floatvalue <= right.asIntegerValue) 1 else 0)
|
right.floatvalue!=null -> LiteralValue.fromBoolean(left.floatvalue <= right.floatvalue, left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(
|
|
||||||
bytevalue = if (left.floatvalue <= right.floatvalue) 1 else 0)
|
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun comparegreater(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun comparegreater(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
val leq = comparelessequal(left, right)
|
val leq = comparelessequal(left, right)
|
||||||
val litval = LiteralValue(bytevalue = if (leq.bytevalue == 1.toShort()) 0 else 1)
|
return LiteralValue.fromBoolean(leq.bytevalue == 1.toShort(), left.position)
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compareless(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun compareless(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
val leq = comparegreaterequal(left, right)
|
val leq = comparegreaterequal(left, right)
|
||||||
val litval = LiteralValue(bytevalue = if (leq.bytevalue == 1.toShort()) 0 else 1)
|
return LiteralValue.fromBoolean(leq.bytevalue == 1.toShort(), left.position)
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun logicalxor(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun logicalxor(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
val error = "cannot compute $left locical-bitxor $right"
|
val error = "cannot compute $left locical-bitxor $right"
|
||||||
val litval = when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(
|
right.asIntegerValue!=null -> LiteralValue.fromBoolean((left.asIntegerValue != 0) xor (right.asIntegerValue != 0), left.position)
|
||||||
bytevalue = if ((left.asIntegerValue != 0).xor(right.asIntegerValue != 0)) 1 else 0)
|
right.floatvalue!=null -> LiteralValue.fromBoolean((left.asIntegerValue != 0) xor (right.floatvalue != 0.0), left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(
|
|
||||||
bytevalue = if ((left.asIntegerValue != 0).xor(right.floatvalue != 0.0)) 1 else 0)
|
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.floatvalue!=null -> when {
|
left.floatvalue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(
|
right.asIntegerValue!=null -> LiteralValue.fromBoolean((left.floatvalue != 0.0) xor (right.asIntegerValue != 0), left.position)
|
||||||
bytevalue = if ((left.floatvalue != 0.0).xor(right.asIntegerValue != 0)) 1 else 0)
|
right.floatvalue!=null -> LiteralValue.fromBoolean((left.floatvalue != 0.0) xor (right.floatvalue != 0.0), left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(
|
|
||||||
bytevalue = if ((left.floatvalue != 0.0).xor(right.floatvalue != 0.0)) 1 else 0)
|
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun logicalor(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun logicalor(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
val error = "cannot compute $left locical-or $right"
|
val error = "cannot compute $left locical-or $right"
|
||||||
val litval = when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(
|
right.asIntegerValue!=null -> LiteralValue.fromBoolean(left.asIntegerValue != 0 || right.asIntegerValue != 0, left.position)
|
||||||
bytevalue = if (left.asIntegerValue != 0 || right.asIntegerValue != 0) 1 else 0)
|
right.floatvalue!=null -> LiteralValue.fromBoolean(left.asIntegerValue != 0 || right.floatvalue != 0.0, left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(
|
|
||||||
bytevalue = if (left.asIntegerValue != 0 || right.floatvalue != 0.0) 1 else 0)
|
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.floatvalue!=null -> when {
|
left.floatvalue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(
|
right.asIntegerValue!=null -> LiteralValue.fromBoolean(left.floatvalue != 0.0 || right.asIntegerValue != 0, left.position)
|
||||||
bytevalue = if (left.floatvalue != 0.0 || right.asIntegerValue != 0) 1 else 0)
|
right.floatvalue!=null -> LiteralValue.fromBoolean(left.floatvalue != 0.0 || right.floatvalue != 0.0, left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(
|
|
||||||
bytevalue = if (left.floatvalue != 0.0 || right.floatvalue != 0.0) 1 else 0)
|
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun logicaland(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun logicaland(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
val error = "cannot compute $left locical-and $right"
|
val error = "cannot compute $left locical-and $right"
|
||||||
val litval = when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(
|
right.asIntegerValue!=null -> LiteralValue.fromBoolean(left.asIntegerValue != 0 && right.asIntegerValue != 0, left.position)
|
||||||
bytevalue = if (left.asIntegerValue != 0 && right.asIntegerValue != 0) 1 else 0)
|
right.floatvalue!=null -> LiteralValue.fromBoolean(left.asIntegerValue != 0 && right.floatvalue != 0.0, left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(
|
|
||||||
bytevalue = if (left.asIntegerValue != 0 && right.floatvalue != 0.0) 1 else 0)
|
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.floatvalue!=null -> when {
|
left.floatvalue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(
|
right.asIntegerValue!=null -> LiteralValue.fromBoolean(left.floatvalue != 0.0 && right.asIntegerValue != 0, left.position)
|
||||||
bytevalue = if (left.floatvalue != 0.0 && right.asIntegerValue != 0) 1 else 0)
|
right.floatvalue!=null -> LiteralValue.fromBoolean(left.floatvalue != 0.0 && right.floatvalue != 0.0, left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(
|
|
||||||
bytevalue = if (left.floatvalue != 0.0 && right.floatvalue != 0.0) 1 else 0)
|
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bitwisexor(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun bitwisexor(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
if(left.isByte) {
|
if(left.type==DataType.BYTE) {
|
||||||
if(right.asIntegerValue!=null) {
|
if(right.asIntegerValue!=null) {
|
||||||
val litval = LiteralValue(bytevalue = (left.bytevalue!!.toInt() xor (right.asIntegerValue and 255)).toShort())
|
return LiteralValue(DataType.BYTE, bytevalue = (left.bytevalue!!.toInt() xor (right.asIntegerValue and 255)).toShort(), position = left.position)
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
} else if(left.isWord) {
|
} else if(left.type==DataType.WORD) {
|
||||||
if(right.asIntegerValue!=null) {
|
if(right.asIntegerValue!=null) {
|
||||||
val litval = LiteralValue(wordvalue = left.wordvalue!! xor right.asIntegerValue)
|
return LiteralValue(DataType.WORD, wordvalue = left.wordvalue!! xor right.asIntegerValue, position = left.position)
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw ExpressionError("cannot calculate $left ^ $right", left.position)
|
throw ExpressionError("cannot calculate $left ^ $right", left.position)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bitwiseor(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun bitwiseor(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
if(left.isByte) {
|
if(left.type==DataType.BYTE) {
|
||||||
if(right.asIntegerValue!=null) {
|
if(right.asIntegerValue!=null) {
|
||||||
val litval = LiteralValue(bytevalue = (left.bytevalue!!.toInt() or (right.asIntegerValue and 255)).toShort())
|
return LiteralValue(DataType.BYTE, bytevalue = (left.bytevalue!!.toInt() or (right.asIntegerValue and 255)).toShort(), position = left.position)
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
} else if(left.isWord) {
|
} else if(left.type==DataType.WORD) {
|
||||||
if(right.asIntegerValue!=null) {
|
if(right.asIntegerValue!=null) {
|
||||||
val litval = LiteralValue(wordvalue = left.wordvalue!! or right.asIntegerValue)
|
return LiteralValue(DataType.WORD, wordvalue = left.wordvalue!! or right.asIntegerValue, position = left.position)
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw ExpressionError("cannot calculate $left | $right", left.position)
|
throw ExpressionError("cannot calculate $left | $right", left.position)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bitwiseand(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun bitwiseand(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
if(left.isByte) {
|
if(left.type==DataType.BYTE) {
|
||||||
if(right.asIntegerValue!=null) {
|
if(right.asIntegerValue!=null) {
|
||||||
val litval = LiteralValue(bytevalue = (left.bytevalue!!.toInt() or (right.asIntegerValue and 255)).toShort())
|
return LiteralValue(DataType.BYTE, bytevalue = (left.bytevalue!!.toInt() or (right.asIntegerValue and 255)).toShort(), position = left.position)
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
} else if(left.isWord) {
|
} else if(left.type==DataType.WORD) {
|
||||||
if(right.asIntegerValue!=null) {
|
if(right.asIntegerValue!=null) {
|
||||||
val litval = LiteralValue(wordvalue = left.wordvalue!! or right.asIntegerValue)
|
return LiteralValue(DataType.WORD, wordvalue = left.wordvalue!! or right.asIntegerValue, position = left.position)
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw ExpressionError("cannot calculate $left & $right", left.position)
|
throw ExpressionError("cannot calculate $left & $right", left.position)
|
||||||
@ -506,119 +449,110 @@ class ConstExprEvaluator {
|
|||||||
|
|
||||||
private fun power(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun power(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
val error = "cannot calculate $left ** $right"
|
val error = "cannot calculate $left ** $right"
|
||||||
val litval = when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(wordvalue = left.asIntegerValue.toDouble().pow(right.asIntegerValue).toInt())
|
// @todo BYTE?
|
||||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.asIntegerValue.toDouble().pow(right.floatvalue))
|
right.asIntegerValue!=null -> LiteralValue(DataType.WORD, wordvalue = left.asIntegerValue.toDouble().pow(right.asIntegerValue).toInt(), position = left.position)
|
||||||
|
right.floatvalue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.asIntegerValue.toDouble().pow(right.floatvalue), position = left.position)
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.floatvalue!=null -> when {
|
left.floatvalue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(floatvalue = left.floatvalue.pow(right.asIntegerValue))
|
right.asIntegerValue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue.pow(right.asIntegerValue), position = left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue.pow(right.floatvalue))
|
right.floatvalue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue.pow(right.floatvalue), position = left.position)
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun plus(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun plus(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
val error = "cannot add $left and $right"
|
val error = "cannot add $left and $right"
|
||||||
val litval = when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue.optimalNumeric(left.asIntegerValue + right.asIntegerValue)
|
right.asIntegerValue!=null -> LiteralValue.optimalNumeric(left.asIntegerValue + right.asIntegerValue, left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.asIntegerValue + right.floatvalue)
|
right.floatvalue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.asIntegerValue + right.floatvalue, position = left.position)
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.floatvalue!=null -> when {
|
left.floatvalue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(floatvalue = left.floatvalue + right.asIntegerValue)
|
right.asIntegerValue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue + right.asIntegerValue, position = left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue + right.floatvalue)
|
right.floatvalue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue + right.floatvalue, position = left.position)
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun minus(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun minus(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
val error = "cannot subtract $left and $right"
|
val error = "cannot subtract $left and $right"
|
||||||
val litval = when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue.optimalNumeric(left.asIntegerValue - right.asIntegerValue)
|
right.asIntegerValue!=null -> LiteralValue.optimalNumeric(left.asIntegerValue - right.asIntegerValue, left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.asIntegerValue - right.floatvalue)
|
right.floatvalue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.asIntegerValue - right.floatvalue, position = left.position)
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.floatvalue!=null -> when {
|
left.floatvalue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(floatvalue = left.floatvalue - right.asIntegerValue)
|
right.asIntegerValue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue - right.asIntegerValue, position = left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue - right.floatvalue)
|
right.floatvalue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue - right.floatvalue, position = left.position)
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun multiply(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun multiply(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
val error = "cannot multiply $left and $right"
|
val error = "cannot multiply $left and $right"
|
||||||
val litval = when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue.optimalNumeric(left.asIntegerValue * right.asIntegerValue)
|
right.asIntegerValue!=null -> LiteralValue.optimalNumeric(left.asIntegerValue * right.asIntegerValue, left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.asIntegerValue * right.floatvalue)
|
right.floatvalue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.asIntegerValue * right.floatvalue, position = left.position)
|
||||||
right.strvalue!=null -> {
|
right.strvalue!=null -> {
|
||||||
if(right.strvalue.length * left.asIntegerValue > 65535) throw ExpressionError("string too large", left.position)
|
if(right.strvalue.length * left.asIntegerValue > 65535) throw ExpressionError("string too large", left.position)
|
||||||
LiteralValue(strvalue = right.strvalue.repeat(left.asIntegerValue))
|
LiteralValue(DataType.STR, strvalue = right.strvalue.repeat(left.asIntegerValue), position = left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.floatvalue!=null -> when {
|
left.floatvalue!=null -> when {
|
||||||
right.asIntegerValue!=null -> LiteralValue(floatvalue = left.floatvalue * right.asIntegerValue)
|
right.asIntegerValue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue * right.asIntegerValue, position = left.position)
|
||||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue * right.floatvalue)
|
right.floatvalue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue * right.floatvalue, position = left.position)
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.strvalue!=null -> when {
|
left.strvalue!=null -> when {
|
||||||
right.asIntegerValue!=null -> {
|
right.asIntegerValue!=null -> {
|
||||||
if(left.strvalue.length * right.asIntegerValue > 65535) throw ExpressionError("string too large", left.position)
|
if(left.strvalue.length * right.asIntegerValue > 65535) throw ExpressionError("string too large", left.position)
|
||||||
LiteralValue(strvalue = left.strvalue.repeat(right.asIntegerValue))
|
LiteralValue(DataType.STR, strvalue = left.strvalue.repeat(right.asIntegerValue), position = left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun divide(left: LiteralValue, right: LiteralValue): LiteralValue {
|
private fun divide(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||||
val error = "cannot divide $left by $right"
|
val error = "cannot divide $left by $right"
|
||||||
val litval = when {
|
return when {
|
||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> {
|
right.asIntegerValue!=null -> {
|
||||||
if(right.asIntegerValue==0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.asIntegerValue==0) throw ExpressionError("attempt to divide by zero", left.position)
|
||||||
LiteralValue.optimalNumeric(left.asIntegerValue / right.asIntegerValue)
|
LiteralValue.optimalNumeric(left.asIntegerValue / right.asIntegerValue, left.position)
|
||||||
}
|
}
|
||||||
right.floatvalue!=null -> {
|
right.floatvalue!=null -> {
|
||||||
if(right.floatvalue==0.0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.floatvalue==0.0) throw ExpressionError("attempt to divide by zero", left.position)
|
||||||
LiteralValue(floatvalue = left.asIntegerValue / right.floatvalue)
|
LiteralValue(DataType.FLOAT, floatvalue = left.asIntegerValue / right.floatvalue, position = left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.floatvalue!=null -> when {
|
left.floatvalue!=null -> when {
|
||||||
right.asIntegerValue!=null -> {
|
right.asIntegerValue!=null -> {
|
||||||
if(right.asIntegerValue==0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.asIntegerValue==0) throw ExpressionError("attempt to divide by zero", left.position)
|
||||||
LiteralValue(floatvalue = left.floatvalue / right.asIntegerValue)
|
LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue / right.asIntegerValue, position = left.position)
|
||||||
}
|
}
|
||||||
right.floatvalue!=null -> {
|
right.floatvalue!=null -> {
|
||||||
if(right.floatvalue==0.0) throw ExpressionError("attempt to divide by zero", left.position)
|
if(right.floatvalue==0.0) throw ExpressionError("attempt to divide by zero", left.position)
|
||||||
LiteralValue(floatvalue = left.floatvalue / right.floatvalue)
|
LiteralValue(DataType.FLOAT, floatvalue = left.floatvalue / right.floatvalue, position = left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
else -> throw ExpressionError(error, left.position)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
litval.position = left.position
|
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,11 +80,11 @@ class StatementOptimizer(private val globalNamespace: INameScope) : IAstProcesso
|
|||||||
return if(constvalue.asBooleanValue){
|
return if(constvalue.asBooleanValue){
|
||||||
// always true -> keep only if-part
|
// always true -> keep only if-part
|
||||||
println("${ifStatement.position} Warning: condition is always true")
|
println("${ifStatement.position} Warning: condition is always true")
|
||||||
AnonymousStatementList(ifStatement.parent, ifStatement.statements)
|
AnonymousStatementList(ifStatement.parent, ifStatement.statements, ifStatement.position)
|
||||||
} else {
|
} else {
|
||||||
// always false -> keep only else-part
|
// always false -> keep only else-part
|
||||||
println("${ifStatement.position} Warning: condition is always false")
|
println("${ifStatement.position} Warning: condition is always false")
|
||||||
AnonymousStatementList(ifStatement.parent, ifStatement.elsepart)
|
AnonymousStatementList(ifStatement.parent, ifStatement.elsepart, ifStatement.position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ifStatement
|
return ifStatement
|
||||||
|
@ -32,7 +32,7 @@ fun importModule(filePath: Path) : Module {
|
|||||||
// tokens.commentTokens().forEach { println(it) }
|
// tokens.commentTokens().forEach { println(it) }
|
||||||
|
|
||||||
// convert to Ast
|
// convert to Ast
|
||||||
val moduleAst = parseTree.toAst(moduleName,true)
|
val moduleAst = parseTree.toAst(moduleName)
|
||||||
importedModules[moduleAst.name] = moduleAst
|
importedModules[moduleAst.name] = moduleAst
|
||||||
|
|
||||||
// process imports
|
// process imports
|
||||||
@ -60,7 +60,7 @@ fun importModule(filePath: Path) : Module {
|
|||||||
|
|
||||||
|
|
||||||
fun discoverImportedModule(name: String, importedFrom: Path, position: Position?): Path {
|
fun discoverImportedModule(name: String, importedFrom: Path, position: Position?): Path {
|
||||||
val fileName = name + ".ill"
|
val fileName = "$name.ill"
|
||||||
val locations = mutableListOf(Paths.get(importedFrom.parent.toString()))
|
val locations = mutableListOf(Paths.get(importedFrom.parent.toString()))
|
||||||
|
|
||||||
val propPath = System.getProperty("il65.libdir")
|
val propPath = System.getProperty("il65.libdir")
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
IL65_LIBDIR=../lib65
|
IL65_LIBDIR=../lib65
|
||||||
IL65CLASSPATH=out/production/il65
|
IL65CLASSPATH=out/production/il65
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package il65tests
|
package il65tests
|
||||||
|
|
||||||
import il65.ast.DataType
|
import il65.ast.DataType
|
||||||
|
import il65.ast.Position
|
||||||
import il65.ast.VarDecl
|
import il65.ast.VarDecl
|
||||||
import il65.ast.VarDeclType
|
import il65.ast.VarDeclType
|
||||||
import il65.compiler.*
|
import il65.compiler.*
|
||||||
@ -106,6 +107,9 @@ class TestCompiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private val dummypos = Position("test", 0, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
class TestZeropage {
|
class TestZeropage {
|
||||||
@Test
|
@Test
|
||||||
@ -113,26 +117,26 @@ class TestZeropage {
|
|||||||
val zp = Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, false))
|
val zp = Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, false))
|
||||||
|
|
||||||
assertFailsWith<AssertionError> {
|
assertFailsWith<AssertionError> {
|
||||||
zp.allocate(VarDecl(VarDeclType.MEMORY, DataType.BYTE, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.MEMORY, DataType.BYTE, null, "", null, dummypos))
|
||||||
}
|
}
|
||||||
|
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null, dummypos))
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null, dummypos))
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "varname", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "varname", null, dummypos))
|
||||||
assertFailsWith<AssertionError> {
|
assertFailsWith<AssertionError> {
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "varname", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "varname", null, dummypos))
|
||||||
}
|
}
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "varname2", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "varname2", null, dummypos))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testZpFloatEnable() {
|
fun testZpFloatEnable() {
|
||||||
val zp = Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, false))
|
val zp = Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, false))
|
||||||
assertFailsWith<CompilerException> {
|
assertFailsWith<CompilerException> {
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null, dummypos))
|
||||||
}
|
}
|
||||||
val zp2 = Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, true))
|
val zp2 = Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, true))
|
||||||
zp2.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null))
|
zp2.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null, dummypos))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -150,22 +154,22 @@ class TestZeropage {
|
|||||||
val zp = Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, true))
|
val zp = Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, true))
|
||||||
assertEquals(23, zp.available())
|
assertEquals(23, zp.available())
|
||||||
|
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null, dummypos))
|
||||||
assertFailsWith<CompilerException> {
|
assertFailsWith<CompilerException> {
|
||||||
// in regular zp there aren't 5 sequential bytes free after we take the first sequence
|
// in regular zp there aren't 5 sequential bytes free after we take the first sequence
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null, dummypos))
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i in 0 until zp.available()) {
|
for (i in 0 until zp.available()) {
|
||||||
val loc = zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null))
|
val loc = zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null, dummypos))
|
||||||
assertTrue(loc > 0)
|
assertTrue(loc > 0)
|
||||||
}
|
}
|
||||||
assertEquals(0, zp.available())
|
assertEquals(0, zp.available())
|
||||||
assertFailsWith<CompilerException> {
|
assertFailsWith<CompilerException> {
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null, dummypos))
|
||||||
}
|
}
|
||||||
assertFailsWith<CompilerException> {
|
assertFailsWith<CompilerException> {
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null, dummypos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,33 +177,33 @@ class TestZeropage {
|
|||||||
fun testFullAllocation() {
|
fun testFullAllocation() {
|
||||||
val zp = Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, true))
|
val zp = Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, true))
|
||||||
assertEquals(239, zp.available())
|
assertEquals(239, zp.available())
|
||||||
val loc = zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null))
|
val loc = zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null, dummypos))
|
||||||
assertTrue(loc > 3)
|
assertTrue(loc > 3)
|
||||||
assertFalse(zp.free.contains(loc))
|
assertFalse(zp.free.contains(loc))
|
||||||
val num = zp.available() / 5
|
val num = zp.available() / 5
|
||||||
val rest = zp.available() % 5
|
val rest = zp.available() % 5
|
||||||
|
|
||||||
for(i in 0..num-4) {
|
for(i in 0..num-4) {
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null, dummypos))
|
||||||
}
|
}
|
||||||
assertEquals(19,zp.available())
|
assertEquals(19,zp.available())
|
||||||
|
|
||||||
assertFailsWith<CompilerException> {
|
assertFailsWith<CompilerException> {
|
||||||
// can't allocate because no more sequential bytes, only fragmented
|
// can't allocate because no more sequential bytes, only fragmented
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null, dummypos))
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i in 0..13) {
|
for(i in 0..13) {
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null, dummypos))
|
||||||
}
|
}
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null, dummypos))
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null, dummypos))
|
||||||
|
|
||||||
assertEquals(1, zp.available())
|
assertEquals(1, zp.available())
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null, dummypos))
|
||||||
assertFailsWith<CompilerException> {
|
assertFailsWith<CompilerException> {
|
||||||
// no more space
|
// no more space
|
||||||
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null))
|
zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null, dummypos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,18 +214,18 @@ class TestZeropage {
|
|||||||
// 0xb5, 0xb6, 0xf7, 0xf8, 0xf9, 0xfa))
|
// 0xb5, 0xb6, 0xf7, 0xf8, 0xf9, 0xfa))
|
||||||
val zp = Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, true))
|
val zp = Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, true))
|
||||||
assertEquals(23, zp.available())
|
assertEquals(23, zp.available())
|
||||||
assertEquals(0x04, zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null)))
|
assertEquals(0x04, zp.allocate(VarDecl(VarDeclType.VAR, DataType.FLOAT, null, "", null, dummypos)))
|
||||||
assertEquals(0x09, zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null)))
|
assertEquals(0x09, zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null, dummypos)))
|
||||||
assertEquals(0x12, zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null)))
|
assertEquals(0x12, zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null, dummypos)))
|
||||||
assertEquals(0x0d, zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null)))
|
assertEquals(0x0d, zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null, dummypos)))
|
||||||
assertEquals(0x94, zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null)))
|
assertEquals(0x94, zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null, dummypos)))
|
||||||
assertEquals(0x2a, zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null)))
|
assertEquals(0x2a, zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null, dummypos)))
|
||||||
assertEquals(0xa7, zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null)))
|
assertEquals(0xa7, zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null, dummypos)))
|
||||||
assertEquals(0xa9, zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null)))
|
assertEquals(0xa9, zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null, dummypos)))
|
||||||
assertEquals(0xb5, zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null)))
|
assertEquals(0xb5, zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null, dummypos)))
|
||||||
assertEquals(0xf7, zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null)))
|
assertEquals(0xf7, zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null, dummypos)))
|
||||||
assertEquals(0xf9, zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null)))
|
assertEquals(0xf9, zp.allocate(VarDecl(VarDeclType.VAR, DataType.WORD, null, "", null, dummypos)))
|
||||||
assertEquals(0x52, zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null)))
|
assertEquals(0x52, zp.allocate(VarDecl(VarDeclType.VAR, DataType.BYTE, null, "", null, dummypos)))
|
||||||
assertEquals(0, zp.available())
|
assertEquals(0, zp.available())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user