import {isString, isPresent, isBlank} from '../../src/facade/lang'; import {CompileIdentifierMetadata} from '../compile_metadata'; //// Types export enum TypeModifier { Const } export abstract class Type { constructor(public modifiers: TypeModifier[] = null) { if (isBlank(modifiers)) { this.modifiers = []; } } abstract visitType(visitor: TypeVisitor, context: any): any; hasModifier(modifier: TypeModifier): boolean { return this.modifiers.indexOf(modifier) !== -1; } } export enum BuiltinTypeName { Dynamic, Bool, String, Int, Number, Function } export class BuiltinType extends Type { constructor(public name: BuiltinTypeName, modifiers: TypeModifier[] = null) { super(modifiers); } visitType(visitor: TypeVisitor, context: any): any { return visitor.visitBuiltintType(this, context); } } export class ExternalType extends Type { constructor(public value: CompileIdentifierMetadata, public typeParams: Type[] = null, modifiers: TypeModifier[] = null) { super(modifiers); } visitType(visitor: TypeVisitor, context: any): any { return visitor.visitExternalType(this, context); } } export class ArrayType extends Type { constructor(public of: Type, modifiers: TypeModifier[] = null) { super(modifiers); } visitType(visitor: TypeVisitor, context: any): any { return visitor.visitArrayType(this, context); } } export class MapType extends Type { constructor(public valueType: Type, modifiers: TypeModifier[] = null) { super(modifiers); } visitType(visitor: TypeVisitor, context: any): any { return visitor.visitMapType(this, context); } } export var DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic); export var BOOL_TYPE = new BuiltinType(BuiltinTypeName.Bool); export var INT_TYPE = new BuiltinType(BuiltinTypeName.Int); export var NUMBER_TYPE = new BuiltinType(BuiltinTypeName.Number); export var STRING_TYPE = new BuiltinType(BuiltinTypeName.String); export var FUNCTION_TYPE = new BuiltinType(BuiltinTypeName.Function); export interface TypeVisitor { visitBuiltintType(type: BuiltinType, context: any): any; visitExternalType(type: ExternalType, context: any): any; visitArrayType(type: ArrayType, context: any): any; visitMapType(type: MapType, context: any): any; } ///// Expressions export enum BinaryOperator { Equals, NotEquals, Identical, NotIdentical, Minus, Plus, Divide, Multiply, Modulo, And, Or, Lower, LowerEquals, Bigger, BiggerEquals } export abstract class Expression { constructor(public type: Type) {} abstract visitExpression(visitor: ExpressionVisitor, context: any): any; prop(name: string): ReadPropExpr { return new ReadPropExpr(this, name); } key(index: Expression, type: Type = null): ReadKeyExpr { return new ReadKeyExpr(this, index, type); } callMethod(name: string | BuiltinMethod, params: Expression[]): InvokeMethodExpr { return new InvokeMethodExpr(this, name, params); } callFn(params: Expression[]): InvokeFunctionExpr { return new InvokeFunctionExpr(this, params); } instantiate(params: Expression[], type: Type = null): InstantiateExpr { return new InstantiateExpr(this, params, type); } conditional(trueCase: Expression, falseCase: Expression = null): ConditionalExpr { return new ConditionalExpr(this, trueCase, falseCase); } equals(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.Equals, this, rhs); } notEquals(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.NotEquals, this, rhs); } identical(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.Identical, this, rhs); } notIdentical(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.NotIdentical, this, rhs); } minus(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.Minus, this, rhs); } plus(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.Plus, this, rhs); } divide(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.Divide, this, rhs); } multiply(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.Multiply, this, rhs); } modulo(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.Modulo, this, rhs); } and(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.And, this, rhs); } or(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.Or, this, rhs); } lower(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.Lower, this, rhs); } lowerEquals(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.LowerEquals, this, rhs); } bigger(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.Bigger, this, rhs); } biggerEquals(rhs: Expression): BinaryOperatorExpr { return new BinaryOperatorExpr(BinaryOperator.BiggerEquals, this, rhs); } isBlank(): Expression { // Note: We use equals by purpose here to compare to null and undefined in JS. return this.equals(NULL_EXPR); } cast(type: Type): Expression { return new CastExpr(this, type); } toStmt(): Statement { return new ExpressionStatement(this); } } export enum BuiltinVar { This, Super, CatchError, CatchStack } export class ReadVarExpr extends Expression { public name; public builtin: BuiltinVar; constructor(name: string | BuiltinVar, type: Type = null) { super(type); if (isString(name)) { this.name = name; this.builtin = null; } else { this.name = null; this.builtin = name; } } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitReadVarExpr(this, context); } set(value: Expression): WriteVarExpr { return new WriteVarExpr(this.name, value); } } export class WriteVarExpr extends Expression { public value: Expression; constructor(public name: string, value: Expression, type: Type = null) { super(isPresent(type) ? type : value.type); this.value = value; } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitWriteVarExpr(this, context); } toDeclStmt(type: Type = null, modifiers: StmtModifier[] = null): DeclareVarStmt { return new DeclareVarStmt(this.name, this.value, type, modifiers); } } export class WriteKeyExpr extends Expression { public value: Expression; constructor(public receiver: Expression, public index: Expression, value: Expression, type: Type = null) { super(isPresent(type) ? type : value.type); this.value = value; } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitWriteKeyExpr(this, context); } } export class WritePropExpr extends Expression { public value: Expression; constructor(public receiver: Expression, public name: string, value: Expression, type: Type = null) { super(isPresent(type) ? type : value.type); this.value = value; } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitWritePropExpr(this, context); } } export enum BuiltinMethod { ConcatArray, SubscribeObservable, bind } export class InvokeMethodExpr extends Expression { public name: string; public builtin: BuiltinMethod; constructor(public receiver: Expression, method: string | BuiltinMethod, public args: Expression[], type: Type = null) { super(type); if (isString(method)) { this.name = method; this.builtin = null; } else { this.name = null; this.builtin = method; } } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitInvokeMethodExpr(this, context); } } export class InvokeFunctionExpr extends Expression { constructor(public fn: Expression, public args: Expression[], type: Type = null) { super(type); } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitInvokeFunctionExpr(this, context); } } export class InstantiateExpr extends Expression { constructor(public classExpr: Expression, public args: Expression[], type?: Type) { super(type); } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitInstantiateExpr(this, context); } } export class LiteralExpr extends Expression { constructor(public value: any, type: Type = null) { super(type); } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitLiteralExpr(this, context); } } export class ExternalExpr extends Expression { constructor(public value: CompileIdentifierMetadata, type: Type = null, public typeParams: Type[] = null) { super(type); } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitExternalExpr(this, context); } } export class ConditionalExpr extends Expression { public trueCase: Expression; constructor(public condition: Expression, trueCase: Expression, public falseCase: Expression = null, type: Type = null) { super(isPresent(type) ? type : trueCase.type); this.trueCase = trueCase; } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitConditionalExpr(this, context); } } export class NotExpr extends Expression { constructor(public condition: Expression) { super(BOOL_TYPE); } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitNotExpr(this, context); } } export class CastExpr extends Expression { constructor(public value: Expression, type: Type) { super(type); } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitCastExpr(this, context); } } export class FnParam { constructor(public name: string, public type: Type = null) {} } export class FunctionExpr extends Expression { constructor(public params: FnParam[], public statements: Statement[], type: Type = null) { super(type); } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitFunctionExpr(this, context); } toDeclStmt(name: string, modifiers: StmtModifier[] = null): DeclareFunctionStmt { return new DeclareFunctionStmt(name, this.params, this.statements, this.type, modifiers); } } export class BinaryOperatorExpr extends Expression { public lhs: Expression; constructor(public operator: BinaryOperator, lhs: Expression, public rhs: Expression, type: Type = null) { super(isPresent(type) ? type : lhs.type); this.lhs = lhs; } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitBinaryOperatorExpr(this, context); } } export class ReadPropExpr extends Expression { constructor(public receiver: Expression, public name: string, type: Type = null) { super(type); } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitReadPropExpr(this, context); } set(value: Expression): WritePropExpr { return new WritePropExpr(this.receiver, this.name, value); } } export class ReadKeyExpr extends Expression { constructor(public receiver: Expression, public index: Expression, type: Type = null) { super(type); } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitReadKeyExpr(this, context); } set(value: Expression): WriteKeyExpr { return new WriteKeyExpr(this.receiver, this.index, value); } } export class LiteralArrayExpr extends Expression { public entries: Expression[]; constructor(entries: Expression[], type: Type = null) { super(type); this.entries = entries; } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitLiteralArrayExpr(this, context); } } export class LiteralMapExpr extends Expression { public valueType: Type = null; constructor(public entries: Array>, type: MapType = null) { super(type); if (isPresent(type)) { this.valueType = type.valueType; } } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitLiteralMapExpr(this, context); } } export interface ExpressionVisitor { visitReadVarExpr(ast: ReadVarExpr, context: any): any; visitWriteVarExpr(expr: WriteVarExpr, context: any): any; visitWriteKeyExpr(expr: WriteKeyExpr, context: any): any; visitWritePropExpr(expr: WritePropExpr, context: any): any; visitInvokeMethodExpr(ast: InvokeMethodExpr, context: any): any; visitInvokeFunctionExpr(ast: InvokeFunctionExpr, context: any): any; visitInstantiateExpr(ast: InstantiateExpr, context: any): any; visitLiteralExpr(ast: LiteralExpr, context: any): any; visitExternalExpr(ast: ExternalExpr, context: any): any; visitConditionalExpr(ast: ConditionalExpr, context: any): any; visitNotExpr(ast: NotExpr, context: any): any; visitCastExpr(ast: CastExpr, context: any): any; visitFunctionExpr(ast: FunctionExpr, context: any): any; visitBinaryOperatorExpr(ast: BinaryOperatorExpr, context: any): any; visitReadPropExpr(ast: ReadPropExpr, context: any): any; visitReadKeyExpr(ast: ReadKeyExpr, context: any): any; visitLiteralArrayExpr(ast: LiteralArrayExpr, context: any): any; visitLiteralMapExpr(ast: LiteralMapExpr, context: any): any; } export var THIS_EXPR = new ReadVarExpr(BuiltinVar.This); export var SUPER_EXPR = new ReadVarExpr(BuiltinVar.Super); export var CATCH_ERROR_VAR = new ReadVarExpr(BuiltinVar.CatchError); export var CATCH_STACK_VAR = new ReadVarExpr(BuiltinVar.CatchStack); export var NULL_EXPR = new LiteralExpr(null, null); //// Statements export enum StmtModifier { Final, Private } export abstract class Statement { constructor(public modifiers: StmtModifier[] = null) { if (isBlank(modifiers)) { this.modifiers = []; } } abstract visitStatement(visitor: StatementVisitor, context: any): any; hasModifier(modifier: StmtModifier): boolean { return this.modifiers.indexOf(modifier) !== -1; } } export class DeclareVarStmt extends Statement { public type: Type; constructor(public name: string, public value: Expression, type: Type = null, modifiers: StmtModifier[] = null) { super(modifiers); this.type = isPresent(type) ? type : value.type; } visitStatement(visitor: StatementVisitor, context: any): any { return visitor.visitDeclareVarStmt(this, context); } } export class DeclareFunctionStmt extends Statement { constructor(public name: string, public params: FnParam[], public statements: Statement[], public type: Type = null, modifiers: StmtModifier[] = null) { super(modifiers); } visitStatement(visitor: StatementVisitor, context: any): any { return visitor.visitDeclareFunctionStmt(this, context); } } export class ExpressionStatement extends Statement { constructor(public expr: Expression) { super(); } visitStatement(visitor: StatementVisitor, context: any): any { return visitor.visitExpressionStmt(this, context); } } export class ReturnStatement extends Statement { constructor(public value: Expression) { super(); } visitStatement(visitor: StatementVisitor, context: any): any { return visitor.visitReturnStmt(this, context); } } export class AbstractClassPart { constructor(public type: Type = null, public modifiers: StmtModifier[]) { if (isBlank(modifiers)) { this.modifiers = []; } } hasModifier(modifier: StmtModifier): boolean { return this.modifiers.indexOf(modifier) !== -1; } } export class ClassField extends AbstractClassPart { constructor(public name: string, type: Type = null, modifiers: StmtModifier[] = null) { super(type, modifiers); } } export class ClassMethod extends AbstractClassPart { constructor(public name: string, public params: FnParam[], public body: Statement[], type: Type = null, modifiers: StmtModifier[] = null) { super(type, modifiers); } } export class ClassGetter extends AbstractClassPart { constructor(public name: string, public body: Statement[], type: Type = null, modifiers: StmtModifier[] = null) { super(type, modifiers); } } export class ClassStmt extends Statement { constructor(public name: string, public parent: Expression, public fields: ClassField[], public getters: ClassGetter[], public constructorMethod: ClassMethod, public methods: ClassMethod[], modifiers: StmtModifier[] = null) { super(modifiers); } visitStatement(visitor: StatementVisitor, context: any): any { return visitor.visitDeclareClassStmt(this, context); } } export class IfStmt extends Statement { constructor(public condition: Expression, public trueCase: Statement[], public falseCase: Statement[] = /*@ts2dart_const*/[]) { super(); } visitStatement(visitor: StatementVisitor, context: any): any { return visitor.visitIfStmt(this, context); } } export class CommentStmt extends Statement { constructor(public comment: string) { super(); } visitStatement(visitor: StatementVisitor, context: any): any { return visitor.visitCommentStmt(this, context); } } export class TryCatchStmt extends Statement { constructor(public bodyStmts: Statement[], public catchStmts: Statement[]) { super(); } visitStatement(visitor: StatementVisitor, context: any): any { return visitor.visitTryCatchStmt(this, context); } } export class ThrowStmt extends Statement { constructor(public error: Expression) { super(); } visitStatement(visitor: StatementVisitor, context: any): any { return visitor.visitThrowStmt(this, context); } } export interface StatementVisitor { visitDeclareVarStmt(stmt: DeclareVarStmt, context: any): any; visitDeclareFunctionStmt(stmt: DeclareFunctionStmt, context: any): any; visitExpressionStmt(stmt: ExpressionStatement, context: any): any; visitReturnStmt(stmt: ReturnStatement, context: any): any; visitDeclareClassStmt(stmt: ClassStmt, context: any): any; visitIfStmt(stmt: IfStmt, context: any): any; visitTryCatchStmt(stmt: TryCatchStmt, context: any): any; visitThrowStmt(stmt: ThrowStmt, context: any): any; visitCommentStmt(stmt: CommentStmt, context: any): any; } export class ExpressionTransformer implements StatementVisitor, ExpressionVisitor { visitReadVarExpr(ast: ReadVarExpr, context: any): any { return ast; } visitWriteVarExpr(expr: WriteVarExpr, context: any): any { return new WriteVarExpr(expr.name, expr.value.visitExpression(this, context)); } visitWriteKeyExpr(expr: WriteKeyExpr, context: any): any { return new WriteKeyExpr(expr.receiver.visitExpression(this, context), expr.index.visitExpression(this, context), expr.value.visitExpression(this, context)); } visitWritePropExpr(expr: WritePropExpr, context: any): any { return new WritePropExpr(expr.receiver.visitExpression(this, context), expr.name, expr.value.visitExpression(this, context)); } visitInvokeMethodExpr(ast: InvokeMethodExpr, context: any): any { var method = isPresent(ast.builtin) ? ast.builtin : ast.name; return new InvokeMethodExpr(ast.receiver.visitExpression(this, context), method, this.visitAllExpressions(ast.args, context), ast.type); } visitInvokeFunctionExpr(ast: InvokeFunctionExpr, context: any): any { return new InvokeFunctionExpr(ast.fn.visitExpression(this, context), this.visitAllExpressions(ast.args, context), ast.type); } visitInstantiateExpr(ast: InstantiateExpr, context: any): any { return new InstantiateExpr(ast.classExpr.visitExpression(this, context), this.visitAllExpressions(ast.args, context), ast.type); } visitLiteralExpr(ast: LiteralExpr, context: any): any { return ast; } visitExternalExpr(ast: ExternalExpr, context: any): any { return ast; } visitConditionalExpr(ast: ConditionalExpr, context: any): any { return new ConditionalExpr(ast.condition.visitExpression(this, context), ast.trueCase.visitExpression(this, context), ast.falseCase.visitExpression(this, context)); } visitNotExpr(ast: NotExpr, context: any): any { return new NotExpr(ast.condition.visitExpression(this, context)); } visitCastExpr(ast: CastExpr, context: any): any { return new CastExpr(ast.value.visitExpression(this, context), context); } visitFunctionExpr(ast: FunctionExpr, context: any): any { // Don't descend into nested functions return ast; } visitBinaryOperatorExpr(ast: BinaryOperatorExpr, context: any): any { return new BinaryOperatorExpr(ast.operator, ast.lhs.visitExpression(this, context), ast.rhs.visitExpression(this, context), ast.type); } visitReadPropExpr(ast: ReadPropExpr, context: any): any { return new ReadPropExpr(ast.receiver.visitExpression(this, context), ast.name, ast.type); } visitReadKeyExpr(ast: ReadKeyExpr, context: any): any { return new ReadKeyExpr(ast.receiver.visitExpression(this, context), ast.index.visitExpression(this, context), ast.type); } visitLiteralArrayExpr(ast: LiteralArrayExpr, context: any): any { return new LiteralArrayExpr(this.visitAllExpressions(ast.entries, context)); } visitLiteralMapExpr(ast: LiteralMapExpr, context: any): any { return new LiteralMapExpr(ast.entries.map( (entry) => [entry[0], (entry[1]).visitExpression(this, context)])); } visitAllExpressions(exprs: Expression[], context: any): Expression[] { return exprs.map(expr => expr.visitExpression(this, context)); } visitDeclareVarStmt(stmt: DeclareVarStmt, context: any): any { return new DeclareVarStmt(stmt.name, stmt.value.visitExpression(this, context), stmt.type, stmt.modifiers); } visitDeclareFunctionStmt(stmt: DeclareFunctionStmt, context: any): any { // Don't descend into nested functions return stmt; } visitExpressionStmt(stmt: ExpressionStatement, context: any): any { return new ExpressionStatement(stmt.expr.visitExpression(this, context)); } visitReturnStmt(stmt: ReturnStatement, context: any): any { return new ReturnStatement(stmt.value.visitExpression(this, context)); } visitDeclareClassStmt(stmt: ClassStmt, context: any): any { // Don't descend into nested functions return stmt; } visitIfStmt(stmt: IfStmt, context: any): any { return new IfStmt(stmt.condition.visitExpression(this, context), this.visitAllStatements(stmt.trueCase, context), this.visitAllStatements(stmt.falseCase, context)); } visitTryCatchStmt(stmt: TryCatchStmt, context: any): any { return new TryCatchStmt(this.visitAllStatements(stmt.bodyStmts, context), this.visitAllStatements(stmt.catchStmts, context)); } visitThrowStmt(stmt: ThrowStmt, context: any): any { return new ThrowStmt(stmt.error.visitExpression(this, context)); } visitCommentStmt(stmt: CommentStmt, context: any): any { return stmt; } visitAllStatements(stmts: Statement[], context: any): Statement[] { return stmts.map(stmt => stmt.visitStatement(this, context)); } } export class RecursiveExpressionVisitor implements StatementVisitor, ExpressionVisitor { visitReadVarExpr(ast: ReadVarExpr, context: any): any { return ast; } visitWriteVarExpr(expr: WriteVarExpr, context: any): any { expr.value.visitExpression(this, context); return expr; } visitWriteKeyExpr(expr: WriteKeyExpr, context: any): any { expr.receiver.visitExpression(this, context); expr.index.visitExpression(this, context); expr.value.visitExpression(this, context); return expr; } visitWritePropExpr(expr: WritePropExpr, context: any): any { expr.receiver.visitExpression(this, context); expr.value.visitExpression(this, context); return expr; } visitInvokeMethodExpr(ast: InvokeMethodExpr, context: any): any { ast.receiver.visitExpression(this, context); this.visitAllExpressions(ast.args, context); return ast; } visitInvokeFunctionExpr(ast: InvokeFunctionExpr, context: any): any { ast.fn.visitExpression(this, context); this.visitAllExpressions(ast.args, context); return ast; } visitInstantiateExpr(ast: InstantiateExpr, context: any): any { ast.classExpr.visitExpression(this, context); this.visitAllExpressions(ast.args, context); return ast; } visitLiteralExpr(ast: LiteralExpr, context: any): any { return ast; } visitExternalExpr(ast: ExternalExpr, context: any): any { return ast; } visitConditionalExpr(ast: ConditionalExpr, context: any): any { ast.condition.visitExpression(this, context); ast.trueCase.visitExpression(this, context); ast.falseCase.visitExpression(this, context); return ast; } visitNotExpr(ast: NotExpr, context: any): any { ast.condition.visitExpression(this, context); return ast; } visitCastExpr(ast: CastExpr, context: any): any { ast.value.visitExpression(this, context); return ast; } visitFunctionExpr(ast: FunctionExpr, context: any): any { return ast; } visitBinaryOperatorExpr(ast: BinaryOperatorExpr, context: any): any { ast.lhs.visitExpression(this, context); ast.rhs.visitExpression(this, context); return ast; } visitReadPropExpr(ast: ReadPropExpr, context: any): any { ast.receiver.visitExpression(this, context); return ast; } visitReadKeyExpr(ast: ReadKeyExpr, context: any): any { ast.receiver.visitExpression(this, context); ast.index.visitExpression(this, context); return ast; } visitLiteralArrayExpr(ast: LiteralArrayExpr, context: any): any { this.visitAllExpressions(ast.entries, context); return ast; } visitLiteralMapExpr(ast: LiteralMapExpr, context: any): any { ast.entries.forEach((entry) => (entry[1]).visitExpression(this, context)); return ast; } visitAllExpressions(exprs: Expression[], context: any): void { exprs.forEach(expr => expr.visitExpression(this, context)); } visitDeclareVarStmt(stmt: DeclareVarStmt, context: any): any { stmt.value.visitExpression(this, context); return stmt; } visitDeclareFunctionStmt(stmt: DeclareFunctionStmt, context: any): any { // Don't descend into nested functions return stmt; } visitExpressionStmt(stmt: ExpressionStatement, context: any): any { stmt.expr.visitExpression(this, context); return stmt; } visitReturnStmt(stmt: ReturnStatement, context: any): any { stmt.value.visitExpression(this, context); return stmt; } visitDeclareClassStmt(stmt: ClassStmt, context: any): any { // Don't descend into nested functions return stmt; } visitIfStmt(stmt: IfStmt, context: any): any { stmt.condition.visitExpression(this, context); this.visitAllStatements(stmt.trueCase, context); this.visitAllStatements(stmt.falseCase, context); return stmt; } visitTryCatchStmt(stmt: TryCatchStmt, context: any): any { this.visitAllStatements(stmt.bodyStmts, context); this.visitAllStatements(stmt.catchStmts, context); return stmt; } visitThrowStmt(stmt: ThrowStmt, context: any): any { stmt.error.visitExpression(this, context); return stmt; } visitCommentStmt(stmt: CommentStmt, context: any): any { return stmt; } visitAllStatements(stmts: Statement[], context: any): void { stmts.forEach(stmt => stmt.visitStatement(this, context)); } } export function replaceVarInExpression(varName: string, newValue: Expression, expression: Expression): Expression { var transformer = new _ReplaceVariableTransformer(varName, newValue); return expression.visitExpression(transformer, null); } class _ReplaceVariableTransformer extends ExpressionTransformer { constructor(private _varName: string, private _newValue: Expression) { super(); } visitReadVarExpr(ast: ReadVarExpr, context: any): any { return ast.name == this._varName ? this._newValue : ast; } } export function findReadVarNames(stmts: Statement[]): Set { var finder = new _VariableFinder(); finder.visitAllStatements(stmts, null); return finder.varNames; } class _VariableFinder extends RecursiveExpressionVisitor { varNames = new Set(); visitReadVarExpr(ast: ReadVarExpr, context: any): any { this.varNames.add(ast.name); return null; } } export function variable(name: string, type: Type = null): ReadVarExpr { return new ReadVarExpr(name, type); } export function importExpr(id: CompileIdentifierMetadata, typeParams: Type[] = null): ExternalExpr { return new ExternalExpr(id, null, typeParams); } export function importType(id: CompileIdentifierMetadata, typeParams: Type[] = null, typeModifiers: TypeModifier[] = null): ExternalType { return isPresent(id) ? new ExternalType(id, typeParams, typeModifiers) : null; } export function literal(value: any, type: Type = null): LiteralExpr { return new LiteralExpr(value, type); } export function literalArr(values: Expression[], type: Type = null): LiteralArrayExpr { return new LiteralArrayExpr(values, type); } export function literalMap(values: Array>, type: MapType = null): LiteralMapExpr { return new LiteralMapExpr(values, type); } export function not(expr: Expression): NotExpr { return new NotExpr(expr); } export function fn(params: FnParam[], body: Statement[], type: Type = null): FunctionExpr { return new FunctionExpr(params, body, type); }