fix: fix incorrect semantic error logging by refactoring error.scala from frontend

This commit is contained in:
Jonny
2025-03-01 01:34:05 +00:00
parent 667fbf4949
commit 01b38b1445
2 changed files with 70 additions and 69 deletions

View File

@@ -53,14 +53,15 @@ def frontend(
if (errors.result.isEmpty) IO.pure(Right(typedProg)) if (errors.result.isEmpty) IO.pure(Right(typedProg))
else { else {
given errorContent: String = contents
val exitCode = errors.result.view.map { val exitCode = errors.result.view.map {
case _: Error.InternalError => 201 case _: Error.InternalError => 201
case _ => 200 case _ => 200
}.max }.max
logger.error(s"Semantic errors:\n${errors.result.mkString("\n")}") *> IO.pure( val formattedErrors = errors.result.map(formatError).mkString("\n")
Left(exitCode)
) logger.error(s"Semantic errors:\n$formattedErrors") *> IO.pure(Left(exitCode))
} }
} }
} }

View File

@@ -2,7 +2,6 @@ package wacc
import wacc.ast.Position import wacc.ast.Position
import wacc.types._ import wacc.types._
import java.io.PrintStream
/** Error types for semantic errors /** Error types for semantic errors
*/ */
@@ -24,71 +23,72 @@ enum Error {
* @param errorContent * @param errorContent
* Contents of the file to generate code snippets * Contents of the file to generate code snippets
*/ */
def printError(error: Error)(using errorContent: String, stdout: PrintStream): Unit = { def formatError(error: Error)(using errorContent: String): String = {
stdout.println("Semantic error:") val sb = new StringBuilder()
error match { sb.append("Semantic error:\n")
case Error.DuplicateDeclaration(ident) =>
printPosition(ident.pos) /** Function to format the position of an error
stdout.println(s"Duplicate declaration of identifier ${ident.v}") *
highlight(ident.pos, ident.v.length) * @param pos
case Error.UndeclaredVariable(ident) => * Position of the error
printPosition(ident.pos) */
stdout.println(s"Undeclared variable ${ident.v}") def formatPosition(pos: Position): Unit = {
highlight(ident.pos, ident.v.length) sb.append(s"(line ${pos.line}, column ${pos.column}):\n")
case Error.UndefinedFunction(ident) =>
printPosition(ident.pos)
stdout.println(s"Undefined function ${ident.v}")
highlight(ident.pos, ident.v.length)
case Error.FunctionParamsMismatch(id, expected, got, funcType) =>
printPosition(id.pos)
stdout.println(s"Function expects $expected parameters, got $got")
stdout.println(
s"(function ${id.v} has type (${funcType.params.mkString(", ")}) -> ${funcType.returnType})"
)
highlight(id.pos, 1)
case Error.TypeMismatch(pos, expected, got, msg) =>
printPosition(pos)
stdout.println(s"Type mismatch: $msg\nExpected: $expected\nGot: $got")
highlight(pos, 1)
case Error.SemanticError(pos, msg) =>
printPosition(pos)
stdout.println(msg)
highlight(pos, 1)
case wacc.Error.InternalError(pos, msg) =>
printPosition(pos)
stdout.println(s"Internal error: $msg")
highlight(pos, 1)
} }
} /** Function to highlight a section of code for an error message
/** Function to highlight a section of code for an error message
* *
* @param pos * @param pos
* Position of the error * Position of the error
* @param size * @param size
* Size(in chars) of section to highlight * Size(in chars) of section to highlight
* @param errorContent
* Contents of the file to generate code snippets
*/ */
def highlight(pos: Position, size: Int)(using errorContent: String, stdout: PrintStream): Unit = { def formatHighlight(pos: Position, size: Int): Unit = {
val lines = errorContent.split("\n") val lines = errorContent.split("\n")
val preLine = if (pos.line > 1) lines(pos.line - 2) else "" val preLine = if (pos.line > 1) lines(pos.line - 2) else ""
val midLine = lines(pos.line - 1) val midLine = lines(pos.line - 1)
val postLine = if (pos.line < lines.size) lines(pos.line) else "" val postLine = if (pos.line < lines.size) lines(pos.line) else ""
val linePointer = " " * (pos.column + 2) + ("^" * (size)) + "\n" val linePointer = " " * (pos.column + 2) + ("^" * (size)) + "\n"
stdout.println( sb.append(
s" >$preLine\n >$midLine\n$linePointer >$postLine" s" >$preLine\n >$midLine\n$linePointer >$postLine\netscape"
) )
} }
error match {
case Error.DuplicateDeclaration(ident) =>
formatPosition(ident.pos)
sb.append(s"Duplicate declaration of identifier ${ident.v}")
formatHighlight(ident.pos, ident.v.length)
case Error.UndeclaredVariable(ident) =>
formatPosition(ident.pos)
sb.append(s"Undeclared variable ${ident.v}")
formatHighlight(ident.pos, ident.v.length)
case Error.UndefinedFunction(ident) =>
formatPosition(ident.pos)
sb.append(s"Undefined function ${ident.v}")
formatHighlight(ident.pos, ident.v.length)
case Error.FunctionParamsMismatch(id, expected, got, funcType) =>
formatPosition(id.pos)
sb.append(s"Function expects $expected parameters, got $got")
sb.append(
s"(function ${id.v} has type (${funcType.params.mkString(", ")}) -> ${funcType.returnType})"
)
formatHighlight(id.pos, 1)
case Error.TypeMismatch(pos, expected, got, msg) =>
formatPosition(pos)
sb.append(s"Type mismatch: $msg\nExpected: $expected\nGot: $got")
formatHighlight(pos, 1)
case Error.SemanticError(pos, msg) =>
formatPosition(pos)
sb.append(msg)
formatHighlight(pos, 1)
case wacc.Error.InternalError(pos, msg) =>
formatPosition(pos)
sb.append(s"Internal error: $msg")
formatHighlight(pos, 1)
}
sb.toString()
/** Function to print the position of an error
*
* @param pos
* Position of the error
*/
def printPosition(pos: Position)(using stdout: PrintStream): Unit = {
stdout.println(s"(line ${pos.line}, column ${pos.column}):")
} }