From 2ac7744e6843460c3742839371295b3343f99a95 Mon Sep 17 00:00:00 2001 From: Guy C Date: Thu, 6 Feb 2025 19:49:17 +0000 Subject: [PATCH 01/12] feat: implements error messages for DuplicateDeclaration and UndefinedIdentifier errors --- src/main/wacc/Error.scala | 27 +++++++++++++++++++++++++++ src/main/wacc/Main.scala | 3 ++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/main/wacc/Error.scala b/src/main/wacc/Error.scala index c627246..a90c340 100644 --- a/src/main/wacc/Error.scala +++ b/src/main/wacc/Error.scala @@ -12,3 +12,30 @@ enum Error { 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) => + println( + s"Duplicate declaration of identifier ${ident.v} at line: ${ident.getPosition.line} column: ${ident.getPosition.column}" + ) + highlight(ident.getPosition.line, ident.getPosition.column, ident.v.length) + case Error.UndefinedIdentifier(ident, identType) => + println( + s"Undefined ${identType.toString.toLowerCase} ${ident.v} at line: ${ident.getPosition.line} column: ${ident.getPosition.column}" + ) + highlight(ident.getPosition.line, ident.getPosition.column, ident.v.length) + case Error.FunctionParamsMismatch(ident, expected, got) => + println(s"Function ${ident.v} expects $expected parameters, got $got") + case Error.TypeMismatch(expected, got) => + println(s"Type mismatch: expected $expected, got $got") + } + +} + +def highlight(line: Int, column: Int, size: Int)(using errorContent: String): Unit = { + val lines = errorContent.split("\n") + val linePointer = " " * (column) + ("^" * (size)) + "\n" + println(s">${lines(line - 2)}\n>${lines(line - 1)}\n$linePointer>${lines(line)}") +} 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) => From a2c81883f49e90fb077d7556f1a4d3e58f662363 Mon Sep 17 00:00:00 2001 From: Guy C Date: Thu, 6 Feb 2025 20:46:45 +0000 Subject: [PATCH 02/12] refactor: improvements to semantic error printing format Co-authored by: al4423 --- src/main/wacc/Error.scala | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/main/wacc/Error.scala b/src/main/wacc/Error.scala index a90c340..87e0a35 100644 --- a/src/main/wacc/Error.scala +++ b/src/main/wacc/Error.scala @@ -20,12 +20,12 @@ def printError(error: Error)(using errorContent: String): Unit = { println( s"Duplicate declaration of identifier ${ident.v} at line: ${ident.getPosition.line} column: ${ident.getPosition.column}" ) - highlight(ident.getPosition.line, ident.getPosition.column, ident.v.length) + highlight(ident) case Error.UndefinedIdentifier(ident, identType) => println( - s"Undefined ${identType.toString.toLowerCase} ${ident.v} at line: ${ident.getPosition.line} column: ${ident.getPosition.column}" + s"Undefined ${identType.toString.toLowerCase()} ${ident.v} at line: ${ident.getPosition.line} column: ${ident.getPosition.column}" ) - highlight(ident.getPosition.line, ident.getPosition.column, ident.v.length) + highlight(ident) case Error.FunctionParamsMismatch(ident, expected, got) => println(s"Function ${ident.v} expects $expected parameters, got $got") case Error.TypeMismatch(expected, got) => @@ -34,8 +34,25 @@ def printError(error: Error)(using errorContent: String): Unit = { } -def highlight(line: Int, column: Int, size: Int)(using errorContent: String): Unit = { +def highlight(ident: ast.Ident)(using errorContent: String): Unit = { val lines = errorContent.split("\n") - val linePointer = " " * (column) + ("^" * (size)) + "\n" - println(s">${lines(line - 2)}\n>${lines(line - 1)}\n$linePointer>${lines(line)}") + + val preLine = if (ident.getPosition.line > 1) lines(ident.getPosition.line - 2) else "" + val midLine = lines(ident.getPosition.line - 1) + val postLine = lines(ident.getPosition.line) + val linePointer = " " * (ident.getPosition.column) + ("^" * (ident.v.length)) + "\n" + + println( + s">$preLine\n>$midLine\n$linePointer>$postLine" + ) + + // var lines: Iterator[String] = errorContent.linesIterator + + // lines = lines.drop(Math.max(0, ident.getPosition.line - 2)) + // println(s">${lines.next()}") + // if (lines.hasNext) + // println(s">${lines.next()}") + // println(" " * (ident.getPosition.column) + ("^" * (ident.v.length))) + // if(lines.hasNext) + // println(s">${lines.next()}") } From f24f8c87d8bc8b70cfb3246519d911b0934bf5da Mon Sep 17 00:00:00 2001 From: Barf-Vader <47476490+Barf-Vader@users.noreply.github.com> Date: Thu, 6 Feb 2025 23:08:34 +0000 Subject: [PATCH 03/12] fix: added explanation for nested pair error, added more errors --- src/main/wacc/parser.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/wacc/parser.scala b/src/main/wacc/parser.scala index 5751732..247ae31 100644 --- a/src/main/wacc/parser.scala +++ b/src/main/wacc/parser.scala @@ -110,8 +110,9 @@ object parser { private lazy val `` = (`` <**> (`` identity)) | ((UntypedPairType from ``) <**> - ((`` <**> ``) - .map(arr => (_: UntypedPairType) => arr) identity)) + ((`` <**> ``.explain( + "non-erased pair types cannot be nested" + )).map(arr => (_: UntypedPairType) => arr) identity)) // Statements private lazy val `` = Program( From b3ecae5dbbb93b5176f363bab9393ac761fcb37f Mon Sep 17 00:00:00 2001 From: Barf-Vader <47476490+Barf-Vader@users.noreply.github.com> Date: Thu, 6 Feb 2025 23:52:13 +0000 Subject: [PATCH 04/12] fix: quotes around char and str errors, added errors for assign and arrayIndex --- src/main/wacc/Error.scala | 14 +++++++------- src/main/wacc/lexer.scala | 8 +++++--- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/wacc/Error.scala b/src/main/wacc/Error.scala index 87e0a35..9d60b2a 100644 --- a/src/main/wacc/Error.scala +++ b/src/main/wacc/Error.scala @@ -20,12 +20,12 @@ def printError(error: Error)(using errorContent: String): Unit = { println( s"Duplicate declaration of identifier ${ident.v} at line: ${ident.getPosition.line} column: ${ident.getPosition.column}" ) - highlight(ident) + highlight(ident.getPosition, ident.v.length) case Error.UndefinedIdentifier(ident, identType) => println( s"Undefined ${identType.toString.toLowerCase()} ${ident.v} at line: ${ident.getPosition.line} column: ${ident.getPosition.column}" ) - highlight(ident) + highlight(ident.getPosition, ident.v.length) case Error.FunctionParamsMismatch(ident, expected, got) => println(s"Function ${ident.v} expects $expected parameters, got $got") case Error.TypeMismatch(expected, got) => @@ -34,13 +34,13 @@ def printError(error: Error)(using errorContent: String): Unit = { } -def highlight(ident: ast.Ident)(using errorContent: String): Unit = { +def highlight(pos: Position, size: Int)(using errorContent: String): Unit = { val lines = errorContent.split("\n") - val preLine = if (ident.getPosition.line > 1) lines(ident.getPosition.line - 2) else "" - val midLine = lines(ident.getPosition.line - 1) - val postLine = lines(ident.getPosition.line) - val linePointer = " " * (ident.getPosition.column) + ("^" * (ident.v.length)) + "\n" + val preLine = if (pos.line > 1) lines(pos.line - 2) else "" + val midLine = lines(pos.line - 1) + val postLine = lines(pos.line) + val linePointer = " " * (pos.column) + ("^" * (size)) + "\n" println( s">$preLine\n>$midLine\n$linePointer>$postLine" diff --git a/src/main/wacc/lexer.scala b/src/main/wacc/lexer.scala index 4a810c0..7a85dae 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") From a65cc018152379e0f8c4cff861e13d4d745c3409 Mon Sep 17 00:00:00 2001 From: Barf-Vader <47476490+Barf-Vader@users.noreply.github.com> Date: Fri, 7 Feb 2025 01:35:16 +0000 Subject: [PATCH 05/12] fix: added error messages for functions missing type, and late function decls --- src/main/wacc/lexer.scala | 7 ++++--- src/main/wacc/parser.scala | 22 ++++++++++++++-------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/wacc/lexer.scala b/src/main/wacc/lexer.scala index 7a85dae..8aa4607 100644 --- a/src/main/wacc/lexer.scala +++ b/src/main/wacc/lexer.scala @@ -33,7 +33,7 @@ val errConfig = new ErrorConfig { "false" -> Label("boolean literal"), "true" -> Label("boolean literal"), "=" -> Label("assignment"), - "[" -> Label("array index") + "[" -> Label("array index"), ) } object lexer { @@ -85,9 +85,10 @@ 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.character.ascii).map(c => s"character literal \'$c\'"), lexer.nonlexeme.string.ascii.map(s => s"string literal \"$s\""), - character.whitespace.map(_ => "") +// lexer.nonlexeme.symbol("()").as("function call, bruh use keyword 'call' to call functions"), + 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 247ae31..654d21b 100644 --- a/src/main/wacc/parser.scala +++ b/src/main/wacc/parser.scala @@ -12,6 +12,8 @@ import cats.data.NonEmptyList import parsley.errors.DefaultErrorBuilder import parsley.errors.ErrorBuilder import parsley.errors.tokenextractors.LexToken +import parsley.errors.patterns.VerifiedErrors +import parsley.character.char object parser { import lexer.implicits.implicitSymbol @@ -48,6 +50,10 @@ object parser { case Expr case Pair + val _parensCheck = + char('(').verifiedExplain("use keyword 'call' to call functions") + + implicit val builder: ErrorBuilder[String] = new DefaultErrorBuilder with LexToken { def tokens = errTokens } @@ -66,8 +72,8 @@ object parser { GreaterEq from ">=" ) +: SOps(InfixL)( - (Add from "+").label("binary operator"), - (Sub from "-").label("binary operator") + ((Add from "+").label("binary operator") | _parensCheck), + ((Sub from "-").label("binary operator") | _parensCheck) ) +: SOps(InfixL)(Mul from "*", Div from "/", Mod from "%") +: SOps(Prefix)( @@ -117,15 +123,15 @@ object parser { // Statements private lazy val `` = Program( "begin" ~> many( - atomic(``.label("function declaration") <~> `` <~ "(") <**> `` + atomic((``.label("function declaration") <~> `` <~ "(")) <**> `` ).label("function declaration"), - ``.label("main program body") <~ "end" + ((`` <~ "(")*> fail("function is missing return type") | ``.label("main program body")) <~ "end" ) private lazy val `` = FuncDecl( - sepBy(``, ",") <~ ")" <~ "is", + sepBy(``, ",") <~ ")".label("parenthesis") <~ "is", ``.guardAgainst { - case stmts if !stmts.isReturning => Seq("All functions must end in a returning statement") + case stmts if !stmts.isReturning => Seq("all functions must end in a returning statement") } <~ "end" ) private lazy val `` = Param(``, ``) @@ -150,8 +156,8 @@ object parser { ) | While("while" ~> ``.labelWithType(LabelType.Expr) <~ "do", `` <~ "done") | Block("begin" ~> `` <~ "end") - | VarDecl(``, `` <~ "=", ``.label("valid initial value for variable")) - // TODO: Can we inline the name of the variable in the message + | VarDecl(``, `` <~ "=".explain("functions must be defined on top of the main block"), + ``.label("valid initial value for variable")) | Assign(`` <~ "=", ``) private lazy val ``: Parsley[LValue] = `` | `` From ee1ea6c63b4c00d88f04e786a2b966f7f702066d Mon Sep 17 00:00:00 2001 From: Guy C Date: Fri, 7 Feb 2025 11:22:50 +0000 Subject: [PATCH 06/12] refactor: created printPosition method for unified error message format --- src/main/wacc/Error.scala | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/main/wacc/Error.scala b/src/main/wacc/Error.scala index 9d60b2a..a3a5f1e 100644 --- a/src/main/wacc/Error.scala +++ b/src/main/wacc/Error.scala @@ -17,19 +17,31 @@ def printError(error: Error)(using errorContent: String): Unit = { println("Semantic error:") error match { case Error.DuplicateDeclaration(ident) => + printPosition(ident.getPosition) println( - s"Duplicate declaration of identifier ${ident.v} at line: ${ident.getPosition.line} column: ${ident.getPosition.column}" + s"Duplicate declaration of identifier ${ident.v}" ) highlight(ident.getPosition, ident.v.length) case Error.UndefinedIdentifier(ident, identType) => + printPosition(ident.getPosition) println( - s"Undefined ${identType.toString.toLowerCase()} ${ident.v} at line: ${ident.getPosition.line} column: ${ident.getPosition.column}" + s"Undefined ${identType.toString.toLowerCase()} ${ident.v}" ) highlight(ident.getPosition, ident.v.length) case Error.FunctionParamsMismatch(ident, expected, got) => + printPosition(ident.getPosition) println(s"Function ${ident.v} expects $expected parameters, got $got") + highlight(ident.getPosition, ident.v.length) case Error.TypeMismatch(expected, got) => println(s"Type mismatch: expected $expected, got $got") + case Error.SemanticError(pos, msg) => + printPosition(pos) + println(s"$msg at line: ${pos.line} column: ${pos.column}") + highlight(pos, 1) + case wacc.Error.InternalError(pos, msg) => + printPosition(pos) + println(s"Internal error: $msg") + highlight(pos, 1) } } @@ -39,20 +51,14 @@ def highlight(pos: Position, size: Int)(using errorContent: String): Unit = { val preLine = if (pos.line > 1) lines(pos.line - 2) else "" val midLine = lines(pos.line - 1) - val postLine = lines(pos.line) - val linePointer = " " * (pos.column) + ("^" * (size)) + "\n" + 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" + s" >$preLine\n >$midLine\n$linePointer >$postLine" ) - - // var lines: Iterator[String] = errorContent.linesIterator - - // lines = lines.drop(Math.max(0, ident.getPosition.line - 2)) - // println(s">${lines.next()}") - // if (lines.hasNext) - // println(s">${lines.next()}") - // println(" " * (ident.getPosition.column) + ("^" * (ident.v.length))) - // if(lines.hasNext) - // println(s">${lines.next()}") +} + +def printPosition(pos: Position): Unit = { + println(s"(line ${pos.line}, column ${pos.column}):") } From 8583a815a89330c44a935e25da76f6521ceccd97 Mon Sep 17 00:00:00 2001 From: Guy C Date: Fri, 7 Feb 2025 11:23:18 +0000 Subject: [PATCH 07/12] refactor: style fixes in lexer and parser --- src/main/wacc/lexer.scala | 4 ++-- src/main/wacc/parser.scala | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/wacc/lexer.scala b/src/main/wacc/lexer.scala index 8aa4607..a00b004 100644 --- a/src/main/wacc/lexer.scala +++ b/src/main/wacc/lexer.scala @@ -33,7 +33,7 @@ val errConfig = new ErrorConfig { "false" -> Label("boolean literal"), "true" -> Label("boolean literal"), "=" -> Label("assignment"), - "[" -> Label("array index"), + "[" -> Label("array index") ) } object lexer { @@ -88,7 +88,7 @@ object lexer { (lexer.nonlexeme.character.ascii).map(c => s"character literal \'$c\'"), lexer.nonlexeme.string.ascii.map(s => s"string literal \"$s\""), // lexer.nonlexeme.symbol("()").as("function call, bruh use keyword 'call' to call functions"), - character.whitespace.map(_ => ""), + 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 654d21b..2f41ab0 100644 --- a/src/main/wacc/parser.scala +++ b/src/main/wacc/parser.scala @@ -53,7 +53,6 @@ object parser { val _parensCheck = char('(').verifiedExplain("use keyword 'call' to call functions") - implicit val builder: ErrorBuilder[String] = new DefaultErrorBuilder with LexToken { def tokens = errTokens } @@ -123,9 +122,13 @@ object parser { // Statements private lazy val `` = Program( "begin" ~> many( - atomic((``.label("function declaration") <~> `` <~ "(")) <**> `` + atomic( + (``.label("function declaration") <~> `` <~ "(") + ) <**> `` ).label("function declaration"), - ((`` <~ "(")*> fail("function is missing return type") | ``.label("main program body")) <~ "end" + ((`` <~ "(") *> fail("function is missing return type") | ``.label( + "main program body" + )) <~ "end" ) private lazy val `` = FuncDecl( @@ -156,8 +159,11 @@ object parser { ) | While("while" ~> ``.labelWithType(LabelType.Expr) <~ "do", `` <~ "done") | Block("begin" ~> `` <~ "end") - | VarDecl(``, `` <~ "=".explain("functions must be defined on top of the main block"), - ``.label("valid initial value for variable")) + | VarDecl( + ``, + `` <~ "=".explain("functions must be defined on top of the main block"), + ``.label("valid initial value for variable") + ) | Assign(`` <~ "=", ``) private lazy val ``: Parsley[LValue] = `` | `` From 731692d95a1580465a48e20f90cfa557a2fb349e Mon Sep 17 00:00:00 2001 From: Guy C Date: Fri, 7 Feb 2025 11:59:28 +0000 Subject: [PATCH 08/12] refactor: bringing in ast and error changes --- src/main/wacc/Error.scala | 10 +++++----- src/main/wacc/ast.scala | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/wacc/Error.scala b/src/main/wacc/Error.scala index a3a5f1e..c702fd2 100644 --- a/src/main/wacc/Error.scala +++ b/src/main/wacc/Error.scala @@ -28,11 +28,11 @@ def printError(error: Error)(using errorContent: String): Unit = { s"Undefined ${identType.toString.toLowerCase()} ${ident.v}" ) highlight(ident.getPosition, ident.v.length) - case Error.FunctionParamsMismatch(ident, expected, got) => - printPosition(ident.getPosition) - println(s"Function ${ident.v} expects $expected parameters, got $got") - highlight(ident.getPosition, ident.v.length) - case Error.TypeMismatch(expected, got) => + 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) => println(s"Type mismatch: expected $expected, got $got") case Error.SemanticError(pos, msg) => printPosition(pos) diff --git a/src/main/wacc/ast.scala b/src/main/wacc/ast.scala index 8ea99d7..1941a16 100644 --- a/src/main/wacc/ast.scala +++ b/src/main/wacc/ast.scala @@ -30,7 +30,9 @@ object ast { object StrLiter extends ParserBridgePos1[String, StrLiter] case class PairLiter()(val pos: Position) extends Expr6 object PairLiter extends ParserBridgePos0[PairLiter] - case class Ident(v: String, var uid: Int = -1)(val pos: Position) extends Expr6 with LValue + case class Ident(v: String, var uid: Int = -1)(val pos: Position) extends Expr6 with LValue { + def getPosition: Position = pos + } object Ident extends ParserBridgePos1[String, Ident] { def apply(v: String)(pos: Position): Ident = new Ident(v)(pos) } From c798fdf41637029fc1dde68e2dea59139c6b85ae Mon Sep 17 00:00:00 2001 From: Barf-Vader <47476490+Barf-Vader@users.noreply.github.com> Date: Fri, 7 Feb 2025 13:00:28 +0000 Subject: [PATCH 09/12] fix: made missing func return type error atomic --- src/main/wacc/parser.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/wacc/parser.scala b/src/main/wacc/parser.scala index 2f41ab0..7da0a0a 100644 --- a/src/main/wacc/parser.scala +++ b/src/main/wacc/parser.scala @@ -126,7 +126,7 @@ object parser { (``.label("function declaration") <~> `` <~ "(") ) <**> `` ).label("function declaration"), - ((`` <~ "(") *> fail("function is missing return type") | ``.label( + (atomic(`` <~ "(") ~> fail("function is missing return type") | ``.label( "main program body" )) <~ "end" ) From b6d8eb31e39380b41115f399621985b2a0962eb5 Mon Sep 17 00:00:00 2001 From: Guy C Date: Fri, 7 Feb 2025 12:46:47 +0000 Subject: [PATCH 10/12] feat: semantic error messages make use of msg strings passed from typeChecker --- src/main/wacc/Error.scala | 15 ++++++--------- src/main/wacc/parser.scala | 29 +++++++++-------------------- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/src/main/wacc/Error.scala b/src/main/wacc/Error.scala index c702fd2..724c08f 100644 --- a/src/main/wacc/Error.scala +++ b/src/main/wacc/Error.scala @@ -6,7 +6,6 @@ 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) @@ -18,25 +17,23 @@ def printError(error: Error)(using errorContent: String): Unit = { error match { case Error.DuplicateDeclaration(ident) => printPosition(ident.getPosition) - println( - s"Duplicate declaration of identifier ${ident.v}" - ) + println(s"Duplicate declaration of identifier ${ident.v}") highlight(ident.getPosition, ident.v.length) case Error.UndefinedIdentifier(ident, identType) => printPosition(ident.getPosition) - println( - s"Undefined ${identType.toString.toLowerCase()} ${ident.v}" - ) + println(s"Undefined ${identType.toString.toLowerCase()} ${ident.v}") highlight(ident.getPosition, 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) => - println(s"Type mismatch: expected $expected, got $got") + printPosition(pos) + println(msg) + highlight(pos, 1) case Error.SemanticError(pos, msg) => printPosition(pos) - println(s"$msg at line: ${pos.line} column: ${pos.column}") + println(msg) highlight(pos, 1) case wacc.Error.InternalError(pos, msg) => printPosition(pos) diff --git a/src/main/wacc/parser.scala b/src/main/wacc/parser.scala index 7da0a0a..dac9fcd 100644 --- a/src/main/wacc/parser.scala +++ b/src/main/wacc/parser.scala @@ -12,8 +12,6 @@ import cats.data.NonEmptyList import parsley.errors.DefaultErrorBuilder import parsley.errors.ErrorBuilder import parsley.errors.tokenextractors.LexToken -import parsley.errors.patterns.VerifiedErrors -import parsley.character.char object parser { import lexer.implicits.implicitSymbol @@ -50,9 +48,6 @@ object parser { case Expr case Pair - val _parensCheck = - char('(').verifiedExplain("use keyword 'call' to call functions") - implicit val builder: ErrorBuilder[String] = new DefaultErrorBuilder with LexToken { def tokens = errTokens } @@ -71,8 +66,8 @@ object parser { GreaterEq from ">=" ) +: SOps(InfixL)( - ((Add from "+").label("binary operator") | _parensCheck), - ((Sub from "-").label("binary operator") | _parensCheck) + (Add from "+").label("binary operator"), + (Sub from "-").label("binary operator") ) +: SOps(InfixL)(Mul from "*", Div from "/", Mod from "%") +: SOps(Prefix)( @@ -115,16 +110,13 @@ object parser { private lazy val `` = (`` <**> (`` identity)) | ((UntypedPairType from ``) <**> - ((`` <**> ``.explain( - "non-erased pair types cannot be nested" - )).map(arr => (_: UntypedPairType) => arr) identity)) + ((`` <**> ``) + .map(arr => (_: UntypedPairType) => arr) identity)) // Statements private lazy val `` = Program( "begin" ~> many( - atomic( - (``.label("function declaration") <~> `` <~ "(") - ) <**> `` + atomic(``.label("function declaration") <~> `` <~ "(") <**> `` ).label("function declaration"), (atomic(`` <~ "(") ~> fail("function is missing return type") | ``.label( "main program body" @@ -132,9 +124,9 @@ object parser { ) private lazy val `` = FuncDecl( - sepBy(``, ",") <~ ")".label("parenthesis") <~ "is", + sepBy(``, ",") <~ ")" <~ "is", ``.guardAgainst { - case stmts if !stmts.isReturning => Seq("all functions must end in a returning statement") + case stmts if !stmts.isReturning => Seq("All functions must end in a returning statement") } <~ "end" ) private lazy val `` = Param(``, ``) @@ -159,11 +151,8 @@ object parser { ) | While("while" ~> ``.labelWithType(LabelType.Expr) <~ "do", `` <~ "done") | Block("begin" ~> `` <~ "end") - | VarDecl( - ``, - `` <~ "=".explain("functions must be defined on top of the main block"), - ``.label("valid initial value for variable") - ) + | VarDecl(``, `` <~ "=", ``.label("valid initial value for variable")) + // TODO: Can we inline the name of the variable in the message | Assign(`` <~ "=", ``) private lazy val ``: Parsley[LValue] = `` | `` From a09d38a40fddca2cde7ae5012ae95f26bc44415a Mon Sep 17 00:00:00 2001 From: Barf-Vader <47476490+Barf-Vader@users.noreply.github.com> Date: Fri, 7 Feb 2025 13:33:25 +0000 Subject: [PATCH 11/12] fix: cleaned up comments, removed getPosition from ident --- src/main/wacc/ast.scala | 4 +--- src/main/wacc/lexer.scala | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/wacc/ast.scala b/src/main/wacc/ast.scala index 1941a16..8ea99d7 100644 --- a/src/main/wacc/ast.scala +++ b/src/main/wacc/ast.scala @@ -30,9 +30,7 @@ object ast { object StrLiter extends ParserBridgePos1[String, StrLiter] case class PairLiter()(val pos: Position) extends Expr6 object PairLiter extends ParserBridgePos0[PairLiter] - case class Ident(v: String, var uid: Int = -1)(val pos: Position) extends Expr6 with LValue { - def getPosition: Position = pos - } + case class Ident(v: String, var uid: Int = -1)(val pos: Position) extends Expr6 with LValue object Ident extends ParserBridgePos1[String, Ident] { def apply(v: String)(pos: Position): Ident = new Ident(v)(pos) } diff --git a/src/main/wacc/lexer.scala b/src/main/wacc/lexer.scala index a00b004..1c609a9 100644 --- a/src/main/wacc/lexer.scala +++ b/src/main/wacc/lexer.scala @@ -87,7 +87,6 @@ object lexer { 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.symbol("()").as("function call, bruh use keyword 'call' to call functions"), character.whitespace.map(_ => "") ) ++ desc.symbolDesc.hardKeywords.map { k => lexer.nonlexeme.symbol(k).as(s"keyword $k") From 31bb23480b13aba177c922fe229d7ad8ef2c3afd Mon Sep 17 00:00:00 2001 From: Barf-Vader <47476490+Barf-Vader@users.noreply.github.com> Date: Fri, 7 Feb 2025 13:36:18 +0000 Subject: [PATCH 12/12] fix: refactored code to use ident.pos --- src/main/wacc/Error.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/wacc/Error.scala b/src/main/wacc/Error.scala index 724c08f..5aa0ad7 100644 --- a/src/main/wacc/Error.scala +++ b/src/main/wacc/Error.scala @@ -16,13 +16,13 @@ def printError(error: Error)(using errorContent: String): Unit = { println("Semantic error:") error match { case Error.DuplicateDeclaration(ident) => - printPosition(ident.getPosition) + printPosition(ident.pos) println(s"Duplicate declaration of identifier ${ident.v}") - highlight(ident.getPosition, ident.v.length) + highlight(ident.pos, ident.v.length) case Error.UndefinedIdentifier(ident, identType) => - printPosition(ident.getPosition) + printPosition(ident.pos) println(s"Undefined ${identType.toString.toLowerCase()} ${ident.v}") - highlight(ident.getPosition, ident.v.length) + highlight(ident.pos, ident.v.length) case Error.FunctionParamsMismatch(pos, expected, got) => printPosition(pos) println(s"Function expects $expected parameters, got $got")