aboutsummaryrefslogtreecommitdiff
path: root/lib/xixanta/src/parser.rs
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mikisabate@gmail.com>2024-12-19 12:59:03 +0100
committerMiquel Sabaté Solà <mikisabate@gmail.com>2024-12-19 12:59:03 +0100
commit69b878d11984b3cf2e1cccc33318bc64c9f62554 (patch)
treecc9780abb2a1e8951dffc870a6848976f5628c9b /lib/xixanta/src/parser.rs
parent42ebea54e35062a1a998f25e8fe019a5e0205fd9 (diff)
downloadtools.nes-69b878d11984b3cf2e1cccc33318bc64c9f62554.tar.gz
tools.nes-69b878d11984b3cf2e1cccc33318bc64c9f62554.zip
parser: Allow for parenthesized expressions
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à <mikisabate@gmail.com>
Diffstat (limited to 'lib/xixanta/src/parser.rs')
-rw-r--r--lib/xixanta/src/parser.rs43
1 files changed, 43 insertions, 0 deletions
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<PNode, ParseError> {
+ 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 {
@@ -1024,6 +1042,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() {
let mut parser = Parser::default();