From 09036040d6316ed63ac76722255e3078693eabe7 Mon Sep 17 00:00:00 2001 From: Guy C Date: Fri, 7 Feb 2025 16:13:50 +0000 Subject: [PATCH] refactor: further commenting to the parser --- src/main/wacc/parser.scala | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/wacc/parser.scala b/src/main/wacc/parser.scala index 92f7487..d4b4d25 100644 --- a/src/main/wacc/parser.scala +++ b/src/main/wacc/parser.scala @@ -73,6 +73,7 @@ object parser { SOps(InfixL)(Mul from "*", Div from "/", Mod from "%") +: SOps(Prefix)( Not from "!", + // notFollowedBy(negateCheck) ensures that negative numbers are parsed as a single int literal (Negate from (notFollowedBy(negateCheck) ~> "-")).hide, Len from "len", Ord from "ord", @@ -114,7 +115,16 @@ object parser { ((`` <**> ``) .map(arr => (_: UntypedPairType) => arr) identity)) - // Statements + /** Statements + * + * Atomic is used in two places here: + * 1. Atomic for function return type - code may be a variable declaration instead, If we were + * to factor out the type, the resulting code would be rather messy. It can only fail once + * in the entire program so it creates minimal overhead. + * 2. Atomic for function missing return type check - there is no easy way around an explicit + * invalid syntax check, this only happens at most once per program so this is not a major + * concern. + */ private lazy val `` = Program( "begin" ~> many( atomic(``.label("function declaration") <~> `` <~ "(") <**> `` @@ -175,6 +185,13 @@ object parser { ) extension (stmts: NonEmptyList[Stmt]) { + + /** Determines whether a function body is guaranteed to return in all cases This is required as + * all functions must end via a "return" or "exit" statement + * + * @return + * true if the statement list ends in a return statement, false otherwise + */ def isReturning: Boolean = stmts.last match { case Return(_) | Exit(_) => true case If(_, thenStmt, elseStmt) => thenStmt.isReturning && elseStmt.isReturning