1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-10-01 07:59:30 +00:00

Improve error reporting

This commit is contained in:
Karol Stasiak 2018-12-19 18:14:11 +01:00
parent 960cee5124
commit 1e9be50ccb
3 changed files with 35 additions and 8 deletions

View File

@ -61,11 +61,8 @@ abstract class AbstractStatementPreprocessor(ctx: CompilationContext, statements
val pos = stmt.position val pos = stmt.position
// generic warnings: // generic warnings:
stmt match { stmt match {
case ExpressionStatement(expr@FunctionCallExpression("strzlen" | "putstrz", List(TextLiteralExpression(ch)))) => case ExpressionStatement(expr@FunctionCallExpression("strzlen" | "putstrz" | "strzcmp" | "strzcopy", params)) =>
ch.last match { for (param <- params) checkIfNullTerminated(stmt, param)
case LiteralExpression(0, _) => //ok
case _ => ctx.log.warn("Passing a non-null-terminated string to a function that expects a null-terminated string.", stmt.position)
}
case ExpressionStatement(VariableExpression(v)) => case ExpressionStatement(VariableExpression(v)) =>
val volatile = ctx.env.maybeGet[ThingInMemory](v).fold(false)(_.isVolatile) val volatile = ctx.env.maybeGet[ThingInMemory](v).fold(false)(_.isVolatile)
if (!volatile) ctx.log.warn("Pointless expression.", stmt.position) if (!volatile) ctx.log.warn("Pointless expression.", stmt.position)
@ -133,6 +130,17 @@ abstract class AbstractStatementPreprocessor(ctx: CompilationContext, statements
} }
} }
private def checkIfNullTerminated(stmt: ExecutableStatement, param: Expression): Unit = {
param match {
case TextLiteralExpression(ch) =>
ch.last match {
case LiteralExpression(0, _) => //ok
case _ => ctx.log.warn("Passing a non-null-terminated string to a function that expects a null-terminated string.", stmt.position)
}
case _ =>
}
}
def search(expr: Expression, cv: VV): VV = { def search(expr: Expression, cv: VV): VV = {
expr match { expr match {
case FunctionCallExpression(op, List(VariableExpression(v), arg)) if op.endsWith("=") && op != "<=" && op != ">=" => case FunctionCallExpression(op, List(VariableExpression(v), arg)) if op.endsWith("=") && op != "<=" && op != ">=" =>

View File

@ -613,7 +613,7 @@ object BuiltIns {
AssemblyLine.variable(ctx, CMP, rva, 0)) AssemblyLine.variable(ctx, CMP, rva, 0))
case _ => case _ =>
// TODO comparing expressions // TODO comparing expressions
ctx.log.error("Too complex expressions in comparison", lhs.position) ctx.log.error("Too complex expressions in comparison", lhs.position.orElse(rhs.position))
(Nil, Nil, Nil, Nil) (Nil, Nil, Nil, Nil)
} }
val lType = MosExpressionCompiler.getExpressionType(ctx, lhs) val lType = MosExpressionCompiler.getExpressionType(ctx, lhs)

View File

@ -798,7 +798,26 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
case e: ExecutableStatement => Some(e) case e: ExecutableStatement => Some(e)
case _ => None case _ => None
} }
val needsExtraRTS = !stmt.isMacro && !stmt.assembly && (statements.isEmpty || !statements.last.isInstanceOf[ReturnStatement]) val paramForAutomaticReturn: List[Option[Expression]] = if (stmt.isMacro || stmt.assembly) {
Nil
} else if (statements.isEmpty) {
List(None)
} else {
statements.last match {
case _: ReturnStatement => Nil
case WhileStatement(VariableExpression(tr), _, _, _) =>
if (resultType.size > 0 && env.getBooleanConstant(tr).contains(true)) {
List(Some(LiteralExpression(0, 1))) // TODO: what if the loop is breakable?
} else List(None)
case DoWhileStatement(_, _, VariableExpression(tr), _) =>
if (resultType.size > 0 && env.getBooleanConstant(tr).contains(true)) {
List(Some(LiteralExpression(0, 1))) // TODO: what if the loop is breakable?
} else List(None)
case _ =>
// None so the compiler warns
List(None)
}
}
if (stmt.isMacro) { if (stmt.isMacro) {
if (stmt.bank.isDefined) { if (stmt.bank.isDefined) {
log.error("Macro functions cannot be in a defined segment", stmt.position) log.error("Macro functions cannot be in a defined segment", stmt.position)
@ -823,7 +842,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
env, env,
stackVariablesSize, stackVariablesSize,
stmt.address.map(a => this.eval(a).getOrElse(errorConstant(s"Address of `${stmt.name}` is not a constant"))), stmt.address.map(a => this.eval(a).getOrElse(errorConstant(s"Address of `${stmt.name}` is not a constant"))),
executableStatements ++ (if (needsExtraRTS) List(ReturnStatement(None).pos(executableStatements.lastOption.fold(stmt.position)(_.position))) else Nil), executableStatements ++ paramForAutomaticReturn.map(param => ReturnStatement(param).pos(executableStatements.lastOption.fold(stmt.position)(_.position))),
interrupt = stmt.interrupt, interrupt = stmt.interrupt,
kernalInterrupt = stmt.kernalInterrupt, kernalInterrupt = stmt.kernalInterrupt,
reentrant = stmt.reentrant, reentrant = stmt.reentrant,