mirror of
https://github.com/irmen/prog8.git
synced 2024-11-04 04:05:00 +00:00
improve errors generated for undefined symbols
This commit is contained in:
parent
e9163aa3a7
commit
eae41de27d
@ -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) {
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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() {
|
||||
|
@ -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?
|
||||
|
||||
...
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user