diff --git a/packages/expressions/src/lib/ast_factory.ts b/packages/expressions/src/lib/ast_factory.ts index b56361c..f77398a 100644 --- a/packages/expressions/src/lib/ast_factory.ts +++ b/packages/expressions/src/lib/ast_factory.ts @@ -7,6 +7,7 @@ import * as ast from './ast.js'; export interface AstFactory { empty(): E; + getValue(receiver: Record, name: string): any; literal(value: ast.LiteralValue): E; id(name: string): E; unary(operator: string, expression: E): E; @@ -30,6 +31,10 @@ export class DefaultAstFactory implements AstFactory { return {type: 'Empty'}; } + getValue(receiver: Record, name: string) { + return receiver?.[name]; + } + // TODO(justinfagnani): just use a JS literal? literal(value: ast.LiteralValue): ast.Literal { return { diff --git a/packages/expressions/src/lib/eval.ts b/packages/expressions/src/lib/eval.ts index 45cef3b..bff41de 100644 --- a/packages/expressions/src/lib/eval.ts +++ b/packages/expressions/src/lib/eval.ts @@ -130,6 +130,10 @@ export class EvalAstFactory implements AstFactory { }; } + getValue(receiver: Record, name: string) { + return receiver?.[name]; + } + // TODO(justinfagnani): just use a JS literal? literal(v: string): Literal { return { @@ -145,13 +149,14 @@ export class EvalAstFactory implements AstFactory { } id(v: string): ID { + const astFactoryInstance = this; return { type: 'ID', value: v, evaluate(scope) { // TODO(justinfagnani): this prevents access to properties named 'this' if (this.value === 'this') return scope; - return scope?.[this.value]; + return astFactoryInstance.getValue(scope, this.value); }, getIds(idents) { idents.push(this.value); @@ -220,12 +225,14 @@ export class EvalAstFactory implements AstFactory { } getter(g: Expression, n: string): Getter { + const astFactoryInstance = this; + return { type: 'Getter', receiver: g, name: n, evaluate(scope) { - return this.receiver.evaluate(scope)?.[this.name]; + return astFactoryInstance.getValue(this.receiver.evaluate(scope), this.name); }, getIds(idents) { this.receiver.getIds(idents); @@ -267,12 +274,14 @@ export class EvalAstFactory implements AstFactory { } index(e: Expression, a: Expression): Index { + const astFactoryInstance = this; + return { type: 'Index', receiver: e, argument: a, evaluate(scope) { - return this.receiver.evaluate(scope)?.[this.argument.evaluate(scope)]; + return astFactoryInstance.getValue(this.receiver.evaluate(scope), this.argument.evaluate(scope)); }, getIds(idents) { this.receiver.getIds(idents);