diff --git a/codeCore/src/prog8/code/core/IErrorReporter.kt b/codeCore/src/prog8/code/core/IErrorReporter.kt index 9bc3d7de3..e60aa9a19 100644 --- a/codeCore/src/prog8/code/core/IErrorReporter.kt +++ b/codeCore/src/prog8/code/core/IErrorReporter.kt @@ -3,6 +3,7 @@ package prog8.code.core interface IErrorReporter { fun err(msg: String, position: Position) fun warn(msg: String, position: Position) + fun undefined(symbol: List, position: Position) fun noErrors(): Boolean fun report() fun finalizeNumErrors(numErrors: Int, numWarnings: Int) { diff --git a/codeGenCpu6502/test/Dummies.kt b/codeGenCpu6502/test/Dummies.kt index 3351be558..b2f3bc8ee 100644 --- a/codeGenCpu6502/test/Dummies.kt +++ b/codeGenCpu6502/test/Dummies.kt @@ -45,6 +45,10 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors: warnings.add(text) } + override fun undefined(symbol: List, position: Position) { + err("undefined symbol: ${symbol.joinToString(".")}", position) + } + override fun noErrors(): Boolean = errors.isEmpty() override fun report() { diff --git a/codeGenIntermediate/test/Dummies.kt b/codeGenIntermediate/test/Dummies.kt index 37b7dc30c..afe25b36f 100644 --- a/codeGenIntermediate/test/Dummies.kt +++ b/codeGenIntermediate/test/Dummies.kt @@ -43,6 +43,10 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors: warnings.add(text) } + override fun undefined(symbol: List, position: Position) { + err("undefined symbol: ${symbol.joinToString(".")}", position) + } + override fun noErrors(): Boolean = errors.isEmpty() override fun report() { diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index 3257697e9..eca513194 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -3,7 +3,6 @@ package prog8.optimizer import prog8.ast.Node import prog8.ast.Program import prog8.ast.base.FatalAstException -import prog8.ast.base.UndefinedSymbolError import prog8.ast.expressions.* import prog8.ast.maySwapOperandOrder import prog8.ast.statements.ForLoop @@ -307,7 +306,7 @@ class ConstantFoldingOptimizer(private val program: Program) : AstWalker() { val rangeTo = iterableRange.to as? NumericLiteral if(rangeFrom==null || rangeTo==null) return noModifications - val loopvar = forLoop.loopVar.targetVarDecl(program) ?: throw UndefinedSymbolError(forLoop.loopVar) + val loopvar = forLoop.loopVar.targetVarDecl(program) ?: return noModifications val stepLiteral = iterableRange.step as? NumericLiteral when(loopvar.datatype) { diff --git a/compiler/src/prog8/compiler/ErrorReporter.kt b/compiler/src/prog8/compiler/ErrorReporter.kt index 4ac48b1a1..0748f68a4 100644 --- a/compiler/src/prog8/compiler/ErrorReporter.kt +++ b/compiler/src/prog8/compiler/ErrorReporter.kt @@ -21,6 +21,10 @@ internal class ErrorReporter: IErrorReporter { messages.add(CompilerMessage(MessageSeverity.WARNING, msg, position)) } + override fun undefined(symbol: List, position: Position) { + err("undefined symbol: ${symbol.joinToString(".")}", position) + } + override fun report() { var numErrors = 0 var numWarnings = 0 diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 7a3a6bd54..e2f6074c3 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -62,7 +62,7 @@ internal class AstChecker(private val program: Program, override fun visit(identifier: IdentifierReference) { val stmt = identifier.targetStatement(program) if(stmt==null) - errors.err("undefined symbol: ${identifier.nameInSource.joinToString(".")}", identifier.position) + errors.undefined(identifier.nameInSource, identifier.position) else { val target = stmt as? VarDecl if (target != null && target.origin == VarDeclOrigin.SUBROUTINEPARAM) { @@ -126,8 +126,11 @@ internal class AstChecker(private val program: Program, override fun visit(ifElse: IfElse) { val dt = ifElse.condition.inferType(program) - if(!dt.isInteger && !dt.istype(DataType.BOOL)) - errors.err("condition value should be an integer type or bool", ifElse.condition.position) + if(!dt.isInteger && !dt.istype(DataType.BOOL)) { + val identifier = ifElse.condition as? IdentifierReference + if(identifier==null || identifier.targetStatement(program)!=null) + errors.err("condition value should be an integer type or bool", ifElse.condition.position) + } super.visit(ifElse) } @@ -443,15 +446,21 @@ internal class AstChecker(private val program: Program, override fun visit(untilLoop: UntilLoop) { val dt = untilLoop.condition.inferType(program) - if(!dt.isInteger && !dt.istype(DataType.BOOL)) - errors.err("condition value should be an integer type or bool", untilLoop.condition.position) + if(!dt.isInteger && !dt.istype(DataType.BOOL)) { + val identifier = untilLoop.condition as? IdentifierReference + if(identifier==null || identifier.targetStatement(program)!=null) + errors.err("condition value should be an integer type or bool", untilLoop.condition.position) + } super.visit(untilLoop) } override fun visit(whileLoop: WhileLoop) { val dt = whileLoop.condition.inferType(program) - if(!dt.isInteger && !dt.istype(DataType.BOOL)) - errors.err("condition value should be an integer type or bool", whileLoop.condition.position) + if(!dt.isInteger && !dt.istype(DataType.BOOL)) { + val identifier = whileLoop.condition as? IdentifierReference + if(identifier==null || identifier.targetStatement(program)!=null) + errors.err("condition value should be an integer type or bool", whileLoop.condition.position) + } super.visit(whileLoop) } @@ -522,7 +531,7 @@ internal class AstChecker(private val program: Program, val targetName = targetIdentifier.nameInSource when (val targetSymbol = assignment.definingScope.lookup(targetName)) { null -> { - errors.err("undefined symbol: ${targetIdentifier.nameInSource.joinToString(".")}", targetIdentifier.position) + errors.undefined(targetIdentifier.nameInSource, targetIdentifier.position) return } !is VarDecl -> { @@ -1237,7 +1246,7 @@ internal class AstChecker(private val program: Program, val target = postIncrDecr.definingScope.lookup(targetName) if(target==null) { val symbol = postIncrDecr.target.identifier!! - errors.err("undefined symbol: ${symbol.nameInSource.joinToString(".")}", symbol.position) + errors.undefined(symbol.nameInSource, symbol.position) } else { if(target !is VarDecl || target.type== VarDeclType.CONST) { errors.err("can only increment or decrement a variable", postIncrDecr.position) @@ -1383,7 +1392,7 @@ internal class AstChecker(private val program: Program, else errors.err("cannot call that: ${target.nameInSource.joinToString(".")}", target.position) } - null -> errors.err("undefined symbol: ${target.nameInSource.joinToString(".")}", target.position) + null -> errors.undefined(target.nameInSource, target.position) else -> errors.err("cannot call that: ${target.nameInSource.joinToString(".")}", target.position) } return null diff --git a/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt b/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt index b94e14266..4ef9878e5 100644 --- a/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt +++ b/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt @@ -67,8 +67,13 @@ internal class VerifyFunctionArgTypes(val program: Program, val errors: IErrorRe fun checkTypes(call: IFunctionCall, program: Program): Pair? { val argITypes = call.args.map { it.inferType(program) } val firstUnknownDt = argITypes.indexOfFirst { it.isUnknown } - if(firstUnknownDt>=0) - return Pair("argument ${firstUnknownDt+1} invalid argument type", call.args[firstUnknownDt].position) + if(firstUnknownDt>=0) { + val identifier = call.args[0] as? IdentifierReference + return if(identifier==null || identifier.targetStatement(program)!=null) + Pair("argument ${firstUnknownDt + 1} invalid argument type", call.args[firstUnknownDt].position) + else + null + } val argtypes = argITypes.map { it.getOr(DataType.UNDEFINED) } val target = call.target.targetStatement(program) if (target is Subroutine) { diff --git a/compiler/test/helpers/ErrorReporterForTests.kt b/compiler/test/helpers/ErrorReporterForTests.kt index c2d8806bb..e8d61f339 100644 --- a/compiler/test/helpers/ErrorReporterForTests.kt +++ b/compiler/test/helpers/ErrorReporterForTests.kt @@ -21,6 +21,10 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors: warnings.add(text) } + override fun undefined(symbol: List, position: Position) { + err("undefined symbol: ${symbol.joinToString(".")}", position) + } + override fun noErrors(): Boolean = errors.isEmpty() override fun report() { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 8ffdee148..827ffc464 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,7 +2,7 @@ TODO ==== - hiram bank 1 usage configurable or maybe even just keep whatever bank is active at program start? -- replace all the string.compare calls in rockrunner with equalites +- is it possible to allow the curly brace to be on the next line instead of requiring it to follow on the same line? ... diff --git a/examples/test.p8 b/examples/test.p8 index dcaafa79e..bcba4c218 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,30 +1,14 @@ -%import textio %zeropage basicsafe +%option no_sysinit main { sub start() { - cx16.r0 = $1234 - cx16.r15 = $ea31 - - txt.print_uwhex(cx16.r0, true) - txt.print_uwhex(cx16.r15, true) - txt.nl() - - cx16.save_virtual_registers() - cx16.r0 = $3333 - cx16.r15 = $4444 - - txt.print_uwhex(cx16.r0, true) - txt.print_uwhex(cx16.r15, true) - txt.nl() - cx16.restore_virtual_registers() - - txt.print_uwhex(cx16.r0, true) - txt.print_uwhex(cx16.r15, true) - txt.nl() - repeat { + if foobar1 { + cx16.r0++ } + + sys.exit(foobar3) } }