diff --git a/src/main/wacc/Error.scala b/src/main/wacc/Error.scala index c627246..5aa0ad7 100644 --- a/src/main/wacc/Error.scala +++ b/src/main/wacc/Error.scala @@ -6,9 +6,56 @@ import wacc.types._ enum Error { case DuplicateDeclaration(ident: ast.Ident) case UndefinedIdentifier(ident: ast.Ident, identType: renamer.IdentType) - case FunctionParamsMismatch(pos: Position, expected: Int, got: Int) case SemanticError(pos: Position, msg: String) case TypeMismatch(pos: Position, expected: SemType, got: SemType, 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}):") +} diff --git a/src/main/wacc/Main.scala b/src/main/wacc/Main.scala index 59796ff..93bc158 100644 --- a/src/main/wacc/Main.scala +++ b/src/main/wacc/Main.scala @@ -38,7 +38,8 @@ def compile(contents: String): Int = { given ctx: typeChecker.TypeCheckerCtx = typeChecker.TypeCheckerCtx(names, errors) typeChecker.check(prog) if (errors.result.nonEmpty) { - errors.result.foreach(println) + given errorContent: String = contents + errors.result.foreach(printError) 200 } else 0 case Failure(msg) => diff --git a/src/main/wacc/lexer.scala b/src/main/wacc/lexer.scala index 4a810c0..1c609a9 100644 --- a/src/main/wacc/lexer.scala +++ b/src/main/wacc/lexer.scala @@ -31,7 +31,9 @@ val errConfig = new ErrorConfig { "fst" -> Label("pair extraction"), "snd" -> Label("pair extraction"), "false" -> Label("boolean literal"), - "true" -> Label("boolean literal") + "true" -> Label("boolean literal"), + "=" -> Label("assignment"), + "[" -> Label("array index") ) } object lexer { @@ -83,8 +85,8 @@ object lexer { val errTokens = Seq( lexer.nonlexeme.names.identifier.map(v => s"identifier $v"), lexer.nonlexeme.integer.decimal32[Int].map(n => s"integer $n"), - lexer.nonlexeme.character.ascii.map(c => s"character literal $c"), - lexer.nonlexeme.string.ascii.map(s => s"string literal $s"), + (lexer.nonlexeme.character.ascii).map(c => s"character literal \'$c\'"), + lexer.nonlexeme.string.ascii.map(s => s"string literal \"$s\""), character.whitespace.map(_ => "") ) ++ desc.symbolDesc.hardKeywords.map { k => lexer.nonlexeme.symbol(k).as(s"keyword $k") diff --git a/src/main/wacc/parser.scala b/src/main/wacc/parser.scala index 5751732..dac9fcd 100644 --- a/src/main/wacc/parser.scala +++ b/src/main/wacc/parser.scala @@ -118,7 +118,9 @@ object parser { "begin" ~> many( atomic(`<type>`.label("function declaration") <~> `<ident>` <~ "(") <**> `<partial-func-decl>` ).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>` = FuncDecl(