diff options
Diffstat (limited to 'src/parsers')
| -rw-r--r-- | src/parsers/semantic.rs | 79 | ||||
| -rw-r--r-- | src/parsers/syntactic.rs | 2 | 
2 files changed, 62 insertions, 19 deletions
diff --git a/src/parsers/semantic.rs b/src/parsers/semantic.rs index 44861e1..7ef4a4a 100644 --- a/src/parsers/semantic.rs +++ b/src/parsers/semantic.rs @@ -43,7 +43,7 @@ impl Tokens {      }      /// Pull tokens until the predicate returns true, otherwise return Err. -    pub fn pull_until(&mut self, predicate: fn(&syn::Token) -> bool) -> Result<Self, ()> { +    pub fn pull_until(&mut self, mut predicate: impl FnMut(&syn::Token) -> bool) -> Result<Self, ()> {          let mut output = VecDeque::new();          while let Some(token) = self.tokens.pop_front() {              match predicate(&token) { @@ -83,18 +83,30 @@ impl ProgramParser {      pub fn parse(mut self) -> Program {          while let Some(syn) = self.tokens.pop() { -            if let SynVar::MacroDefinition(name) = syn.variant { -                // Collect all tokens up to the next definition terminator. -                let Ok(definition_tokens) = self.tokens.pull_until(is_terminator) else { -                    let variant = ParseErrorVariant::UnterminatedMacroDefinition; +            match syn.variant { +                SynVar::MacroDefinition(name) => { +                    // Collect all tokens up to the next definition terminator. +                    let Ok(definition_tokens) = self.tokens.pull_until(is_terminator) else { +                        let variant = ParseErrorVariant::UnterminatedMacroDefinition(name); +                        self.errors.push(ParseError { source: syn.source, variant}); +                        break; +                    }; +                    // Parse macro definition arguments. +                    match DefinitionParser::new(name, syn.source, definition_tokens).parse() { +                        Ok(definition) => self.definitions.push(definition), +                        Err(errors) => self.errors.extend(errors), +                    }; +                } +                SynVar::Comment(_) => (), +                SynVar::Symbol(name) => { +                    let parser = InvocationParser::new(name, &mut self.tokens); +                    self.invocations.push(parser.parse()); +                } +                _ => { +                    let variant = ParseErrorVariant::InvalidToken;                      self.errors.push(ParseError { source: syn.source, variant});                      break; -                }; -                // Parse macro definition arguments. -                match DefinitionParser::new(name, syn.source, definition_tokens).parse() { -                    Ok(definition) => self.definitions.push(definition), -                    Err(errors) => self.errors.extend(errors), -                }; +                }              }          } @@ -222,11 +234,8 @@ impl BlockParser {              let source = token.source;              match token.variant {                  SynVar::Symbol(name) => { -                    let mut arguments = Vec::new(); -                    while let Some(argument) = self.parse_invocation_argument() { -                        arguments.push(argument); -                    } -                    let invocation = Invocation { name, arguments }; +                    let parser = InvocationParser::new(name, &mut self.tokens); +                    let invocation = parser.parse();                      let variant = BlockTokenVariant::Invocation(invocation);                      let block_token = BlockToken { source, variant };                      self.block_tokens.push(block_token); @@ -244,6 +253,31 @@ impl BlockParser {          }          BlockDefinition { tokens: self.block_tokens, errors: self.errors }      } +} + + +struct InvocationParser<'a> { +    name: String, +    tokens: &'a mut Tokens, +    arguments: Vec<DefinitionVariant>, +    errors: Vec<ParseError>, +} + +impl<'a> InvocationParser<'a> { +    pub fn new(name: String, tokens: &'a mut Tokens) -> Self { +        Self { name, tokens, arguments: Vec::new(), errors: Vec::new() } +    } + +    pub fn parse(mut self) -> Invocation { +        while let Some(argument) = self.parse_invocation_argument() { +            self.arguments.push(argument); +        } +        Invocation { +            name: self.name, +            arguments: self.arguments, +            errors: self.errors, +        } +    }      fn parse_invocation_argument(&mut self) -> Option<DefinitionVariant> {          // Only continue if the first token is a separator. @@ -251,7 +285,17 @@ impl BlockParser {          if let Some(block_open) = self.tokens.pop_if(is_block_open) {              let source = block_open.source; -            if let Ok(block_tokens) = self.tokens.pull_until(is_block_close) { +            let mut depth = 1; +            let is_matching_block_close = |token: &syntactic::Token| { +                match token.variant { +                    syntactic::TokenVariant::BlockOpen => { +                        depth += 1; false } +                    syntactic::TokenVariant::BlockClose => { +                        depth -= 1; depth == 0 } +                    _ => false, +                } +            }; +            if let Ok(block_tokens) = self.tokens.pull_until(is_matching_block_close) {                  let block = BlockParser::new(block_tokens).parse();                  Some(DefinitionVariant::Block(block))              } else { @@ -283,7 +327,6 @@ impl BlockParser {                      None                  }              } -          }      }  } diff --git a/src/parsers/syntactic.rs b/src/parsers/syntactic.rs index c98a592..909dbaa 100644 --- a/src/parsers/syntactic.rs +++ b/src/parsers/syntactic.rs @@ -94,7 +94,7 @@ impl Iterator for SyntacticParser {              // Check if the comment fills the entire line.              if t.start_position.column == 0 && t.end_of_line() {                  if let Some(path) = comment.strip_prefix(": ") { -                    t.source_path = Some(PathBuf::from(path.trim())); +                    t.embedded_path = Some(PathBuf::from(path.trim()));                      t.embedded_first_line = t.start_position.line + 1;                  }              }  | 
