Merge remote-tracking branch 'redux/master' into sh4-pool
[tamarin-stm.git] / esc / src / ast.es
blob209effe3f99174e26b6f8dc274f6b61e8e9fae6b
1 /* -*- mode: java; tab-width: 4; insert-tabs-mode: nil; indent-tabs-mode: nil -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is [Open Source Virtual Machine.].
16  *
17  * The Initial Developer of the Original Code is
18  * Adobe System Incorporated.
19  * Portions created by the Initial Developer are Copyright (C) 2004-2006
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *   Adobe AS3 Team
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either the GNU General Public License Version 2 or later (the "GPL"), or
27  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the MPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the MPL, the GPL or the LGPL.
36  *
37  * ***** END LICENSE BLOCK ***** */
39 use default namespace Ast,
40     namespace Ast;
42 interface Serializable {
43     function serialize(s);
46 class ASTNode {
47     public function toString()
48         (new Serializer(true)).serialize(this);
51 // BASIC TYPES
53 type IDENT = Token::Tok; // hm, how does this serialize??
55 class Head extends ASTNode implements Serializable {
56     const fixtures: [...Fixture];
57     const exprs: [...Expr];
58     const cache = null;  // used by the definer, for the moment
59     function Head (fixtures,exprs)
60         : fixtures=fixtures
61         , exprs=exprs {}
63     function serialize(s)
64         s.sClass(this, "Head", "fixtures", "exprs");
67 class Fixture extends ASTNode implements Serializable {
68     const name: FixtureName;
69     const data: FixtureData;
70     function Fixture(name, data) : name=name, data=data {}
72     function serialize(s)
73         s.sClass(this, "Fixture", "name", "data");
76 interface FixtureName {
79 // FIXME: conflating "temps" and "positional parameters" seems wrong
80 // and is an unnecessary Tamarin dependency.  The parser uses TempName
81 // for "positional parameter" but will want to start using something
82 // for true unforgeable temporaries.
84 class TempName extends ASTNode implements FixtureName, Serializable {
85     const index : int;
86     function TempName (index) : index=index {}
88     function serialize(s)
89         s.sClass(this, "TempName", "index");
92 // FIXME: does this serve any purpose at all?  Strikes me as pure
93 // bureaucracy.  (It does allow FixtureName to be attached, but it
94 // seems that the real problem -- see comment above -- is that naming
95 // in general is not all that coherent atm.
97 class PropName extends ASTNode implements FixtureName, Serializable {
98     const name: Name;
99     function PropName(name) : name=name {}
101     function serialize(s)
102         s.sClass(this, "PropName", "name");
105 class InitBinding extends ASTNode implements Serializable {
106     const name: FixtureName;
107     const expr: Expr;
108     function InitBinding(name, expr) : name=name, expr=expr {}
110     function serialize(s)
111         s.sClass(this, "InitBinding", "name", "expr");
114 class Name extends ASTNode implements Serializable {
115     const ns;
116     const id;
117     function Name(ns, id) : ns=ns, id=id {}
118      
119     function serialize(s)
120         s.sClass(this, "Name", "ns", "id");
123 // Must be qualified everywhere it's used as 'Ast::Namespace' because
124 // Tamarin does not (yet) have prioritized name lookup.
126 interface Namespace {
129 function nsEquals(ns1, ns2) {
130     if (ns1 == ns2)
131         return true;
132     if (ns1.name != ns2.name)
133         return false;
134     switch type (ns1) {
135     case (x: UnforgeableNamespace) { return ns2 is UnforgeableNamespace; }
136     case (x: ForgeableNamespace) { return ns2 is UnforgeableNamespace; }
137     case (x: PrivateNamespace) { return ns2 is PrivateNamespace; }
138     case (x: ProtectedNamespace) { return ns2 is ProtectedNamespace; }
139     case (x: PublicNamespace) { return ns2 is PublicNamespace; }
140     case (x: InternalNamespace) { return ns2 is InternalNamespace; }
141     case (x: *) { return ns1.hash() == ns2.hash(); }
142     }
145 class PrivateNamespace extends ASTNode implements Ast::Namespace, Serializable {
146     const name : IDENT;
147     function PrivateNamespace (name)
148         : name = name { }
149     function hash () { return "private " + name; }
151     function serialize(s)
152         s.sClass(this, "PrivateNamespace", "name");
155 class ProtectedNamespace extends ASTNode implements Ast::Namespace, Serializable {
156     const name : IDENT;
157     function ProtectedNamespace (name)
158         : name = name { }
159     function hash () { return "protected " + name; }
161     function serialize(s)
162         s.sClass(this, "ProtectedNamespace", "name");
165 class PublicNamespace extends ASTNode implements Ast::Namespace, Serializable {
166     const name : IDENT;
167     function PublicNamespace (name)
168         : name = name { }
169     function hash () { return "public " + name; }
171     function serialize(s)
172         s.sClass(this, "PublicNamespace", "name");
175 class InternalNamespace extends ASTNode implements Ast::Namespace, Serializable {
176     const name : IDENT;
177     function InternalNamespace (name)
178         : name = name { }
179     function hash () { return "internal " + name; }
181     function serialize(s)
182         s.sClass(this, "InternalNamespace", "name");
185 class ForgeableNamespace extends ASTNode implements Ast::Namespace, Serializable {
186     const name : IDENT;
187     function ForgeableNamespace (name)
188         : name = name { }
189     function hash () { return "forgeable " + name; }
191     function serialize(s)
192         s.sClass(this, "ForgeableNamespace", "name");
195 class UnforgeableNamespace extends ASTNode implements Ast::Namespace, Serializable {
196     const name : IDENT;
197     function UnforgeableNamespace (name)
198         : name = name { }
199     function hash () { return "unforgeable " + name; }
201     function serialize(s)
202         s.sClass(this, "UnforgeableNamespace", "name");
205 internal var nshash = 0;  // Used as an object ID for namespace nodes in the back end
207 // The correctness of optimizations in the back-end depends on
208 // NamespaceSet and NamespaceSetList being functional data structures.
210 final class NamespaceSet extends ASTNode implements Serializable {
211     const ns;
212     const link: NamespaceSet;
213     const hash = nshash++;
214     function NamespaceSet(ns, link) : ns=ns, link=link {}
216     function serialize(s)
217         s.sClass(this, "NamespaceSet", "ns", "link");
220 final class NamespaceSetList extends ASTNode implements Serializable {
221     const nsset: NamespaceSet;
222     const link : NamespaceSetList;
223     const hash = nshash++;
224     function NamespaceSetList(nsset, link) : nsset=nsset, link=link {}
226     function serialize(s)
227         s.sClass(this, "NamespaceSetList", "nsset", "link");
229     function pushScope()
230         new NamespaceSetList(null, this);
232     function pushNamespace(ns)
233         new NamespaceSetList(new NamespaceSet(ns, nsset), this.link);
236 const publicNS = new Ast::PublicNamespace(Token::sym_EMPTY);
237 const publicNSSL = new Ast::NamespaceSetList(new Ast::NamespaceSet(publicNS, null), null);
239 // Binary type operators
241 type BINTYOP = int;
243 const castOp = 0;
244 const isOp = 1;
245 const likeOp = 2;
247 // Binary arithmetic and logical operators
249 type BINOP = int;
251 const plusOp = 0;
252 const minusOp = 1;
253 const timesOp = 2;
254 const divideOp = 3;
255 const remainderOp = 4;
256 const leftShiftOp = 5;
257 const rightShiftOp = 6;
258 const rightShiftUnsignedOp = 7;
259 const bitwiseAndOp = 8;
260 const bitwiseOrOp = 9;
261 const bitwiseXorOp = 10;
262 const logicalAndOp = 11;
263 const logicalOrOp = 12;
264 const instanceOfOp = 13;
265 const inOp = 14;
266 const equalOp = 15;
267 const notEqualOp = 16;
268 const strictEqualOp = 17;
269 const strictNotEqualOp = 18;
270 const lessOp = 19;
271 const lessOrEqualOp = 20;
272 const greaterOp = 21;
273 const greaterOrEqualOp = 22;
274 const commaOp = 23;
276 // Assignment operators
278 type ASSIGNOP = int;
280 const assignOp = 0;
281 const assignPlusOp = 1;
282 const assignMinusOp = 2;
283 const assignTimesOp = 3;
284 const assignDivideOp = 4;
285 const assignRemainderOp = 5;
286 const assignLeftShiftOp = 6;
287 const assignRightShiftOp = 7;
288 const assignRightShiftUnsignedOp = 8;
289 const assignBitwiseAndOp = 9;
290 const assignBitwiseOrOp = 10;
291 const assignBitwiseXorOp = 11;
292 const assignLogicalAndOp = 12;
293 const assignLogicalOrOp = 13;
295 // Unary arithmetic and logical operators
297 type UNOP = int;
299 const deleteOp = 0;
300 const voidOp = 1;
301 const typeOfOp = 2;
302 const preIncrOp = 3;
303 const preDecrOp = 4;
304 const postIncrOp = 5;
305 const postDecrOp = 6;
306 const unaryPlusOp = 7;
307 const unaryMinusOp = 8;
308 const bitwiseNotOp = 9;
309 const logicalNotOp = 10;
310 const typeOp = 11;
311 const spreadOp = 12;
313 // The strictFlag is set on ops that generated in strict mode.
315 const strictFlag = 64;
316 const strictMask = strictFlag-1;
318 class Expr extends ASTNode {
319     const pos: int;
320     function Expr(pos=0) : pos=pos {}
323 class TernaryExpr extends Expr implements Serializable {
324     const e1 : Expr;
325     const e2 : Expr;
326     const e3 : Expr;
327     function TernaryExpr (e1,e2,e3) : e1=e1, e2=e2, e3=e3 {}
329     function serialize(s)
330         s.sClass(this, "TernaryExpr", "e1", "e2", "e3");
333 class BinaryExpr extends Expr implements Serializable {
334     const op : BINOP;
335     const e1 : Expr;
336     const e2 : Expr;
337     function BinaryExpr (op,e1,e2) : op=op, e1=e1, e2=e2 {}
339     function serialize(s)
340         s.sClass(this, "BinaryExpr", "op", "e1", "e2");
343 class BinaryTypeExpr extends Expr implements Serializable {
344     const op : BINTYOP;
345     const e1 : Expr;
346     const e2 : TypeExpr;
347     function BinaryTypeExpr (op,e1,e2) : op=op, e1=e1, e2=e2 {}
349     function serialize(s)
350         s.sClass(this, "BinaryTypeExpr", "op", "e1", "e2");
353 class UnaryExpr extends Expr implements Serializable {
354     const op : UNOP;
355     const e1 : Expr;
356     function UnaryExpr (op,e1) : op=op, e1=e1 {}
358     function serialize(s)
359         s.sClass(this, "UnaryExpr", "op", "e1");
362 // FIXME: ex => expr
364 class TypeOpExpr extends Expr implements Serializable {
365     const ex : TypeExpr;
366     function TypeOpExpr (ex) : ex=ex {}
368     function serialize(s)
369         s.sClass(this, "TypeOpExpr", "ex");
372 class ThisExpr extends Expr implements Serializable {
373     const strict: Boolean;
374     function ThisExpr(strict) : strict=strict {}
376     function serialize(s)
377         s.sClass(this, "ThisExpr", "strict");
380 class ThisGeneratorExpr extends Expr implements Serializable {
381     function serialize(s)
382         s.sClass(this, "ThisGeneratorExpr");
385 class ThisFunctionExpr extends Expr implements Serializable {
386     function serialize(s)
387         s.sClass(this, "ThisFunctionExpr");
390 // FIXME: ex => expr
391 class YieldExpr extends Expr implements Serializable {
392     const ex : ? Expr;
393     function YieldExpr (ex=null) : ex=ex {}
395     function serialize(s)
396         s.sClass(this, "YieldExpr", "ex");
399 // FIXME: ex => expr
400 class SuperExpr extends Expr implements Serializable {
401     const ex : ? Expr;
402     function SuperExpr (ex=null) : ex=ex {}
404     function serialize(s)
405         s.sClass(this, "SuperExpr", "ex");
408 class CallExpr extends Expr implements Serializable {
409     const expr : Expr;
410     const args : [...Expr];
411     const spread: ? Expr;
412     const strict: Boolean;
413     function CallExpr (expr,args,spread,pos=0,strict=false)
414         : expr=expr
415         , args=args
416         , spread=spread
417         , strict=strict
418         , super(pos) {}
420     function serialize(s)
421         s.sClass(this, "CallExpr", "expr", "args", "spread", "pos", "strict");
424 class ApplyTypeExpr extends Expr implements Serializable {
425     const expr : Expr;
426     const args : [...TypeExpr];
427     function ApplyTypeExpr (expr,args)
428         : expr=expr
429         , args=args {}
431     function serialize(s)
432         s.sClass(this, "ApplyTypeExpr", "expr", "args");
435 class LetExpr extends Expr implements Serializable {
436     const head : Head;
437     const expr : Expr;
438     function LetExpr (head,expr)
439         : head = head
440         , expr = expr {}
442     function serialize(s)
443         s.sClass(this, "LetExpr", "head", "expr");
446 class DynamicOverrideExpr extends Expr implements Serializable {
447     const names: [...IdentExpr];
448     const exprs: [...Expr];
449     const body : Expr;
450     function DynamicOverrideExpr (names, exprs, body)
451         : names=names
452         , exprs=exprs
453         , body=body {}
455     function serialize(s)
456         s.sClass(this, "DynamicOverrideExpr", "names", "exprs", "body");
459 class NewExpr extends Expr implements Serializable {
460     const expr : Expr;
461     const args : [...Expr];
462     const spread: ? Expr;
463     function NewExpr (expr,args,spread)
464         : expr = expr
465         , args = args
466         , spread = spread {}
468     function serialize(s)
469         s.sClass(this, "NewExpr", "expr", "args", "spread");
472 class ObjectRef extends Expr implements Serializable {
473     const base  : Expr;
474     const ident : (IdentExpr | ComputedName);
475     function ObjectRef (base,ident,pos=0)
476         : base = base
477         , ident = ident
478         , super(pos) { }
480     function serialize(s)
481         s.sClass(this, "ObjectRef", "base", "ident", "pos");
484 // This is used to encode obj[E] because that whole expression is
485 // encoded as an ObjectRef; the "ident" in ObjectRef (the 'E' above)
486 // turns out to be a ComputedName.  Note that E cannot be a slice
487 // expression; the pattern obj[E1:E2:E3] is translated into a call
488 // expression.
490 class ComputedName extends Expr implements Serializable {
491     const expr: Expr;
492     function ComputedName (expr)
493         : expr=expr { }
495     function serialize(s)
496         s.sClass(this, "ComputedName", "expr");
499 // FIXME: le? re?
500 class SetExpr extends Expr implements Serializable {
501     const op : ASSIGNOP;
502     const le : Expr;
503     const re : Expr;
504     function SetExpr (op,le,re,pos=0)
505         : op=op
506         , le=le
507         , re=re 
508         , super(pos) {}
510     function serialize(s)
511         s.sClass(this, "SetExpr", "op", "le", "re");
514 class EvalScopeInitExpr extends Expr implements Serializable {
515     const index: int;
516     const how: String;
517     function EvalScopeInitExpr(index, how)
518         : index=index
519         , how=how
520     {}
522     function serialize(s)
523         s.sClass(this, "EvalScopeInitExpr", "index", "how");
526 interface Comprehension {
529 class ComprehendIf extends Expr implements Comprehension, Serializable {
530     const condition: Expr;
531     const subclause: ? Expr;
532     function ComprehendIf(condition, subclause) 
533         : condition=condition
534         , subclause=subclause {}
535         
536     function serialize(s)
537         s.sClass(this, "ComprehendIf", "condition", "subclause");
540 class ComprehendLet extends Expr implements Comprehension, Serializable {
541     const head: Head;
542     const subclause: ? Expr;
543     function ComprehendLet(head, subclause) 
544         : head=head
545         , subclause=subclause {}
546         
547     function serialize(s)
548         s.sClass(this, "ComprehendLet", "head", "subclause");
551 class ComprehendFor extends Expr implements Comprehension, Serializable {
552     const is_each: Boolean;
553     const head: Head;
554     const iterator: Expr;
555     const subclause: ? Expr;
556     function ComprehendFor(is_each, head, iterator, subclause) 
557         : is_each=is_each
558         , head=head
559         , iterator=iterator
560         , subclause=subclause {}
561         
562     function serialize(s)
563         s.sClass(this, "ComprehendFor", "is_each", "head", "iterator", "subclause");
566 interface Bind {}
567     
568 // Couldn't resolve to any scope/reg
569 class NoBind implements Bind {
572 const nobind = new NoBind;
574 class RegBind implements Bind {
575     const reg;
576     const type_index;
577     function RegBind(reg, type_index)
578         : reg = reg
579         , type_index = type_index { }
582 class SlotBind implements Bind {
583     const slot;   // slot id
584     const scope;  // Register the scope is in.  Could scope ever not be in a register?
585     function SlotBind(slot, scope)
586         : slot = slot
587         , scope = scope { }
590 // FIXME: better as an ENUM, but then that needs to be serializable.
592 type INIT_TARGET = int;
594 const varInit = 0;
595 const letInit = 1;
596 const prototypeInit = 2;
597 const instanceInit = 3;
599 class InitExpr extends Expr implements Serializable {
600     const target : INIT_TARGET;
601     const head : Head;               // for desugaring temporaries
602     const inits : [...InitBinding];
603     function InitExpr (target, head, inits)
604         : target = target
605         , head = head
606         , inits = inits {}
608     function serialize(s)
609         s.sClass(this, "InitExpr", "target", "head", "inits");
612 class GetTemp extends Expr implements Serializable {
613     const n : int;
614     function GetTemp (n)
615         : n = n {}
617     function serialize(s)
618         s.sClass(this, "GetTemp", "n");
621 class GetParam extends Expr implements Serializable {
622     const n : int;
623     function GetParam (n) 
624         : n = n {}
626     function serialize(s)
627         s.sClass(this, "GetParam", "n");
630 class GetCogenTemp extends Expr implements Serializable {
631     const n;   // set by the code generator
632     function GetCogenTemp() {}
634     function serialize(s)
635         s.sClass(this, "GetCogenTemp");
638 interface IdentExpr {
641 // Values in nss are unresolved expressions until definition time, but
642 // the parser also places literal namespace values in the list when it
643 // needs to.
645 class Identifier extends Expr implements IdentExpr, Serializable {
646     const ident : IDENT;
647     const nss: [...(Ast::Namespace | Expr)];
648     var binding;
649     function Identifier (ident,nss,pos=0)
650         : ident = ident
651         , nss = nss
652         , binding = undefined
653         , super(pos) {}
655     function serialize(s)
656         s.sClass(this, "Identifier", "ident", "nss");
659 class QualifiedIdentifier extends Expr implements IdentExpr, Serializable {
660     const qual  : (Ast::Namespace | Expr);
661     const ident : IDENT;
662     function QualifiedIdentifier (qual,ident,pos=0)
663         : qual=qual
664         , ident=ident
665         , super(pos) {}
667     function serialize(s)
668         s.sClass(this, "QualifiedIdentifier", "qual", "ident");
671 interface LiteralExpr {
674 class LiteralNull extends Expr implements LiteralExpr, Serializable {
675     function LiteralNull(pos=0)
676         : super(pos) { }
677     
678     function serialize(s)
679         s.sClass(this, "LiteralNull");
682 class LiteralUndefined extends Expr implements LiteralExpr, Serializable {
683     function LiteralUndefined(pos=0)
684         : super(pos) { }
686     function serialize(s)
687         s.sClass(this, "LiteralUndefined");
690 class LiteralDouble extends Expr implements LiteralExpr, Serializable {
691     const doubleValue : Number;
692     function LiteralDouble (doubleValue, pos=0)
693         : doubleValue=doubleValue
694         , super(pos) { }
696     function serialize(s)
697         s.sClass(this, "LiteralDouble", "doubleValue");
700 class LiteralDecimal extends Expr implements LiteralExpr, Serializable {
701     const decimalValue : decimal;
702     function LiteralDecimal (decimalValue, pos=0)
703         : decimalValue = decimalValue
704         , super(pos) { }
706     function serialize(s)
707         s.sClass(this, "LiteralDouble", "decimalValue");
710 class LiteralInt extends Expr implements LiteralExpr, Serializable {
711     const intValue : int;
712     function LiteralInt(intValue, pos=0) 
713         : intValue=intValue
714         , super(pos) {}
716     function serialize(s)
717         s.sClass(this, "LiteralInt", "intValue");
720 class LiteralUInt extends Expr implements LiteralExpr, Serializable {
721     const uintValue : uint;
722     function LiteralUInt(uintValue, pos=0) 
723         : uintValue=uintValue
724         , super(pos) {}
726     function serialize(s)
727         s.sClass(this, "LiteralUInt", "uintValue");
730 class LiteralBoolean extends Expr implements LiteralExpr, Serializable {
731     const booleanValue : Boolean;
732     function LiteralBoolean(booleanValue, pos=0) 
733         : booleanValue=booleanValue
734         , super(pos) {}
736     function serialize(s)
737         s.sClass(this, "LiteralBoolean", "booleanValue");
740 class LiteralString extends Expr implements LiteralExpr, Serializable {
741     const strValue : Token::Tok;
742     function LiteralString (strValue, pos=0)
743         : strValue = strValue
744         , super(pos) {}
746     function serialize(s)
747         s.sClass(this, "LiteralString", "strValue");
750 class LiteralArray extends Expr implements LiteralExpr, Serializable {
751     const exprs : [...Expr];
752     const spread : ? Expr;
753     const ty : TypeExpr;
754     function LiteralArray (exprs, spread, ty, pos=0)
755         : exprs = exprs
756         , spread = spread
757         , ty = ty
758         , super(pos) { }
760     function serialize(s)
761         s.sClass(this, "LiteralArray", "exprs", "ty");
764 class LiteralComprehension extends Expr implements LiteralExpr, Serializable {
765     const expr : Expr;
766     const comprehension : Comprehension;
767     const ty : TypeExpr;
768     function LiteralComprehension (expr, comprehension, ty, pos=0)
769         : expr = expr
770         , comprehension = comprehension
771         , ty = ty
772         , super(pos) { }
774     function serialize(s)
775         s.sClass(this, "LiteralComprehension", "expr", "comprehension", "ty");
778 class LiteralNamespace extends Expr implements LiteralExpr, Serializable {
779     const namespaceValue : Ast::Namespace;
780     function LiteralNamespace (namespaceValue, pos=0)
781         : namespaceValue = namespaceValue 
782         , super(pos) {}
784     function serialize(s)
785         s.sClass(this, "LiteralNamespace", "namespaceValue");
788 class LiteralObject extends Expr implements LiteralExpr, Serializable {
789     const fields : [...LiteralField];
790     const ty : TypeExpr;
791     function LiteralObject (fields, ty, pos=0)
792         : fields = fields
793         , ty = ty 
794         , super(pos) { }
796     function serialize(s)
797         s.sClass(this, "LiteralObject", "fields", "ty");
799     
800 class LiteralField extends ASTNode implements Serializable {
801     const kind:  VAR_DEFN_TAG;
802     const ident: IdentExpr;
803     const expr:  ? Expr;
804     function LiteralField (kind,ident,expr)
805         : kind = kind
806         , ident = ident
807         , expr = expr {}
809     function serialize(s)
810         s.sClass(this, "LiteralField", "kind", "ident", "expr");
813 class ProtoField extends ASTNode implements Serializable {
814     const expr : Expr;
815     function ProtoField(expr) : expr=expr {}
817     function serialize(s)
818         s.sClass(this, "ProtoField", "expr");
821 class VirtualField extends ASTNode implements Serializable {
822     const tag  : VAR_DEFN_TAG;
823     const name : IdentExpr;
824     const kind : FUNC_NAME_KIND;
825     const func : Func;
826     function VirtualField(tag, name, kind, func)
827         : tag=tag
828         , name=name
829         , kind=kind
830         , func=func {}
832     function serialize(s)
833         s.sClass(this, "VirtualField", "tag", "name", "kind", "func");
837 class LiteralFunction extends Expr implements LiteralExpr, Serializable {
838     const func : Func;
839     function LiteralFunction (func, pos=0)
840         : func = func
841         , super(pos) {}
843     function serialize(s)
844         s.sClass(this, "LiteralFunction", "func");
847 class LiteralRegExp extends Expr implements LiteralExpr, Serializable {
848     const src : Token::Tok;
849     function LiteralRegExp(src, pos=0)
850         : src=src
851         , super(pos) {}
853     function serialize(s)
854         s.sClass(this, "LiteralRegExp", "src");
857 type VAR_DEFN_TAG = int;
859 const noTag = 0;     // dynamic property
860 const constTag = 1;  // 'const' fixture or parameter
861 const varTag = 2;    // 'var' fixture or parameter
863 /*  Not used
864 class VariableDefn extends ASTNode implements Serializable {
865     const ns: Namespace;
866     const isStatic: Boolean;
867     const isPrototype: Boolean;
868     const kind: VAR_DEFN_TAG;
869     const bindings: BINDING_INITS;
870     function VariableDefn (ns,isStatic,isPrototype,kind,bindings)
871         : ns = ns
872         , isStatic = isStatic
873         , isPrototype = isPrototype
874         , kind = kind
875         , bindings = bindings {}
877     function serialize(s)
878         s.sClass(this, "VariableDefn", "ns", "isStatic", "isPrototype", "kind", "bindings");
882 class Cls extends ASTNode implements Serializable {
883     const name: Name;
884     const typeParams: [...TypeExpr];
885     const nonnullable: Boolean;
886     const baseName: IdentExpr;
887     const interfaceNames: [...IdentExpr];
888     const protectedns;
889     const constructor : Ctor;
890     const classHead: Head;
891     const instanceHead: Head;
892     const classType: ObjectType;
893     const instanceType: InstanceType;
894     const classBody: [...Stmt];
895     const isDynamic;
896     const isFinal;
897     function Cls (name,typeParams,nonnullable,baseName,interfaceNames,protectedns,
898                   constructor,classHead,instanceHead,classType,instanceType,classBody,
899                   isDynamic,isFinal)
900         : name = name
901         , typeParams = typeParams
902         , nonnullable = nonnullable
903         , baseName = baseName
904         , interfaceNames = interfaceNames
905         , protectedns = protectedns
906         , constructor = constructor
907         , classHead = classHead
908         , instanceHead = instanceHead
909         , classType = classType
910         , instanceType = instanceType
911         , classBody = classBody
912         , isDynamic = isDynamic
913         , isFinal = isFinal
914     {}
916     function serialize(s)
917         s.sClass(this, "Cls", 
918                  "name", "typeParams", "nonnullable", "baseName", "interfaceNames", "protectedns", 
919                  "constructor", "classHead", "instanceHead", "classType", "instanceType", "classBody",
920                  "isDynamic", "isFinal");
923 class Interface extends ASTNode implements Serializable {
924     const name: Name;
925     const typeParams: [...TypeExpr];
926     const interfaceNames: [...IdentExpr];
927     const instanceHead: Head;
928     function Interface (name,typeParams,interfaceNames,instanceHead)
929         : name = name
930         , typeParams = typeParams
931         , interfaceNames = interfaceNames
932         , instanceHead = instanceHead
933     {}
935     function serialize(s)
936         s.sClass(this, "Interface", "typeParams", "name", "interfaceNames", "instanceHead");
939 // Functions
941 // FIXME: 'TAG' is better here, see above uses.
942 type FUNC_NAME_KIND = int;
944 const ordinaryFunction = 0;
945 const getterFunction = 1;
946 const setterFunction = 2;
947 const staticInitFunction = 3;
949 class FuncName extends ASTNode implements Serializable {
950     const kind: FUNC_NAME_KIND;
951     const ident: IDENT;
952     function FuncName(kind, ident) : kind=kind, ident=ident {}
954     function serialize(s)
955         s.sClass(this, "FuncName", "kind", "ident");
958 class FuncAttr extends ASTNode implements Serializable {
959     /* Outer function, or null if the function is at the global
960        level (including for class methods). */
961     const parent: FuncAttr;
963     /* Nested functions and function expressions, empty for leaf functions */
964     const children;
966     /* True iff identifier "arguments" lexically referenced in function body.
967        Note that the parameter list is excluded. */
968     var uses_arguments = false;
969         
970     /* True iff identifier expression "eval" is lexically referenced 
971        in the function body as the operator in a call expression. */
972     var uses_eval = false;
974     /* True iff ...<id> appears in the parameter list. */
975     var uses_rest = false;
976         
977     /* True iff the body has a "with" statement */
978     var uses_with = false;
980     /* True iff the body has a "try" statement with a "catch" clause */
981     var uses_catch = false;
983     /* True iff the body has a "try" statement with a "finally" clause */
984     var uses_finally = false;
986     /* True iff the body has a "yield" statement or expression */
987     var uses_yield = false;
989     /* True iff this is a constructor whose body or settings has an
990        explicit "super" call */
991     var uses_super = false;
993     /* True iff this function is native */
994     var is_native = false;
996     /* True iff the function must capture its statement result value and return it if 
997        control falls off the end */
998     var capture_result = false;
1000     /* Synthesized: true iff activation object must be reified for any reason */
1001     var reify_activation = false;
1003     function FuncAttr(...rest) {
1004         if (rest.length == 1) {
1005             this.parent = rest[0];
1006             this.children = [];
1007         }
1008         else {
1009             // Unserialization.  An ad hoc pass over the AST will (hopefully) take 
1010             // care of patching up parent/children.
1011             [uses_arguments, uses_eval, uses_rest, uses_with, uses_catch, 
1012              uses_finally, uses_yield, uses_super, is_native, capture_result, 
1013              reify_activation] = rest;
1014         }
1015     }
1017     function serialize(s)
1018         s.sClass(this, "FuncAttr", "uses_arguments", "uses_eval", "uses_rest", "uses_with",
1019                  "uses_catch", "uses_finally", "uses_yield", "uses_super", "is_native", 
1020                  "capture_result", "reify_activation");
1023 class Func extends ASTNode implements Serializable {
1024     const name; //: FUNC_NAME;
1025     const body: [...Stmt];
1026     const params: Head;
1027     const numparams: int;
1028     const vars: Head;
1029     const defaults: [...Expr];
1030     const ty: TypeExpr;
1031     const attr: FuncAttr;
1032     const strict: Boolean;
1033     const pos;
1034     const filename;
1035     function Func (name,body,params,numparams,vars,defaults,ty,attr,strict,pos=0,filename=null)
1036         : name = name
1037         , body = body
1038         , params = params
1039         , numparams = numparams
1040         , vars = vars
1041         , defaults = defaults
1042         , ty = ty
1043         , attr = attr 
1044         , strict = strict
1045         , pos = pos
1046         , filename = filename {}
1048     function serialize(s)
1049         s.sClass(this, "Func", "name", "body", "params", "numparams", "vars", "defaults", "ty", "attr", "strict", "pos", "filename");
1052 class Ctor extends ASTNode implements Serializable {
1053     const settings : [...Expr];
1054     const superArgs : ? [...Expr];   // Will be null if there is no 'super' call in the settings
1055     const superSpread: ? Expr
1056     const func : Func;
1057     function Ctor (settings,superArgs,superSpread,func)
1058         : settings = settings
1059         , superArgs = superArgs
1060         , superSpread = superSpread
1061         , func = func {}
1063     function serialize(s)
1064         s.sClass(this, "Ctor", "settings", "superArgs", "superSpread", "func");
1067 interface BindingIdent {
1070 class TempIdent extends ASTNode implements BindingIdent, Serializable {
1071     const index : int;
1072     function TempIdent (index)
1073         : index = index {}
1075     function serialize(s)
1076         s.sClass(this, "TempIdent", "index");
1079 class ParamIdent extends ASTNode implements BindingIdent, Serializable {
1080     const index : int;
1081     function ParamIdent (index)
1082         : index = index {}
1084     function serialize(s)
1085         s.sClass(this, "ParamIdent", "index");
1088 class PropIdent extends ASTNode implements BindingIdent, Serializable {
1089     const ident : IDENT;
1090     function PropIdent (ident)
1091         : ident = ident { }
1093     function serialize(s)
1094         s.sClass(this, "PropIdent", "ident");
1097 interface FixtureData {
1100 class NamespaceFixture extends ASTNode implements FixtureData, Serializable {
1101     const ns : Ast::Namespace;
1102     function NamespaceFixture (ns)
1103         : ns = ns {}
1105     function serialize(s)
1106         s.sClass(this, "NamespaceFixture", "ns");
1109 internal class FixtureFwd extends ASTNode implements FixtureData {
1110     const params     : [...IDENT];
1111     const nonnullable: Boolean;
1112     function FixtureFwd (params, nonnullable) 
1113         : params=params
1114         , nonnullable=nonnullable {}
1117 class ClassFixtureFwd extends FixtureFwd implements Serializable {
1118     function ClassFixtureFwd (params, nonnullable) : super(params, nonnullable) {}
1120     function serialize(s)
1121         s.sClass(this, "ClassFixtureFwd", "params", "nonnullable");
1124 class ClassFixture extends ASTNode implements FixtureData, Serializable {
1125     const cls : Cls;
1126     function ClassFixture (cls)
1127         : cls = cls {}
1129     function serialize(s)
1130         s.sClass(this, "ClassFixture", "cls");
1133 class InterfaceFixtureFwd extends FixtureFwd implements Serializable {
1134     function InterfaceFixtureFwd (params) : super(params, false) {}
1136     function serialize(s)
1137         s.sClass(this, "InterfaceFixtureFwd", "params");
1140 class InterfaceFixture extends ASTNode implements FixtureData, Serializable {
1141     const iface : Interface;
1142     function InterfaceFixture (iface)
1143         : iface = iface {}
1145     function serialize(s)
1146         s.sClass(this, "InterfaceFixture", "iface");
1150 class TypeVarFixture extends ASTNode implements FixtureData, Serializable {
1151     function serialize(s)
1152         s.sClass(this, "TypeVarFixture");
1156 class TypeFixtureFwd extends FixtureFwd implements Serializable {
1157     function TypeFixtureFwd (params, nonnullable) : super(params, nonnullable) {}
1159     function serialize(s)
1160         s.sClass(this, "TypeFixtureFwd", "params", "nonnullable");
1163 class TypeFixture extends ASTNode implements FixtureData, Serializable {
1164     const params     : [...IDENT];
1165     const nonnullable: Boolean;
1166     const ty         : TypeExpr;
1167     function TypeFixture (params, nonnullable, ty)
1168         : params=params
1169         , nonnullable=nonnullable
1170         , ty = ty {}
1172     function serialize(s)
1173         s.sClass(this, "TypeFixture", "params", "nonnullable", "ty");
1176 class MethodFixture extends ASTNode implements FixtureData, Serializable {
1177     const func : Func;
1178     const ty : TypeExpr;
1179     const isReadOnly : Boolean;
1180     const isOverride : Boolean;
1181     const isFinal : Boolean;
1182     function MethodFixture(func, ty, isReadOnly, isOverride, isFinal) 
1183         : func = func
1184         , ty = ty
1185         , isReadOnly = isReadOnly
1186         , isOverride = isOverride
1187         , isFinal = isFinal { }
1189     function serialize(s)
1190         s.sClass(this, "MethodFixture", "func", "ty", "isReadOnly", "isOverride", "isFinal");
1193 class ValFixture extends ASTNode implements FixtureData, Serializable {
1194     const ty : TypeExpr;
1195     const isReadOnly : Boolean;
1196     function ValFixture(ty, isReadOnly) 
1197         : ty=ty
1198         , isReadOnly=isReadOnly {}
1200     function serialize(s)
1201         s.sClass(this, "ValFixture", "ty", "isReadOnly");
1204 class VirtualValFixture extends ASTNode implements FixtureData, Serializable {
1205     const ty : TypeExpr;
1206     const getter : ? Func;
1207     const setter : ? Func;
1209     function VirtualValFixture(ty, getter, setter)
1210         : ty=ty
1211         , getter=getter
1212         , setter=setter {}
1214     function serialize(s)
1215         s.sClass(this, "VirtualValFixture", "ty", "getter", "setter");
1218 interface TypeExpr {
1221 type SPECIAL_TYPE_KIND = int;
1223 class SpecialType extends ASTNode implements TypeExpr, Serializable {
1224     const kind : SPECIAL_TYPE_KIND;
1225     function SpecialType(kind) : kind=kind {}
1227     function serialize(s)
1228         s.sConstant("Ast::specialTypes[" + kind + "]");
1231 const specialTypes = [new SpecialType(0), 
1232                       new SpecialType(1), 
1233                       new SpecialType(2), 
1234                       new SpecialType(3)];
1236 const [anyType, nullType, undefinedType, voidType] = specialTypes;
1238 // These may not be required any more, serialization and
1239 // deserialization preserves identity of the special type objects.
1241 function isAnyType(t:TypeExpr): Boolean
1242     t is SpecialType && t.kind == 0;
1244 function isNullType(t:TypeExpr): Boolean
1245     t is SpecialType && t.kind == 1;
1247 function isUndefinedType(t:TypeExpr): Boolean
1248     t is SpecialType && t.kind == 2;
1250 function isVoidType(t:TypeExpr): Boolean
1251     t is SpecialType && t.kind == 3;
1253 class UnionType extends ASTNode implements TypeExpr, Serializable {
1254     const types : [...TypeExpr];
1255     function UnionType (types)
1256         : types = types { }
1258     function serialize(s)
1259         s.sClass(this, "UnionType", "types");
1262 // "spread" may not be the best choice of name here.
1264 class ArrayType extends ASTNode implements TypeExpr, Serializable {
1265     const types : [...TypeExpr];
1266     const spread: ? TypeExpr;
1267     function ArrayType (types, spread)
1268         : types = types
1269         , spread = spread {}
1271     function serialize(s)
1272         s.sClass(this, "ArrayType", "types", "spread");
1275 // FIXME: Really redundant, except it introduces the tag TypeExpr
1276 // which might also be moved to Identifier and QualifiedIdentifier.
1277 // But keep for now until the type language settles down.
1279 class TypeName extends ASTNode implements TypeExpr, Serializable {
1280     const ident : IdentExpr;
1281     function TypeName (ident)
1282         : ident = ident {}
1284     function serialize(s)
1285         s.sClass(this, "TypeName", "ident");
1288 class ElementTypeRef extends ASTNode implements TypeExpr, Serializable {
1289     const base : TypeExpr;
1290     const index : int;
1291     function ElementTypeRef (base,index)
1292         : base = base
1293         , index = index { }
1295     function serialize(s)
1296         s.sClass(this, "ElementTypeRef", "base", "index");
1299 class FieldTypeRef extends ASTNode implements TypeExpr, Serializable {
1300     const base : TypeExpr;
1301     const ident : IdentExpr;
1302     function FieldTypeRef (base,ident)
1303         : base = base
1304         , ident = ident { }
1306     function serialize(s)
1307         s.sClass(this, "FieldTypeRef", "base", "ident");
1310 class FunctionType extends ASTNode implements TypeExpr, Serializable {
1311     const typeParams: [...IDENT];
1312     const thisType  : ? TypeExpr;
1313     const paramTypes: [...{ty:TypeExpr, optional:Boolean}];
1314     const hasRest   : Boolean;
1315     const returnType: ? TypeExpr;
1316     function FunctionType(typeParams, thisType, paramTypes, hasRest, returnType) 
1317         : typeParams = typeParams
1318         , thisType = thisType
1319         , paramTypes = paramTypes
1320         , hasRest = hasRest
1321         , returnType = returnType {}
1323     function serialize(s) 
1324         s.sClass(this, "FunctionType", "typeParams", "thisType", "paramTypes", "hasRest", "returnType");
1327 class ObjectType extends ASTNode implements Serializable {
1328     const fields : [...FieldType];
1329     function ObjectType (fields)
1330         : fields = fields { }
1332     function serialize(s)
1333         s.sClass(this, "ObjectType", "fields");
1336 class FieldType extends ASTNode implements Serializable {
1337     const ident: IDENT;
1338     const ty: TypeExpr;
1339     function FieldType (ident,ty)
1340         : ident = ident
1341         , ty = ty {}
1343     function serialize(s)
1344         s.sClass(this, "FieldType", "ident", "ty");
1347 class AppType extends ASTNode implements TypeExpr, Serializable {
1348     const base : TypeExpr;
1349     const args : [...TypeExpr];
1350     function AppType (base,args)
1351         : base = base
1352         , args = args { }
1354     function serialize(s)
1355         s.sClass(this, "AppType", "base", "args");
1358 class NullableType extends ASTNode implements TypeExpr, Serializable {
1359     const ty : TypeExpr;
1360     const isNullable : Boolean;
1361     function NullableType (ty,isNullable)
1362         : ty = ty
1363         , isNullable = isNullable { }
1365     function serialize(s)
1366         s.sClass(this, "NullableType", "ty", "isNullable");
1369 class InstanceType extends ASTNode implements TypeExpr, Serializable {
1370     const name : Name;
1371     const typeParams : [...IDENT];
1372     const ty : TypeExpr;
1373     const isDynamic : Boolean;
1374     function InstanceType(name, typeParams, ty, isDynamic)
1375         : name=name
1376         , typeParams=typeParams
1377         , ty=ty
1378         , isDynamic=isDynamic
1379     { }
1381     function serialize(s)
1382         s.sClass(this, "InstanceType", "name", "typeParams", "ty", "isDynamic");
1385 class LikeType extends ASTNode implements Serializable {
1386     const ty: TypeExpr;
1387     function LikeType(ty) : ty=ty {}
1389     function serialize(s)
1390         s.sClass(this, "LikeType", "ty");
1393 interface Stmt {
1396 interface LabelSet {
1397     // Want to express (but can't): has 'labels': Array The best thing
1398     // we can do is either specify a push method, or a getter method
1399     // for 'labels'.
1402 class EmptyStmt extends ASTNode implements Stmt, Serializable {
1403     function serialize(s)
1404         s.sClass(this, "EmptyStmt");
1407 class ExprStmt extends ASTNode implements Stmt, Serializable {
1408     const expr : Expr;
1409     function ExprStmt (expr)
1410         : expr = expr {}
1412     function serialize(s)
1413         s.sClass(this, "ExprStmt", "expr");
1416 internal class ForInStmtCore extends ASTNode implements Stmt, LabelSet {
1417     const assignment: Expr;
1418     const tmp: Expr;
1419     const obj  : Expr;
1420     const stmt : Stmt;
1421     const is_each : boolean;
1422     const labels: [...IDENT];
1423     function ForInStmtCore (assignment,tmp,obj,stmt,is_each=false,labels=null)
1424         : assignment = assignment
1425         , tmp = tmp
1426         , obj = obj
1427         , stmt = stmt
1428         , is_each = is_each
1429         , labels = labels == null ? ([] : [...IDENT]) : labels {}
1432 class ForInStmt extends ForInStmtCore implements Serializable {
1433     function ForInStmt (assignment,tmp,obj,stmt,is_each=false,labels=null)
1434         : super(assignment, tmp, obj, stmt, is_each, labels) {}
1436     function serialize(s)
1437         s.sClass(this, "ForInStmt", "assignment", "tmp", "obj", "stmt", "is_each", "labels");
1440 class ForInBindingStmt extends ForInStmtCore implements Serializable {
1441     const head: Head;
1442     const init: ? Expr;
1444     function ForInBindingStmt (head, assignment, tmp, init, obj, stmt,is_each=false,labels=null)
1445         : head = head
1446         , init = init
1447         , super(assignment, tmp, obj, stmt, is_each, labels) {}
1449     function serialize(s)
1450         s.sClass(this, "ForInBindingStmt", "head", "assignment", "tmp", "init", "obj", "stmt", "is_each", "labels");
1453 class ThrowStmt extends ASTNode implements Stmt, Serializable {
1454     const expr : Expr;
1455     function ThrowStmt (expr)
1456         : expr = expr { }
1458     function serialize(s)
1459         s.sClass(this, "ThrowStmt", "expr");
1462 class ReturnStmt extends ASTNode implements Stmt, Serializable {
1463     const expr : ? Expr;
1464     function ReturnStmt(expr) 
1465         : expr = expr { }
1467     function serialize(s)
1468         s.sClass(this, "ReturnStmt", "expr");
1471 class BreakStmt extends ASTNode implements Stmt, Serializable {
1472     const ident : ? IDENT;
1473     function BreakStmt (ident)
1474         : ident = ident { }
1476     function serialize(s)
1477         s.sClass(this, "BreakStmt", "ident");
1480 class ContinueStmt extends ASTNode implements Stmt, Serializable {
1481     const ident : ? IDENT;
1482     function ContinueStmt (ident)
1483         : ident = ident { }
1485     function serialize(s)
1486         s.sClass(this, "ContinueStmt", "ident");
1489 class BlockStmt extends ASTNode implements Stmt, Serializable {
1490     const block : Block;
1491     function BlockStmt (block)
1492         : block = block {}
1494     function serialize(s)
1495         s.sClass(this, "BlockStmt", "block");
1498 class LabeledStmt extends ASTNode implements Stmt, Serializable {
1499     const label : IDENT;
1500     const stmt : Stmt;
1501     function LabeledStmt (label,stmt)
1502         : label = label
1503         , stmt = stmt { }
1505     function serialize(s)
1506         s.sClass(this, "LabeledStmt", "label", "stmt");
1509 class LetBlockStmt extends ASTNode implements Stmt, Serializable {
1510     const outer_head : Head;
1511     const inner_head : Head;
1512     const body : [...Stmt];
1513     function LetBlockStmt (outer_head,inner_head,body)
1514         : outer_head = outer_head
1515         , inner_head = inner_head
1516         , body = body{}
1518     function serialize(s)
1519         s.sClass(this, "LetBlockStmt", "outer_head", "inner_head", "body");
1522 class WhileStmt extends ASTNode implements Stmt, Serializable, LabelSet {
1523     const expr : Expr;
1524     const stmt : Stmt;
1525     const labels: [...IDENT];
1526     function WhileStmt (expr,stmt,labels=null)
1527         : expr = expr
1528         , stmt = stmt
1529         , labels = labels == null ? ([] : [...IDENT]) : labels {}
1531     function serialize(s)
1532         s.sClass(this, "WhileStmt", "expr", "stmt", "labels");
1535 class DoWhileStmt extends ASTNode implements Stmt, Serializable, LabelSet {
1536     const expr : Expr;
1537     const stmt : Stmt;
1538     const labels : [...IDENT];
1539     function DoWhileStmt (expr,stmt,labels=null)
1540         : expr = expr
1541         , stmt = stmt 
1542         , labels = labels == null ? ([] : [...IDENT]) : labels {}
1544     function serialize(s)
1545         s.sClass(this, "DoWhileStmt", "expr", "stmt", "labels");
1548 internal class ForStmtCore extends ASTNode implements Stmt, LabelSet {
1549     const init : ? Expr;
1550     const cond : ? Expr;
1551     const incr : ? Expr;
1552     const stmt : Stmt;
1553     const labels : [...IDENT];
1554     function ForStmtCore (init,cond,incr,stmt,labels=null)
1555         : init = init
1556         , cond = cond
1557         , incr = incr
1558         , stmt = stmt
1559         , labels = labels == null ? ([] : [...IDENT]) : labels {}
1562 class ForStmt extends ForStmtCore implements Serializable {
1563     function ForStmt (init,cond,incr,stmt,labels=null)
1564         : super(init, cond, incr, stmt, labels) {}
1566     function serialize(s)
1567         s.sClass(this, "ForStmt", "init", "cond", "incr", "stmt", "labels");
1570 class ForBindingStmt extends ForStmtCore implements Serializable {
1571     const head : Head;
1572     function ForBindingStmt (head,init,cond,incr,stmt,labels=null)
1573         : head = head
1574         , super(init, cond, incr, stmt, labels) {}
1576     function serialize(s)
1577         s.sClass(this, "ForBindingStmt", "head", "init", "cond", "incr", "stmt", "labels");
1580 class IfStmt extends ASTNode implements Stmt, Serializable {
1581     const test       : Expr;
1582     const consequent : Stmt;
1583     const alternate  : ? Stmt;
1584     function IfStmt (test, consequent, alternate)
1585         : test=test
1586         , consequent=consequent
1587         , alternate=alternate { }
1589     function serialize(s)
1590         s.sClass(this, "IfStmt", "test", "consequent", "alternate");
1593 class SwitchStmt extends ASTNode implements Stmt, Serializable {
1594     const head  : Head;
1595     const expr  : Expr;
1596     const cases : [...Case];
1597     function SwitchStmt (head, expr, cases)
1598         : head = head
1599         , expr = expr
1600         , cases = cases { }
1602     function serialize(s)
1603         s.sClass(this, "SwitchStmt", "head", "expr", "cases");
1606 class Case extends ASTNode implements Stmt, Serializable {
1607     const expr : ? Expr;  // null for default
1608     const stmts : [...Stmt];
1609     function Case (expr,stmts)
1610         : expr = expr
1611         , stmts = stmts { }
1613     function serialize(s)
1614         s.sClass(this, "Case", "expr", "stmts");
1617 class WithStmt extends ASTNode implements Stmt, Serializable {
1618     const expr : Expr;
1619     const stmt : Stmt;
1620     function WithStmt (expr,stmt)
1621         : expr = expr
1622         , stmt = stmt { }
1624     function serialize(s)
1625         s.sClass(this, "WithStmt", "expr", "stmt");
1628 class TryStmt extends ASTNode implements Stmt, Serializable {
1629     const block        : Block;
1630     const catches      : [...Catch];
1631     const finallyBlock : ? Block;
1632     function TryStmt (block,catches,finallyBlock)
1633         : block = block
1634         , catches = catches
1635         , finallyBlock = finallyBlock { }
1637     function serialize(s)
1638         s.sClass(this, "TryStmt", "block", "catches", "finallyBlock");
1641 class SwitchTypeStmt extends ASTNode implements Stmt, Serializable {
1642     const expr: Expr;
1643     const cases: [...Catch];
1644     function SwitchTypeStmt (expr,cases)
1645         : expr = expr
1646         , cases = cases { }
1648     function serialize(s)
1649         s.sClass(this, "SwitchTypeStmt", "expr", "cases");
1652 class Catch extends ASTNode implements Serializable {
1653     const param: Head;
1654     const block: Block;
1655     function Catch (param,block)
1656         : param = param
1657         , block = block { }
1659     function serialize(s)
1660         s.sClass(this, "Catch", "param", "block");
1663 class SuperStmt extends ASTNode implements Stmt, Serializable {
1664     const args  : [...Expr];
1665     const spread: ? Expr;
1666     function SuperStmt(args, spread) 
1667         : args=args
1668         , spread=spread {}
1670     function serialize(s)
1671         s.sClass(this, "SuperStmt", "args", "spread");
1674 class Block extends ASTNode implements Serializable {
1675     const head  : ? Head;
1676     const stmts : [...Stmt];
1677     function Block (head,stmts)
1678         : head = head
1679         , stmts = stmts { }
1681     function serialize(s) 
1682         s.sClass(this, "Block", "head", "stmts");
1686  * PROGRAM
1687  */
1689 class Program extends ASTNode implements Serializable {
1690     const body : [...Stmt];
1691     const head : Head;
1692     const file : ? String;
1693     const attr : FuncAttr;
1694     function Program (body, head, attr, file=null)
1695         : body = body
1696         , head = head
1697         , attr = attr
1698         , file = file {}
1700     function serialize(s)
1701         s.sClass(this, "Program", "body", "head", "attr", "file");
1704 /* Helper tables */
1706 const tokenToOperator = [];
1708 // Binary
1709 tokenToOperator[Token::Equal] = Ast::equalOp;
1710 tokenToOperator[Token::NotEqual] = Ast::notEqualOp;
1711 tokenToOperator[Token::StrictEqual] = Ast::strictEqualOp;
1712 tokenToOperator[Token::StrictNotEqual] = Ast::strictNotEqualOp;
1713 tokenToOperator[Token::LessThan] = Ast::lessOp;
1714 tokenToOperator[Token::GreaterThan] = Ast::greaterOp;
1715 tokenToOperator[Token::LessThanOrEqual] = Ast::lessOrEqualOp;
1716 tokenToOperator[Token::GreaterThanOrEqual] = Ast::greaterOrEqualOp;
1717 tokenToOperator[Token::In] = Ast::inOp;
1718 tokenToOperator[Token::InstanceOf] = Ast::instanceOfOp;
1719 tokenToOperator[Token::Is] = Ast::isOp;
1720 tokenToOperator[Token::Cast] = Ast::castOp;
1721 tokenToOperator[Token::Like] = Ast::likeOp;
1722 tokenToOperator[Token::LeftShift] = Ast::leftShiftOp;
1723 tokenToOperator[Token::RightShift] = Ast::rightShiftOp;
1724 tokenToOperator[Token::UnsignedRightShift] = Ast::rightShiftUnsignedOp;
1725 tokenToOperator[Token::Plus] = Ast::plusOp;
1726 tokenToOperator[Token::Minus] = Ast::minusOp;
1727 tokenToOperator[Token::Mult] = Ast::timesOp;
1728 tokenToOperator[Token::Div] = Ast::divideOp;
1729 tokenToOperator[Token::Remainder] = Ast::remainderOp;
1730 tokenToOperator[Token::Delete] = Ast::deleteOp;
1731 tokenToOperator[Token::Assign] = Ast::assignOp;
1732 tokenToOperator[Token::PlusAssign] = Ast::assignPlusOp;
1733 tokenToOperator[Token::MinusAssign] = Ast::assignMinusOp;
1734 tokenToOperator[Token::MultAssign] = Ast::assignTimesOp;
1735 tokenToOperator[Token::DivAssign] = Ast::assignDivideOp;
1736 tokenToOperator[Token::RemainderAssign] = Ast::assignRemainderOp;
1737 tokenToOperator[Token::BitwiseAndAssign] = Ast::assignBitwiseAndOp;
1738 tokenToOperator[Token::BitwiseOrAssign] = Ast::assignBitwiseOrOp;
1739 tokenToOperator[Token::BitwiseXorAssign] = Ast::assignBitwiseXorOp;
1740 tokenToOperator[Token::LeftShiftAssign] = Ast::assignLeftShiftOp;
1741 tokenToOperator[Token::RightShiftAssign] = Ast::assignRightShiftOp;
1742 tokenToOperator[Token::UnsignedRightShiftAssign] = Ast::assignRightShiftUnsignedOp;
1743 tokenToOperator[Token::LogicalAndAssign] = Ast::assignLogicalAndOp;
1744 tokenToOperator[Token::LogicalOrAssign] = Ast::assignLogicalOrOp;
1746 // Unary.
1747 tokenToOperator[Token::Delete + 1000] = Ast::deleteOp;
1748 tokenToOperator[Token::PlusPlus + 1000] = Ast::preIncrOp;
1749 tokenToOperator[Token::MinusMinus + 1000] = Ast::preDecrOp;
1750 tokenToOperator[Token::Void + 1000] = Ast::voidOp;
1751 tokenToOperator[Token::TypeOf + 1000] = Ast::typeOfOp;
1752 tokenToOperator[Token::Plus + 1000] = Ast::unaryPlusOp;
1753 tokenToOperator[Token::Minus + 1000] = Ast::unaryMinusOp;
1754 tokenToOperator[Token::BitwiseNot + 1000] = Ast::bitwiseNotOp;
1755 tokenToOperator[Token::Not + 1000] = Ast::logicalNotOp;
1757 //////////////////////////////////////////////////////////////////////
1759 // Serialization
1761 class Serializer {
1762     use default namespace internal, 
1763         namespace internal;
1765     var compact;
1767     public function Serializer(compact=false) : compact=compact {}
1769     public function serialize(obj) {
1770         if (obj is Serializable)
1771             return obj.serialize(this);
1773         if (obj is Array) 
1774             return serializeArray(obj, true);
1776         if (obj is Number || obj is Boolean || obj is int || obj is uint || obj === null || obj === undefined)
1777             return String(obj);
1779         if (obj is String)
1780             return "'" + sanitize(obj) + "'";
1782         //throw new Error("Unserializable datum " + obj);
1783         return "[[" + obj + "]]";
1784     }
1786     function serializeArray(obj, linebreak) {
1787         let s = "[";
1788         let separator = !compact && linebreak ? "\n," : ",";
1789         let lastWasOK = true;
1790         for ( let i=0, limit=obj.length ; i < limit ; i++ ) {
1791             lastWasOK = false;
1792             if (i > 0)
1793                 s += separator;
1794             if (obj.hasOwnProperty(i)) {
1795                 lastWasOK = true;
1796                 s += serialize(obj[i]);
1797             }
1798         }
1799         if (!lastWasOK)
1800             s += separator;
1801         s += "]";
1802         return s;
1803     }
1805     function sanitize(s) {
1806         let r = "";
1807         let i = 0;
1808         let l = s.length;
1809         outer:
1810         while (i < l) {
1811             let start = i;
1812             while (i < l) {
1813                 let c = s.charCodeAt(i);
1814                 if (c < 32 || 
1815                     c == Char::BackSlash || 
1816                     c == Char::SingleQuote || 
1817                     c == Char::DoubleQuote ||
1818                     c == Char::UnicodePS ||
1819                     c == Char::UnicodeLS) {
1820                     r += s.substring(start, i);
1821                     s += uescape(c);
1822                     i++;
1823                     continue outer;
1824                 }
1825                 i++;
1826             }
1827             r += s.substring(start, i);
1828         }
1829         return r;
1830     }
1832     function uescape(c)
1833         "\\u" + (c+0x10000).toString(16).substring(1);
1835     public function sClass(obj, ...rest) {
1836         // The 'ast_layout' is reduced to the class name the day 
1837         // Tamarin performs enumeration/itemization in insertion 
1838         // order.  If size concerns us (not likely) then we can
1839         // compress by maintaining an indexed dictionary of
1840         // layout arrays, which is emitted as part of the output.
1842         let sep0 = compact ? "" : "\n, ";
1843         let sep1 = compact ? "," : "\n, ";
1844         let s = "";
1845         if (compact)
1846             s += "{/*" + rest[0] + "*/ ";
1847         else
1848             s += "{ 'ast_layout': " + serializeArray(rest, false);
1849         for ( let i=1, limit=rest.length ; i < limit ; i++ ) {
1850             s += (i > 1 ? sep1 : sep0) + "'" + rest[i] + "': ";
1851             s += serialize(obj[rest[i]]);
1852         }
1853         s += "}";
1854         return s;
1855     }
1857     public function sConstant(expr)
1858         "{ 'ast_constant': '" + expr + "' }";
1861 // FIXME I:
1862 // The unserializer uses 'eval' for three things:
1863 //   - to decode the JSON input (dangerous)
1864 //   - to create constructor functions for classes
1865 //   - to look up global constant properties
1867 // The latter two could be gotten rid of by using 
1869 //    new Ast::[tag](...desc.map(decode))
1871 // and
1873 //    Ast::[constName]
1875 // respectively (if the serializer cooperates; right now the
1876 // constName expression is not a name so that wouldn't work), 
1877 // but for that we need bracket syntax and splat to work.
1879 // FIXME II:
1880 // The function 'globalEval' should be removed and invocations
1881 // of it should be replaced simply by 'global.eval', but that
1882 // requires a working notion of 'global' in tamarin.
1884 class Unserializer {
1885     use default namespace internal,
1886         namespace internal;
1888     public function unserializeText(s) 
1889         decode(globalEval("(" + s + ")"));
1891     public function unserializeObject(obj) 
1892         decode(obj);
1894     function decode(x) {
1895         if (x is Boolean || x is Number || x is int || x is uint || x is String)
1896             return x;
1898         if (x is Array) {
1899             for ( let i=0, limit=x.length ; i < limit ; i++ )
1900                 if (x.hasOwnProperty(i))
1901                     x[i] = decode(x[i]);
1902             return x;
1903         }
1905         if (x.hasOwnProperty("ast_layout")) {
1906             let desc = x.ast_layout;
1907             let tag = desc[0];
1908             desc.shift(1);
1909             return (getConstructor(tag, desc.length)).apply(null, Util::map(function (n) { return decode(x[n]) }, desc));
1910         }
1912         if (x.hasOwnProperty("ast_constant"))
1913             return globalEval(x.ast_constant);
1915         let s = "{ ";
1916         for ( let n in x )
1917             if (x.hasOwnProperty(n))
1918                 s += "'" + n + "': " + x[n];
1919         s += "}";
1920         throw new Error("Unknown datum type: object without a tag: " + s);
1921     }
1923     // A map from name to function that constructs instance of name.
1924     var constructors = {};
1926     function getConstructor(name, arity) {
1927         if (!constructors.hasOwnProperty(name)) {
1928             // FIXME: An array comprehension would be pretty here...
1929             let args = [];
1930             for ( let i=0 ; i < arity ; i++ )
1931                 args.push("_p" + i);
1932             constructors[name] = globalEval("(function (" + args + ") { return new Ast::" + name + "(" + args + ") })");
1933         }
1934         return constructors[name];
1935     }
1937     function globalEval(s)
1938         ESC::evaluateInScopeArray([s], [], "");