refactor: improvements to semantic error printing format
Merge request lab2425_spring/WACC_37!14 Co-authored-by: Barf-Vader <47476490+Barf-Vader@users.noreply.github.com> Co-authored-by: Guy C <gc1523@ic.ac.uk>
This commit is contained in:
commit
df4ed93726
@ -6,9 +6,56 @@ 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)
|
||||||
case InternalError(pos: Position, msg: String)
|
case InternalError(pos: Position, msg: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def printError(error: Error)(using errorContent: String): Unit = {
|
||||||
|
println("Semantic error:")
|
||||||
|
error match {
|
||||||
|
case Error.DuplicateDeclaration(ident) =>
|
||||||
|
printPosition(ident.pos)
|
||||||
|
println(s"Duplicate declaration of identifier ${ident.v}")
|
||||||
|
highlight(ident.pos, ident.v.length)
|
||||||
|
case Error.UndefinedIdentifier(ident, identType) =>
|
||||||
|
printPosition(ident.pos)
|
||||||
|
println(s"Undefined ${identType.toString.toLowerCase()} ${ident.v}")
|
||||||
|
highlight(ident.pos, 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) =>
|
||||||
|
printPosition(pos)
|
||||||
|
println(msg)
|
||||||
|
highlight(pos, 1)
|
||||||
|
case Error.SemanticError(pos, msg) =>
|
||||||
|
printPosition(pos)
|
||||||
|
println(msg)
|
||||||
|
highlight(pos, 1)
|
||||||
|
case wacc.Error.InternalError(pos, msg) =>
|
||||||
|
printPosition(pos)
|
||||||
|
println(s"Internal error: $msg")
|
||||||
|
highlight(pos, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
def highlight(pos: Position, size: Int)(using errorContent: String): Unit = {
|
||||||
|
val lines = errorContent.split("\n")
|
||||||
|
|
||||||
|
val preLine = if (pos.line > 1) lines(pos.line - 2) else ""
|
||||||
|
val midLine = lines(pos.line - 1)
|
||||||
|
val postLine = if (pos.line < lines.size) lines(pos.line) else ""
|
||||||
|
val linePointer = " " * (pos.column + 2) + ("^" * (size)) + "\n"
|
||||||
|
|
||||||
|
println(
|
||||||
|
s" >$preLine\n >$midLine\n$linePointer >$postLine"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def printPosition(pos: Position): Unit = {
|
||||||
|
println(s"(line ${pos.line}, column ${pos.column}):")
|
||||||
|
}
|
||||||
|
@ -38,7 +38,8 @@ def compile(contents: String): Int = {
|
|||||||
given ctx: typeChecker.TypeCheckerCtx = typeChecker.TypeCheckerCtx(names, errors)
|
given ctx: typeChecker.TypeCheckerCtx = typeChecker.TypeCheckerCtx(names, errors)
|
||||||
typeChecker.check(prog)
|
typeChecker.check(prog)
|
||||||
if (errors.result.nonEmpty) {
|
if (errors.result.nonEmpty) {
|
||||||
errors.result.foreach(println)
|
given errorContent: String = contents
|
||||||
|
errors.result.foreach(printError)
|
||||||
200
|
200
|
||||||
} else 0
|
} else 0
|
||||||
case Failure(msg) =>
|
case Failure(msg) =>
|
||||||
|
@ -31,7 +31,9 @@ val errConfig = new ErrorConfig {
|
|||||||
"fst" -> Label("pair extraction"),
|
"fst" -> Label("pair extraction"),
|
||||||
"snd" -> Label("pair extraction"),
|
"snd" -> Label("pair extraction"),
|
||||||
"false" -> Label("boolean literal"),
|
"false" -> Label("boolean literal"),
|
||||||
"true" -> Label("boolean literal")
|
"true" -> Label("boolean literal"),
|
||||||
|
"=" -> Label("assignment"),
|
||||||
|
"[" -> Label("array index")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
object lexer {
|
object lexer {
|
||||||
@ -83,8 +85,8 @@ object lexer {
|
|||||||
val errTokens = Seq(
|
val errTokens = Seq(
|
||||||
lexer.nonlexeme.names.identifier.map(v => s"identifier $v"),
|
lexer.nonlexeme.names.identifier.map(v => s"identifier $v"),
|
||||||
lexer.nonlexeme.integer.decimal32[Int].map(n => s"integer $n"),
|
lexer.nonlexeme.integer.decimal32[Int].map(n => s"integer $n"),
|
||||||
lexer.nonlexeme.character.ascii.map(c => s"character literal $c"),
|
(lexer.nonlexeme.character.ascii).map(c => s"character literal \'$c\'"),
|
||||||
lexer.nonlexeme.string.ascii.map(s => s"string literal $s"),
|
lexer.nonlexeme.string.ascii.map(s => s"string literal \"$s\""),
|
||||||
character.whitespace.map(_ => "")
|
character.whitespace.map(_ => "")
|
||||||
) ++ desc.symbolDesc.hardKeywords.map { k =>
|
) ++ desc.symbolDesc.hardKeywords.map { k =>
|
||||||
lexer.nonlexeme.symbol(k).as(s"keyword $k")
|
lexer.nonlexeme.symbol(k).as(s"keyword $k")
|
||||||
|
@ -118,7 +118,9 @@ object parser {
|
|||||||
"begin" ~> many(
|
"begin" ~> many(
|
||||||
atomic(`<type>`.label("function declaration") <~> `<ident>` <~ "(") <**> `<partial-func-decl>`
|
atomic(`<type>`.label("function declaration") <~> `<ident>` <~ "(") <**> `<partial-func-decl>`
|
||||||
).label("function declaration"),
|
).label("function declaration"),
|
||||||
`<stmt>`.label("main program body") <~ "end"
|
(atomic(`<ident>` <~ "(") ~> fail("function is missing return type") | `<stmt>`.label(
|
||||||
|
"main program body"
|
||||||
|
)) <~ "end"
|
||||||
)
|
)
|
||||||
private lazy val `<partial-func-decl>` =
|
private lazy val `<partial-func-decl>` =
|
||||||
FuncDecl(
|
FuncDecl(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user