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:
parent
7092f2a5de
commit
12df1ef6e4
@ -204,7 +204,7 @@ class AbstractExpressionCompiler[T <: AbstractCode] {
|
|||||||
}
|
}
|
||||||
val sourceType = getExpressionType(ctx, params.head)
|
val sourceType = getExpressionType(ctx, params.head)
|
||||||
if (typ.size != sourceType.size && !sourceType.isAssignableTo(typ)) {
|
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
|
failed = true
|
||||||
}
|
}
|
||||||
sourceType
|
sourceType
|
||||||
|
@ -495,11 +495,11 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
|
|||||||
case (minus, arg) => minus -> optimizeExpr(arg, currentVarValues)
|
case (minus, arg) => minus -> optimizeExpr(arg, currentVarValues)
|
||||||
}.filterNot{
|
}.filterNot{
|
||||||
case (_, e) => env.eval(e).exists(_.isProvablyZero)
|
case (_, e) => env.eval(e).exists(_.isProvablyZero)
|
||||||
}, decimal = false)
|
}, decimal = false).pos(pos)
|
||||||
case SumExpression(expressions, decimal) =>
|
case SumExpression(expressions, decimal) =>
|
||||||
// don't collapse additions, let the later stages deal with it
|
// don't collapse additions, let the later stages deal with it
|
||||||
// expecially important when inside a nonet operation
|
// 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) =>
|
case IndexedExpression(name, index) =>
|
||||||
val pointy = env.getPointy(name)
|
val pointy = env.getPointy(name)
|
||||||
val targetType = pointy.elementType
|
val targetType = pointy.elementType
|
||||||
|
@ -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.compiler.{AbstractExpressionCompiler, BranchIfFalse, BranchIfTrue, BranchSpec, ComparisonType, CompilationContext, NoBranching}
|
||||||
import millfork.node.{DerefExpression, Expression, FunctionCallExpression, GeneratedConstantExpression, IndexedExpression, LhsExpression, LiteralExpression, M6809Register, SumExpression, VariableExpression}
|
import millfork.node.{DerefExpression, Expression, FunctionCallExpression, GeneratedConstantExpression, IndexedExpression, LhsExpression, LiteralExpression, M6809Register, SumExpression, VariableExpression}
|
||||||
import millfork.assembly.m6809.MOpcode._
|
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
|
import scala.collection.GenTraversableOnce
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ import MExpressionTarget.toLd
|
|||||||
|
|
||||||
object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
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 env = ctx.env
|
||||||
val exprType = getExpressionType(ctx, expr)
|
val exprType = getExpressionType(ctx, expr)
|
||||||
val targetSize = MExpressionTarget.size(target)
|
val targetSize = MExpressionTarget.size(target)
|
||||||
@ -466,6 +466,10 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
|||||||
}
|
}
|
||||||
case _ => ???
|
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)
|
def compileToA(ctx: CompilationContext, expr: Expression): List[MLine] = compile(ctx, expr, MExpressionTarget.A)
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
package millfork.compiler.mos
|
package millfork.compiler.mos
|
||||||
|
|
||||||
import millfork.{CompilationFlag, env}
|
import millfork.CompilationFlag
|
||||||
import millfork.assembly.Elidability
|
import millfork.assembly.Elidability
|
||||||
import millfork.assembly.mos.AddrMode._
|
import millfork.assembly.mos.AddrMode._
|
||||||
import millfork.assembly.mos.Opcode._
|
import millfork.assembly.mos.Opcode._
|
||||||
import millfork.assembly.mos._
|
import millfork.assembly.mos._
|
||||||
import millfork.assembly.z80.ZLine
|
|
||||||
import millfork.compiler._
|
import millfork.compiler._
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ConsoleLogger
|
|
||||||
import millfork.node.{MosRegister, _}
|
import millfork.node.{MosRegister, _}
|
||||||
import millfork.output.NoAlignment
|
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 env = ctx.env
|
||||||
val b = env.get[Type]("byte")
|
val b = env.get[Type]("byte")
|
||||||
val exprType = AbstractExpressionCompiler.getExpressionType(ctx, expr)
|
val exprType = AbstractExpressionCompiler.getExpressionType(ctx, expr)
|
||||||
@ -1781,6 +1779,10 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
calculate ++ compile(ctx, VariableExpression(resultVariable), exprTypeAndVariable, branches)
|
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,
|
private def compileTransitiveRelation(ctx: CompilationContext,
|
||||||
|
2
src/main/scala/millfork/env/Constant.scala
vendored
2
src/main/scala/millfork/env/Constant.scala
vendored
@ -204,7 +204,7 @@ case class UnexpandedConstant(name: String, requiredSize: Int) extends Constant
|
|||||||
case class NumericConstant(value: Long, requiredSize: Int) extends Constant {
|
case class NumericConstant(value: Long, requiredSize: Int) extends Constant {
|
||||||
if (requiredSize == 1) {
|
if (requiredSize == 1) {
|
||||||
if (value < -128 || value > 255) {
|
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
|
override def isQuiteNegative: Boolean = value < 0
|
||||||
|
31
src/main/scala/millfork/env/Environment.scala
vendored
31
src/main/scala/millfork/env/Environment.scala
vendored
@ -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)
|
log.warn(s"Alias `$name` is deprecated, use `$target` instead", position)
|
||||||
}
|
}
|
||||||
root.get[T](target)
|
root.get[T](target)
|
||||||
case _ => log.fatal(s"`$name` is not a ${clazz.getSimpleName}", position)
|
case _ => throw IdentifierHasWrongTypeOfThingException(clazz, name, position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else parent.fold {
|
} else parent.fold {
|
||||||
hintTypo(name)
|
hintTypo(name)
|
||||||
log.fatal(s"${clazz.getSimpleName} `$name` is not defined", position)
|
throw UndefinedIdentifierException(clazz, name, position)
|
||||||
} {
|
} {
|
||||||
_.get[T](name, position)
|
_.get[T](name, position)
|
||||||
}
|
}
|
||||||
@ -604,7 +604,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
|||||||
case VariableExpression(name) =>
|
case VariableExpression(name) =>
|
||||||
maybeGet[Thing](name) match {
|
maybeGet[Thing](name) match {
|
||||||
case None =>
|
case None =>
|
||||||
log.error(s"`$name` is not defined")
|
log.error(s"`$name` is not defined", expr.position)
|
||||||
hintTypo(name)
|
hintTypo(name)
|
||||||
1
|
1
|
||||||
case Some(thing) => thing match {
|
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)
|
def eval(e: Expression): Option[Constant] = evalImpl(e, None)
|
||||||
|
|
||||||
//noinspection ScalaUnnecessaryParentheses,ZeroIndexToHead
|
//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 {
|
e match {
|
||||||
case LiteralExpression(value, size) => Some(NumericConstant(value, size))
|
case LiteralExpression(value, size) => Some(NumericConstant(value, size))
|
||||||
case tl:TextLiteralExpression => Some(getPointy(getTextLiteralArrayName(tl)).asInstanceOf[ConstantPointy].value)
|
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 = {
|
def debugConstness(item: Expression): Unit = {
|
||||||
if (!log.debugEnabled) return
|
if (!log.debugEnabled) return
|
||||||
@ -1996,11 +2000,18 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
|||||||
fixStructFields()
|
fixStructFields()
|
||||||
val pointies = collectPointies(program.declarations)
|
val pointies = collectPointies(program.declarations)
|
||||||
pointiesUsed("") = pointies
|
pointiesUsed("") = pointies
|
||||||
program.declarations.foreach {
|
program.declarations.foreach { decl =>
|
||||||
case f: FunctionDeclarationStatement => registerFunction(f, options)
|
try {
|
||||||
case v: VariableDeclarationStatement => registerVariable(v, options, pointies(v.name))
|
decl match {
|
||||||
case a: ArrayDeclarationStatement => registerArray(a, options)
|
case f: FunctionDeclarationStatement => registerFunction(f, options)
|
||||||
case _ =>
|
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()
|
expandAliases()
|
||||||
if (options.zpRegisterSize > 0 && !things.contains("__reg")) {
|
if (options.zpRegisterSize > 0 && !things.contains("__reg")) {
|
||||||
|
28
src/main/scala/millfork/env/NonFatalCompilationException.scala
vendored
Normal file
28
src/main/scala/millfork/env/NonFatalCompilationException.scala
vendored
Normal 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}") {
|
||||||
|
|
||||||
|
}
|
@ -2,7 +2,7 @@ package millfork.test
|
|||||||
|
|
||||||
import millfork.Cpu
|
import millfork.Cpu
|
||||||
import millfork.env.{BasicPlainType, DerivedPlainType, NumericConstant}
|
import millfork.env.{BasicPlainType, DerivedPlainType, NumericConstant}
|
||||||
import millfork.test.emu.EmuUnoptimizedCrossPlatformRun
|
import millfork.test.emu.{EmuUnoptimizedCrossPlatformRun, ShouldNotCompile}
|
||||||
import org.scalatest.{FunSuite, Matchers}
|
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(0x7f, 2).isProvablyNegative(signed(2)) should be(false)
|
||||||
NumericConstant(-1, 8).isProvablyNegative(signed(8)) should be(true)
|
NumericConstant(-1, 8).isProvablyNegative(signed(8)) should be(true)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
test ("Overflow errors should be nice") {
|
||||||
|
ShouldNotCompile(
|
||||||
|
"""
|
||||||
|
|word sum
|
||||||
|
|void main() {
|
||||||
|
| sum = 246 + 18
|
||||||
|
|}
|
||||||
|
|""".stripMargin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user