diff --git a/include/loader_0401.mfk b/include/loader_0401.mfk index 9e1db8ad..40f4a6b2 100644 --- a/include/loader_0401.mfk +++ b/include/loader_0401.mfk @@ -2,7 +2,7 @@ #warn loader_0401 module should be only used on Commodore targets #endif -array _basic_loader @$401 = [ +const array _basic_loader @$401 = [ $0b, 4, 10, diff --git a/include/loader_0801.mfk b/include/loader_0801.mfk index 8d369804..82ddd414 100644 --- a/include/loader_0801.mfk +++ b/include/loader_0801.mfk @@ -2,7 +2,7 @@ #warn loader_0801 module should be only used on Commodore targets #endif -array _basic_loader @$801 = [ +const array _basic_loader @$801 = [ $0b, $08, 10, diff --git a/include/loader_0801_16bit.mfk b/include/loader_0801_16bit.mfk index cc306a78..3ea6df22 100644 --- a/include/loader_0801_16bit.mfk +++ b/include/loader_0801_16bit.mfk @@ -2,7 +2,7 @@ #warn loader_0801_16bit module should be only used on Commodore targets #endif -array _basic_loader @$801 = [ +const array _basic_loader @$801 = [ $0b, $08, 10, diff --git a/include/loader_1001.mfk b/include/loader_1001.mfk index b1bdac12..e15ed4fc 100644 --- a/include/loader_1001.mfk +++ b/include/loader_1001.mfk @@ -2,7 +2,7 @@ #warn loader_1001 module should be only used on Commodore targets #endif -array _basic_loader @$1001 = [ +const array _basic_loader @$1001 = [ $0b, $10, 10, diff --git a/include/loader_1201.mfk b/include/loader_1201.mfk index e3fdece0..ae668bff 100644 --- a/include/loader_1201.mfk +++ b/include/loader_1201.mfk @@ -2,7 +2,7 @@ #warn loader_1201 module should be only used on Commodore targets #endif -array _basic_loader @$1201 = [ +const array _basic_loader @$1201 = [ $0b, $12, 10, diff --git a/include/loader_1c01.mfk b/include/loader_1c01.mfk index a405c45e..7f6c9c77 100644 --- a/include/loader_1c01.mfk +++ b/include/loader_1c01.mfk @@ -2,7 +2,7 @@ #warn loader_1c01 module should be only used on Commodore targets #endif -array _basic_loader @$1C01 = [ +const array _basic_loader @$1C01 = [ $0b, $1C, 10, diff --git a/include/loader_a000.mfk b/include/loader_a000.mfk index 57f708be..3c70c90b 100644 --- a/include/loader_a000.mfk +++ b/include/loader_a000.mfk @@ -7,4 +7,4 @@ const array __vectors @$A000 = [ ] segment(prgrom) -array __boot_signature @$A004 = [$41, $30, $C3, $C2, $CD] +const array __boot_signature @$A004 = [$41, $30, $C3, $C2, $CD] diff --git a/include/loader_c64crt.mfk b/include/loader_c64crt.mfk index d5536888..75f34651 100644 --- a/include/loader_c64crt.mfk +++ b/include/loader_c64crt.mfk @@ -7,4 +7,4 @@ const array __vectors @$8000 = [ ] segment(prgrom) -array __boot_signature @$8004 = [$C3, $C2, $CD, $38, $30] +const array __boot_signature @$8004 = [$C3, $C2, $CD, $38, $30] diff --git a/include/msx_crt.mfk b/include/msx_crt.mfk index 89d72c5d..d27d805a 100644 --- a/include/msx_crt.mfk +++ b/include/msx_crt.mfk @@ -1,4 +1,4 @@ -array __header[16] @$4000 = [ +const array __header[16] @$4000 = [ "AB" ascii, @word [main.addr, 0, 0, 0], 0,0, 0,0, 0,0 diff --git a/src/main/scala/millfork/compiler/AbstractExpressionCompiler.scala b/src/main/scala/millfork/compiler/AbstractExpressionCompiler.scala index 8611c78a..d5896e0f 100644 --- a/src/main/scala/millfork/compiler/AbstractExpressionCompiler.scala +++ b/src/main/scala/millfork/compiler/AbstractExpressionCompiler.scala @@ -213,10 +213,20 @@ class AbstractExpressionCompiler[T <: AbstractCode] { object AbstractExpressionCompiler { @inline def getExpressionType(ctx: CompilationContext, expr: Expression): Type = { - getExpressionType(ctx.env, ctx.log, expr) + getExpressionTypeImpl(ctx.env, ctx.log, expr, loosely = false) + } + @inline + def getExpressionTypeLoosely(ctx: CompilationContext, expr: Expression): Type = { + getExpressionTypeImpl(ctx.env, ctx.log, expr, loosely = true) } - def getExpressionType(env: Environment, log: Logger, expr: Expression): Type = { + @inline + def getExpressionType(env: Environment, log: Logger, expr: Expression): Type = getExpressionTypeImpl(env, log, expr, loosely = false) + + @inline + def getExpressionTypeLoosely(env: Environment, log: Logger, expr: Expression): Type = getExpressionTypeImpl(env, log, expr, loosely = true) + + def getExpressionTypeImpl(env: Environment, log: Logger, expr: Expression, loosely: Boolean): Type = { if (expr.typeCache ne null) expr.typeCache val b = env.get[Type]("byte") val bool = env.get[Type]("bool$") @@ -235,7 +245,7 @@ object AbstractExpressionCompiler { mask = (1L << (8 * maxSize)) - 1 signMask = ~mask signTest = if (signMask == 0) Long.MaxValue else signMask >> 1 - types = exprs.map(e => getExpressionType(env, log, e)) + types = exprs.map(e => getExpressionTypeImpl(env, log, e, loosely)) if types.forall(_.size.<(8)) signednesses = types.flatMap { case d: DerivedPlainType => Some(d.isSigned) @@ -249,7 +259,7 @@ object AbstractExpressionCompiler { } def toAllBooleanConstants(exprs: List[Expression]): Option[List[Boolean]] = { for { - types <- Some(exprs.map(e => getExpressionType(env, log, e))) + types <- Some(exprs.map(e => getExpressionTypeImpl(env, log, e, loosely))) if types.forall(_.isInstanceOf[ConstantBooleanType]) bools = types.map(_.asInstanceOf[ConstantBooleanType].value) if bools.nonEmpty @@ -283,9 +293,24 @@ object AbstractExpressionCompiler { case GeneratedConstantExpression(_, typ) => typ case TextLiteralExpression(_) => env.get[Type]("pointer") case VariableExpression(name) => - env.get[TypedThing](name, expr.position).typ + if (loosely) { + env.maybeGet[TypedThing](name) match { + case Some(t) => t.typ + case None => + if (name.endsWith(".lo") || name.endsWith(".hi")) { + b + } else if (name.endsWith(".addr")) { + env.get[Type]("pointer") + } else { + log.error(s"TypedThing `$name` is not defined", expr.position) + b + } + } + } else { + env.get[TypedThing](name, expr.position).typ + } case HalfWordExpression(param, _) => - getExpressionType(env, log, param) + getExpressionTypeImpl(env, log, param, loosely) b case IndexedExpression(name, _) => env.getPointy(name).elementType @@ -299,9 +324,9 @@ object AbstractExpressionCompiler { case Some(a: MfArray) => env.get[Type]("pointer." + a.elementType) case _ => - getExpressionType(env, log, inner) + getExpressionTypeImpl(env, log, inner, loosely) } - case _ => getExpressionType(env, log, inner) + case _ => getExpressionTypeImpl(env, log, inner, loosely) } var ok = true for(_ <- firstIndices) { @@ -370,10 +395,10 @@ object AbstractExpressionCompiler { } if (ok) currentType else b case SeparateBytesExpression(hi, lo) => - if (getExpressionType(env, log, hi).size > 1) log.error("Hi byte too large", hi.position) - if (getExpressionType(env, log, lo).size > 1) log.error("Lo byte too large", lo.position) + if (getExpressionTypeImpl(env, log, hi, loosely).size > 1) log.error("Hi byte too large", hi.position) + if (getExpressionTypeImpl(env, log, lo, loosely).size > 1) log.error("Lo byte too large", lo.position) w - case SumExpression(params, _) => params.map { case (_, e) => getExpressionType(env, log, e).size }.max match { + case SumExpression(params, _) => params.map { case (_, e) => getExpressionTypeImpl(env, log, e, loosely).size }.max match { case 1 => b case 2 => w case _ => log.error("Adding values bigger than words", expr.position); w @@ -387,7 +412,7 @@ object AbstractExpressionCompiler { case f@FunctionCallExpression("call", params) => params match { case List(fp) => - getExpressionType(env, log, fp) match { + getExpressionTypeImpl(env, log, fp, loosely) match { case fpt@FunctionPointerType(_, _, _, Some(v), Some(r)) => if (v.name != "void"){ log.error(s"Invalid function pointer type: $fpt", fp.position) @@ -398,9 +423,9 @@ object AbstractExpressionCompiler { v } case List(fp, pp) => - getExpressionType(env, log, fp) match { + getExpressionTypeImpl(env, log, fp, loosely) match { case fpt@FunctionPointerType(_, _, _, Some(p), Some(r)) => - if (!getExpressionType(env, log, pp).isAssignableTo(p)){ + if (!getExpressionTypeImpl(env, log, pp, loosely).isAssignableTo(p)){ log.error(s"Invalid function pointer type: $fpt", fp.position) } r @@ -414,29 +439,29 @@ object AbstractExpressionCompiler { } case FunctionCallExpression("hi", _) => b case FunctionCallExpression("lo", _) => b - case FunctionCallExpression("sin", params) => if (params.size < 2) b else getExpressionType(env, log, params(1)) - case FunctionCallExpression("cos", params) => if (params.size < 2) b else getExpressionType(env, log, params(1)) - case FunctionCallExpression("tan", params) => if (params.size < 2) b else getExpressionType(env, log, params(1)) + 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("tan", params) => if (params.size < 2) b else getExpressionTypeImpl(env, log, params(1), loosely) case FunctionCallExpression("sizeof", params) => env.evalSizeof(params.head).requiredSize match { case 1 => b case 2 => w } - case FunctionCallExpression("%%", params) => params.map { e => getExpressionType(env, log, e).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, 2) | List(2, 2) => w case _ => log.error("Combining values bigger than words", expr.position); w } - case FunctionCallExpression("*" | "|" | "&" | "^" | "/", params) => params.map { e => getExpressionType(env, log, e).size }.max match { + case FunctionCallExpression("*" | "|" | "&" | "^" | "/", params) => params.map { e => getExpressionTypeImpl(env, log, e, loosely).size }.max match { case 1 => b case 2 => w case _ => log.error("Combining values bigger than words", expr.position); w } case FunctionCallExpression("<<", List(a1, a2)) => - if (getExpressionType(env, log, a2).size > 1) log.error("Shift amount too large", a2.position) - getExpressionType(env, log, a1) + if (getExpressionTypeImpl(env, log, a2, loosely).size > 1) log.error("Shift amount too large", a2.position) + getExpressionTypeImpl(env, log, a1, loosely) case FunctionCallExpression(">>", List(a1, a2)) => - if (getExpressionType(env, log, a2).size > 1) log.error("Shift amount too large", a2.position) - getExpressionType(env, log, a1) + if (getExpressionTypeImpl(env, log, a2, loosely).size > 1) log.error("Shift amount too large", a2.position) + getExpressionTypeImpl(env, log, a1, loosely) case FunctionCallExpression("<<'", _) => b case FunctionCallExpression(">>'", _) => b case FunctionCallExpression(">>>>", _) => b @@ -529,6 +554,13 @@ object AbstractExpressionCompiler { } } + def checkAssignmentTypeLoosely(env: Environment, source: Expression, targetType: Type): Unit = { + val sourceType = getExpressionTypeLoosely(env, env.log, source) + if (!sourceType.isAssignableTo(targetType)) { + env.log.error(s"Cannot assign `$sourceType` to `$targetType`", source.position) + } + } + def checkAssignmentType(env: Environment, source: Expression, targetType: Type): Unit = { val sourceType = getExpressionType(env, env.log, source) if (!sourceType.isAssignableTo(targetType)) { diff --git a/src/main/scala/millfork/env/Environment.scala b/src/main/scala/millfork/env/Environment.scala index fda129be..ab7319d9 100644 --- a/src/main/scala/millfork/env/Environment.scala +++ b/src/main/scala/millfork/env/Environment.scala @@ -1567,7 +1567,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa val alignment = stmt.alignment.getOrElse(defaultArrayAlignment(options, length)) val address = stmt.address.map(a => eval(a).getOrElse(errorConstant(s"Array `${stmt.name}` has non-constant address", stmt.position))) for (element <- contents) { - AbstractExpressionCompiler.checkAssignmentType(this, element, e) + AbstractExpressionCompiler.checkAssignmentTypeLoosely(this, element, e) } val array = InitializedArray(arrayName + ".array", address, contents, declaredBank = stmt.bank, indexType, e, readOnly = stmt.const, alignment) if (!stmt.const && options.platform.ramInitialValuesBank.isDefined && array.bank(options) != "default") { diff --git a/src/main/scala/millfork/output/AbstractAssembler.scala b/src/main/scala/millfork/output/AbstractAssembler.scala index 058b3767..f5d2e996 100644 --- a/src/main/scala/millfork/output/AbstractAssembler.scala +++ b/src/main/scala/millfork/output/AbstractAssembler.scala @@ -429,7 +429,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program labelMap(name) = bank0.index -> index if (!readOnlyPass) { rwDataStart = rwDataStart.min(index) - rwDataEnd = rwDataEnd.min(index + thing.sizeInBytes) + rwDataEnd = rwDataEnd.max(index + thing.sizeInBytes) } assembly.append("* = $" + index.toHexString) assembly.append(name + ":")