[IMP] compiler: add better support for "in" and "new" operators

Previously, the support for the "in" operator was iffy, and "new" was
not supported at all, "in" would fail when checking if a nested property
was in something else, as the leading space would be stripped, and "new"
would fail because the following space would be stripped.

This commit fixes that by preserving the significant whitespace where
necessary.
This commit is contained in:
Samuel Degueldre
2022-05-18 16:06:52 +02:00
committed by Géry Debongnie
parent 4c77132ae2
commit d917af4614
2 changed files with 15 additions and 4 deletions
+8 -3
View File
@@ -85,8 +85,10 @@ const STATIC_TOKEN_MAP: { [key: string]: TKind } = Object.assign(Object.create(n
}); });
// note that the space after typeof is relevant. It makes sure that the formatted // note that the space after typeof is relevant. It makes sure that the formatted
// expression has a space after typeof // expression has a space after typeof. Currently we don't support delete and void
const OPERATORS = "...,.,===,==,+,!==,!=,!,||,&&,>=,>,<=,<,?,-,*,/,%,typeof ,=>,=,;,in ".split(","); const OPERATORS = "...,.,===,==,+,!==,!=,!,||,&&,>=,>,<=,<,?,-,*,/,%,typeof ,=>,=,;,in ,new ".split(
","
);
type Tokenizer = (expr: string) => Token | false; type Tokenizer = (expr: string) => Token | false;
@@ -344,9 +346,12 @@ export function compileExprToArray(expr: string): Token[] {
return tokens; return tokens;
} }
// Leading spaces are trimmed during tokenization, so they need to be added back for some values
const paddedValues = new Map([["in ", " in "]]);
export function compileExpr(expr: string): string { export function compileExpr(expr: string): string {
return compileExprToArray(expr) return compileExprToArray(expr)
.map((t) => t.value) .map((t) => paddedValues.get(t.value) || t.value)
.join(""); .join("");
} }
+7 -1
View File
@@ -135,7 +135,7 @@ describe("expression evaluation", () => {
expect(compileExpr("color === 'black'")).toBe("ctx['color']==='black'"); expect(compileExpr("color === 'black'")).toBe("ctx['color']==='black'");
expect(compileExpr("'li_'+item")).toBe("'li_'+ctx['item']"); expect(compileExpr("'li_'+item")).toBe("'li_'+ctx['item']");
expect(compileExpr("state.val > 1")).toBe("ctx['state'].val>1"); expect(compileExpr("state.val > 1")).toBe("ctx['state'].val>1");
expect(compileExpr("a in b")).toBe("ctx['a']in ctx['b']"); expect(compileExpr("a in b")).toBe("ctx['a'] in ctx['b']");
}); });
test("boolean operations", () => { test("boolean operations", () => {
@@ -215,4 +215,10 @@ describe("expression evaluation", () => {
expect(compileExpr("[a, {b, c},d]")).toBe("[ctx['a'],{b:ctx['b'],c:ctx['c']},ctx['d']]"); expect(compileExpr("[a, {b, c},d]")).toBe("[ctx['a'],{b:ctx['b'],c:ctx['c']},ctx['d']]");
expect(compileExpr("{a:[b, {c, d: e}]}")).toBe("{a:[ctx['b'],{c:ctx['c'],d:ctx['e']}]}"); expect(compileExpr("{a:[b, {c, d: e}]}")).toBe("{a:[ctx['b'],{c:ctx['c'],d:ctx['e']}]}");
}); });
test("preserving spaces where needed for text operators", () => {
expect(compileExpr("new Date()")).toBe("new Date()");
expect(compileExpr("a.c in b")).toBe("ctx['a'].c in ctx['b']");
expect(compileExpr("typeof val")).toBe("typeof ctx['val']");
});
}); });