summaryrefslogtreecommitdiff
path: root/src/parsers/semantic.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/parsers/semantic.rs')
-rw-r--r--src/parsers/semantic.rs79
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
}
}
-
}
}
}