fix error reporting of constantfolding, and number of errors printed

This commit is contained in:
Irmen de Jong
2020-03-15 01:10:08 +01:00
parent 835555171e
commit 9d7eb3be5a
6 changed files with 32 additions and 50 deletions

View File

@@ -270,7 +270,7 @@ class GlobalNamespace(val modules: List<Module>): Node, INameScope {
return when (val stmt = localContext.definingModule().lookup(scopedName, localContext)) {
is Label, is VarDecl, is Block, is Subroutine -> stmt
null -> null
else -> throw NameError("wrong identifier target: $stmt", stmt.position)
else -> throw SyntaxError("wrong identifier target: $stmt", stmt.position)
}
}
}

View File

@@ -17,6 +17,8 @@ class ErrorReporter {
fun warn(msg: String, position: Position?) = messages.add(CompilerMessage(MessageSeverity.WARNING, msg, position))
fun handle() {
var numErrors = 0
var numWarnings = 0
messages.forEach {
when(it.severity) {
MessageSeverity.ERROR -> System.err.print("\u001b[91m") // bright red
@@ -26,14 +28,17 @@ class ErrorReporter {
if(msg !in alreadyReportedMessages) {
System.err.println(msg)
alreadyReportedMessages.add(msg)
when(it.severity) {
MessageSeverity.WARNING -> numWarnings++
MessageSeverity.ERROR -> numErrors++
}
}
System.err.print("\u001b[0m") // reset color
}
val numErrors = messages.count { it.severity==MessageSeverity.ERROR }
messages.clear()
if(numErrors>0)
throw ParsingFailedError("There are $numErrors errors.")
throw ParsingFailedError("There are $numErrors errors and $numWarnings warnings.")
}
fun isEmpty() = messages.isEmpty()
}

View File

@@ -6,17 +6,13 @@ class FatalAstException (override var message: String) : Exception(message)
open class AstException (override var message: String) : Exception(message)
class SyntaxError(override var message: String, val position: Position) : AstException(message) {
open class SyntaxError(override var message: String, val position: Position) : AstException(message) {
override fun toString() = "$position Syntax error: $message"
}
open class NameError(override var message: String, val position: Position) : AstException(message) {
override fun toString() = "$position Name error: $message"
}
class ExpressionError(message: String, val position: Position) : AstException(message) {
override fun toString() = "$position Error: $message"
}
class UndefinedSymbolError(symbol: IdentifierReference)
: NameError("undefined symbol: ${symbol.nameInSource.joinToString(".")}", symbol.position)
: SyntaxError("undefined symbol: ${symbol.nameInSource.joinToString(".")}", symbol.position)

View File

@@ -71,7 +71,8 @@ fun compileProgram(filepath: Path,
//println(" time1: $time1")
val time2 = measureTimeMillis {
programAst.constantFold()
programAst.constantFold(errors)
errors.handle()
}
//println(" time2: $time2")
val time3 = measureTimeMillis {

View File

@@ -11,24 +11,14 @@ import prog8.functions.BuiltinFunctions
import kotlin.math.floor
class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
class ConstantFolding(private val program: Program, private val errors: ErrorReporter) : IAstModifyingVisitor {
var optimizationsDone: Int = 0
var errors : MutableList<AstException> = mutableListOf()
private val reportedErrorMessages = mutableSetOf<String>()
fun addError(x: AstException) {
// check that we don't add the isSameAs error more than once
if(x.toString() !in reportedErrorMessages) {
reportedErrorMessages.add(x.toString())
errors.add(x)
}
}
override fun visit(decl: VarDecl): Statement {
// the initializer value can't refer to the variable itself (recursive definition)
// TODO: use call tree for this?
if(decl.value?.referencesIdentifiers(decl.name) == true || decl.arraysize?.index?.referencesIdentifiers(decl.name) == true) {
errors.add(ExpressionError("recursive var declaration", decl.position))
errors.err("recursive var declaration", decl.position)
return decl
}
@@ -69,7 +59,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
// convert the initializer range expression to an actual array
val declArraySize = decl.arraysize?.size()
if(declArraySize!=null && declArraySize!=rangeExpr.size())
errors.add(ExpressionError("range expression size doesn't match declared array size", decl.value?.position!!))
errors.err("range expression size doesn't match declared array size", decl.value?.position!!)
val constRange = rangeExpr.toConstantIntegerRange()
if(constRange!=null) {
val eltType = rangeExpr.inferType(program).typeOrElse(DataType.UBYTE)
@@ -88,7 +78,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
}
}
if(numericLv!=null && numericLv.type== DataType.FLOAT)
errors.add(ExpressionError("arraysize requires only integers here", numericLv.position))
errors.err("arraysize requires only integers here", numericLv.position)
val size = decl.arraysize?.size() ?: return decl
if (rangeExpr==null && numericLv!=null) {
// arraysize initializer is empty or a single int, and we know the size; create the arraysize.
@@ -96,19 +86,19 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
when(decl.datatype){
DataType.ARRAY_UB -> {
if(fillvalue !in 0..255)
errors.add(ExpressionError("ubyte value overflow", numericLv.position))
errors.err("ubyte value overflow", numericLv.position)
}
DataType.ARRAY_B -> {
if(fillvalue !in -128..127)
errors.add(ExpressionError("byte value overflow", numericLv.position))
errors.err("byte value overflow", numericLv.position)
}
DataType.ARRAY_UW -> {
if(fillvalue !in 0..65535)
errors.add(ExpressionError("uword value overflow", numericLv.position))
errors.err("uword value overflow", numericLv.position)
}
DataType.ARRAY_W -> {
if(fillvalue !in -32768..32767)
errors.add(ExpressionError("word value overflow", numericLv.position))
errors.err("word value overflow", numericLv.position)
}
else -> {}
}
@@ -131,7 +121,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
// arraysize initializer is a single int, and we know the size.
val fillvalue = litval.number.toDouble()
if (fillvalue < CompilationTarget.machine.FLOAT_MAX_NEGATIVE || fillvalue > CompilationTarget.machine.FLOAT_MAX_POSITIVE)
errors.add(ExpressionError("float value overflow", litval.position))
errors.err("float value overflow", litval.position)
else {
// create the array itself, filled with the fillvalue.
val array = Array(size) {fillvalue}.map { NumericLiteralValue(DataType.FLOAT, it, litval.position) as Expression}.toTypedArray()
@@ -178,7 +168,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
else -> identifier
}
} catch (ax: AstException) {
addError(ax)
errors.err("unhandled AST error: $ax", identifier.position)
identifier
}
}
@@ -189,7 +179,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
return try {
functionCall.constValue(program) ?: functionCall
} catch (ax: AstException) {
addError(ax)
errors.err("unhandled AST error: $ax", functionCall.position)
functionCall
}
}
@@ -284,7 +274,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
}
return prefixExpr
} catch (ax: AstException) {
addError(ax)
errors.err("unhandled AST error: $ax", expr.position)
expr
}
}
@@ -344,7 +334,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
else -> expr
}
} catch (ax: AstException) {
addError(ax)
errors.err("unhandled AST error: $ax", expr.position)
expr
}
}

View File

@@ -1,30 +1,20 @@
package prog8.optimizer
import prog8.ast.Program
import prog8.ast.base.AstException
import prog8.ast.base.ErrorReporter
import prog8.parser.ParsingFailedError
internal fun Program.constantFold() {
val optimizer = ConstantFolding(this)
try {
optimizer.visit(this)
} catch (ax: AstException) {
optimizer.addError(ax)
}
internal fun Program.constantFold(errors: ErrorReporter) {
val optimizer = ConstantFolding(this, errors)
optimizer.visit(this)
while(optimizer.errors.isEmpty() && optimizer.optimizationsDone>0) {
while(errors.isEmpty() && optimizer.optimizationsDone>0) {
optimizer.optimizationsDone = 0
optimizer.visit(this)
}
if(optimizer.errors.isNotEmpty()) {
optimizer.errors.forEach { System.err.println(it) }
throw ParsingFailedError("There are ${optimizer.errors.size} errors.")
} else {
if(errors.isEmpty())
modules.forEach { it.linkParents(namespace) } // re-link in final configuration
}
}