Skip to content
This repository was archived by the owner on Apr 20, 2018. It is now read-only.

Commit 037234d

Browse files
committed
Update compiler.ts
1 parent 93547af commit 037234d

File tree

1 file changed

+287
-21
lines changed

1 file changed

+287
-21
lines changed

src/core/expressions/compiler.ts

Lines changed: 287 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,29 @@ class Expression {
116116
static Invoke(expression: Expression, ...args: Expression[]): InvocationExpression {
117117
return new InvocationExpression(expression, args);
118118
}
119+
120+
static New(typeName: string, ...args: Expression[]): NewExpression {
121+
return new NewExpression(typeName, args);
122+
}
123+
124+
static Call(obj: Expression, methodName: string, ...args: Expression[]): CallExpression {
125+
return new CallExpression(obj, methodName, args);
126+
}
127+
128+
static Member(obj: Expression, memberName: string): MemberExpression {
129+
return new MemberExpression(obj, memberName);
130+
}
131+
132+
static Index(obj: Expression, ...args: Expression[]): IndexExpression {
133+
return new IndexExpression(obj, args);
134+
}
119135
}
120136

121137
class ExpressionVisitor {
122138
Visit(node: Expression): Expression {
139+
if (node === null) {
140+
return null;
141+
}
123142
return node.Accept(this);
124143
}
125144

@@ -151,6 +170,22 @@ class ExpressionVisitor {
151170
return node.Update(this.Visit(node.expression), this.VisitMany(node.args));
152171
}
153172

173+
VisitCall(node: CallExpression): Expression {
174+
return node.Update(this.Visit(node.obj), this.VisitMany(node.args));
175+
}
176+
177+
VisitNew(node: NewExpression): Expression {
178+
return node.Update(this.VisitMany(node.args));
179+
}
180+
181+
VisitMember(node: MemberExpression): Expression {
182+
return node.Update(this.Visit(node.obj));
183+
}
184+
185+
VisitIndex(node: IndexExpression): Expression {
186+
return node.Update(this.Visit(node.obj), this.VisitMany(node.args));
187+
}
188+
154189
VisitMany<T extends Expression>(nodes: T[]): T[] {
155190
var res = new Array<T>(nodes.length);
156191

@@ -325,6 +360,7 @@ class LambdaExpression<T extends Function> extends Expression {
325360
var comp = new LambdaCompiler();
326361
comp.Visit(this);
327362
var code = comp.code;
363+
code = code.replace(/\"/g, "\\\""); // TODO: more escape sequences
328364
code = "new Function(\"return " + code + ";\")";
329365
code = code.replace(/\r?\n|\r/g, "");
330366
alert(code);
@@ -363,6 +399,136 @@ class InvocationExpression extends Expression {
363399
}
364400
}
365401

402+
class CallExpression extends Expression {
403+
_expression: Expression;
404+
_method: string;
405+
_args: Expression[];
406+
407+
constructor(expression: Expression, methodName: string, args: Expression[]) {
408+
super(ExpressionType.Call);
409+
this._expression = expression;
410+
this._method = methodName;
411+
this._args = args;
412+
}
413+
414+
get obj(): Expression {
415+
return this._expression;
416+
}
417+
418+
get method(): string {
419+
return this._method;
420+
}
421+
422+
get args(): Expression[] {
423+
return this._args;
424+
}
425+
426+
Accept(visitor: ExpressionVisitor): Expression {
427+
return visitor.VisitCall(this);
428+
}
429+
430+
Update(expression: Expression, args: Expression[]): CallExpression {
431+
if (expression !== this._expression || args !== this._args) {
432+
return new CallExpression(expression, this._method, args);
433+
}
434+
435+
return this;
436+
}
437+
}
438+
439+
class IndexExpression extends Expression {
440+
_expression: Expression;
441+
_args: Expression[];
442+
443+
constructor(expression: Expression, args: Expression[]) {
444+
super(ExpressionType.Index);
445+
this._expression = expression;
446+
this._args = args;
447+
}
448+
449+
get obj(): Expression {
450+
return this._expression;
451+
}
452+
453+
get args(): Expression[] {
454+
return this._args;
455+
}
456+
457+
Accept(visitor: ExpressionVisitor): Expression {
458+
return visitor.VisitIndex(this);
459+
}
460+
461+
Update(expression: Expression, args: Expression[]): IndexExpression {
462+
if (expression !== this._expression || args !== this._args) {
463+
return new IndexExpression(expression, args);
464+
}
465+
466+
return this;
467+
}
468+
}
469+
470+
class NewExpression extends Expression {
471+
_type: string;
472+
_args: Expression[];
473+
474+
constructor(typeName: string, args: Expression[]) {
475+
super(ExpressionType.New);
476+
this._type = typeName;
477+
this._args = args;
478+
}
479+
480+
get type(): string {
481+
return this._type;
482+
}
483+
484+
get args(): Expression[] {
485+
return this._args;
486+
}
487+
488+
Accept(visitor: ExpressionVisitor): Expression {
489+
return visitor.VisitNew(this);
490+
}
491+
492+
Update(args: Expression[]): NewExpression {
493+
if (args !== this._args) {
494+
return new NewExpression(this._type, args);
495+
}
496+
497+
return this;
498+
}
499+
}
500+
501+
class MemberExpression extends Expression {
502+
_obj: Expression;
503+
_member: string;
504+
505+
constructor(obj: Expression, memberName: string) {
506+
super(ExpressionType.Member);
507+
this._obj = obj;
508+
this._member = memberName;
509+
}
510+
511+
get obj(): Expression {
512+
return this._obj;
513+
}
514+
515+
get member(): string {
516+
return this._member;
517+
}
518+
519+
Accept(visitor: ExpressionVisitor): Expression {
520+
return visitor.VisitMember(this);
521+
}
522+
523+
Update(obj: Expression): MemberExpression {
524+
if (obj !== this._obj) {
525+
return new MemberExpression(obj, this._member);
526+
}
527+
528+
return this;
529+
}
530+
}
531+
366532
class LambdaCompiler extends ExpressionVisitor {
367533
_stack: string[];
368534

@@ -385,10 +551,13 @@ class LambdaCompiler extends ExpressionVisitor {
385551
value = "\"" + node.value + "\""; // TODO: escape characters
386552
}
387553
else if (node.value instanceof Array) {
388-
value = "[" + node.value + "]"; // TODO: proper formatting
554+
value = JSON.stringify(node.value);
555+
}
556+
else if (node.value === undefined) {
557+
value = "undefined";
389558
}
390559
else {
391-
value = node.value.toString();
560+
value = node.value.toString(); // TODO
392561
}
393562

394563
this._stack.push(value);
@@ -417,7 +586,7 @@ class LambdaCompiler extends ExpressionVisitor {
417586
break;
418587
}
419588

420-
var res = i + "" + o;
589+
var res = "(" + i + "" + o + ")";
421590
this._stack.push(res);
422591

423592
return node;
@@ -538,11 +707,36 @@ class LambdaCompiler extends ExpressionVisitor {
538707
}
539708

540709
VisitInvoke(node: InvocationExpression): Expression {
541-
this.VisitMany(node.args);
542710
this.Visit(node.expression);
711+
this.VisitMany(node.args);
712+
713+
var n = node.args.length;
714+
var args = new Array<string>(n);
715+
for (var i = 0; i < n; i++) {
716+
args[n - i - 1] = this._stack.pop();
717+
}
718+
719+
var argList = args.join(", ");
543720

544721
var func = this._stack.pop();
545722

723+
var res = func + "(" + argList + ")";
724+
725+
this._stack.push(res);
726+
727+
return node;
728+
}
729+
730+
VisitCall(node: CallExpression): Expression {
731+
var res = "";
732+
733+
if (node.obj !== null) {
734+
this.Visit(node.obj);
735+
res = this._stack.pop() + ".";
736+
}
737+
738+
this.VisitMany(node.args);
739+
546740
var n = node.args.length;
547741
var args = new Array<string>(n);
548742
for (var i = 0; i < n; i++) {
@@ -551,7 +745,61 @@ class LambdaCompiler extends ExpressionVisitor {
551745

552746
var argList = args.join(", ");
553747

554-
var res = func + "(" + argList + ")";
748+
res += node.method + "(" + argList + ")";
749+
750+
this._stack.push(res);
751+
752+
return node;
753+
}
754+
755+
VisitNew(node: NewExpression): Expression {
756+
this.VisitMany(node.args);
757+
758+
var n = node.args.length;
759+
var args = new Array<string>(n);
760+
for (var i = 0; i < n; i++) {
761+
args[n - i - 1] = this._stack.pop();
762+
}
763+
764+
var argList = args.join(", ");
765+
766+
var res = "new " + node.type + "(" + argList + ")";
767+
768+
this._stack.push(res);
769+
770+
return node;
771+
}
772+
773+
VisitMember(node: MemberExpression): Expression {
774+
var res = "";
775+
776+
if (node.obj !== null) {
777+
this.Visit(node.obj);
778+
res = this._stack.pop() + ".";
779+
}
780+
781+
res += node.member;
782+
783+
this._stack.push(res);
784+
785+
return node;
786+
}
787+
788+
VisitIndex(node: IndexExpression): Expression {
789+
this.Visit(node.obj);
790+
var res = this._stack.pop();
791+
792+
this.VisitMany(node.args);
793+
794+
var n = node.args.length;
795+
var args = new Array<string>(n);
796+
for (var i = 0; i < n; i++) {
797+
args[n - i - 1] = this._stack.pop();
798+
}
799+
800+
var argList = args.join(", ");
801+
802+
res += "[" + argList + "]";
555803

556804
this._stack.push(res);
557805

@@ -629,6 +877,10 @@ enum ExpressionType {
629877
UnaryPlus,
630878
OnesComplement,
631879
Condition,
880+
New,
881+
Call,
882+
Member,
883+
Index,
632884
}
633885

634886
class Binder extends ExpressionVisitor {
@@ -669,8 +921,16 @@ class Binder extends ExpressionVisitor {
669921
}
670922
}
671923

924+
var resources =
925+
{
926+
"my://xs": [1, 2, 3, 4, 5],
927+
"my://ss": ["bar", "foo", "qux"],
928+
"rx://operators/filter": function (xs: any[], f: (any) => boolean) { return xs.filter(f); },
929+
"rx://operators/map": function (xs: any[], f: (any) => any) { return xs.map(f); },
930+
};
931+
672932
var x = Expression.Parameter("x");
673-
var f =
933+
var f1 =
674934
Expression.Invoke(
675935
Expression.Parameter("rx://operators/map"),
676936
Expression.Invoke(
@@ -696,22 +956,28 @@ var f =
696956
)
697957
);
698958

699-
var fvs = new FreeVariableScanner();
700-
fvs.Visit(f);
701-
702-
var unbound = fvs.result;
703-
704-
var resources =
705-
{
706-
"my://xs": [1, 2, 3, 4, 5],
707-
"rx://operators/filter": function (xs: any[], f: (any) => boolean) { return xs.filter(f); },
708-
"rx://operators/map": function (xs: any[], f: (any) => any) { return xs.map(f); },
709-
};
959+
var f2 =
960+
Expression.Invoke(
961+
Expression.Parameter("rx://operators/map"),
962+
Expression.Parameter("my://ss"),
963+
Expression.Lambda<(string) => string>(
964+
Expression.Call(
965+
x,
966+
"substring",
967+
Expression.Constant(1)
968+
),
969+
x
970+
)
971+
);
710972

711973
var binder = new Binder(resources);
712-
var bound = Expression.Lambda<() => number[]>(binder.Visit(f));
713974

714-
var compiled = bound.Compile();
715-
var res = compiled();
716-
alert(res.join(", "));
975+
var b1 = Expression.Lambda<() => number[]>(binder.Visit(f1));
976+
var c1 = b1.Compile();
977+
var r1 = c1();
978+
alert(r1.join(", "));
717979

980+
var b2 = Expression.Lambda<() => string[]>(binder.Visit(f2));
981+
var c2 = b2.Compile();
982+
var r2 = c2();
983+
alert(r2.join(", "));

0 commit comments

Comments
 (0)