aboutsummaryrefslogtreecommitdiff
path: root/lib/xixanta
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mikisabate@gmail.com>2025-01-15 15:58:34 +0100
committerMiquel Sabaté Solà <mikisabate@gmail.com>2025-01-15 16:02:34 +0100
commita11fd7b8fb7b1590defb692dcb17d9d7272aebe7 (patch)
tree2d807fe637c2da9977b09c65af2bfde982c251e2 /lib/xixanta
parentb6f2d3f8bf503efde672f4bb1a34e2ee8f985c38 (diff)
downloadtools.nes-a11fd7b8fb7b1590defb692dcb17d9d7272aebe7.tar.gz
tools.nes-a11fd7b8fb7b1590defb692dcb17d9d7272aebe7.zip
Split 'parse_expression' into more functions
The other cases in which fetching an "identifier" is not needed were starting to pile up. Hence, split them into separate functions and allow 'parse_expression' to be more simple. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
Diffstat (limited to 'lib/xixanta')
-rw-r--r--lib/xixanta/src/parser.rs156
1 files changed, 86 insertions, 70 deletions
diff --git a/lib/xixanta/src/parser.rs b/lib/xixanta/src/parser.rs
index 5a46daf..d42ff12 100644
--- a/lib/xixanta/src/parser.rs
+++ b/lib/xixanta/src/parser.rs
@@ -873,86 +873,102 @@ impl Parser {
Ok(idx)
}
- // Parse the expression under `line`. Indeces such as `self.column` and
- // `self.offset` are assumed to be correct at this point for the given
- // `line` (e.g. the line might not be a full line but rather a limited range
- // 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, Error> {
- // Cases where fetching an "identifier" is really not needed.
- let first = line.chars().next().unwrap_or_default();
- if first == '(' {
- // This is an expression under paranthesis. Get those out of the way
- // and call `parse_expression` again but for the expression inside.
+ // Parses the given line by assuming it's an expression under parenthesis.
+ // This function then grabs whatever is inside of these parenthesis and
+ // parses the expression inside of them.
+ fn extract_parenthesized_expression(&mut self, line: &str) -> Result<PNode, Error> {
+ // Skip '(' character and whitespace characters in between.
+ self.next();
+ self.skip_whitespace(line);
- // 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();
- // 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;
+ self.parse_expression(l)
+ }
- // And return what you can parse from the inner expression.
- self.offset = 0;
- return self.parse_expression(l);
- } else if first == '"' {
- let start = self.offset;
- let start_column = self.column;
- self.next();
+ // Consumes the given line by assuming is a string in double quotes.
+ fn parse_quoted_string(&mut self, line: &str) -> Result<PNode, Error> {
+ let start = self.offset;
+ let start_column = self.column;
- let mut prev = '"';
-
- for ch in line.get(self.offset..).unwrap_or("").chars() {
- if ch == '"' && prev != '\\' {
- self.next();
-
- return Ok(PNode {
- node_type: NodeType::Literal,
- value: PString {
- value: line.get(start..self.offset).unwrap().to_string(),
- line: self.line,
- start: start_column,
- end: self.column,
- },
- left: None,
- right: None,
- args: None,
- source: self.current_source,
- });
- }
+ // Skip opening quote.
+ self.next();
+ // Just iterate over the string until we find the matching quote
+ // character (unless it was escaped through '\').
+ let mut prev = '"';
+ for ch in line.get(self.offset..).unwrap_or("").chars() {
+ if ch == '"' && prev != '\\' {
self.next();
- prev = ch;
+
+ return Ok(PNode {
+ node_type: NodeType::Value,
+ value: PString {
+ value: line.get(start..self.offset).unwrap().to_string(),
+ line: self.line,
+ start: start_column,
+ end: self.column,
+ },
+ left: None,
+ right: None,
+ args: None,
+ source: self.current_source,
+ });
}
- return Err(self.parser_error("unclosed string"));
- } else if let Some(node_type) = self.get_unary_from_line(line) {
- // This is a unary operation. Just parse the right side and return
- // early.
- // Skip operator and whitespaces.
- let start = self.column;
self.next();
- self.skip_whitespace(line);
+ prev = ch;
+ }
- // Fetch the right side of the operator.
- let right_str = line.get(self.offset..).unwrap_or_default().trim_end();
- self.offset = 0;
- let right = self.parse_expression(right_str)?;
+ Err(self.parser_error("unclosed string"))
+ }
- return Ok(PNode {
- node_type,
- value: PString {
- value: String::from(""),
- line: self.line,
- start,
- end: right.value.end,
- },
- left: None,
- right: Some(Box::new(right)),
- args: None,
- source: self.current_source,
- });
+ // Returns a node for the given `node_type` unary operation, where the given
+ // `line` is the whole expression (including the unary operator).
+ fn parse_unary_operation(&mut self, node_type: NodeType, line: &str) -> Result<PNode, Error> {
+ // Skip operator and whitespaces.
+ let start = self.column;
+ self.next();
+ self.skip_whitespace(line);
+
+ // Fetch the right side of the operator.
+ let right_str = line.get(self.offset..).unwrap_or_default().trim_end();
+ self.offset = 0;
+ let right = self.parse_expression(right_str)?;
+
+ Ok(PNode {
+ node_type,
+ value: PString {
+ value: String::from(""),
+ line: self.line,
+ start,
+ end: right.value.end,
+ },
+ left: None,
+ right: Some(Box::new(right)),
+ args: None,
+ source: self.current_source,
+ })
+ }
+
+ // Parse the expression under `line`. Indeces such as `self.column` and
+ // `self.offset` are assumed to be correct at this point for the given
+ // `line` (e.g. the line might not be a full line but rather a limited range
+ // 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, Error> {
+ // Cases where fetching an "identifier" is really not needed.
+ let first = line.chars().next().unwrap_or_default();
+ if first == '(' {
+ return self.extract_parenthesized_expression(line);
+ } else if first == '"' {
+ return self.parse_quoted_string(line);
+ } else if let Some(node_type) = self.get_unary_from_line(line) {
+ return self.parse_unary_operation(node_type, line);
}
// Now that we have changed specific cases where detecting an
@@ -1562,7 +1578,7 @@ mod tests {
assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok());
let stmt = parser.nodes.last().unwrap().last().unwrap();
- let inner = stmt.args.as_ref().unwrap().first().clone().unwrap();
+ let inner = stmt.args.as_ref().unwrap().first().unwrap();
assert_eq!(inner.node_type, NodeType::Literal);
assert_eq!(inner.value.value, "\"a: b\"");
assert_eq!(