Skip to content

Commit

Permalink
Merge pull request #652 from streamich/expr-perf
Browse files Browse the repository at this point in the history
JSON Expression performance improvements
  • Loading branch information
streamich authored Jun 24, 2024
2 parents a7c7591 + 43cd177 commit 0817d77
Show file tree
Hide file tree
Showing 6 changed files with 18 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/json-expression/__tests__/codegen.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const check = (
operators: operatorsMap,
});
const fn = codegen.run().compile();
const result = fn({vars: new Vars(data)});
const result = fn(new Vars(data));
expect(result).toStrictEqual(expected);
};

Expand Down
2 changes: 1 addition & 1 deletion src/json-expression/__tests__/impure.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const compile = (expression: Expr, options: JsonExpressionCodegenContext = {}) =
operators: operatorsMap,
});
const fn = codegen.run().compile();
return (data: unknown) => fn({vars: new Vars(data)});
return (data: unknown) => fn(new Vars(data));
};

test('can execute expression twice with different inputs', () => {
Expand Down
20 changes: 11 additions & 9 deletions src/json-expression/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {JavaScript} from '@jsonjoy.com/util/lib/codegen';
import {Vars} from './Vars';
import type * as types from './types';

export type JsonExpressionFn = (ctx: types.JsonExpressionExecutionContext) => unknown;
export type JsonExpressionFn = (vars: types.JsonExpressionExecutionContext['vars']) => unknown;

export interface JsonExpressionCodegenOptions extends types.JsonExpressionCodegenContext {
expression: types.Expr;
Expand All @@ -19,8 +19,7 @@ export class JsonExpressionCodegen {

public constructor(protected options: JsonExpressionCodegenOptions) {
this.codegen = new Codegen<JsonExpressionFn>({
args: ['ctx'],
prologue: 'var vars = ctx.vars;',
args: ['vars'],
epilogue: '',
});
this.evaluate = createEvaluate({...options});
Expand All @@ -42,7 +41,7 @@ export class JsonExpressionCodegen {
return this.codegen.addConstant(js);
};

private subExpression = (expr: types.Expr): ((ctx: types.JsonExpressionExecutionContext) => unknown) => {
private subExpression = (expr: types.Expr): JsonExpressionFn => {
const codegen = new JsonExpressionCodegen({...this.options, expression: expr});
const fn = codegen.run().compile();
return fn;
Expand Down Expand Up @@ -90,12 +89,15 @@ export class JsonExpressionCodegen {
return this.codegen.generate();
}

public compile() {
const fn = this.codegen.compile();
// console.log('fn', fn.toString());
return (ctx: types.JsonExpressionExecutionContext) => {
public compileRaw(): JsonExpressionFn {
return this.codegen.compile();
}

public compile(): JsonExpressionFn {
const fn = this.compileRaw();
return (vars) => {
try {
return fn(ctx);
return fn(vars);
} catch (err) {
if (err instanceof Error) throw err;
const error = new Error('Expression evaluation error.');
Expand Down
4 changes: 2 additions & 2 deletions src/json-expression/operators/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const createSubExpressionOperator = <N extends string>(
operand1 instanceof Literal && operand1.val instanceof Array
? JSON.stringify(operand1.val)
: `asArr(${operand1})`;
const js = `${name}(${arr},${JSON.stringify(varname)},vars,function(){return ${d}({vars:vars})})`;
const js = `${name}(${arr},${JSON.stringify(varname)},vars,function(){return ${d}(vars)})`;
return new Expression(js);
},
] as types.OperatorDefinition<types.TernaryExpression<N>>;
Expand Down Expand Up @@ -257,7 +257,7 @@ export const arrayOperators: types.OperatorDefinition<any>[] = [
: `asArr(${operand1})`;
const js = `reduce((${arr}),(${ctx.operands[1]}),${JSON.stringify(accname)},${JSON.stringify(
varname,
)},vars,function(){return ${d}({vars:vars})})`;
)},vars,function(){return ${d}(vars)})`;
return new Expression(js);
},
] as types.OperatorDefinition<types.ExprReduce>,
Expand Down
3 changes: 2 additions & 1 deletion src/json-expression/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {JavaScript} from '@jsonjoy.com/util/lib/codegen';
import type {Vars} from './Vars';
import type {ExpressionResult} from './codegen-steps';
import type {JsonExpressionFn} from './codegen';

export type Literal<T> = T | LiteralExpression<T>;
export type LiteralExpression<O> = [constant: O];
Expand Down Expand Up @@ -321,7 +322,7 @@ export interface OperatorCodegenCtx<E extends Expression> extends JsonExpression
operand: (operand: Expression) => ExpressionResult;
link: (value: unknown, name?: string) => string;
const: (js: JavaScript<unknown>) => string;
subExpression: (expr: Expression) => (ctx: JsonExpressionExecutionContext) => unknown;
subExpression: (expr: Expression) => JsonExpressionFn;
var: (name: string) => string;
}

Expand Down
2 changes: 1 addition & 1 deletion src/json-type/type/classes/OrType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export class OrType<T extends Type[]> extends AbstractType<schema.OrSchema<{[K i
operators: operatorsMap,
});
const fn = codegen.run().compile();
return (this.__discriminator = (data: unknown) => +(fn({vars: new Vars(data)}) as any));
return (this.__discriminator = (data: unknown) => +(fn(new Vars(data)) as any));
}

public validateSchema(): void {
Expand Down

0 comments on commit 0817d77

Please sign in to comment.