2016-06-23 09:47:54 -07:00
|
|
|
/**
|
|
|
|
* @license
|
2020-05-19 12:08:49 -07:00
|
|
|
* Copyright Google LLC All Rights Reserved.
|
2016-06-23 09:47:54 -07:00
|
|
|
*
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
*/
|
2017-08-16 09:00:03 -07:00
|
|
|
import {CompileReflector} from '../compile_reflector';
|
2016-06-08 16:38:52 -07:00
|
|
|
import * as o from './output_ast';
|
2016-01-06 14:13:44 -08:00
|
|
|
import {debugOutputAstAsTypeScript} from './ts_emitter';
|
|
|
|
|
2017-08-16 09:00:03 -07:00
|
|
|
export function interpretStatements(
|
|
|
|
statements: o.Statement[], reflector: CompileReflector): {[key: string]: any} {
|
2016-11-12 14:08:58 +01:00
|
|
|
const ctx = new _ExecutionContext(null, null, null, new Map<string, any>());
|
2017-08-16 09:00:03 -07:00
|
|
|
const visitor = new StatementInterpreter(reflector);
|
2017-05-16 16:30:37 -07:00
|
|
|
visitor.visitAllStatements(statements, ctx);
|
|
|
|
const result: {[key: string]: any} = {};
|
2020-04-08 10:14:18 -07:00
|
|
|
ctx.exports.forEach((exportName) => {
|
|
|
|
result[exportName] = ctx.vars.get(exportName);
|
|
|
|
});
|
2017-05-16 16:30:37 -07:00
|
|
|
return result;
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
|
|
|
|
2016-06-08 16:38:52 -07:00
|
|
|
function _executeFunctionStatements(
|
|
|
|
varNames: string[], varValues: any[], statements: o.Statement[], ctx: _ExecutionContext,
|
|
|
|
visitor: StatementInterpreter): any {
|
2016-11-12 14:08:58 +01:00
|
|
|
const childCtx = ctx.createChildWihtLocalVars();
|
|
|
|
for (let i = 0; i < varNames.length; i++) {
|
2016-01-06 14:13:44 -08:00
|
|
|
childCtx.vars.set(varNames[i], varValues[i]);
|
|
|
|
}
|
2016-11-12 14:08:58 +01:00
|
|
|
const result = visitor.visitAllStatements(statements, childCtx);
|
2017-01-27 14:23:12 -08:00
|
|
|
return result ? result.value : null;
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
class _ExecutionContext {
|
2017-05-16 16:30:37 -07:00
|
|
|
exports: string[] = [];
|
|
|
|
|
2016-06-08 16:38:52 -07:00
|
|
|
constructor(
|
2019-06-14 09:28:04 +02:00
|
|
|
public parent: _ExecutionContext|null, public instance: Object|null,
|
|
|
|
public className: string|null, public vars: Map<string, any>) {}
|
2016-01-06 14:13:44 -08:00
|
|
|
|
|
|
|
createChildWihtLocalVars(): _ExecutionContext {
|
2016-06-28 09:54:42 -07:00
|
|
|
return new _ExecutionContext(this, this.instance, this.className, new Map<string, any>());
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class ReturnValue {
|
|
|
|
constructor(public value: any) {}
|
|
|
|
}
|
|
|
|
|
2016-06-28 09:54:42 -07:00
|
|
|
function createDynamicClass(
|
|
|
|
_classStmt: o.ClassStmt, _ctx: _ExecutionContext, _visitor: StatementInterpreter): Function {
|
2016-11-12 14:08:58 +01:00
|
|
|
const propertyDescriptors: {[key: string]: any} = {};
|
2016-01-06 14:13:44 -08:00
|
|
|
|
2016-06-28 09:54:42 -07:00
|
|
|
_classStmt.getters.forEach((getter: o.ClassGetter) => {
|
|
|
|
// Note: use `function` instead of arrow function to capture `this`
|
|
|
|
propertyDescriptors[getter.name] = {
|
|
|
|
configurable: false,
|
|
|
|
get: function() {
|
2016-11-12 14:08:58 +01:00
|
|
|
const instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars);
|
2016-06-28 09:54:42 -07:00
|
|
|
return _executeFunctionStatements([], [], getter.body, instanceCtx, _visitor);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
});
|
|
|
|
_classStmt.methods.forEach(function(method: o.ClassMethod) {
|
2016-07-13 11:01:32 -07:00
|
|
|
const paramNames = method.params.map(param => param.name);
|
2016-06-28 09:54:42 -07:00
|
|
|
// Note: use `function` instead of arrow function to capture `this`
|
2020-04-08 10:14:18 -07:00
|
|
|
propertyDescriptors[method.name!] = {
|
2016-06-28 09:54:42 -07:00
|
|
|
writable: false,
|
|
|
|
configurable: false,
|
|
|
|
value: function(...args: any[]) {
|
2016-11-12 14:08:58 +01:00
|
|
|
const instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars);
|
2016-06-28 09:54:42 -07:00
|
|
|
return _executeFunctionStatements(paramNames, args, method.body, instanceCtx, _visitor);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
});
|
2016-01-06 14:13:44 -08:00
|
|
|
|
2016-11-12 14:08:58 +01:00
|
|
|
const ctorParamNames = _classStmt.constructorMethod.params.map(param => param.name);
|
2016-06-28 09:54:42 -07:00
|
|
|
// Note: use `function` instead of arrow function to capture `this`
|
2019-06-14 09:28:04 +02:00
|
|
|
const ctor = function(this: Object, ...args: any[]) {
|
2016-11-12 14:08:58 +01:00
|
|
|
const instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars);
|
2020-04-08 10:14:18 -07:00
|
|
|
_classStmt.fields.forEach((field) => {
|
|
|
|
(this as any)[field.name] = undefined;
|
|
|
|
});
|
2016-06-08 16:38:52 -07:00
|
|
|
_executeFunctionStatements(
|
2016-06-28 09:54:42 -07:00
|
|
|
ctorParamNames, args, _classStmt.constructorMethod.body, instanceCtx, _visitor);
|
|
|
|
};
|
2016-11-12 14:08:58 +01:00
|
|
|
const superClass = _classStmt.parent ? _classStmt.parent.visitExpression(_visitor, _ctx) : Object;
|
2016-06-28 09:54:42 -07:00
|
|
|
ctor.prototype = Object.create(superClass.prototype, propertyDescriptors);
|
|
|
|
return ctor;
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
2017-08-16 09:00:03 -07:00
|
|
|
constructor(private reflector: CompileReflector) {}
|
2020-04-08 10:14:18 -07:00
|
|
|
debugAst(ast: o.Expression|o.Statement|o.Type): string {
|
|
|
|
return debugOutputAstAsTypeScript(ast);
|
|
|
|
}
|
2016-01-06 14:13:44 -08:00
|
|
|
|
|
|
|
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: _ExecutionContext): any {
|
2018-02-13 10:48:22 -08:00
|
|
|
const initialValue = stmt.value ? stmt.value.visitExpression(this, ctx) : undefined;
|
|
|
|
ctx.vars.set(stmt.name, initialValue);
|
2017-05-16 16:30:37 -07:00
|
|
|
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
|
|
|
ctx.exports.push(stmt.name);
|
|
|
|
}
|
2016-01-06 14:13:44 -08:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
visitWriteVarExpr(expr: o.WriteVarExpr, ctx: _ExecutionContext): any {
|
2016-11-12 14:08:58 +01:00
|
|
|
const value = expr.value.visitExpression(this, ctx);
|
|
|
|
let currCtx = ctx;
|
2016-01-06 14:13:44 -08:00
|
|
|
while (currCtx != null) {
|
|
|
|
if (currCtx.vars.has(expr.name)) {
|
|
|
|
currCtx.vars.set(expr.name, value);
|
|
|
|
return value;
|
|
|
|
}
|
2020-04-08 10:14:18 -07:00
|
|
|
currCtx = currCtx.parent!;
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
2016-08-25 00:50:16 -07:00
|
|
|
throw new Error(`Not declared variable ${expr.name}`);
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
2018-04-06 09:53:10 -07:00
|
|
|
visitWrappedNodeExpr(ast: o.WrappedNodeExpr<any>, ctx: _ExecutionContext): never {
|
|
|
|
throw new Error('Cannot interpret a WrappedNodeExpr.');
|
|
|
|
}
|
fix(ivy): use 'typeof' and 'never' for type metadata (#24862)
Previously ngtsc would use a tuple of class types for listing metadata
in .d.ts files. For example, an @NgModule's declarations might be
represented with the type:
[NgIf, NgForOf, NgClass]
If the module had no declarations, an empty tuple [] would be produced.
This has two problems.
1. If the class type has generic type parameters, TypeScript will
complain that they're not provided.
2. The empty tuple type is not actually legal.
This commit addresses both problems.
1. Class types are now represented using the `typeof` operator, so the
above declarations would be represented as:
[typeof NgIf, typeof NgForOf, typeof NgClass].
Since typeof operates on a value, it doesn't require generic type
arguments.
2. Instead of an empty tuple, `never` is used to indicate no metadata.
PR Close #24862
2018-07-17 13:34:20 -07:00
|
|
|
visitTypeofExpr(ast: o.TypeofExpr, ctx: _ExecutionContext): never {
|
|
|
|
throw new Error('Cannot interpret a TypeofExpr');
|
|
|
|
}
|
2016-01-06 14:13:44 -08:00
|
|
|
visitReadVarExpr(ast: o.ReadVarExpr, ctx: _ExecutionContext): any {
|
2020-04-08 10:14:18 -07:00
|
|
|
let varName = ast.name!;
|
2017-03-02 09:37:01 -08:00
|
|
|
if (ast.builtin != null) {
|
2016-01-06 14:13:44 -08:00
|
|
|
switch (ast.builtin) {
|
|
|
|
case o.BuiltinVar.Super:
|
2019-06-14 09:28:04 +02:00
|
|
|
return Object.getPrototypeOf(ctx.instance);
|
2016-01-06 14:13:44 -08:00
|
|
|
case o.BuiltinVar.This:
|
2016-06-28 09:54:42 -07:00
|
|
|
return ctx.instance;
|
2016-01-06 14:13:44 -08:00
|
|
|
case o.BuiltinVar.CatchError:
|
|
|
|
varName = CATCH_ERROR_VAR;
|
|
|
|
break;
|
|
|
|
case o.BuiltinVar.CatchStack:
|
|
|
|
varName = CATCH_STACK_VAR;
|
|
|
|
break;
|
|
|
|
default:
|
2016-08-25 00:50:16 -07:00
|
|
|
throw new Error(`Unknown builtin variable ${ast.builtin}`);
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
|
|
|
}
|
2016-11-12 14:08:58 +01:00
|
|
|
let currCtx = ctx;
|
2016-01-06 14:13:44 -08:00
|
|
|
while (currCtx != null) {
|
|
|
|
if (currCtx.vars.has(varName)) {
|
|
|
|
return currCtx.vars.get(varName);
|
|
|
|
}
|
2020-04-08 10:14:18 -07:00
|
|
|
currCtx = currCtx.parent!;
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
2016-08-25 00:50:16 -07:00
|
|
|
throw new Error(`Not declared variable ${varName}`);
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
|
|
|
visitWriteKeyExpr(expr: o.WriteKeyExpr, ctx: _ExecutionContext): any {
|
2016-11-12 14:08:58 +01:00
|
|
|
const receiver = expr.receiver.visitExpression(this, ctx);
|
|
|
|
const index = expr.index.visitExpression(this, ctx);
|
|
|
|
const value = expr.value.visitExpression(this, ctx);
|
2016-01-06 14:13:44 -08:00
|
|
|
receiver[index] = value;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
visitWritePropExpr(expr: o.WritePropExpr, ctx: _ExecutionContext): any {
|
2016-11-12 14:08:58 +01:00
|
|
|
const receiver = expr.receiver.visitExpression(this, ctx);
|
|
|
|
const value = expr.value.visitExpression(this, ctx);
|
2016-06-28 09:54:42 -07:00
|
|
|
receiver[expr.name] = value;
|
2016-01-06 14:13:44 -08:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
visitInvokeMethodExpr(expr: o.InvokeMethodExpr, ctx: _ExecutionContext): any {
|
2016-11-12 14:08:58 +01:00
|
|
|
const receiver = expr.receiver.visitExpression(this, ctx);
|
|
|
|
const args = this.visitAllExpressions(expr.args, ctx);
|
|
|
|
let result: any;
|
2017-03-02 09:37:01 -08:00
|
|
|
if (expr.builtin != null) {
|
2016-01-06 14:13:44 -08:00
|
|
|
switch (expr.builtin) {
|
|
|
|
case o.BuiltinMethod.ConcatArray:
|
2016-10-26 16:58:35 -07:00
|
|
|
result = receiver.concat(...args);
|
2016-01-06 14:13:44 -08:00
|
|
|
break;
|
|
|
|
case o.BuiltinMethod.SubscribeObservable:
|
2016-08-02 15:53:34 -07:00
|
|
|
result = receiver.subscribe({next: args[0]});
|
2016-01-06 14:13:44 -08:00
|
|
|
break;
|
2016-08-14 07:04:37 -10:00
|
|
|
case o.BuiltinMethod.Bind:
|
2016-10-26 16:58:35 -07:00
|
|
|
result = receiver.bind(...args);
|
2016-04-22 15:33:32 -07:00
|
|
|
break;
|
2016-01-06 14:13:44 -08:00
|
|
|
default:
|
2016-08-25 00:50:16 -07:00
|
|
|
throw new Error(`Unknown builtin method ${expr.builtin}`);
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
|
|
|
} else {
|
2020-04-08 10:14:18 -07:00
|
|
|
result = receiver[expr.name!].apply(receiver, args);
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
visitInvokeFunctionExpr(stmt: o.InvokeFunctionExpr, ctx: _ExecutionContext): any {
|
2016-11-12 14:08:58 +01:00
|
|
|
const args = this.visitAllExpressions(stmt.args, ctx);
|
|
|
|
const fnExpr = stmt.fn;
|
2016-01-06 14:13:44 -08:00
|
|
|
if (fnExpr instanceof o.ReadVarExpr && fnExpr.builtin === o.BuiltinVar.Super) {
|
2020-04-08 10:14:18 -07:00
|
|
|
ctx.instance!.constructor.prototype.constructor.apply(ctx.instance, args);
|
2016-01-06 14:13:44 -08:00
|
|
|
return null;
|
|
|
|
} else {
|
2016-11-12 14:08:58 +01:00
|
|
|
const fn = stmt.fn.visitExpression(this, ctx);
|
2016-06-28 09:54:42 -07:00
|
|
|
return fn.apply(null, args);
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
|
|
|
}
|
2020-09-27 01:45:38 +00:00
|
|
|
visitTaggedTemplateExpr(expr: o.TaggedTemplateExpr, ctx: _ExecutionContext): any {
|
|
|
|
const templateElements = expr.template.elements.map((e) => e.text);
|
|
|
|
Object.defineProperty(
|
|
|
|
templateElements, 'raw', {value: expr.template.elements.map((e) => e.rawText)});
|
|
|
|
const args = this.visitAllExpressions(expr.template.expressions, ctx);
|
|
|
|
args.unshift(templateElements);
|
|
|
|
const tag = expr.tag.visitExpression(this, ctx);
|
|
|
|
return tag.apply(null, args);
|
|
|
|
}
|
2016-01-06 14:13:44 -08:00
|
|
|
visitReturnStmt(stmt: o.ReturnStatement, ctx: _ExecutionContext): any {
|
|
|
|
return new ReturnValue(stmt.value.visitExpression(this, ctx));
|
|
|
|
}
|
|
|
|
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: _ExecutionContext): any {
|
2016-11-12 14:08:58 +01:00
|
|
|
const clazz = createDynamicClass(stmt, ctx, this);
|
2016-01-06 14:13:44 -08:00
|
|
|
ctx.vars.set(stmt.name, clazz);
|
2017-05-16 16:30:37 -07:00
|
|
|
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
|
|
|
ctx.exports.push(stmt.name);
|
|
|
|
}
|
2016-01-06 14:13:44 -08:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
visitExpressionStmt(stmt: o.ExpressionStatement, ctx: _ExecutionContext): any {
|
|
|
|
return stmt.expr.visitExpression(this, ctx);
|
|
|
|
}
|
|
|
|
visitIfStmt(stmt: o.IfStmt, ctx: _ExecutionContext): any {
|
2016-11-12 14:08:58 +01:00
|
|
|
const condition = stmt.condition.visitExpression(this, ctx);
|
2016-01-06 14:13:44 -08:00
|
|
|
if (condition) {
|
|
|
|
return this.visitAllStatements(stmt.trueCase, ctx);
|
2017-03-02 09:37:01 -08:00
|
|
|
} else if (stmt.falseCase != null) {
|
2016-01-06 14:13:44 -08:00
|
|
|
return this.visitAllStatements(stmt.falseCase, ctx);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
visitTryCatchStmt(stmt: o.TryCatchStmt, ctx: _ExecutionContext): any {
|
|
|
|
try {
|
|
|
|
return this.visitAllStatements(stmt.bodyStmts, ctx);
|
|
|
|
} catch (e) {
|
2016-11-12 14:08:58 +01:00
|
|
|
const childCtx = ctx.createChildWihtLocalVars();
|
2016-01-06 14:13:44 -08:00
|
|
|
childCtx.vars.set(CATCH_ERROR_VAR, e);
|
|
|
|
childCtx.vars.set(CATCH_STACK_VAR, e.stack);
|
|
|
|
return this.visitAllStatements(stmt.catchStmts, childCtx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
visitThrowStmt(stmt: o.ThrowStmt, ctx: _ExecutionContext): any {
|
|
|
|
throw stmt.error.visitExpression(this, ctx);
|
|
|
|
}
|
|
|
|
visitInstantiateExpr(ast: o.InstantiateExpr, ctx: _ExecutionContext): any {
|
2016-11-12 14:08:58 +01:00
|
|
|
const args = this.visitAllExpressions(ast.args, ctx);
|
|
|
|
const clazz = ast.classExpr.visitExpression(this, ctx);
|
2016-06-28 09:54:42 -07:00
|
|
|
return new clazz(...args);
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
2020-04-08 10:14:18 -07:00
|
|
|
visitLiteralExpr(ast: o.LiteralExpr, ctx: _ExecutionContext): any {
|
|
|
|
return ast.value;
|
|
|
|
}
|
|
|
|
visitLocalizedString(ast: o.LocalizedString, context: any): any {
|
|
|
|
return null;
|
|
|
|
}
|
2017-08-16 09:00:03 -07:00
|
|
|
visitExternalExpr(ast: o.ExternalExpr, ctx: _ExecutionContext): any {
|
|
|
|
return this.reflector.resolveExternalReference(ast.value);
|
|
|
|
}
|
2016-01-06 14:13:44 -08:00
|
|
|
visitConditionalExpr(ast: o.ConditionalExpr, ctx: _ExecutionContext): any {
|
|
|
|
if (ast.condition.visitExpression(this, ctx)) {
|
|
|
|
return ast.trueCase.visitExpression(this, ctx);
|
2017-03-02 09:37:01 -08:00
|
|
|
} else if (ast.falseCase != null) {
|
2016-01-06 14:13:44 -08:00
|
|
|
return ast.falseCase.visitExpression(this, ctx);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
visitNotExpr(ast: o.NotExpr, ctx: _ExecutionContext): any {
|
|
|
|
return !ast.condition.visitExpression(this, ctx);
|
|
|
|
}
|
2017-05-11 10:15:54 -07:00
|
|
|
visitAssertNotNullExpr(ast: o.AssertNotNull, ctx: _ExecutionContext): any {
|
|
|
|
return ast.condition.visitExpression(this, ctx);
|
|
|
|
}
|
2016-01-06 14:13:44 -08:00
|
|
|
visitCastExpr(ast: o.CastExpr, ctx: _ExecutionContext): any {
|
|
|
|
return ast.value.visitExpression(this, ctx);
|
|
|
|
}
|
|
|
|
visitFunctionExpr(ast: o.FunctionExpr, ctx: _ExecutionContext): any {
|
2016-11-12 14:08:58 +01:00
|
|
|
const paramNames = ast.params.map((param) => param.name);
|
2016-01-06 14:13:44 -08:00
|
|
|
return _declareFn(paramNames, ast.statements, ctx, this);
|
|
|
|
}
|
|
|
|
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: _ExecutionContext): any {
|
2016-11-12 14:08:58 +01:00
|
|
|
const paramNames = stmt.params.map((param) => param.name);
|
2016-01-06 14:13:44 -08:00
|
|
|
ctx.vars.set(stmt.name, _declareFn(paramNames, stmt.statements, ctx, this));
|
2017-05-16 16:30:37 -07:00
|
|
|
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
|
|
|
ctx.exports.push(stmt.name);
|
|
|
|
}
|
2016-01-06 14:13:44 -08:00
|
|
|
return null;
|
|
|
|
}
|
2020-07-04 01:52:40 +02:00
|
|
|
visitUnaryOperatorExpr(ast: o.UnaryOperatorExpr, ctx: _ExecutionContext): any {
|
|
|
|
const rhs = () => ast.expr.visitExpression(this, ctx);
|
|
|
|
|
|
|
|
switch (ast.operator) {
|
|
|
|
case o.UnaryOperator.Plus:
|
|
|
|
return +rhs();
|
|
|
|
case o.UnaryOperator.Minus:
|
|
|
|
return -rhs();
|
|
|
|
default:
|
|
|
|
throw new Error(`Unknown operator ${ast.operator}`);
|
|
|
|
}
|
|
|
|
}
|
2016-01-06 14:13:44 -08:00
|
|
|
visitBinaryOperatorExpr(ast: o.BinaryOperatorExpr, ctx: _ExecutionContext): any {
|
2016-11-12 14:08:58 +01:00
|
|
|
const lhs = () => ast.lhs.visitExpression(this, ctx);
|
|
|
|
const rhs = () => ast.rhs.visitExpression(this, ctx);
|
2016-01-06 14:13:44 -08:00
|
|
|
|
|
|
|
switch (ast.operator) {
|
|
|
|
case o.BinaryOperator.Equals:
|
|
|
|
return lhs() == rhs();
|
|
|
|
case o.BinaryOperator.Identical:
|
|
|
|
return lhs() === rhs();
|
|
|
|
case o.BinaryOperator.NotEquals:
|
|
|
|
return lhs() != rhs();
|
|
|
|
case o.BinaryOperator.NotIdentical:
|
|
|
|
return lhs() !== rhs();
|
|
|
|
case o.BinaryOperator.And:
|
|
|
|
return lhs() && rhs();
|
|
|
|
case o.BinaryOperator.Or:
|
|
|
|
return lhs() || rhs();
|
|
|
|
case o.BinaryOperator.Plus:
|
|
|
|
return lhs() + rhs();
|
|
|
|
case o.BinaryOperator.Minus:
|
|
|
|
return lhs() - rhs();
|
|
|
|
case o.BinaryOperator.Divide:
|
|
|
|
return lhs() / rhs();
|
|
|
|
case o.BinaryOperator.Multiply:
|
|
|
|
return lhs() * rhs();
|
|
|
|
case o.BinaryOperator.Modulo:
|
|
|
|
return lhs() % rhs();
|
|
|
|
case o.BinaryOperator.Lower:
|
|
|
|
return lhs() < rhs();
|
|
|
|
case o.BinaryOperator.LowerEquals:
|
|
|
|
return lhs() <= rhs();
|
|
|
|
case o.BinaryOperator.Bigger:
|
|
|
|
return lhs() > rhs();
|
|
|
|
case o.BinaryOperator.BiggerEquals:
|
|
|
|
return lhs() >= rhs();
|
2021-04-03 18:10:31 +02:00
|
|
|
case o.BinaryOperator.NullishCoalesce:
|
|
|
|
return lhs() ?? rhs();
|
2016-01-06 14:13:44 -08:00
|
|
|
default:
|
2016-08-25 00:50:16 -07:00
|
|
|
throw new Error(`Unknown operator ${ast.operator}`);
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
visitReadPropExpr(ast: o.ReadPropExpr, ctx: _ExecutionContext): any {
|
2016-11-12 14:08:58 +01:00
|
|
|
let result: any;
|
|
|
|
const receiver = ast.receiver.visitExpression(this, ctx);
|
2016-06-28 09:54:42 -07:00
|
|
|
result = receiver[ast.name];
|
2016-01-06 14:13:44 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
visitReadKeyExpr(ast: o.ReadKeyExpr, ctx: _ExecutionContext): any {
|
2016-11-12 14:08:58 +01:00
|
|
|
const receiver = ast.receiver.visitExpression(this, ctx);
|
|
|
|
const prop = ast.index.visitExpression(this, ctx);
|
2016-01-06 14:13:44 -08:00
|
|
|
return receiver[prop];
|
|
|
|
}
|
|
|
|
visitLiteralArrayExpr(ast: o.LiteralArrayExpr, ctx: _ExecutionContext): any {
|
|
|
|
return this.visitAllExpressions(ast.entries, ctx);
|
|
|
|
}
|
|
|
|
visitLiteralMapExpr(ast: o.LiteralMapExpr, ctx: _ExecutionContext): any {
|
2017-07-05 14:51:39 -07:00
|
|
|
const result: {[k: string]: any} = {};
|
|
|
|
ast.entries.forEach(entry => result[entry.key] = entry.value.visitExpression(this, ctx));
|
2016-01-06 14:13:44 -08:00
|
|
|
return result;
|
|
|
|
}
|
2017-03-14 09:16:15 -07:00
|
|
|
visitCommaExpr(ast: o.CommaExpr, context: any): any {
|
|
|
|
const values = this.visitAllExpressions(ast.parts, context);
|
|
|
|
return values[values.length - 1];
|
|
|
|
}
|
2016-01-06 14:13:44 -08:00
|
|
|
visitAllExpressions(expressions: o.Expression[], ctx: _ExecutionContext): any {
|
|
|
|
return expressions.map((expr) => expr.visitExpression(this, ctx));
|
|
|
|
}
|
|
|
|
|
2017-03-24 09:59:58 -07:00
|
|
|
visitAllStatements(statements: o.Statement[], ctx: _ExecutionContext): ReturnValue|null {
|
2016-11-12 14:08:58 +01:00
|
|
|
for (let i = 0; i < statements.length; i++) {
|
|
|
|
const stmt = statements[i];
|
|
|
|
const val = stmt.visitStatement(this, ctx);
|
2016-01-06 14:13:44 -08:00
|
|
|
if (val instanceof ReturnValue) {
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-08 16:38:52 -07:00
|
|
|
function _declareFn(
|
|
|
|
varNames: string[], statements: o.Statement[], ctx: _ExecutionContext,
|
|
|
|
visitor: StatementInterpreter): Function {
|
2016-06-28 09:54:42 -07:00
|
|
|
return (...args: any[]) => _executeFunctionStatements(varNames, args, statements, ctx, visitor);
|
2016-01-06 14:13:44 -08:00
|
|
|
}
|
|
|
|
|
2016-11-12 14:08:58 +01:00
|
|
|
const CATCH_ERROR_VAR = 'error';
|
|
|
|
const CATCH_STACK_VAR = 'stack';
|