Files
WACC_37/src/main/wacc/frontend/Error.scala

127 lines
3.7 KiB
Scala

package wacc
import wacc.ast.Position
import wacc.types._
import java.io.File
private val SYNTAX_ERROR = 100
private val SEMANTIC_ERROR = 200
/** Error types for semantic errors
*/
enum Error {
case DuplicateDeclaration(ident: ast.Ident)
case UndeclaredVariable(ident: ast.Ident)
case UndefinedFunction(ident: ast.Ident)
case FunctionParamsMismatch(ident: ast.Ident, expected: Int, got: Int, funcType: FuncType)
case SemanticError(pos: Position, msg: String)
case TypeMismatch(pos: Position, expected: SemType, got: SemType, msg: String)
case InternalError(pos: Position, msg: String)
case SyntaxError(file: File, msg: String)
}
extension (e: Error) {
def exitCode: Int = e match {
case Error.SyntaxError(_, _) => SYNTAX_ERROR
case _ => SEMANTIC_ERROR
}
}
/** Function to handle printing the details of a given semantic error
*
* @param error
* Error object
* @param errorContent
* Contents of the file to generate code snippets
*/
def formatError(error: Error): String = {
val sb = new StringBuilder()
/** Format the file of an error
*
* @param file
* File of the error
*/
def formatFile(file: File): Unit = {
sb.append(s"File: ${file.getCanonicalPath}\n")
}
/** Function to format the position of an error
*
* @param pos
* Position of the error
*/
def formatPosition(pos: Position): Unit = {
formatFile(pos.file)
sb.append(s"(line ${pos.line}, column ${pos.column}):\n")
}
/** Function to highlight a section of code for an error message
*
* @param pos
* Position of the error
* @param size
* Size(in chars) of section to highlight
*/
def formatHighlight(pos: Position, size: Int): Unit = {
val lines = os.read(os.Path(pos.file.getCanonicalPath)).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"
sb.append(
s" >$preLine\n >$midLine\n$linePointer >$postLine\netscape"
)
}
error match {
case Error.SyntaxError(_, _) =>
sb.append("Syntax error:\n")
case _ =>
sb.append("Semantic error:\n")
}
error match {
case Error.DuplicateDeclaration(ident) =>
formatPosition(ident.pos)
sb.append(s"Duplicate declaration of identifier ${ident.v}\n")
formatHighlight(ident.pos, ident.v.length)
case Error.UndeclaredVariable(ident) =>
formatPosition(ident.pos)
sb.append(s"Undeclared variable ${ident.v}\n")
formatHighlight(ident.pos, ident.v.length)
case Error.UndefinedFunction(ident) =>
formatPosition(ident.pos)
sb.append(s"Undefined function ${ident.v}\n")
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\n")
sb.append(
s"(function ${id.v} has type (${funcType.params.mkString(", ")}) -> ${funcType.returnType})\n"
)
formatHighlight(id.pos, 1)
case Error.TypeMismatch(pos, expected, got, msg) =>
formatPosition(pos)
sb.append(s"Type mismatch: $msg\nExpected: $expected\nGot: $got\n")
formatHighlight(pos, 1)
case Error.SemanticError(pos, msg) =>
formatPosition(pos)
sb.append(msg + "\n")
formatHighlight(pos, 1)
case wacc.Error.InternalError(pos, msg) =>
formatPosition(pos)
sb.append(s"Internal error: $msg\n")
formatHighlight(pos, 1)
case Error.SyntaxError(file, msg) =>
formatFile(file)
sb.append(msg + "\n")
sb.append("\n")
}
sb.toString()
}