diff --git a/src/main/wacc/parser.scala b/src/main/wacc/parser.scala index 71ae4c4..c167ca1 100644 --- a/src/main/wacc/parser.scala +++ b/src/main/wacc/parser.scala @@ -6,12 +6,14 @@ 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 import parsley.errors.DefaultErrorBuilder import parsley.errors.ErrorBuilder import parsley.errors.tokenextractors.LexToken +import parsley.character.char object parser { import lexer.implicits.implicitSymbol @@ -48,7 +50,9 @@ object parser { case Expr case Pair - // Lexer-backed errorBuilder + 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)( @@ -92,7 +96,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("[" ~> `` <~ "]")) @@ -125,18 +130,23 @@ object parser { concern. */ private lazy val `` = Program( - "begin" ~> many( - atomic(``.label("function declaration") <~> `` <~ "(") <**> `` - ).label("function declaration"), - (atomic(`` <~ "(") ~> fail("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( 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(``, ``) @@ -161,7 +171,14 @@ object parser { ) | While("while" ~> ``.labelWithType(LabelType.Expr) <~ "do", `` <~ "done") | Block("begin" ~> `` <~ "end") - | VarDecl(``, `` <~ "=", ``) + | 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] = `` | ``