package wacc

object types {
  import ast._

  sealed trait RenamerType

  sealed trait SemType extends RenamerType {
    override def toString(): String = this match {
      case KnownType.Int               => "int"
      case KnownType.Bool              => "bool"
      case KnownType.Char              => "char"
      case KnownType.String            => "string"
      case KnownType.Array(?)          => "array"
      case KnownType.Array(elem)       => s"$elem[]"
      case KnownType.Pair(?, ?)        => "pair"
      case KnownType.Pair(left, right) => s"pair($left, $right)"
      case ?                           => "<unknown-type>"
    }
  }

  case object ? extends SemType
  enum KnownType extends SemType {
    case Int
    case Bool
    case Char
    case String
    case Array(elem: SemType)
    case Pair(left: SemType, right: SemType)
  }

  object SemType {
    def apply(synType: Type | PairElemType): KnownType = synType match {
      case IntType()    => KnownType.Int
      case BoolType()   => KnownType.Bool
      case CharType()   => KnownType.Char
      case StringType() => KnownType.String
      // For semantic types it is easier to work with recursion rather than a fixed size
      case ArrayType(elemType, dimension) =>
        (0 until dimension).foldLeft(SemType(elemType))((acc, _) => KnownType.Array(acc))
      case PairType(fst, snd) => KnownType.Pair(SemType(fst), SemType(snd))
      case UntypedPairType()  => KnownType.Pair(?, ?)
    }
  }

  case class FuncType(returnType: SemType, params: List[SemType]) extends RenamerType
}
