mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
some WARN messages are now INFO
This commit is contained in:
parent
44d82f9190
commit
9c1b11d605
@ -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.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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 }
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 ....
|
||||||
|
|
||||||
...
|
...
|
||||||
|
Loading…
Reference in New Issue
Block a user