UPDATE: API for defined names

This commit is contained in:
Nicolás Hatcher
2024-12-03 21:30:46 +01:00
committed by Nicolás Hatcher Andrés
parent ad2efad3ae
commit e455ed14ea
26 changed files with 897 additions and 112 deletions

View File

@@ -164,7 +164,9 @@ pub enum Node {
args: Vec<Node>,
},
ArrayKind(Vec<Node>),
VariableKind(String),
DefinedNameKind((String, Option<u32>)),
TableNameKind(String),
WrongVariableKind(String),
CompareKind {
kind: OpCompare,
left: Box<Node>,
@@ -187,12 +189,17 @@ pub enum Node {
pub struct Parser {
lexer: lexer::Lexer,
worksheets: Vec<String>,
defined_names: Vec<(String, Option<u32>)>,
context: Option<CellReferenceRC>,
tables: HashMap<String, Table>,
}
impl Parser {
pub fn new(worksheets: Vec<String>, tables: HashMap<String, Table>) -> Parser {
pub fn new(
worksheets: Vec<String>,
defined_names: Vec<(String, Option<u32>)>,
tables: HashMap<String, Table>,
) -> Parser {
let lexer = lexer::Lexer::new(
"",
lexer::LexerMode::A1,
@@ -204,6 +211,7 @@ impl Parser {
Parser {
lexer,
worksheets,
defined_names,
context: None,
tables,
}
@@ -212,8 +220,13 @@ impl Parser {
self.lexer.set_lexer_mode(mode)
}
pub fn set_worksheets(&mut self, worksheets: Vec<String>) {
pub fn set_worksheets_and_names(
&mut self,
worksheets: Vec<String>,
defined_names: Vec<(String, Option<u32>)>,
) {
self.worksheets = worksheets;
self.defined_names = defined_names;
}
pub fn parse(&mut self, formula: &str, context: &Option<CellReferenceRC>) -> Node {
@@ -232,6 +245,24 @@ impl Parser {
None
}
// Returns:
// * None: If there is no defined name by that name
// * Some(Some(index)): If there is a defined name local to that sheet
// * Some(None): If there is a global defined name
fn get_defined_name(&self, name: &str, sheet: u32) -> Option<Option<u32>> {
for (df_name, df_scope) in &self.defined_names {
if name.to_lowercase() == df_name.to_lowercase() && df_scope == &Some(sheet) {
return Some(*df_scope);
}
}
for (df_name, df_scope) in &self.defined_names {
if name.to_lowercase() == df_name.to_lowercase() && df_scope.is_none() {
return Some(None);
}
}
None
}
fn parse_expr(&mut self) -> Node {
let mut t = self.parse_concat();
if let Node::ParseErrorKind { .. } = t {
@@ -585,11 +616,42 @@ impl Parser {
kind: function_kind,
args,
};
} else {
return Node::InvalidFunctionKind { name, args };
}
return Node::InvalidFunctionKind { name, args };
}
let context = match &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) {
Some(i) => i,
None => {
return Node::ParseErrorKind {
formula: self.lexer.get_formula(),
position: 0,
message: "sheet not found".to_string(),
};
}
};
// Could be a defined name or a table
if let Some(scope) = self.get_defined_name(&name, context_sheet_index) {
return Node::DefinedNameKind((name, scope));
}
let name_lower = name.to_lowercase();
for table_name in self.tables.keys() {
if table_name.to_lowercase() == name_lower {
return Node::TableNameKind(name);
}
}
Node::VariableKind(name)
Node::WrongVariableKind(name)
}
TokenType::Error(kind) => Node::ErrorKind(kind),
TokenType::Illegal(error) => Node::ParseErrorKind {

View File

@@ -375,7 +375,9 @@ fn to_string_moved(node: &Node, move_context: &MoveContext) -> String {
}
format!("{{{}}}", arguments)
}
VariableKind(value) => value.to_string(),
DefinedNameKind((name, _)) => name.to_string(),
TableNameKind(name) => name.to_string(),
WrongVariableKind(name) => name.to_string(),
CompareKind { kind, left, right } => format!(
"{}{}{}",
to_string_moved(left, move_context),

View File

@@ -464,7 +464,9 @@ fn stringify(
| ReferenceKind { .. }
| RangeKind { .. }
| WrongReferenceKind { .. }
| VariableKind(_)
| DefinedNameKind(_)
| TableNameKind(_)
| WrongVariableKind(_)
| WrongRangeKind { .. } => {
stringify(left, context, displace_data, use_original_name)
}
@@ -492,7 +494,9 @@ fn stringify(
| ReferenceKind { .. }
| RangeKind { .. }
| WrongReferenceKind { .. }
| VariableKind(_)
| DefinedNameKind(_)
| TableNameKind(_)
| WrongVariableKind(_)
| WrongRangeKind { .. } => {
stringify(right, context, displace_data, use_original_name)
}
@@ -543,7 +547,9 @@ fn stringify(
}
format!("{{{}}}", arguments)
}
VariableKind(value) => value.to_string(),
TableNameKind(value) => value.to_string(),
DefinedNameKind((name, _)) => name.to_string(),
WrongVariableKind(name) => name.to_string(),
UnaryKind { kind, right } => match kind {
OpUnary::Minus => {
format!(
@@ -660,7 +666,90 @@ pub(crate) fn rename_sheet_in_node(node: &mut Node, sheet_index: u32, new_name:
Node::ErrorKind(_) => {}
Node::ParseErrorKind { .. } => {}
Node::ArrayKind(_) => {}
Node::VariableKind(_) => {}
Node::DefinedNameKind(_) => {}
Node::TableNameKind(_) => {}
Node::WrongVariableKind(_) => {}
Node::EmptyArgKind => {}
}
}
pub(crate) fn rename_defined_name_in_node(
node: &mut Node,
name: &str,
scope: Option<u32>,
new_name: &str,
) {
match node {
// Rename
Node::DefinedNameKind((n, s)) => {
if name.to_lowercase() == n.to_lowercase() && *s == scope {
*n = new_name.to_string();
}
}
// Go next level
Node::OpRangeKind { left, right } => {
rename_defined_name_in_node(left, name, scope, new_name);
rename_defined_name_in_node(right, name, scope, new_name);
}
Node::OpConcatenateKind { left, right } => {
rename_defined_name_in_node(left, name, scope, new_name);
rename_defined_name_in_node(right, name, scope, new_name);
}
Node::OpSumKind {
kind: _,
left,
right,
} => {
rename_defined_name_in_node(left, name, scope, new_name);
rename_defined_name_in_node(right, name, scope, new_name);
}
Node::OpProductKind {
kind: _,
left,
right,
} => {
rename_defined_name_in_node(left, name, scope, new_name);
rename_defined_name_in_node(right, name, scope, new_name);
}
Node::OpPowerKind { left, right } => {
rename_defined_name_in_node(left, name, scope, new_name);
rename_defined_name_in_node(right, name, scope, new_name);
}
Node::FunctionKind { kind: _, args } => {
for arg in args {
rename_defined_name_in_node(arg, name, scope, new_name);
}
}
Node::InvalidFunctionKind { name: _, args } => {
for arg in args {
rename_defined_name_in_node(arg, name, scope, new_name);
}
}
Node::CompareKind {
kind: _,
left,
right,
} => {
rename_defined_name_in_node(left, name, scope, new_name);
rename_defined_name_in_node(right, name, scope, new_name);
}
Node::UnaryKind { kind: _, right } => {
rename_defined_name_in_node(right, name, scope, new_name);
}
// Do nothing
Node::BooleanKind(_) => {}
Node::NumberKind(_) => {}
Node::StringKind(_) => {}
Node::ErrorKind(_) => {}
Node::ParseErrorKind { .. } => {}
Node::ArrayKind(_) => {}
Node::EmptyArgKind => {}
Node::ReferenceKind { .. } => {}
Node::RangeKind { .. } => {}
Node::WrongReferenceKind { .. } => {}
Node::WrongRangeKind { .. } => {}
Node::TableNameKind(_) => {}
Node::WrongVariableKind(_) => {}
}
}

View File

@@ -17,7 +17,7 @@ struct Formula<'a> {
#[test]
fn test_parser_reference() {
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -32,7 +32,7 @@ fn test_parser_reference() {
#[test]
fn test_parser_absolute_column() {
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -47,7 +47,7 @@ fn test_parser_absolute_column() {
#[test]
fn test_parser_absolute_row_col() {
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -62,7 +62,7 @@ fn test_parser_absolute_row_col() {
#[test]
fn test_parser_absolute_row_col_1() {
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -77,7 +77,7 @@ fn test_parser_absolute_row_col_1() {
#[test]
fn test_parser_simple_formula() {
let worksheets = vec!["Sheet1".to_string(), "Sheet2".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -93,7 +93,7 @@ fn test_parser_simple_formula() {
#[test]
fn test_parser_boolean() {
let worksheets = vec!["Sheet1".to_string(), "Sheet2".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -109,7 +109,7 @@ fn test_parser_boolean() {
#[test]
fn test_parser_bad_formula() {
let worksheets = vec!["Sheet1".to_string(), "Sheet2".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -138,7 +138,7 @@ fn test_parser_bad_formula() {
#[test]
fn test_parser_bad_formula_1() {
let worksheets = vec!["Sheet1".to_string(), "Sheet2".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -167,7 +167,7 @@ fn test_parser_bad_formula_1() {
#[test]
fn test_parser_bad_formula_2() {
let worksheets = vec!["Sheet1".to_string(), "Sheet2".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -196,7 +196,7 @@ fn test_parser_bad_formula_2() {
#[test]
fn test_parser_bad_formula_3() {
let worksheets = vec!["Sheet1".to_string(), "Sheet2".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -225,7 +225,7 @@ fn test_parser_bad_formula_3() {
#[test]
fn test_parser_formulas() {
let worksheets = vec!["Sheet1".to_string(), "Sheet2".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
let formulas = vec![
Formula {
@@ -273,7 +273,7 @@ fn test_parser_formulas() {
#[test]
fn test_parser_r1c1_formulas() {
let worksheets = vec!["Sheet1".to_string(), "Sheet2".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
parser.set_lexer_mode(LexerMode::R1C1);
let formulas = vec![
@@ -338,7 +338,7 @@ fn test_parser_r1c1_formulas() {
#[test]
fn test_parser_quotes() {
let worksheets = vec!["Sheet1".to_string(), "Second Sheet".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -354,7 +354,7 @@ fn test_parser_quotes() {
#[test]
fn test_parser_escape_quotes() {
let worksheets = vec!["Sheet1".to_string(), "Second '2' Sheet".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -370,7 +370,7 @@ fn test_parser_escape_quotes() {
#[test]
fn test_parser_parenthesis() {
let worksheets = vec!["Sheet1".to_string(), "Second2".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -386,7 +386,7 @@ fn test_parser_parenthesis() {
#[test]
fn test_parser_excel_xlfn() {
let worksheets = vec!["Sheet1".to_string(), "Second2".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -407,7 +407,7 @@ fn test_to_string_displaced() {
column: 1,
};
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
let node = parser.parse("C3", &Some(context.clone()));
let displace_data = DisplaceData::Column {
@@ -427,7 +427,7 @@ fn test_to_string_displaced_full_ranges() {
column: 1,
};
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
let node = parser.parse("SUM(3:3)", &Some(context.clone()));
let displace_data = DisplaceData::Column {
@@ -460,7 +460,7 @@ fn test_to_string_displaced_too_low() {
column: 1,
};
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
let node = parser.parse("C3", &Some(context.clone()));
let displace_data = DisplaceData::Column {
@@ -480,7 +480,7 @@ fn test_to_string_displaced_too_high() {
column: 1,
};
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
let node = parser.parse("C3", &Some(context.clone()));
let displace_data = DisplaceData::Column {

View File

@@ -9,7 +9,7 @@ use crate::expressions::types::CellReferenceRC;
#[test]
fn issue_155_parser() {
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -24,7 +24,7 @@ fn issue_155_parser() {
#[test]
fn issue_155_parser_case_2() {
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -39,7 +39,7 @@ fn issue_155_parser_case_2() {
#[test]
fn issue_155_parser_only_row() {
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {
@@ -55,7 +55,7 @@ fn issue_155_parser_only_row() {
#[test]
fn issue_155_parser_only_column() {
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {

View File

@@ -15,7 +15,7 @@ fn test_move_formula() {
column,
};
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Area is C2:F6
let area = &Area {
@@ -102,7 +102,7 @@ fn test_move_formula_context_offset() {
column,
};
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Area is C2:F6
let area = &Area {
@@ -140,7 +140,7 @@ fn test_move_formula_area_limits() {
column,
};
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Area is C2:F6
let area = &Area {
@@ -195,7 +195,7 @@ fn test_move_formula_ranges() {
column,
};
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
let area = &Area {
sheet: 0,
@@ -318,7 +318,7 @@ fn test_move_formula_wrong_reference() {
height: 5,
};
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Wrong formulas will NOT be displaced
let node = parser.parse("Sheet3!AB31", &Some(context.clone()));
@@ -377,7 +377,7 @@ fn test_move_formula_misc() {
column,
};
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Area is C2:F6
let area = &Area {
@@ -445,7 +445,7 @@ fn test_move_formula_another_sheet() {
};
// we add two sheets and we cut/paste from Sheet1 to Sheet2
let worksheets = vec!["Sheet1".to_string(), "Sheet2".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Area is C2:F6
let area = &Area {

View File

@@ -14,7 +14,7 @@ struct Formula<'a> {
#[test]
fn test_parser_formulas_with_full_ranges() {
let worksheets = vec!["Sheet1".to_string(), "Second Sheet".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
let formulas = vec![
Formula {
@@ -81,7 +81,7 @@ fn test_parser_formulas_with_full_ranges() {
#[test]
fn test_range_inverse_order() {
let worksheets = vec!["Sheet1".to_string(), "Sheet2".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {

View File

@@ -9,7 +9,7 @@ use crate::expressions::types::CellReferenceRC;
#[test]
fn exp_order() {
let worksheets = vec!["Sheet1".to_string()];
let mut parser = Parser::new(worksheets, HashMap::new());
let mut parser = Parser::new(worksheets, vec![], HashMap::new());
// Reference cell is Sheet1!A1
let cell_reference = CellReferenceRC {

View File

@@ -63,7 +63,7 @@ fn simple_table() {
let row_count = 3;
let tables = create_test_table("tblIncome", &column_names, "A1", row_count);
let mut parser = Parser::new(worksheets, tables);
let mut parser = Parser::new(worksheets, vec![], tables);
// Reference cell is 'Sheet One'!F2
let cell_reference = CellReferenceRC {
sheet: "Sheet One".to_string(),

View File

@@ -263,7 +263,9 @@ pub(crate) fn forward_references(
// TODO: Not implemented
Node::ArrayKind(_) => {}
// Do nothing. Note: we could do a blanket _ => {}
Node::VariableKind(_) => {}
Node::DefinedNameKind(_) => {}
Node::TableNameKind(_) => {}
Node::WrongVariableKind(_) => {}
Node::ErrorKind(_) => {}
Node::ParseErrorKind { .. } => {}
Node::EmptyArgKind => {}