From 785eb0780b415079b201643c1430c3862935695a Mon Sep 17 00:00:00 2001
From: Karol Stasiak <karol.m.stasiak@gmail.com>
Date: Fri, 16 Aug 2019 01:09:03 +0200
Subject: [PATCH] Fix cartridge targets

---
 include/loader_0401.mfk                       |  2 +-
 include/loader_0801.mfk                       |  2 +-
 include/loader_0801_16bit.mfk                 |  2 +-
 include/loader_1001.mfk                       |  2 +-
 include/loader_1201.mfk                       |  2 +-
 include/loader_1c01.mfk                       |  2 +-
 include/loader_a000.mfk                       |  2 +-
 include/loader_c64crt.mfk                     |  2 +-
 include/msx_crt.mfk                           |  2 +-
 .../compiler/AbstractExpressionCompiler.scala | 78 +++++++++++++------
 src/main/scala/millfork/env/Environment.scala |  2 +-
 .../millfork/output/AbstractAssembler.scala   |  2 +-
 12 files changed, 66 insertions(+), 34 deletions(-)

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 + ":")