diff --git a/meson.build b/meson.build index 33b7629..7549e56 100644 --- a/meson.build +++ b/meson.build @@ -27,6 +27,7 @@ executable(meson.project_name(), 'src/Services/Formula/AST/CellReference.vala', 'src/Services/Formula/AST/Expression.vala', 'src/Services/Formula/AST/NumberExpression.vala', + 'src/Services/Formula/AST/TextExpression.vala', 'src/Services/Formula/FormulaGrammar.vala', 'src/Services/Formula/FormulaParser.vala', 'src/Services/Parsing/Evaluator.vala', diff --git a/src/Models/Cell.vala b/src/Models/Cell.vala index c639f88..982516e 100644 --- a/src/Models/Cell.vala +++ b/src/Models/Cell.vala @@ -22,7 +22,13 @@ public class Spreadsheet.Models.Cell : Object { try { var parser = new FormulaParser (new Lexer (new FormulaGrammar ()).tokenize (value)); var expression = parser.parse (); - display_content = ((double)expression.eval (page)).to_string (); + + var eval = expression.eval (page); + if (eval.type () == typeof (double)) { + display_content = ((double)eval).to_string (); + } else if (eval.type () == typeof (string)) { + display_content = (string)eval; + } } catch (ParserError err) { debug ("Error: " + err.message); display_content = "Error"; diff --git a/src/Services/Formula/AST/TextExpression.vala b/src/Services/Formula/AST/TextExpression.vala new file mode 100644 index 0000000..872ef70 --- /dev/null +++ b/src/Services/Formula/AST/TextExpression.vala @@ -0,0 +1,13 @@ +public class Spreadsheet.Services.Formula.AST.TextExpression : Expression { + public string text { get; construct; } + + public TextExpression (string value) { + Object ( + text: value + ); + } + + public override Value eval (Spreadsheet.Models.Page sheet) { + return text; + } +} diff --git a/src/Services/Formula/FormulaGrammar.vala b/src/Services/Formula/FormulaGrammar.vala index f0fee66..058a0d7 100644 --- a/src/Services/Formula/FormulaGrammar.vala +++ b/src/Services/Formula/FormulaGrammar.vala @@ -1,15 +1,32 @@ using Spreadsheet.Services.Parsing; public class Spreadsheet.Services.Formula.FormulaGrammar : Grammar { + private string func_name_regex = ""; + public FormulaGrammar () { rules["root"] = root_rules (); } + private string get_func_name_regex () { + if (func_name_regex == "") { + string[]? func_names = null; + foreach (var function in App.functions) { + func_names += function.name; + func_names += function.name.ascii_up (); + } + + func_name_regex = string.joinv ("|", func_names); + } + + return func_name_regex; + } + private Gee.ArrayList root_rules () { return new Gee.ArrayList.wrap ({ new Evaluator (/[ \t]/, token ("[[ignore]]")), new Evaluator (/[A-Z]+[0-9]+/, token ("cell-name")), - new Evaluator (/[A-Za-z][\w]*/, token ("identifier")), + new Evaluator (/=/, token ("equal")), + new Evaluator (get_func_name_regex (), token ("identifier")), new Evaluator (/\(/, token ("left-parenthese")), new Evaluator (/\)/, token ("right-parenthese")), new Evaluator (/,/, token ("comma")), @@ -20,7 +37,8 @@ public class Spreadsheet.Services.Formula.FormulaGrammar : Grammar { new Evaluator (/-/, token ("dash")), new Evaluator (/\//, token ("slash")), new Evaluator (/%/, token ("percent")), - new Evaluator (/\^/, token ("carat")) + new Evaluator (/\^/, token ("carat")), + new Evaluator (/\D+/, token ("text")) }); } } diff --git a/src/Services/Formula/FormulaParser.vala b/src/Services/Formula/FormulaParser.vala index b8edc91..097f958 100644 --- a/src/Services/Formula/FormulaParser.vala +++ b/src/Services/Formula/FormulaParser.vala @@ -20,8 +20,6 @@ public class Spreadsheet.Services.Formula.FormulaParser : Parsing.Parser { last = parse_expression (); if (current.kind == delimiter) { break; - } else { - expect ("semi-colon"); } } @@ -34,19 +32,27 @@ public class Spreadsheet.Services.Formula.FormulaParser : Parsing.Parser { } private Expression parse_primary_expression () throws ParserError { - if (current.kind == "identifier") { - return parse_call_expression (); + if (current.kind == "equal") { + accept ("equal"); + + if (current.kind == "identifier") { + return parse_call_expression (); + } else if (current.kind == "number") { + return parse_number (); + } else if (accept ("left-parenthese")) { + var res = parse_expression (); + expect ("right-parenthese"); + return res; + } else if (current.kind == "cell-name") { + return parse_cell_name (); + } else { + unexpected (); + return new NumberExpression (0.0); + } } else if (current.kind == "number") { return parse_number (); - } else if (accept ("left-parenthese")) { - var res = parse_expression (); - expect ("right-parenthese"); - return res; - } else if (current.kind == "cell-name") { - return parse_cell_name (); } else { - unexpected (); - return new NumberExpression (0.0); + return parse_text (); } } @@ -135,6 +141,17 @@ public class Spreadsheet.Services.Formula.FormulaParser : Parsing.Parser { return res; } + private TextExpression parse_text () throws ParserError { + string val = ""; + + while (current.kind != "eof") { + val += current.lexeme; + eat (); + } + + return new TextExpression (val); + } + private CellReference parse_cell_name () throws ParserError { var cell = new CellReference () { cell_name = current.lexeme }; expect ("cell-name");