Skip to content

Commit

Permalink
feat(json-expression): 🎸 implement "push" operator
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Jun 21, 2024
1 parent 16e0e71 commit edbd128
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 0 deletions.
34 changes: 34 additions & 0 deletions src/json-expression/__tests__/jsonExpressionUnitTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1640,6 +1640,40 @@ export const jsonExpressionUnitTests = (
});
});

describe('push', () => {
test('can push static values into static array', () => {
const arr: unknown[] = [];
check(['push', [arr], 1], [1]);
check(['push', [arr], 1, 2, 3], [1, 2, 3]);
check(['push', [arr], 1, '2', true, [[]]], [1, '2', true, []]);
check(['push', [[1]], 2, 3], [1, 2, 3]);
});

test('can push static values into array', () => {
check(['push', ['$', '/arr'], 1], [1], {arr: []});
check(['push', ['$', '/arr'], 1, 2, 3], [1, 2, 3], {arr: []});
check(['push', ['$', '/arr'], 1, 2, 3], [0, 1, 2, 3], {arr: [0]});
});

test('can push values into static array', () => {
check(['push', [[]], ['$', '/val'], 1], [0, 1], {val: 0});
});

test('can push values into array', () => {
check(['push', ['$', '/arr'], ['$', '/val'], '2'], [0, 1, '2'], {arr: [0], val: 1});
});

test('concatenates empty arrays', () => {
check(['push', [[1]], [[]]], [1, []]);
check(['push', [[]], [[]]], [[]]);
});

test('throws on invalid operand count', () => {
expect(() => check((['push', [[]]] as any), false)).toThrowErrorMatchingInlineSnapshot(`""push" operator expects at least two operands."`);
expect(() => check((['push', []] as any), false)).toThrowErrorMatchingInlineSnapshot(`""push" operator expects at least two operands."`);
});
});

describe('head', () => {
test('returns first two elements', () => {
check(['head', [[1, 2, 3]], 2], [1, 2]);
Expand Down
1 change: 1 addition & 0 deletions src/json-expression/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export class JsonExpressionCodegen {
link: this.linkOperandDeps,
const: this.operatorConst,
subExpression: this.subExpression,
var: (value: string) => this.codegen.var(value),
};
return codegen(ctx);
}
Expand Down
1 change: 1 addition & 0 deletions src/json-expression/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './types';
export * from './evaluate';
export * from './codegen';
export * from './Vars';
31 changes: 31 additions & 0 deletions src/json-expression/operators/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {Expression, ExpressionResult, Literal} from '../codegen-steps';
import {$$deepEqual} from '../../json-equal/$$deepEqual';
import type * as types from '../types';
import {Vars} from '../Vars';
import {clone} from '../../json-clone';

const createSubExpressionOperator = <N extends string>(
name: N,
Expand Down Expand Up @@ -51,6 +52,36 @@ export const arrayOperators: types.OperatorDefinition<any>[] = [
},
] as types.OperatorDefinition<types.ExprConcat>,

[
'push',
[],
-1,
(expr: types.ExprPush, ctx) => {
const operand1 = ctx.eval(expr[1], ctx);
const arr = clone(util.asArr(operand1));
for (let i = 2; i < expr.length; i++)
arr.push(ctx.eval(expr[i], ctx));
return arr;
},
(ctx: types.OperatorCodegenCtx<types.ExprPush>): ExpressionResult => {
const arrOperand = ctx.operands[0];
let arr: Literal | Expression;
if (arrOperand instanceof Literal) {
arr = new Literal(clone(util.asArr(arrOperand.val)));
} else {
ctx.link(util.asArr, 'asArr');
arr = new Expression(`asArr(${arrOperand})`);
}
const rArr = ctx.var('' + arr);
const pushes: string[] = [];
for (let i = 1; i < ctx.operands.length; i++) {
const operand = ctx.operands[i];
pushes.push(`(${rArr}.push(${operand}))`);
}
return new Expression(`(${pushes.join(',')},${rArr})`);
},
] as types.OperatorDefinition<types.ExprPush>,

[
'head',
[],
Expand Down
3 changes: 3 additions & 0 deletions src/json-expression/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ export type ExprF64 = BinaryExpression<'f64'>;
// Array expressions
export type ArrayExpression =
| ExprConcat
| ExprPush
| ExprHead
| ExprSort
| ExprReverse
Expand All @@ -213,6 +214,7 @@ export type ArrayExpression =
| ExprReduce;

export type ExprConcat = VariadicExpression<'concat' | '++'>;
export type ExprPush = VariadicExpression<'push'>;
export type ExprHead = BinaryExpression<'head'>;
export type ExprSort = UnaryExpression<'sort'>;
export type ExprReverse = UnaryExpression<'reverse'>;
Expand Down Expand Up @@ -320,6 +322,7 @@ export interface OperatorCodegenCtx<E extends Expression> extends JsonExpression
link: (value: unknown, name?: string) => string;
const: (js: JavaScript<unknown>) => string;
subExpression: (expr: Expression) => (ctx: JsonExpressionExecutionContext) => unknown;
var: (name: string) => string;
}

export type OperatorMap = Map<string | number, OperatorDefinition<Expression>>;

0 comments on commit edbd128

Please sign in to comment.