mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-06 09:33:22 +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
|
failed = true
|
||||||
}
|
}
|
||||||
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.isExplicitlyCastableTo(typ)) {
|
||||||
ctx.log.error(s"Cannot cast a type ${sourceType.name} to an incompatible type ${typ.name} of different size", params.head.position)
|
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
|
||||||
}
|
}
|
||||||
|
@ -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, 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
|
import scala.collection.GenTraversableOnce
|
||||||
|
|
||||||
@ -388,6 +388,9 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
|||||||
env.maybeGet[Type](fce.functionName) match {
|
env.maybeGet[Type](fce.functionName) match {
|
||||||
case Some(typ) =>
|
case Some(typ) =>
|
||||||
val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params)
|
val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params)
|
||||||
|
if (sourceType.isBoollike) {
|
||||||
|
return compileToFatBooleanInB(ctx, params.head) ++ targetifyB(ctx, target, isSigned = false)
|
||||||
|
}
|
||||||
return typ.size match {
|
return typ.size match {
|
||||||
// TODO: alternating signedness?
|
// TODO: alternating signedness?
|
||||||
case 1 => compileToB(ctx, params.head) ++ targetifyB(ctx, target, isSigned = typ.isSigned)
|
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 FatBooleanType => compileToB(ctx, expr)
|
||||||
case t: ConstantBooleanType =>
|
case t: ConstantBooleanType =>
|
||||||
List(MLine.immediate(MOpcode.LDB, if (t.value) 1 else 0))
|
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 _ =>
|
case _ =>
|
||||||
println(sourceType)
|
println(sourceType)
|
||||||
|
println(expr)
|
||||||
???
|
???
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1676,6 +1676,9 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
env.maybeGet[Type](f.functionName) match {
|
env.maybeGet[Type](f.functionName) match {
|
||||||
case Some(typ) =>
|
case Some(typ) =>
|
||||||
val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params)
|
val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params)
|
||||||
|
if (sourceType.isBoollike) {
|
||||||
|
return compileToFatBooleanInA(ctx, params.head) ++ expressionStorageFromA(ctx, exprTypeAndVariable, position = expr.position, signedSource = false)
|
||||||
|
}
|
||||||
exprTypeAndVariable match {
|
exprTypeAndVariable match {
|
||||||
case None =>
|
case None =>
|
||||||
return compile(ctx, params.head, None, branches)
|
return compile(ctx, params.head, None, branches)
|
||||||
|
@ -1202,6 +1202,9 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
env.maybeGet[Type](f.functionName) match {
|
env.maybeGet[Type](f.functionName) match {
|
||||||
case Some(typ) =>
|
case Some(typ) =>
|
||||||
val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params)
|
val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params)
|
||||||
|
if (sourceType.isBoollike) {
|
||||||
|
return targetifyA(ctx, target, compileToFatBooleanInA(ctx, params.head), isSigned = false)
|
||||||
|
}
|
||||||
return typ.size match {
|
return typ.size match {
|
||||||
// TODO: alternating signedness?
|
// TODO: alternating signedness?
|
||||||
case 1 => targetifyA(ctx, target, compileToA(ctx, params.head), isSigned = typ.isSigned)
|
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 isSigned: Boolean
|
||||||
|
|
||||||
|
def isBoollike: Boolean = false
|
||||||
|
|
||||||
def isSubtypeOf(other: Type): Boolean = this == other
|
def isSubtypeOf(other: Type): Boolean = this == other
|
||||||
|
|
||||||
def isCompatible(other: Type): Boolean = this == other
|
def isCompatible(other: Type): Boolean = this == other
|
||||||
|
|
||||||
override def toString: String = name
|
override def toString: String = name
|
||||||
|
|
||||||
|
def isExplicitlyCastableTo(targetType: Type): Boolean = isAssignableTo(targetType)
|
||||||
|
|
||||||
def isAssignableTo(targetType: Type): Boolean = isCompatible(targetType)
|
def isAssignableTo(targetType: Type): Boolean = isCompatible(targetType)
|
||||||
|
|
||||||
def isArithmetic = false
|
def isArithmetic = false
|
||||||
@ -131,6 +135,8 @@ case object FatBooleanType extends VariableType {
|
|||||||
|
|
||||||
override def isSigned: Boolean = false
|
override def isSigned: Boolean = false
|
||||||
|
|
||||||
|
override def isBoollike: Boolean = true
|
||||||
|
|
||||||
override def name: String = "bool"
|
override def name: String = "bool"
|
||||||
|
|
||||||
override def isPointy: Boolean = false
|
override def isPointy: Boolean = false
|
||||||
@ -138,6 +144,8 @@ case object FatBooleanType extends VariableType {
|
|||||||
override def isSubtypeOf(other: Type): Boolean = this == other
|
override def isSubtypeOf(other: Type): Boolean = this == other
|
||||||
|
|
||||||
override def isAssignableTo(targetType: Type): Boolean = this == targetType
|
override def isAssignableTo(targetType: Type): Boolean = this == targetType
|
||||||
|
|
||||||
|
override def isExplicitlyCastableTo(targetType: Type): Boolean = targetType.isArithmetic || isAssignableTo(targetType)
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed trait BooleanType extends Type {
|
sealed trait BooleanType extends Type {
|
||||||
@ -145,7 +153,11 @@ sealed trait BooleanType extends Type {
|
|||||||
|
|
||||||
def isSigned = false
|
def isSigned = false
|
||||||
|
|
||||||
|
override def isBoollike: Boolean = true
|
||||||
|
|
||||||
override def isAssignableTo(targetType: Type): Boolean = isCompatible(targetType) || targetType == FatBooleanType
|
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
|
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)
|
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