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 { interface IErrorReporter {
fun err(msg: String, position: Position) fun err(msg: String, position: Position)
fun warn(msg: String, position: Position) fun warn(msg: String, position: Position)
fun info(msg: String, position: Position)
fun undefined(symbol: List<String>, position: Position) fun undefined(symbol: List<String>, position: Position)
fun noErrors(): Boolean fun noErrors(): Boolean
fun report() fun report()
fun finalizeNumErrors(numErrors: Int, numWarnings: Int) { fun finalizeNumErrors(numErrors: Int, numWarnings: Int, numInfos: Int) {
if(numErrors>0) 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): internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors: Boolean=true, private val keepMessagesAfterReporting: Boolean=false): IErrorReporter {
IErrorReporter {
val errors = mutableListOf<String>() val errors = mutableListOf<String>()
val warnings = mutableListOf<String>() val warnings = mutableListOf<String>()
val infos = mutableListOf<String>()
override fun err(msg: String, position: Position) { override fun err(msg: String, position: Position) {
val text = "${position.toClickableStr()} $msg" val text = "${position.toClickableStr()} $msg"
@ -47,6 +47,12 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
warnings.add(text) 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) { override fun undefined(symbol: List<String>, position: Position) {
err("undefined symbol: ${symbol.joinToString(".")}", 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 noErrors(): Boolean = errors.isEmpty()
override fun report() { override fun report() {
infos.forEach { println("UNITTEST COMPILATION REPORT: INFO: $it") }
warnings.forEach { println("UNITTEST COMPILATION REPORT: WARNING: $it") } warnings.forEach { println("UNITTEST COMPILATION REPORT: WARNING: $it") }
errors.forEach { println("UNITTEST COMPILATION REPORT: ERROR: $it") } errors.forEach { println("UNITTEST COMPILATION REPORT: ERROR: $it") }
if(throwExceptionAtReportIfErrors) if(throwExceptionAtReportIfErrors)
finalizeNumErrors(errors.size, warnings.size) finalizeNumErrors(errors.size, warnings.size, infos.size)
if(!keepMessagesAfterReporting) { if(!keepMessagesAfterReporting) {
clear() clear()
} }
@ -66,5 +73,6 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
fun clear() { fun clear() {
errors.clear() errors.clear()
warnings.clear() warnings.clear()
infos.clear()
} }
} }

View File

@ -61,7 +61,7 @@ class IRUnusedCodeRemover(
block.children.filterIsInstance<IRSubroutine>().reversed().forEach { sub -> block.children.filterIsInstance<IRSubroutine>().reversed().forEach { sub ->
if(sub.isEmpty()) { if(sub.isEmpty()) {
if(!block.options.ignoreUnused) { if(!block.options.ignoreUnused) {
errors.warn("unused subroutine '${sub.label}'", sub.position) errors.info("unused subroutine '${sub.label}'", sub.position)
} }
block.children.remove(sub) block.children.remove(sub)
irprog.st.removeTree(sub.label) irprog.st.removeTree(sub.label)
@ -82,7 +82,7 @@ class IRUnusedCodeRemover(
block.children.filterIsInstance<IRAsmSubroutine>().reversed().forEach { sub -> block.children.filterIsInstance<IRAsmSubroutine>().reversed().forEach { sub ->
if(sub.isEmpty()) { if(sub.isEmpty()) {
if(!block.options.ignoreUnused) { if(!block.options.ignoreUnused) {
errors.warn("unused subroutine '${sub.label}'", sub.position) errors.info("unused subroutine '${sub.label}'", sub.position)
} }
block.children.remove(sub) block.children.remove(sub)
irprog.st.removeTree(sub.label) 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): internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors: Boolean=true, private val keepMessagesAfterReporting: Boolean=false): IErrorReporter {
IErrorReporter {
val errors = mutableListOf<String>() val errors = mutableListOf<String>()
val warnings = mutableListOf<String>() val warnings = mutableListOf<String>()
val infos = mutableListOf<String>()
override fun err(msg: String, position: Position) { override fun err(msg: String, position: Position) {
val text = "${position.toClickableStr()} $msg" val text = "${position.toClickableStr()} $msg"
@ -45,6 +45,12 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
warnings.add(text) 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) { override fun undefined(symbol: List<String>, position: Position) {
err("undefined symbol: ${symbol.joinToString(".")}", 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 noErrors(): Boolean = errors.isEmpty()
override fun report() { override fun report() {
infos.forEach { println("UNITTEST COMPILATION REPORT: INFO: $it") }
warnings.forEach { println("UNITTEST COMPILATION REPORT: WARNING: $it") } warnings.forEach { println("UNITTEST COMPILATION REPORT: WARNING: $it") }
errors.forEach { println("UNITTEST COMPILATION REPORT: ERROR: $it") } errors.forEach { println("UNITTEST COMPILATION REPORT: ERROR: $it") }
if(throwExceptionAtReportIfErrors) if(throwExceptionAtReportIfErrors)
finalizeNumErrors(errors.size, warnings.size) finalizeNumErrors(errors.size, warnings.size, infos.size)
if(!keepMessagesAfterReporting) { if(!keepMessagesAfterReporting) {
clear() clear()
} }
@ -64,5 +71,6 @@ internal class ErrorReporterForTests(private val throwExceptionAtReportIfErrors:
fun clear() { fun clear() {
errors.clear() errors.clear()
warnings.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> { override fun after(forLoop: ForLoop, parent: Node): Iterable<IAstModification> {
if(forLoop.body.isEmpty()) { 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)) return listOf(IAstModification.Remove(forLoop, parent as IStatementContainer))
} else if(forLoop.body.statements.size==1) { } else if(forLoop.body.statements.size==1) {
val loopvar = forLoop.body.statements[0] as? VarDecl val loopvar = forLoop.body.statements[0] as? VarDecl
@ -287,7 +287,7 @@ class StatementOptimizer(private val program: Program,
val iter = repeatLoop.iterations val iter = repeatLoop.iterations
if(iter!=null) { if(iter!=null) {
if(repeatLoop.body.isEmpty()) { 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)) return listOf(IAstModification.Remove(repeatLoop, parent as IStatementContainer))
} }
val iterations = iter.constValue(program)?.number?.toInt() 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> { fun replaceWithIf(condition: Expression, trueBlock: AnonymousScope, elseBlock: AnonymousScope?): List<IAstModification> {
val ifStmt = IfElse(condition, trueBlock, elseBlock ?: AnonymousScope(mutableListOf(), whenStmt.position), whenStmt.position) 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)) return listOf(IAstModification.ReplaceNode(whenStmt, ifStmt, parent))
} }

View File

@ -60,14 +60,14 @@ class UnusedCodeRemover(private val program: Program,
if (block.containsNoCodeNorVars) { if (block.containsNoCodeNorVars) {
if(block.name != internedStringsModuleName) { if(block.name != internedStringsModuleName) {
if(!block.statements.any { it is Subroutine && it.hasBeenInlined }) 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)) return listOf(IAstModification.Remove(block, parent as IStatementContainer))
} }
if(callgraph.unused(block)) { if(callgraph.unused(block)) {
if(block.statements.any{ it !is VarDecl || it.type== VarDeclType.VAR}) { if(block.statements.any{ it !is VarDecl || it.type== VarDeclType.VAR}) {
if(!block.statements.any { it is Subroutine && it.hasBeenInlined }) 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 }) { if(!block.statements.any { it is Subroutine && it.hasBeenInlined }) {
program.removeInternedStringsFromRemovedBlock(block) program.removeInternedStringsFromRemovedBlock(block)
@ -85,7 +85,7 @@ class UnusedCodeRemover(private val program: Program,
if(callgraph.unused(subroutine)) { if(callgraph.unused(subroutine)) {
if(subroutine.containsNoCodeNorVars) { if(subroutine.containsNoCodeNorVars) {
if("ignore_unused" !in subroutine.definingBlock.options()) 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)) val removals = mutableListOf(IAstModification.Remove(subroutine, parent as IStatementContainer))
callgraph.calledBy[subroutine]?.let { callgraph.calledBy[subroutine]?.let {
for(node in it) for(node in it)
@ -94,7 +94,7 @@ class UnusedCodeRemover(private val program: Program,
return removals return removals
} }
if(!subroutine.hasBeenInlined && "ignore_unused" !in subroutine.definingBlock.options()) { 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) { if(!subroutine.inline) {
program.removeInternedStringsFromRemovedSubroutine(subroutine) program.removeInternedStringsFromRemovedSubroutine(subroutine)
@ -114,7 +114,7 @@ class UnusedCodeRemover(private val program: Program,
val usages = callgraph.usages(decl) val usages = callgraph.usages(decl)
if (usages.isEmpty()) { if (usages.isEmpty()) {
if("ignore_unused" !in decl.definingBlock.options()) 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)) return listOf(IAstModification.Remove(decl, parent as IStatementContainer))
} }
else { else {
@ -130,7 +130,7 @@ class UnusedCodeRemover(private val program: Program,
if (singleAssignment!=null && reads.isNotEmpty()) { if (singleAssignment!=null && reads.isNotEmpty()) {
if (singleAssignment.origin == AssignmentOrigin.VARINIT && singleAssignment.value.constValue(program) != null) { 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 // 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) 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( return listOf(
IAstModification.ReplaceNode(decl, const, parent), IAstModification.ReplaceNode(decl, const, parent),
@ -156,7 +156,7 @@ class UnusedCodeRemover(private val program: Program,
if(assignment.value.isSimple) { if(assignment.value.isSimple) {
// remove the vardecl // remove the vardecl
if("ignore_unused" !in decl.definingBlock.options()) 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( return listOf(
IAstModification.Remove(decl, parent as IStatementContainer), IAstModification.Remove(decl, parent as IStatementContainer),
IAstModification.Remove(assignment, assignment.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 declIndex = (parent as IStatementContainer).statements.indexOf(decl)
val singleUseIndex = (parent as IStatementContainer).statements.indexOf(singleUse.parent) val singleUseIndex = (parent as IStatementContainer).statements.indexOf(singleUse.parent)
if(declIndex==singleUseIndex-1) { 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 fcall = assignment.value as IFunctionCall
val voidCall = FunctionCallStatement(fcall.target, fcall.args, true, fcall.position) val voidCall = FunctionCallStatement(fcall.target, fcall.args, true, fcall.position)
return listOf( return listOf(
@ -178,7 +178,7 @@ class UnusedCodeRemover(private val program: Program,
} }
} }
} else { } 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_GROUP = "prog8"
const val MAVEN_NAME = "compiler" const val MAVEN_NAME = "compiler"
const val VERSION = "9.8-SNAPSHOT" const val VERSION = "9.8-SNAPSHOT"
const val GIT_REVISION = 4287 const val GIT_REVISION = 4335
const val GIT_SHA = "08a079a96e67c26298b81de2d35919be51a3dfd0" const val GIT_SHA = "44d82f9190763aa5113a3dce4a7d4623018a1c25"
const val GIT_DATE = "2023-12-11T20:15:48Z" const val GIT_DATE = "2023-12-28T12:30:07Z"
const val GIT_BRANCH = "no-vardecls" const val GIT_BRANCH = "master"
const val BUILD_DATE = "2023-12-11T21:48:14Z" const val BUILD_DATE = "2023-12-28T12:44:26Z"
const val BUILD_UNIX_TIME = 1702331294381L const val BUILD_UNIX_TIME = 1703767466828L
const val DIRTY = 1 const val DIRTY = 1

View File

@ -6,6 +6,7 @@ import prog8.code.core.Position
internal class ErrorReporter: IErrorReporter { internal class ErrorReporter: IErrorReporter {
private enum class MessageSeverity { private enum class MessageSeverity {
INFO,
WARNING, WARNING,
ERROR ERROR
} }
@ -20,6 +21,9 @@ internal class ErrorReporter: IErrorReporter {
override fun warn(msg: String, position: Position) { override fun warn(msg: String, position: Position) {
messages.add(CompilerMessage(MessageSeverity.WARNING, msg, 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) { override fun undefined(symbol: List<String>, position: Position) {
err("undefined symbol: ${symbol.joinToString(".")}", position) err("undefined symbol: ${symbol.joinToString(".")}", position)
@ -28,29 +32,37 @@ internal class ErrorReporter: IErrorReporter {
override fun report() { override fun report() {
var numErrors = 0 var numErrors = 0
var numWarnings = 0 var numWarnings = 0
var numInfos = 0
messages.forEach { messages.forEach {
val printer = when(it.severity) { val printer = when(it.severity) {
MessageSeverity.INFO -> System.out
MessageSeverity.WARNING -> System.out MessageSeverity.WARNING -> System.out
MessageSeverity.ERROR -> System.err MessageSeverity.ERROR -> System.err
} }
val msg = "${it.position.toClickableStr()} ${it.message}".trim() val msg = "${it.position.toClickableStr()} ${it.message}".trim()
if(msg !in alreadyReportedMessages) { if(msg !in alreadyReportedMessages) {
when(it.severity) { when(it.severity) {
MessageSeverity.ERROR -> printer.print("\u001b[91mERROR\u001B[0m ") // bright red MessageSeverity.ERROR -> {
MessageSeverity.WARNING -> printer.print("\u001b[93mWARN\u001B[0m ") // bright yellow 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) printer.println(msg)
alreadyReportedMessages.add(msg) alreadyReportedMessages.add(msg)
when(it.severity) {
MessageSeverity.WARNING -> numWarnings++
MessageSeverity.ERROR -> numErrors++
}
} }
} }
System.out.flush() System.out.flush()
System.err.flush() System.err.flush()
messages.clear() messages.clear()
finalizeNumErrors(numErrors, numWarnings) finalizeNumErrors(numErrors, numWarnings, numInfos)
} }
override fun noErrors() = messages.none { it.severity==MessageSeverity.ERROR } 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 (expectedReturnValues[0] != valueDt.getOr(DataType.UNDEFINED)) {
if(valueDt istype DataType.BOOL && expectedReturnValues[0] == DataType.UBYTE) { 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. // 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) { } 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 // 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 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 try { // just *try* if it can be encoded, don't actually do it
val bytes = compilerOptions.compTarget.encodeString(string.value, string.encoding) val bytes = compilerOptions.compTarget.encodeString(string.value, string.encoding)
if(0u in bytes) 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) { } catch (cx: CharConversionException) {
errors.err(cx.message ?: "can't encode string", string.position) errors.err(cx.message ?: "can't encode string", string.position)
} }
@ -1187,14 +1187,14 @@ internal class AstChecker(private val program: Program,
when(targetStatement) { when(targetStatement) {
is BuiltinFunctionPlaceholder -> { is BuiltinFunctionPlaceholder -> {
if(!builtinFunctionReturnType(targetStatement.name).isKnown) if(!builtinFunctionReturnType(targetStatement.name).isKnown)
errors.warn("redundant void", functionCallStatement.position) errors.info("redundant void", functionCallStatement.position)
} }
is Label -> { is Label -> {
errors.warn("redundant void", functionCallStatement.position) errors.info("redundant void", functionCallStatement.position)
} }
is Subroutine -> { is Subroutine -> {
if(targetStatement.returntypes.isEmpty()) if(targetStatement.returntypes.isEmpty())
errors.warn("redundant void", functionCallStatement.position) errors.info("redundant void", functionCallStatement.position)
} }
else -> {} else -> {}
} }
@ -1745,13 +1745,13 @@ internal fun checkUnusedReturnValues(call: FunctionCallStatement, target: Statem
// check for unused return values // check for unused return values
if (target is Subroutine && target.returntypes.isNotEmpty()) { if (target is Subroutine && target.returntypes.isNotEmpty()) {
if (target.returntypes.size == 1) 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 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) { } else if (target is BuiltinFunctionPlaceholder) {
val rt = builtinFunctionReturnType(target.name) val rt = builtinFunctionReturnType(target.name)
if (rt.isKnown) 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) { if(value==null) {
val blockOptions = srcVar.definingBlock.options() val blockOptions = srcVar.definingBlock.options()
if("align_page" in blockOptions || "align_word" in blockOptions) { 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) val zeros = PtArray(srcVar.datatype, srcVar.position)
repeat(srcVar.arraysize!!.constIndex()!!) { repeat(srcVar.arraysize!!.constIndex()!!) {
zeros.children.add(PtNumber(ArrayToElementTypes.getValue(srcVar.datatype), 0.0, srcVar.position)) 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> { override fun after(containment: ContainmentCheck, parent: Node): Iterable<IAstModification> {
// replace trivial containment checks with just false or a single comparison // replace trivial containment checks with just false or a single comparison
fun replaceWithEquals(value: NumericLiteral): Iterable<IAstModification> { 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) val equals = BinaryExpression(containment.element, "==", value, containment.position)
return listOf(IAstModification.ReplaceNode(containment, equals, parent)) 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> { override fun after(branch: ConditionalBranch, parent: Node): Iterable<IAstModification> {
if(branch.truepart.isEmpty() && branch.elsepart.isEmpty()) { 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)) 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> { override fun after(ifElse: IfElse, parent: Node): Iterable<IAstModification> {
if(ifElse.truepart.isEmpty() && ifElse.elsepart.isEmpty()) { 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 listOf(IAstModification.Remove(ifElse, parent as IStatementContainer))
} }
return noModifications return noModifications

View File

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

View File

@ -2,9 +2,6 @@
TODO 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 .... - [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
... ...