use crate::constants::{LAST_COLUMN, LAST_ROW}; use crate::expressions::{token::TokenType, utils::column_to_number}; use super::Lexer; use super::{ParsedRange, ParsedReference, Result}; impl Lexer { /// Consumes a reference in A1 style like: /// AS23, $AS23, AS$23, $AS$23, R12 /// Or returns an error fn consume_reference_a1(&mut self) -> Result { let mut absolute_column = false; let mut absolute_row = false; let mut position = self.position; let len = self.len; if position < len && self.chars[position] == '$' { absolute_column = true; position += 1; } let mut column = "".to_string(); while position < len { let x = self.chars[position].to_ascii_uppercase(); match x { 'A'..='Z' => column.push(x), _ => break, } position += 1; } if column.is_empty() { return Err(self.set_error("Failed to parse reference", position)); } if position < len && self.chars[position] == '$' { absolute_row = true; position += 1; } let mut row = "".to_string(); while position < len { let x = self.chars[position]; match x { '0'..='9' => row.push(x), _ => break, } position += 1; } // Note that row numbers could start with 0 self.position = position; let column = column_to_number(&column).map_err(|error| self.set_error(&error, position))?; match row.parse::() { Ok(row) => { if row > LAST_ROW { return Err(self.set_error("Row too large in reference", position)); } Ok(ParsedReference { column, row, absolute_column, absolute_row, }) } Err(..) => Err(self.set_error("Failed to parse integer", position)), } } // Parsing a range is a parser on it's own right. Here is the grammar: // // range -> cell | cell ':' cell | row ':' row | column ':' column // cell -> column row // column -> '$' column_name | column_name // row -> '$' row_name | row_name // column_name -> 'A'..'XFD' // row_name -> 1..1_048_576 // /// Consumes a range of references in A1 style like: /// AS23:AS24, $AS23:AS24, AS$23:AS24, $AS$23:AS24, R12:R23, $R12:R23, R$12:R23, $R$12:R23 pub(super) fn consume_range_a1(&mut self) -> Result { // first let's try to parse a cell let mut position = self.position; match self.consume_reference_a1() { Ok(cell) => { if self.peek_char() == Some(':') { // It's a range self.position += 1; if let Ok(cell2) = self.consume_reference_a1() { Ok(ParsedRange { left: cell, right: Some(cell2), }) } else { Err(self.set_error("Expecting reference in range", self.position)) } } else { // just a reference Ok(ParsedRange { left: cell, right: None, }) } } Err(_) => { self.position = position; // It's either a row range or a column range (or not a range at all) let len = self.len; let mut absolute_left = false; if position < len && self.chars[position] == '$' { absolute_left = true; position += 1; } let mut column_left = "".to_string(); let mut row_left = "".to_string(); while position < len { let x = self.chars[position].to_ascii_uppercase(); match x { 'A'..='Z' => column_left.push(x), '0'..='9' => row_left.push(x), _ => break, } position += 1; } if position >= len || self.chars[position] != ':' { return Err(self.set_error("Expecting reference in range", self.position)); } position += 1; let mut absolute_right = false; if position < len && self.chars[position] == '$' { absolute_right = true; position += 1; } let mut column_right = "".to_string(); let mut row_right = "".to_string(); while position < len { let x = self.chars[position].to_ascii_uppercase(); match x { 'A'..='Z' => column_right.push(x), '0'..='9' => row_right.push(x), _ => break, } position += 1; } self.position = position; // At this point either the columns are the empty string or the rows are the empty string if !row_left.is_empty() { // It is a row range 23:56 if row_right.is_empty() || !column_left.is_empty() || !column_right.is_empty() { return Err(self.set_error("Error parsing Range", position)); } // Note that row numbers can start with 0 let row_left = match row_left.parse::() { Ok(n) => n, Err(_) => { return Err(self .set_error(&format!("Failed parsing row {}", row_left), position)) } }; let row_right = match row_right.parse::() { Ok(n) => n, Err(_) => { return Err(self .set_error(&format!("Failed parsing row {}", row_right), position)) } }; if row_left > LAST_ROW { return Err(self.set_error("Row too large in reference", position)); } if row_right > LAST_ROW { return Err(self.set_error("Row too large in reference", position)); } return Ok(ParsedRange { left: ParsedReference { row: row_left, absolute_row: absolute_left, column: 1, absolute_column: true, }, right: Some(ParsedReference { row: row_right, absolute_row: absolute_right, column: LAST_COLUMN, absolute_column: true, }), }); } // It is a column range if column_right.is_empty() || !row_right.is_empty() { return Err(self.set_error("Error parsing Range", position)); } let column_left = column_to_number(&column_left) .map_err(|error| self.set_error(&error, position))?; let column_right = column_to_number(&column_right) .map_err(|error| self.set_error(&error, position))?; Ok(ParsedRange { left: ParsedReference { row: 1, absolute_row: true, column: column_left, absolute_column: absolute_left, }, right: Some(ParsedReference { row: LAST_ROW, absolute_row: true, column: column_right, absolute_column: absolute_right, }), }) } } } /// Consumes a range of references in R1C1 style like: /// R12C3:R23C4, R[2]C[-2]:R[3]C[6], R3C[6]:R[-3]C4, R[-2]C:R[-2]C pub(super) fn consume_range_r1c1(&mut self) -> Result { // first let's try to parse a cell match self.consume_reference_r1c1() { Ok(cell) => { if self.peek_char() == Some(':') { // It's a range self.position += 1; if let Ok(cell2) = self.consume_reference_r1c1() { Ok(ParsedRange { left: cell, right: Some(cell2), }) } else { Err(self.set_error("Expecting reference in range", self.position)) } } else { // just a reference Ok(ParsedRange { left: cell, right: None, }) } } Err(s) => Err(s), } } /// Consumes a reference in R1C1 style like: /// R12C3, R[2]C[-2], R3C[6], R[-3]C4, RC1, R[-2]C pub(super) fn consume_reference_r1c1(&mut self) -> Result { // R12C3, R[2]C[-2], R3C[6], R[-3]C4, RC1, R[-2]C let absolute_column; let absolute_row; let position = self.position; let row; let column; self.expect_char('R')?; match self.peek_char() { Some('[') => { absolute_row = false; self.expect_char('[')?; let c = match self.read_next_char() { Some(s) => s, None => { return Err(self.set_error("Expected column number", position)); } }; match self.consume_integer(c) { Ok(v) => row = v, Err(_) => { return Err(self.set_error("Expected row number", position)); } } self.expect(TokenType::RightBracket)?; } Some(c) => { absolute_row = true; self.expect_char(c)?; match self.consume_integer(c) { Ok(v) => row = v, Err(_) => { return Err(self.set_error("Expected row number", position)); } } } None => { return Err(self.set_error("Expected row number or '['", position)); } } self.expect_char('C')?; match self.peek_char() { Some('[') => { self.expect_char('[')?; absolute_column = false; let c = match self.read_next_char() { Some(s) => s, None => { return Err(self.set_error("Expected column number", position)); } }; match self.consume_integer(c) { Ok(v) => column = v, Err(_) => { return Err(self.set_error("Expected column number", position)); } } self.expect(TokenType::RightBracket)?; } Some(c) => { absolute_column = true; self.expect_char(c)?; match self.consume_integer(c) { Ok(v) => column = v, Err(_) => { return Err(self.set_error("Expected column number", position)); } } } None => { return Err(self.set_error("Expected column number or '['", position)); } } if let Some(c) = self.peek_char() { if c.is_alphanumeric() { return Err(self.set_error("Expected end of reference", position)); } } Ok(ParsedReference { column, row, absolute_column, absolute_row, }) } }