| @@ -35,7 +35,7 @@ def printError(error: Error)(using errorContent: String): Unit = { | ||||
|       highlight(pos, 1) | ||||
|     case Error.TypeMismatch(pos, expected, got, msg) => | ||||
|       printPosition(pos) | ||||
|       println(msg) | ||||
|       println(s"Type mismatch: $msg\nExpected: $expected\nGot: $got") | ||||
|       highlight(pos, 1) | ||||
|     case Error.SemanticError(pos, msg) => | ||||
|       printPosition(pos) | ||||
|   | ||||
| @@ -60,35 +60,45 @@ object ast { | ||||
|   object Chr extends ParserBridgePos1[Expr6, Chr] | ||||
|  | ||||
|   // Binary operators | ||||
|   sealed trait BinaryOp extends Expr { | ||||
|   sealed trait BinaryOp(val name: String) extends Expr { | ||||
|     val x: Expr | ||||
|     val y: Expr | ||||
|   } | ||||
|   case class Add(x: Expr4, y: Expr5)(val pos: Position) extends Expr4 with BinaryOp | ||||
|   case class Add(x: Expr4, y: Expr5)(val pos: Position) extends Expr4 with BinaryOp("addition") | ||||
|   object Add extends ParserBridgePos2[Expr4, Expr5, Add] | ||||
|   case class Sub(x: Expr4, y: Expr5)(val pos: Position) extends Expr4 with BinaryOp | ||||
|   case class Sub(x: Expr4, y: Expr5)(val pos: Position) extends Expr4 with BinaryOp("subtraction") | ||||
|   object Sub extends ParserBridgePos2[Expr4, Expr5, Sub] | ||||
|   case class Mul(x: Expr5, y: Expr6)(val pos: Position) extends Expr5 with BinaryOp | ||||
|   case class Mul(x: Expr5, y: Expr6)(val pos: Position) | ||||
|       extends Expr5 | ||||
|       with BinaryOp("multiplication") | ||||
|   object Mul extends ParserBridgePos2[Expr5, Expr6, Mul] | ||||
|   case class Div(x: Expr5, y: Expr6)(val pos: Position) extends Expr5 with BinaryOp | ||||
|   case class Div(x: Expr5, y: Expr6)(val pos: Position) extends Expr5 with BinaryOp("division") | ||||
|   object Div extends ParserBridgePos2[Expr5, Expr6, Div] | ||||
|   case class Mod(x: Expr5, y: Expr6)(val pos: Position) extends Expr5 with BinaryOp | ||||
|   case class Mod(x: Expr5, y: Expr6)(val pos: Position) extends Expr5 with BinaryOp("modulus") | ||||
|   object Mod extends ParserBridgePos2[Expr5, Expr6, Mod] | ||||
|   case class Greater(x: Expr4, y: Expr4)(val pos: Position) extends Expr3 with BinaryOp | ||||
|   case class Greater(x: Expr4, y: Expr4)(val pos: Position) | ||||
|       extends Expr3 | ||||
|       with BinaryOp("strictly greater than") | ||||
|   object Greater extends ParserBridgePos2[Expr4, Expr4, Greater] | ||||
|   case class GreaterEq(x: Expr4, y: Expr4)(val pos: Position) extends Expr3 with BinaryOp | ||||
|   case class GreaterEq(x: Expr4, y: Expr4)(val pos: Position) | ||||
|       extends Expr3 | ||||
|       with BinaryOp("greater than or equal to") | ||||
|   object GreaterEq extends ParserBridgePos2[Expr4, Expr4, GreaterEq] | ||||
|   case class Less(x: Expr4, y: Expr4)(val pos: Position) extends Expr3 with BinaryOp | ||||
|   case class Less(x: Expr4, y: Expr4)(val pos: Position) | ||||
|       extends Expr3 | ||||
|       with BinaryOp("strictly less than") | ||||
|   object Less extends ParserBridgePos2[Expr4, Expr4, Less] | ||||
|   case class LessEq(x: Expr4, y: Expr4)(val pos: Position) extends Expr3 with BinaryOp | ||||
|   case class LessEq(x: Expr4, y: Expr4)(val pos: Position) | ||||
|       extends Expr3 | ||||
|       with BinaryOp("less than or equal to") | ||||
|   object LessEq extends ParserBridgePos2[Expr4, Expr4, LessEq] | ||||
|   case class Eq(x: Expr3, y: Expr3)(val pos: Position) extends Expr2 with BinaryOp | ||||
|   case class Eq(x: Expr3, y: Expr3)(val pos: Position) extends Expr2 with BinaryOp("equality") | ||||
|   object Eq extends ParserBridgePos2[Expr3, Expr3, Eq] | ||||
|   case class Neq(x: Expr3, y: Expr3)(val pos: Position) extends Expr2 with BinaryOp | ||||
|   case class Neq(x: Expr3, y: Expr3)(val pos: Position) extends Expr2 with BinaryOp("inequality") | ||||
|   object Neq extends ParserBridgePos2[Expr3, Expr3, Neq] | ||||
|   case class And(x: Expr2, y: Expr1)(val pos: Position) extends Expr1 with BinaryOp | ||||
|   case class And(x: Expr2, y: Expr1)(val pos: Position) extends Expr1 with BinaryOp("logical and") | ||||
|   object And extends ParserBridgePos2[Expr2, Expr1, And] | ||||
|   case class Or(x: Expr1, y: Expr)(val pos: Position) extends Expr with BinaryOp | ||||
|   case class Or(x: Expr1, y: Expr)(val pos: Position) extends Expr with BinaryOp("logical or") | ||||
|   object Or extends ParserBridgePos2[Expr1, Expr, Or] | ||||
|  | ||||
|   // Types | ||||
|   | ||||
| @@ -159,24 +159,25 @@ object typeChecker { | ||||
|       ctx.typeOf(id).satisfies(constraint, id.pos) | ||||
|     case ArrayElem(id, indices) => | ||||
|       val arrayTy = ctx.typeOf(id) | ||||
|       val elemTy = indices.toList.foldRight(arrayTy) { (elem, acc) => | ||||
|       val elemTy = indices.foldLeftM(arrayTy) { (acc, elem) => | ||||
|         checkValue(elem, Constraint.Is(KnownType.Int, "array index must be an int")) | ||||
|         acc match { | ||||
|           case KnownType.Array(innerTy) => innerTy | ||||
|           case _ => | ||||
|           case KnownType.Array(innerTy) => Some(innerTy) | ||||
|           case nonArrayTy => | ||||
|             ctx.error( | ||||
|               Error.TypeMismatch(elem.pos, KnownType.Array(?), acc, "cannot index into a non-array") | ||||
|             ) | ||||
|             None | ||||
|         } | ||||
|       } | ||||
|       elemTy.satisfies(constraint, id.pos) | ||||
|       elemTy.getOrElse(?).satisfies(constraint, id.pos) | ||||
|     case Parens(expr) => checkValue(expr, constraint) | ||||
|     case l @ ArrayLiter(elems) => | ||||
|       KnownType | ||||
|         .Array(elems.foldRight[SemType](?) { case (elem, acc) => | ||||
|         .Array(elems.foldLeft[SemType](?) { case (acc, elem) => | ||||
|           checkValue( | ||||
|             elem, | ||||
|             Constraint.IsSymmetricCompatible(acc, "array elements must have the same type") | ||||
|             Constraint.IsSymmetricCompatible(acc, s"array elements must have the same type") | ||||
|           ) | ||||
|         }) | ||||
|         .satisfies(constraint, l.pos) | ||||
| @@ -233,13 +234,16 @@ object typeChecker { | ||||
|  | ||||
|     // Binary operators | ||||
|     case op: (Add | Sub | Mul | Div | Mod) => | ||||
|       val operand = Constraint.Is(KnownType.Int, "binary operator must be applied to an int") | ||||
|       val operand = Constraint.Is(KnownType.Int, s"${op.name} operator must be applied to an int") | ||||
|       checkValue(op.x, operand) | ||||
|       checkValue(op.y, operand) | ||||
|       KnownType.Int.satisfies(constraint, op.pos) | ||||
|     case op: (Eq | Neq) => | ||||
|       val xTy = checkValue(op.x, Constraint.Unconstrained) | ||||
|       checkValue(op.y, Constraint.Is(xTy, "equality must be applied to values of the same type")) | ||||
|       checkValue( | ||||
|         op.y, | ||||
|         Constraint.Is(xTy, s"${op.name} operator must be applied to values of the same type") | ||||
|       ) | ||||
|       KnownType.Bool.satisfies(constraint, op.pos) | ||||
|     case op: (Less | LessEq | Greater | GreaterEq) => | ||||
|       val xTy = checkValue( | ||||
| @@ -247,13 +251,16 @@ object typeChecker { | ||||
|         Constraint.IsEither( | ||||
|           KnownType.Int, | ||||
|           KnownType.Char, | ||||
|           "comparison must be applied to an int or char" | ||||
|           s"${op.name} operator must be applied to an int or char" | ||||
|         ) | ||||
|       ) | ||||
|       checkValue(op.y, Constraint.Is(xTy, "comparison must be applied to values of the same type")) | ||||
|       checkValue( | ||||
|         op.y, | ||||
|         Constraint.Is(xTy, s"${op.name} operator must be applied to values of the same type") | ||||
|       ) | ||||
|       KnownType.Bool.satisfies(constraint, op.pos) | ||||
|     case op: (And | Or) => | ||||
|       val operand = Constraint.Is(KnownType.Bool, "logical operator must be applied to a bool") | ||||
|       val operand = Constraint.Is(KnownType.Bool, s"${op.name} operator must be applied to a bool") | ||||
|       checkValue(op.x, operand) | ||||
|       checkValue(op.y, operand) | ||||
|       KnownType.Bool.satisfies(constraint, op.pos) | ||||
|   | ||||
| @@ -9,9 +9,11 @@ object types { | ||||
|       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 ?                           => "?" | ||||
|       case ?                           => "<unknown-type>" | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user