1
0
mirror of https://github.com/KarolS/millfork.git synced 2025-01-12 03:30:09 +00:00

Make less compilation errors fatal, improve error reporting (relates to #16)

This commit is contained in:
Karol Stasiak 2019-10-31 12:14:52 +01:00
parent 7092f2a5de
commit 12df1ef6e4
8 changed files with 77 additions and 22 deletions

View File

@ -204,7 +204,7 @@ class AbstractExpressionCompiler[T <: AbstractCode] {
}
val sourceType = getExpressionType(ctx, params.head)
if (typ.size != sourceType.size && !sourceType.isAssignableTo(typ)) {
ctx.log.error("Cannot cast a type to an incompatible type of different size")
ctx.log.error(s"Cannot cast a type ${sourceType.name} to an incompatible type ${typ.name} of different size", params.head.position)
failed = true
}
sourceType

View File

@ -495,11 +495,11 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
case (minus, arg) => minus -> optimizeExpr(arg, currentVarValues)
}.filterNot{
case (_, e) => env.eval(e).exists(_.isProvablyZero)
}, decimal = false)
}, decimal = false).pos(pos)
case SumExpression(expressions, decimal) =>
// don't collapse additions, let the later stages deal with it
// expecially important when inside a nonet operation
SumExpression(expressions.map{case (minus, arg) => minus -> optimizeExpr(arg, currentVarValues)}, decimal)
SumExpression(expressions.map{case (minus, arg) => minus -> optimizeExpr(arg, currentVarValues)}, decimal).pos(pos)
case IndexedExpression(name, index) =>
val pointy = env.getPointy(name)
val targetType = pointy.elementType

View File

@ -4,7 +4,7 @@ import millfork.assembly.m6809.{DAccumulatorIndexed, Indexed, MLine, MOpcode, Tw
import millfork.compiler.{AbstractExpressionCompiler, BranchIfFalse, BranchIfTrue, BranchSpec, ComparisonType, CompilationContext, NoBranching}
import millfork.node.{DerefExpression, Expression, FunctionCallExpression, GeneratedConstantExpression, IndexedExpression, LhsExpression, LiteralExpression, M6809Register, SumExpression, VariableExpression}
import millfork.assembly.m6809.MOpcode._
import millfork.env.{AssemblyParamSignature, Constant, ConstantBooleanType, ConstantPointy, ExternFunction, FatBooleanType, FunctionInMemory, FunctionPointerType, M6809RegisterVariable, MacroFunction, MathOperator, MemoryVariable, NormalFunction, NormalParamSignature, NumericConstant, StackVariablePointy, ThingInMemory, Type, Variable, VariableInMemory, VariablePointy}
import millfork.env.{AssemblyParamSignature, Constant, ConstantBooleanType, ConstantPointy, ExternFunction, FatBooleanType, FunctionInMemory, FunctionPointerType, M6809RegisterVariable, MacroFunction, MathOperator, MemoryVariable, NonFatalCompilationException, NormalFunction, NormalParamSignature, NumericConstant, StackVariablePointy, ThingInMemory, Type, Variable, VariableInMemory, VariablePointy}
import scala.collection.GenTraversableOnce
@ -43,7 +43,7 @@ import MExpressionTarget.toLd
object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
def compile(ctx: CompilationContext, expr: Expression, target: MExpressionTarget.Value, branches: BranchSpec = BranchSpec.None): List[MLine] = {
def compile(ctx: CompilationContext, expr: Expression, target: MExpressionTarget.Value, branches: BranchSpec = BranchSpec.None): List[MLine] = try {
val env = ctx.env
val exprType = getExpressionType(ctx, expr)
val targetSize = MExpressionTarget.size(target)
@ -466,6 +466,10 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
}
case _ => ???
}
} catch {
case ex: NonFatalCompilationException =>
ctx.log.error(ex.getMessage, ex.position.orElse(expr.position))
Nil
}
def compileToA(ctx: CompilationContext, expr: Expression): List[MLine] = compile(ctx, expr, MExpressionTarget.A)

View File

@ -1,14 +1,12 @@
package millfork.compiler.mos
import millfork.{CompilationFlag, env}
import millfork.CompilationFlag
import millfork.assembly.Elidability
import millfork.assembly.mos.AddrMode._
import millfork.assembly.mos.Opcode._
import millfork.assembly.mos._
import millfork.assembly.z80.ZLine
import millfork.compiler._
import millfork.env._
import millfork.error.ConsoleLogger
import millfork.node.{MosRegister, _}
import millfork.output.NoAlignment
/**
@ -630,7 +628,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
}
}
def compile(ctx: CompilationContext, expr: Expression, exprTypeAndVariable: Option[(Type, Variable)], branches: BranchSpec): List[AssemblyLine] = {
def compile(ctx: CompilationContext, expr: Expression, exprTypeAndVariable: Option[(Type, Variable)], branches: BranchSpec): List[AssemblyLine] = try {
val env = ctx.env
val b = env.get[Type]("byte")
val exprType = AbstractExpressionCompiler.getExpressionType(ctx, expr)
@ -1781,6 +1779,10 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
calculate ++ compile(ctx, VariableExpression(resultVariable), exprTypeAndVariable, branches)
}
}
} catch {
case ex: ConstantOverflowException =>
ctx.log.error(ex.getMessage, ex.position.orElse(expr.position))
Nil
}
private def compileTransitiveRelation(ctx: CompilationContext,

View File

@ -204,7 +204,7 @@ case class UnexpandedConstant(name: String, requiredSize: Int) extends Constant
case class NumericConstant(value: Long, requiredSize: Int) extends Constant {
if (requiredSize == 1) {
if (value < -128 || value > 255) {
throw new IllegalArgumentException(s"The constant $value is too big")
throw ConstantOverflowException(value, requiredSize)
}
}
override def isQuiteNegative: Boolean = value < 0

View File

@ -313,12 +313,12 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
log.warn(s"Alias `$name` is deprecated, use `$target` instead", position)
}
root.get[T](target)
case _ => log.fatal(s"`$name` is not a ${clazz.getSimpleName}", position)
case _ => throw IdentifierHasWrongTypeOfThingException(clazz, name, position)
}
}
} else parent.fold {
hintTypo(name)
log.fatal(s"${clazz.getSimpleName} `$name` is not defined", position)
throw UndefinedIdentifierException(clazz, name, position)
} {
_.get[T](name, position)
}
@ -604,7 +604,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
case VariableExpression(name) =>
maybeGet[Thing](name) match {
case None =>
log.error(s"`$name` is not defined")
log.error(s"`$name` is not defined", expr.position)
hintTypo(name)
1
case Some(thing) => thing match {
@ -628,7 +628,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
def eval(e: Expression): Option[Constant] = evalImpl(e, None)
//noinspection ScalaUnnecessaryParentheses,ZeroIndexToHead
private def evalImpl(e: Expression, vv: Option[Map[String, Constant]]): Option[Constant] = {
private def evalImpl(e: Expression, vv: Option[Map[String, Constant]]): Option[Constant] = try{{
e match {
case LiteralExpression(value, size) => Some(NumericConstant(value, size))
case tl:TextLiteralExpression => Some(getPointy(getTextLiteralArrayName(tl)).asInstanceOf[ConstantPointy].value)
@ -796,7 +796,11 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
}
}
}
}.map(_.quickSimplify)
}.map(_.quickSimplify)} catch {
case ez:NonFatalCompilationException =>
log.error(ez.getMessage, e.position)
None
}
def debugConstness(item: Expression): Unit = {
if (!log.debugEnabled) return
@ -1996,12 +2000,19 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
fixStructFields()
val pointies = collectPointies(program.declarations)
pointiesUsed("") = pointies
program.declarations.foreach {
program.declarations.foreach { decl =>
try {
decl match {
case f: FunctionDeclarationStatement => registerFunction(f, options)
case v: VariableDeclarationStatement => registerVariable(v, options, pointies(v.name))
case a: ArrayDeclarationStatement => registerArray(a, options)
case _ =>
}
} catch {
case ex: NonFatalCompilationException =>
log.error(ex.getMessage, ex.position.orElse(decl.position))
}
}
expandAliases()
if (options.zpRegisterSize > 0 && !things.contains("__reg")) {
addThing(BasicPlainType("__reg$type", options.zpRegisterSize), None)

View File

@ -0,0 +1,28 @@
package millfork.env
import millfork.node.Position
/**
* @author Karol Stasiak
*/
abstract class NonFatalCompilationException(msg: String) extends RuntimeException(msg) {
def position: Option[Position]
}
case class ConstantOverflowException(value: Long, expectedSize: Int) extends NonFatalCompilationException (
if (expectedSize == 1) {
s"The constant $value is too big to fit in a byte"
} else {
s"The constant $value is too big to fit in $expectedSize bytes"
}
) {
override def position: Option[Position] = None
}
case class UndefinedIdentifierException(thingClass: Class[_], name: String, val position: Option[Position])
extends NonFatalCompilationException(s"${thingClass.getSimpleName} `$name` is not defined") {
}
case class IdentifierHasWrongTypeOfThingException(thingClass: Class[_], name: String, val position: Option[Position])
extends NonFatalCompilationException(s"`$name` is not a ${thingClass.getSimpleName}") {
}

View File

@ -2,7 +2,7 @@ package millfork.test
import millfork.Cpu
import millfork.env.{BasicPlainType, DerivedPlainType, NumericConstant}
import millfork.test.emu.EmuUnoptimizedCrossPlatformRun
import millfork.test.emu.{EmuUnoptimizedCrossPlatformRun, ShouldNotCompile}
import org.scalatest.{FunSuite, Matchers}
/**
@ -33,4 +33,14 @@ class ConstantSuite extends FunSuite with Matchers {
NumericConstant(0x7f, 2).isProvablyNegative(signed(2)) should be(false)
NumericConstant(-1, 8).isProvablyNegative(signed(8)) should be(true)
}
test ("Overflow errors should be nice") {
ShouldNotCompile(
"""
|word sum
|void main() {
| sum = 246 + 18
|}
|""".stripMargin)
}
}