From 0955f19a816f134bcac188ec36f690e3367f30b6 Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Fri, 7 Feb 2025 15:39:04 +0000 Subject: [PATCH 1/5] feat: detect function declarations mid-body --- src/main/wacc/parser.scala | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/wacc/parser.scala b/src/main/wacc/parser.scala index dac9fcd..8098e84 100644 --- a/src/main/wacc/parser.scala +++ b/src/main/wacc/parser.scala @@ -6,6 +6,7 @@ import parsley.Parsley.{atomic, many, notFollowedBy, pure} import parsley.combinator.{countSome, sepBy} import parsley.expr.{precedence, SOps, InfixL, InfixN, InfixR, Prefix, Atoms} import parsley.errors.combinator._ +import parsley.errors.patterns.VerifiedErrors import parsley.syntax.zipped._ import parsley.cats.combinator.{some} import cats.data.NonEmptyList @@ -126,7 +127,7 @@ object parser { FuncDecl( 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(``, ``) @@ -151,7 +152,13 @@ object parser { ) | While("while" ~> ``.labelWithType(LabelType.Expr) <~ "do", `` <~ "done") | Block("begin" ~> `` <~ "end") - | VarDecl(``, `` <~ "=", ``.label("valid initial value for variable")) + | VarDecl( + ``, + `` <~ ("=" | "(".verifiedExplain( + "all function declarations must be above the main program body" + )), + ``.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 959c556eae337961664a66d8e6f70e7a559af2b4 Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Fri, 7 Feb 2025 15:39:50 +0000 Subject: [PATCH 2/5] fix: use verifiedExplain for missing return type check --- 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 8098e84..5403060 100644 --- a/src/main/wacc/parser.scala +++ b/src/main/wacc/parser.scala @@ -119,7 +119,7 @@ object parser { "begin" ~> many( atomic(``.label("function declaration") <~> `` <~ "(") <**> `` ).label("function declaration"), - (atomic(`` <~ "(") ~> fail("function is missing return type") | ``.label( + (atomic(`` <~ "(").verifiedExplain("function is missing return type") | ``.label( "main program body" )) <~ "end" ) From d32855cc293928b287bc3c4202396f2122ec4906 Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Fri, 7 Feb 2025 15:40:49 +0000 Subject: [PATCH 3/5] feat: detect pointer operators --- src/main/wacc/parser.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/wacc/parser.scala b/src/main/wacc/parser.scala index 5403060..8141a4c 100644 --- a/src/main/wacc/parser.scala +++ b/src/main/wacc/parser.scala @@ -91,7 +91,8 @@ object parser { ``, Parens("(" ~> `` <~ ")") ) - private val `` = Ident(ident) + private val `` = + Ident(ident) | some("*" | "&").verifiedExplain("pointer operators are not allowed") private lazy val `` = `` <**> (`` identity) private val `` = ArrayElem(some("[" ~> `` <~ "]")) From 4738207523be857b0a6c766406ee573c6f4619c5 Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Fri, 7 Feb 2025 16:22:00 +0000 Subject: [PATCH 4/5] refactor: make missing return type message more precise --- src/main/wacc/parser.scala | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/wacc/parser.scala b/src/main/wacc/parser.scala index 8141a4c..115dc58 100644 --- a/src/main/wacc/parser.scala +++ b/src/main/wacc/parser.scala @@ -117,12 +117,17 @@ object parser { // Statements private lazy val `` = Program( - "begin" ~> many( - atomic(``.label("function declaration") <~> `` <~ "(") <**> `` - ).label("function declaration"), - (atomic(`` <~ "(").verifiedExplain("function is missing return type") | ``.label( + "begin" ~> ( + many( + atomic( + ``.label("function declaration") <~> `` <~ "(" + ) <**> `` + ).label("function declaration") | + atomic(`` <~ "(").verifiedExplain("function declaration is missing return type") + ), + ``.label( "main program body" - )) <~ "end" + ) <~ "end" ) private lazy val `` = FuncDecl( From 4bf63454f4f8daa2f438898b6396fec6e4ad1a36 Mon Sep 17 00:00:00 2001 From: Barf-Vader <47476490+Barf-Vader@users.noreply.github.com> Date: Fri, 7 Feb 2025 16:27:32 +0000 Subject: [PATCH 5/5] fix: catch function call without keyword with parenscheck --- src/main/wacc/parser.scala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/wacc/parser.scala b/src/main/wacc/parser.scala index 8141a4c..71198b2 100644 --- a/src/main/wacc/parser.scala +++ b/src/main/wacc/parser.scala @@ -13,6 +13,7 @@ import cats.data.NonEmptyList import parsley.errors.DefaultErrorBuilder import parsley.errors.ErrorBuilder import parsley.errors.tokenextractors.LexToken +import parsley.character.char object parser { import lexer.implicits.implicitSymbol @@ -49,6 +50,9 @@ object parser { case Expr case Pair + val _parensCheck = + char('(').verifiedExplain("functions can only be called using 'call' keyword") + implicit val builder: ErrorBuilder[String] = new DefaultErrorBuilder with LexToken { def tokens = errTokens } @@ -67,8 +71,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)(