870 lines
30 KiB
TypeScript
870 lines
30 KiB
TypeScript
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 = <string>name;
|
|
this.builtin = null;
|
|
} else {
|
|
this.name = null;
|
|
this.builtin = <BuiltinVar>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 = <string>method;
|
|
this.builtin = null;
|
|
} else {
|
|
this.name = null;
|
|
this.builtin = <BuiltinMethod>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<Array<string | Expression>>, 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], (<Expression>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) => (<Expression>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<string> {
|
|
var finder = new _VariableFinder();
|
|
finder.visitAllStatements(stmts, null);
|
|
return finder.varNames;
|
|
}
|
|
|
|
class _VariableFinder extends RecursiveExpressionVisitor {
|
|
varNames = new Set<string>();
|
|
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<Array<string | Expression>>,
|
|
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);
|
|
}
|