renamed InferredType.typeOrElse to getOr()

this is closer to the convention of most functional return types
This commit is contained in:
Irmen de Jong 2021-10-13 00:21:38 +02:00
parent 1c7c67060d
commit 66574d058a
25 changed files with 104 additions and 103 deletions

View File

@ -146,7 +146,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I
// see if we can remove superfluous typecasts (outside of expressions) // see if we can remove superfluous typecasts (outside of expressions)
// such as casting byte<->ubyte, word<->uword // such as casting byte<->ubyte, word<->uword
// Also the special typecast of a reference type (str, array) to an UWORD will be changed into address-of. // Also the special typecast of a reference type (str, array) to an UWORD will be changed into address-of.
val sourceDt = typecast.expression.inferType(program).typeOrElse(DataType.UNDEFINED) val sourceDt = typecast.expression.inferType(program).getOr(DataType.UNDEFINED)
if (typecast.type in ByteDatatypes && sourceDt in ByteDatatypes if (typecast.type in ByteDatatypes && sourceDt in ByteDatatypes
|| typecast.type in WordDatatypes && sourceDt in WordDatatypes) { || typecast.type in WordDatatypes && sourceDt in WordDatatypes) {
if(typecast.parent !is Expression) { if(typecast.parent !is Expression) {
@ -266,8 +266,8 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I
// if the datatype of the arguments of cmp() are different, cast the byte one to word. // if the datatype of the arguments of cmp() are different, cast the byte one to word.
val arg1 = functionCallStatement.args[0] val arg1 = functionCallStatement.args[0]
val arg2 = functionCallStatement.args[1] val arg2 = functionCallStatement.args[1]
val dt1 = arg1.inferType(program).typeOrElse(DataType.UNDEFINED) val dt1 = arg1.inferType(program).getOr(DataType.UNDEFINED)
val dt2 = arg2.inferType(program).typeOrElse(DataType.UNDEFINED) val dt2 = arg2.inferType(program).getOr(DataType.UNDEFINED)
if(dt1 in ByteDatatypes) { if(dt1 in ByteDatatypes) {
if(dt2 in ByteDatatypes) if(dt2 in ByteDatatypes)
return noModifications return noModifications

View File

@ -79,7 +79,7 @@ internal class AstChecker(private val program: Program,
if(!valueDt.isKnown) { if(!valueDt.isKnown) {
errors.err("return value type mismatch or unknown symbol", returnStmt.value!!.position) errors.err("return value type mismatch or unknown symbol", returnStmt.value!!.position)
} else { } else {
if (expectedReturnValues[0] != valueDt.typeOrElse(DataType.UNDEFINED)) if (expectedReturnValues[0] != valueDt.getOr(DataType.UNDEFINED))
errors.err("type $valueDt of return value doesn't match subroutine's return type ${expectedReturnValues[0]}", returnStmt.value!!.position) errors.err("type $valueDt of return value doesn't match subroutine's return type ${expectedReturnValues[0]}", returnStmt.value!!.position)
} }
} }
@ -105,7 +105,7 @@ internal class AstChecker(private val program: Program,
} }
} }
val iterableDt = forLoop.iterable.inferType(program).typeOrElse(DataType.BYTE) val iterableDt = forLoop.iterable.inferType(program).getOr(DataType.BYTE)
if(iterableDt !in IterableDatatypes && forLoop.iterable !is RangeExpr) { if(iterableDt !in IterableDatatypes && forLoop.iterable !is RangeExpr) {
errors.err("can only loop over an iterable type", forLoop.position) errors.err("can only loop over an iterable type", forLoop.position)
} else { } else {
@ -414,7 +414,7 @@ internal class AstChecker(private val program: Program,
if(!idt.isKnown) { if(!idt.isKnown) {
errors.err("return type mismatch", assignment.value.position) errors.err("return type mismatch", assignment.value.position)
} }
if(stmt.returntypes.isEmpty() || (stmt.returntypes.size == 1 && stmt.returntypes.single() isNotAssignableTo idt.typeOrElse(DataType.BYTE))) { if(stmt.returntypes.isEmpty() || (stmt.returntypes.size == 1 && stmt.returntypes.single() isNotAssignableTo idt.getOr(DataType.BYTE))) {
errors.err("return type mismatch", assignment.value.position) errors.err("return type mismatch", assignment.value.position)
} }
} }
@ -479,15 +479,15 @@ internal class AstChecker(private val program: Program,
if (targetDatatype.isKnown) { if (targetDatatype.isKnown) {
val constVal = assignment.value.constValue(program) val constVal = assignment.value.constValue(program)
if (constVal != null) { if (constVal != null) {
checkValueTypeAndRange(targetDatatype.typeOrElse(DataType.BYTE), constVal) checkValueTypeAndRange(targetDatatype.getOr(DataType.BYTE), constVal)
} else { } else {
val sourceDatatype = assignment.value.inferType(program) val sourceDatatype = assignment.value.inferType(program)
if (sourceDatatype.isUnknown) { if (sourceDatatype.isUnknown) {
if (assignment.value !is FunctionCall) if (assignment.value !is FunctionCall)
errors.err("assignment value is invalid or has no proper datatype", assignment.value.position) errors.err("assignment value is invalid or has no proper datatype", assignment.value.position)
} else { } else {
checkAssignmentCompatible(targetDatatype.typeOrElse(DataType.BYTE), assignTarget, checkAssignmentCompatible(targetDatatype.getOr(DataType.BYTE), assignTarget,
sourceDatatype.typeOrElse(DataType.BYTE), assignment.value, assignment.position) sourceDatatype.getOr(DataType.BYTE), assignment.value, assignment.position)
} }
} }
} }
@ -741,11 +741,11 @@ internal class AstChecker(private val program: Program,
override fun visit(array: ArrayLiteralValue) { override fun visit(array: ArrayLiteralValue) {
if(array.type.isKnown) { if(array.type.isKnown) {
if (!compilerOptions.floats && array.type.typeOrElse(DataType.UNDEFINED) in setOf(DataType.FLOAT, DataType.ARRAY_F)) { if (!compilerOptions.floats && array.type.getOr(DataType.UNDEFINED) in setOf(DataType.FLOAT, DataType.ARRAY_F)) {
errors.err("floating point used, but that is not enabled via options", array.position) errors.err("floating point used, but that is not enabled via options", array.position)
} }
val arrayspec = ArrayIndex.forArray(array) val arrayspec = ArrayIndex.forArray(array)
checkValueTypeAndRangeArray(array.type.typeOrElse(DataType.UNDEFINED), arrayspec, array) checkValueTypeAndRangeArray(array.type.getOr(DataType.UNDEFINED), arrayspec, array)
} }
fun isPassByReferenceElement(e: Expression): Boolean { fun isPassByReferenceElement(e: Expression): Boolean {
@ -794,7 +794,7 @@ internal class AstChecker(private val program: Program,
if(!idt.isKnown) if(!idt.isKnown)
return // any error should be reported elsewhere return // any error should be reported elsewhere
val dt = idt.typeOrElse(DataType.UNDEFINED) val dt = idt.getOr(DataType.UNDEFINED)
if(expr.operator=="-") { if(expr.operator=="-") {
if (dt != DataType.BYTE && dt != DataType.WORD && dt != DataType.FLOAT) { if (dt != DataType.BYTE && dt != DataType.WORD && dt != DataType.FLOAT) {
errors.err("can only take negative of a signed number type", expr.position) errors.err("can only take negative of a signed number type", expr.position)
@ -819,8 +819,8 @@ internal class AstChecker(private val program: Program,
if(!leftIDt.isKnown || !rightIDt.isKnown) if(!leftIDt.isKnown || !rightIDt.isKnown)
return // hopefully this error will be detected elsewhere return // hopefully this error will be detected elsewhere
val leftDt = leftIDt.typeOrElse(DataType.UNDEFINED) val leftDt = leftIDt.getOr(DataType.UNDEFINED)
val rightDt = rightIDt.typeOrElse(DataType.UNDEFINED) val rightDt = rightIDt.getOr(DataType.UNDEFINED)
when(expr.operator){ when(expr.operator){
"/", "%" -> { "/", "%" -> {
@ -1028,7 +1028,7 @@ internal class AstChecker(private val program: Program,
if((args[0] as? AddressOf)?.identifier?.targetVarDecl(program)?.datatype == DataType.STR) { if((args[0] as? AddressOf)?.identifier?.targetVarDecl(program)?.datatype == DataType.STR) {
errors.err("any/all on a string is useless (is always true unless the string is empty)", position) errors.err("any/all on a string is useless (is always true unless the string is empty)", position)
} }
if(args[0].inferType(program).typeOrElse(DataType.STR) == DataType.STR) { if(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) errors.err("any/all on a string is useless (is always true unless the string is empty)", position)
} }
} }
@ -1157,7 +1157,7 @@ internal class AstChecker(private val program: Program,
when { when {
constvalue == null -> errors.err("choice value must be a constant", whenChoice.position) constvalue == null -> errors.err("choice value must be a constant", whenChoice.position)
constvalue.type !in IntegerDatatypes -> errors.err("choice value must be a byte or word", whenChoice.position) constvalue.type !in IntegerDatatypes -> errors.err("choice value must be a byte or word", whenChoice.position)
constvalue.type != conditionType.typeOrElse(DataType.UNDEFINED) -> errors.err("choice value datatype differs from condition value", whenChoice.position) constvalue.type != conditionType.getOr(DataType.UNDEFINED) -> errors.err("choice value datatype differs from condition value", whenChoice.position)
} }
} }
} else { } else {

View File

@ -38,7 +38,7 @@ internal class LiteralsToAutoVars(private val program: Program) : AstWalker() {
val arrayDt = array.guessDatatype(program) val arrayDt = array.guessDatatype(program)
if(arrayDt.isKnown) { if(arrayDt.isKnown) {
// this array literal is part of an expression, turn it into an identifier reference // this array literal is part of an expression, turn it into an identifier reference
val litval2 = array.cast(arrayDt.typeOrElse(DataType.UNDEFINED)) val litval2 = array.cast(arrayDt.getOr(DataType.UNDEFINED))
if(litval2!=null) { if(litval2!=null) {
val vardecl2 = VarDecl.createAuto(litval2) val vardecl2 = VarDecl.createAuto(litval2)
val identifier = IdentifierReference(listOf(vardecl2.name), vardecl2.position) val identifier = IdentifierReference(listOf(vardecl2.name), vardecl2.position)

View File

@ -106,7 +106,7 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
is Assignment -> { is Assignment -> {
val targetDt = parent.target.inferType(program) val targetDt = parent.target.inferType(program)
if(leftDt != targetDt) { if(leftDt != targetDt) {
val cast = TypecastExpression(expr.left, targetDt.typeOrElse(DataType.UNDEFINED), true, parent.position) val cast = TypecastExpression(expr.left, targetDt.getOr(DataType.UNDEFINED), true, parent.position)
return listOf(IAstModification.ReplaceNode(expr.left, cast, expr)) return listOf(IAstModification.ReplaceNode(expr.left, cast, expr))
} }
} }

View File

@ -47,7 +47,7 @@ class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalk
val rightDt = expr.right.inferType(program) val rightDt = expr.right.inferType(program)
if(leftDt.isKnown && rightDt.isKnown && leftDt!=rightDt) { if(leftDt.isKnown && rightDt.isKnown && leftDt!=rightDt) {
// determine common datatype and add typecast as required to make left and right equal types // determine common datatype and add typecast as required to make left and right equal types
val (commonDt, toFix) = BinaryExpression.commonDatatype(leftDt.typeOrElse(DataType.UNDEFINED), rightDt.typeOrElse(DataType.UNDEFINED), expr.left, expr.right) val (commonDt, toFix) = BinaryExpression.commonDatatype(leftDt.getOr(DataType.UNDEFINED), rightDt.getOr(DataType.UNDEFINED), expr.left, expr.right)
if(toFix!=null) { if(toFix!=null) {
return when { return when {
toFix===expr.left -> listOf(IAstModification.ReplaceNode( toFix===expr.left -> listOf(IAstModification.ReplaceNode(
@ -66,8 +66,8 @@ class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalk
val valueItype = assignment.value.inferType(program) val valueItype = assignment.value.inferType(program)
val targetItype = assignment.target.inferType(program) val targetItype = assignment.target.inferType(program)
if(targetItype.isKnown && valueItype.isKnown) { if(targetItype.isKnown && valueItype.isKnown) {
val targettype = targetItype.typeOrElse(DataType.UNDEFINED) val targettype = targetItype.getOr(DataType.UNDEFINED)
val valuetype = valueItype.typeOrElse(DataType.UNDEFINED) val valuetype = valueItype.getOr(DataType.UNDEFINED)
if (valuetype != targettype) { if (valuetype != targettype) {
if (valuetype isAssignableTo targettype) { if (valuetype isAssignableTo targettype) {
if(valuetype in IterableDatatypes && targettype==DataType.UWORD) if(valuetype in IterableDatatypes && targettype==DataType.UWORD)
@ -126,7 +126,7 @@ class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalk
sub.parameters.zip(call.args).forEachIndexed { index, pair -> sub.parameters.zip(call.args).forEachIndexed { index, pair ->
val argItype = pair.second.inferType(program) val argItype = pair.second.inferType(program)
if(argItype.isKnown) { if(argItype.isKnown) {
val argtype = argItype.typeOrElse(DataType.UNDEFINED) val argtype = argItype.getOr(DataType.UNDEFINED)
val requiredType = pair.first.type val requiredType = pair.first.type
if (requiredType != argtype) { if (requiredType != argtype) {
if (argtype isAssignableTo requiredType) { if (argtype isAssignableTo requiredType) {
@ -159,7 +159,7 @@ class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalk
func.parameters.zip(call.args).forEachIndexed { index, pair -> func.parameters.zip(call.args).forEachIndexed { index, pair ->
val argItype = pair.second.inferType(program) val argItype = pair.second.inferType(program)
if (argItype.isKnown) { if (argItype.isKnown) {
val argtype = argItype.typeOrElse(DataType.UNDEFINED) val argtype = argItype.getOr(DataType.UNDEFINED)
if (pair.first.possibleDatatypes.all { argtype != it }) { if (pair.first.possibleDatatypes.all { argtype != it }) {
for (possibleType in pair.first.possibleDatatypes) { for (possibleType in pair.first.possibleDatatypes) {
if (argtype isAssignableTo possibleType) { if (argtype isAssignableTo possibleType) {
@ -191,7 +191,7 @@ class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalk
override fun after(memread: DirectMemoryRead, parent: Node): Iterable<IAstModification> { override fun after(memread: DirectMemoryRead, parent: Node): Iterable<IAstModification> {
// make sure the memory address is an uword // make sure the memory address is an uword
val dt = memread.addressExpression.inferType(program) val dt = memread.addressExpression.inferType(program)
if(dt.isKnown && dt.typeOrElse(DataType.UWORD)!=DataType.UWORD) { if(dt.isKnown && dt.getOr(DataType.UWORD)!=DataType.UWORD) {
val typecast = (memread.addressExpression as? NumericLiteralValue)?.cast(DataType.UWORD)?.valueOrZero() val typecast = (memread.addressExpression as? NumericLiteralValue)?.cast(DataType.UWORD)?.valueOrZero()
?: TypecastExpression(memread.addressExpression, DataType.UWORD, true, memread.addressExpression.position) ?: TypecastExpression(memread.addressExpression, DataType.UWORD, true, memread.addressExpression.position)
return listOf(IAstModification.ReplaceNode(memread.addressExpression, typecast, memread)) return listOf(IAstModification.ReplaceNode(memread.addressExpression, typecast, memread))
@ -202,7 +202,7 @@ class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalk
override fun after(memwrite: DirectMemoryWrite, parent: Node): Iterable<IAstModification> { override fun after(memwrite: DirectMemoryWrite, parent: Node): Iterable<IAstModification> {
// make sure the memory address is an uword // make sure the memory address is an uword
val dt = memwrite.addressExpression.inferType(program) val dt = memwrite.addressExpression.inferType(program)
if(dt.isKnown && dt.typeOrElse(DataType.UWORD)!=DataType.UWORD) { if(dt.isKnown && dt.getOr(DataType.UWORD)!=DataType.UWORD) {
val typecast = (memwrite.addressExpression as? NumericLiteralValue)?.cast(DataType.UWORD)?.valueOrZero() val typecast = (memwrite.addressExpression as? NumericLiteralValue)?.cast(DataType.UWORD)?.valueOrZero()
?: TypecastExpression(memwrite.addressExpression, DataType.UWORD, true, memwrite.addressExpression.position) ?: TypecastExpression(memwrite.addressExpression, DataType.UWORD, true, memwrite.addressExpression.position)
return listOf(IAstModification.ReplaceNode(memwrite.addressExpression, typecast, memwrite)) return listOf(IAstModification.ReplaceNode(memwrite.addressExpression, typecast, memwrite))

View File

@ -44,7 +44,7 @@ class VerifyFunctionArgTypes(val program: Program) : IAstVisitor {
val firstUnknownDt = argITypes.indexOfFirst { it.isUnknown } val firstUnknownDt = argITypes.indexOfFirst { it.isUnknown }
if(firstUnknownDt>=0) if(firstUnknownDt>=0)
return "argument ${firstUnknownDt+1} invalid argument type" return "argument ${firstUnknownDt+1} invalid argument type"
val argtypes = argITypes.map { it.typeOrElse(DataType.UNDEFINED) } val argtypes = argITypes.map { it.getOr(DataType.UNDEFINED) }
val target = call.target.targetStatement(program) val target = call.target.targetStatement(program)
if (target is Subroutine) { if (target is Subroutine) {
if(call.args.size != target.parameters.size) if(call.args.size != target.parameters.size)

View File

@ -164,7 +164,7 @@ fun builtinFunctionReturnType(function: String, args: List<Expression>, program:
fun datatypeFromIterableArg(arglist: Expression): DataType { fun datatypeFromIterableArg(arglist: Expression): DataType {
if(arglist is ArrayLiteralValue) { if(arglist is ArrayLiteralValue) {
val dt = arglist.value.map {it.inferType(program).typeOrElse(DataType.UNDEFINED)}.toSet() val dt = arglist.value.map {it.inferType(program).getOr(DataType.UNDEFINED)}.toSet()
if(dt.any { it !in NumericDatatypes }) { if(dt.any { it !in NumericDatatypes }) {
throw FatalAstException("fuction $function only accepts array of numeric values") throw FatalAstException("fuction $function only accepts array of numeric values")
} }
@ -178,7 +178,7 @@ fun builtinFunctionReturnType(function: String, args: List<Expression>, program:
val idt = arglist.inferType(program) val idt = arglist.inferType(program)
if(!idt.isKnown) if(!idt.isKnown)
throw FatalAstException("couldn't determine type of iterable $arglist") throw FatalAstException("couldn't determine type of iterable $arglist")
return when(val dt = idt.typeOrElse(DataType.UNDEFINED)) { return when(val dt = idt.getOr(DataType.UNDEFINED)) {
DataType.STR, in NumericDatatypes -> dt DataType.STR, in NumericDatatypes -> dt
in ArrayDatatypes -> ArrayToElementTypes.getValue(dt) in ArrayDatatypes -> ArrayToElementTypes.getValue(dt)
else -> throw FatalAstException("function '$function' requires one argument which is an iterable") else -> throw FatalAstException("function '$function' requires one argument which is an iterable")
@ -302,11 +302,11 @@ private fun builtinSizeof(args: List<Expression>, position: Position, program: P
return when { return when {
dt.isArray -> { dt.isArray -> {
val length = (target as VarDecl).arraysize!!.constIndex() ?: throw CannotEvaluateException("sizeof", "unknown array size") val length = (target as VarDecl).arraysize!!.constIndex() ?: throw CannotEvaluateException("sizeof", "unknown array size")
val elementDt = ArrayToElementTypes.getValue(dt.typeOrElse(DataType.UNDEFINED)) val elementDt = ArrayToElementTypes.getValue(dt.getOr(DataType.UNDEFINED))
numericLiteral(memsizer.memorySize(elementDt) * length, position) numericLiteral(memsizer.memorySize(elementDt) * length, position)
} }
dt.istype(DataType.STR) -> throw SyntaxError("sizeof str is undefined, did you mean len?", position) dt.istype(DataType.STR) -> throw SyntaxError("sizeof str is undefined, did you mean len?", position)
else -> NumericLiteralValue(DataType.UBYTE, memsizer.memorySize(dt.typeOrElse(DataType.UNDEFINED)), position) else -> NumericLiteralValue(DataType.UBYTE, memsizer.memorySize(dt.getOr(DataType.UNDEFINED)), position)
} }
} else { } else {
throw SyntaxError("sizeof invalid argument type", position) throw SyntaxError("sizeof invalid argument type", position)

View File

@ -1061,7 +1061,7 @@ internal class AsmGen(private val program: Program,
val dt = stmt.iterations!!.inferType(program) val dt = stmt.iterations!!.inferType(program)
if(!dt.isKnown) if(!dt.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
when (dt.typeOrElse(DataType.UNDEFINED)) { when (dt.getOr(DataType.UNDEFINED)) {
in ByteDatatypes -> { in ByteDatatypes -> {
assignExpressionToRegister(stmt.iterations!!, RegisterOrPair.A) assignExpressionToRegister(stmt.iterations!!, RegisterOrPair.A)
repeatByteCountInA(null, repeatLabel, endLabel, stmt) repeatByteCountInA(null, repeatLabel, endLabel, stmt)
@ -1193,7 +1193,7 @@ $repeatLabel lda $counterVar
val conditionDt = stmt.condition.inferType(program) val conditionDt = stmt.condition.inferType(program)
if(!conditionDt.isKnown) if(!conditionDt.isKnown)
throw AssemblyError("unknown condition dt") throw AssemblyError("unknown condition dt")
if(conditionDt.typeOrElse(DataType.BYTE) in ByteDatatypes) if(conditionDt.getOr(DataType.BYTE) in ByteDatatypes)
assignExpressionToRegister(stmt.condition, RegisterOrPair.A) assignExpressionToRegister(stmt.condition, RegisterOrPair.A)
else else
assignExpressionToRegister(stmt.condition, RegisterOrPair.AY) assignExpressionToRegister(stmt.condition, RegisterOrPair.AY)
@ -1208,7 +1208,7 @@ $repeatLabel lda $counterVar
choiceBlocks.add(choiceLabel to choice.statements) choiceBlocks.add(choiceLabel to choice.statements)
for (cv in choice.values!!) { for (cv in choice.values!!) {
val value = (cv as NumericLiteralValue).number.toInt() val value = (cv as NumericLiteralValue).number.toInt()
if(conditionDt.typeOrElse(DataType.BYTE) in ByteDatatypes) { if(conditionDt.getOr(DataType.BYTE) in ByteDatatypes) {
out(" cmp #${value.toHex()} | beq $choiceLabel") out(" cmp #${value.toHex()} | beq $choiceLabel")
} else { } else {
out(""" out("""

View File

@ -177,8 +177,8 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
private fun funcCmp(fcall: IFunctionCall) { private fun funcCmp(fcall: IFunctionCall) {
val arg1 = fcall.args[0] val arg1 = fcall.args[0]
val arg2 = fcall.args[1] val arg2 = fcall.args[1]
val dt1 = arg1.inferType(program).typeOrElse(DataType.UNDEFINED) val dt1 = arg1.inferType(program).getOr(DataType.UNDEFINED)
val dt2 = arg2.inferType(program).typeOrElse(DataType.UNDEFINED) val dt2 = arg2.inferType(program).getOr(DataType.UNDEFINED)
if(dt1 in ByteDatatypes) { if(dt1 in ByteDatatypes) {
if(dt2 in ByteDatatypes) { if(dt2 in ByteDatatypes) {
when (arg2) { when (arg2) {
@ -368,7 +368,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
private fun funcRor2(fcall: IFunctionCall) { private fun funcRor2(fcall: IFunctionCall) {
val what = fcall.args.single() val what = fcall.args.single()
val dt = what.inferType(program) val dt = what.inferType(program)
when (dt.typeOrElse(DataType.UNDEFINED)) { when (dt.getOr(DataType.UNDEFINED)) {
DataType.UBYTE -> { DataType.UBYTE -> {
when (what) { when (what) {
is ArrayIndexedExpression -> { is ArrayIndexedExpression -> {
@ -411,7 +411,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
private fun funcRor(fcall: IFunctionCall) { private fun funcRor(fcall: IFunctionCall) {
val what = fcall.args.single() val what = fcall.args.single()
val dt = what.inferType(program) val dt = what.inferType(program)
when (dt.typeOrElse(DataType.UNDEFINED)) { when (dt.getOr(DataType.UNDEFINED)) {
DataType.UBYTE -> { DataType.UBYTE -> {
when (what) { when (what) {
is ArrayIndexedExpression -> { is ArrayIndexedExpression -> {
@ -469,7 +469,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
private fun funcRol2(fcall: IFunctionCall) { private fun funcRol2(fcall: IFunctionCall) {
val what = fcall.args.single() val what = fcall.args.single()
val dt = what.inferType(program) val dt = what.inferType(program)
when (dt.typeOrElse(DataType.UNDEFINED)) { when (dt.getOr(DataType.UNDEFINED)) {
DataType.UBYTE -> { DataType.UBYTE -> {
when (what) { when (what) {
is ArrayIndexedExpression -> { is ArrayIndexedExpression -> {
@ -512,7 +512,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
private fun funcRol(fcall: IFunctionCall) { private fun funcRol(fcall: IFunctionCall) {
val what = fcall.args.single() val what = fcall.args.single()
val dt = what.inferType(program) val dt = what.inferType(program)
when (dt.typeOrElse(DataType.UNDEFINED)) { when (dt.getOr(DataType.UNDEFINED)) {
DataType.UBYTE -> { DataType.UBYTE -> {
when (what) { when (what) {
is ArrayIndexedExpression -> { is ArrayIndexedExpression -> {
@ -586,7 +586,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
translateArguments(fcall.args, func, scope) translateArguments(fcall.args, func, scope)
val dt = fcall.args.single().inferType(program) val dt = fcall.args.single().inferType(program)
if(resultToStack) { if(resultToStack) {
when (dt.typeOrElse(DataType.UNDEFINED)) { when (dt.getOr(DataType.UNDEFINED)) {
DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_stack") DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_stack")
DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_stack") DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_stack")
DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_stack") DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_stack")
@ -595,7 +595,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
else -> throw AssemblyError("weird type $dt") else -> throw AssemblyError("weird type $dt")
} }
} else { } else {
when (dt.typeOrElse(DataType.UNDEFINED)) { when (dt.getOr(DataType.UNDEFINED)) {
DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_into_A") DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_into_A")
DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A") DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A")
DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A") DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A")
@ -611,14 +611,14 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
outputAddressAndLenghtOfArray(fcall.args[0]) outputAddressAndLenghtOfArray(fcall.args[0])
val dt = fcall.args.single().inferType(program) val dt = fcall.args.single().inferType(program)
if(resultToStack) { if(resultToStack) {
when (dt.typeOrElse(DataType.UNDEFINED)) { when (dt.getOr(DataType.UNDEFINED)) {
DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${function.name}_b_stack") DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${function.name}_b_stack")
DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${function.name}_w_stack") DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${function.name}_w_stack")
DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${function.name}_f_stack") DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${function.name}_f_stack")
else -> throw AssemblyError("weird type $dt") else -> throw AssemblyError("weird type $dt")
} }
} else { } else {
when (dt.typeOrElse(DataType.UNDEFINED)) { when (dt.getOr(DataType.UNDEFINED)) {
DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${function.name}_b_into_A") DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${function.name}_b_into_A")
DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${function.name}_w_into_A") DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${function.name}_w_into_A")
DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${function.name}_f_into_A") DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${function.name}_f_into_A")
@ -632,7 +632,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
outputAddressAndLenghtOfArray(fcall.args[0]) outputAddressAndLenghtOfArray(fcall.args[0])
val dt = fcall.args.single().inferType(program) val dt = fcall.args.single().inferType(program)
if(resultToStack) { if(resultToStack) {
when (dt.typeOrElse(DataType.UNDEFINED)) { when (dt.getOr(DataType.UNDEFINED)) {
DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${function.name}_ub_stack") DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${function.name}_ub_stack")
DataType.ARRAY_B -> asmgen.out(" jsr prog8_lib.func_${function.name}_b_stack") DataType.ARRAY_B -> asmgen.out(" jsr prog8_lib.func_${function.name}_b_stack")
DataType.ARRAY_UW -> asmgen.out(" jsr prog8_lib.func_${function.name}_uw_stack") DataType.ARRAY_UW -> asmgen.out(" jsr prog8_lib.func_${function.name}_uw_stack")
@ -641,7 +641,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
else -> throw AssemblyError("weird type $dt") else -> throw AssemblyError("weird type $dt")
} }
} else { } else {
when (dt.typeOrElse(DataType.UNDEFINED)) { when (dt.getOr(DataType.UNDEFINED)) {
DataType.ARRAY_UB, DataType.STR -> { DataType.ARRAY_UB, DataType.STR -> {
asmgen.out(" jsr prog8_lib.func_${function.name}_ub_into_A") asmgen.out(" jsr prog8_lib.func_${function.name}_ub_into_A")
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, scope, program, asmgen), CpuRegister.A) assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, scope, program, asmgen), CpuRegister.A)
@ -671,7 +671,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
outputAddressAndLenghtOfArray(fcall.args[0]) outputAddressAndLenghtOfArray(fcall.args[0])
val dt = fcall.args.single().inferType(program) val dt = fcall.args.single().inferType(program)
if(resultToStack) { if(resultToStack) {
when (dt.typeOrElse(DataType.UNDEFINED)) { when (dt.getOr(DataType.UNDEFINED)) {
DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_sum_ub_stack") DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_sum_ub_stack")
DataType.ARRAY_B -> asmgen.out(" jsr prog8_lib.func_sum_b_stack") DataType.ARRAY_B -> asmgen.out(" jsr prog8_lib.func_sum_b_stack")
DataType.ARRAY_UW -> asmgen.out(" jsr prog8_lib.func_sum_uw_stack") DataType.ARRAY_UW -> asmgen.out(" jsr prog8_lib.func_sum_uw_stack")
@ -680,7 +680,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
else -> throw AssemblyError("weird type $dt") else -> throw AssemblyError("weird type $dt")
} }
} else { } else {
when (dt.typeOrElse(DataType.UNDEFINED)) { when (dt.getOr(DataType.UNDEFINED)) {
DataType.ARRAY_UB, DataType.STR -> { DataType.ARRAY_UB, DataType.STR -> {
asmgen.out(" jsr prog8_lib.func_sum_ub_into_AY") asmgen.out(" jsr prog8_lib.func_sum_ub_into_AY")
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, scope, program, asmgen), RegisterOrPair.AY) assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, scope, program, asmgen), RegisterOrPair.AY)
@ -825,7 +825,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val elementIDt = first.inferType(program) val elementIDt = first.inferType(program)
if(!elementIDt.isKnown) if(!elementIDt.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
val elementDt = elementIDt.typeOrElse(DataType.UNDEFINED) val elementDt = elementIDt.getOr(DataType.UNDEFINED)
val firstNum = first.indexer.indexExpr as? NumericLiteralValue val firstNum = first.indexer.indexExpr as? NumericLiteralValue
val firstVar = first.indexer.indexExpr as? IdentifierReference val firstVar = first.indexer.indexExpr as? IdentifierReference
@ -858,7 +858,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
} }
} }
when(val datatype: DataType = first.inferType(program).typeOrElse(DataType.UNDEFINED)) { when(val datatype: DataType = first.inferType(program).getOr(DataType.UNDEFINED)) {
in ByteDatatypes, in WordDatatypes -> { in ByteDatatypes, in WordDatatypes -> {
asmgen.assignExpressionToVariable(first, "P8ZP_SCRATCH_W1", datatype, null) asmgen.assignExpressionToVariable(first, "P8ZP_SCRATCH_W1", datatype, null)
asmgen.assignExpressionToVariable(second, "P8ZP_SCRATCH_W2", datatype, null) asmgen.assignExpressionToVariable(second, "P8ZP_SCRATCH_W2", datatype, null)
@ -1128,7 +1128,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
private fun funcAbs(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) { private fun funcAbs(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) {
translateArguments(fcall.args, func, scope) translateArguments(fcall.args, func, scope)
val dt = fcall.args.single().inferType(program).typeOrElse(DataType.UNDEFINED) val dt = fcall.args.single().inferType(program).getOr(DataType.UNDEFINED)
if(resultToStack) { if(resultToStack) {
when (dt) { when (dt) {
in ByteDatatypes -> asmgen.out(" jsr prog8_lib.abs_b_stack") in ByteDatatypes -> asmgen.out(" jsr prog8_lib.abs_b_stack")
@ -1474,7 +1474,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
} }
private fun translateArguments(args: MutableList<Expression>, signature: FSignature, scope: Subroutine?) { private fun translateArguments(args: MutableList<Expression>, signature: FSignature, scope: Subroutine?) {
val callConv = signature.callConvention(args.map { it.inferType(program).typeOrElse(DataType.UNDEFINED) }) val callConv = signature.callConvention(args.map { it.inferType(program).getOr(DataType.UNDEFINED) })
fun getSourceForFloat(value: Expression): AsmAssignSource { fun getSourceForFloat(value: Expression): AsmAssignSource {
return when (value) { return when (value) {

View File

@ -57,7 +57,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
val idt = left.inferType(program) val idt = left.inferType(program)
if(!idt.isKnown) if(!idt.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
val dt = idt.typeOrElse(DataType.UNDEFINED) val dt = idt.getOr(DataType.UNDEFINED)
when (operator) { when (operator) {
"==" -> { "==" -> {
// if the left operand is an expression, and the right is 0, we can just evaluate that expression, // if the left operand is an expression, and the right is 0, we can just evaluate that expression,
@ -1626,7 +1626,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
private fun translateExpression(typecast: TypecastExpression) { private fun translateExpression(typecast: TypecastExpression) {
translateExpression(typecast.expression) translateExpression(typecast.expression)
when(typecast.expression.inferType(program).typeOrElse(DataType.UNDEFINED)) { when(typecast.expression.inferType(program).getOr(DataType.UNDEFINED)) {
DataType.UBYTE -> { DataType.UBYTE -> {
when(typecast.type) { when(typecast.type) {
DataType.UBYTE, DataType.BYTE -> {} DataType.UBYTE, DataType.BYTE -> {}
@ -1757,7 +1757,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
private fun translateExpression(expr: IdentifierReference) { private fun translateExpression(expr: IdentifierReference) {
val varname = asmgen.asmVariableName(expr) val varname = asmgen.asmVariableName(expr)
when(expr.inferType(program).typeOrElse(DataType.UNDEFINED)) { when(expr.inferType(program).getOr(DataType.UNDEFINED)) {
DataType.UBYTE, DataType.BYTE -> { DataType.UBYTE, DataType.BYTE -> {
asmgen.out(" lda $varname | sta P8ESTACK_LO,x | dex") asmgen.out(" lda $varname | sta P8ESTACK_LO,x | dex")
} }
@ -1781,8 +1781,8 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
if(!leftIDt.isKnown || !rightIDt.isKnown) if(!leftIDt.isKnown || !rightIDt.isKnown)
throw AssemblyError("can't infer type of both expression operands") throw AssemblyError("can't infer type of both expression operands")
val leftDt = leftIDt.typeOrElse(DataType.UNDEFINED) val leftDt = leftIDt.getOr(DataType.UNDEFINED)
val rightDt = rightIDt.typeOrElse(DataType.UNDEFINED) val rightDt = rightIDt.getOr(DataType.UNDEFINED)
// see if we can apply some optimized routines // see if we can apply some optimized routines
// TODO avoid using evaluation on stack everywhere // TODO avoid using evaluation on stack everywhere
when(expr.operator) { when(expr.operator) {
@ -2108,7 +2108,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
val itype = expr.inferType(program) val itype = expr.inferType(program)
if(!itype.isKnown) if(!itype.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
val type = itype.typeOrElse(DataType.UNDEFINED) val type = itype.getOr(DataType.UNDEFINED)
when(expr.operator) { when(expr.operator) {
"+" -> {} "+" -> {}
"-" -> { "-" -> {
@ -2146,7 +2146,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
val elementIDt = arrayExpr.inferType(program) val elementIDt = arrayExpr.inferType(program)
if(!elementIDt.isKnown) if(!elementIDt.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
val elementDt = elementIDt.typeOrElse(DataType.UNDEFINED) val elementDt = elementIDt.getOr(DataType.UNDEFINED)
val arrayVarName = asmgen.asmVariableName(arrayExpr.arrayvar) val arrayVarName = asmgen.asmVariableName(arrayExpr.arrayvar)
val constIndexNum = arrayExpr.indexer.constIndex() val constIndexNum = arrayExpr.indexer.constIndex()
if(constIndexNum!=null) { if(constIndexNum!=null) {

View File

@ -22,13 +22,13 @@ internal class ForLoopsAsmGen(private val program: Program, private val asmgen:
is RangeExpr -> { is RangeExpr -> {
val range = (stmt.iterable as RangeExpr).toConstantIntegerRange(asmgen.options.compTarget) val range = (stmt.iterable as RangeExpr).toConstantIntegerRange(asmgen.options.compTarget)
if(range==null) { if(range==null) {
translateForOverNonconstRange(stmt, iterableDt.typeOrElse(DataType.UNDEFINED), stmt.iterable as RangeExpr) translateForOverNonconstRange(stmt, iterableDt.getOr(DataType.UNDEFINED), stmt.iterable as RangeExpr)
} else { } else {
translateForOverConstRange(stmt, iterableDt.typeOrElse(DataType.UNDEFINED), range) translateForOverConstRange(stmt, iterableDt.getOr(DataType.UNDEFINED), range)
} }
} }
is IdentifierReference -> { is IdentifierReference -> {
translateForOverIterableVar(stmt, iterableDt.typeOrElse(DataType.UNDEFINED), stmt.iterable as IdentifierReference) translateForOverIterableVar(stmt, iterableDt.getOr(DataType.UNDEFINED), stmt.iterable as IdentifierReference)
} }
else -> throw AssemblyError("can't iterate over ${stmt.iterable.javaClass} - should have been replaced by a variable") else -> throw AssemblyError("can't iterate over ${stmt.iterable.javaClass} - should have been replaced by a variable")
} }
@ -589,5 +589,5 @@ $loopLabel""")
} }
private fun assignLoopvar(stmt: ForLoop, range: RangeExpr) = private fun assignLoopvar(stmt: ForLoop, range: RangeExpr) =
asmgen.assignExpressionToVariable(range.from, asmgen.asmVariableName(stmt.loopVar), stmt.loopVarDt(program).typeOrElse(DataType.UNDEFINED), stmt.definingSubroutine) asmgen.assignExpressionToVariable(range.from, asmgen.asmVariableName(stmt.loopVar), stmt.loopVarDt(program).getOr(DataType.UNDEFINED), stmt.definingSubroutine)
} }

View File

@ -252,7 +252,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
val valueIDt = value.inferType(program) val valueIDt = value.inferType(program)
if(!valueIDt.isKnown) if(!valueIDt.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
val valueDt = valueIDt.typeOrElse(DataType.UNDEFINED) val valueDt = valueIDt.getOr(DataType.UNDEFINED)
if(!isArgumentTypeCompatible(valueDt, parameter.value.type)) if(!isArgumentTypeCompatible(valueDt, parameter.value.type))
throw AssemblyError("argument type incompatible") throw AssemblyError("argument type incompatible")
@ -265,7 +265,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
val valueIDt = value.inferType(program) val valueIDt = value.inferType(program)
if(!valueIDt.isKnown) if(!valueIDt.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
val valueDt = valueIDt.typeOrElse(DataType.UNDEFINED) val valueDt = valueIDt.getOr(DataType.UNDEFINED)
if(!isArgumentTypeCompatible(valueDt, parameter.value.type)) if(!isArgumentTypeCompatible(valueDt, parameter.value.type))
throw AssemblyError("argument type incompatible") throw AssemblyError("argument type incompatible")

View File

@ -19,7 +19,7 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg
when { when {
targetIdent!=null -> { targetIdent!=null -> {
val what = asmgen.asmVariableName(targetIdent) val what = asmgen.asmVariableName(targetIdent)
when (stmt.target.inferType(program).typeOrElse(DataType.UNDEFINED)) { when (stmt.target.inferType(program).getOr(DataType.UNDEFINED)) {
in ByteDatatypes -> asmgen.out(if (incr) " inc $what" else " dec $what") in ByteDatatypes -> asmgen.out(if (incr) " inc $what" else " dec $what")
in WordDatatypes -> { in WordDatatypes -> {
if(incr) if(incr)
@ -65,7 +65,7 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg
} }
targetArrayIdx!=null -> { targetArrayIdx!=null -> {
val asmArrayvarname = asmgen.asmVariableName(targetArrayIdx.arrayvar) val asmArrayvarname = asmgen.asmVariableName(targetArrayIdx.arrayvar)
val elementDt = targetArrayIdx.inferType(program).typeOrElse(DataType.UNDEFINED) val elementDt = targetArrayIdx.inferType(program).getOr(DataType.UNDEFINED)
val constIndex = targetArrayIdx.indexer.constIndex() val constIndex = targetArrayIdx.indexer.constIndex()
if(constIndex!=null) { if(constIndex!=null) {
val indexValue = constIndex * program.memsizer.memorySize(elementDt) val indexValue = constIndex * program.memsizer.memorySize(elementDt)

View File

@ -59,7 +59,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
val idt = inferType(program) val idt = inferType(program)
if(!idt.isKnown) if(!idt.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
val dt = idt.typeOrElse(DataType.UNDEFINED) val dt = idt.getOr(DataType.UNDEFINED)
when { when {
identifier != null -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, assign.definingSubroutine, variableAsmName = asmgen.asmVariableName(identifier!!), origAstTarget = this) identifier != null -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, assign.definingSubroutine, variableAsmName = asmgen.asmVariableName(identifier!!), origAstTarget = this)
arrayindexed != null -> AsmAssignTarget(TargetStorageKind.ARRAY, program, asmgen, dt, assign.definingSubroutine, array = arrayindexed, origAstTarget = this) arrayindexed != null -> AsmAssignTarget(TargetStorageKind.ARRAY, program, asmgen, dt, assign.definingSubroutine, array = arrayindexed, origAstTarget = this)
@ -132,7 +132,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
is StringLiteralValue -> throw AssemblyError("string literal value should not occur anymore for asm generation") is StringLiteralValue -> throw AssemblyError("string literal value should not occur anymore for asm generation")
is ArrayLiteralValue -> throw AssemblyError("array literal value should not occur anymore for asm generation") is ArrayLiteralValue -> throw AssemblyError("array literal value should not occur anymore for asm generation")
is IdentifierReference -> { is IdentifierReference -> {
val dt = value.inferType(program).typeOrElse(DataType.UNDEFINED) val dt = value.inferType(program).getOr(DataType.UNDEFINED)
val varName=asmgen.asmVariableName(value) val varName=asmgen.asmVariableName(value)
// special case: "cx16.r[0-15]" are 16-bits virtual registers of the commander X16 system // special case: "cx16.r[0-15]" are 16-bits virtual registers of the commander X16 system
if(dt == DataType.UWORD && varName.lowercase().startsWith("cx16.r")) { if(dt == DataType.UWORD && varName.lowercase().startsWith("cx16.r")) {
@ -147,7 +147,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
AsmAssignSource(SourceStorageKind.MEMORY, program, asmgen, DataType.UBYTE, memory = value) AsmAssignSource(SourceStorageKind.MEMORY, program, asmgen, DataType.UBYTE, memory = value)
} }
is ArrayIndexedExpression -> { is ArrayIndexedExpression -> {
val dt = value.inferType(program).typeOrElse(DataType.UNDEFINED) val dt = value.inferType(program).getOr(DataType.UNDEFINED)
AsmAssignSource(SourceStorageKind.ARRAY, program, asmgen, dt, array = value) AsmAssignSource(SourceStorageKind.ARRAY, program, asmgen, dt, array = value)
} }
is FunctionCall -> { is FunctionCall -> {
@ -162,7 +162,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
val returnType = value.inferType(program) val returnType = value.inferType(program)
if(!returnType.isKnown) if(!returnType.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType.typeOrElse(DataType.UNDEFINED), expression = value) AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType.getOr(DataType.UNDEFINED), expression = value)
} }
else -> { else -> {
throw AssemblyError("weird call") throw AssemblyError("weird call")
@ -173,7 +173,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
val dt = value.inferType(program) val dt = value.inferType(program)
if(!dt.isKnown) if(!dt.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, dt.typeOrElse(DataType.UNDEFINED), expression = value) AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, dt.getOr(DataType.UNDEFINED), expression = value)
} }
} }
} }

View File

@ -217,7 +217,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val returntype = builtinFunctionReturnType(sub.name, value.args, program) val returntype = builtinFunctionReturnType(sub.name, value.args, program)
if(!returntype.isKnown) if(!returntype.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
when(returntype.typeOrElse(DataType.UNDEFINED)) { when(returntype.getOr(DataType.UNDEFINED)) {
in ByteDatatypes -> assignRegisterByte(assign.target, CpuRegister.A) // function's byte result is in A in ByteDatatypes -> assignRegisterByte(assign.target, CpuRegister.A) // function's byte result is in A
in WordDatatypes -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) // function's word result is in AY in WordDatatypes -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) // function's word result is in AY
DataType.STR -> { DataType.STR -> {
@ -299,7 +299,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val valueIDt = value.inferType(program) val valueIDt = value.inferType(program)
if(!valueIDt.isKnown) if(!valueIDt.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
val valueDt = valueIDt.typeOrElse(DataType.UNDEFINED) val valueDt = valueIDt.getOr(DataType.UNDEFINED)
if(valueDt==targetDt) if(valueDt==targetDt)
throw AssemblyError("type cast to identical dt should have been removed") throw AssemblyError("type cast to identical dt should have been removed")

View File

@ -25,7 +25,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
val itype = value.inferType(program) val itype = value.inferType(program)
if(!itype.isKnown) if(!itype.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
val type = itype.typeOrElse(DataType.UNDEFINED) val type = itype.getOr(DataType.UNDEFINED)
when (value.operator) { when (value.operator) {
"+" -> {} "+" -> {}
"-" -> inplaceNegate(assign.target, type) "-" -> inplaceNegate(assign.target, type)
@ -280,7 +280,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
val childIDt = value.expression.inferType(program) val childIDt = value.expression.inferType(program)
if(!childIDt.isKnown) if(!childIDt.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
val childDt = childIDt.typeOrElse(DataType.UNDEFINED) val childDt = childIDt.getOr(DataType.UNDEFINED)
if (value.type!=DataType.FLOAT && (value.type.equalsSize(childDt) || value.type.largerThan(childDt))) { if (value.type!=DataType.FLOAT && (value.type.equalsSize(childDt) || value.type.largerThan(childDt))) {
// this typecast is redundant here; the rest of the code knows how to deal with the uncasted value. // this typecast is redundant here; the rest of the code knows how to deal with the uncasted value.
// (works for integer types, not for float.) // (works for integer types, not for float.)
@ -1218,7 +1218,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
val valueiDt = value.inferType(program) val valueiDt = value.inferType(program)
if(!valueiDt.isKnown) if(!valueiDt.isKnown)
throw AssemblyError("unknown dt") throw AssemblyError("unknown dt")
val valueDt = valueiDt.typeOrElse(DataType.UNDEFINED) val valueDt = valueiDt.getOr(DataType.UNDEFINED)
fun multiplyVarByWordInAY() { fun multiplyVarByWordInAY() {
asmgen.out(""" asmgen.out("""

View File

@ -105,7 +105,7 @@ internal class ConstantFoldingOptimizer(private val program: Program) : AstWalke
// optimize various simple cases of ** : // optimize various simple cases of ** :
// optimize away 1 ** x into just 1 and 0 ** x into just 0 // optimize away 1 ** x into just 1 and 0 ** x into just 0
// optimize 2 ** x into (1<<x) if both operands are integer. // optimize 2 ** x into (1<<x) if both operands are integer.
val leftDt = leftconst.inferType(program).typeOrElse(DataType.UNDEFINED) val leftDt = leftconst.inferType(program).getOr(DataType.UNDEFINED)
when (leftconst.number.toDouble()) { when (leftconst.number.toDouble()) {
0.0 -> { 0.0 -> {
val value = NumericLiteralValue(leftDt, 0, expr.position) val value = NumericLiteralValue(leftDt, 0, expr.position)
@ -120,11 +120,11 @@ internal class ConstantFoldingOptimizer(private val program: Program) : AstWalke
val value = NumericLiteralValue(leftDt, 2.0.pow(rightconst.number.toDouble()), expr.position) val value = NumericLiteralValue(leftDt, 2.0.pow(rightconst.number.toDouble()), expr.position)
modifications += IAstModification.ReplaceNode(expr, value, parent) modifications += IAstModification.ReplaceNode(expr, value, parent)
} else { } else {
val rightDt = expr.right.inferType(program).typeOrElse(DataType.UNDEFINED) val rightDt = expr.right.inferType(program).getOr(DataType.UNDEFINED)
if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) {
val targetDt = val targetDt =
when (parent) { when (parent) {
is Assignment -> parent.target.inferType(program).typeOrElse(DataType.UNDEFINED) is Assignment -> parent.target.inferType(program).getOr(DataType.UNDEFINED)
is VarDecl -> parent.datatype is VarDecl -> parent.datatype
else -> leftDt else -> leftDt
} }
@ -186,7 +186,7 @@ internal class ConstantFoldingOptimizer(private val program: Program) : AstWalke
} else { } else {
val arrayDt = array.guessDatatype(program) val arrayDt = array.guessDatatype(program)
if (arrayDt.isKnown) { if (arrayDt.isKnown) {
val newArray = array.cast(arrayDt.typeOrElse(DataType.UNDEFINED)) val newArray = array.cast(arrayDt.getOr(DataType.UNDEFINED))
if (newArray != null && newArray != array) if (newArray != null && newArray != array)
return listOf(IAstModification.ReplaceNode(array, newArray, parent)) return listOf(IAstModification.ReplaceNode(array, newArray, parent))
} }

View File

@ -164,7 +164,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private
errors.err("range expression size doesn't match declared array size", decl.value?.position!!) errors.err("range expression size doesn't match declared array size", decl.value?.position!!)
val constRange = rangeExpr.toConstantIntegerRange(compTarget) val constRange = rangeExpr.toConstantIntegerRange(compTarget)
if(constRange!=null) { if(constRange!=null) {
val eltType = rangeExpr.inferType(program).typeOrElse(DataType.UBYTE) val eltType = rangeExpr.inferType(program).getOr(DataType.UBYTE)
val newValue = if(eltType in ByteDatatypes) { val newValue = if(eltType in ByteDatatypes) {
ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype),
constRange.map { NumericLiteralValue(eltType, it.toShort(), decl.value!!.position) }.toTypedArray(), constRange.map { NumericLiteralValue(eltType, it.toShort(), decl.value!!.position) }.toTypedArray(),

View File

@ -134,8 +134,8 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
)) ))
} }
val leftDt = leftIDt.typeOrElse(DataType.UNDEFINED) val leftDt = leftIDt.getOr(DataType.UNDEFINED)
val rightDt = rightIDt.typeOrElse(DataType.UNDEFINED) val rightDt = rightIDt.getOr(DataType.UNDEFINED)
if (expr.operator == "+" || expr.operator == "-" if (expr.operator == "+" || expr.operator == "-"
&& leftVal == null && rightVal == null && leftVal == null && rightVal == null
@ -309,7 +309,7 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
// useless msb() of byte value that was typecasted to word, replace with 0 // useless msb() of byte value that was typecasted to word, replace with 0
return listOf(IAstModification.ReplaceNode( return listOf(IAstModification.ReplaceNode(
functionCall, functionCall,
NumericLiteralValue(valueDt.typeOrElse(DataType.UBYTE), 0, arg.expression.position), NumericLiteralValue(valueDt.getOr(DataType.UBYTE), 0, arg.expression.position),
parent)) parent))
} }
} else { } else {
@ -318,7 +318,7 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
// useless msb() of byte value, replace with 0 // useless msb() of byte value, replace with 0
return listOf(IAstModification.ReplaceNode( return listOf(IAstModification.ReplaceNode(
functionCall, functionCall,
NumericLiteralValue(argDt.typeOrElse(DataType.UBYTE), 0, arg.position), NumericLiteralValue(argDt.getOr(DataType.UBYTE), 0, arg.position),
parent)) parent))
} }
} }
@ -489,7 +489,7 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
val idt = expr.inferType(program) val idt = expr.inferType(program)
if(!idt.isKnown) if(!idt.isKnown)
throw FatalAstException("unknown dt") throw FatalAstException("unknown dt")
return NumericLiteralValue(idt.typeOrElse(DataType.UNDEFINED), 0, expr.position) return NumericLiteralValue(idt.getOr(DataType.UNDEFINED), 0, expr.position)
} else if (cv in powersOfTwo) { } else if (cv in powersOfTwo) {
expr.operator = "&" expr.operator = "&"
expr.right = NumericLiteralValue.optimalInteger(cv!!.toInt()-1, expr.position) expr.right = NumericLiteralValue.optimalInteger(cv!!.toInt()-1, expr.position)
@ -513,7 +513,7 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
val leftIDt = expr.left.inferType(program) val leftIDt = expr.left.inferType(program)
if (!leftIDt.isKnown) if (!leftIDt.isKnown)
return null return null
val leftDt = leftIDt.typeOrElse(DataType.UNDEFINED) val leftDt = leftIDt.getOr(DataType.UNDEFINED)
when (cv) { when (cv) {
-1.0 -> { -1.0 -> {
// '/' -> -left // '/' -> -left
@ -621,7 +621,7 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
val targetIDt = expr.left.inferType(program) val targetIDt = expr.left.inferType(program)
if(!targetIDt.isKnown) if(!targetIDt.isKnown)
throw FatalAstException("unknown dt") throw FatalAstException("unknown dt")
when (val targetDt = targetIDt.typeOrElse(DataType.UNDEFINED)) { when (val targetDt = targetIDt.getOr(DataType.UNDEFINED)) {
DataType.UBYTE, DataType.BYTE -> { DataType.UBYTE, DataType.BYTE -> {
if (amount >= 8) { if (amount >= 8) {
return NumericLiteralValue(targetDt, 0, expr.position) return NumericLiteralValue(targetDt, 0, expr.position)
@ -656,7 +656,7 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
val idt = expr.left.inferType(program) val idt = expr.left.inferType(program)
if(!idt.isKnown) if(!idt.isKnown)
throw FatalAstException("unknown dt") throw FatalAstException("unknown dt")
when (idt.typeOrElse(DataType.UNDEFINED)) { when (idt.getOr(DataType.UNDEFINED)) {
DataType.UBYTE -> { DataType.UBYTE -> {
if (amount >= 8) { if (amount >= 8) {
return NumericLiteralValue.optimalInteger(0, expr.position) return NumericLiteralValue.optimalInteger(0, expr.position)

View File

@ -373,7 +373,7 @@ internal class StatementOptimizer(private val program: Program,
throw FatalAstException("can't infer type of assignment target") throw FatalAstException("can't infer type of assignment target")
// optimize binary expressions a bit // optimize binary expressions a bit
val targetDt = targetIDt.typeOrElse(DataType.UNDEFINED) val targetDt = targetIDt.getOr(DataType.UNDEFINED)
val bexpr=assignment.value as? BinaryExpression val bexpr=assignment.value as? BinaryExpression
if(bexpr!=null) { if(bexpr!=null) {
val rightCv = bexpr.right.constValue(program)?.number?.toDouble() val rightCv = bexpr.right.constValue(program)?.number?.toDouble()

View File

@ -257,7 +257,7 @@ class TestCompilerOnRanges {
.map { it.iterable } .map { it.iterable }
.filterIsInstance<IdentifierReference>()[0] .filterIsInstance<IdentifierReference>()[0]
assertEquals(DataType.STR, iterable.inferType(program).typeOrElse(DataType.UNDEFINED)) assertEquals(DataType.STR, iterable.inferType(program).getOr(DataType.UNDEFINED))
} }
} }

View File

@ -88,14 +88,14 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid
return when(operator) { return when(operator) {
"+" -> inferred "+" -> inferred
"~", "not" -> { "~", "not" -> {
when(inferred.typeOrElse(DataType.UNDEFINED)) { when(inferred.getOr(DataType.UNDEFINED)) {
in ByteDatatypes -> InferredTypes.knownFor(DataType.UBYTE) in ByteDatatypes -> InferredTypes.knownFor(DataType.UBYTE)
in WordDatatypes -> InferredTypes.knownFor(DataType.UWORD) in WordDatatypes -> InferredTypes.knownFor(DataType.UWORD)
else -> inferred else -> inferred
} }
} }
"-" -> { "-" -> {
when(inferred.typeOrElse(DataType.UNDEFINED)) { when(inferred.getOr(DataType.UNDEFINED)) {
in ByteDatatypes -> InferredTypes.knownFor(DataType.BYTE) in ByteDatatypes -> InferredTypes.knownFor(DataType.BYTE)
in WordDatatypes -> InferredTypes.knownFor(DataType.WORD) in WordDatatypes -> InferredTypes.knownFor(DataType.WORD)
else -> inferred else -> inferred
@ -155,8 +155,8 @@ class BinaryExpression(var left: Expression, var operator: String, var right: Ex
try { try {
InferredTypes.knownFor( InferredTypes.knownFor(
commonDatatype( commonDatatype(
leftDt.typeOrElse(DataType.BYTE), leftDt.getOr(DataType.BYTE),
rightDt.typeOrElse(DataType.BYTE), rightDt.getOr(DataType.BYTE),
null, null null, null
).first ).first
) )
@ -597,7 +597,7 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be
fun memsize(memsizer: IMemSizer): Int { fun memsize(memsizer: IMemSizer): Int {
if(type.isKnown) { if(type.isKnown) {
val eltType = ArrayToElementTypes.getValue(type.typeOrElse(DataType.UNDEFINED)) val eltType = ArrayToElementTypes.getValue(type.getOr(DataType.UNDEFINED))
return memsizer.memorySize(eltType) * value.size return memsizer.memorySize(eltType) * value.size
} }
else throw IllegalArgumentException("array datatype is not yet known") else throw IllegalArgumentException("array datatype is not yet known")
@ -613,14 +613,14 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be
return if(!loopvarDt.isArrayElement) return if(!loopvarDt.isArrayElement)
InferredTypes.InferredType.unknown() InferredTypes.InferredType.unknown()
else else
InferredTypes.InferredType.known(ElementToArrayTypes.getValue(loopvarDt.typeOrElse(DataType.UNDEFINED))) InferredTypes.InferredType.known(ElementToArrayTypes.getValue(loopvarDt.getOr(DataType.UNDEFINED)))
} }
} }
// otherwise, select the "biggegst" datatype based on the elements in the array. // otherwise, select the "biggegst" datatype based on the elements in the array.
val datatypesInArray = value.map { it.inferType(program) } val datatypesInArray = value.map { it.inferType(program) }
require(datatypesInArray.isNotEmpty() && datatypesInArray.all { it.isKnown }) { "can't determine type of empty array" } require(datatypesInArray.isNotEmpty() && datatypesInArray.all { it.isKnown }) { "can't determine type of empty array" }
val dts = datatypesInArray.map { it.typeOrElse(DataType.UNDEFINED) } val dts = datatypesInArray.map { it.getOr(DataType.UNDEFINED) }
return when { return when {
DataType.FLOAT in dts -> InferredTypes.InferredType.known(DataType.ARRAY_F) DataType.FLOAT in dts -> InferredTypes.InferredType.known(DataType.ARRAY_F)
DataType.STR in dts -> InferredTypes.InferredType.known(DataType.ARRAY_UW) DataType.STR in dts -> InferredTypes.InferredType.known(DataType.ARRAY_UW)
@ -705,8 +705,8 @@ class RangeExpr(var from: Expression,
fromDt istype DataType.WORD || toDt istype DataType.WORD -> InferredTypes.knownFor(DataType.ARRAY_W) fromDt istype DataType.WORD || toDt istype DataType.WORD -> InferredTypes.knownFor(DataType.ARRAY_W)
fromDt istype DataType.BYTE || toDt istype DataType.BYTE -> InferredTypes.knownFor(DataType.ARRAY_B) fromDt istype DataType.BYTE || toDt istype DataType.BYTE -> InferredTypes.knownFor(DataType.ARRAY_B)
else -> { else -> {
val fdt = fromDt.typeOrElse(DataType.UNDEFINED) val fdt = fromDt.getOr(DataType.UNDEFINED)
val tdt = toDt.typeOrElse(DataType.UNDEFINED) val tdt = toDt.getOr(DataType.UNDEFINED)
if(fdt largerThan tdt) if(fdt largerThan tdt)
InferredTypes.knownFor(ElementToArrayTypes.getValue(fdt)) InferredTypes.knownFor(ElementToArrayTypes.getValue(fdt))
else else

View File

@ -11,7 +11,9 @@ object InferredTypes {
} }
val isKnown = datatype!=null && datatype!=DataType.UNDEFINED val isKnown = datatype!=null && datatype!=DataType.UNDEFINED
fun typeOrElse(alternative: DataType) = if(isUnknown || isVoid) alternative else datatype!! fun getOr(default: DataType) = if(isUnknown || isVoid) default else datatype!!
fun getOrElse(transform: (InferredType) -> DataType): DataType =
if(isUnknown || isVoid) transform(this) else datatype!!
infix fun istype(type: DataType): Boolean = if(isUnknown || isVoid) false else this.datatype==type infix fun istype(type: DataType): Boolean = if(isUnknown || isVoid) false else this.datatype==type
companion object { companion object {

View File

@ -181,7 +181,7 @@ open class VarDecl(val type: VarDeclType,
if(!array.type.isKnown) if(!array.type.isKnown)
throw FatalAstException("unknown dt") throw FatalAstException("unknown dt")
else else
array.type.typeOrElse(DataType.UNDEFINED) array.type.getOr(DataType.UNDEFINED)
val declaredType = ArrayToElementTypes.getValue(arrayDt) val declaredType = ArrayToElementTypes.getValue(arrayDt)
val arraysize = ArrayIndex.forArray(array) val arraysize = ArrayIndex.forArray(array)
return VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, array, return VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, array,

View File

@ -8,7 +8,6 @@ For next release
- can Position.file be a Path- making the source variable for nodes unnecessary? - can Position.file be a Path- making the source variable for nodes unnecessary?
- refactor code to improve testability and other things, see [CompilerDevelopment](CompilerDevelopment.md)
- simplify cx16.joystick_get2() once this cx16 rom issue is resolved: https://github.com/commanderx16/x16-rom/issues/203 - simplify cx16.joystick_get2() once this cx16 rom issue is resolved: https://github.com/commanderx16/x16-rom/issues/203
(I hope this will still be included into the final v39 roms release for the cx16) (I hope this will still be included into the final v39 roms release for the cx16)