some WARN messages are now INFO

This commit is contained in:
Irmen de Jong 2023-12-28 13:48:01 +01:00
parent 44d82f9190
commit 9c1b11d605
13 changed files with 87 additions and 53 deletions

View File

@ -3,11 +3,12 @@ package prog8.code.core
interface IErrorReporter {
fun err(msg: String, position: Position)
fun warn(msg: String, position: Position)
fun info(msg: String, position: Position)
fun undefined(symbol: List<String>, position: Position)
fun noErrors(): Boolean
fun report()
fun finalizeNumErrors(numErrors: Int, numWarnings: Int) {
fun finalizeNumErrors(numErrors: Int, numWarnings: Int, numInfos: Int) {
if(numErrors>0)
throw ErrorsReportedException("There are $numErrors errors and $numWarnings warnings.")
throw ErrorsReportedException("There are $numErrors errors, $numWarnings warnings, and $numInfos infos.")
}
}

View File

@ -29,11 +29,11 @@ internal object DummyStringEncoder : IStringEncoding {
}
}
internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors: Boolean=true, private val keepMessagesAfterReporting: Boolean=false):
IErrorReporter {
internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors: Boolean=true, private val keepMessagesAfterReporting: Boolean=false): IErrorReporter {
val errors = mutableListOf<String>()
val warnings = mutableListOf<String>()
val infos = mutableListOf<String>()
override fun err(msg: String, position: Position) {
val text = "${position.toClickableStr()} $msg"
@ -47,6 +47,12 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
warnings.add(text)
}
override fun info(msg: String, position: Position) {
val text = "${position.toClickableStr()} $msg"
if(text !in infos)
infos.add(text)
}
override fun undefined(symbol: List<String>, position: Position) {
err("undefined symbol: ${symbol.joinToString(".")}", position)
}
@ -54,10 +60,11 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
override fun noErrors(): Boolean = errors.isEmpty()
override fun report() {
infos.forEach { println("UNITTEST COMPILATION REPORT: INFO: $it") }
warnings.forEach { println("UNITTEST COMPILATION REPORT: WARNING: $it") }
errors.forEach { println("UNITTEST COMPILATION REPORT: ERROR: $it") }
if(throwExceptionAtReportIfErrors)
finalizeNumErrors(errors.size, warnings.size)
finalizeNumErrors(errors.size, warnings.size, infos.size)
if(!keepMessagesAfterReporting) {
clear()
}
@ -66,5 +73,6 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
fun clear() {
errors.clear()
warnings.clear()
infos.clear()
}
}

View File

@ -61,7 +61,7 @@ class IRUnusedCodeRemover(
block.children.filterIsInstance<IRSubroutine>().reversed().forEach { sub ->
if(sub.isEmpty()) {
if(!block.options.ignoreUnused) {
errors.warn("unused subroutine '${sub.label}'", sub.position)
errors.info("unused subroutine '${sub.label}'", sub.position)
}
block.children.remove(sub)
irprog.st.removeTree(sub.label)
@ -82,7 +82,7 @@ class IRUnusedCodeRemover(
block.children.filterIsInstance<IRAsmSubroutine>().reversed().forEach { sub ->
if(sub.isEmpty()) {
if(!block.options.ignoreUnused) {
errors.warn("unused subroutine '${sub.label}'", sub.position)
errors.info("unused subroutine '${sub.label}'", sub.position)
}
block.children.remove(sub)
irprog.st.removeTree(sub.label)

View File

@ -27,11 +27,11 @@ internal object DummyStringEncoder : IStringEncoding {
}
}
internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors: Boolean=true, private val keepMessagesAfterReporting: Boolean=false):
IErrorReporter {
internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors: Boolean=true, private val keepMessagesAfterReporting: Boolean=false): IErrorReporter {
val errors = mutableListOf<String>()
val warnings = mutableListOf<String>()
val infos = mutableListOf<String>()
override fun err(msg: String, position: Position) {
val text = "${position.toClickableStr()} $msg"
@ -45,6 +45,12 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
warnings.add(text)
}
override fun info(msg: String, position: Position) {
val text = "${position.toClickableStr()} $msg"
if(text !in infos)
infos.add(text)
}
override fun undefined(symbol: List<String>, position: Position) {
err("undefined symbol: ${symbol.joinToString(".")}", position)
}
@ -52,10 +58,11 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
override fun noErrors(): Boolean = errors.isEmpty()
override fun report() {
infos.forEach { println("UNITTEST COMPILATION REPORT: INFO: $it") }
warnings.forEach { println("UNITTEST COMPILATION REPORT: WARNING: $it") }
errors.forEach { println("UNITTEST COMPILATION REPORT: ERROR: $it") }
if(throwExceptionAtReportIfErrors)
finalizeNumErrors(errors.size, warnings.size)
finalizeNumErrors(errors.size, warnings.size, infos.size)
if(!keepMessagesAfterReporting) {
clear()
}
@ -64,5 +71,6 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
fun clear() {
errors.clear()
warnings.clear()
infos.clear()
}
}

View File

@ -131,7 +131,7 @@ class StatementOptimizer(private val program: Program,
override fun after(forLoop: ForLoop, parent: Node): Iterable<IAstModification> {
if(forLoop.body.isEmpty()) {
errors.warn("removing empty for loop", forLoop.position)
errors.info("removing empty for loop", forLoop.position)
return listOf(IAstModification.Remove(forLoop, parent as IStatementContainer))
} else if(forLoop.body.statements.size==1) {
val loopvar = forLoop.body.statements[0] as? VarDecl
@ -287,7 +287,7 @@ class StatementOptimizer(private val program: Program,
val iter = repeatLoop.iterations
if(iter!=null) {
if(repeatLoop.body.isEmpty()) {
errors.warn("empty loop removed", repeatLoop.position)
errors.info("empty loop removed", repeatLoop.position)
return listOf(IAstModification.Remove(repeatLoop, parent as IStatementContainer))
}
val iterations = iter.constValue(program)?.number?.toInt()
@ -469,7 +469,7 @@ class StatementOptimizer(private val program: Program,
fun replaceWithIf(condition: Expression, trueBlock: AnonymousScope, elseBlock: AnonymousScope?): List<IAstModification> {
val ifStmt = IfElse(condition, trueBlock, elseBlock ?: AnonymousScope(mutableListOf(), whenStmt.position), whenStmt.position)
errors.warn("for boolean condition a normal if statement is preferred", whenStmt.position)
errors.info("for boolean condition a normal if statement is preferred", whenStmt.position)
return listOf(IAstModification.ReplaceNode(whenStmt, ifStmt, parent))
}

View File

@ -60,14 +60,14 @@ class UnusedCodeRemover(private val program: Program,
if (block.containsNoCodeNorVars) {
if(block.name != internedStringsModuleName) {
if(!block.statements.any { it is Subroutine && it.hasBeenInlined })
errors.warn("removing unused block '${block.name}'", block.position)
errors.info("removing unused block '${block.name}'", block.position)
}
return listOf(IAstModification.Remove(block, parent as IStatementContainer))
}
if(callgraph.unused(block)) {
if(block.statements.any{ it !is VarDecl || it.type== VarDeclType.VAR}) {
if(!block.statements.any { it is Subroutine && it.hasBeenInlined })
errors.warn("removing unused block '${block.name}'", block.position)
errors.info("removing unused block '${block.name}'", block.position)
}
if(!block.statements.any { it is Subroutine && it.hasBeenInlined }) {
program.removeInternedStringsFromRemovedBlock(block)
@ -85,7 +85,7 @@ class UnusedCodeRemover(private val program: Program,
if(callgraph.unused(subroutine)) {
if(subroutine.containsNoCodeNorVars) {
if("ignore_unused" !in subroutine.definingBlock.options())
errors.warn("removing empty subroutine '${subroutine.name}'", subroutine.position)
errors.info("removing empty subroutine '${subroutine.name}'", subroutine.position)
val removals = mutableListOf(IAstModification.Remove(subroutine, parent as IStatementContainer))
callgraph.calledBy[subroutine]?.let {
for(node in it)
@ -94,7 +94,7 @@ class UnusedCodeRemover(private val program: Program,
return removals
}
if(!subroutine.hasBeenInlined && "ignore_unused" !in subroutine.definingBlock.options()) {
errors.warn("unused subroutine '${subroutine.name}'", subroutine.position)
errors.info("unused subroutine '${subroutine.name}'", subroutine.position)
}
if(!subroutine.inline) {
program.removeInternedStringsFromRemovedSubroutine(subroutine)
@ -114,7 +114,7 @@ class UnusedCodeRemover(private val program: Program,
val usages = callgraph.usages(decl)
if (usages.isEmpty()) {
if("ignore_unused" !in decl.definingBlock.options())
errors.warn("removing unused variable '${decl.name}'", decl.position)
errors.info("removing unused variable '${decl.name}'", decl.position)
return listOf(IAstModification.Remove(decl, parent as IStatementContainer))
}
else {
@ -130,7 +130,7 @@ class UnusedCodeRemover(private val program: Program,
if (singleAssignment!=null && reads.isNotEmpty()) {
if (singleAssignment.origin == AssignmentOrigin.VARINIT && singleAssignment.value.constValue(program) != null) {
// variable only has a single write and it is the initialization value, so it can be replaced with a constant, IF the value is a constant
errors.warn("variable is never written to and was replaced by a constant", decl.position)
errors.info("variable is never written to and was replaced by a constant", decl.position)
val const = VarDecl(VarDeclType.CONST, decl.origin, decl.datatype, decl.zeropage, decl.arraysize, decl.name, decl.names, singleAssignment.value, decl.sharedWithAsm, decl.splitArray, decl.position)
return listOf(
IAstModification.ReplaceNode(decl, const, parent),
@ -156,7 +156,7 @@ class UnusedCodeRemover(private val program: Program,
if(assignment.value.isSimple) {
// remove the vardecl
if("ignore_unused" !in decl.definingBlock.options())
errors.warn("removing unused variable '${decl.name}'", decl.position)
errors.info("removing unused variable '${decl.name}'", decl.position)
return listOf(
IAstModification.Remove(decl, parent as IStatementContainer),
IAstModification.Remove(assignment, assignment.parent as IStatementContainer)
@ -168,7 +168,7 @@ class UnusedCodeRemover(private val program: Program,
val declIndex = (parent as IStatementContainer).statements.indexOf(decl)
val singleUseIndex = (parent as IStatementContainer).statements.indexOf(singleUse.parent)
if(declIndex==singleUseIndex-1) {
errors.warn("replaced unused variable '${decl.name}' with void call, maybe this can be removed altogether", decl.position)
errors.info("replaced unused variable '${decl.name}' with void call, maybe this can be removed altogether", decl.position)
val fcall = assignment.value as IFunctionCall
val voidCall = FunctionCallStatement(fcall.target, fcall.args, true, fcall.position)
return listOf(
@ -178,7 +178,7 @@ class UnusedCodeRemover(private val program: Program,
}
}
} else {
errors.warn("variable '${decl.name}' is unused but has non-trivial initialization assignment. Leaving this in but maybe it can be removed altogether", decl.position)
errors.info("variable '${decl.name}' is unused but has non-trivial initialization assignment. Leaving this in but maybe it can be removed altogether", decl.position)
}
}
}

View File

@ -6,10 +6,10 @@ package prog8.buildversion
const val MAVEN_GROUP = "prog8"
const val MAVEN_NAME = "compiler"
const val VERSION = "9.8-SNAPSHOT"
const val GIT_REVISION = 4287
const val GIT_SHA = "08a079a96e67c26298b81de2d35919be51a3dfd0"
const val GIT_DATE = "2023-12-11T20:15:48Z"
const val GIT_BRANCH = "no-vardecls"
const val BUILD_DATE = "2023-12-11T21:48:14Z"
const val BUILD_UNIX_TIME = 1702331294381L
const val GIT_REVISION = 4335
const val GIT_SHA = "44d82f9190763aa5113a3dce4a7d4623018a1c25"
const val GIT_DATE = "2023-12-28T12:30:07Z"
const val GIT_BRANCH = "master"
const val BUILD_DATE = "2023-12-28T12:44:26Z"
const val BUILD_UNIX_TIME = 1703767466828L
const val DIRTY = 1

View File

@ -6,6 +6,7 @@ import prog8.code.core.Position
internal class ErrorReporter: IErrorReporter {
private enum class MessageSeverity {
INFO,
WARNING,
ERROR
}
@ -20,6 +21,9 @@ internal class ErrorReporter: IErrorReporter {
override fun warn(msg: String, position: Position) {
messages.add(CompilerMessage(MessageSeverity.WARNING, msg, position))
}
override fun info(msg: String, position: Position) {
messages.add(CompilerMessage(MessageSeverity.INFO, msg, position))
}
override fun undefined(symbol: List<String>, position: Position) {
err("undefined symbol: ${symbol.joinToString(".")}", position)
@ -28,29 +32,37 @@ internal class ErrorReporter: IErrorReporter {
override fun report() {
var numErrors = 0
var numWarnings = 0
var numInfos = 0
messages.forEach {
val printer = when(it.severity) {
MessageSeverity.INFO -> System.out
MessageSeverity.WARNING -> System.out
MessageSeverity.ERROR -> System.err
}
val msg = "${it.position.toClickableStr()} ${it.message}".trim()
if(msg !in alreadyReportedMessages) {
when(it.severity) {
MessageSeverity.ERROR -> printer.print("\u001b[91mERROR\u001B[0m ") // bright red
MessageSeverity.WARNING -> printer.print("\u001b[93mWARN\u001B[0m ") // bright yellow
MessageSeverity.ERROR -> {
printer.print("\u001b[91mERROR\u001B[0m ") // bright red
numErrors++
}
MessageSeverity.WARNING -> {
printer.print("\u001b[93mWARN\u001B[0m ") // bright yellow
numWarnings++
}
MessageSeverity.INFO -> {
printer.print("\u001b[92mINFO\u001B[0m ") // bright green
numInfos++
}
}
printer.println(msg)
alreadyReportedMessages.add(msg)
when(it.severity) {
MessageSeverity.WARNING -> numWarnings++
MessageSeverity.ERROR -> numErrors++
}
}
}
System.out.flush()
System.err.flush()
messages.clear()
finalizeNumErrors(numErrors, numWarnings)
finalizeNumErrors(numErrors, numWarnings, numInfos)
}
override fun noErrors() = messages.none { it.severity==MessageSeverity.ERROR }

View File

@ -122,7 +122,7 @@ internal class AstChecker(private val program: Program,
if (expectedReturnValues[0] != valueDt.getOr(DataType.UNDEFINED)) {
if(valueDt istype DataType.BOOL && expectedReturnValues[0] == DataType.UBYTE) {
// if the return value is a bool and the return type is ubyte, allow this. But give a warning.
errors.warn("return type of the subroutine should probably be bool instead of ubyte", returnStmt.position)
errors.info("return type of the subroutine should probably be bool instead of ubyte", returnStmt.position)
} else if(valueDt istype DataType.UBYTE && expectedReturnValues[0] == DataType.BOOL) {
// if the return value is ubyte and the return type is bool, allow this only if value is 0 or 1
val returnValue = returnStmt.value as? NumericLiteral
@ -933,7 +933,7 @@ internal class AstChecker(private val program: Program,
try { // just *try* if it can be encoded, don't actually do it
val bytes = compilerOptions.compTarget.encodeString(string.value, string.encoding)
if(0u in bytes)
errors.warn("a character in the string encodes as 0-byte, which will terminate the string prematurely", string.position)
errors.info("a character in the string encodes as 0-byte, which will terminate the string prematurely", string.position)
} catch (cx: CharConversionException) {
errors.err(cx.message ?: "can't encode string", string.position)
}
@ -1187,14 +1187,14 @@ internal class AstChecker(private val program: Program,
when(targetStatement) {
is BuiltinFunctionPlaceholder -> {
if(!builtinFunctionReturnType(targetStatement.name).isKnown)
errors.warn("redundant void", functionCallStatement.position)
errors.info("redundant void", functionCallStatement.position)
}
is Label -> {
errors.warn("redundant void", functionCallStatement.position)
errors.info("redundant void", functionCallStatement.position)
}
is Subroutine -> {
if(targetStatement.returntypes.isEmpty())
errors.warn("redundant void", functionCallStatement.position)
errors.info("redundant void", functionCallStatement.position)
}
else -> {}
}
@ -1745,13 +1745,13 @@ internal fun checkUnusedReturnValues(call: FunctionCallStatement, target: Statem
// check for unused return values
if (target is Subroutine && target.returntypes.isNotEmpty()) {
if (target.returntypes.size == 1)
errors.warn("result value of subroutine call is discarded (use void?)", call.position)
errors.info("result value of subroutine call is discarded (use void?)", call.position)
else
errors.warn("result values of subroutine call are discarded (use void?)", call.position)
errors.info("result values of subroutine call are discarded (use void?)", call.position)
} else if (target is BuiltinFunctionPlaceholder) {
val rt = builtinFunctionReturnType(target.name)
if (rt.isKnown)
errors.warn("result value of a function call is discarded (use void?)", call.position)
errors.info("result value of a function call is discarded (use void?)", call.position)
}
}
}

View File

@ -497,7 +497,7 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
if(value==null) {
val blockOptions = srcVar.definingBlock.options()
if("align_page" in blockOptions || "align_word" in blockOptions) {
errors.warn("converting uninitialized array to explicit zeros because of block alignment option", srcVar.position)
errors.info("converting uninitialized array to explicit zeros because of block alignment option", srcVar.position)
val zeros = PtArray(srcVar.datatype, srcVar.position)
repeat(srcVar.arraysize!!.constIndex()!!) {
zeros.children.add(PtNumber(ArrayToElementTypes.getValue(srcVar.datatype), 0.0, srcVar.position))

View File

@ -174,7 +174,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
override fun after(containment: ContainmentCheck, parent: Node): Iterable<IAstModification> {
// replace trivial containment checks with just false or a single comparison
fun replaceWithEquals(value: NumericLiteral): Iterable<IAstModification> {
errors.warn("containment could be written as just a single comparison", containment.position)
errors.info("containment could be written as just a single comparison", containment.position)
val equals = BinaryExpression(containment.element, "==", value, containment.position)
return listOf(IAstModification.ReplaceNode(containment, equals, parent))
}
@ -258,7 +258,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
override fun after(branch: ConditionalBranch, parent: Node): Iterable<IAstModification> {
if(branch.truepart.isEmpty() && branch.elsepart.isEmpty()) {
errors.warn("removing empty conditional branch", branch.position)
errors.info("removing empty conditional branch", branch.position)
return listOf(IAstModification.Remove(branch, parent as IStatementContainer))
}
@ -267,7 +267,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
override fun after(ifElse: IfElse, parent: Node): Iterable<IAstModification> {
if(ifElse.truepart.isEmpty() && ifElse.elsepart.isEmpty()) {
errors.warn("removing empty if-else statement", ifElse.position)
errors.info("removing empty if-else statement", ifElse.position)
return listOf(IAstModification.Remove(ifElse, parent as IStatementContainer))
}
return noModifications

View File

@ -3,11 +3,11 @@ package prog8tests.helpers
import prog8.code.core.IErrorReporter
import prog8.code.core.Position
internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors: Boolean=true, private val keepMessagesAfterReporting: Boolean=false):
IErrorReporter {
internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors: Boolean=true, private val keepMessagesAfterReporting: Boolean=false): IErrorReporter {
val errors = mutableListOf<String>()
val warnings = mutableListOf<String>()
val infos = mutableListOf<String>()
override fun err(msg: String, position: Position) {
val text = "${position.toClickableStr()} $msg"
@ -21,6 +21,12 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
warnings.add(text)
}
override fun info(msg: String, position: Position) {
val text = "${position.toClickableStr()} $msg"
if(text !in infos)
infos.add(text)
}
override fun undefined(symbol: List<String>, position: Position) {
err("undefined symbol: ${symbol.joinToString(".")}", position)
}
@ -28,10 +34,11 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
override fun noErrors(): Boolean = errors.isEmpty()
override fun report() {
infos.forEach { println("UNITTEST COMPILATION REPORT: INFO: $it") }
warnings.forEach { println("UNITTEST COMPILATION REPORT: WARNING: $it") }
errors.forEach { println("UNITTEST COMPILATION REPORT: ERROR: $it") }
if(throwExceptionAtReportIfErrors)
finalizeNumErrors(errors.size, warnings.size)
finalizeNumErrors(errors.size, warnings.size, infos.size)
if(!keepMessagesAfterReporting) {
clear()
}
@ -40,5 +47,6 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
fun clear() {
errors.clear()
warnings.clear()
infos.clear()
}
}

View File

@ -2,9 +2,6 @@
TODO
====
- add INFO error level and move some warnings to info
- add switch to enable INFO error messages (default is WARN and up)
- [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
...