mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-01 06:29:53 +00:00
Conversions from bool to byte
This commit is contained in:
parent
590db9ade0
commit
802cd7d86a
@ -203,7 +203,7 @@ class AbstractExpressionCompiler[T <: AbstractCode] {
|
||||
failed = true
|
||||
}
|
||||
val sourceType = getExpressionType(ctx, params.head)
|
||||
if (typ.size != sourceType.size && !sourceType.isAssignableTo(typ)) {
|
||||
if (typ.size != sourceType.size && !sourceType.isExplicitlyCastableTo(typ)) {
|
||||
ctx.log.error(s"Cannot cast a type ${sourceType.name} to an incompatible type ${typ.name} of different size", params.head.position)
|
||||
failed = true
|
||||
}
|
||||
|
@ -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, NonFatalCompilationException, NormalFunction, NormalParamSignature, NumericConstant, StackVariablePointy, ThingInMemory, Type, Variable, VariableInMemory, VariablePointy}
|
||||
import millfork.env.{AssemblyParamSignature, BuiltInBooleanType, Constant, ConstantBooleanType, ConstantPointy, ExternFunction, FatBooleanType, FlagBooleanType, FunctionInMemory, FunctionPointerType, M6809RegisterVariable, MacroFunction, MathOperator, MemoryVariable, NonFatalCompilationException, NormalFunction, NormalParamSignature, NumericConstant, StackVariablePointy, ThingInMemory, Type, Variable, VariableInMemory, VariablePointy}
|
||||
|
||||
import scala.collection.GenTraversableOnce
|
||||
|
||||
@ -388,6 +388,9 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
||||
env.maybeGet[Type](fce.functionName) match {
|
||||
case Some(typ) =>
|
||||
val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params)
|
||||
if (sourceType.isBoollike) {
|
||||
return compileToFatBooleanInB(ctx, params.head) ++ targetifyB(ctx, target, isSigned = false)
|
||||
}
|
||||
return typ.size match {
|
||||
// TODO: alternating signedness?
|
||||
case 1 => compileToB(ctx, params.head) ++ targetifyB(ctx, target, isSigned = typ.isSigned)
|
||||
@ -482,8 +485,35 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
||||
case FatBooleanType => compileToB(ctx, expr)
|
||||
case t: ConstantBooleanType =>
|
||||
List(MLine.immediate(MOpcode.LDB, if (t.value) 1 else 0))
|
||||
case BuiltInBooleanType | _: FlagBooleanType =>
|
||||
val label = ctx.env.nextLabel("bo")
|
||||
val condition = compile(ctx, expr, MExpressionTarget.NOTHING, BranchIfFalse(label))
|
||||
val conditionWithoutJump = condition.init
|
||||
condition.last.opcode match {
|
||||
case BCC =>
|
||||
conditionWithoutJump ++ List(MLine.immediate(LDB, 0), MLine.inherentB(ROL))
|
||||
case BCS =>
|
||||
conditionWithoutJump ++ List(MLine.immediate(LDB, 0), MLine.inherentB(ROL), MLine.immediate(EORB, 1))
|
||||
case BVC | BVS =>
|
||||
conditionWithoutJump ++ List(
|
||||
MLine.immediate(LDB, 0),
|
||||
condition.last,
|
||||
MLine.inherentB(INC),
|
||||
MLine.label(label)
|
||||
)
|
||||
case _ =>
|
||||
conditionWithoutJump ++ List(
|
||||
MLine.immediate(ANDCC, 0xfe),
|
||||
condition.last,
|
||||
MLine.immediate(ORCC, 1),
|
||||
MLine.label(label),
|
||||
MLine.immediate(LDB, 0),
|
||||
MLine.inherentB(ROL)
|
||||
)
|
||||
}
|
||||
case _ =>
|
||||
println(sourceType)
|
||||
println(expr)
|
||||
???
|
||||
}
|
||||
}
|
||||
|
@ -1676,6 +1676,9 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
env.maybeGet[Type](f.functionName) match {
|
||||
case Some(typ) =>
|
||||
val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params)
|
||||
if (sourceType.isBoollike) {
|
||||
return compileToFatBooleanInA(ctx, params.head) ++ expressionStorageFromA(ctx, exprTypeAndVariable, position = expr.position, signedSource = false)
|
||||
}
|
||||
exprTypeAndVariable match {
|
||||
case None =>
|
||||
return compile(ctx, params.head, None, branches)
|
||||
|
@ -1202,6 +1202,9 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
env.maybeGet[Type](f.functionName) match {
|
||||
case Some(typ) =>
|
||||
val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params)
|
||||
if (sourceType.isBoollike) {
|
||||
return targetifyA(ctx, target, compileToFatBooleanInA(ctx, params.head), isSigned = false)
|
||||
}
|
||||
return typ.size match {
|
||||
// TODO: alternating signedness?
|
||||
case 1 => targetifyA(ctx, target, compileToA(ctx, params.head), isSigned = typ.isSigned)
|
||||
|
12
src/main/scala/millfork/env/Thing.scala
vendored
12
src/main/scala/millfork/env/Thing.scala
vendored
@ -23,12 +23,16 @@ sealed trait Type extends CallableThing {
|
||||
|
||||
def isSigned: Boolean
|
||||
|
||||
def isBoollike: Boolean = false
|
||||
|
||||
def isSubtypeOf(other: Type): Boolean = this == other
|
||||
|
||||
def isCompatible(other: Type): Boolean = this == other
|
||||
|
||||
override def toString: String = name
|
||||
|
||||
def isExplicitlyCastableTo(targetType: Type): Boolean = isAssignableTo(targetType)
|
||||
|
||||
def isAssignableTo(targetType: Type): Boolean = isCompatible(targetType)
|
||||
|
||||
def isArithmetic = false
|
||||
@ -131,6 +135,8 @@ case object FatBooleanType extends VariableType {
|
||||
|
||||
override def isSigned: Boolean = false
|
||||
|
||||
override def isBoollike: Boolean = true
|
||||
|
||||
override def name: String = "bool"
|
||||
|
||||
override def isPointy: Boolean = false
|
||||
@ -138,6 +144,8 @@ case object FatBooleanType extends VariableType {
|
||||
override def isSubtypeOf(other: Type): Boolean = this == other
|
||||
|
||||
override def isAssignableTo(targetType: Type): Boolean = this == targetType
|
||||
|
||||
override def isExplicitlyCastableTo(targetType: Type): Boolean = targetType.isArithmetic || isAssignableTo(targetType)
|
||||
}
|
||||
|
||||
sealed trait BooleanType extends Type {
|
||||
@ -145,7 +153,11 @@ sealed trait BooleanType extends Type {
|
||||
|
||||
def isSigned = false
|
||||
|
||||
override def isBoollike: Boolean = true
|
||||
|
||||
override def isAssignableTo(targetType: Type): Boolean = isCompatible(targetType) || targetType == FatBooleanType
|
||||
|
||||
override def isExplicitlyCastableTo(targetType: Type): Boolean = targetType.isArithmetic || isAssignableTo(targetType)
|
||||
}
|
||||
|
||||
case class ConstantBooleanType(name: String, value: Boolean) extends BooleanType
|
||||
|
@ -246,4 +246,22 @@ class BooleanSuite extends FunSuite with Matchers {
|
||||
m.readByte(0xc001) should equal(1)
|
||||
}
|
||||
}
|
||||
|
||||
test("Boolean to number conversions") {
|
||||
val code =
|
||||
"""
|
||||
|byte output @$c000
|
||||
|void main () {
|
||||
|output = 0
|
||||
|output += byte(output == 0) // ↑
|
||||
|output += byte(output == 0)
|
||||
|output += byte(output != 2) // ↑
|
||||
|output += byte(output != 2)
|
||||
|output += byte(2 > 1) // ↑
|
||||
|}
|
||||
|""".stripMargin
|
||||
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(code){ m =>
|
||||
m.readByte(0xc000) should equal(code.count(_ == '↑'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user