1
0
mirror of https://github.com/KarolS/millfork.git synced 2025-02-24 10:28:57 +00:00

Allow casting to wider types

This commit is contained in:
Karol Stasiak 2018-08-08 23:14:09 +02:00
parent 9581891d66
commit 34b7107d27
5 changed files with 46 additions and 32 deletions

View File

@ -225,8 +225,17 @@ Other kinds of expressions than the above (even `nonet(byte + byte + byte)`) wil
* `hi`, `lo`: most/least significant byte of a word * `hi`, `lo`: most/least significant byte of a word
`hi(word)` `hi(word)`
Furthermore, any type that can be assigned to a variable Furthermore, any type that can be assigned to a variable can be used to convert
can be used to convert from one type to another of the same size. either from one type either to another type of the same size,
or from a 1-byte integer type to a compatible 2-byte integer type.
`byte``word`
`word``pointer`
some enum → `byte`
`byte` → some enum
but not
`word``byte`
some enum → `word`

View File

@ -130,6 +130,24 @@ class AbstractExpressionCompiler[T <: AbstractCode] {
} }
count <= 1 count <= 1
} }
def validateTypeCastAndGetSourceExpressionType(ctx: CompilationContext, typ: Type, params: List[Expression]): Type = {
var failed = false
if (typ.name == "pointer") {
ctx.log.error("Cannot cast into pointer")
failed = true
}
if (params.length != 1) {
ctx.log.error("Type casting should have exactly one argument")
failed = true
}
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")
failed = true
}
sourceType
}
} }
object AbstractExpressionCompiler { object AbstractExpressionCompiler {

View File

@ -1066,22 +1066,9 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
case _ => case _ =>
env.maybeGet[Type](f.functionName) match { env.maybeGet[Type](f.functionName) match {
case Some(typ) => case Some(typ) =>
var failed = false val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params)
if (typ.name == "pointer") {
ctx.log.error("Cannot cast into pointer")
failed = true
}
if (params.length != 1) {
ctx.log.error("Type casting should have exactly one argument")
failed = true
}
val sourceType = getExpressionType(ctx, params.head)
if (typ.size != sourceType.size){
ctx.log.error("Cannot cast a type to a type of different size")
failed = true
}
val newExprTypeAndVariable = exprTypeAndVariable.map(i => sourceType -> i._2) val newExprTypeAndVariable = exprTypeAndVariable.map(i => sourceType -> i._2)
return if (failed) Nil else compile(ctx, params.head, newExprTypeAndVariable, branches) return compile(ctx, params.head, newExprTypeAndVariable, branches)
case None => case None =>
// fallthrough to the lookup below // fallthrough to the lookup below
} }

View File

@ -782,20 +782,7 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
case _ => case _ =>
env.maybeGet[Type](f.functionName) match { env.maybeGet[Type](f.functionName) match {
case Some(typ) => case Some(typ) =>
var failed = false val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params)
if (typ.name == "pointer") {
ctx.log.error("Cannot cast into pointer")
failed = true
}
if (params.length != 1) {
ctx.log.error("Type casting should have exactly one argument")
failed = true
}
val sourceType = getExpressionType(ctx, params.head)
if (typ.size != sourceType.size) {
ctx.log.error("Cannot cast a type to a type of different size")
failed = true
}
return sourceType.size match { return sourceType.size match {
case 1 => targetifyA(ctx, target, compileToA(ctx, params.head), isSigned = sourceType.isSigned) case 1 => targetifyA(ctx, target, compileToA(ctx, params.head), isSigned = sourceType.isSigned)
case 2 => targetifyHL(ctx, target, compileToHL(ctx, params.head)) case 2 => targetifyHL(ctx, target, compileToHL(ctx, params.head))

View File

@ -20,6 +20,19 @@ class WordMathSuite extends FunSuite with Matchers {
""".stripMargin)(_.readWord(0xc000) should equal(1280)) """.stripMargin)(_.readWord(0xc000) should equal(1280))
} }
test("Cast word addition") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)("""
| byte output @$c000
| word a
| void main () {
| output = add(155, 166)
| }
| byte add(byte a, byte b) {
| return hi(word(a) + word(b))
| }
""".stripMargin)(_.readByte(0xc000) should equal(1))
}
test("Word subtraction") { test("Word subtraction") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(""" EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)("""
| word output @$c000 | word output @$c000
@ -132,7 +145,7 @@ class WordMathSuite extends FunSuite with Matchers {
| output = get(5, 6) | output = get(5, 6)
| } | }
| byte get(byte mx, byte my) { | byte get(byte mx, byte my) {
| return map[((mx + 00000) << 5) + my] | return map[(word(mx) << 5) + my]
| } | }
""".stripMargin){ m => """.stripMargin){ m =>
m.readByte(0xc3a6) should equal(77) m.readByte(0xc3a6) should equal(77)