From 69b878d11984b3cf2e1cccc33318bc64c9f62554 Mon Sep 17 00:00:00 2001 From: Miquel Sabaté Solà Date: Thu, 19 Dec 2024 12:59:03 +0100 Subject: parser: Allow for parenthesized expressions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some expressions might be enclosed with parenthesis in order to avoid ambiguations when evaluating them. Account for this on the parser when parsing expressions. Note that this is strictly only on the `parse_expression` function; statements or other top level constructs cannot be enclosed inside of parenthesis. Signed-off-by: Miquel Sabaté Solà --- lib/xixanta/src/parser.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'lib/xixanta/src/parser.rs') diff --git a/lib/xixanta/src/parser.rs b/lib/xixanta/src/parser.rs index 19b4530..d2bb75b 100644 --- a/lib/xixanta/src/parser.rs +++ b/lib/xixanta/src/parser.rs @@ -634,6 +634,24 @@ impl Parser { // and the offset has been set accordingly). Returns a new node for the // expression at hand. fn parse_expression(&mut self, line: &str) -> Result { + let first = line.chars().next().unwrap_or_default(); + + if first == '(' { + // Skip '(' character and whitespace characters in between. + self.next(); + self.skip_whitespace(line); + + // Extract what's inside of the enclosing parenthesis. + let paren = self.find_matching_paren(line, self.offset)?; + let l = line.get(self.offset..paren).unwrap_or_default(); + + // And return what you can parse from the inner expression. + self.offset = 0; + return self.parse_expression(l); + } + + // There's no complex expression going on. Hence, we can try to parse an + // "identifier" and pass it along. let (id, nt) = self.parse_identifier(line)?; if nt == NodeType::Label { @@ -1023,6 +1041,31 @@ mod tests { ); } + #[test] + fn parse_paren_expression() { + let line = "ldx #(Variable)"; + let mut parser = Parser::default(); + assert!(parser.parse(line.as_bytes()).is_ok()); + + let instr = parser.nodes.last().unwrap(); + assert_eq!(instr.node_type, NodeType::Instruction); + assert!(instr.right.is_none()); + assert!(instr.args.is_none()); + + let node = instr.left.clone().unwrap(); + assert_eq!(node.node_type, NodeType::Literal); + assert!(node.right.is_none()); + assert!(node.args.is_none()); + + let inner = node.left.clone().unwrap(); + assert_eq!(inner.node_type, NodeType::Value); + assert_eq!(inner.value.value, "Variable"); + assert_eq!( + line.get(inner.value.start..inner.value.end).unwrap(), + "Variable" + ); + } + #[test] fn parse_bad_literals() { for line in vec!["#", "#%", "$"].into_iter() { -- cgit v1.2.3