feat: semantic error messages make use of msg strings passed from typeChecker
This commit is contained in:
		| @@ -6,7 +6,6 @@ import wacc.types._ | ||||
| enum Error { | ||||
|   case DuplicateDeclaration(ident: ast.Ident) | ||||
|   case UndefinedIdentifier(ident: ast.Ident, identType: renamer.IdentType) | ||||
|  | ||||
|   case FunctionParamsMismatch(pos: Position, expected: Int, got: Int) | ||||
|   case SemanticError(pos: Position, msg: String) | ||||
|   case TypeMismatch(pos: Position, expected: SemType, got: SemType, msg: String) | ||||
| @@ -18,25 +17,23 @@ def printError(error: Error)(using errorContent: String): Unit = { | ||||
|   error match { | ||||
|     case Error.DuplicateDeclaration(ident) => | ||||
|       printPosition(ident.getPosition) | ||||
|       println( | ||||
|         s"Duplicate declaration of identifier ${ident.v}" | ||||
|       ) | ||||
|       println(s"Duplicate declaration of identifier ${ident.v}") | ||||
|       highlight(ident.getPosition, ident.v.length) | ||||
|     case Error.UndefinedIdentifier(ident, identType) => | ||||
|       printPosition(ident.getPosition) | ||||
|       println( | ||||
|         s"Undefined ${identType.toString.toLowerCase()} ${ident.v}" | ||||
|       ) | ||||
|       println(s"Undefined ${identType.toString.toLowerCase()} ${ident.v}") | ||||
|       highlight(ident.getPosition, ident.v.length) | ||||
|     case Error.FunctionParamsMismatch(pos, expected, got) => | ||||
|       printPosition(pos) | ||||
|       println(s"Function expects $expected parameters, got $got") | ||||
|       highlight(pos, 1) | ||||
|     case Error.TypeMismatch(pos, expected, got, msg) => | ||||
|       println(s"Type mismatch: expected $expected, got $got") | ||||
|       printPosition(pos) | ||||
|       println(msg) | ||||
|       highlight(pos, 1) | ||||
|     case Error.SemanticError(pos, msg) => | ||||
|       printPosition(pos) | ||||
|       println(s"$msg at line: ${pos.line} column: ${pos.column}") | ||||
|       println(msg) | ||||
|       highlight(pos, 1) | ||||
|     case wacc.Error.InternalError(pos, msg) => | ||||
|       printPosition(pos) | ||||
|   | ||||
| @@ -12,8 +12,6 @@ import cats.data.NonEmptyList | ||||
| import parsley.errors.DefaultErrorBuilder | ||||
| import parsley.errors.ErrorBuilder | ||||
| import parsley.errors.tokenextractors.LexToken | ||||
| import parsley.errors.patterns.VerifiedErrors | ||||
| import parsley.character.char | ||||
|  | ||||
| object parser { | ||||
|   import lexer.implicits.implicitSymbol | ||||
| @@ -50,9 +48,6 @@ object parser { | ||||
|     case Expr | ||||
|     case Pair | ||||
|  | ||||
|   val _parensCheck = | ||||
|     char('(').verifiedExplain("use keyword 'call' to call functions") | ||||
|  | ||||
|   implicit val builder: ErrorBuilder[String] = new DefaultErrorBuilder with LexToken { | ||||
|     def tokens = errTokens | ||||
|   } | ||||
| @@ -71,8 +66,8 @@ object parser { | ||||
|         GreaterEq from ">=" | ||||
|       ) +: | ||||
|       SOps(InfixL)( | ||||
|         ((Add from "+").label("binary operator") | _parensCheck), | ||||
|         ((Sub from "-").label("binary operator") | _parensCheck) | ||||
|         (Add from "+").label("binary operator"), | ||||
|         (Sub from "-").label("binary operator") | ||||
|       ) +: | ||||
|       SOps(InfixL)(Mul from "*", Div from "/", Mod from "%") +: | ||||
|       SOps(Prefix)( | ||||
| @@ -115,16 +110,13 @@ object parser { | ||||
|   private lazy val `<pair-elem-type>` = | ||||
|     (`<base-type>` <**> (`<array-type>` </> identity)) | | ||||
|       ((UntypedPairType from `<pair-type>`) <**> | ||||
|         ((`<pair-elems-type>` <**> `<array-type>`.explain( | ||||
|           "non-erased pair types cannot be nested" | ||||
|         )).map(arr => (_: UntypedPairType) => arr) </> identity)) | ||||
|         ((`<pair-elems-type>` <**> `<array-type>`) | ||||
|           .map(arr => (_: UntypedPairType) => arr) </> identity)) | ||||
|  | ||||
|   // Statements | ||||
|   private lazy val `<program>` = Program( | ||||
|     "begin" ~> many( | ||||
|       atomic( | ||||
|         (`<type>`.label("function declaration") <~> `<ident>` <~ "(") | ||||
|       ) <**> `<partial-func-decl>` | ||||
|       atomic(`<type>`.label("function declaration") <~> `<ident>` <~ "(") <**> `<partial-func-decl>` | ||||
|     ).label("function declaration"), | ||||
|     (atomic(`<ident>` <~ "(") ~> fail("function is missing return type") | `<stmt>`.label( | ||||
|       "main program body" | ||||
| @@ -132,9 +124,9 @@ object parser { | ||||
|   ) | ||||
|   private lazy val `<partial-func-decl>` = | ||||
|     FuncDecl( | ||||
|       sepBy(`<param>`, ",") <~ ")".label("parenthesis") <~ "is", | ||||
|       sepBy(`<param>`, ",") <~ ")" <~ "is", | ||||
|       `<stmt>`.guardAgainst { | ||||
|         case stmts if !stmts.isReturning => Seq("all functions must end in a returning statement") | ||||
|         case stmts if !stmts.isReturning => Seq("All functions must end in a returning statement") | ||||
|       } <~ "end" | ||||
|     ) | ||||
|   private lazy val `<param>` = Param(`<type>`, `<ident>`) | ||||
| @@ -159,11 +151,8 @@ object parser { | ||||
|       ) | ||||
|       | While("while" ~> `<expr>`.labelWithType(LabelType.Expr) <~ "do", `<stmt>` <~ "done") | ||||
|       | Block("begin" ~> `<stmt>` <~ "end") | ||||
|       | VarDecl( | ||||
|         `<type>`, | ||||
|         `<ident>` <~ "=".explain("functions must be defined on top of the main block"), | ||||
|         `<rvalue>`.label("valid initial value for variable") | ||||
|       ) | ||||
|       | VarDecl(`<type>`, `<ident>` <~ "=", `<rvalue>`.label("valid initial value for variable")) | ||||
|       // TODO: Can we inline the name of the variable in the message | ||||
|       | Assign(`<lvalue>` <~ "=", `<rvalue>`) | ||||
|   private lazy val `<lvalue>`: Parsley[LValue] = | ||||
|     `<pair-elem>` | `<ident-or-array-elem>` | ||||
|   | ||||
		Reference in New Issue
	
	Block a user