refactor some type checks

This commit is contained in:
Irmen de Jong 2021-04-30 00:09:15 +02:00
parent 29c8e8b740
commit d906fcea0e
13 changed files with 46 additions and 36 deletions

View File

@ -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<Int>()
for((choices, choiceNode) in whenStatement.choiceValues(program)) {

View File

@ -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 {

View File

@ -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

View File

@ -180,7 +180,7 @@ fun builtinFunctionReturnType(function: String, args: List<Expression>, 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<Expression>, 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<Expression>, 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<Expression>, 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)

View File

@ -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")

View File

@ -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) {

View File

@ -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<Expression>()
val array = Array(size) {fillvalue}.map { NumericLiteralValue(ArrayToElementTypes.getValue(decl.datatype), it, numericLv.position) }.toTypedArray<Expression>()
val refValue = ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), array, position = numericLv.position)
return listOf(IAstModification.ReplaceNode(decl.value!!, refValue, decl))
}

View File

@ -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)

View File

@ -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,

View File

@ -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))
}
}
}

View File

@ -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()

View File

@ -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)

View File

@ -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?