mirror of
https://github.com/KarolS/millfork.git
synced 2024-11-18 22:07:07 +00:00
Improve error reporting
This commit is contained in:
parent
960cee5124
commit
1e9be50ccb
@ -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 != ">=" =>
|
||||||
|
@ -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)
|
||||||
|
23
src/main/scala/millfork/env/Environment.scala
vendored
23
src/main/scala/millfork/env/Environment.scala
vendored
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user