mirror of
https://github.com/irmen/prog8.git
synced 2025-11-02 13:16:07 +00:00
fix error reporting of constantfolding, and number of errors printed
This commit is contained in:
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user