improve datatype checks, auto convert some value types

This commit is contained in:
Irmen de Jong 2018-09-05 01:28:06 +02:00
parent a81c1485d7
commit cd6327850e
10 changed files with 225 additions and 126 deletions

View File

@ -22,6 +22,9 @@
return A+snerp2
}
sub thingy()->() {
return 99
}
}

View File

@ -6,9 +6,10 @@
~ main $c003 {
const word len1 = len([1,2,3,wa1, wa2, ws1, all1])
const word wa1 = abs(-999)
const word wa1 = ceil(abs(-999.22))
const byte wa2 = abs(-99)
const float wa3 = abs(-1.23456)
const float wa4 = abs(-133)
const float avg1 = avg([-1.23456, 99999])
const float sum1 = sum([-1.23456, 99999])
const word ws1 = floor(sum([1,2,3,4.9]))
@ -28,14 +29,15 @@
A = X>2
X = Y>Y
byte myByteChar = "A"
word myWordChar = "B"
word[1000] ascending = 10 to 1009
word[100] ascending2 = "a" to "z"
str ascending3 = "a" to "z"
str ascending5 = "z" to "z"
const byte cc = 4 + (2==9)
byte cc2 = 4 - (2==10)
memory byte derp = max([$ffdd])
memory byte derpA = abs(-2.5-0.5)
memory byte derpA = abs(-20000)
memory byte derpB = max([1, 2.2, 4.4, 100])
memory byte cderp = min([$ffdd])+ (1/1)
memory byte cderpA = min([$ffdd, 10, 20, 30])
@ -92,18 +94,21 @@
if(6==6) {
A=sin(X)
A=sin([X])
X=max([1,2,Y])
X=min([1,2,Y])
X=lsl(1)
X=lsl(1.2)
X=lsl(Y)
P_carry(0)
P_carry(Y) ; TODO error
P_carry(9.99) ; TODO error
P_carry(1)
P_carry(1-1)
P_irqd(0)
P_irqd(Y) ; TODO error
P_irqd(9.99) ; TODO error
P_irqd(1)
} else X=33
X= extra233.thingy() ; TODO EHHHH, should be counted as used?
if(6>36) {
A=99
} else {
@ -126,6 +131,7 @@ cool:
mega:
cool:
sub ultrafoo() -> () {
X= extra233.thingy() ; TODO EHHHH, should be counted as used?
return 33
goto main.mega
}

View File

@ -64,12 +64,13 @@ fun main(args: Array<String>) {
val intermediate = compiler.compile(moduleAst)
intermediate.optimize()
// val assembler = intermediate.compileToAssembly()
// assembler.assemble(compilerOptions, "input", "output")
// val monitorfile = assembler.generateBreakpointList()
// val assembly = intermediate.compileToAssembly()
//
// assembly.assemble(compilerOptions, "input", "output")
// val monitorfile = assembly.generateBreakpointList()
val endTime = System.currentTimeMillis()
println("Compilation time: ${(endTime-startTime)/1000.0} sec.")
println("\nTotal compilation time: ${(endTime-startTime)/1000.0} sec.")
// // start the vice emulator
// val program = "foo"

View File

@ -518,6 +518,10 @@ class VarDecl(val type: VarDeclType,
fun arraySizeY(namespace: INameScope) : Int? {
return arrayspec?.y?.constValue(namespace)?.intvalue
}
override fun toString(): String {
return "VarDecl(name=$name, vartype=$type, datatype=$datatype, value=$value, pos=$position)"
}
}
@ -601,31 +605,19 @@ class LiteralValue(val intvalue: Int? = null,
override lateinit var parent: Node
override fun referencesIdentifier(name: String) = arrayvalue?.any { it.referencesIdentifier(name) } ?: false
fun asInt(errorIfNotNumeric: Boolean=true): Int? {
return when {
intvalue!=null -> intvalue
floatvalue!=null -> floatvalue.toInt()
else -> {
if((strvalue!=null || arrayvalue!=null) && errorIfNotNumeric)
throw AstException("attempt to get int value from non-numeric $this")
else null
}
}
val isInteger = intvalue!=null
val isFloat = floatvalue!=null
val isNumeric = intvalue!=null || floatvalue!=null
val isArray = arrayvalue!=null
val isString = strvalue!=null
val asNumericValue: Number? = when {
intvalue!=null -> intvalue
floatvalue!=null -> floatvalue
else -> null
}
fun asFloat(errorIfNotNumeric: Boolean=true): Double? {
return when {
floatvalue!=null -> floatvalue
intvalue!=null -> intvalue.toDouble()
else -> {
if((strvalue!=null || arrayvalue!=null) && errorIfNotNumeric)
throw AstException("attempt to get float value from non-numeric $this")
else null
}
}
}
fun asBoolean(): Boolean =
val asBooleanValue: Boolean =
(floatvalue!=null && floatvalue != 0.0) ||
(intvalue!=null && intvalue != 0) ||
(strvalue!=null && strvalue.isNotEmpty()) ||
@ -775,12 +767,12 @@ class FunctionCall(override var target: IdentifierReference, override var arglis
"ceil" -> builtinCeil(arglist, position, namespace)
"lsl" -> builtinLsl(arglist, position, namespace)
"lsr" -> builtinLsr(arglist, position, namespace)
"rol" -> throw ExpressionException("builtin function _rol can't be used in expressions because it doesn't return a value", position)
"rol2" -> throw ExpressionException("builtin function _rol2 can't be used in expressions because it doesn't return a value", position)
"ror" -> throw ExpressionException("builtin function _ror can't be used in expressions because it doesn't return a value", position)
"ror2" -> throw ExpressionException("builtin function _ror2 can't be used in expressions because it doesn't return a value", position)
"P_carry" -> throw ExpressionException("builtin function _P_carry can't be used in expressions because it doesn't return a value", position)
"P_irqd" -> throw ExpressionException("builtin function _P_irqd can't be used in expressions because it doesn't return a value", position)
"rol" -> throw ExpressionException("builtin function rol can't be used in expressions because it doesn't return a value", position)
"rol2" -> throw ExpressionException("builtin function rol2 can't be used in expressions because it doesn't return a value", position)
"ror" -> throw ExpressionException("builtin function ror can't be used in expressions because it doesn't return a value", position)
"ror2" -> throw ExpressionException("builtin function ror2 can't be used in expressions because it doesn't return a value", position)
"P_carry" -> throw ExpressionException("builtin function P_carry can't be used in expressions because it doesn't return a value", position)
"P_irqd" -> throw ExpressionException("builtin function P_irqd can't be used in expressions because it doesn't return a value", position)
else -> null
}
}
@ -791,7 +783,7 @@ class FunctionCall(override var target: IdentifierReference, override var arglis
}
override fun toString(): String {
return "FunctionCall(target=$target, targetStmt=$targetStatement, pos=$position)"
return "FunctionCall(target=$target, pos=$position)"
}
override fun process(processor: IAstProcessor) = processor.process(this)

View File

@ -129,9 +129,9 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor {
decl.value !is LiteralValue ->
err("var/const declaration needs a compile-time constant initializer value, found: ${decl.value!!::class.simpleName}")
decl.isScalar -> {
checkConstInitializerValueScalar(decl)
checkValueType(decl, decl.value as LiteralValue, decl.position)
checkValueRange(decl.datatype, decl.value as LiteralValue, decl.position)
if(checkValueType(decl, decl.value as LiteralValue, decl.position)) {
checkValueRange(decl.datatype, decl.value as LiteralValue, decl.position)
}
}
decl.isArray || decl.isMatrix -> {
checkConstInitializerValueArray(decl)
@ -159,7 +159,7 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor {
override fun process(ifStatement: IfStatement): IStatement {
val constvalue = ifStatement.condition.constValue(globalNamespace)
if(constvalue!=null) {
val msg = if (constvalue.asBoolean()) "condition is always true" else "condition is always false"
val msg = if (constvalue.asBooleanValue) "condition is always true" else "condition is always false"
println("${ifStatement.position} Warning: $msg")
}
@ -303,21 +303,26 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor {
?: throw FatalAstException("cannot determine statement scope of function call expression at ${functionCall.position}")
val targetStatement = checkFunctionOrLabelExists(functionCall.target, stmtOfExpression)
if(targetStatement!=null)
if(targetStatement!=null) {
functionCall.targetStatement = targetStatement // link to the actual target statement
checkBuiltinFunctionCall(functionCall, functionCall.position)
}
return super.process(functionCall)
}
override fun process(functionCall: FunctionCallStatement): IStatement {
val targetStatement = checkFunctionOrLabelExists(functionCall.target, functionCall)
if(targetStatement!=null)
if(targetStatement!=null) {
functionCall.targetStatement = targetStatement // link to the actual target statement
checkBuiltinFunctionCall(functionCall, functionCall.position)
}
return super.process(functionCall)
}
private fun checkFunctionOrLabelExists(target: IdentifierReference, statement: IStatement): IStatement? {
if(target.nameInSource.size==1 && BuiltinFunctionNames.contains(target.nameInSource[0]))
return BuiltinFunctionStatementPlaceholder
if(target.nameInSource.size==1 && BuiltinFunctionNames.contains(target.nameInSource[0])) {
return BuiltinFunctionStatementPlaceholder
}
val targetStatement = globalNamespace.lookup(target.nameInSource, statement)
if(targetStatement is Label || targetStatement is Subroutine)
return targetStatement
@ -325,6 +330,23 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor {
return null
}
private fun checkBuiltinFunctionCall(call: IFunctionCall, position: Position?) {
if(call.target.nameInSource.size==1 && BuiltinFunctionNames.contains(call.target.nameInSource[0])) {
val functionName = call.target.nameInSource[0]
if(functionName=="P_carry" || functionName=="P_irqd") {
// these functions allow only 0 or 1 as argument
if(call.arglist.size!=1 || call.arglist[0] !is LiteralValue) {
checkResult.add(SyntaxError("$functionName requires one argument, 0 or 1", position))
} else {
val value = call.arglist[0] as LiteralValue
if(value.intvalue==null || value.intvalue < 0 || value.intvalue > 1) {
checkResult.add(SyntaxError("$functionName requires one argument, 0 or 1", position))
}
}
}
}
}
private fun checkValueRange(datatype: DataType, value: LiteralValue, position: Position?) : Boolean {
fun err(msg: String) : Boolean {
checkResult.add(SyntaxError(msg, position))
@ -332,23 +354,27 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor {
}
when (datatype) {
DataType.FLOAT -> {
val number = value.asFloat(false)
if (number!=null && (number > 1.7014118345e+38 || number < -1.7014118345e+38))
val number = value.floatvalue
?: return err("floating point value expected")
if (number > 1.7014118345e+38 || number < -1.7014118345e+38)
return err("floating point value '$number' out of range for MFLPT format")
}
DataType.BYTE -> {
val number = value.asInt(false)
if (number!=null && (number < 0 || number > 255))
val number = value.intvalue
?: return err("byte integer value expected")
if (number < 0 || number > 255)
return err("value '$number' out of range for unsigned byte")
}
DataType.WORD -> {
val number = value.asInt(false)
if (number!=null && (number < 0 || number > 65535))
val number = value.intvalue
?: return err("word integer value expected")
if (number < 0 || number > 65535)
return err("value '$number' out of range for unsigned word")
}
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
val str = value.strvalue
if (str!=null && (str.isEmpty() || str.length > 65535))
?: return err("string value expected")
if (str.isEmpty() || str.length > 65535)
return err("string length must be 1..65535")
}
}
@ -385,33 +411,4 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor {
}
return true
}
private fun checkConstInitializerValueScalar(decl: VarDecl) {
fun err(msg: String) {
checkResult.add(SyntaxError(msg, decl.position))
}
val value = decl.value as LiteralValue
when (decl.datatype) {
DataType.FLOAT -> {
val number = value.asFloat(false)
if (number == null)
err("need a const float initializer value")
}
DataType.BYTE -> {
val number = value.asInt(false)
if (number == null)
err("need a const integer initializer value")
}
DataType.WORD -> {
val number = value.asInt(false)
if (number == null)
err("need a const integer initializer value")
}
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
val str = value.strvalue
if (str == null)
err("need a const string initializer value")
}
}
}
}

View File

@ -1,5 +1,6 @@
package il65.compiler
import il65.ast.Block
import il65.ast.INameScope
import il65.ast.Module
import kotlin.experimental.and
@ -93,7 +94,16 @@ class Compiler(private val options: CompilationOptions, val namespace: INameScop
}
fun compile(module: Module) : IntermediateForm {
println("......@TODO compile Ast into Intermediate result......") // todo
println("\nCompiling parsed source code to intermediate code...")
// todo
namespace.debugPrint()
module.statements.filter { it is Block }.map {
with(it as Block) {
"$address $scopedname"
}
}.forEach { println(it) }
return IntermediateForm(module.name)
}
}
@ -101,11 +111,13 @@ class Compiler(private val options: CompilationOptions, val namespace: INameScop
class IntermediateForm(val name: String) {
fun optimize() {
println("......@TODO optimize intermediate result......") // todo
println("\nOptimizing intermediate code...")
// todo
}
fun compileToAssembly(): AssemblyResult {
println("......@TODO compile intermediate result to assembly code......") // todo
println("\nGenerating assembly code from intermediate code... ")
// todo
return AssemblyResult(name)
}
@ -136,10 +148,10 @@ data class CompilationOptions(val output: OutputType,
class AssemblyResult(val name: String) {
fun assemble(options: CompilationOptions, inputfilename: String, outputfilename: String) {
println("......@TODO assemble with 64tass......") // todo
println("\nGenerating machine code program...")
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "-Wall", "-Wno-strict-bool",
"--dump-labels", "--vice-labels", "-l", outputfilename+".vice-mon-list",
"--dump-labels", "--vice-labels", "-l", "$outputfilename.vice-mon-list",
"--no-monitor", "--output", outputfilename, inputfilename)
when(options.output) {

View File

@ -1052,7 +1052,11 @@ class Petscii {
fun encodePetscii(text: String, lowercase: Boolean = false): List<Short> {
val lookup = if(lowercase) encodingPetsciiLowercase else encodingPetsciiUppercase
return text.map {
val petscii = lookup[it] ?: throw CompilerException("no Petscii character for '$it'")
val petscii = lookup[it]
if(petscii==null) {
val case = if(lowercase) "lower" else "upper"
throw CompilerException("no ${case}case Petscii character for '$it'")
}
petscii.toShort()
}
}
@ -1065,7 +1069,11 @@ class Petscii {
fun encodeScreencode(text: String, lowercase: Boolean = false): List<Short> {
val lookup = if(lowercase) encodingScreencodeLowercase else encodingScreencodeUppercase
return text.map{
val screencode = lookup[it] ?: throw CompilerException("no Screencode character for '$it'")
val screencode = lookup[it]
if(screencode==null) {
val case = if(lowercase) "lower" else "upper"
throw CompilerException("no ${case}Screencode character for '$it'")
}
screencode.toShort()
}
}

View File

@ -1,6 +1,8 @@
package il65.functions
import il65.ast.*
import kotlin.math.abs
import kotlin.math.floor
val BuiltIns = listOf(
@ -16,9 +18,9 @@ private fun oneDoubleArg(args: List<IExpression>, position: Position?, namespace
if(args.size!=1)
throw SyntaxError("built-in function requires one floating point argument", position)
val float = args[0].constValue(namespace)?.asFloat()
val float = args[0].constValue(namespace)?.asNumericValue?.toDouble()
if(float!=null) {
val result = intOrFloatLiteral(function(float).toDouble(), args[0].position)
val result = numericLiteral(function(float), args[0].position)
result.position = args[0].position
return result
}
@ -30,7 +32,7 @@ private fun oneDoubleArgOutputInt(args: List<IExpression>, position: Position?,
if(args.size!=1)
throw SyntaxError("built-in function requires one floating point argument", position)
val float = args[0].constValue(namespace)?.asFloat()
val float = args[0].constValue(namespace)?.asNumericValue?.toDouble()
if(float!=null) {
val result = LiteralValue(function(float).toInt())
result.position = args[0].position
@ -44,7 +46,7 @@ private fun oneIntArgOutputInt(args: List<IExpression>, position: Position?, nam
if(args.size!=1)
throw SyntaxError("built-in function requires one integer argument", position)
val integer = args[0].constValue(namespace)?.asInt()
val integer = args[0].constValue(namespace)?.asNumericValue?.toInt()
if(integer!=null) {
val result = LiteralValue(function(integer).toInt())
result.position = args[0].position
@ -54,31 +56,38 @@ private fun oneIntArgOutputInt(args: List<IExpression>, position: Position?, nam
throw NotConstArgumentException()
}
private fun nonScalarArgOutputNumber(args: List<IExpression>, position: Position?, namespace:INameScope,
function: (arg: Collection<Double>)->Number): LiteralValue {
private fun collectionArgOutputNumber(args: List<IExpression>, position: Position?, namespace:INameScope,
function: (arg: Collection<Double>)->Number): LiteralValue {
if(args.size!=1)
throw SyntaxError("builtin function requires one non-scalar argument", position)
val iterable = args[0].constValue(namespace)
if(iterable?.arrayvalue == null)
throw SyntaxError("builtin function requires one non-scalar argument", position)
val constants = iterable.arrayvalue.map { it.constValue(namespace) }
val constants = iterable.arrayvalue.map { it.constValue(namespace)?.asNumericValue }
if(constants.contains(null))
throw NotConstArgumentException()
val result = function(constants.map { it?.asFloat()!! }).toDouble()
return intOrFloatLiteral(result, args[0].position)
val result = function(constants.map { it!!.toDouble() }).toDouble()
val value =
if(result-floor(result) == 0.0) {
LiteralValue(result.toInt())
} else {
LiteralValue(floatvalue = result)
}
value.position = args[0].position
return value
}
private fun nonScalarArgOutputBoolean(args: List<IExpression>, position: Position?, namespace:INameScope,
function: (arg: Collection<Double>)->Boolean): LiteralValue {
private fun collectionArgOutputBoolean(args: List<IExpression>, position: Position?, namespace:INameScope,
function: (arg: Collection<Double>)->Boolean): LiteralValue {
if(args.size!=1)
throw SyntaxError("builtin function requires one non-scalar argument", position)
val iterable = args[0].constValue(namespace)
if(iterable?.arrayvalue == null)
throw SyntaxError("builtin function requires one non-scalar argument", position)
val constants = iterable.arrayvalue.map { it.constValue(namespace) }
val constants = iterable.arrayvalue.map { it.constValue(namespace)?.asNumericValue }
if(constants.contains(null))
throw NotConstArgumentException()
val result = function(constants.map { it?.asFloat()!! })
val result = function(constants.map { it?.toDouble()!! })
return LiteralValue(if(result) 1 else 0)
}
@ -124,8 +133,25 @@ fun builtinRad(args: List<IExpression>, position: Position?, namespace:INameScop
fun builtinDeg(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
= oneDoubleArg(args, position, namespace, Math::toDegrees)
fun builtinAbs(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
= oneDoubleArg(args, position, namespace, Math::abs)
fun builtinAbs(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue {
// 1 arg, type = float or int, result type= same as argument type
if(args.size!=1)
throw SyntaxError("abs requires one numeric argument", position)
val constval = args[0].constValue(namespace) ?: throw NotConstArgumentException()
var number = constval.asNumericValue
val result =
if(number is Int || number is Byte || number is Short) {
number = number.toInt()
LiteralValue(intvalue = abs(number))
} else if(number is Double) {
LiteralValue(floatvalue = abs(number.toDouble()))
} else {
throw SyntaxError("abs requires one numeric argument", position)
}
result.position = args[0].position
return result
}
fun builtinLsl(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
= oneIntArgOutputInt(args, position, namespace) { x: Int -> x shl 1 }
@ -134,33 +160,60 @@ fun builtinLsr(args: List<IExpression>, position: Position?, namespace:INameScop
= oneIntArgOutputInt(args, position, namespace) { x: Int -> x ushr 1 }
fun builtinMin(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
= nonScalarArgOutputNumber(args, position, namespace) { it.min()!! }
= collectionArgOutputNumber(args, position, namespace) { it.min()!! }
fun builtinMax(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
= nonScalarArgOutputNumber(args, position, namespace) { it.max()!! }
= collectionArgOutputNumber(args, position, namespace) { it.max()!! }
fun builtinSum(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
= nonScalarArgOutputNumber(args, position, namespace) { it.sum() }
= collectionArgOutputNumber(args, position, namespace) { it.sum() }
fun builtinAvg(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
= nonScalarArgOutputNumber(args, position, namespace) { it.average() }
fun builtinAvg(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue {
if(args.size!=1)
throw SyntaxError("avg requires one non-scalar argument", position)
val iterable = args[0].constValue(namespace)
if(iterable?.arrayvalue == null)
throw SyntaxError("avg requires one non-scalar argument", position)
val constants = iterable.arrayvalue.map { it.constValue(namespace)?.asNumericValue }
if(constants.contains(null))
throw NotConstArgumentException()
val result = (constants.map { it!!.toDouble() }).average()
val value = LiteralValue(floatvalue = result)
value.position = args[0].position
return value
}
fun builtinLen(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
= nonScalarArgOutputNumber(args, position, namespace) { it.size }
fun builtinLen(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue {
if(args.size!=1)
throw SyntaxError("len requires one non-scalar argument", position)
val iterable = args[0].constValue(namespace)
if(iterable?.arrayvalue == null)
throw SyntaxError("len requires one non-scalar argument", position)
val constants = iterable.arrayvalue.map { it.constValue(namespace)?.asNumericValue }
if(constants.contains(null))
throw NotConstArgumentException()
val result = (constants.map { it!!.toDouble() }).size
val value = LiteralValue(intvalue = result)
value.position = args[0].position
return value
}
fun builtinAny(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
= nonScalarArgOutputBoolean(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
= nonScalarArgOutputBoolean(args, position, namespace) { it.all { v -> v != 0.0} }
= collectionArgOutputBoolean(args, position, namespace) { it.all { v -> v != 0.0} }
private fun intOrFloatLiteral(value: Double, position: Position?): LiteralValue {
val intresult = value.toInt()
val result = if(value-intresult==0.0)
LiteralValue(intvalue = intresult)
else
LiteralValue(floatvalue = value)
private fun numericLiteral(value: Number, position: Position?): LiteralValue {
val result = when(value) {
is Int -> LiteralValue(intvalue = value.toInt())
is Short -> LiteralValue(intvalue = value.toInt())
is Byte -> LiteralValue(intvalue = value.toInt())
is Double -> LiteralValue(floatvalue = value.toDouble())
is Float -> LiteralValue(floatvalue = value.toDouble())
else -> throw FatalAstException("invalid number type ${value::class}")
}
result.position = position
return result
}
}

View File

@ -2,6 +2,7 @@ package il65.optimizing
import il65.parser.ParsingFailedError
import il65.ast.*
import il65.compiler.Petscii
import kotlin.math.pow
@ -64,7 +65,33 @@ class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcess
errors.add(ExpressionException("recursive var declaration", decl.position))
return decl
}
return super.process(decl)
val result = super.process(decl)
if(decl.type==VarDeclType.CONST || decl.type==VarDeclType.VAR) {
when {
decl.datatype == DataType.FLOAT -> {
// vardecl: for float vars, promote constant integer initialization values to floats
val literal = decl.value as? LiteralValue
if (literal != null && literal.isInteger) {
val newValue = LiteralValue(floatvalue = literal.intvalue!!.toDouble())
newValue.position = literal.position
decl.value = newValue
}
}
decl.datatype == DataType.BYTE || decl.datatype == DataType.WORD -> {
// vardecl: for byte/word vars, convert char/string of length 1 initialization values to integer
val literal = decl.value as? LiteralValue
if (literal != null && literal.isString && literal.strvalue?.length == 1) {
val petscii = Petscii.encodePetscii(literal.strvalue)[0]
val newValue = LiteralValue(petscii.toInt())
newValue.position = literal.position
decl.value = newValue
}
}
}
}
return result
}
/**

View File

@ -64,7 +64,7 @@ class StatementOptimizer(private val globalNamespace: INameScope) : IAstProcesso
super.process(ifStatement)
val constvalue = ifStatement.condition.constValue(globalNamespace)
if(constvalue!=null) {
return if(constvalue.asBoolean()) {
return if(constvalue.asBooleanValue){
// always true -> keep only if-part
println("${ifStatement.position} Warning: condition is always true")
AnonymousStatementList(ifStatement.parent, ifStatement.statements)