diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 1d06e725f..8c0322d50 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -86,7 +86,7 @@ internal class AstChecker(private val program: Program, } override fun visit(ifStatement: IfStatement) { - if(ifStatement.condition.inferType(program).typeOrElse(DataType.UNDEFINED) !in IntegerDatatypes) + if(!ifStatement.condition.inferType(program).isInteger()) errors.err("condition value should be an integer type", ifStatement.condition.position) super.visit(ifStatement) } @@ -386,13 +386,13 @@ internal class AstChecker(private val program: Program, } override fun visit(untilLoop: UntilLoop) { - if(untilLoop.condition.inferType(program).typeOrElse(DataType.UNDEFINED) !in IntegerDatatypes) + if(!untilLoop.condition.inferType(program).isInteger()) errors.err("condition value should be an integer type", untilLoop.condition.position) super.visit(untilLoop) } override fun visit(whileLoop: WhileLoop) { - if(whileLoop.condition.inferType(program).typeOrElse(DataType.UNDEFINED) !in IntegerDatatypes) + if(!whileLoop.condition.inferType(program).isInteger()) errors.err("condition value should be an integer type", whileLoop.condition.position) super.visit(whileLoop) } @@ -421,7 +421,7 @@ internal class AstChecker(private val program: Program, val targetDt = assignment.target.inferType(program) val valueDt = assignment.value.inferType(program) if(valueDt.isKnown && !(valueDt isAssignableTo targetDt)) { - if(targetDt.typeOrElse(DataType.UNDEFINED) in IterableDatatypes) + if(targetDt.isIterable()) errors.err("cannot assign value to string or array", assignment.value.position) else if(!(valueDt.istype(DataType.STR) && targetDt.istype(DataType.UWORD))) errors.err("type of value doesn't match target", assignment.value.position) @@ -998,7 +998,7 @@ internal class AstChecker(private val program: Program, errors.err("swap requires 2 variables, not constant value(s)", position) else if(args[0] isSameAs args[1]) errors.err("swap should have 2 different args", position) - else if(dt1.typeOrElse(DataType.UNDEFINED) !in NumericDatatypes) + else if(!dt1.isNumeric()) errors.err("swap requires args of numerical type", position) } else if(target.name=="all" || target.name=="any") { @@ -1103,8 +1103,7 @@ internal class AstChecker(private val program: Program, } override fun visit(whenStatement: WhenStatement) { - val conditionType = whenStatement.condition.inferType(program).typeOrElse(DataType.UNDEFINED) - if(conditionType !in IntegerDatatypes) + if(!whenStatement.condition.inferType(program).isInteger()) errors.err("when condition must be an integer value", whenStatement.position) val tally = mutableSetOf() for((choices, choiceNode) in whenStatement.choiceValues(program)) { diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index b88acd189..62d60dfb6 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -208,7 +208,7 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport val valueType = assignment.value.inferType(program) val targetType = assignment.target.inferType(program) - if(targetType.typeOrElse(DataType.UNDEFINED) in ArrayDatatypes && valueType.typeOrElse(DataType.UNDEFINED) in ArrayDatatypes ) { + if(targetType.isArray() && valueType.isArray() ) { if (assignment.value is ArrayLiteralValue) { errors.err("cannot assign array literal here, use separate assignment per element", assignment.position) } else { diff --git a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt index 9043b38b3..080949462 100644 --- a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt +++ b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt @@ -25,7 +25,7 @@ class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalk if(!valueDt.istype(decl.datatype)) { // don't add a typecast on an array initializer value - if(valueDt.typeOrElse(DataType.UNDEFINED) in IntegerDatatypes && decl.datatype in ArrayDatatypes) + if(valueDt.isInteger() && decl.datatype in ArrayDatatypes) return noModifications // don't add a typecast if the initializer value is inherently not assignable diff --git a/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt b/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt index 5e440b1a6..e32011398 100644 --- a/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt @@ -180,7 +180,7 @@ fun builtinFunctionReturnType(function: String, args: List, program: throw FatalAstException("couldn't determine type of iterable $arglist") return when(val dt = idt.typeOrElse(DataType.UNDEFINED)) { DataType.STR, in NumericDatatypes -> dt - in ArrayDatatypes -> ArrayElementTypes.getValue(dt) + in ArrayDatatypes -> ArrayToElementTypes.getValue(dt) else -> throw FatalAstException("function '$function' requires one argument which is an iterable") } } @@ -195,7 +195,7 @@ fun builtinFunctionReturnType(function: String, args: List, program: return when (function) { "abs" -> { val dt = args.single().inferType(program) - return if(dt.typeOrElse(DataType.UNDEFINED) in NumericDatatypes) + return if(dt.isNumeric()) dt else InferredTypes.InferredType.unknown() @@ -204,7 +204,7 @@ fun builtinFunctionReturnType(function: String, args: List, program: when(val dt = datatypeFromIterableArg(args.single())) { DataType.STR -> InferredTypes.knownFor(DataType.UBYTE) in NumericDatatypes -> InferredTypes.knownFor(dt) - in ArrayDatatypes -> InferredTypes.knownFor(ArrayElementTypes.getValue(dt)) + in ArrayDatatypes -> InferredTypes.knownFor(ArrayToElementTypes.getValue(dt)) else -> InferredTypes.unknown() } } @@ -300,9 +300,9 @@ private fun builtinSizeof(args: List, position: Position, program: P ?: throw CannotEvaluateException("sizeof", "no target") return when { - dt.typeOrElse(DataType.UNDEFINED) in ArrayDatatypes -> { + dt.isArray() -> { val length = (target as VarDecl).arraysize!!.constIndex() ?: throw CannotEvaluateException("sizeof", "unknown array size") - val elementDt = ArrayElementTypes.getValue(dt.typeOrElse(DataType.UNDEFINED)) + val elementDt = ArrayToElementTypes.getValue(dt.typeOrElse(DataType.UNDEFINED)) numericLiteral(memsizer.memorySize(elementDt) * length, position) } dt.istype(DataType.STR) -> throw SyntaxError("sizeof str is undefined, did you mean len?", position) diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt index e7b6bfa83..bd17c271a 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt @@ -1321,7 +1321,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val private fun funcMsb(fcall: IFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { val arg = fcall.args.single() - if (arg.inferType(program).typeOrElse(DataType.UNDEFINED) !in WordDatatypes) + if (!arg.inferType(program).isWords()) throw AssemblyError("msb required word argument") if (arg is NumericLiteralValue) throw AssemblyError("msb(const) should have been const-folded away") @@ -1365,7 +1365,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val private fun funcLsb(fcall: IFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) { val arg = fcall.args.single() - if (arg.inferType(program).typeOrElse(DataType.UNDEFINED) !in WordDatatypes) + if (!arg.inferType(program).isWords()) throw AssemblyError("lsb required word argument") if (arg is NumericLiteralValue) throw AssemblyError("lsb(const) should have been const-folded away") diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/ForLoopsAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/ForLoopsAsmGen.kt index fefe491e8..99727fb27 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/ForLoopsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/ForLoopsAsmGen.kt @@ -1,7 +1,7 @@ package prog8.compiler.target.cpu6502.codegen import prog8.ast.Program -import prog8.ast.base.ArrayElementTypes +import prog8.ast.base.ArrayToElementTypes import prog8.ast.base.DataType import prog8.ast.base.RegisterOrPair import prog8.ast.expressions.IdentifierReference @@ -56,8 +56,8 @@ internal class ForLoopsAsmGen(private val program: Program, private val asmgen: val incdec = if(stepsize==1) "inc" else "dec" // loop over byte range via loopvar val varname = asmgen.asmVariableName(stmt.loopVar) - asmgen.assignExpressionToVariable(range.from, varname, ArrayElementTypes.getValue(iterableDt), null) - asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayElementTypes.getValue(iterableDt), null) + asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt), null) + asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayToElementTypes.getValue(iterableDt), null) asmgen.out(loopLabel) asmgen.translate(stmt.body) asmgen.out(""" @@ -74,8 +74,8 @@ $modifiedLabel cmp #0 ; modified // loop over byte range via loopvar val varname = asmgen.asmVariableName(stmt.loopVar) - asmgen.assignExpressionToVariable(range.from, varname, ArrayElementTypes.getValue(iterableDt), null) - asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayElementTypes.getValue(iterableDt), null) + asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt), null) + asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayToElementTypes.getValue(iterableDt), null) asmgen.out(loopLabel) asmgen.translate(stmt.body) if(stepsize>0) { diff --git a/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt b/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt index d41bc8728..103abd50e 100644 --- a/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt +++ b/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt @@ -172,7 +172,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private else -> {} } // create the array itself, filled with the fillvalue. - val array = Array(size) {fillvalue}.map { NumericLiteralValue(ArrayElementTypes.getValue(decl.datatype), it, numericLv.position) }.toTypedArray() + val array = Array(size) {fillvalue}.map { NumericLiteralValue(ArrayToElementTypes.getValue(decl.datatype), it, numericLv.position) }.toTypedArray() val refValue = ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), array, position = numericLv.position) return listOf(IAstModification.ReplaceNode(decl.value!!, refValue, decl)) } diff --git a/compiler/src/prog8/optimizer/ExpressionSimplifier.kt b/compiler/src/prog8/optimizer/ExpressionSimplifier.kt index 39d0d15e8..60fc8e140 100644 --- a/compiler/src/prog8/optimizer/ExpressionSimplifier.kt +++ b/compiler/src/prog8/optimizer/ExpressionSimplifier.kt @@ -590,14 +590,14 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker() return expr2.left } in powersOfTwo -> { - if (leftValue.inferType(program).typeOrElse(DataType.UNDEFINED) in IntegerDatatypes) { + if (leftValue.inferType(program).isInteger()) { // times a power of two => shift left val numshifts = log2(cv).toInt() return BinaryExpression(expr2.left, "<<", NumericLiteralValue.optimalInteger(numshifts, expr.position), expr.position) } } in negativePowersOfTwo -> { - if (leftValue.inferType(program).typeOrElse(DataType.UNDEFINED) in IntegerDatatypes) { + if (leftValue.inferType(program).isInteger()) { // times a negative power of two => negate, then shift left val numshifts = log2(-cv).toInt() return BinaryExpression(PrefixExpression("-", expr2.left, expr.position), "<<", NumericLiteralValue.optimalInteger(numshifts, expr.position), expr.position) diff --git a/compilerAst/src/prog8/ast/base/Base.kt b/compilerAst/src/prog8/ast/base/Base.kt index 6ff5533e3..d78413bd4 100644 --- a/compilerAst/src/prog8/ast/base/Base.kt +++ b/compilerAst/src/prog8/ast/base/Base.kt @@ -141,7 +141,7 @@ val IterableDatatypes = setOf( ) val PassByValueDatatypes = NumericDatatypes val PassByReferenceDatatypes = IterableDatatypes -val ArrayElementTypes = mapOf( +val ArrayToElementTypes = mapOf( DataType.STR to DataType.UBYTE, DataType.ARRAY_B to DataType.BYTE, DataType.ARRAY_UB to DataType.UBYTE, @@ -149,7 +149,7 @@ val ArrayElementTypes = mapOf( DataType.ARRAY_UW to DataType.UWORD, DataType.ARRAY_F to DataType.FLOAT ) -val ElementArrayTypes = mapOf( +val ElementToArrayTypes = mapOf( DataType.BYTE to DataType.ARRAY_B, DataType.UBYTE to DataType.ARRAY_UB, DataType.WORD to DataType.ARRAY_W, diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 9b9b5ebd8..75f6114c3 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -268,7 +268,7 @@ class ArrayIndexedExpression(var arrayvar: IdentifierReference, if (target is VarDecl) { return when (target.datatype) { DataType.STR -> InferredTypes.knownFor(DataType.UBYTE) - in ArrayDatatypes -> InferredTypes.knownFor(ArrayElementTypes.getValue(target.datatype)) + in ArrayDatatypes -> InferredTypes.knownFor(ArrayToElementTypes.getValue(target.datatype)) else -> InferredTypes.unknown() } } @@ -567,7 +567,7 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be fun memsize(memsizer: IMemSizer): Int { if(type.isKnown) { - val eltType = ArrayElementTypes.getValue(type.typeOrElse(DataType.UNDEFINED)) + val eltType = ArrayToElementTypes.getValue(type.typeOrElse(DataType.UNDEFINED)) return memsizer.memorySize(eltType) * value.size } else throw IllegalArgumentException("array datatype is not yet known") @@ -580,10 +580,10 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be if(forloop != null) { val loopvarDt = forloop.loopVarDt(program) if(loopvarDt.isKnown) { - return if(loopvarDt.typeOrElse(DataType.UNDEFINED) !in ElementArrayTypes) + return if(!loopvarDt.isArrayElement()) InferredTypes.InferredType.unknown() else - InferredTypes.InferredType.known(ElementArrayTypes.getValue(loopvarDt.typeOrElse(DataType.UNDEFINED))) + InferredTypes.InferredType.known(ElementToArrayTypes.getValue(loopvarDt.typeOrElse(DataType.UNDEFINED))) } } @@ -611,7 +611,7 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be if(type.istype(targettype)) return this if(targettype in ArrayDatatypes) { - val elementType = ArrayElementTypes.getValue(targettype) + val elementType = ArrayToElementTypes.getValue(targettype) val castArray = value.map{ val num = it as? NumericLiteralValue if(num==null) { @@ -679,9 +679,9 @@ class RangeExpr(var from: Expression, val fdt = fromDt.typeOrElse(DataType.UNDEFINED) val tdt = toDt.typeOrElse(DataType.UNDEFINED) if(fdt largerThan tdt) - InferredTypes.knownFor(ElementArrayTypes.getValue(fdt)) + InferredTypes.knownFor(ElementToArrayTypes.getValue(fdt)) else - InferredTypes.knownFor(ElementArrayTypes.getValue(tdt)) + InferredTypes.knownFor(ElementToArrayTypes.getValue(tdt)) } } } diff --git a/compilerAst/src/prog8/ast/expressions/InferredTypes.kt b/compilerAst/src/prog8/ast/expressions/InferredTypes.kt index c98361892..c55c5ef54 100644 --- a/compilerAst/src/prog8/ast/expressions/InferredTypes.kt +++ b/compilerAst/src/prog8/ast/expressions/InferredTypes.kt @@ -1,6 +1,6 @@ package prog8.ast.expressions -import prog8.ast.base.DataType +import prog8.ast.base.* import java.util.* @@ -42,6 +42,17 @@ object InferredTypes { isKnown && (datatype!! isAssignableTo targetDt) infix fun isNotAssignableTo(targetDt: InferredType): Boolean = !this.isAssignableTo(targetDt) infix fun isNotAssignableTo(targetDt: DataType): Boolean = !this.isAssignableTo(targetDt) + + fun isBytes() = datatype in ByteDatatypes + fun isWords() = datatype in WordDatatypes + fun isInteger() = datatype in IntegerDatatypes + fun isNumeric() = datatype in NumericDatatypes + fun isArray() = datatype in ArrayDatatypes + fun isString() = datatype in StringlyDatatypes + fun isIterable() = datatype in IterableDatatypes + fun isPassByReference() = datatype in PassByReferenceDatatypes + fun isPassByValue() = datatype in PassByValueDatatypes + fun isArrayElement() = datatype in ElementToArrayTypes } private val unknownInstance = InferredType.unknown() diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 48a2a0327..b09cd3d02 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -180,7 +180,7 @@ open class VarDecl(val type: VarDeclType, throw FatalAstException("unknown dt") else array.type.typeOrElse(DataType.UNDEFINED) - val declaredType = ArrayElementTypes.getValue(arrayDt) + val declaredType = ArrayToElementTypes.getValue(arrayDt) val arraysize = ArrayIndex.forArray(array) return VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, array, isArray = true, autogeneratedDontRemove = true, position = array.position) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 78cab9732..d383dbc04 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -11,7 +11,7 @@ TODO Low prio ^^^^^^^^ -- see if we can improve the ".typeOrElse(DataType.UNDEFINED)" to not depend on the DEFINED anymore or at least less +- see if we can remove more ".typeOrElse(DataType.UNDEFINED)" - optimize several inner loops in gfx2 even further? - add modes 2 and 3 to gfx2 (lowres 4 color and 16 color)? - add a flood fill routine to gfx2?