package millfork.env import millfork.assembly.Opcode import millfork.error.ErrorReporting import millfork.node._ sealed trait Thing { def name: String } sealed trait Type extends Thing { def size: Int def isSigned: Boolean def isSubtypeOf(other: Type): Boolean = this == other def isCompatible(other: Type): Boolean = this == other override def toString(): String = name def isAssignableTo(targetType: Type): Boolean = isCompatible(targetType) } case object VoidType extends Type { def size = 0 def isSigned = false override def name = "void" } sealed trait PlainType extends Type { override def isCompatible(other: Type): Boolean = this == other || this.isSubtypeOf(other) || other.isSubtypeOf(this) override def isAssignableTo(targetType: Type): Boolean = isCompatible(targetType) || (targetType match { case BasicPlainType(_, size) => size > this.size // TODO case _ => false }) } case class BasicPlainType(name: String, size: Int) extends PlainType { def isSigned = false override def isSubtypeOf(other: Type): Boolean = this == other } case class DerivedPlainType(name: String, parent: PlainType, isSigned: Boolean) extends PlainType { def size: Int = parent.size override def isSubtypeOf(other: Type): Boolean = parent == other || parent.isSubtypeOf(other) } sealed trait BooleanType extends Type { def size = 0 def isSigned = false } case class ConstantBooleanType(name: String, value: Boolean) extends BooleanType case class FlagBooleanType(name: String, jumpIfTrue: Opcode.Value, jumpIfFalse: Opcode.Value) extends BooleanType case object BuiltInBooleanType extends BooleanType { override def name = "bool$" } sealed trait TypedThing extends Thing { def typ: Type } sealed trait ThingInMemory extends Thing { def toAddress: Constant } sealed trait PrellocableThing extends ThingInMemory { def shouldGenerate: Boolean def address: Option[Constant] def toAddress: Constant = address.getOrElse(MemoryAddressConstant(this)) } case class Label(name: String) extends ThingInMemory { override def toAddress: MemoryAddressConstant = MemoryAddressConstant(this) } sealed trait Variable extends TypedThing case class BlackHole(typ: Type) extends Variable { override def name = "" } sealed trait VariableInMemory extends Variable with ThingInMemory { def zeropage: Boolean } case class RegisterVariable(register: Register.Value, typ: Type) extends Variable { def name: String = register.toString } case class Placeholder(name: String, typ: Type) extends Variable sealed trait UninitializedMemory extends ThingInMemory { def sizeInBytes: Int def alloc: VariableAllocationMethod.Value } object VariableAllocationMethod extends Enumeration { val Auto, Static, Zeropage, None = Value } case class StackVariable(name: String, typ: Type, baseOffset: Int) extends Variable { def sizeInBytes: Int = typ.size } case class MemoryVariable(name: String, typ: Type, alloc: VariableAllocationMethod.Value) extends VariableInMemory with UninitializedMemory { override def sizeInBytes: Int = typ.size override def zeropage: Boolean = alloc == VariableAllocationMethod.Zeropage override def toAddress: MemoryAddressConstant = MemoryAddressConstant(this) } trait MlArray extends ThingInMemory case class UninitializedArray(name: String, sizeInBytes: Int) extends MlArray with UninitializedMemory { override def toAddress: MemoryAddressConstant = MemoryAddressConstant(this) override def alloc = VariableAllocationMethod.Static } case class RelativeArray(name: String, address: Constant, sizeInBytes: Int) extends MlArray { override def toAddress: Constant = address } case class InitializedArray(name: String, address: Option[Constant], contents: List[Constant]) extends MlArray with PrellocableThing { override def shouldGenerate = true } case class RelativeVariable(name: String, address: Constant, typ: Type, zeropage: Boolean) extends VariableInMemory { override def toAddress: Constant = address } sealed trait MangledFunction extends Thing { def name: String def returnType: Type def params: ParamSignature def interrupt: Boolean } case class EmptyFunction(name: String, returnType: Type, paramType: Type) extends MangledFunction { override def params = EmptyFunctionParamSignature(paramType) override def interrupt = false } case class InlinedFunction(name: String, returnType: Type, params: ParamSignature, environment: Environment, code: List[ExecutableStatement]) extends MangledFunction { override def interrupt = false } sealed trait FunctionInMemory extends MangledFunction with ThingInMemory { def environment: Environment } case class ExternFunction(name: String, returnType: Type, params: ParamSignature, address: Constant, environment: Environment) extends FunctionInMemory { override def toAddress: Constant = address override def interrupt = false } case class NormalFunction(name: String, returnType: Type, params: ParamSignature, environment: Environment, stackVariablesSize: Int, address: Option[Constant], code: List[ExecutableStatement], interrupt: Boolean, reentrant: Boolean, position: Option[Position]) extends FunctionInMemory with PrellocableThing { override def shouldGenerate = true } case class ConstantThing(name: String, value: Constant, typ: Type) extends TypedThing trait ParamSignature { def types: List[Type] def length: Int } case class NormalParamSignature(params: List[MemoryVariable]) extends ParamSignature { override def length: Int = params.length override def types: List[Type] = params.map(_.typ) } sealed trait ParamPassingConvention { def inInlinedOnly: Boolean def inNonInlinedOnly: Boolean } case class ByRegister(register: Register.Value) extends ParamPassingConvention { override def inInlinedOnly = false override def inNonInlinedOnly = false } case class ByVariable(name: String) extends ParamPassingConvention { override def inInlinedOnly = false override def inNonInlinedOnly = true } case class ByConstant(name: String) extends ParamPassingConvention { override def inInlinedOnly = true override def inNonInlinedOnly = false } case class ByReference(name: String) extends ParamPassingConvention { override def inInlinedOnly = true override def inNonInlinedOnly = false } object AssemblyParameterPassingBehaviour extends Enumeration { val Copy, ByReference, ByConstant = Value } case class AssemblyParam(typ: Type, variable: TypedThing, behaviour: AssemblyParameterPassingBehaviour.Value) case class AssemblyParamSignature(params: List[AssemblyParam]) extends ParamSignature { override def length: Int = params.length override def types: List[Type] = params.map(_.typ) } case class EmptyFunctionParamSignature(paramType: Type) extends ParamSignature { override def length: Int = 1 override def types: List[Type] = List(paramType) }