diff options
author | Ben Bridle <bridle.benjamin@gmail.com> | 2025-02-15 08:20:18 +1300 |
---|---|---|
committer | Ben Bridle <bridle.benjamin@gmail.com> | 2025-02-15 08:20:18 +1300 |
commit | 4e8fae09f0f7d6f3a4ddbe285aeb01ef0622b761 (patch) | |
tree | 79eab5ef0f5d3eee7949a317db50489dac2fce99 /src/parsers | |
parent | e39505931b05be321ee2b04c41a9739f00c19208 (diff) | |
download | torque-asm-4e8fae09f0f7d6f3a4ddbe285aeb01ef0622b761.zip |
Implement semantic error reporting
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; } } |