f7
f7 is a spreadsheet formula execution library
git clone https://git.vogt.world/f7.git
Log | Files | README.md | LICENSE.md
← All files
name: src/main/js/utils/Parsers.ts
-rw-r--r--
3062
 1import { InvalidArgumentError } from "../common/errors/InvalidArgumentError";
 2import { TranspilationVisitor } from "../execution/TranspilationVisitor";
 3import { CellQuery } from "../models/nodes/CellQuery";
 4import { ErrorNode } from "../models/nodes/ErrorNode";
 5import { Node } from "../models/nodes/Node";
 6import { NodeType } from "../models/nodes/NodeType";
 7import { RangeNode } from "../models/nodes/RangeNode";
 8import { Ref } from "../spreadsheet/Ref";
 9import { AlphaUtils } from "./AlphaUtils";
10import * as antlr4 from "antlr4";
11import { F7Lexer } from "../antlr/F7Lexer";
12import { F7Parser } from "../antlr/F7Parser";
13
14export class Parsers {
15  /**
16   * Parse a range to node for execution.
17   * Eg: Sheet1!A1:B33
18   *
19   * @param range - range string
20   * @return range node.
21   */
22  static parseNamedRange(range: string): Node {
23    try {
24      const chars = new antlr4.InputStream(range);
25      const lexer: any = new F7Lexer(chars);
26      const tokens = new antlr4.CommonTokenStream(lexer);
27      const parser = new F7Parser(tokens) as any;
28      parser.buildParseTrees = true;
29      // This is the key line that is different from what tree we use when parsing normal F7 code.
30      const tree = parser.range();
31      return new TranspilationVisitor().visit(tree);
32    } catch (e) {
33      return new ErrorNode(e);
34    }
35  }
36
37  /**
38   * Parse a named range query in string format to a CellQuery, throwing an invalid argument error
39   * if we can't parse it.
40   * @param range to parse.
41   */
42  static parseNamedRangeToCellQuery(range: string): CellQuery {
43    const node = Parsers.parseNamedRange(range);
44    if (node.type === NodeType.Range) {
45      const rangeNode = <RangeNode>node;
46      return rangeNode.query;
47    }
48    throw new InvalidArgumentError(`Invalid range: ${range}`);
49  }
50
51  /**
52   * Parse formula code to a node for execution.
53   * Eg: SUM({1, 2, 3}, 888.22, "99.1")
54   *
55   * @param input - formula string.
56   * @return node
57   */
58  static parseFormulaCode(input: string): Node {
59    try {
60      const chars = new antlr4.InputStream(input);
61      const lexer: any = new F7Lexer(chars);
62      const tokens = new antlr4.CommonTokenStream(lexer);
63      const parser = new F7Parser(tokens) as any;
64      parser.buildParseTrees = true;
65      const tree = parser.start().block();
66      return new TranspilationVisitor().visit(tree);
67    } catch (e) {
68      return new ErrorNode(e);
69    }
70  }
71
72  /**
73   * Parse a reference pair, which is just two relative cell references separated by a semicolon.
74   * Eg:  A1:A2
75   * @param ref string to parse.
76   */
77  static parseReferencePair(ref: string): Ref {
78    const REF_PATTERN = /^(\D+)(\d+):(\D+)(\d+)$/;
79    const matches = ref.match(REF_PATTERN);
80    if (matches) {
81      return {
82        startColumnIndex: AlphaUtils.columnToInt(matches[1]),
83        startRowIndex: AlphaUtils.rowToInt(matches[2]),
84        endColumnIndex: AlphaUtils.columnToInt(matches[3]),
85        endRowIndex: AlphaUtils.rowToInt(matches[4]),
86      };
87    }
88    throw new InvalidArgumentError(`Invalid ref: ${ref}`);
89  }
90}