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)) { return when (val stmt = localContext.definingModule().lookup(scopedName, localContext)) {
is Label, is VarDecl, is Block, is Subroutine -> stmt is Label, is VarDecl, is Block, is Subroutine -> stmt
null -> null 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 warn(msg: String, position: Position?) = messages.add(CompilerMessage(MessageSeverity.WARNING, msg, position))
fun handle() { fun handle() {
var numErrors = 0
var numWarnings = 0
messages.forEach { messages.forEach {
when(it.severity) { when(it.severity) {
MessageSeverity.ERROR -> System.err.print("\u001b[91m") // bright red MessageSeverity.ERROR -> System.err.print("\u001b[91m") // bright red
@@ -26,14 +28,17 @@ class ErrorReporter {
if(msg !in alreadyReportedMessages) { if(msg !in alreadyReportedMessages) {
System.err.println(msg) System.err.println(msg)
alreadyReportedMessages.add(msg) alreadyReportedMessages.add(msg)
when(it.severity) {
MessageSeverity.WARNING -> numWarnings++
MessageSeverity.ERROR -> numErrors++
}
} }
System.err.print("\u001b[0m") // reset color System.err.print("\u001b[0m") // reset color
} }
val numErrors = messages.count { it.severity==MessageSeverity.ERROR }
messages.clear() messages.clear()
if(numErrors>0) 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) 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" 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) { class ExpressionError(message: String, val position: Position) : AstException(message) {
override fun toString() = "$position Error: $message" override fun toString() = "$position Error: $message"
} }
class UndefinedSymbolError(symbol: IdentifierReference) 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") //println(" time1: $time1")
val time2 = measureTimeMillis { val time2 = measureTimeMillis {
programAst.constantFold() programAst.constantFold(errors)
errors.handle()
} }
//println(" time2: $time2") //println(" time2: $time2")
val time3 = measureTimeMillis { val time3 = measureTimeMillis {

View File

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

View File

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