From cb3956f5bb8c3da8fb1b6401f2a2f055ea921794 Mon Sep 17 00:00:00 2001
From: Bhavya Kukkar <bhavyakukkar@gmail.com>
Date: Thu, 3 Oct 2024 17:06:16 +0530
Subject: [PATCH] Recursive vs. One-shot Parser

- new switch `parse_defs` on `struct Parser` that is read in
  `Parser.read_one` and disables parsing new syntax definitions if
  `false`
- made `Parser` public so that it can be used directly without relying
  on `fn parse`
- made field `Parser.reader` public so that it can be used as it was
  being used for reporting location of failure in `fn parse`
- new Parser constructors `Parser::recursive` and `Parser::one_shot` to
  construct Parsers that do and do not have the ability to parse new
  syntax definitions, respectively
- made fn `Parser.read_all` public so that it can be used directly
  without relying on `fn parse`
---
 crates/ast/src/lib.rs | 28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/crates/ast/src/lib.rs b/crates/ast/src/lib.rs
index 9f6415c..41f02fb 100644
--- a/crates/ast/src/lib.rs
+++ b/crates/ast/src/lib.rs
@@ -134,6 +134,7 @@ impl std::fmt::Display for Ast {
 pub fn parse(syntax: &Syntax, source: SourceFile) -> Result<Option<Ast>, Error> {
     let mut parser = Parser {
         reader: lex(source)?,
+        parse_defs: true,
     };
     let result = parser.read_all(syntax);
     result.map_err(|msg| msg.at(parser.reader.peek().unwrap().span.clone()))
@@ -164,8 +165,9 @@ pub fn read_syntax(source: SourceFile) -> Result<Syntax, Error> {
     result.map_err(|msg: ErrorMessage| msg.at(reader.peek().unwrap().span.clone()))
 }
 
-struct Parser {
-    reader: peek2::Reader<SpannedToken>,
+pub struct Parser {
+    pub reader: peek2::Reader<SpannedToken>,
+    parse_defs: bool,
 }
 
 fn read_syntax_def(reader: &mut peek2::Reader<SpannedToken>) -> Result<(SyntaxDefinition, Span)> {
@@ -298,6 +300,24 @@ enum ReadOneResult {
 }
 
 impl Parser {
+    /// Construct a new parser that has the ability to parse new syntax-definitions when
+    /// [`Parser::read_all`] is called
+    pub fn recursive(reader: peek2::Reader<SpannedToken>) -> Self {
+        Parser {
+            reader,
+            parse_defs: true,
+        }
+    }
+
+    /// Construct a new parser that does not have the ability to parse new syntax-definitions
+    /// when [`Parser::read_all`] is called
+    pub fn one_shot(reader: peek2::Reader<SpannedToken>) -> Self {
+        Parser {
+            reader,
+            parse_defs: false,
+        }
+    }
+
     fn skip_comments(&mut self) {
         while self.reader.peek().unwrap().is_comment() {
             self.reader.next().unwrap();
@@ -325,7 +345,7 @@ impl Parser {
             self.skip_comments();
             let peek = self.reader.peek().unwrap();
             let raw = peek.raw();
-            if raw == "syntax" {
+            if self.parse_defs && raw == "syntax" {
                 tracing::trace!("see syntax keyword, parsing syntax definition...");
                 let (def, span) = read_syntax_def(&mut self.reader)?;
                 return Ok(ReadOneResult::Progress(Ast::SyntaxDefinition {
@@ -478,7 +498,7 @@ impl Parser {
         }
     }
 
-    fn read_all(&mut self, syntax: &Syntax) -> Result<Option<Ast>> {
+    pub fn read_all(&mut self, syntax: &Syntax) -> Result<Option<Ast>> {
         let result = self.read_expr(syntax, &HashSet::new(), None)?;
         let peek = self.reader.peek().unwrap();
         if !peek.is_eof() {