FIX: Remove optional context in parser

The context was optional because I thought that paring an RC formula
did not need context.

You at least need the sheet in which you are parsing
For instance toknow if a defined name is local
This commit is contained in:
Nicolás Hatcher
2024-12-26 00:02:28 +01:00
committed by Nicolás Hatcher Andrés
parent 86213a8434
commit 690032c811
10 changed files with 246 additions and 283 deletions

View File

@@ -190,7 +190,7 @@ pub struct Parser {
lexer: lexer::Lexer, lexer: lexer::Lexer,
worksheets: Vec<String>, worksheets: Vec<String>,
defined_names: Vec<(String, Option<u32>)>, defined_names: Vec<(String, Option<u32>)>,
context: Option<CellReferenceRC>, context: CellReferenceRC,
tables: HashMap<String, Table>, tables: HashMap<String, Table>,
} }
@@ -208,11 +208,16 @@ impl Parser {
#[allow(clippy::expect_used)] #[allow(clippy::expect_used)]
get_language("en").expect(""), get_language("en").expect(""),
); );
let context = CellReferenceRC {
sheet: worksheets.first().map_or("", |v| v).to_string(),
column: 1,
row: 1,
};
Parser { Parser {
lexer, lexer,
worksheets, worksheets,
defined_names, defined_names,
context: None, context,
tables, tables,
} }
} }
@@ -229,9 +234,9 @@ impl Parser {
self.defined_names = defined_names; self.defined_names = defined_names;
} }
pub fn parse(&mut self, formula: &str, context: &Option<CellReferenceRC>) -> Node { pub fn parse(&mut self, formula: &str, context: &CellReferenceRC) -> Node {
self.lexer.set_formula(formula); self.lexer.set_formula(formula);
self.context.clone_from(context); self.context = context.clone();
self.parse_expr() self.parse_expr()
} }
@@ -477,16 +482,7 @@ impl Parser {
absolute_column, absolute_column,
absolute_row, absolute_row,
} => { } => {
let context = match &self.context { let context = &self.context;
Some(c) => c,
None => {
return Node::ParseErrorKind {
formula: self.lexer.get_formula(),
position: self.lexer.get_position() as usize,
message: "Expected context for the reference".to_string(),
}
}
};
let sheet_index = match &sheet { let sheet_index = match &sheet {
Some(name) => self.get_sheet_index_by_name(name), Some(name) => self.get_sheet_index_by_name(name),
None => self.get_sheet_index_by_name(&context.sheet), None => self.get_sheet_index_by_name(&context.sheet),
@@ -521,16 +517,7 @@ impl Parser {
} }
} }
TokenType::Range { sheet, left, right } => { TokenType::Range { sheet, left, right } => {
let context = match &self.context { let context = &self.context;
Some(c) => c,
None => {
return Node::ParseErrorKind {
formula: self.lexer.get_formula(),
position: self.lexer.get_position() as usize,
message: "Expected context for the reference".to_string(),
}
}
};
let sheet_index = match &sheet { let sheet_index = match &sheet {
Some(name) => self.get_sheet_index_by_name(name), Some(name) => self.get_sheet_index_by_name(name),
None => self.get_sheet_index_by_name(&context.sheet), None => self.get_sheet_index_by_name(&context.sheet),
@@ -619,16 +606,7 @@ impl Parser {
} }
return Node::InvalidFunctionKind { name, args }; return Node::InvalidFunctionKind { name, args };
} }
let context = match &self.context { let context = &self.context;
Some(c) => c,
None => {
return Node::ParseErrorKind {
formula: self.lexer.get_formula(),
position: self.lexer.get_position() as usize,
message: "Expected context for the reference".to_string(),
}
}
};
let context_sheet_index = match self.get_sheet_index_by_name(&context.sheet) { let context_sheet_index = match self.get_sheet_index_by_name(&context.sheet) {
Some(i) => i, Some(i) => i,
@@ -723,187 +701,177 @@ impl Parser {
// We will try to convert to a normal reference // We will try to convert to a normal reference
// table_name[column_name] => cell1:cell2 // table_name[column_name] => cell1:cell2
// table_name[[#This Row], [column_name]:[column_name]] => cell1:cell2 // table_name[[#This Row], [column_name]:[column_name]] => cell1:cell2
if let Some(context) = &self.context { let context = &self.context;
let context_sheet_index = match self.get_sheet_index_by_name(&context.sheet) { let context_sheet_index = match self.get_sheet_index_by_name(&context.sheet) {
Some(i) => i, Some(i) => i,
None => { None => {
return Node::ParseErrorKind { return Node::ParseErrorKind {
formula: self.lexer.get_formula(), formula: self.lexer.get_formula(),
position: 0, position: 0,
message: "sheet not found".to_string(), message: "sheet not found".to_string(),
}; };
} }
}; };
// table-name => table // table-name => table
let table = match self.tables.get(&table_name) { let table = match self.tables.get(&table_name) {
Some(t) => t, Some(t) => t,
None => { None => {
let message = format!( let message = format!(
"Table not found: '{table_name}' at '{}!{}{}'", "Table not found: '{table_name}' at '{}!{}{}'",
context.sheet, context.sheet,
number_to_column(context.column) number_to_column(context.column)
.unwrap_or(format!("{}", context.column)), .unwrap_or(format!("{}", context.column)),
context.row context.row
); );
return Node::ParseErrorKind { return Node::ParseErrorKind {
formula: self.lexer.get_formula(), formula: self.lexer.get_formula(),
position: 0, position: 0,
message, message,
}; };
} }
}; };
let table_sheet_index = match self.get_sheet_index_by_name(&table.sheet_name) { let table_sheet_index = match self.get_sheet_index_by_name(&table.sheet_name) {
Some(i) => i, Some(i) => i,
None => { None => {
return Node::ParseErrorKind { return Node::ParseErrorKind {
formula: self.lexer.get_formula(), formula: self.lexer.get_formula(),
position: 0, position: 0,
message: "sheet not found".to_string(), message: "sheet not found".to_string(),
}; };
} }
}; };
let sheet_name = if table_sheet_index == context_sheet_index { let sheet_name = if table_sheet_index == context_sheet_index {
None None
} else { } else {
Some(table.sheet_name.clone()) Some(table.sheet_name.clone())
}; };
// context must be with tables.reference // context must be with tables.reference
#[allow(clippy::expect_used)] #[allow(clippy::expect_used)]
let (column_start, mut row_start, column_end, mut row_end) = let (column_start, mut row_start, column_end, mut row_end) =
parse_range(&table.reference).expect("Failed parsing range"); parse_range(&table.reference).expect("Failed parsing range");
let totals_row_count = table.totals_row_count as i32; let totals_row_count = table.totals_row_count as i32;
let header_row_count = table.header_row_count as i32; let header_row_count = table.header_row_count as i32;
row_end -= totals_row_count; row_end -= totals_row_count;
match specifier { match specifier {
Some(token::TableSpecifier::ThisRow) => { Some(token::TableSpecifier::ThisRow) => {
row_start = context.row; row_start = context.row;
row_end = context.row; row_end = context.row;
} }
Some(token::TableSpecifier::Totals) => { Some(token::TableSpecifier::Totals) => {
if totals_row_count != 0 { if totals_row_count != 0 {
row_start = row_end + 1; row_start = row_end + 1;
row_end = row_start;
} else {
// Table1[#Totals] is #REF! if Table1 does not have totals
return Node::ErrorKind(token::Error::REF);
}
}
Some(token::TableSpecifier::Headers) => {
row_end = row_start; row_end = row_start;
} } else {
Some(token::TableSpecifier::Data) => { // Table1[#Totals] is #REF! if Table1 does not have totals
row_start += header_row_count; return Node::ErrorKind(token::Error::REF);
}
Some(token::TableSpecifier::All) => {
if totals_row_count != 0 {
row_end += 1;
}
}
None => {
// skip the headers
row_start += header_row_count;
} }
} }
match table_reference { Some(token::TableSpecifier::Headers) => {
None => { row_end = row_start;
return Node::RangeKind { }
sheet_name, Some(token::TableSpecifier::Data) => {
sheet_index: table_sheet_index, row_start += header_row_count;
absolute_row1: true, }
absolute_column1: true, Some(token::TableSpecifier::All) => {
row1: row_start, if totals_row_count != 0 {
column1: column_start, row_end += 1;
absolute_row2: true,
absolute_column2: true,
row2: row_end,
column2: column_end,
};
}
Some(TableReference::ColumnReference(s)) => {
let column_index = match get_table_column_by_name(&s, table) {
Some(s) => s + column_start,
None => {
return Node::ParseErrorKind {
formula: self.lexer.get_formula(),
position: self.lexer.get_position() as usize,
message: format!(
"Expecting column: {s} in table {table_name}"
),
};
}
};
if row_start == row_end {
return Node::ReferenceKind {
sheet_name,
sheet_index: table_sheet_index,
absolute_row: true,
absolute_column: true,
row: row_start,
column: column_index,
};
}
return Node::RangeKind {
sheet_name,
sheet_index: table_sheet_index,
absolute_row1: true,
absolute_column1: true,
row1: row_start,
column1: column_index,
absolute_row2: true,
absolute_column2: true,
row2: row_end,
column2: column_index,
};
}
Some(TableReference::RangeReference((left, right))) => {
let left_column_index = match get_table_column_by_name(&left, table) {
Some(f) => f + column_start,
None => {
return Node::ParseErrorKind {
formula: self.lexer.get_formula(),
position: self.lexer.get_position() as usize,
message: format!(
"Expecting column: {left} in table {table_name}"
),
};
}
};
let right_column_index = match get_table_column_by_name(&right, table) {
Some(f) => f + column_start,
None => {
return Node::ParseErrorKind {
formula: self.lexer.get_formula(),
position: self.lexer.get_position() as usize,
message: format!(
"Expecting column: {right} in table {table_name}"
),
};
}
};
return Node::RangeKind {
sheet_name,
sheet_index: table_sheet_index,
absolute_row1: true,
absolute_column1: true,
row1: row_start,
column1: left_column_index,
absolute_row2: true,
absolute_column2: true,
row2: row_end,
column2: right_column_index,
};
} }
} }
None => {
// skip the headers
row_start += header_row_count;
}
} }
Node::ParseErrorKind { match table_reference {
formula: self.lexer.get_formula(), None => Node::RangeKind {
position: 0, sheet_name,
message: "Structured references not supported in R1C1 mode".to_string(), sheet_index: table_sheet_index,
absolute_row1: true,
absolute_column1: true,
row1: row_start,
column1: column_start,
absolute_row2: true,
absolute_column2: true,
row2: row_end,
column2: column_end,
},
Some(TableReference::ColumnReference(s)) => {
let column_index = match get_table_column_by_name(&s, table) {
Some(s) => s + column_start,
None => {
return Node::ParseErrorKind {
formula: self.lexer.get_formula(),
position: self.lexer.get_position() as usize,
message: format!("Expecting column: {s} in table {table_name}"),
};
}
};
if row_start == row_end {
return Node::ReferenceKind {
sheet_name,
sheet_index: table_sheet_index,
absolute_row: true,
absolute_column: true,
row: row_start,
column: column_index,
};
}
Node::RangeKind {
sheet_name,
sheet_index: table_sheet_index,
absolute_row1: true,
absolute_column1: true,
row1: row_start,
column1: column_index,
absolute_row2: true,
absolute_column2: true,
row2: row_end,
column2: column_index,
}
}
Some(TableReference::RangeReference((left, right))) => {
let left_column_index = match get_table_column_by_name(&left, table) {
Some(f) => f + column_start,
None => {
return Node::ParseErrorKind {
formula: self.lexer.get_formula(),
position: self.lexer.get_position() as usize,
message: format!(
"Expecting column: {left} in table {table_name}"
),
};
}
};
let right_column_index = match get_table_column_by_name(&right, table) {
Some(f) => f + column_start,
None => {
return Node::ParseErrorKind {
formula: self.lexer.get_formula(),
position: self.lexer.get_position() as usize,
message: format!(
"Expecting column: {right} in table {table_name}"
),
};
}
};
Node::RangeKind {
sheet_name,
sheet_index: table_sheet_index,
absolute_row1: true,
absolute_column1: true,
row1: row_start,
column1: left_column_index,
absolute_row2: true,
absolute_column2: true,
row2: row_end,
column2: right_column_index,
}
}
} }
} }
} }

View File

@@ -25,7 +25,7 @@ fn test_parser_reference() {
row: 1, row: 1,
column: 1, column: 1,
}; };
let t = parser.parse("A2", &Some(cell_reference)); let t = parser.parse("A2", &cell_reference);
assert_eq!(to_rc_format(&t), "R[1]C[0]"); assert_eq!(to_rc_format(&t), "R[1]C[0]");
} }
@@ -40,7 +40,7 @@ fn test_parser_absolute_column() {
row: 1, row: 1,
column: 1, column: 1,
}; };
let t = parser.parse("$A1", &Some(cell_reference)); let t = parser.parse("$A1", &cell_reference);
assert_eq!(to_rc_format(&t), "R[0]C1"); assert_eq!(to_rc_format(&t), "R[0]C1");
} }
@@ -55,7 +55,7 @@ fn test_parser_absolute_row_col() {
row: 1, row: 1,
column: 1, column: 1,
}; };
let t = parser.parse("$C$5", &Some(cell_reference)); let t = parser.parse("$C$5", &cell_reference);
assert_eq!(to_rc_format(&t), "R5C3"); assert_eq!(to_rc_format(&t), "R5C3");
} }
@@ -70,7 +70,7 @@ fn test_parser_absolute_row_col_1() {
row: 1, row: 1,
column: 1, column: 1,
}; };
let t = parser.parse("$A$1", &Some(cell_reference)); let t = parser.parse("$A$1", &cell_reference);
assert_eq!(to_rc_format(&t), "R1C1"); assert_eq!(to_rc_format(&t), "R1C1");
} }
@@ -86,7 +86,7 @@ fn test_parser_simple_formula() {
column: 1, column: 1,
}; };
let t = parser.parse("C3+Sheet2!D4", &Some(cell_reference)); let t = parser.parse("C3+Sheet2!D4", &cell_reference);
assert_eq!(to_rc_format(&t), "R[2]C[2]+Sheet2!R[3]C[3]"); assert_eq!(to_rc_format(&t), "R[2]C[2]+Sheet2!R[3]C[3]");
} }
@@ -102,7 +102,7 @@ fn test_parser_boolean() {
column: 1, column: 1,
}; };
let t = parser.parse("true", &Some(cell_reference)); let t = parser.parse("true", &cell_reference);
assert_eq!(to_rc_format(&t), "TRUE"); assert_eq!(to_rc_format(&t), "TRUE");
} }
@@ -117,7 +117,7 @@ fn test_parser_bad_formula() {
row: 1, row: 1,
column: 1, column: 1,
}; };
let t = parser.parse("#Value", &Some(cell_reference)); let t = parser.parse("#Value", &cell_reference);
match &t { match &t {
Node::ParseErrorKind { Node::ParseErrorKind {
formula, formula,
@@ -146,7 +146,7 @@ fn test_parser_bad_formula_1() {
row: 1, row: 1,
column: 1, column: 1,
}; };
let t = parser.parse("<5", &Some(cell_reference)); let t = parser.parse("<5", &cell_reference);
match &t { match &t {
Node::ParseErrorKind { Node::ParseErrorKind {
formula, formula,
@@ -175,7 +175,7 @@ fn test_parser_bad_formula_2() {
row: 1, row: 1,
column: 1, column: 1,
}; };
let t = parser.parse("*5", &Some(cell_reference)); let t = parser.parse("*5", &cell_reference);
match &t { match &t {
Node::ParseErrorKind { Node::ParseErrorKind {
formula, formula,
@@ -204,7 +204,7 @@ fn test_parser_bad_formula_3() {
row: 1, row: 1,
column: 1, column: 1,
}; };
let t = parser.parse("SUM(#VALVE!)", &Some(cell_reference)); let t = parser.parse("SUM(#VALVE!)", &cell_reference);
match &t { match &t {
Node::ParseErrorKind { Node::ParseErrorKind {
formula, formula,
@@ -259,11 +259,11 @@ fn test_parser_formulas() {
for formula in formulas { for formula in formulas {
let t = parser.parse( let t = parser.parse(
formula.initial, formula.initial,
&Some(CellReferenceRC { &CellReferenceRC {
sheet: "Sheet1".to_string(), sheet: "Sheet1".to_string(),
row: 1, row: 1,
column: 1, column: 1,
}), },
); );
assert_eq!(to_rc_format(&t), formula.expected); assert_eq!(to_rc_format(&t), formula.expected);
assert_eq!(to_string(&t, &cell_reference), formula.initial); assert_eq!(to_string(&t, &cell_reference), formula.initial);
@@ -324,11 +324,11 @@ fn test_parser_r1c1_formulas() {
for formula in formulas { for formula in formulas {
let t = parser.parse( let t = parser.parse(
formula.initial, formula.initial,
&Some(CellReferenceRC { &CellReferenceRC {
sheet: "Sheet1".to_string(), sheet: "Sheet1".to_string(),
row: 1, row: 1,
column: 1, column: 1,
}), },
); );
assert_eq!(to_string(&t, &cell_reference), formula.expected); assert_eq!(to_string(&t, &cell_reference), formula.expected);
assert_eq!(to_rc_format(&t), formula.initial); assert_eq!(to_rc_format(&t), formula.initial);
@@ -347,7 +347,7 @@ fn test_parser_quotes() {
column: 1, column: 1,
}; };
let t = parser.parse("C3+'Second Sheet'!D4", &Some(cell_reference)); let t = parser.parse("C3+'Second Sheet'!D4", &cell_reference);
assert_eq!(to_rc_format(&t), "R[2]C[2]+'Second Sheet'!R[3]C[3]"); assert_eq!(to_rc_format(&t), "R[2]C[2]+'Second Sheet'!R[3]C[3]");
} }
@@ -363,7 +363,7 @@ fn test_parser_escape_quotes() {
column: 1, column: 1,
}; };
let t = parser.parse("C3+'Second ''2'' Sheet'!D4", &Some(cell_reference)); let t = parser.parse("C3+'Second ''2'' Sheet'!D4", &cell_reference);
assert_eq!(to_rc_format(&t), "R[2]C[2]+'Second ''2'' Sheet'!R[3]C[3]"); assert_eq!(to_rc_format(&t), "R[2]C[2]+'Second ''2'' Sheet'!R[3]C[3]");
} }
@@ -379,7 +379,7 @@ fn test_parser_parenthesis() {
column: 1, column: 1,
}; };
let t = parser.parse("(C3=\"Yes\")*5", &Some(cell_reference)); let t = parser.parse("(C3=\"Yes\")*5", &cell_reference);
assert_eq!(to_rc_format(&t), "(R[2]C[2]=\"Yes\")*5"); assert_eq!(to_rc_format(&t), "(R[2]C[2]=\"Yes\")*5");
} }
@@ -395,7 +395,7 @@ fn test_parser_excel_xlfn() {
column: 1, column: 1,
}; };
let t = parser.parse("_xlfn.CONCAT(C3)", &Some(cell_reference)); let t = parser.parse("_xlfn.CONCAT(C3)", &cell_reference);
assert_eq!(to_rc_format(&t), "CONCAT(R[2]C[2])"); assert_eq!(to_rc_format(&t), "CONCAT(R[2]C[2])");
} }
@@ -409,7 +409,7 @@ fn test_to_string_displaced() {
let worksheets = vec!["Sheet1".to_string()]; let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, vec![], HashMap::new()); let mut parser = Parser::new(worksheets, vec![], HashMap::new());
let node = parser.parse("C3", &Some(context.clone())); let node = parser.parse("C3", context);
let displace_data = DisplaceData::Column { let displace_data = DisplaceData::Column {
sheet: 0, sheet: 0,
column: 1, column: 1,
@@ -429,7 +429,7 @@ fn test_to_string_displaced_full_ranges() {
let worksheets = vec!["Sheet1".to_string()]; let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, vec![], HashMap::new()); let mut parser = Parser::new(worksheets, vec![], HashMap::new());
let node = parser.parse("SUM(3:3)", &Some(context.clone())); let node = parser.parse("SUM(3:3)", context);
let displace_data = DisplaceData::Column { let displace_data = DisplaceData::Column {
sheet: 0, sheet: 0,
column: 1, column: 1,
@@ -440,7 +440,7 @@ fn test_to_string_displaced_full_ranges() {
"SUM(3:3)".to_string() "SUM(3:3)".to_string()
); );
let node = parser.parse("SUM(D:D)", &Some(context.clone())); let node = parser.parse("SUM(D:D)", context);
let displace_data = DisplaceData::Row { let displace_data = DisplaceData::Row {
sheet: 0, sheet: 0,
row: 3, row: 3,
@@ -462,7 +462,7 @@ fn test_to_string_displaced_too_low() {
let worksheets = vec!["Sheet1".to_string()]; let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, vec![], HashMap::new()); let mut parser = Parser::new(worksheets, vec![], HashMap::new());
let node = parser.parse("C3", &Some(context.clone())); let node = parser.parse("C3", context);
let displace_data = DisplaceData::Column { let displace_data = DisplaceData::Column {
sheet: 0, sheet: 0,
column: 1, column: 1,
@@ -482,7 +482,7 @@ fn test_to_string_displaced_too_high() {
let worksheets = vec!["Sheet1".to_string()]; let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, vec![], HashMap::new()); let mut parser = Parser::new(worksheets, vec![], HashMap::new());
let node = parser.parse("C3", &Some(context.clone())); let node = parser.parse("C3", context);
let displace_data = DisplaceData::Column { let displace_data = DisplaceData::Column {
sheet: 0, sheet: 0,
column: 1, column: 1,

View File

@@ -17,7 +17,7 @@ fn issue_155_parser() {
row: 2, row: 2,
column: 2, column: 2,
}; };
let t = parser.parse("A$1:A2", &Some(cell_reference.clone())); let t = parser.parse("A$1:A2", &cell_reference);
assert_eq!(to_string(&t, &cell_reference), "A$1:A2"); assert_eq!(to_string(&t, &cell_reference), "A$1:A2");
} }
@@ -32,7 +32,7 @@ fn issue_155_parser_case_2() {
row: 20, row: 20,
column: 20, column: 20,
}; };
let t = parser.parse("C$1:D2", &Some(cell_reference.clone())); let t = parser.parse("C$1:D2", &cell_reference);
assert_eq!(to_string(&t, &cell_reference), "C$1:D2"); assert_eq!(to_string(&t, &cell_reference), "C$1:D2");
} }
@@ -48,7 +48,7 @@ fn issue_155_parser_only_row() {
column: 20, column: 20,
}; };
// This is tricky, I am not sure what to do in these cases // This is tricky, I am not sure what to do in these cases
let t = parser.parse("A$2:B1", &Some(cell_reference.clone())); let t = parser.parse("A$2:B1", &cell_reference);
assert_eq!(to_string(&t, &cell_reference), "A1:B$2"); assert_eq!(to_string(&t, &cell_reference), "A1:B$2");
} }
@@ -64,6 +64,6 @@ fn issue_155_parser_only_column() {
column: 20, column: 20,
}; };
// This is tricky, I am not sure what to do in these cases // This is tricky, I am not sure what to do in these cases
let t = parser.parse("D1:$A3", &Some(cell_reference.clone())); let t = parser.parse("D1:$A3", &cell_reference);
assert_eq!(to_string(&t, &cell_reference), "$A1:D3"); assert_eq!(to_string(&t, &cell_reference), "$A1:D3");
} }

View File

@@ -27,7 +27,7 @@ fn test_move_formula() {
}; };
// formula AB31 will not change // formula AB31 will not change
let node = parser.parse("AB31", &Some(context.clone())); let node = parser.parse("AB31", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -43,7 +43,7 @@ fn test_move_formula() {
assert_eq!(t, "AB31"); assert_eq!(t, "AB31");
// formula $AB$31 will not change // formula $AB$31 will not change
let node = parser.parse("AB31", &Some(context.clone())); let node = parser.parse("AB31", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -59,7 +59,7 @@ fn test_move_formula() {
assert_eq!(t, "AB31"); assert_eq!(t, "AB31");
// but formula D5 will change to N15 (N = D + 10) // but formula D5 will change to N15 (N = D + 10)
let node = parser.parse("D5", &Some(context.clone())); let node = parser.parse("D5", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -75,7 +75,7 @@ fn test_move_formula() {
assert_eq!(t, "N15"); assert_eq!(t, "N15");
// Also formula $D$5 will change to N15 (N = D + 10) // Also formula $D$5 will change to N15 (N = D + 10)
let node = parser.parse("$D$5", &Some(context.clone())); let node = parser.parse("$D$5", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -113,7 +113,7 @@ fn test_move_formula_context_offset() {
height: 5, height: 5,
}; };
let node = parser.parse("-X9+C2%", &Some(context.clone())); let node = parser.parse("-X9+C2%", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -152,7 +152,7 @@ fn test_move_formula_area_limits() {
}; };
// Outside of the area. Not moved // Outside of the area. Not moved
let node = parser.parse("B2+B3+C1+G6+H5", &Some(context.clone())); let node = parser.parse("B2+B3+C1+G6+H5", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -168,7 +168,7 @@ fn test_move_formula_area_limits() {
assert_eq!(t, "B2+B3+C1+G6+H5"); assert_eq!(t, "B2+B3+C1+G6+H5");
// In the area. Moved // In the area. Moved
let node = parser.parse("C2+F4+F5+F6", &Some(context.clone())); let node = parser.parse("C2+F4+F5+F6", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -205,7 +205,7 @@ fn test_move_formula_ranges() {
height: 5, height: 5,
}; };
// Ranges inside the area are fully displaced (absolute or not) // Ranges inside the area are fully displaced (absolute or not)
let node = parser.parse("SUM(C2:F5)", &Some(context.clone())); let node = parser.parse("SUM(C2:F5)", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -220,7 +220,7 @@ fn test_move_formula_ranges() {
); );
assert_eq!(t, "SUM(M12:P15)"); assert_eq!(t, "SUM(M12:P15)");
let node = parser.parse("SUM($C$2:$F$5)", &Some(context.clone())); let node = parser.parse("SUM($C$2:$F$5)", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -236,7 +236,7 @@ fn test_move_formula_ranges() {
assert_eq!(t, "SUM($M$12:$P$15)"); assert_eq!(t, "SUM($M$12:$P$15)");
// Ranges completely outside of the area are not touched // Ranges completely outside of the area are not touched
let node = parser.parse("SUM(A1:B3)", &Some(context.clone())); let node = parser.parse("SUM(A1:B3)", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -251,7 +251,7 @@ fn test_move_formula_ranges() {
); );
assert_eq!(t, "SUM(A1:B3)"); assert_eq!(t, "SUM(A1:B3)");
let node = parser.parse("SUM($A$1:$B$3)", &Some(context.clone())); let node = parser.parse("SUM($A$1:$B$3)", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -267,7 +267,7 @@ fn test_move_formula_ranges() {
assert_eq!(t, "SUM($A$1:$B$3)"); assert_eq!(t, "SUM($A$1:$B$3)");
// Ranges that overlap with the area are also NOT displaced // Ranges that overlap with the area are also NOT displaced
let node = parser.parse("SUM(A1:F5)", &Some(context.clone())); let node = parser.parse("SUM(A1:F5)", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -283,7 +283,7 @@ fn test_move_formula_ranges() {
assert_eq!(t, "SUM(A1:F5)"); assert_eq!(t, "SUM(A1:F5)");
// Ranges that contain the area are also NOT displaced // Ranges that contain the area are also NOT displaced
let node = parser.parse("SUM(A1:X50)", &Some(context.clone())); let node = parser.parse("SUM(A1:X50)", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -321,7 +321,7 @@ fn test_move_formula_wrong_reference() {
let mut parser = Parser::new(worksheets, vec![], HashMap::new()); let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Wrong formulas will NOT be displaced // Wrong formulas will NOT be displaced
let node = parser.parse("Sheet3!AB31", &Some(context.clone())); let node = parser.parse("Sheet3!AB31", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -335,7 +335,7 @@ fn test_move_formula_wrong_reference() {
}, },
); );
assert_eq!(t, "Sheet3!AB31"); assert_eq!(t, "Sheet3!AB31");
let node = parser.parse("Sheet3!$X$9", &Some(context.clone())); let node = parser.parse("Sheet3!$X$9", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -350,7 +350,7 @@ fn test_move_formula_wrong_reference() {
); );
assert_eq!(t, "Sheet3!$X$9"); assert_eq!(t, "Sheet3!$X$9");
let node = parser.parse("SUM(Sheet3!D2:D3)", &Some(context.clone())); let node = parser.parse("SUM(Sheet3!D2:D3)", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -387,7 +387,7 @@ fn test_move_formula_misc() {
width: 4, width: 4,
height: 5, height: 5,
}; };
let node = parser.parse("X9^C2-F4*H2", &Some(context.clone())); let node = parser.parse("X9^C2-F4*H2", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -402,7 +402,7 @@ fn test_move_formula_misc() {
); );
assert_eq!(t, "X9^M12-P14*H2"); assert_eq!(t, "X9^M12-P14*H2");
let node = parser.parse("F5*(-D5)*SUM(A1, X9, $D$5)", &Some(context.clone())); let node = parser.parse("F5*(-D5)*SUM(A1, X9, $D$5)", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -417,7 +417,7 @@ fn test_move_formula_misc() {
); );
assert_eq!(t, "P15*(-N15)*SUM(A1,X9,$N$15)"); assert_eq!(t, "P15*(-N15)*SUM(A1,X9,$N$15)");
let node = parser.parse("IF(F5 < -D5, X9 & F5, FALSE)", &Some(context.clone())); let node = parser.parse("IF(F5 < -D5, X9 & F5, FALSE)", context);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {
@@ -457,10 +457,7 @@ fn test_move_formula_another_sheet() {
}; };
// Formula AB31 and JJ3:JJ4 refers to original Sheet1!AB31 and Sheet1!JJ3:JJ4 // Formula AB31 and JJ3:JJ4 refers to original Sheet1!AB31 and Sheet1!JJ3:JJ4
let node = parser.parse( let node = parser.parse("AB31*SUM(JJ3:JJ4)+SUM(Sheet2!C2:F6)*SUM(C2:F6)", context);
"AB31*SUM(JJ3:JJ4)+SUM(Sheet2!C2:F6)*SUM(C2:F6)",
&Some(context.clone()),
);
let t = move_formula( let t = move_formula(
&node, &node,
&MoveContext { &MoveContext {

View File

@@ -52,11 +52,11 @@ fn test_parser_formulas_with_full_ranges() {
for formula in &formulas { for formula in &formulas {
let t = parser.parse( let t = parser.parse(
formula.formula_a1, formula.formula_a1,
&Some(CellReferenceRC { &CellReferenceRC {
sheet: "Sheet1".to_string(), sheet: "Sheet1".to_string(),
row: 1, row: 1,
column: 1, column: 1,
}), },
); );
assert_eq!(to_rc_format(&t), formula.formula_r1c1); assert_eq!(to_rc_format(&t), formula.formula_r1c1);
assert_eq!(to_string(&t, &cell_reference), formula.formula_a1); assert_eq!(to_string(&t, &cell_reference), formula.formula_a1);
@@ -67,11 +67,11 @@ fn test_parser_formulas_with_full_ranges() {
for formula in &formulas { for formula in &formulas {
let t = parser.parse( let t = parser.parse(
formula.formula_r1c1, formula.formula_r1c1,
&Some(CellReferenceRC { &CellReferenceRC {
sheet: "Sheet1".to_string(), sheet: "Sheet1".to_string(),
row: 1, row: 1,
column: 1, column: 1,
}), },
); );
assert_eq!(to_rc_format(&t), formula.formula_r1c1); assert_eq!(to_rc_format(&t), formula.formula_r1c1);
assert_eq!(to_string(&t, &cell_reference), formula.formula_a1); assert_eq!(to_string(&t, &cell_reference), formula.formula_a1);
@@ -93,7 +93,7 @@ fn test_range_inverse_order() {
// D4:C2 => C2:D4 // D4:C2 => C2:D4
let t = parser.parse( let t = parser.parse(
"SUM(D4:C2)*SUM(Sheet2!D4:C20)*SUM($C$20:D4)", "SUM(D4:C2)*SUM(Sheet2!D4:C20)*SUM($C$20:D4)",
&Some(cell_reference.clone()), &cell_reference,
); );
assert_eq!( assert_eq!(
to_string(&t, &cell_reference), to_string(&t, &cell_reference),

View File

@@ -17,18 +17,18 @@ fn exp_order() {
row: 1, row: 1,
column: 1, column: 1,
}; };
let t = parser.parse("(1 + 2)^3 + 4", &Some(cell_reference.clone())); let t = parser.parse("(1 + 2)^3 + 4", &cell_reference);
assert_eq!(to_string(&t, &cell_reference), "(1+2)^3+4"); assert_eq!(to_string(&t, &cell_reference), "(1+2)^3+4");
let t = parser.parse("(C5 + 3)^R4", &Some(cell_reference.clone())); let t = parser.parse("(C5 + 3)^R4", &cell_reference);
assert_eq!(to_string(&t, &cell_reference), "(C5+3)^R4"); assert_eq!(to_string(&t, &cell_reference), "(C5+3)^R4");
let t = parser.parse("(C5 + 3)^(R4*6)", &Some(cell_reference.clone())); let t = parser.parse("(C5 + 3)^(R4*6)", &cell_reference);
assert_eq!(to_string(&t, &cell_reference), "(C5+3)^(R4*6)"); assert_eq!(to_string(&t, &cell_reference), "(C5+3)^(R4*6)");
let t = parser.parse("(C5)^(R4)", &Some(cell_reference.clone())); let t = parser.parse("(C5)^(R4)", &cell_reference);
assert_eq!(to_string(&t, &cell_reference), "C5^R4"); assert_eq!(to_string(&t, &cell_reference), "C5^R4");
let t = parser.parse("(5)^(4)", &Some(cell_reference.clone())); let t = parser.parse("(5)^(4)", &cell_reference);
assert_eq!(to_string(&t, &cell_reference), "5^4"); assert_eq!(to_string(&t, &cell_reference), "5^4");
} }

View File

@@ -72,7 +72,7 @@ fn simple_table() {
}; };
let formula = "SUM(tblIncome[[#This Row],[Jan]:[Dec]])"; let formula = "SUM(tblIncome[[#This Row],[Jan]:[Dec]])";
let t = parser.parse(formula, &Some(cell_reference.clone())); let t = parser.parse(formula, &cell_reference);
assert_eq!(to_string(&t, &cell_reference), "SUM($A$2:$E$2)"); assert_eq!(to_string(&t, &cell_reference), "SUM($A$2:$E$2)");
// Cell A3 // Cell A3
@@ -82,7 +82,7 @@ fn simple_table() {
column: 1, column: 1,
}; };
let formula = "SUBTOTAL(109, tblIncome[Jan])"; let formula = "SUBTOTAL(109, tblIncome[Jan])";
let t = parser.parse(formula, &Some(cell_reference.clone())); let t = parser.parse(formula, &cell_reference);
assert_eq!(to_string(&t, &cell_reference), "SUBTOTAL(109,$A$2:$A$3)"); assert_eq!(to_string(&t, &cell_reference), "SUBTOTAL(109,$A$2:$A$3)");
// Cell A3 in 'Second Sheet' // Cell A3 in 'Second Sheet'
@@ -92,7 +92,7 @@ fn simple_table() {
column: 1, column: 1,
}; };
let formula = "SUBTOTAL(109, tblIncome[Jan])"; let formula = "SUBTOTAL(109, tblIncome[Jan])";
let t = parser.parse(formula, &Some(cell_reference.clone())); let t = parser.parse(formula, &cell_reference);
assert_eq!( assert_eq!(
to_string(&t, &cell_reference), to_string(&t, &cell_reference),
"SUBTOTAL(109,'Sheet One'!$A$2:$A$3)" "SUBTOTAL(109,'Sheet One'!$A$2:$A$3)"

View File

@@ -1040,7 +1040,7 @@ impl Model {
column: source.column, column: source.column,
}; };
let formula_str = move_formula( let formula_str = move_formula(
&self.parser.parse(formula, &Some(cell_reference)), &self.parser.parse(formula, &cell_reference),
&MoveContext { &MoveContext {
source_sheet_name: &source_sheet_name, source_sheet_name: &source_sheet_name,
row: source.row, row: source.row,
@@ -1148,7 +1148,7 @@ impl Model {
row: source.row, row: source.row,
column: source.column, column: source.column,
}; };
let formula = &self.parser.parse(formula_str, &Some(cell_reference)); let formula = &self.parser.parse(formula_str, &cell_reference);
let cell_reference = CellReferenceRC { let cell_reference = CellReferenceRC {
sheet: target_sheet_name, sheet: target_sheet_name,
row: target.row, row: target.row,
@@ -1524,13 +1524,11 @@ impl Model {
column, column,
}; };
let shared_formulas = &mut worksheet.shared_formulas; let shared_formulas = &mut worksheet.shared_formulas;
let mut parsed_formula = self.parser.parse(formula, &Some(cell_reference.clone())); let mut parsed_formula = self.parser.parse(formula, &cell_reference);
// If the formula fails to parse try adding a parenthesis // If the formula fails to parse try adding a parenthesis
// SUM(A1:A3 => SUM(A1:A3) // SUM(A1:A3 => SUM(A1:A3)
if let Node::ParseErrorKind { .. } = parsed_formula { if let Node::ParseErrorKind { .. } = parsed_formula {
let new_parsed_formula = self let new_parsed_formula = self.parser.parse(&format!("{})", formula), &cell_reference);
.parser
.parse(&format!("{})", formula), &Some(cell_reference));
match new_parsed_formula { match new_parsed_formula {
Node::ParseErrorKind { .. } => {} Node::ParseErrorKind { .. } => {}
_ => parsed_formula = new_parsed_formula, _ => parsed_formula = new_parsed_formula,
@@ -2140,14 +2138,14 @@ impl Model {
self.parser.set_lexer_mode(LexerMode::R1C1); self.parser.set_lexer_mode(LexerMode::R1C1);
let worksheets = &mut self.workbook.worksheets; let worksheets = &mut self.workbook.worksheets;
for worksheet in worksheets { for worksheet in worksheets {
let cell_reference = &Some(CellReferenceRC { let cell_reference = CellReferenceRC {
sheet: worksheet.get_name(), sheet: worksheet.get_name(),
row: 1, row: 1,
column: 1, column: 1,
}); };
let mut formulas = Vec::new(); let mut formulas = Vec::new();
for formula in &worksheet.shared_formulas { for formula in &worksheet.shared_formulas {
let mut t = self.parser.parse(formula, cell_reference); let mut t = self.parser.parse(formula, &cell_reference);
rename_defined_name_in_node(&mut t, name, scope, new_name); rename_defined_name_in_node(&mut t, name, scope, new_name);
formulas.push(to_rc_format(&t)); formulas.push(to_rc_format(&t));
} }

View File

@@ -85,14 +85,14 @@ impl Model {
let worksheets = &self.workbook.worksheets; let worksheets = &self.workbook.worksheets;
for worksheet in worksheets { for worksheet in worksheets {
let shared_formulas = &worksheet.shared_formulas; let shared_formulas = &worksheet.shared_formulas;
let cell_reference = &Some(CellReferenceRC { let cell_reference = CellReferenceRC {
sheet: worksheet.get_name(), sheet: worksheet.get_name(),
row: 1, row: 1,
column: 1, column: 1,
}); };
let mut parse_formula = Vec::new(); let mut parse_formula = Vec::new();
for formula in shared_formulas { for formula in shared_formulas {
let t = self.parser.parse(formula, cell_reference); let t = self.parser.parse(formula, &cell_reference);
parse_formula.push(t); parse_formula.push(t);
} }
self.parsed_formulas.push(parse_formula); self.parsed_formulas.push(parse_formula);
@@ -268,11 +268,11 @@ impl Model {
// We use iter because the default would be a mut_iter and we don't need a mutable reference // We use iter because the default would be a mut_iter and we don't need a mutable reference
let worksheets = &mut self.workbook.worksheets; let worksheets = &mut self.workbook.worksheets;
for worksheet in worksheets { for worksheet in worksheets {
let cell_reference = &Some(CellReferenceRC { let cell_reference = &CellReferenceRC {
sheet: worksheet.get_name(), sheet: worksheet.get_name(),
row: 1, row: 1,
column: 1, column: 1,
}); };
let mut formulas = Vec::new(); let mut formulas = Vec::new();
for formula in &worksheet.shared_formulas { for formula in &worksheet.shared_formulas {
let mut t = self.parser.parse(formula, cell_reference); let mut t = self.parser.parse(formula, cell_reference);

View File

@@ -309,7 +309,7 @@ fn from_a1_to_rc(
let mut parser = Parser::new(worksheets.to_owned(), defined_names, tables); let mut parser = Parser::new(worksheets.to_owned(), defined_names, tables);
let cell_reference = let cell_reference =
parse_reference(&context).map_err(|error| XlsxError::Xml(error.to_string()))?; parse_reference(&context).map_err(|error| XlsxError::Xml(error.to_string()))?;
let t = parser.parse(&formula, &Some(cell_reference)); let t = parser.parse(&formula, &cell_reference);
Ok(to_rc_format(&t)) Ok(to_rc_format(&t))
} }