Skip to content

Commit e1da7b0

Browse files
committed
NEXT WIP
1 parent f0bee95 commit e1da7b0

File tree

10 files changed

+202
-250
lines changed

10 files changed

+202
-250
lines changed

src/components/composer/composer/cell_composer_store.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { prettify } from "../../../formulas/formula_formatter";
12
import { parseTokens } from "../../../formulas/parser";
23
import { isMultipleElementMatrix, toScalar } from "../../../functions/helper_matrices";
34
import { parseLiteral } from "../../../helpers/cells";
@@ -28,7 +29,6 @@ import {
2829
isMatrix,
2930
} from "../../../types";
3031
import { AbstractComposerStore } from "./abstract_composer_store";
31-
import { prettify } from "./prettifier_content";
3232

3333
const CELL_DELETED_MESSAGE = _t("The cell you are trying to edit has been deleted.");
3434

@@ -206,7 +206,7 @@ export class CellComposerStore extends AbstractComposerStore {
206206
if (cell?.isFormula) {
207207
const prettifiedContent = cell.compiledFormula.isBadExpression
208208
? cell.content
209-
: prettify(parseTokens(cell.compiledFormula.tokens));
209+
: prettify(parseTokens(cell.compiledFormula.tokens), 80);
210210
return localizeFormula(prettifiedContent, locale);
211211
}
212212
const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);

src/components/composer/composer/prettifier_content.ts renamed to src/formulas/formula_formatter.ts

Lines changed: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
import {
2-
AST,
3-
leftOperandNeedsParenthesis,
4-
rightOperandNeedsParenthesis,
5-
} from "../../../formulas/parser";
6-
import { memoize } from "../../../helpers";
1+
import { memoize } from "../helpers";
2+
import { AST, ASTOperation, ASTUnaryOperation, OP_PRIORITY } from "./parser";
3+
4+
const ASSOCIATIVE_OPERATORS = ["*", "+", "&"];
75

86
/**
97
* Pretty-prints formula ASTs into readable formulas.
@@ -17,8 +15,8 @@ import { memoize } from "../../../helpers";
1715
* - https://lik.ai/blog/how-a-pretty-printer-works/
1816
* - Wadler, "A prettier printer": https://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf
1917
*/
20-
export function prettify(ast: AST): string {
21-
return "=" + print(astToDoc(ast), 59); // 59 but 60 with the `=` at the beginning
18+
export function prettify(ast: AST, width = 60): string {
19+
return "=" + print(astToDoc(ast), width - 1); // width-1 because of the leading '='
2220
}
2321

2422
// ---------------------------------------
@@ -290,3 +288,66 @@ function wrapInParentheses(doc: Doc, functionName: undefined | string = undefine
290288
}
291289
return group(concat(docToConcat));
292290
}
291+
292+
/**
293+
* Converts an ast formula to the corresponding string
294+
*/
295+
export function astToFormula(ast: AST): string {
296+
switch (ast.type) {
297+
case "FUNCALL":
298+
const args = ast.args.map((arg) => astToFormula(arg));
299+
return `${ast.value}(${args.join(",")})`;
300+
case "NUMBER":
301+
return ast.value.toString();
302+
case "REFERENCE":
303+
return ast.value;
304+
case "STRING":
305+
return `"${ast.value}"`;
306+
case "BOOLEAN":
307+
return ast.value ? "TRUE" : "FALSE";
308+
case "UNARY_OPERATION":
309+
if (ast.postfix) {
310+
const leftOperand = leftOperandNeedsParenthesis(ast)
311+
? `(${astToFormula(ast.operand)})`
312+
: astToFormula(ast.operand);
313+
return leftOperand + ast.value;
314+
}
315+
const rightOperand = rightOperandNeedsParenthesis(ast)
316+
? `(${astToFormula(ast.operand)})`
317+
: astToFormula(ast.operand);
318+
return ast.value + rightOperand;
319+
case "BIN_OPERATION":
320+
const leftOperation = leftOperandNeedsParenthesis(ast)
321+
? `(${astToFormula(ast.left)})`
322+
: astToFormula(ast.left);
323+
const rightOperation = rightOperandNeedsParenthesis(ast)
324+
? `(${astToFormula(ast.right)})`
325+
: astToFormula(ast.right);
326+
return leftOperation + ast.value + rightOperation;
327+
default:
328+
return ast.value;
329+
}
330+
}
331+
332+
function leftOperandNeedsParenthesis(operationAST: ASTOperation | ASTUnaryOperation): boolean {
333+
const mainOperator = operationAST.value;
334+
const leftOperation = "left" in operationAST ? operationAST.left : operationAST.operand;
335+
const leftOperator = leftOperation.value;
336+
return (
337+
leftOperation.type === "BIN_OPERATION" && OP_PRIORITY[leftOperator] < OP_PRIORITY[mainOperator]
338+
);
339+
}
340+
341+
function rightOperandNeedsParenthesis(operationAST: ASTOperation | ASTUnaryOperation): boolean {
342+
const mainOperator = operationAST.value;
343+
const rightOperation = "right" in operationAST ? operationAST.right : operationAST.operand;
344+
const rightPriority = OP_PRIORITY[rightOperation.value];
345+
const mainPriority = OP_PRIORITY[mainOperator];
346+
if (rightOperation.type !== "BIN_OPERATION") {
347+
return false;
348+
}
349+
if (rightPriority < mainPriority) {
350+
return true;
351+
}
352+
return rightPriority === mainPriority && !ASSOCIATIVE_OPERATORS.includes(mainOperator);
353+
}

src/formulas/parser.ts

Lines changed: 2 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ const functionRegex = /[a-zA-Z0-9\_]+(\.[a-zA-Z0-9\_]+)*/;
1010
const UNARY_OPERATORS_PREFIX = ["-", "+"];
1111
const UNARY_OPERATORS_POSTFIX = ["%"];
1212

13-
const ASSOCIATIVE_OPERATORS = ["*", "+", "&"];
14-
1513
interface RichToken extends Token {
1614
tokenIndex: number;
1715
}
@@ -68,14 +66,14 @@ interface ASTBoolean extends ASTBase {
6866
value: boolean;
6967
}
7068

71-
interface ASTUnaryOperation extends ASTBase {
69+
export interface ASTUnaryOperation extends ASTBase {
7270
type: "UNARY_OPERATION";
7371
value: any;
7472
operand: AST;
7573
postfix?: boolean; // needed to rebuild string from ast
7674
}
7775

78-
interface ASTOperation extends ASTBase {
76+
export interface ASTOperation extends ASTBase {
7977
type: "BIN_OPERATION";
8078
value: any;
8179
left: AST;
@@ -414,70 +412,3 @@ export function mapAst<T extends AST["type"]>(
414412
return ast;
415413
}
416414
}
417-
418-
/**
419-
* Converts an ast formula to the corresponding string
420-
*/
421-
export function astToFormula(ast: AST): string {
422-
switch (ast.type) {
423-
case "FUNCALL":
424-
const args = ast.args.map((arg) => astToFormula(arg));
425-
return `${ast.value}(${args.join(",")})`;
426-
case "NUMBER":
427-
return ast.value.toString();
428-
case "REFERENCE":
429-
return ast.value;
430-
case "STRING":
431-
return `"${ast.value}"`;
432-
case "BOOLEAN":
433-
return ast.value ? "TRUE" : "FALSE";
434-
case "UNARY_OPERATION":
435-
if (ast.postfix) {
436-
const leftOperand = leftOperandNeedsParenthesis(ast)
437-
? `(${astToFormula(ast.operand)})`
438-
: astToFormula(ast.operand);
439-
return leftOperand + ast.value;
440-
}
441-
const rightOperand = rightOperandNeedsParenthesis(ast)
442-
? `(${astToFormula(ast.operand)})`
443-
: astToFormula(ast.operand);
444-
return ast.value + rightOperand;
445-
case "BIN_OPERATION":
446-
const leftOperation = leftOperandNeedsParenthesis(ast)
447-
? `(${astToFormula(ast.left)})`
448-
: astToFormula(ast.left);
449-
const rightOperation = rightOperandNeedsParenthesis(ast)
450-
? `(${astToFormula(ast.right)})`
451-
: astToFormula(ast.right);
452-
return leftOperation + ast.value + rightOperation;
453-
default:
454-
return ast.value;
455-
}
456-
}
457-
458-
export function leftOperandNeedsParenthesis(
459-
operationAST: ASTOperation | ASTUnaryOperation
460-
): boolean {
461-
const mainOperator = operationAST.value;
462-
const leftOperation = "left" in operationAST ? operationAST.left : operationAST.operand;
463-
const leftOperator = leftOperation.value;
464-
return (
465-
leftOperation.type === "BIN_OPERATION" && OP_PRIORITY[leftOperator] < OP_PRIORITY[mainOperator]
466-
);
467-
}
468-
469-
export function rightOperandNeedsParenthesis(
470-
operationAST: ASTOperation | ASTUnaryOperation
471-
): boolean {
472-
const mainOperator = operationAST.value;
473-
const rightOperation = "right" in operationAST ? operationAST.right : operationAST.operand;
474-
const rightPriority = OP_PRIORITY[rightOperation.value];
475-
const mainPriority = OP_PRIORITY[mainOperator];
476-
if (rightOperation.type !== "BIN_OPERATION") {
477-
return false;
478-
}
479-
if (rightPriority < mainPriority) {
480-
return true;
481-
}
482-
return rightPriority === mainPriority && !ASSOCIATIVE_OPERATORS.includes(mainOperator);
483-
}

src/index.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -213,13 +213,8 @@ export { tokenColors } from "./components/composer/composer/abstract_composer_st
213213
export { Spreadsheet } from "./components/index";
214214
export { setDefaultSheetViewSize } from "./constants";
215215
export { compile, compileTokens, functionCache } from "./formulas/compiler";
216-
export {
217-
astToFormula,
218-
convertAstNodes,
219-
iterateAstNodes,
220-
parse,
221-
parseTokens,
222-
} from "./formulas/parser";
216+
export { astToFormula } from "./formulas/formula_formatter";
217+
export { convertAstNodes, iterateAstNodes, parse, parseTokens } from "./formulas/parser";
223218
export { tokenize } from "./formulas/tokenizer";
224219
export { AbstractChart } from "./helpers/figures/charts";
225220
export { findCellInNewZone } from "./helpers/zones";

src/plugins/ui_core_views/pivot_ui.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Token } from "../../formulas";
2-
import { astToFormula } from "../../formulas/parser";
2+
import { astToFormula } from "../../formulas/formula_formatter";
33
import { toScalar } from "../../functions/helper_matrices";
44
import { toBoolean } from "../../functions/helpers";
55
import { getUniqueText } from "../../helpers";

src/xlsx/functions/cells.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
1-
import {
2-
AST,
3-
ASTFuncall,
4-
ASTString,
5-
astToFormula,
6-
convertAstNodes,
7-
parse,
8-
} from "../../formulas/parser";
1+
import { astToFormula } from "../../formulas/formula_formatter";
2+
import { AST, ASTFuncall, ASTString, convertAstNodes, parse } from "../../formulas/parser";
93
import { functionRegistry } from "../../functions";
104
import { formatValue, isNumber } from "../../helpers";
115
import { mdyDateRegexp, parseDateTime, timeRegexp, ymdDateRegexp } from "../../helpers/dates";

tests/composer/composer_prettifier.test.ts

Lines changed: 0 additions & 148 deletions
This file was deleted.

0 commit comments

Comments
 (0)