1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-08-13 02:28:59 +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(word)`
Furthermore, any type that can be assigned to a variable
can be used to convert from one type to another of the same size.
Furthermore, any type that can be assigned to a variable can be used to convert
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
}
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 {

View File

@ -1066,22 +1066,9 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
case _ =>
env.maybeGet[Type](f.functionName) match {
case Some(typ) =>
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){
ctx.log.error("Cannot cast a type to a type of different size")
failed = true
}
val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params)
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 =>
// fallthrough to the lookup below
}

View File

@ -782,20 +782,7 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
case _ =>
env.maybeGet[Type](f.functionName) match {
case Some(typ) =>
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) {
ctx.log.error("Cannot cast a type to a type of different size")
failed = true
}
val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params)
return sourceType.size match {
case 1 => targetifyA(ctx, target, compileToA(ctx, params.head), isSigned = sourceType.isSigned)
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))
}
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") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)("""
| word output @$c000
@ -132,7 +145,7 @@ class WordMathSuite extends FunSuite with Matchers {
| output = get(5, 6)
| }
| byte get(byte mx, byte my) {
| return map[((mx + 00000) << 5) + my]
| return map[(word(mx) << 5) + my]
| }
""".stripMargin){ m =>
m.readByte(0xc3a6) should equal(77)