package wacc import wacc.ast.Position import wacc.types._ /** 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) } /** 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 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.UndeclaredVariable(ident) => printPosition(ident.pos) println(s"Undeclared variable ${ident.v}") highlight(ident.pos, ident.v.length) case Error.UndefinedFunction(ident) => printPosition(ident.pos) println(s"Undefined function ${ident.v}") highlight(ident.pos, ident.v.length) case Error.FunctionParamsMismatch(id, expected, got, funcType) => printPosition(id.pos) println(s"Function expects $expected parameters, got $got") 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) println(s"Type mismatch: $msg\nExpected: $expected\nGot: $got") 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) } } /** 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 * @param errorContent * Contents of the file to generate code snippets */ 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" ) } /** Function to print the position of an error * * @param pos * Position of the error */ def printPosition(pos: Position): Unit = { println(s"(line ${pos.line}, column ${pos.column}):") }