Skip to content

Commit

Permalink
feat(INT-701): add support for return and throw
Browse files Browse the repository at this point in the history
  • Loading branch information
koladilip committed Sep 23, 2023
1 parent 341b3e7 commit f021cb1
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 40 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"format": "prettier --write '**/*.ts' '**/*.js' '**/*.json'",
"prepare": "husky install",
"jest:scenarios": "jest e2e.test.ts --verbose",
"test:scenario": "ts-node test/test_scenario.ts",
"test:scenario": "jest test/scenario.test.ts --verbose",
"test:stryker": "stryker run"
},
"lint-staged": {
Expand Down
22 changes: 22 additions & 0 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import {
Keyword,
EngineOptions,
PathType,
ReturnExpression,
ThrowExpression,
} from './types';
import { JsonTemplateParserError } from './errors';
import { DATA_PARAM_KEY } from './constants';
Expand Down Expand Up @@ -997,6 +999,22 @@ export class JsonTemplateParser {
};
}

private parseReturnExpr(): ReturnExpression {
this.lexer.ignoreTokens(1);
return {
type: SyntaxType.RETURN_EXPR,
value: this.parseBaseExpr(),
};
}

private parseThrowExpr(): ThrowExpression {
this.lexer.ignoreTokens(1);
return {
type: SyntaxType.THROW_EXPR,
value: this.parseBaseExpr(),
};
}

private parseKeywordBasedExpr(): Expression {
const token = this.lexer.lookahead();
switch (token.value) {
Expand All @@ -1006,6 +1024,10 @@ export class JsonTemplateParser {
return this.parseLambdaExpr();
case Keyword.ASYNC:
return this.parseAsyncFunctionExpr();
case Keyword.RETURN:
return this.parseReturnExpr();
case Keyword.THROW:
return this.parseThrowExpr();
case Keyword.FUNCTION:
return this.parseFunctionExpr();
default:
Expand Down
26 changes: 25 additions & 1 deletion src/translator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import {
BlockExpression,
PathOptions,
PathType,
ReturnExpression,
ThrowExpression,
} from './types';
import { CommonUtils } from './utils';

Expand Down Expand Up @@ -82,7 +84,6 @@ export class JsonTemplateTranslator {
this.init();
let code: string[] = [];
const exprCode = this.translateExpr(this.expr, dest, ctx);

code.push(`let ${dest};`);
code.push(this.vars.map((elm) => `let ${elm};`).join(''));
code.push(exprCode);
Expand Down Expand Up @@ -159,11 +160,34 @@ export class JsonTemplateTranslator {
case SyntaxType.CONDITIONAL_EXPR:
return this.translateConditionalExpr(expr as ConditionalExpression, dest, ctx);

case SyntaxType.RETURN_EXPR:
return this.translateReturnExpr(expr as ReturnExpression, dest, ctx);

case SyntaxType.THROW_EXPR:
return this.translateThrowExpr(expr as ThrowExpression, dest, ctx);
default:
return '';
}
}

private translateThrowExpr(expr: ThrowExpression, _dest: string, ctx: string): string {
const code: string[] = [];
const value = this.acquireVar();
code.push(this.translateExpr(expr.value, value, ctx));
code.push(`throw ${value};`);
this.releaseVars(value);
return code.join('');
}

private translateReturnExpr(expr: ReturnExpression, _dest: string, ctx: string): string {
const code: string[] = [];
const value = this.acquireVar();
code.push(this.translateExpr(expr.value, value, ctx));
code.push(`return ${value};`);
this.releaseVars(value);
return code.join('');
}

private translateConditionalExpr(expr: ConditionalExpression, dest: string, ctx: string): string {
const code: string[] = [];
const ifVar = this.acquireVar();
Expand Down
12 changes: 12 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export enum Keyword {
ASYNC = 'async',
IN = 'in',
NOT = 'not',
RETURN = 'return',
THROW = 'throw',
}

export enum TokenType {
Expand Down Expand Up @@ -74,6 +76,8 @@ export enum SyntaxType {
FUNCTION_EXPR,
FUNCTION_CALL_ARG,
FUNCTION_CALL_EXPR,
RETURN_EXPR,
THROW_EXPR,
STATEMENTS_EXPR,
}

Expand Down Expand Up @@ -211,3 +215,11 @@ export interface ConditionalExpression extends Expression {
then: Expression;
else: Expression;
}

export interface ReturnExpression extends Expression {
value: Expression;
}

export interface ThrowExpression extends Expression {
value: Expression;
}
42 changes: 42 additions & 0 deletions test/scenario.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { join } from 'path';
import { Command } from 'commander';
import { Scenario } from './types';
import { ScenarioUtils } from './utils';

// Run: npm run test:scenario -- --scenario=arrays --index=1
const command = new Command();
command
.allowUnknownOption()
.option('-s, --scenario <string>', 'Enter Scenario Name')
.option('-i, --index <number>', 'Enter Test case index')
.parse();

const opts = command.opts();
const scenarioName = opts.scenario || 'none';
const index = +(opts.index || 0);

describe(`${scenarioName}:`, () => {
it(`Scenario ${index}`, async () => {
if (scenarioName === 'none') {
return;
}
const scenarioDir = join(__dirname, 'scenarios', scenarioName);
const scenarios = ScenarioUtils.extractScenarios(scenarioDir);
const scenario: Scenario = scenarios[index] || scenarios[0];
let result;
try {
console.log(
`Executing scenario: ${scenarioName}, test: ${index}, template: ${
scenario.templatePath || 'template.jt'
}`,
);
const templateEngine = ScenarioUtils.createTemplateEngine(scenarioDir, scenario);
result = await ScenarioUtils.evaluateScenario(templateEngine, scenario);
expect(result).toEqual(scenario.output);
} catch (error: any) {
console.log('Actual result', JSON.stringify(result, null, 2));
console.log('Expected result', JSON.stringify(scenario.output, null, 2));
expect(error.message).toEqual(scenario.error);
}
});
});
12 changes: 12 additions & 0 deletions test/scenarios/return/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Scenario } from '../../types';

export const data: Scenario[] = [
{
input: 3,
output: 1,
},
{
input: 2,
output: 1,
},
];
2 changes: 2 additions & 0 deletions test/scenarios/return/template.jt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(. % 2 === 0) ? return ./2;
(. - 1)/2;
12 changes: 12 additions & 0 deletions test/scenarios/throw/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Scenario } from '../../types';

export const data: Scenario[] = [
{
input: 3,
error: 'num must be even',
},
{
input: 2,
output: 1,
},
];
1 change: 1 addition & 0 deletions test/scenarios/throw/template.jt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(. % 2 !== 0) ? throw new Error("num must be even") : ./2;
38 changes: 0 additions & 38 deletions test/test_scenario.ts

This file was deleted.

0 comments on commit f021cb1

Please sign in to comment.