compiler stuff

This commit is contained in:
Irmen de Jong 2024-02-05 01:09:33 +01:00
parent 6b87cbb703
commit 41afeccd51
22 changed files with 220 additions and 357 deletions

View File

@ -17,7 +17,7 @@ internal fun IPtSubroutine.returnsWhatWhere(): List<Pair<RegisterOrStatusflag, D
emptyList()
else {
val register = when (returntype!!) {
in ByteDatatypes -> RegisterOrStatusflag(RegisterOrPair.A, null)
in ByteDatatypesWithBoolean -> RegisterOrStatusflag(RegisterOrPair.A, null)
in WordDatatypes -> RegisterOrStatusflag(RegisterOrPair.AY, null)
DataType.FLOAT -> RegisterOrStatusflag(RegisterOrPair.FAC1, null)
else -> RegisterOrStatusflag(RegisterOrPair.AY, null)
@ -31,7 +31,7 @@ internal fun IPtSubroutine.returnsWhatWhere(): List<Pair<RegisterOrStatusflag, D
internal fun PtSub.returnRegister(): RegisterOrStatusflag? {
return when(returntype) {
in ByteDatatypes -> RegisterOrStatusflag(RegisterOrPair.A, null)
in ByteDatatypesWithBoolean -> RegisterOrStatusflag(RegisterOrPair.A, null)
in WordDatatypes -> RegisterOrStatusflag(RegisterOrPair.AY, null)
DataType.FLOAT -> RegisterOrStatusflag(RegisterOrPair.FAC1, null)
null -> null

View File

@ -91,7 +91,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
if(errors.noErrors()) {
val sortedList = varsDontCare.sortedByDescending { it.scopedName }
for (variable in sortedList) {
if(variable.dt in IntegerDatatypes) {
if(variable.dt in IntegerDatatypesWithBoolean) {
if(zeropage.free.isEmpty()) {
break
} else {

View File

@ -70,6 +70,8 @@ private fun compileMain(args: Array<String>): Boolean {
return false
}
println("BREAKPOINTINSTR=$breakpointCpuInstruction")
val outputPath = pathFrom(outputDir)
if(!outputPath.toFile().isDirectory) {
System.err.println("Output path doesn't exist")

View File

@ -98,8 +98,8 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
importedFiles = imported
processAst(program, args.errors, compilationOptions)
// println("*********** COMPILER AST RIGHT BEFORE OPTIMIZING *************")
// printProgram(program)
// println("*********** COMPILER AST RIGHT BEFORE OPTIMIZING *************")
// printProgram(program)
if (compilationOptions.optimize) {
optimizeAst(

View File

@ -123,12 +123,6 @@ internal class AstChecker(private val program: Program,
if(valueDt istype DataType.BOOL && expectedReturnValues[0] == DataType.UBYTE) {
// if the return value is a bool and the return type is ubyte, allow this. But give a warning.
errors.info("return type of the subroutine should probably be bool instead of ubyte", returnStmt.position)
} else if(valueDt istype DataType.UBYTE && expectedReturnValues[0] == DataType.BOOL) {
// if the return value is ubyte and the return type is bool, allow this only if value is 0 or 1
val returnValue = returnStmt.value as? NumericLiteral
if (returnValue == null || returnValue.type != DataType.UBYTE || (returnValue.number!=0.0 && returnValue.number!=1.0)) {
errors.err("type $valueDt of return value doesn't match subroutine's return type ${expectedReturnValues[0]}",returnStmt.value!!.position)
}
} else if(valueDt.isIterable && expectedReturnValues[0]==DataType.UWORD) {
// you can return a string or array when an uword (pointer) is returned
} else if(valueDt istype DataType.UWORD && expectedReturnValues[0]==DataType.STR) {
@ -156,12 +150,9 @@ internal class AstChecker(private val program: Program,
}
override fun visit(ifElse: IfElse) {
val dt = ifElse.condition.inferType(program)
if(!dt.isInteger && !dt.istype(DataType.BOOL)) {
val identifier = ifElse.condition as? IdentifierReference
if(identifier==null || identifier.targetStatement(program)!=null)
errors.err("condition value should be an integer type or bool", ifElse.condition.position)
}
if(!ifElse.condition.inferType(program).isBool)
errors.err("condition should be a boolean", ifElse.condition.position)
super.visit(ifElse)
}
@ -480,22 +471,16 @@ internal class AstChecker(private val program: Program,
}
override fun visit(untilLoop: UntilLoop) {
val dt = untilLoop.condition.inferType(program)
if(!dt.isInteger && !dt.istype(DataType.BOOL)) {
val identifier = untilLoop.condition as? IdentifierReference
if(identifier==null || identifier.targetStatement(program)!=null)
errors.err("condition value should be an integer type or bool", untilLoop.condition.position)
}
if(!untilLoop.condition.inferType(program).isBool)
errors.err("condition should be a boolean", untilLoop.condition.position)
super.visit(untilLoop)
}
override fun visit(whileLoop: WhileLoop) {
val dt = whileLoop.condition.inferType(program)
if(!dt.isInteger && !dt.istype(DataType.BOOL)) {
val identifier = whileLoop.condition as? IdentifierReference
if(identifier==null || identifier.targetStatement(program)!=null)
errors.err("condition value should be an integer type or bool", whileLoop.condition.position)
}
if(!whileLoop.condition.inferType(program).isBool)
errors.err("condition should be a boolean", whileLoop.condition.position)
super.visit(whileLoop)
}
@ -539,20 +524,10 @@ internal class AstChecker(private val program: Program,
if(numvalue!=null && targetDt.isKnown)
checkValueTypeAndRange(targetDt.getOr(DataType.UNDEFINED), numvalue)
// for now, don't enforce bool type with only logical operators...
// if(assignment.isAugmentable && targetDt istype DataType.BOOL) {
// val operator = (assignment.value as? BinaryExpression)?.operator
// if(operator in InvalidOperatorsForBoolean)
// errors.err("can't use boolean operand with this operator $operator", assignment.position)
// }
super.visit(assignment)
}
override fun visit(assignTarget: AssignTarget) {
if(assignTarget.inferType(program).istype(DataType.LONG))
errors.err("integer overflow", assignTarget.position)
super.visit(assignTarget)
val memAddr = assignTarget.memoryAddress?.addressExpression?.constValue(program)?.number?.toInt()
@ -586,16 +561,13 @@ internal class AstChecker(private val program: Program,
if (assignment is Assignment) {
val targetDatatype = assignTarget.inferType(program)
if (targetDatatype.isKnown) {
val constVal = assignment.value.constValue(program)
if(constVal==null) {
val sourceDatatype = assignment.value.inferType(program)
if (sourceDatatype.isUnknown) {
if (assignment.value !is FunctionCallExpression)
errors.err("invalid assignment value, maybe forgot '&' (address-of)", assignment.value.position)
} else {
checkAssignmentCompatible(targetDatatype.getOr(DataType.UNDEFINED),
sourceDatatype.getOr(DataType.UNDEFINED), assignment.value)
}
val sourceDatatype = assignment.value.inferType(program)
if (sourceDatatype.isUnknown) {
if (assignment.value !is BinaryExpression && assignment.value !is PrefixExpression && assignment.value !is ContainmentCheck)
errors.err("invalid assignment value, maybe forgot '&' (address-of)", assignment.value.position)
} else {
checkAssignmentCompatible(targetDatatype.getOr(DataType.UNDEFINED),
sourceDatatype.getOr(DataType.UNDEFINED), assignment.value)
}
}
}
@ -619,6 +591,10 @@ internal class AstChecker(private val program: Program,
if(decl.datatype==DataType.LONG)
errors.err("integer overflow", decl.position)
if(decl.type==VarDeclType.MEMORY) {
if (decl.datatype == DataType.BOOL || decl.datatype == DataType.ARRAY_BOOL)
errors.err("variables mapped in memory should be numeric", decl.position)
}
fun err(msg: String) = errors.err(msg, decl.position)
@ -628,8 +604,8 @@ internal class AstChecker(private val program: Program,
// CONST can only occur on simple types (byte, word, float)
if(decl.type== VarDeclType.CONST) {
if (decl.datatype !in NumericDatatypes)
err("const can only be used on numeric types (byte, word, float)")
if (decl.datatype !in NumericDatatypesWithBoolean)
err("const can only be used on numeric types or booleans")
}
// FLOATS enabled?
@ -717,11 +693,11 @@ internal class AstChecker(private val program: Program,
val eltDt = ArrayToElementTypes.getValue(decl.datatype)
if(iDt isnot eltDt) {
if(!(iDt.isBool && eltDt==DataType.UBYTE || iDt.istype(DataType.UBYTE) && eltDt==DataType.BOOL))
err("initialisation value has incompatible type (${declValue.inferType(program)}) for the variable (${decl.datatype})")
err("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})")
}
} else {
if(!(iDt.isBool && decl.datatype==DataType.UBYTE || iDt.istype(DataType.UBYTE) && decl.datatype==DataType.BOOL))
err("initialisation value has incompatible type (${declValue.inferType(program)}) for the variable (${decl.datatype})")
err("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})")
}
}
}
@ -971,9 +947,13 @@ internal class AstChecker(private val program: Program,
else if(expr.operator == "~") {
if(dt !in IntegerDatatypes)
errors.err("can only use bitwise invert on integer types", expr.position)
if(dt==DataType.BOOL)
else if(dt==DataType.BOOL)
errors.err("bitwise invert is for integer types, use 'not' on booleans", expr.position)
}
else if(expr.operator == "not") {
if(dt!=DataType.BOOL)
errors.err("logical not is for booleans", expr.position)
}
super.visit(expr)
}
@ -1014,11 +994,6 @@ internal class AstChecker(private val program: Program,
errors.err("remainder can only be used on unsigned integer operands", expr.right.position)
}
}
"&", "|", "^" -> {
// only integer numeric operands accepted
if(leftDt !in IntegerDatatypes || rightDt !in IntegerDatatypes)
errors.err("bitwise operator can only be used on integer operands", expr.right.position)
}
"in" -> throw FatalAstException("in expression should have been replaced by containmentcheck")
"<<", ">>" -> {
if(rightDt in WordDatatypes) {
@ -1043,10 +1018,12 @@ internal class AstChecker(private val program: Program,
// expression with one side BOOL other side (U)BYTE is allowed; bool==byte
} else if((expr.operator == "<<" || expr.operator == ">>") && (leftDt in WordDatatypes && rightDt in ByteDatatypes)) {
// exception allowed: shifting a word by a byte
} else if((expr.operator in BitwiseOperators) && (leftDt in IntegerDatatypes && rightDt in IntegerDatatypes)) {
// exception allowed: bitwise operations with any integers
} else if((leftDt==DataType.UWORD && rightDt==DataType.STR) || (leftDt==DataType.STR && rightDt==DataType.UWORD)) {
// exception allowed: comparing uword (pointer) with string
} else {
errors.err("left and right operands aren't the same type", expr.left.position)
errors.err("left and right operands aren't the same type", expr.position)
}
}
@ -1089,6 +1066,18 @@ internal class AstChecker(private val program: Program,
errors.err("can't use boolean operand with this operator ${expr.operator}", expr.right.position)
}
}
if(expr.operator in LogicalOperators) {
if (leftDt != DataType.BOOL || rightDt != DataType.BOOL)
errors.err("logical operator requires boolean operands", expr.right.position)
}
else {
if (leftDt == DataType.BOOL || rightDt == DataType.BOOL) {
if(expr.operator!="==" && expr.operator!="!=")
errors.err("operator requires numeric operands", expr.right.position)
}
}
}
override fun visit(typecast: TypecastExpression) {
@ -1289,14 +1278,7 @@ internal class AstChecker(private val program: Program,
if(target is Label && args.isNotEmpty())
errors.err("cannot use arguments when calling a label", position)
if(target is BuiltinFunctionPlaceholder) {
if(target.name=="all" || target.name=="any") {
if((args[0] as? AddressOf)?.identifier?.targetVarDecl(program)?.datatype == DataType.STR
|| args[0].inferType(program).getOr(DataType.STR) == DataType.STR) {
errors.err("any/all on a string is useless (is always true unless the string is empty)", position)
}
}
} else if(target is Subroutine) {
if(target is Subroutine) {
if(target.isAsmSubroutine) {
for (arg in args.zip(target.parameters)) {
val argIDt = arg.first.inferType(program)
@ -1375,7 +1357,10 @@ internal class AstChecker(private val program: Program,
}
override fun visit(whenStmt: When) {
if(!whenStmt.condition.inferType(program).isInteger)
val conditionDt = whenStmt.condition.inferType(program)
if(conditionDt.isBool)
errors.err("condition is boolean, use if statement instead", whenStmt.position)
else if(!conditionDt.isInteger)
errors.err("when condition must be an integer value", whenStmt.position)
val tally = mutableSetOf<Int>()
for((choices, choiceNode) in whenStmt.choiceValues(program)) {
@ -1406,7 +1391,7 @@ internal class AstChecker(private val program: Program,
for((constvalue, pos) in constvalues) {
when {
constvalue == null -> errors.err("choice value must be a constant", pos)
constvalue.type !in IntegerDatatypes -> errors.err("choice value must be a byte or word", pos)
constvalue.type !in IntegerDatatypesWithBoolean -> errors.err("choice value must be a byte or word", pos)
conditionType isnot constvalue.type -> {
if(conditionType.isKnown) {
if(conditionType.istype(DataType.BOOL)) {
@ -1492,7 +1477,8 @@ internal class AstChecker(private val program: Program,
private fun checkLongType(expression: Expression) {
if(expression.inferType(program).istype(DataType.LONG)) {
errors.err("integer overflow", expression.position)
if(errors.noErrorForLine(expression.position))
errors.err("integer overflow", expression.position)
}
}
@ -1654,13 +1640,14 @@ internal class AstChecker(private val program: Program,
return err("value '$number' out of range for word")
}
DataType.BOOL -> {
return true
if(value.type!=DataType.BOOL)
err("type of value ${value.type} doesn't match target $targetDt")
}
in ArrayDatatypes -> {
val eltDt = ArrayToElementTypes.getValue(targetDt)
return checkValueTypeAndRange(eltDt, value)
}
else -> return err("value of type ${value.type} not compatible with $targetDt")
else -> return err("type of value ${value.type} doesn't match target $targetDt")
}
return true
}
@ -1723,11 +1710,11 @@ internal class AstChecker(private val program: Program,
}
val result = when(targetDatatype) {
DataType.BOOL -> sourceDatatype in NumericDatatypes
DataType.BYTE -> sourceDatatype == DataType.BYTE || sourceDatatype == DataType.BOOL
DataType.UBYTE -> sourceDatatype == DataType.UBYTE || sourceDatatype == DataType.BOOL
DataType.WORD -> sourceDatatype in setOf(DataType.BYTE, DataType.UBYTE, DataType.WORD, DataType.BOOL)
DataType.UWORD -> sourceDatatype == DataType.UBYTE || sourceDatatype == DataType.UWORD || sourceDatatype == DataType.BOOL
DataType.BOOL -> sourceDatatype==DataType.BOOL
DataType.BYTE -> sourceDatatype == DataType.BYTE
DataType.UBYTE -> sourceDatatype == DataType.UBYTE
DataType.WORD -> sourceDatatype in setOf(DataType.BYTE, DataType.UBYTE, DataType.WORD)
DataType.UWORD -> sourceDatatype == DataType.UBYTE || sourceDatatype == DataType.UWORD
DataType.FLOAT -> sourceDatatype in NumericDatatypes
DataType.STR -> sourceDatatype == DataType.STR
else -> {
@ -1747,12 +1734,14 @@ internal class AstChecker(private val program: Program,
}
else if(sourceDatatype== DataType.FLOAT && targetDatatype in IntegerDatatypes)
errors.err("cannot assign float to ${targetDatatype.name.lowercase()}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position)
else if((sourceValue as? BinaryExpression)?.operator in BitwiseOperators && targetDatatype.equalsSize(sourceDatatype)) {
// this is allowed: bitwise operation between different types as long as they're the same size.
}
else if(targetDatatype==DataType.UWORD && sourceDatatype in PassByReferenceDatatypes) {
// this is allowed: a pass-by-reference datatype into a uword (pointer value).
}
else {
if(targetDatatype!=DataType.UWORD && sourceDatatype !in PassByReferenceDatatypes) {
// allow bitwise operations on different types as long as the size is the same
if (!((sourceValue as? BinaryExpression)?.operator in BitwiseOperators && targetDatatype.equalsSize(sourceDatatype)))
errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position)
}
errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position)
}
return false

View File

@ -22,10 +22,6 @@ internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: Compila
}
internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationOptions, errors: IErrorReporter) {
val boolRemover = BoolRemover(this)
boolRemover.visit(this)
boolRemover.applyModifications()
val fixer = BeforeAsmAstChanger(this, compilerOptions)
fixer.visit(this)
while (errors.noErrors() && fixer.applyModifications() > 0) {

View File

@ -136,7 +136,7 @@ class AstPreprocessor(val program: Program,
}
} else {
// handle declaration of a single variable
if(decl.value!=null && decl.datatype in NumericDatatypes) {
if(decl.value!=null && (decl.datatype in NumericDatatypes || decl.datatype==DataType.BOOL)) {
val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, decl.position)
val assign = Assignment(target, decl.value!!, AssignmentOrigin.VARINIT, decl.position)
replacements.add(IAstModification.ReplaceNode(decl, assign, scope))

View File

@ -26,7 +26,7 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
}
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
if (decl.type == VarDeclType.VAR && decl.value != null && decl.datatype in NumericDatatypes)
if (decl.type == VarDeclType.VAR && decl.value != null && (decl.datatype in NumericDatatypes || decl.datatype==DataType.BOOL))
throw InternalCompilerException("vardecls for variables, with initial numerical value, should have been rewritten as plain vardecl + assignment $decl")
return noModifications
@ -104,17 +104,7 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
override fun after(ifElse: IfElse, parent: Node): Iterable<IAstModification> {
val binExpr = ifElse.condition as? BinaryExpression
if(binExpr==null) {
// if x -> if x!=0
val booleanExpr = BinaryExpression(
ifElse.condition,
"!=",
NumericLiteral.optimalInteger(0, ifElse.condition.position),
ifElse.condition.position
)
return listOf(IAstModification.ReplaceNode(ifElse.condition, booleanExpr, ifElse))
}
if(binExpr!=null) {
if(binExpr.operator !in ComparisonOperators) {
val constRight = binExpr.right.constValue(program)
if(constRight!=null) {
@ -131,20 +121,13 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
return listOf(IAstModification.ReplaceNode(ifElse.condition, booleanExpr, ifElse))
}
}
// if x*5 -> if x*5 != 0
val booleanExpr = BinaryExpression(
ifElse.condition,
"!=",
NumericLiteral.optimalInteger(0, ifElse.condition.position),
ifElse.condition.position
)
return listOf(IAstModification.ReplaceNode(ifElse.condition, booleanExpr, ifElse))
}
if((binExpr.left as? NumericLiteral)?.number==0.0 &&
(binExpr.right as? NumericLiteral)?.number!=0.0)
throw InternalCompilerException("0==X should have been swapped to if X==0")
throw InternalCompilerException("0==X should be just X")
}
return noModifications
}

View File

@ -15,14 +15,6 @@ internal class BeforeAsmTypecastCleaner(val program: Program,
private val errors: IErrorReporter
) : AstWalker() {
override fun before(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
if(typecast.type == DataType.BOOL) {
val notZero = BinaryExpression(typecast.expression, "!=", NumericLiteral(DataType.UBYTE, 0.0, typecast.position), typecast.position)
return listOf(IAstModification.ReplaceNode(typecast, notZero, parent))
}
return noModifications
}
override fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
// see if we can remove redundant typecasts (outside of expressions)
// such as casting byte<->ubyte, word<->uword or even redundant casts (sourcetype = target type).

View File

@ -1,133 +0,0 @@
package prog8.compiler.astprocessing
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.FatalAstException
import prog8.ast.expressions.*
import prog8.ast.statements.Subroutine
import prog8.ast.statements.SubroutineParameter
import prog8.ast.statements.VarDecl
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.code.core.*
internal class BoolRemover(val program: Program) : AstWalker() {
override fun before(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
if(typecast.type == DataType.BOOL) {
val valueDt = typecast.expression.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val notZero = BinaryExpression(typecast.expression, "!=", NumericLiteral(valueDt, 0.0, typecast.position), typecast.position)
return listOf(IAstModification.ReplaceNode(typecast, notZero, parent))
}
return noModifications
}
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
if(decl.datatype==DataType.BOOL) {
var newvalue = decl.value
if(newvalue is NumericLiteral) {
if(newvalue.number!=0.0)
newvalue = NumericLiteral(DataType.UBYTE, 1.0, newvalue.position)
}
val ubyteDecl = VarDecl(decl.type, decl.origin, DataType.UBYTE, decl.zeropage, null, decl.name, emptyList(),
newvalue, decl.sharedWithAsm, false, decl.position)
return listOf(IAstModification.ReplaceNode(decl, ubyteDecl, parent))
}
if(decl.datatype==DataType.ARRAY_BOOL) {
var newarray = decl.value
if(decl.value is ArrayLiteral) {
val oldArray = (decl.value as ArrayLiteral).value
val convertedArray = oldArray.map {
var number: Expression = it
if (it is NumericLiteral && it.type == DataType.BOOL)
number = NumericLiteral(DataType.UBYTE, if (it.number == 0.0) 0.0 else 1.0, number.position)
number
}.toTypedArray()
newarray = ArrayLiteral(InferredTypes.InferredType.known(DataType.ARRAY_UB), convertedArray, decl.position)
}
val ubyteArrayDecl = VarDecl(decl.type, decl.origin, DataType.ARRAY_UB, decl.zeropage, decl.arraysize, decl.name, emptyList(),
newarray, decl.sharedWithAsm, decl.splitArray, decl.position)
return listOf(IAstModification.ReplaceNode(decl, ubyteArrayDecl, parent))
}
return noModifications
}
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
// replace BOOL return type and parameters by UBYTE
if(subroutine.returntypes.any { it==DataType.BOOL } || subroutine.parameters.any {it.type==DataType.BOOL}) {
val newReturnTypes = subroutine.returntypes.map {
if(it==DataType.BOOL) DataType.UBYTE else it
}
val newParams = subroutine.parameters.map {
if(it.type==DataType.BOOL) SubroutineParameter(it.name, DataType.UBYTE, it.position) else it
}.toMutableList()
val newSubroutine = Subroutine(subroutine.name, newParams, newReturnTypes,
subroutine.asmParameterRegisters, subroutine.asmReturnvaluesRegisters, subroutine.asmClobbers,
subroutine.asmAddress, subroutine.isAsmSubroutine, subroutine.inline, false, subroutine.statements,
subroutine.position)
return listOf(IAstModification.ReplaceNode(subroutine, newSubroutine, parent))
}
return noModifications
}
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
if(expr.operator in setOf("and", "or", "xor")) {
// see if any of the arguments to a logical boolean expression need type casting to bool
val mods = mutableListOf<IAstModification>()
val newLeft = wrapWithBooleanCastIfNeeded(expr.left, program)
val newRight = wrapWithBooleanCastIfNeeded(expr.right, program)
if(newLeft!=null)
mods += IAstModification.ReplaceNodeSafe(expr.left, newLeft, expr)
if(newRight!=null)
mods += IAstModification.ReplaceNodeSafe(expr.right, newRight, expr)
return mods
}
return noModifications
}
override fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
if(expr.operator=="not") {
val binExpr = expr.expression as? BinaryExpression
if(binExpr!=null) {
val invertedOperator = invertedComparisonOperator(binExpr.operator)
if(invertedOperator!=null) {
val inverted = BinaryExpression(binExpr.left, invertedOperator, binExpr.right, binExpr.position)
return listOf(IAstModification.ReplaceNode(expr, inverted, parent))
}
}
val exprDt = expr.expression.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val nonBoolDt = if(exprDt==DataType.BOOL) DataType.UBYTE else exprDt
val equalZero = BinaryExpression(expr.expression, "==", NumericLiteral(nonBoolDt, 0.0, expr.expression.position), expr.expression.position)
return listOf(IAstModification.ReplaceNode(expr, equalZero, parent))
}
return noModifications
}
}
internal fun wrapWithBooleanCastIfNeeded(expr: Expression, program: Program): Expression? {
fun isBoolean(expr: Expression): Boolean {
return if(expr.inferType(program) istype DataType.BOOL)
true
else if(expr is NumericLiteral && expr.type in IntegerDatatypes && (expr.number==0.0 || expr.number==1.0))
true
else if(expr is BinaryExpression && expr.operator in ComparisonOperators + LogicalOperators)
true
else if(expr is PrefixExpression && expr.operator == "not")
true
else if(expr is BinaryExpression && expr.operator in BitwiseOperators) {
if(isBoolean(expr.left) && isBoolean(expr.right))
true
else expr.operator=="&" && expr.right.constValue(program)?.number==1.0 // x & 1 is also a boolean result
}
else
false
}
return if(isBoolean(expr))
null
else
TypecastExpression(expr, DataType.BOOL, true, expr.position)
}

View File

@ -124,6 +124,11 @@ if not CONDITION
}
override fun after(whileLoop: WhileLoop, parent: Node): Iterable<IAstModification> {
if(!whileLoop.condition.inferType(program).isBool)
errors.err("condition should be a boolean", whileLoop.condition.position)
/*
while true -> repeat
while false -> discard

View File

@ -558,8 +558,7 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
private fun transform(srcExpr: BinaryExpression): PtBinaryExpression {
val type = srcExpr.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val actualType = if(type==DataType.BOOL) DataType.UBYTE else type
val expr = PtBinaryExpression(srcExpr.operator, actualType, srcExpr.position)
val expr = PtBinaryExpression(srcExpr.operator, type, srcExpr.position)
expr.add(transformExpression(srcExpr.left))
expr.add(transformExpression(srcExpr.right))
return expr
@ -578,27 +577,27 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
fun desugar(range: RangeExpression): PtExpression {
require(range.from.inferType(program)==range.to.inferType(program))
val expr = PtBinaryExpression("and", DataType.UBYTE, srcCheck.position)
val expr = PtBinaryExpression("and", DataType.BOOL, srcCheck.position)
val x1 = transformExpression(srcCheck.element)
val x2 = transformExpression(srcCheck.element)
val eltDt = srcCheck.element.inferType(program)
if(eltDt.isInteger) {
val low = PtBinaryExpression("<=", DataType.UBYTE, srcCheck.position)
val low = PtBinaryExpression("<=", DataType.BOOL, srcCheck.position)
low.add(transformExpression(range.from))
low.add(x1)
expr.add(low)
val high = PtBinaryExpression("<=", DataType.UBYTE, srcCheck.position)
val high = PtBinaryExpression("<=", DataType.BOOL, srcCheck.position)
high.add(x2)
high.add(transformExpression(range.to))
expr.add(high)
} else {
val low = PtBinaryExpression("<=", DataType.UBYTE, srcCheck.position)
val low = PtBinaryExpression("<=", DataType.BOOL, srcCheck.position)
val lowFloat = PtTypeCast(DataType.FLOAT, range.from.position)
lowFloat.add(transformExpression(range.from))
low.add(lowFloat)
low.add(x1)
expr.add(low)
val high = PtBinaryExpression("<=", DataType.UBYTE, srcCheck.position)
val high = PtBinaryExpression("<=", DataType.BOOL, srcCheck.position)
high.add(x2)
val highFLoat = PtTypeCast(DataType.FLOAT, range.to.position)
highFLoat.add(transformExpression(range.to))
@ -655,8 +654,12 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
return mem
}
private fun transform(number: NumericLiteral): PtNumber =
PtNumber(number.type, number.number, number.position)
private fun transform(number: NumericLiteral): PtExpression {
return if(number.type==DataType.BOOL)
PtBool(number.asBooleanValue, number.position)
else
PtNumber(number.type, number.number, number.position)
}
private fun transform(srcPrefix: PrefixExpression): PtPrefix {
val type = srcPrefix.inferType(program).getOrElse { throw FatalAstException("unknown dt") }

View File

@ -76,8 +76,8 @@ internal class LiteralsToAutoVars(private val program: Program,
if(decl.names.size>1) {
// note: the desugaring of a multi-variable vardecl has to be done here
// and not in CodeDesugarer, that one is too late (identifiers can't be found otherwise)
if(decl.datatype !in NumericDatatypes)
errors.err("can only multi declare numeric variables", decl.position)
if(decl.datatype !in NumericDatatypesWithBoolean)
errors.err("can only multi declare numeric and boolean variables", decl.position)
if(errors.noErrors()) {
// desugar into individual vardecl per name.
return decl.desugarMultiDecl().map {

View File

@ -6,13 +6,9 @@ import prog8.ast.base.FatalAstException
import prog8.ast.expressions.BinaryExpression
import prog8.ast.expressions.NumericLiteral
import prog8.ast.expressions.PrefixExpression
import prog8.ast.expressions.invertCondition
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.code.core.DataType
import prog8.code.core.ICompilationTarget
import prog8.code.core.IErrorReporter
import prog8.code.core.IntegerDatatypes
import prog8.code.core.*
internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val errors: IErrorReporter, val compTarget: ICompilationTarget) : AstWalker() {
@ -21,7 +17,7 @@ internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val
val left = expr.left as? BinaryExpression
if (left != null) {
val rightValue = expr.right.constValue(program)
if (rightValue?.number == 0.0 && rightValue.type in IntegerDatatypes) {
if (rightValue?.number == 0.0 && rightValue.type in IntegerDatatypesWithBoolean) {
if (left.operator == "==" && expr.operator == "==") {
// (x==something)==0 --> x!=something
left.operator = "!="
@ -43,15 +39,11 @@ internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val
}
}
if(expr.operator=="^" && expr.left.inferType(program) istype DataType.BOOL && expr.right.constValue(program)?.number == 1.0) {
// boolean ^ 1 --> not boolean
return listOf(IAstModification.ReplaceNode(expr, invertCondition(expr.left, program), parent))
}
// applying De Morgan's laws proved beneficial for the code generator,
// when the code has one outer 'not' instead of two inner ones.
if(expr.operator=="or" || expr.operator=="and") {
// boolean case
val newOper = if(expr.operator=="or") "and" else "or"
val leftP = expr.left as? PrefixExpression
val rightP = expr.right as? PrefixExpression
@ -62,17 +54,25 @@ internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val
val notExpr = PrefixExpression("not", inner, expr.position)
return listOf(IAstModification.ReplaceNode(expr, notExpr, parent))
}
val leftB = expr.left as? BinaryExpression
val rightB = expr.right as? BinaryExpression
if(leftB!=null && leftB.operator=="==" && (leftB.right as? NumericLiteral)?.number==0.0
&& rightB!=null && rightB.operator=="==" && (rightB.right as? NumericLiteral)?.number==0.0) {
// a==0 or b==0 --> (a!=0 and b!=0)==0
// a==0 and b==0 --> (a!=0 or b!=0)==0
leftB.operator = "!="
rightB.operator = "!="
val inner = BinaryExpression(leftB, newOper, rightB, expr.position)
val notExpr = BinaryExpression(inner, "==", NumericLiteral.optimalInteger(0, expr.position), expr.position)
return listOf(IAstModification.ReplaceNode(expr, notExpr, parent))
// integer case (only if both are the same type)
val leftC = expr.left as? BinaryExpression
val rightC = expr.right as? BinaryExpression
if(leftC!=null && rightC!=null && leftC.operator=="==" && rightC.operator=="==") {
if (leftC.right.constValue(program)?.number == 0.0 && rightC.right.constValue(program)?.number == 0.0) {
val leftDt = leftC.left.inferType(program).getOr(DataType.UNDEFINED)
val rightDt = rightC.left.inferType(program).getOr(DataType.UNDEFINED)
if(leftDt==rightDt && leftDt in IntegerDatatypes) {
if (rightC.left.isSimple) {
// x==0 or y==0 -> (x & y)==0
// x==0 and y==0 -> (x | y)==0
val newOperator = if(expr.operator=="or") "&" else "|"
val inner = BinaryExpression(leftC.left, newOperator, rightC.left, expr.position)
val compare = BinaryExpression(inner, "==", NumericLiteral(leftDt, 0.0, expr.position), expr.position)
return listOf(IAstModification.ReplaceNode(expr, compare, parent))
}
}
}
}
}
@ -82,17 +82,50 @@ internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val
override fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
if(expr.operator == "not") {
// first check if we're already part of a "boolean" expresion (i.e. comparing against 0)
// first check if we're already part of a "boolean" expression (i.e. comparing against 0 or 1)
// if so, simplify THAT whole expression rather than making it more complicated
if(parent is BinaryExpression && parent.right.constValue(program)?.number==0.0) {
if(parent.operator=="==") {
// (NOT X)==0 --> X!=0
val replacement = BinaryExpression(expr.expression, "!=", NumericLiteral.optimalInteger(0, expr.position), expr.position)
return listOf(IAstModification.ReplaceNode(parent, replacement, parent.parent))
} else if(parent.operator=="!=") {
// (NOT X)!=0 --> X==0
val replacement = BinaryExpression(expr.expression, "==", NumericLiteral.optimalInteger(0, expr.position), expr.position)
return listOf(IAstModification.ReplaceNode(parent, replacement, parent.parent))
if (parent is BinaryExpression) {
if (parent.right.constValue(program)?.number == 0.0) {
if(parent.right.inferType(program).isBool) {
if(parent.operator=="==") {
// (NOT X)==false --> X==true --> X
return listOf(IAstModification.ReplaceNode(parent, expr.expression, parent.parent))
} else if(parent.operator=="!=") {
// (NOT X)!=false --> X!=true -> not X
return listOf(IAstModification.ReplaceNode(parent, expr, parent.parent))
}
} else {
if(parent.operator=="==") {
// (NOT X)==0 --> X!=0
val replacement = BinaryExpression(expr.expression, "!=", NumericLiteral.optimalInteger(0, expr.position), expr.position)
return listOf(IAstModification.ReplaceNode(parent, replacement, parent.parent))
} else if(parent.operator=="!=") {
// (NOT X)!=0 --> X==0
val replacement = BinaryExpression(expr.expression, "==", NumericLiteral.optimalInteger(0, expr.position), expr.position)
return listOf(IAstModification.ReplaceNode(parent, replacement, parent.parent))
}
}
}
else if (parent.right.constValue(program)?.number == 1.0) {
if(parent.right.inferType(program).isBool) {
if(parent.operator=="==") {
// (NOT X)==true --> X==false --> not X
return listOf(IAstModification.ReplaceNode(parent, expr, parent.parent))
} else if(parent.operator=="!=") {
// (NOT X)!=true --> X!=false -> X
return listOf(IAstModification.ReplaceNode(parent, expr.expression, parent.parent))
}
} else {
if(parent.operator=="==") {
// (NOT X)==1 --> X==0
val replacement = BinaryExpression(expr.expression, "==", NumericLiteral.optimalInteger(0, expr.position), expr.position)
return listOf(IAstModification.ReplaceNode(parent, replacement, parent.parent))
} else if(parent.operator=="!=") {
// (NOT X)!=1 --> X!=0
val replacement = BinaryExpression(expr.expression, "!=", NumericLiteral.optimalInteger(0, expr.position), expr.position)
return listOf(IAstModification.ReplaceNode(parent, replacement, parent.parent))
}
}
}
}
@ -120,13 +153,8 @@ internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val
return listOf(IAstModification.ReplaceNode(expr, subBinExpr, parent))
}
}
// not simpleX -> simpleX==0
if(expr.expression.isSimple) {
val replacement = BinaryExpression(expr.expression.copy(),"==", NumericLiteral(DataType.UBYTE, 0.0, expr.position), expr.position)
return listOf(IAstModification.ReplaceNodeSafe(expr, replacement, parent))
}
}
return noModifications
}
}

View File

@ -44,7 +44,7 @@ internal class StatementReorderer(
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
if (decl.type == VarDeclType.VAR) {
if (decl.datatype in NumericDatatypes) {
if (decl.datatype in NumericDatatypes || decl.datatype==DataType.BOOL) {
if(decl !in declsProcessedWithInitAssignment) {
declsProcessedWithInitAssignment.add(decl)
if (decl.value == null) {

View File

@ -24,12 +24,11 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val valueDt = declValue.inferType(program)
if(valueDt isnot decl.datatype) {
// don't add a typecast on an array initializer value, unless booleans
if(valueDt.isInteger && decl.isArray) {
if(decl.datatype == DataType.ARRAY_BOOL) {
val integer = declValue.constValue(program)?.number
if(integer!=null) {
val num = NumericLiteral(DataType.UBYTE, if(integer==0.0) 0.0 else 1.0, declValue.position)
val num = NumericLiteral(DataType.BOOL, if(integer==0.0) 0.0 else 1.0, declValue.position)
num.parent = decl
decl.value = num
}
@ -87,30 +86,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
}
}
if(expr.operator in LogicalOperators && leftDt.isInteger && rightDt.isInteger) {
// see if any of the operands needs conversion to bool
val modifications = mutableListOf<IAstModification>()
val newLeft = wrapWithBooleanCastIfNeeded(expr.left, program)
val newRight = wrapWithBooleanCastIfNeeded(expr.right, program)
if(newLeft!=null)
modifications += IAstModification.ReplaceNode(expr.left, newLeft, expr)
if(newRight!=null)
modifications += IAstModification.ReplaceNode(expr.right, newRight, expr)
if(modifications.isNotEmpty())
return modifications
}
if(leftDt!=rightDt) {
// convert bool type to byte if needed
if(leftDt istype DataType.BOOL && rightDt.isBytes && !rightDt.istype(DataType.BOOL)) {
if(rightCv==null || (rightCv.number!=1.0 && rightCv.number!=0.0))
return listOf(IAstModification.ReplaceNode(expr.left,
TypecastExpression(expr.left, rightDt.getOr(DataType.UNDEFINED),true, expr.left.position), expr))
} else if(leftDt.isBytes && !leftDt.istype(DataType.BOOL) && rightDt istype DataType.BOOL) {
if(leftCv==null || (leftCv.number!=1.0 && leftCv.number!=0.0))
return listOf(IAstModification.ReplaceNode(expr.right,
TypecastExpression(expr.right, leftDt.getOr(DataType.UNDEFINED),true, expr.right.position), expr))
}
// convert a negative operand for bitwise operator to the 2's complement positive number instead
if(expr.operator in BitwiseOperators && leftDt.isInteger && rightDt.isInteger) {
if(leftCv!=null && leftCv.number<0) {
@ -169,13 +145,18 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
// determine common datatype and add typecast as required to make left and right equal types
val (commonDt, toFix) = BinaryExpression.commonDatatype(leftDt.getOr(DataType.UNDEFINED), rightDt.getOr(DataType.UNDEFINED), expr.left, expr.right)
if(toFix!=null) {
val modifications = mutableListOf<IAstModification>()
when {
toFix===expr.left -> addTypecastOrCastedValueModification(modifications, expr.left, commonDt, expr)
toFix===expr.right -> addTypecastOrCastedValueModification(modifications, expr.right, commonDt, expr)
else -> throw FatalAstException("confused binary expression side")
if(commonDt==DataType.BOOL) {
// don't automatically cast to bool
errors.err("left and right operands aren't the same type", expr.position)
} else {
val modifications = mutableListOf<IAstModification>()
when {
toFix===expr.left -> addTypecastOrCastedValueModification(modifications, expr.left, commonDt, expr)
toFix===expr.right -> addTypecastOrCastedValueModification(modifications, expr.right, commonDt, expr)
else -> throw FatalAstException("confused binary expression side")
}
return modifications
}
return modifications
}
}
}
@ -196,10 +177,6 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(valuetype in IterableDatatypes && targettype==DataType.UWORD)
// special case, don't typecast STR/arrays to UWORD, we support those assignments "directly"
return noModifications
if((assignment.value as? BinaryExpression)?.operator in ComparisonOperators && targettype in IntegerDatatypes) {
// special case, treat a boolean comparison result as the same type as the target value to avoid needless casts later
return noModifications
}
val modifications = mutableListOf<IAstModification>()
addTypecastOrCastedValueModification(modifications, assignment.value, targettype, assignment)
return modifications
@ -244,7 +221,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
}
private fun afterFunctionCallArgs(call: IFunctionCall): Iterable<IAstModification> {
// see if a typecast is needed to convert the arguments into the required parameter's type
// see if a typecast is needed to convert the arguments into the required parameter type
val modifications = mutableListOf<IAstModification>()
val sub = call.target.targetStatement(program)
val params = when(sub) {
@ -398,6 +375,8 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
val sourceDt = expressionToCast.inferType(program).getOr(DataType.UNDEFINED)
if(sourceDt == requiredType)
return
if(requiredType==DataType.BOOL)
return
if(expressionToCast is NumericLiteral && expressionToCast.type!=DataType.FLOAT) { // refuse to automatically truncate floats
val castedValue = expressionToCast.cast(requiredType, true)
if (castedValue.isValid) {

View File

@ -105,12 +105,7 @@ internal class VerifyFunctionArgTypes(val program: Program, val errors: IErrorRe
if(mismatch>=0) {
val actual = argtypes[mismatch]
val expected = consideredParamTypes[mismatch]
return if(actual==DataType.BOOL && expected in ByteDatatypes)
null // a bool is just 1 or 0.
else if(expected==DataType.BOOL && actual==DataType.UBYTE && call.args[mismatch].constValue(program)?.number in setOf(0.0, 1.0))
null // specifying a 1 or 0 as a BOOL is okay
else
Pair("argument ${mismatch + 1} type mismatch, was: $actual expected: $expected", call.args[mismatch].position)
return Pair("argument ${mismatch + 1} type mismatch, was: $actual expected: $expected", call.args[mismatch].position)
}
if(target.isAsmSubroutine) {
if(target.asmReturnvaluesRegisters.size>1) {

View File

@ -174,7 +174,7 @@ class IRFileReader {
if('.' !in name)
throw IRParseException("unscoped varname: $name")
val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null
val dt: DataType = parseDatatype(type, arraysize!=null)
val dt = parseDatatype(type, arraysize!=null)
val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish)
val dummyNode = PtVariable(name, dt, zp, null, null, Position.DUMMY)
val newVar = StStaticVariable(name, dt, null, null, null, arraysize, zp, dummyNode)
@ -210,7 +210,8 @@ class IRFileReader {
var initNumeric: Double? = null
var initArray: StArray? = null
when(dt) {
in NumericDatatypes -> initNumeric = parseIRValue(value).toDouble()
DataType.BOOL -> TODO("parse boolean $value")
in NumericDatatypes -> initNumeric = parseIRValue(value)
in ArrayDatatypes -> {
initArray = value.split(',').map {
if (it.startsWith('@'))
@ -496,24 +497,24 @@ class IRFileReader {
private fun parseDatatype(type: String, isArray: Boolean): DataType {
if(isArray) {
return when(type) {
// note: there are no BOOLEANS anymore in the IR. Only UBYTE.
"byte" -> DataType.ARRAY_B
"ubyte", "str" -> DataType.ARRAY_UB
"word" -> DataType.ARRAY_W
"uword" -> DataType.ARRAY_UW
"float" -> DataType.ARRAY_F
"bool" -> DataType.ARRAY_B
"uword_split" -> DataType.ARRAY_UW_SPLIT
"word_split" -> DataType.ARRAY_W_SPLIT
else -> throw IRParseException("invalid dt")
}
} else {
return when(type) {
// note: there are no BOOLEANS anymore in the IR. Only UBYTE.
"byte" -> DataType.BYTE
"ubyte" -> DataType.UBYTE
"word" -> DataType.WORD
"uword" -> DataType.UWORD
"float" -> DataType.FLOAT
"bool" -> DataType.BOOL
// note: 'str' should not occur anymore in IR. Should be 'uword'
else -> throw IRParseException("invalid dt")
}

View File

@ -100,7 +100,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
is IRSubroutine -> {
xml.writeStartElement("SUB")
xml.writeAttribute("NAME", child.label)
xml.writeAttribute("RETURNTYPE", child.returnType?.toString()?.lowercase() ?: "")
xml.writeAttribute("RETURNTYPE", child.returnType?.typeString(null)?.lowercase() ?: "")
xml.writeAttribute("POS", child.position.toString())
xml.writeCharacters("\n")
xml.writeStartElement("PARAMS")
@ -247,8 +247,9 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_msb=$msbValue zp=${variable.zpwish}\n")
} else {
val value: String = when(variable.dt) {
DataType.BOOL -> variable.onetimeInitializationNumericValue?.toInt()?.toString() ?: ""
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: "").toString()
in NumericDatatypes -> (variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: "").toString()
in NumericDatatypes -> variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: ""
DataType.STR -> {
val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue.second) + listOf(0u)
encoded.joinToString(",") { it.toInt().toString() }

View File

@ -409,8 +409,8 @@ class IRSubroutine(
require(!label.startsWith("main.main.")) {"subroutine name invalid main prefix: $label"}
// params and return value should not be str
require(parameters.all{ it.dt in NumericDatatypes }) {"non-numeric parameter"}
require(returnType==null || returnType in NumericDatatypes) {"non-numeric returntype $returnType"}
require(parameters.all{ it.dt in NumericDatatypes || it.dt==DataType.BOOL }) {"non-numeric/non-bool parameter"}
require(returnType==null || returnType in NumericDatatypes || returnType==DataType.BOOL) {"non-numeric/non-bool returntype $returnType"}
}
operator fun plusAssign(chunk: IRCodeChunkBase) {

View File

@ -80,7 +80,13 @@ class IRSymbolTable {
return newArray
}
scopedName = variable.scopedName
varToadd = IRStStaticVariable(scopedName, variable.dt,
val dt = when(variable.dt) {
DataType.BOOL -> DataType.UBYTE
DataType.ARRAY_BOOL -> DataType.ARRAY_UB
else -> variable.dt
}
varToadd = IRStStaticVariable(scopedName,
dt,
variable.onetimeInitializationNumericValue,
variable.onetimeInitializationStringValue,
fixupAddressOfInArray(variable.onetimeInitializationArrayValue),
@ -166,6 +172,10 @@ class IRStMemVar(name: String,
}
}
init {
require(dt!=DataType.BOOL && dt!=DataType.ARRAY_BOOL)
}
val typeString: String = dt.typeString(length)
}
@ -205,6 +215,10 @@ class IRStStaticVariable(name: String,
}
}
init {
require(dt!=DataType.BOOL && dt!=DataType.ARRAY_BOOL)
}
val uninitialized = onetimeInitializationArrayValue==null && onetimeInitializationStringValue==null && onetimeInitializationNumericValue==null
val typeString: String = dt.typeString(length)
@ -213,9 +227,17 @@ class IRStStaticVariable(name: String,
class IRStArrayElement(val number: Double?, val addressOfSymbol: String?) {
companion object {
fun from(elt: StArrayElement): IRStArrayElement {
return IRStArrayElement(elt.number, elt.addressOfSymbol)
if(elt.boolean!=null)
return IRStArrayElement(if(elt.boolean==true) 1.0 else 0.0, elt.addressOfSymbol)
else
return IRStArrayElement(elt.number, elt.addressOfSymbol)
}
}
init {
// TODO TEMPORARY
require(number!=null || addressOfSymbol!=null)
}
}
typealias IRStArray = List<IRStArrayElement>

View File

@ -9,15 +9,15 @@ import prog8.code.right
fun DataType.typeString(length: Int?): String {
val lengthStr = if(length==0) "" else length.toString()
return when (this) {
DataType.BOOL -> "bool"
DataType.BOOL -> "ubyte" // in IR , a boolean is represented by an ubyte.
DataType.UBYTE -> "ubyte"
DataType.BYTE -> "byte"
DataType.UWORD -> "uword"
DataType.WORD -> "word"
DataType.LONG -> "long"
DataType.FLOAT -> "float"
DataType.STR -> "ubyte[$lengthStr]" // here string doesn't exist as a seperate datatype anymore
DataType.ARRAY_BOOL -> "bool[$lengthStr]"
DataType.STR -> "ubyte[$lengthStr]" // here string doesn't exist as a seperate datatype anymore
DataType.ARRAY_BOOL -> "ubyte[$lengthStr]" // in IR , a boolean is represented by an ubyte.
DataType.ARRAY_UB -> "ubyte[$lengthStr]"
DataType.ARRAY_B -> "byte[$lengthStr]"
DataType.ARRAY_UW -> "uword[$lengthStr]"