diff options
Diffstat (limited to 'src/parsers/semantic.rs')
-rw-r--r-- | src/parsers/semantic.rs | 79 |
1 files changed, 61 insertions, 18 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 } } - } } } |