summaryrefslogtreecommitdiff
path: root/src/parsers
diff options
context:
space:
mode:
authorBen Bridle <bridle.benjamin@gmail.com>2025-02-15 08:20:18 +1300
committerBen Bridle <bridle.benjamin@gmail.com>2025-02-15 08:20:18 +1300
commit4e8fae09f0f7d6f3a4ddbe285aeb01ef0622b761 (patch)
tree79eab5ef0f5d3eee7949a317db50489dac2fce99 /src/parsers
parente39505931b05be321ee2b04c41a9739f00c19208 (diff)
downloadtorque-asm-4e8fae09f0f7d6f3a4ddbe285aeb01ef0622b761.zip
Implement semantic error reporting
Diffstat (limited to 'src/parsers')
-rw-r--r--src/parsers/semantic.rs79
-rw-r--r--src/parsers/syntactic.rs2
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;
}
}