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