better handling of inferred type errors

This commit is contained in:
Irmen de Jong 2020-10-30 16:26:19 +01:00
parent 3ab641aa21
commit 87862f772a
16 changed files with 103 additions and 42 deletions

View File

@ -35,8 +35,9 @@ enum class DataType {
else -> false else -> false
} }
infix fun isAssignableTo(targetTypes: Set<DataType>) = targetTypes.any { this isAssignableTo it } infix fun isAssignableTo(targetTypes: Set<DataType>) = targetTypes.any { this isAssignableTo it }
infix fun isNotAssignableTo(targetType: DataType) = !this.isAssignableTo(targetType)
infix fun isNotAssignableTo(targetTypes: Set<DataType>) = !this.isAssignableTo(targetTypes)
infix fun largerThan(other: DataType) = infix fun largerThan(other: DataType) =
when { when {

View File

@ -36,9 +36,12 @@ object InferredTypes {
override fun hashCode(): Int = Objects.hash(isVoid, datatype) override fun hashCode(): Int = Objects.hash(isVoid, datatype)
infix fun isAssignableTo(targetDt: InferredType): Boolean { infix fun isAssignableTo(targetDt: InferredType): Boolean =
return isKnown && targetDt.isKnown && (datatype!! isAssignableTo targetDt.datatype!!) isKnown && targetDt.isKnown && (datatype!! isAssignableTo targetDt.datatype!!)
} infix fun isAssignableTo(targetDt: DataType): Boolean =
isKnown && (datatype!! isAssignableTo targetDt)
infix fun isNotAssignableTo(targetDt: InferredType): Boolean = !this.isAssignableTo(targetDt)
infix fun isNotAssignableTo(targetDt: DataType): Boolean = !this.isAssignableTo(targetDt)
} }
private val unknownInstance = InferredType.unknown() private val unknownInstance = InferredType.unknown()

View File

@ -348,7 +348,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.size <= 1 && !(stmt.returntypes.single() isAssignableTo idt.typeOrElse(DataType.BYTE))) { if(stmt.returntypes.size <= 1 && stmt.returntypes.single() isNotAssignableTo idt.typeOrElse(DataType.BYTE)) {
errors.err("return type mismatch", assignment.value.position) errors.err("return type mismatch", assignment.value.position)
} }
} }
@ -593,8 +593,8 @@ internal class AstChecker(private val program: Program,
if(declValue!=null && decl.type==VarDeclType.VAR) { if(declValue!=null && decl.type==VarDeclType.VAR) {
if(decl.datatype==DataType.STRUCT) { if(decl.datatype==DataType.STRUCT) {
val valueIdt = declValue.inferType(program) val valueIdt = declValue.inferType(program)
if(valueIdt.isUnknown) if(!valueIdt.isKnown)
throw AstException("invalid value type") throw AstException("unknown dt")
val valueDt = valueIdt.typeOrElse(DataType.STRUCT) val valueDt = valueIdt.typeOrElse(DataType.STRUCT)
if(valueDt !in ArrayDatatypes) if(valueDt !in ArrayDatatypes)
err("initialisation of struct should be with array value", declValue.position) err("initialisation of struct should be with array value", declValue.position)
@ -769,7 +769,11 @@ internal class AstChecker(private val program: Program,
} }
override fun visit(expr: PrefixExpression) { override fun visit(expr: PrefixExpression) {
val dt = expr.inferType(program).typeOrElse(DataType.STRUCT) val idt = expr.inferType(program)
if(!idt.isKnown)
return // any error should be reported elsewhere
val dt = idt.typeOrElse(DataType.STRUCT)
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)
@ -1218,7 +1222,7 @@ internal class AstChecker(private val program: Program,
for(elt in value.value.zip(struct.statements)) { for(elt in value.value.zip(struct.statements)) {
val vardecl = elt.second as VarDecl val vardecl = elt.second as VarDecl
val valuetype = elt.first.inferType(program) val valuetype = elt.first.inferType(program)
if (!valuetype.isKnown || !(valuetype.typeOrElse(DataType.STRUCT) isAssignableTo vardecl.datatype)) { if (!valuetype.isKnown || valuetype isNotAssignableTo vardecl.datatype) {
errors.err("invalid struct member init value type $valuetype, expected ${vardecl.datatype}", elt.first.position) errors.err("invalid struct member init value type $valuetype, expected ${vardecl.datatype}", elt.first.position)
return false return false
} }

View File

@ -4,6 +4,7 @@ import prog8.ast.IFunctionCall
import prog8.ast.INameScope import prog8.ast.INameScope
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.DataType import prog8.ast.base.DataType
import prog8.ast.base.FatalAstException
import prog8.ast.expressions.Expression import prog8.ast.expressions.Expression
import prog8.ast.expressions.FunctionCall import prog8.ast.expressions.FunctionCall
import prog8.ast.statements.* import prog8.ast.statements.*
@ -39,7 +40,10 @@ class VerifyFunctionArgTypes(val program: Program) : IAstVisitor {
} }
fun checkTypes(call: IFunctionCall, scope: INameScope, program: Program): String? { fun checkTypes(call: IFunctionCall, scope: INameScope, program: Program): String? {
val argtypes = call.args.map { it.inferType(program).typeOrElse(DataType.STRUCT) } val argITypes = call.args.map { it.inferType(program) }
if(argITypes.any { !it.isKnown })
throw FatalAstException("unknown dt")
val argtypes = argITypes.map { it.typeOrElse(DataType.STRUCT) }
val target = call.target.targetStatement(scope) val target = call.target.targetStatement(scope)
if (target is Subroutine) { if (target is Subroutine) {
if(call.args.size != target.parameters.size) if(call.args.size != target.parameters.size)

View File

@ -187,7 +187,12 @@ open class VarDecl(val type: VarDeclType,
fun createAuto(array: ArrayLiteralValue): VarDecl { fun createAuto(array: ArrayLiteralValue): VarDecl {
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}" val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
val declaredType = ArrayElementTypes.getValue(array.type.typeOrElse(DataType.STRUCT)) val arrayDt =
if(!array.type.isKnown)
throw FatalAstException("unknown dt")
else
array.type.typeOrElse(DataType.STRUCT)
val declaredType = ArrayElementTypes.getValue(arrayDt)
val arraysize = ArrayIndex.forArray(array) val arraysize = ArrayIndex.forArray(array)
return VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, null, array, return VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, null, array,
isArray = true, autogeneratedDontRemove = true, position = array.position) isArray = true, autogeneratedDontRemove = true, position = array.position)

View File

@ -896,8 +896,10 @@ internal class AsmGen(private val program: Program,
} }
else -> { else -> {
translateExpression(stmt.iterations!!) translateExpression(stmt.iterations!!)
val dt = stmt.iterations!!.inferType(program).typeOrElse(DataType.STRUCT) val dt = stmt.iterations!!.inferType(program)
when (dt) { if(!dt.isKnown)
throw AssemblyError("unknown dt")
when (dt.typeOrElse(DataType.STRUCT)) {
in ByteDatatypes -> { in ByteDatatypes -> {
out(" inx | lda P8ESTACK_LO,x") out(" inx | lda P8ESTACK_LO,x")
repeatByteCountInA(null, repeatLabel, endLabel, stmt.body) repeatByteCountInA(null, repeatLabel, endLabel, stmt.body)

View File

@ -578,7 +578,10 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
if(first is ArrayIndexedExpression && second is ArrayIndexedExpression) { if(first is ArrayIndexedExpression && second is ArrayIndexedExpression) {
val arrayVarName1 = asmgen.asmVariableName(first.arrayvar) val arrayVarName1 = asmgen.asmVariableName(first.arrayvar)
val arrayVarName2 = asmgen.asmVariableName(second.arrayvar) val arrayVarName2 = asmgen.asmVariableName(second.arrayvar)
val elementDt = first.inferType(program).typeOrElse(DataType.STRUCT) val elementIDt = first.inferType(program)
if(!elementIDt.isKnown)
throw AssemblyError("unknown dt")
val elementDt = elementIDt.typeOrElse(DataType.STRUCT)
val firstNum = first.indexer.indexNum val firstNum = first.indexer.indexNum
val firstVar = first.indexer.indexVar val firstVar = first.indexer.indexVar
@ -612,7 +615,10 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
asmgen.translateExpression(first) asmgen.translateExpression(first)
asmgen.translateExpression(second) asmgen.translateExpression(second)
val datatype = first.inferType(program).typeOrElse(DataType.STRUCT) val idatatype = first.inferType(program)
if(!idatatype.isKnown)
throw AssemblyError("unknown dt")
val datatype = idatatype.typeOrElse(DataType.STRUCT)
val assignFirst = AsmAssignment( val assignFirst = AsmAssignment(
AsmAssignSource(SourceStorageKind.STACK, program, asmgen, datatype), AsmAssignSource(SourceStorageKind.STACK, program, asmgen, datatype),
targetFromExpr(first, datatype), targetFromExpr(first, datatype),

View File

@ -53,7 +53,10 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
} }
} }
val dt = left.inferType(program).typeOrElse(DataType.STRUCT) val idt = left.inferType(program)
if(!idt.isKnown)
throw AssemblyError("unknown dt")
val dt = idt.typeOrElse(DataType.STRUCT)
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.
@ -1512,7 +1515,10 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
private fun translateExpression(expr: PrefixExpression) { private fun translateExpression(expr: PrefixExpression) {
translateExpression(expr.expression) translateExpression(expr.expression)
val type = expr.inferType(program).typeOrElse(DataType.STRUCT) val itype = expr.inferType(program)
if(!itype.isKnown)
throw AssemblyError("unknown dt")
val type = itype.typeOrElse(DataType.STRUCT)
when(expr.operator) { when(expr.operator) {
"+" -> {} "+" -> {}
"-" -> { "-" -> {
@ -1547,7 +1553,10 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
} }
private fun translateExpression(arrayExpr: ArrayIndexedExpression) { private fun translateExpression(arrayExpr: ArrayIndexedExpression) {
val elementDt = arrayExpr.inferType(program).typeOrElse(DataType.STRUCT) val elementIDt = arrayExpr.inferType(program)
if(!elementIDt.isKnown)
throw AssemblyError("unknown dt")
val elementDt = elementIDt.typeOrElse(DataType.STRUCT)
val arrayVarName = asmgen.asmVariableName(arrayExpr.arrayvar) val arrayVarName = asmgen.asmVariableName(arrayExpr.arrayvar)
if(arrayExpr.indexer.indexNum!=null) { if(arrayExpr.indexer.indexNum!=null) {
val indexValue = arrayExpr.indexer.constIndex()!! * elementDt.memorySize() val indexValue = arrayExpr.indexer.constIndex()!! * elementDt.memorySize()

View File

@ -18,7 +18,7 @@ internal class ForLoopsAsmGen(private val program: Program, private val asmgen:
internal fun translate(stmt: ForLoop) { internal fun translate(stmt: ForLoop) {
val iterableDt = stmt.iterable.inferType(program) val iterableDt = stmt.iterable.inferType(program)
if(!iterableDt.isKnown) if(!iterableDt.isKnown)
throw AssemblyError("can't determine iterable dt") throw AssemblyError("unknown dt")
when(stmt.iterable) { when(stmt.iterable) {
is RangeExpr -> { is RangeExpr -> {
val range = (stmt.iterable as RangeExpr).toConstantIntegerRange() val range = (stmt.iterable as RangeExpr).toConstantIntegerRange()

View File

@ -159,7 +159,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
// pass parameter via a regular variable (not via registers) // pass parameter via a regular variable (not via registers)
val valueIDt = value.inferType(program) val valueIDt = value.inferType(program)
if(!valueIDt.isKnown) if(!valueIDt.isKnown)
throw AssemblyError("arg type unknown") throw AssemblyError("unknown dt")
val valueDt = valueIDt.typeOrElse(DataType.STRUCT) val valueDt = valueIDt.typeOrElse(DataType.STRUCT)
if(!isArgumentTypeCompatible(valueDt, parameter.value.type)) if(!isArgumentTypeCompatible(valueDt, parameter.value.type))
throw AssemblyError("argument type incompatible") throw AssemblyError("argument type incompatible")
@ -175,7 +175,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
// pass argument via a register parameter // pass argument via a register parameter
val valueIDt = value.inferType(program) val valueIDt = value.inferType(program)
if(!valueIDt.isKnown) if(!valueIDt.isKnown)
throw AssemblyError("arg type unknown") throw AssemblyError("unknown dt")
val valueDt = valueIDt.typeOrElse(DataType.STRUCT) val valueDt = valueIDt.typeOrElse(DataType.STRUCT)
if(!isArgumentTypeCompatible(valueDt, parameter.value.type)) if(!isArgumentTypeCompatible(valueDt, parameter.value.type))
throw AssemblyError("argument type incompatible") throw AssemblyError("argument type incompatible")

View File

@ -55,7 +55,10 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
companion object { companion object {
fun fromAstAssignment(assign: Assignment, program: Program, asmgen: AsmGen): AsmAssignTarget = with(assign.target) { fun fromAstAssignment(assign: Assignment, program: Program, asmgen: AsmGen): AsmAssignTarget = with(assign.target) {
val dt = inferType(program, assign).typeOrElse(DataType.STRUCT) val idt = inferType(program, assign)
if(!idt.isKnown)
throw AssemblyError("unknown dt")
val dt = idt.typeOrElse(DataType.STRUCT)
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)
@ -127,8 +130,10 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType, expression = value) AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType, expression = value)
} }
is BuiltinFunctionStatementPlaceholder -> { is BuiltinFunctionStatementPlaceholder -> {
val returnType = value.inferType(program).typeOrElse(DataType.STRUCT) val returnType = value.inferType(program)
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType, expression = value) if(!returnType.isKnown)
throw AssemblyError("unknown dt")
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType.typeOrElse(DataType.STRUCT), expression = value)
} }
else -> { else -> {
throw AssemblyError("weird call") throw AssemblyError("weird call")
@ -136,8 +141,10 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
} }
} }
else -> { else -> {
val dt = value.inferType(program).typeOrElse(DataType.STRUCT) val dt = value.inferType(program)
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, dt, expression = value) if(!dt.isKnown)
throw AssemblyError("unknown dt")
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, dt.typeOrElse(DataType.STRUCT), expression = value)
} }
} }
} }

View File

@ -150,8 +150,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val signature = BuiltinFunctions.getValue(sub.name) val signature = BuiltinFunctions.getValue(sub.name)
asmgen.translateBuiltinFunctionCallExpression(value, signature, false) asmgen.translateBuiltinFunctionCallExpression(value, signature, false)
val returntype = builtinFunctionReturnType(sub.name, value.args, program) val returntype = builtinFunctionReturnType(sub.name, value.args, program)
if(returntype.isUnknown) if(!returntype.isKnown)
throw AssemblyError("weird result type") throw AssemblyError("unknown dt")
when(returntype.typeOrElse(DataType.STRUCT)) { when(returntype.typeOrElse(DataType.STRUCT)) {
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
@ -184,7 +184,10 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
} }
private fun assignTypeCastedValue(target: AsmAssignTarget, targetDt: DataType, value: Expression, origAssign: AsmAssignment) { private fun assignTypeCastedValue(target: AsmAssignTarget, targetDt: DataType, value: Expression, origAssign: AsmAssignment) {
val valueDt = value.inferType(program).typeOrElse(DataType.STRUCT) val valueIDt = value.inferType(program)
if(!valueIDt.isKnown)
throw AssemblyError("unknown dt")
val valueDt = valueIDt.typeOrElse(DataType.STRUCT)
when(value) { when(value) {
is IdentifierReference -> { is IdentifierReference -> {
if(targetDt in WordDatatypes) { if(targetDt in WordDatatypes) {

View File

@ -22,7 +22,10 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
when (val value = assign.source.expression!!) { when (val value = assign.source.expression!!) {
is PrefixExpression -> { is PrefixExpression -> {
// A = -A , A = +A, A = ~A, A = not A // A = -A , A = +A, A = ~A, A = not A
val type = value.inferType(program).typeOrElse(DataType.STRUCT) val itype = value.inferType(program)
if(!itype.isKnown)
throw AssemblyError("unknown dt")
val type = itype.typeOrElse(DataType.STRUCT)
when (value.operator) { when (value.operator) {
"+" -> {} "+" -> {}
"-" -> inplaceNegate(assign.target, type) "-" -> inplaceNegate(assign.target, type)
@ -210,7 +213,10 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
private fun tryRemoveRedundantCast(value: TypecastExpression, target: AsmAssignTarget, operator: String): Boolean { private fun tryRemoveRedundantCast(value: TypecastExpression, target: AsmAssignTarget, operator: String): Boolean {
if (target.datatype == value.type) { if (target.datatype == value.type) {
val childDt = value.expression.inferType(program).typeOrElse(DataType.STRUCT) val childIDt = value.expression.inferType(program)
if(!childIDt.isKnown)
throw AssemblyError("unknown dt")
val childDt = childIDt.typeOrElse(DataType.STRUCT)
if (value.type.equalsSize(childDt) || value.type.largerThan(childDt)) { if (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.
inplaceModification(target, operator, value.expression) inplaceModification(target, operator, value.expression)
@ -1096,7 +1102,11 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
if(asmgen.options.slowCodegenWarnings) if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value) asmgen.translateExpression(value)
val valueDt = value.inferType(program).typeOrElse(DataType.STRUCT)
val valueiDt = value.inferType(program)
if(!valueiDt.isKnown)
throw AssemblyError("unknown dt")
val valueDt = valueiDt.typeOrElse(DataType.STRUCT)
fun multiplyWord() { fun multiplyWord() {
asmgen.out(""" asmgen.out("""

View File

@ -477,7 +477,10 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
when (expr.operator) { when (expr.operator) {
"%" -> { "%" -> {
if (cv == 1.0) { if (cv == 1.0) {
return NumericLiteralValue(expr.inferType(program).typeOrElse(DataType.STRUCT), 0, expr.position) val idt = expr.inferType(program)
if(!idt.isKnown)
throw FatalAstException("unknown dt")
return NumericLiteralValue(idt.typeOrElse(DataType.STRUCT), 0, expr.position)
} else if (cv == 2.0) { } else if (cv == 2.0) {
expr.operator = "&" expr.operator = "&"
expr.right = NumericLiteralValue.optimalInteger(1, expr.position) expr.right = NumericLiteralValue.optimalInteger(1, expr.position)
@ -606,8 +609,10 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
if (amount == 0) { if (amount == 0) {
return expr.left return expr.left
} }
val targetDt = expr.left.inferType(program).typeOrElse(DataType.STRUCT) val targetIDt = expr.left.inferType(program)
when (targetDt) { if(!targetIDt.isKnown)
throw FatalAstException("unknown dt")
when (val targetDt = targetIDt.typeOrElse(DataType.STRUCT)) {
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)
@ -639,7 +644,10 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
if (amount == 0) { if (amount == 0) {
return expr.left return expr.left
} }
when (expr.left.inferType(program).typeOrElse(DataType.STRUCT)) { val idt = expr.left.inferType(program)
if(!idt.isKnown)
throw FatalAstException("unknown dt")
when (idt.typeOrElse(DataType.STRUCT)) {
DataType.UBYTE -> { DataType.UBYTE -> {
if (amount >= 8) { if (amount >= 8) {
return NumericLiteralValue.optimalInteger(0, expr.position) return NumericLiteralValue.optimalInteger(0, expr.position)

View File

@ -2,16 +2,15 @@
TODO TODO
==== ====
- get rid of all the .typeOrElse(STRUCT) 'shortcuts' and replace them with proper error handling
- make memset(w) and memcopy able to work with >256 bytes - make memset(w) and memcopy able to work with >256 bytes
- make memset and memcopy use the ROM routines on the CX16 - after that: make memset and memcopy use the ROM routines on the CX16
- calling convention for builtin functions no longer via stack but via statically allocated vars inside the subroutine proc (just as normal subroutines) - calling convention for builtin functions no longer via stack but via statically allocated vars inside the subroutine proc (just as normal subroutines)
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_' - make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_'
- option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging) - option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging)
- see if we can group some errors together for instance the (now single) errors about unidentified symbols - see if we can group some errors together for instance the (now single) errors about unidentified symbols
- use VIC banking to move up the graphics bitmap memory location. Don't move it under the ROM though as that would require IRQ disabling and memory bank swapping for every bitmap manipulation - use VIC banking to move up the graphics bitmap memory location. Don't move it under the ROM though as that would require IRQ disabling and memory bank swapping for every bitmap manipulation
- add some primitives/subroutines/examples for using custom char sets, copying the default charset. - add a c-64 example for using custom char sets, copying (part of) the default charset.
- some better handling of recursive subroutines? via %option recursive?: allocate all params and local vars on estack, don't allow nested subroutines, can begin by first not allowing any local variables just fixing the parameters - some support for recursive subroutines? via %option recursive?: allocate all params and local vars on estack, don't allow nested subroutines, can begin by first not allowing any local variables just fixing the parameters
- get rid of all other TODO's in the code ;-) - get rid of all other TODO's in the code ;-)
More optimizations More optimizations
@ -21,8 +20,7 @@ Add more compiler optimizations to the existing ones.
- further optimize assignment codegeneration, such as the following: - further optimize assignment codegeneration, such as the following:
- binexpr splitting (beware self-referencing expressions and asm code ballooning though) - binexpr splitting (beware self-referencing expressions and asm code ballooning though)
- subroutine calling convention? like: 1 byte arg -> pass in A, 2 bytes -> pass in A+Y, return value likewise. Especially for built-in functions! - detect var->var argument passing to subroutines and avoid the second variable and copying of the value
- can such parameter passing to subroutines be optimized to avoid copying?
- more optimizations on the language AST level - more optimizations on the language AST level
- more optimizations on the final assembly source level - more optimizations on the final assembly source level
- note: subroutine inlining is abandoned because of problems referencing non-local stuff. Can't move everything around. - note: subroutine inlining is abandoned because of problems referencing non-local stuff. Can't move everything around.

View File

@ -191,6 +191,7 @@ main {
sub facing_away(ubyte edgePointsIdx) -> ubyte { sub facing_away(ubyte edgePointsIdx) -> ubyte {
; simplistic visibility determination by checking the Z component of the surface normal ; simplistic visibility determination by checking the Z component of the surface normal
; TODO: actually take the line of sight vector into account
ubyte p1 = shipdata.facesPoints[edgePointsIdx] ubyte p1 = shipdata.facesPoints[edgePointsIdx]
edgePointsIdx++ edgePointsIdx++
ubyte p2 = shipdata.facesPoints[edgePointsIdx] ubyte p2 = shipdata.facesPoints[edgePointsIdx]