improve errors generated for undefined symbols

This commit is contained in:
Irmen de Jong 2023-06-25 15:19:51 +02:00
parent e9163aa3a7
commit eae41de27d
10 changed files with 50 additions and 36 deletions

View File

@ -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<String>, position: Position)
fun noErrors(): Boolean
fun report()
fun finalizeNumErrors(numErrors: Int, numWarnings: Int) {

View File

@ -45,6 +45,10 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
warnings.add(text)
}
override fun undefined(symbol: List<String>, position: Position) {
err("undefined symbol: ${symbol.joinToString(".")}", position)
}
override fun noErrors(): Boolean = errors.isEmpty()
override fun report() {

View File

@ -43,6 +43,10 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
warnings.add(text)
}
override fun undefined(symbol: List<String>, position: Position) {
err("undefined symbol: ${symbol.joinToString(".")}", position)
}
override fun noErrors(): Boolean = errors.isEmpty()
override fun report() {

View File

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

View File

@ -21,6 +21,10 @@ internal class ErrorReporter: IErrorReporter {
messages.add(CompilerMessage(MessageSeverity.WARNING, msg, position))
}
override fun undefined(symbol: List<String>, position: Position) {
err("undefined symbol: ${symbol.joinToString(".")}", position)
}
override fun report() {
var numErrors = 0
var numWarnings = 0

View File

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

View File

@ -67,8 +67,13 @@ internal class VerifyFunctionArgTypes(val program: Program, val errors: IErrorRe
fun checkTypes(call: IFunctionCall, program: Program): Pair<String, Position>? {
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) {

View File

@ -21,6 +21,10 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
warnings.add(text)
}
override fun undefined(symbol: List<String>, position: Position) {
err("undefined symbol: ${symbol.joinToString(".")}", position)
}
override fun noErrors(): Boolean = errors.isEmpty()
override fun report() {

View File

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

View File

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