mirror of
https://github.com/KarolS/millfork.git
synced 2024-09-28 18:55:09 +00:00
Better type error reporting
This commit is contained in:
parent
89ff89bc48
commit
d1c0ad6b22
@ -14,11 +14,14 @@ class AbstractExpressionCompiler[T <: AbstractCode] {
|
|||||||
|
|
||||||
def getExpressionType(ctx: CompilationContext, expr: Expression): Type = AbstractExpressionCompiler.getExpressionType(ctx, expr)
|
def getExpressionType(ctx: CompilationContext, expr: Expression): Type = AbstractExpressionCompiler.getExpressionType(ctx, expr)
|
||||||
|
|
||||||
def assertAllArithmetic(ctx: CompilationContext,expressions: List[Expression]): Unit = {
|
def assertAllArithmetic(ctx: CompilationContext,expressions: List[Expression], booleanHint: String = ""): Unit = {
|
||||||
for(e <- expressions) {
|
for(e <- expressions) {
|
||||||
val typ = getExpressionType(ctx, e)
|
val typ = getExpressionType(ctx, e)
|
||||||
if (!typ.isArithmetic) {
|
if (!typ.isArithmetic) {
|
||||||
ctx.log.error(s"Cannot perform arithmetic operations on type `$typ`", e.position)
|
ctx.log.error(s"Cannot perform arithmetic operations on type `$typ`", e.position)
|
||||||
|
if (booleanHint != "" && typ.isBoollike) {
|
||||||
|
ctx.log.info(s"Did you mean: $booleanHint")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,8 +39,8 @@ class AbstractExpressionCompiler[T <: AbstractCode] {
|
|||||||
ctx.copy(env = result)
|
ctx.copy(env = result)
|
||||||
}
|
}
|
||||||
|
|
||||||
def getArithmeticParamMaxSize(ctx: CompilationContext, params: List[Expression]): Int = {
|
def getArithmeticParamMaxSize(ctx: CompilationContext, params: List[Expression], booleanHint: String = ""): Int = {
|
||||||
assertAllArithmetic(ctx, params)
|
assertAllArithmetic(ctx, params, booleanHint = booleanHint)
|
||||||
params.map(expr => getExpressionType(ctx, expr).size).max
|
params.map(expr => getExpressionType(ctx, expr).size).max
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,8 +162,8 @@ class AbstractExpressionCompiler[T <: AbstractCode] {
|
|||||||
getExpressionType(ctx, param) match {
|
getExpressionType(ctx, param) match {
|
||||||
case _: BooleanType =>
|
case _: BooleanType =>
|
||||||
case FatBooleanType =>
|
case FatBooleanType =>
|
||||||
case _=>
|
case t =>
|
||||||
ctx.log.fatal("Parameter should be boolean", param.position)
|
ctx.log.fatal(s"Parameter has type `${t.name}`, but it should be boolean", param.position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -429,6 +432,7 @@ object AbstractExpressionCompiler {
|
|||||||
}
|
}
|
||||||
case 3 => env.get[Type]("int24")
|
case 3 => env.get[Type]("int24")
|
||||||
case 4 => env.get[Type]("int32")
|
case 4 => env.get[Type]("int32")
|
||||||
|
case 0 => b
|
||||||
case _ => log.error("Adding values bigger than longs", expr.position); env.get[Type]("int32")
|
case _ => log.error("Adding values bigger than longs", expr.position); env.get[Type]("int32")
|
||||||
}
|
}
|
||||||
case FunctionCallExpression("nonet", _) => w
|
case FunctionCallExpression("nonet", _) => w
|
||||||
@ -470,14 +474,16 @@ object AbstractExpressionCompiler {
|
|||||||
case FunctionCallExpression("sin", params) => if (params.size < 2) b else getExpressionTypeImpl(env, log, params(1), loosely)
|
case FunctionCallExpression("sin", params) => if (params.size < 2) b else getExpressionTypeImpl(env, log, params(1), loosely)
|
||||||
case FunctionCallExpression("cos", params) => if (params.size < 2) b else getExpressionTypeImpl(env, log, params(1), loosely)
|
case FunctionCallExpression("cos", params) => if (params.size < 2) b else getExpressionTypeImpl(env, log, params(1), loosely)
|
||||||
case FunctionCallExpression("tan", params) => if (params.size < 2) b else getExpressionTypeImpl(env, log, params(1), loosely)
|
case FunctionCallExpression("tan", params) => if (params.size < 2) b else getExpressionTypeImpl(env, log, params(1), loosely)
|
||||||
case FunctionCallExpression("min" | "max", params) => if (params.isEmpty) b else params.map { e => getExpressionTypeImpl(env, log, e, loosely).size }.max match {
|
case FunctionCallExpression(name@("min" | "max"), params) => if (params.isEmpty) b else params.map { e => getExpressionTypeImpl(env, log, e, loosely).size }.max match {
|
||||||
case 1 => b
|
case 1 => b
|
||||||
case 2 => w
|
case 2 => w
|
||||||
|
case 0 => log.error(s"Invalid parameters to $name", expr.position); b
|
||||||
case n if n >= 3 => env.get[Type]("int" + n * 8)
|
case n if n >= 3 => env.get[Type]("int" + n * 8)
|
||||||
} // TODO: ?
|
} // TODO: ?
|
||||||
case FunctionCallExpression("if", params) => if (params.length < 3) b else params.tail.map { e => getExpressionTypeImpl(env, log, e, loosely).size }.max match {
|
case FunctionCallExpression("if", params) => if (params.length < 3) b else params.tail.map { e => getExpressionTypeImpl(env, log, e, loosely).size }.max match {
|
||||||
case 1 => b
|
case 1 => b
|
||||||
case 2 => w
|
case 2 => w
|
||||||
|
case 0 => log.error(s"Invalid parameters to if", expr.position); b
|
||||||
case n if n >= 3 => env.get[Type]("int" + n * 8)
|
case n if n >= 3 => env.get[Type]("int" + n * 8)
|
||||||
} // TODO: ?
|
} // TODO: ?
|
||||||
case FunctionCallExpression("sizeof", params) => env.evalSizeof(params.head).requiredSize match {
|
case FunctionCallExpression("sizeof", params) => env.evalSizeof(params.head).requiredSize match {
|
||||||
@ -487,10 +493,11 @@ object AbstractExpressionCompiler {
|
|||||||
case FunctionCallExpression("%%", params) => params.map { e => getExpressionTypeImpl(env, log, e, loosely).size } match {
|
case FunctionCallExpression("%%", params) => params.map { e => getExpressionTypeImpl(env, log, e, loosely).size } match {
|
||||||
case List(1, 1) | List(2, 1) => b
|
case List(1, 1) | List(2, 1) => b
|
||||||
case List(1, 2) | List(2, 2) => w
|
case List(1, 2) | List(2, 2) => w
|
||||||
|
case List(0, _) | List(_, 0) => b
|
||||||
case _ => log.error("Combining values bigger than words", expr.position); w
|
case _ => log.error("Combining values bigger than words", expr.position); w
|
||||||
}
|
}
|
||||||
case FunctionCallExpression("*" | "|" | "&" | "^" | "/", params) => params.map { e => getExpressionTypeImpl(env, log, e, loosely).size }.max match {
|
case FunctionCallExpression("*" | "|" | "&" | "^" | "/", params) => params.map { e => getExpressionTypeImpl(env, log, e, loosely).size }.max match {
|
||||||
case 1 => b
|
case 0 | 1 => b
|
||||||
case 2 => w
|
case 2 => w
|
||||||
case _ => log.error("Combining values bigger than words", expr.position); w
|
case _ => log.error("Combining values bigger than words", expr.position); w
|
||||||
}
|
}
|
||||||
|
@ -174,6 +174,10 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
|||||||
getArithmeticParamMaxSize(ctx, expressions.map(_._2)) match {
|
getArithmeticParamMaxSize(ctx, expressions.map(_._2)) match {
|
||||||
case 1 => M6809Buitins.compileByteSum(ctx, e, fromScratch = true) ++ targetifyB(ctx, target, isSigned = false)
|
case 1 => M6809Buitins.compileByteSum(ctx, e, fromScratch = true) ++ targetifyB(ctx, target, isSigned = false)
|
||||||
case 2 => M6809Buitins.compileWordSum(ctx, e, fromScratch = true) ++ targetifyD(ctx, target)
|
case 2 => M6809Buitins.compileWordSum(ctx, e, fromScratch = true) ++ targetifyD(ctx, target)
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Non-in-place addition or subtraction of variables larger than 2 bytes is not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case SeparateBytesExpression(hi, lo) =>
|
case SeparateBytesExpression(hi, lo) =>
|
||||||
val h = compile(ctx, hi, MExpressionTarget.A)
|
val h = compile(ctx, hi, MExpressionTarget.A)
|
||||||
@ -255,11 +259,19 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
|||||||
getArithmeticParamMaxSize(ctx, params) match {
|
getArithmeticParamMaxSize(ctx, params) match {
|
||||||
case 1 => M6809MulDiv.compileByteMultiplication(ctx, params, updateDerefX = false) ++ targetifyB(ctx, target, isSigned = false)
|
case 1 => M6809MulDiv.compileByteMultiplication(ctx, params, updateDerefX = false) ++ targetifyB(ctx, target, isSigned = false)
|
||||||
case 2 => M6809MulDiv.compileWordMultiplication(ctx, params, updateDerefX = false) ++ targetifyD(ctx, target)
|
case 2 => M6809MulDiv.compileWordMultiplication(ctx, params, updateDerefX = false) ++ targetifyD(ctx, target)
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Multiplication of variables larger than 2 bytes is not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "/" =>
|
case "/" =>
|
||||||
assertArithmeticBinary(ctx, params) match {
|
assertArithmeticBinary(ctx, params) match {
|
||||||
case (l, r, 1) => M6809MulDiv.compileByteDivision(ctx, Some(l), r, mod=false) ++ targetifyB(ctx, target, isSigned = false)
|
case (l, r, 1) => M6809MulDiv.compileByteDivision(ctx, Some(l), r, mod = false) ++ targetifyB(ctx, target, isSigned = false)
|
||||||
case (l, r, 2) => M6809MulDiv.compileWordDivision(ctx, Some(l), r, mod=false) ++ targetifyD(ctx, target)
|
case (l, r, 2) => M6809MulDiv.compileWordDivision(ctx, Some(l), r, mod = false) ++ targetifyD(ctx, target)
|
||||||
|
case (_, _, 0) => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Division of variables larger than 2 bytes is not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "%%" =>
|
case "%%" =>
|
||||||
assertArithmeticBinary(ctx, params) match {
|
assertArithmeticBinary(ctx, params) match {
|
||||||
@ -270,21 +282,37 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
|||||||
} else {
|
} else {
|
||||||
M6809MulDiv.compileWordDivision(ctx, Some(l), r, mod=true) ++ targetifyD(ctx, target)
|
M6809MulDiv.compileWordDivision(ctx, Some(l), r, mod=true) ++ targetifyD(ctx, target)
|
||||||
}
|
}
|
||||||
|
case (_, _, 0) => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Division of variables larger than 2 bytes is not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "&" =>
|
case "&" =>
|
||||||
getArithmeticParamMaxSize(ctx, params) match {
|
getArithmeticParamMaxSize(ctx, params, booleanHint = "&&") match {
|
||||||
case 1 => M6809Buitins.compileByteBitwise(ctx, params, fromScratch = true, ANDB, MathOperator.And, 0xff) ++ targetifyB(ctx, target, isSigned = false)
|
case 1 => M6809Buitins.compileByteBitwise(ctx, params, fromScratch = true, ANDB, MathOperator.And, 0xff) ++ targetifyB(ctx, target, isSigned = false)
|
||||||
case 2 => M6809Buitins.compileWordBitwise(ctx, params, fromScratch = true, ANDA, ANDB, MathOperator.And, 0xffff) ++ targetifyD(ctx, target)
|
case 2 => M6809Buitins.compileWordBitwise(ctx, params, fromScratch = true, ANDA, ANDB, MathOperator.And, 0xffff) ++ targetifyD(ctx, target)
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Non-in-place bit operations of variables larger than 2 bytes are not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "|" =>
|
case "|" =>
|
||||||
getArithmeticParamMaxSize(ctx, params) match {
|
getArithmeticParamMaxSize(ctx, params, booleanHint = "||") match {
|
||||||
case 1 => M6809Buitins.compileByteBitwise(ctx, params, fromScratch = true, ORB, MathOperator.Or, 0) ++ targetifyB(ctx, target, isSigned = false)
|
case 1 => M6809Buitins.compileByteBitwise(ctx, params, fromScratch = true, ORB, MathOperator.Or, 0) ++ targetifyB(ctx, target, isSigned = false)
|
||||||
case 2 => M6809Buitins.compileWordBitwise(ctx, params, fromScratch = true, ORA, ORB, MathOperator.Or, 0) ++ targetifyD(ctx, target)
|
case 2 => M6809Buitins.compileWordBitwise(ctx, params, fromScratch = true, ORA, ORB, MathOperator.Or, 0) ++ targetifyD(ctx, target)
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Non-in-place bit operations of variables larger than 2 bytes are not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "^" =>
|
case "^" =>
|
||||||
getArithmeticParamMaxSize(ctx, params) match {
|
getArithmeticParamMaxSize(ctx, params) match {
|
||||||
case 1 => M6809Buitins.compileByteBitwise(ctx, params, fromScratch = true, EORB, MathOperator.Exor, 0) ++ targetifyB(ctx, target, isSigned = false)
|
case 1 => M6809Buitins.compileByteBitwise(ctx, params, fromScratch = true, EORB, MathOperator.Exor, 0) ++ targetifyB(ctx, target, isSigned = false)
|
||||||
case 2 => M6809Buitins.compileWordBitwise(ctx, params, fromScratch = true, EORA, EORB, MathOperator.Exor, 0) ++ targetifyD(ctx, target)
|
case 2 => M6809Buitins.compileWordBitwise(ctx, params, fromScratch = true, EORA, EORB, MathOperator.Exor, 0) ++ targetifyD(ctx, target)
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Non-in-place bit operations of variables larger than 2 bytes are not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "&&" =>
|
case "&&" =>
|
||||||
assertBool(ctx, "&&", params)
|
assertBool(ctx, "&&", params)
|
||||||
@ -446,12 +474,20 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
|||||||
size match {
|
size match {
|
||||||
case 1 => compileAddressToX(ctx, l) ++ M6809MulDiv.compileByteDivision(ctx, None, r, mod=false)
|
case 1 => compileAddressToX(ctx, l) ++ M6809MulDiv.compileByteDivision(ctx, None, r, mod=false)
|
||||||
case 2 => compileAddressToX(ctx, l) ++ M6809MulDiv.compileWordDivision(ctx, None, r, mod=false)
|
case 2 => compileAddressToX(ctx, l) ++ M6809MulDiv.compileWordDivision(ctx, None, r, mod=false)
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Division of variables larger than 2 bytes is not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "%%=" =>
|
case "%%=" =>
|
||||||
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
|
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
|
||||||
size match {
|
size match {
|
||||||
case 1 => compileAddressToX(ctx, l) ++ M6809MulDiv.compileByteDivision(ctx, None, r, mod=true)
|
case 1 => compileAddressToX(ctx, l) ++ M6809MulDiv.compileByteDivision(ctx, None, r, mod=true)
|
||||||
case 2 => compileAddressToX(ctx, l) ++ M6809MulDiv.compileWordDivision(ctx, None, r, mod=true)
|
case 2 => compileAddressToX(ctx, l) ++ M6809MulDiv.compileWordDivision(ctx, None, r, mod=true)
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Division of variables larger than 2 bytes is not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "&=" =>
|
case "&=" =>
|
||||||
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
|
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
|
||||||
|
@ -1171,6 +1171,8 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
} else {
|
} else {
|
||||||
PseudoregisterBuiltIns.compileWordAdditionViaAX(ctx, exprTypeAndVariable, expr.position, params, decimal = decimal)
|
PseudoregisterBuiltIns.compileWordAdditionViaAX(ctx, exprTypeAndVariable, expr.position, params, decimal = decimal)
|
||||||
}
|
}
|
||||||
|
case 0 =>
|
||||||
|
Nil
|
||||||
case _ =>
|
case _ =>
|
||||||
ctx.log.error("Non-in-place addition or subtraction of variables larger than 2 bytes is not supported", expr.position)
|
ctx.log.error("Non-in-place addition or subtraction of variables larger than 2 bytes is not supported", expr.position)
|
||||||
Nil
|
Nil
|
||||||
@ -1382,11 +1384,15 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
}
|
}
|
||||||
case "^^" => ???
|
case "^^" => ???
|
||||||
case "&" =>
|
case "&" =>
|
||||||
getArithmeticParamMaxSize(ctx, params) match {
|
getArithmeticParamMaxSize(ctx, params, booleanHint = "&&") match {
|
||||||
case 1 =>
|
case 1 =>
|
||||||
zeroExtend = true
|
zeroExtend = true
|
||||||
BuiltIns.compileBitOps(AND, ctx, params)
|
BuiltIns.compileBitOps(AND, ctx, params)
|
||||||
case 2 => PseudoregisterBuiltIns.compileWordBitOpsToAX(ctx, params, AND)
|
case 2 => PseudoregisterBuiltIns.compileWordBitOpsToAX(ctx, params, AND)
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Non-in-place bit operations of variables larger than 2 bytes are not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "*" =>
|
case "*" =>
|
||||||
assertSizesForMultiplication(ctx, params, inPlace = false)
|
assertSizesForMultiplication(ctx, params, inPlace = false)
|
||||||
@ -1397,13 +1403,21 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
case 2 =>
|
case 2 =>
|
||||||
//noinspection ZeroIndexToHead
|
//noinspection ZeroIndexToHead
|
||||||
PseudoregisterBuiltIns.compileWordMultiplication(ctx, Some(params(0)), params(1), storeInRegLo = false)
|
PseudoregisterBuiltIns.compileWordMultiplication(ctx, Some(params(0)), params(1), storeInRegLo = false)
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Multiplication of variables larger than 2 bytes are not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "|" =>
|
case "|" =>
|
||||||
getArithmeticParamMaxSize(ctx, params) match {
|
getArithmeticParamMaxSize(ctx, params, booleanHint = "||") match {
|
||||||
case 1 =>
|
case 1 =>
|
||||||
zeroExtend = true
|
zeroExtend = true
|
||||||
BuiltIns.compileBitOps(ORA, ctx, params)
|
BuiltIns.compileBitOps(ORA, ctx, params)
|
||||||
case 2 => PseudoregisterBuiltIns.compileWordBitOpsToAX(ctx, params, ORA)
|
case 2 => PseudoregisterBuiltIns.compileWordBitOpsToAX(ctx, params, ORA)
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Non-in-place bit operations of variables larger than 2 bytes are not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "^" =>
|
case "^" =>
|
||||||
getArithmeticParamMaxSize(ctx, params) match {
|
getArithmeticParamMaxSize(ctx, params) match {
|
||||||
@ -1411,6 +1425,10 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
zeroExtend = true
|
zeroExtend = true
|
||||||
BuiltIns.compileBitOps(EOR, ctx, params)
|
BuiltIns.compileBitOps(EOR, ctx, params)
|
||||||
case 2 => PseudoregisterBuiltIns.compileWordBitOpsToAX(ctx, params, EOR)
|
case 2 => PseudoregisterBuiltIns.compileWordBitOpsToAX(ctx, params, EOR)
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Non-in-place bit operations of variables larger than 2 bytes are not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case ">>>>" =>
|
case ">>>>" =>
|
||||||
val (l, r, size) = assertArithmeticBinary(ctx, params)
|
val (l, r, size) = assertArithmeticBinary(ctx, params)
|
||||||
@ -1421,7 +1439,10 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
case 1 =>
|
case 1 =>
|
||||||
zeroExtend = true
|
zeroExtend = true
|
||||||
BuiltIns.compileShiftOps(LSR, ctx, l ,r)
|
BuiltIns.compileShiftOps(LSR, ctx, l ,r)
|
||||||
case _ => ???
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Non-in-place shifts of variables larger than 2 bytes is not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "<<" =>
|
case "<<" =>
|
||||||
val (l, r, size) = assertArithmeticBinary(ctx, params)
|
val (l, r, size) = assertArithmeticBinary(ctx, params)
|
||||||
@ -1431,6 +1452,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
BuiltIns.compileShiftOps(ASL, ctx, l, r)
|
BuiltIns.compileShiftOps(ASL, ctx, l, r)
|
||||||
case 2 =>
|
case 2 =>
|
||||||
BuiltIns.maybeCompileShiftFromByteToWord(ctx, l, r, left = true).getOrElse(PseudoregisterBuiltIns.compileWordShiftOps(left = true, ctx, l, r))
|
BuiltIns.maybeCompileShiftFromByteToWord(ctx, l, r, left = true).getOrElse(PseudoregisterBuiltIns.compileWordShiftOps(left = true, ctx, l, r))
|
||||||
|
case 0 => Nil
|
||||||
case _ =>
|
case _ =>
|
||||||
ctx.log.error("Long shift ops not supported", l.position)
|
ctx.log.error("Long shift ops not supported", l.position)
|
||||||
Nil
|
Nil
|
||||||
@ -1443,6 +1465,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
BuiltIns.compileShiftOps(LSR, ctx, l, r)
|
BuiltIns.compileShiftOps(LSR, ctx, l, r)
|
||||||
case 2 =>
|
case 2 =>
|
||||||
BuiltIns.maybeCompileShiftFromByteToWord(ctx, l, r, left = false).getOrElse(PseudoregisterBuiltIns.compileWordShiftOps(left = false, ctx, l, r))
|
BuiltIns.maybeCompileShiftFromByteToWord(ctx, l, r, left = false).getOrElse(PseudoregisterBuiltIns.compileWordShiftOps(left = false, ctx, l, r))
|
||||||
|
case 0 => Nil
|
||||||
case _ =>
|
case _ =>
|
||||||
ctx.log.error("Long shift ops not supported", l.position)
|
ctx.log.error("Long shift ops not supported", l.position)
|
||||||
Nil
|
Nil
|
||||||
@ -1643,7 +1666,10 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
} else {
|
} else {
|
||||||
compileAssignment(ctx, FunctionCallExpression("/", List(l, r)).pos(f.position), l)
|
compileAssignment(ctx, FunctionCallExpression("/", List(l, r)).pos(f.position), l)
|
||||||
}
|
}
|
||||||
case _ => ctx.log.fatal("Oops")
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Division of variables larger than 2 bytes is not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "/" | "%%" =>
|
case "/" | "%%" =>
|
||||||
assertSizesForDivision(ctx, params, inPlace = false)
|
assertSizesForDivision(ctx, params, inPlace = false)
|
||||||
@ -1654,6 +1680,10 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
BuiltIns.compileUnsignedByteDivision(ctx, l, r, f.functionName == "%%")
|
BuiltIns.compileUnsignedByteDivision(ctx, l, r, f.functionName == "%%")
|
||||||
case 2 =>
|
case 2 =>
|
||||||
BuiltIns.compileUnsignedWordByByteDivision(ctx, l, r, f.functionName == "%%")
|
BuiltIns.compileUnsignedWordByByteDivision(ctx, l, r, f.functionName == "%%")
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Division of variables larger than 2 bytes is not supported", expr.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "*'=" =>
|
case "*'=" =>
|
||||||
assertAllArithmeticBytes("Long multiplication not supported", ctx, params)
|
assertAllArithmeticBytes("Long multiplication not supported", ctx, params)
|
||||||
|
@ -559,6 +559,10 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
getArithmeticParamMaxSize(ctx, params.map(_._2)) match {
|
getArithmeticParamMaxSize(ctx, params.map(_._2)) match {
|
||||||
case 1 => targetifyA(ctx, target, ZBuiltIns.compile8BitSum(ctx, params, decimal), isSigned = false)
|
case 1 => targetifyA(ctx, target, ZBuiltIns.compile8BitSum(ctx, params, decimal), isSigned = false)
|
||||||
case 2 => targetifyHL(ctx, target, ZBuiltIns.compile16BitSum(ctx, params, decimal))
|
case 2 => targetifyHL(ctx, target, ZBuiltIns.compile16BitSum(ctx, params, decimal))
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Non-in-place addition or subtraction of variables larger than 2 bytes is not supported", expression.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case SeparateBytesExpression(h, l) =>
|
case SeparateBytesExpression(h, l) =>
|
||||||
val hi = compileToA(ctx, h)
|
val hi = compileToA(ctx, h)
|
||||||
@ -890,9 +894,13 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
case "^^" => ???
|
case "^^" => ???
|
||||||
|
|
||||||
case "&" =>
|
case "&" =>
|
||||||
getArithmeticParamMaxSize(ctx, params) match {
|
getArithmeticParamMaxSize(ctx, params, booleanHint = "&&") match {
|
||||||
case 1 => targetifyA(ctx, target, ZBuiltIns.compile8BitOperation(ctx, AND, params), isSigned = false)
|
case 1 => targetifyA(ctx, target, ZBuiltIns.compile8BitOperation(ctx, AND, params), isSigned = false)
|
||||||
case 2 => targetifyHL(ctx, target, ZBuiltIns.compile16BitOperation(ctx, AND, params))
|
case 2 => targetifyHL(ctx, target, ZBuiltIns.compile16BitOperation(ctx, AND, params))
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Non-in-place bit operations of variables larger than 2 bytes are not supported", expression.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "*" =>
|
case "*" =>
|
||||||
assertSizesForMultiplication(ctx, params, inPlace = false)
|
assertSizesForMultiplication(ctx, params, inPlace = false)
|
||||||
@ -904,14 +912,22 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
targetifyHL(ctx, target, Z80Multiply.compile16BitMultiplyToHL(ctx, params(0), params(1)))
|
targetifyHL(ctx, target, Z80Multiply.compile16BitMultiplyToHL(ctx, params(0), params(1)))
|
||||||
}
|
}
|
||||||
case "|" =>
|
case "|" =>
|
||||||
getArithmeticParamMaxSize(ctx, params) match {
|
getArithmeticParamMaxSize(ctx, params, booleanHint = "||") match {
|
||||||
case 1 => targetifyA(ctx, target, ZBuiltIns.compile8BitOperation(ctx, OR, params), isSigned = false)
|
case 1 => targetifyA(ctx, target, ZBuiltIns.compile8BitOperation(ctx, OR, params), isSigned = false)
|
||||||
case 2 => targetifyHL(ctx, target, ZBuiltIns.compile16BitOperation(ctx, OR, params))
|
case 2 => targetifyHL(ctx, target, ZBuiltIns.compile16BitOperation(ctx, OR, params))
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Non-in-place bit operations of variables larger than 2 bytes are not supported", expression.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "^" =>
|
case "^" =>
|
||||||
getArithmeticParamMaxSize(ctx, params) match {
|
getArithmeticParamMaxSize(ctx, params) match {
|
||||||
case 1 => targetifyA(ctx, target, ZBuiltIns.compile8BitOperation(ctx, XOR, params), isSigned = false)
|
case 1 => targetifyA(ctx, target, ZBuiltIns.compile8BitOperation(ctx, XOR, params), isSigned = false)
|
||||||
case 2 => targetifyHL(ctx, target, ZBuiltIns.compile16BitOperation(ctx, XOR, params))
|
case 2 => targetifyHL(ctx, target, ZBuiltIns.compile16BitOperation(ctx, XOR, params))
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Non-in-place bit operations of variables larger than 2 bytes are not supported", expression.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case ">>>>" =>
|
case ">>>>" =>
|
||||||
val (l, r, size) = assertArithmeticBinary(ctx, params)
|
val (l, r, size) = assertArithmeticBinary(ctx, params)
|
||||||
@ -1154,6 +1170,10 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
Nil
|
Nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Division of variables larger than 2 bytes is not supported", expression.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "/" | "%%" =>
|
case "/" | "%%" =>
|
||||||
assertSizesForDivision(ctx, params, inPlace = false)
|
assertSizesForDivision(ctx, params, inPlace = false)
|
||||||
@ -1169,6 +1189,10 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
} else {
|
} else {
|
||||||
targetifyHL(ctx, target, Z80Multiply.compileUnsignedWordDivision(ctx, Right(l), r, modulo, rhsWord))
|
targetifyHL(ctx, target, Z80Multiply.compileUnsignedWordDivision(ctx, Right(l), r, modulo, rhsWord))
|
||||||
}
|
}
|
||||||
|
case 0 => Nil
|
||||||
|
case _ =>
|
||||||
|
ctx.log.error("Division of variables larger than 2 bytes is not supported", expression.position)
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
case "*'=" =>
|
case "*'=" =>
|
||||||
assertAllArithmeticBytes("Long multiplication not supported", ctx, params)
|
assertAllArithmeticBytes("Long multiplication not supported", ctx, params)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package millfork.test
|
package millfork.test
|
||||||
|
|
||||||
import millfork.Cpu
|
import millfork.Cpu
|
||||||
import millfork.test.emu.{EmuCrossPlatformBenchmarkRun, EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedRun}
|
import millfork.test.emu.{EmuCrossPlatformBenchmarkRun, EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedRun, ShouldNotCompile}
|
||||||
import org.scalatest.{FunSuite, Matchers}
|
import org.scalatest.{FunSuite, Matchers}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -264,4 +264,28 @@ class BooleanSuite extends FunSuite with Matchers {
|
|||||||
m.readByte(0xc000) should equal(code.count(_ == '↑'))
|
m.readByte(0xc000) should equal(code.count(_ == '↑'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("Booleans should not work arithmetically") {
|
||||||
|
ShouldNotCompile(
|
||||||
|
"""
|
||||||
|
|byte b
|
||||||
|
|void main() {
|
||||||
|
| b += b == 1
|
||||||
|
|}
|
||||||
|
|""".stripMargin)
|
||||||
|
ShouldNotCompile(
|
||||||
|
"""
|
||||||
|
|byte b
|
||||||
|
|void main() {
|
||||||
|
| b = (b == 1) + (b == 1)
|
||||||
|
|}
|
||||||
|
|""".stripMargin)
|
||||||
|
ShouldNotCompile(
|
||||||
|
"""
|
||||||
|
|byte b
|
||||||
|
|void main() {
|
||||||
|
| b = (b == 1) | (b == 1)
|
||||||
|
|}
|
||||||
|
|""".stripMargin)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user