Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Re-worked js parser from the beginning

  • Loading branch information...
commit 459e9aaf654d7fc875fba2d3f75528141bc98f0c 1 parent 95436c8
Christopher Johnson authored October 06, 2011
9,396  lib/parser.js
5786 additions, 3610 deletions not shown
1,319  src/parser.pegjs
@@ -20,6 +20,16 @@
20 20
  * THE SOFTWARE.
21 21
  */
22 22
 
  23
+{
  24
+  function sourceToString() {
  25
+    return this.source;
  26
+  }
  27
+  
  28
+  function treeToString() {
  29
+    return this.left + this.source + this.right;
  30
+  }
  31
+}
  32
+
23 33
 Xjs
24 34
   = XjsElements
25 35
 
@@ -43,12 +53,12 @@ XjsLiteral
43 53
   }
44 54
 
45 55
 XjsCodeBlock
46  
-  = '<?' write:'='? js:script '?>'
  56
+  = '<?' write:'='? js:javascript '?>'
47 57
   {
48 58
     return {
49 59
       type: write ? 'write' : 'script',
50 60
       source: '<?' + write + js + '?>',
51  
-      script: js
  61
+      script: js.toString()
52 62
     }
53 63
   }
54 64
 
@@ -120,7 +130,7 @@ XmlAttributeValue
120 130
       return {
121 131
         type:'expression',
122 132
         source:'{' + expression + '}',
123  
-        script:expression
  133
+        script:expression.toString()
124 134
       };
125 135
     }
126 136
 
@@ -145,22 +155,6 @@ XmlPCDATA
145 155
     };
146 156
   }
147 157
 
148  
-script
149  
-  = script:(Comment / [^?] / '?' [^>])+
150  
-  {
151  
-    function cleanJoin(a) {
152  
-      if (typeof a === 'string') {
153  
-        return a;
154  
-      }
155  
-      var result = '';
156  
-      for (var i in a) {
157  
-        result += cleanJoin(a[i]);
158  
-      }
159  
-      return result;
160  
-    }
161  
-    
162  
-    return cleanJoin(script);
163  
-  }
164 158
 
165 159
 /*
166 160
  * JavaScript parser based on the grammar described in ECMA-262, 5th ed.
@@ -210,31 +204,9 @@ script
210 204
  */
211 205
 
212 206
 javascript
213  
-  = js:(__ Program __)
214  
-  {
215  
-    var result = [''];
216  
-    var marker = 0;
217  
-    
218  
-    cleanJoin(js);
219  
-    if (result.length === 1) {
220  
-      result = result[0];
221  
-    }
222  
-    return result;
223  
-    
224  
-    function cleanJoin(a) {
225  
-      for (var i in a) {
226  
-        if (typeof a[i] === 'string') {
227  
-          result[marker] += a[i];
228  
-        } else if (a[i].length !== undefined) {
229  
-          cleanJoin(a[i]);
230  
-        } else {
231  
-          marker++;
232  
-          result[marker] = a[i];
233  
-          marker++;
234  
-          result[marker] = '';
235  
-        }
236  
-      }
237  
-    }
  207
+  = w1:__ program:Program w2:__ {
  208
+    program.source = w1 + program.source + w2;
  209
+    return program;
238 210
   }
239 211
 
240 212
 /* ===== A.1 Lexical Grammar ===== */
@@ -253,7 +225,7 @@ LineTerminatorSequence "end of line"
253 225
   = "\n"
254 226
   / "\r\n"
255 227
   / "\r"
256  
-  / "\u2028" // line separator
  228
+  / "\u2028" // line spearator
257 229
   / "\u2029" // paragraph separator
258 230
 
259 231
 Comment "comment"
@@ -261,13 +233,19 @@ Comment "comment"
261 233
   / SingleLineComment
262 234
 
263 235
 MultiLineComment
264  
-  = "/*" (!"*/" SourceCharacter)* "*/"
  236
+  = "/*" comment:(!"*/" c:SourceCharacter { return c; })* "*/" {
  237
+      return "/*" + comment.join("") + "*/";
  238
+    }
265 239
 
266 240
 MultiLineCommentNoLineTerminator
267  
-  = "/*" (!("*/" / LineTerminator) SourceCharacter)* "*/"
  241
+  = "/*" comment:(!("*/" / LineTerminator) c:SourceCharacter { return c; })* "*/" {
  242
+      return "/*" + comment.join("") + "*/";
  243
+    }
268 244
 
269 245
 SingleLineComment
270  
-  = "//" (!(LineTerminator / '?>') SourceCharacter)*
  246
+  = "//" comment:(!("?>" / LineTerminator) c:SourceCharacter { return c; })* {
  247
+      return "//" + comment.join("");
  248
+    }
271 249
 
272 250
 Identifier "identifier"
273 251
   = !ReservedWord name:IdentifierName { return name; }
@@ -281,15 +259,15 @@ IdentifierStart
281 259
   = UnicodeLetter
282 260
   / "$"
283 261
   / "_"
284  
-  / "\\" UnicodeEscapeSequence
  262
+  / "\\" sequence:UnicodeEscapeSequence { return sequence; }
285 263
 
286 264
 IdentifierPart
287 265
   = IdentifierStart
288 266
   / UnicodeCombiningMark
289 267
   / UnicodeDigit
290 268
   / UnicodeConnectorPunctuation
291  
-  / "\u200C" // zero-width non-joiner
292  
-  / "\u200D" // zero-width joiner
  269
+  / "\u200C" { return "\u200C"; } // zero-width non-joiner
  270
+  / "\u200D" { return "\u200D"; } // zero-width joiner
293 271
 
294 272
 UnicodeLetter
295 273
   = Lu
@@ -365,16 +343,30 @@ FutureReservedWord
365 343
 Literal
366 344
   = NullLiteral
367 345
   / BooleanLiteral
368  
-  / NumericLiteral
369  
-  / StringLiteral
  346
+  / value:NumericLiteral {
  347
+      return {
  348
+        type:  "NumericLiteral",
  349
+        value: value,
  350
+        source: value,
  351
+        toString: sourceToString
  352
+      };
  353
+    }
  354
+  / value:StringLiteral {
  355
+      return {
  356
+        type:  "StringLiteral",
  357
+        value: value.value,
  358
+        source: value.source,
  359
+        toString: sourceToString
  360
+      };
  361
+    }
370 362
   / RegularExpressionLiteral
371 363
 
372 364
 NullLiteral
373  
-  = NullToken
  365
+  = NullToken { return { type: "NullLiteral", toString: function () { return "null"; } }; }
374 366
 
375 367
 BooleanLiteral
376  
-  = TrueToken
377  
-  / FalseToken
  368
+  = TrueToken  { return { type: "BooleanLiteral", value: true,  toString: function () { return "true"; }  }; }
  369
+  / FalseToken { return { type: "BooleanLiteral", value: false, toString: function () { return "false"; } }; }
378 370
 
379 371
 NumericLiteral "number"
380 372
   = literal:(HexIntegerLiteral / DecimalLiteral) !IdentifierStart {
@@ -419,14 +411,18 @@ SignedInteger
419 411
   = sign:[-+]? digits:DecimalDigits { return sign + digits; }
420 412
 
421 413
 HexIntegerLiteral
422  
-  = "0" x:[xX] digits:HexDigit+ { return "0" + x + dgits.join(""); }
  414
+  = "0" x:[xX] digits:HexDigit+ { return "0" + x + digits.join(""); }
423 415
 
424 416
 HexDigit
425 417
   = [0-9a-fA-F]
426 418
 
427 419
 StringLiteral "string"
428 420
   = parts:('"' DoubleStringCharacters? '"' / "'" SingleStringCharacters? "'") {
429  
-      return parts.join('');
  421
+      return {
  422
+        value: parts[1],
  423
+        source: parts.join(""),
  424
+        toString: sourceToString
  425
+      };
430 426
     }
431 427
 
432 428
 DoubleStringCharacters
@@ -450,7 +446,7 @@ LineContinuation
450 446
 
451 447
 EscapeSequence
452 448
   = CharacterEscapeSequence
453  
-  / "0" !DecimalDigit { return "0"; }
  449
+  / "0" !DecimalDigit { return "\0"; }
454 450
   / HexEscapeSequence
455 451
   / UnicodeEscapeSequence
456 452
 
@@ -459,7 +455,15 @@ CharacterEscapeSequence
459 455
   / NonEscapeCharacter
460 456
 
461 457
 SingleEscapeCharacter
462  
-  = ['"\\bfnrtv]
  458
+  = char_:['"\\bfnrtv] {
  459
+      return char_
  460
+        .replace("b", "\b")
  461
+        .replace("f", "\f")
  462
+        .replace("n", "\n")
  463
+        .replace("r", "\r")
  464
+        .replace("t", "\t")
  465
+        .replace("v", "\x0B") // IE does not recognize "\v".
  466
+    }
463 467
 
464 468
 NonEscapeCharacter
465 469
   = (!EscapeCharacter / LineTerminator) char_:SourceCharacter { return char_; }
@@ -472,17 +476,21 @@ EscapeCharacter
472 476
 
473 477
 HexEscapeSequence
474 478
   = "x" h1:HexDigit h2:HexDigit {
475  
-      return "x" + h1 + h2;
  479
+      return String.fromCharCode(parseInt("0x" + h1 + h2));
476 480
     }
477 481
 
478 482
 UnicodeEscapeSequence
479 483
   = "u" h1:HexDigit h2:HexDigit h3:HexDigit h4:HexDigit {
480  
-      return "u" + h1 + h2 + h3 + h4;
  484
+      return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4));
481 485
     }
482 486
 
483 487
 RegularExpressionLiteral "regular expression"
484 488
   = "/" body:RegularExpressionBody "/" flags:RegularExpressionFlags {
485  
-      return "/" + body + "/" + flags;
  489
+      return {
  490
+        type:  "RegularExpressionLiteral",
  491
+        body:  body,
  492
+        flags: flags
  493
+      };
486 494
     }
487 495
 
488 496
 RegularExpressionBody
@@ -611,16 +619,18 @@ Zs = [\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u
611 619
 /* Automatic Semicolon Insertion */
612 620
 
613 621
 EOS
614  
-  = __ ";"
615  
-  / _ LineTerminatorSequence
616  
-  / _ &"}"
617  
-  / __ EOF
  622
+  = w:__ ";"  { return w + ";"; }
  623
+  / w:_ term:LineTerminatorSequence { return w + term; }
  624
+  / w:_ &"}"  { return w; }
  625
+  / w:_ &"?>" { return w; }
  626
+  / w:__ EOF  { return w; }
618 627
 
619 628
 EOSNoLineTerminator
620  
-  = _ ";"
621  
-  / _ LineTerminatorSequence
622  
-  / _ &"}"
623  
-  / _ EOF
  629
+  = w:_ ";"   { return w + ";"; }
  630
+  / w:_ term:LineTerminatorSequence { return w + term; }
  631
+  / w:_ &"}"  { return w; }
  632
+  / w:_ &"?>" { return w; }
  633
+  / w:_ EOF   { return w; }
624 634
 
625 635
 EOF
626 636
   = !.
@@ -628,11 +638,10 @@ EOF
628 638
 /* Whitespace */
629 639
 
630 640
 _
631  
-  = w:(WhiteSpace / MultiLineCommentNoLineTerminator / SingleLineComment)*
632  
-  { return w.join(''); }
  641
+  = ws:(WhiteSpace / MultiLineCommentNoLineTerminator / SingleLineComment)* { return ws.join(""); }
633 642
 
634 643
 __
635  
-  = (WhiteSpace / LineTerminatorSequence / Comment)*
  644
+  = ws:(WhiteSpace / LineTerminatorSequence / Comment)* { return ws.join(""); }
636 645
 
637 646
 /* ===== A.2 Number Conversions ===== */
638 647
 
@@ -644,39 +653,102 @@ __
644 653
 /* ===== A.3 Expressions ===== */
645 654
 
646 655
 PrimaryExpression
647  
-  = ThisToken
648  
-  / Identifier
  656
+  = ThisToken       { return { type: "This", toString: function () { return "this"; } }; }
  657
+  / name:Identifier { return { type: "Variable", name: name, toString: function () { return this.name; } }; }
649 658
   / Literal
650 659
   / ArrayLiteral
651 660
   / ObjectLiteral
652  
-  / XjsLiteral
653  
-  / "(" __ Expression __ ")"
  661
+  / "(" w1:__ expression:Expression w2:__ ")" {
  662
+      return {
  663
+        expression: expression,
  664
+        source:     "(" + w1 + expression + w2 + ")",
  665
+        toString:   sourceToString
  666
+      };
  667
+    }
654 668
 
655 669
 ArrayLiteral
656  
-  = "[" __ ElementList? __ (Elision __)? "]"
  670
+  = "[" w1:__ elements:ElementList? w2:__ elision:(e:Elision w:__ { return e + w; })? "]" {
  671
+      elements = elements !== "" ? elements : [];
  672
+      return {
  673
+        type:     "ArrayLiteral",
  674
+        elements: elements,
  675
+        source:   "[" + w1 + elements + w2 + elision + "]",
  676
+        toString: sourceToString
  677
+      };
  678
+    }
657 679
 
658 680
 ElementList
659 681
   = (Elision __)?
660  
-    AssignmentExpression
661  
-    (__ "," __ Elision? __ AssignmentExpression)*
  682
+    head:AssignmentExpression
  683
+    tail:(__ "," __ Elision? __ AssignmentExpression)* {
  684
+      var result = [head];
  685
+      result.source = head.toString();
  686
+      for (var i = 0; i < tail.length; i++) {
  687
+        result.push(tail[i][5]);
  688
+        result.source += tail[i].join("");
  689
+      }
  690
+      result.toString = sourceToString;
  691
+      return result;
  692
+    }
662 693
 
663 694
 Elision
664  
-  = "," (__ ",")*
  695
+  = "," elision:(w:__ "," { return w + ","; })* { return "," + elision.join(""); }
665 696
 
666 697
 ObjectLiteral
667  
-  = "{" __ (PropertyNameAndValueList __ ("," __)?)? "}"
  698
+  = "{" w:__ properties:(PropertyNameAndValueList __ ("," w:__ { return "," + w; })?)? "}" {
  699
+      return {
  700
+        type:       "ObjectLiteral",
  701
+        properties: properties !== "" ? properties[0] : [],
  702
+        source: "{" + w + properties.join("") + "}",
  703
+        toString: sourceToString
  704
+      };
  705
+    }
668 706
 
669 707
 PropertyNameAndValueList
670  
-  = PropertyAssignment (__ "," __ PropertyAssignment)*
  708
+  = head:PropertyAssignment tail:(__ "," __ PropertyAssignment)* {
  709
+      var result = [head];
  710
+      result.source = head.toString();
  711
+      for (var i = 0; i < tail.length; i++) {
  712
+        result.push(tail[i][3]);
  713
+        result.source += tail[i].join("");
  714
+      }
  715
+      result.toString = sourceToString;
  716
+      return result;
  717
+    }
671 718
 
672 719
 PropertyAssignment
673  
-  = PropertyName __ ":" __ AssignmentExpression
674  
-  / GetToken __ PropertyName __
675  
-    "(" __ ")" __
676  
-    "{" __ FunctionBody __ "}"
677  
-  / SetToken __ PropertyName __
678  
-    "(" __ PropertySetParameterList __ ")" __
679  
-    "{" __ FunctionBody __ "}"
  720
+  = name:PropertyName w1:__ ":" w2:__ value:AssignmentExpression {
  721
+      return {
  722
+        type:  "PropertyAssignment",
  723
+        name:  name,
  724
+        value: value,
  725
+        source: name + w1 + ":" + w2 + value,
  726
+        toString: sourceToString
  727
+      };
  728
+    }
  729
+  / GetToken w1:__ name:PropertyName w2:__
  730
+    "(" w3:__ ")" w4:__
  731
+    "{" w5:__ body:FunctionBody w6:__ "}" {
  732
+      return {
  733
+        type: "GetterDefinition",
  734
+        name: name,
  735
+        body: body,
  736
+        source: "get" + w1 + name + w2 + "(" + w3 + ")" + w4 + "{" + w5 + body + w6 + "}",
  737
+        toString: sourceToString
  738
+      };
  739
+    }
  740
+  / SetToken w1:__ name:PropertyName w2:__
  741
+    "(" w3:__ param:PropertySetParameterList w4:__ ")" w5:__
  742
+    "{" w6:__ body:FunctionBody w7:__ "}" {
  743
+      return {
  744
+        type:  "SetterDefinition",
  745
+        name:  name,
  746
+        param: param,
  747
+        body:  body,
  748
+        source: "set" + w1 + name + w2 + "(" + w3 + param + w4 + ")" + w5 + "{" + w6 + body + w7 + "}",
  749
+        toString: sourceToString
  750
+      };
  751
+    }
680 752
 
681 753
 PropertyName
682 754
   = IdentifierName
@@ -687,42 +759,157 @@ PropertySetParameterList
687 759
   = Identifier
688 760
 
689 761
 MemberExpression
690  
-  = (
  762
+  = base:(
691 763
         PrimaryExpression
692 764
       / FunctionExpression
693  
-      / NewToken __ MemberExpression __ Arguments
  765
+      / NewToken __ constructor:MemberExpression __ arguments:Arguments {
  766
+          return {
  767
+            type:        "NewOperator",
  768
+            constructor: constructor,
  769
+            arguments:   arguments,
  770
+            source:      "new" + w1 + constructor + w2 + arguments,
  771
+            toString:    sourceToString
  772
+          };
  773
+        }
694 774
     )
695  
-    (
696  
-        __ "[" __ Expression __ "]"
697  
-      / __ "." __ IdentifierName
698  
-    )*
  775
+    accessors:(
  776
+        w1:__ "[" w2:__ name:Expression w3:__ "]" {
  777
+          return {
  778
+            name: name,
  779
+            source: w1 + "[" + w2 + name + w3 + "]"
  780
+          };
  781
+        }
  782
+      / w1:__ "." w2:__ name:IdentifierName    {
  783
+          return {
  784
+            name: name,
  785
+            source: w1 + "." + w2 + name
  786
+          };
  787
+        }
  788
+    )* {
  789
+      var result = base;
  790
+      for (var i = 0; i < accessors.length; i++) {
  791
+        result = {
  792
+          type: "PropertyAccess",
  793
+          base: result,
  794
+          name: accessors[i].name,
  795
+          source: accessors[i].source,
  796
+          toString: function () { return this.base.toString() + this.source }
  797
+        };
  798
+      }
  799
+      return result;
  800
+    }
699 801
 
700 802
 NewExpression
701 803
   = MemberExpression
702  
-  / NewToken __ NewExpression
  804
+  / NewToken __ constructor:NewExpression {
  805
+      return {
  806
+        type:        "NewOperator",
  807
+        constructor: constructor,
  808
+        arguments:   []
  809
+      };
  810
+    }
703 811
 
704 812
 CallExpression
705  
-  = (
706  
-      MemberExpression __ Arguments
  813
+  = base:(
  814
+      name:MemberExpression w:__ arguments:Arguments {
  815
+        return {
  816
+          type:      "FunctionCall",
  817
+          name:      name,
  818
+          arguments: arguments,
  819
+          source:    name + w + arguments,
  820
+          toString:  sourceToString
  821
+        };
  822
+      }
707 823
     )
708  
-    (
709  
-        __ Arguments
710  
-      / __ "[" __ Expression __ "]"
711  
-      / __ "." __ IdentifierName
712  
-    )*
  824
+    argumentsOrAccessors:(
  825
+        w:__ arguments:Arguments {
  826
+          return {
  827
+            type:      "FunctionCallArguments",
  828
+            arguments: arguments,
  829
+            source: w + arguments,
  830
+            toString: sourceToString
  831
+          };
  832
+        }
  833
+      / w1:__ "[" w2:__ name:Expression w3:__ "]" {
  834
+          return {
  835
+            type: "PropertyAccessProperty",
  836
+            name: name,
  837
+            source: w1 + "[" + w2 + name + w3 + "]",
  838
+            toString: sourceToString
  839
+          };
  840
+        }
  841
+      / w1:__ "." w2:__ name:IdentifierName {
  842
+          return {
  843
+            type: "PropertyAccessProperty",
  844
+            name: name,
  845
+            source: w1 + "." + w2 + name,
  846
+            toString: sourceToString
  847
+          };
  848
+        }
  849
+    )* {
  850
+      var result = base;
  851
+      for (var i = 0; i < argumentsOrAccessors.length; i++) {
  852
+        switch (argumentsOrAccessors[i].type) {
  853
+          case "FunctionCallArguments":
  854
+            result = {
  855
+              type:      "FunctionCall",
  856
+              name:      result,
  857
+              arguments: argumentsOrAccessors[i].arguments,
  858
+              toString:  function () { return this.name.toString() + this.source; }
  859
+            };
  860
+            break;
  861
+          case "PropertyAccessProperty":
  862
+            result = {
  863
+              type: "PropertyAccess",
  864
+              base: result,
  865
+              name: argumentsOrAccessors[i].name,
  866
+              toString: function () { return this.base.toString() + this.source; }
  867
+            };
  868
+            break;
  869
+          default:
  870
+            throw new Error(
  871
+              "Invalid expression type: " + argumentsOrAccessors[i].type
  872
+            );
  873
+        }
  874
+        result.source = argumentsOrAccessors[i].source;
  875
+      }
  876
+      return result;
  877
+    }
713 878
 
714 879
 Arguments
715  
-  = "(" __ ArgumentList? __ ")"
  880
+  = "(" w1:__ list:ArgumentList? w2:__ ")" {
  881
+    arguments = list !== "" ? list : [];
  882
+    arguments.source = "(" + w1 + list.toString() + w2 + ")";
  883
+    arguments.toString = sourceToString;
  884
+    return arguments;
  885
+  }
716 886
 
717 887
 ArgumentList
718  
-  = AssignmentExpression (__ "," __ AssignmentExpression)*
  888
+  = head:AssignmentExpression tail:(__ "," __ AssignmentExpression)* {
  889
+    var result = [head];
  890
+    result.source = head;
  891
+    for (var i = 0; i < tail.length; i++) {
  892
+      result.push(tail[i][3]);
  893
+      result.source += tail[i].join("");
  894
+    }
  895
+    result.toString = sourceToString;
  896
+    return result;
  897
+  }
719 898
 
720 899
 LeftHandSideExpression
721 900
   = CallExpression
722 901
   / NewExpression
723 902
 
724 903
 PostfixExpression
725  
-  = LeftHandSideExpression _ PostfixOperator
  904
+  = expression:LeftHandSideExpression w:_ operator:PostfixOperator {
  905
+      return {
  906
+        type:       "PostfixExpression",
  907
+        operator:   operator,
  908
+        expression: expression,
  909
+        source:     expression + w + operator,
  910
+        toString:   sourceToString
  911
+      };
  912
+    }
726 913
   / LeftHandSideExpression
727 914
 
728 915
 PostfixOperator
@@ -731,7 +918,15 @@ PostfixOperator
731 918
 
732 919
 UnaryExpression
733 920
   = PostfixExpression
734  
-  / UnaryOperator __ UnaryExpression
  921
+  / operator:UnaryOperator w:__ expression:UnaryExpression {
  922
+      return {
  923
+        type:       "UnaryExpression",
  924
+        operator:   operator,
  925
+        expression: expression,
  926
+        source:     operator + w + expression,
  927
+        toString:   sourceToString
  928
+      };
  929
+    }
735 930
 
736 931
 UnaryOperator
737 932
   = DeleteToken
@@ -745,23 +940,62 @@ UnaryOperator
745 940
   /  "!"
746 941
 
747 942
 MultiplicativeExpression
748  
-  = UnaryExpression
749  
-    (__ MultiplicativeOperator __ UnaryExpression)*
  943
+  = head:UnaryExpression
  944
+    tail:(__ MultiplicativeOperator __ UnaryExpression)* {
  945
+      var result = head;
  946
+      for (var i = 0; i < tail.length; i++) {
  947
+        result = {
  948
+          type:     "BinaryExpression",
  949
+          operator: tail[i][1],
  950
+          left:     result,
  951
+          right:    tail[i][3],
  952
+          source:   tail[i].slice(0, 3).join(""),
  953
+          toString: treeToString
  954
+        };
  955
+      }
  956
+      return result;
  957
+    }
750 958
 
751 959
 MultiplicativeOperator
752  
-  = ("*" / "/" / "%") !"=" { return operator; }
  960
+  = operator:("*" / "/" / "%") !"=" { return operator; }
753 961
 
754 962
 AdditiveExpression
755  
-  = MultiplicativeExpression
756  
-    (__ AdditiveOperator __ MultiplicativeExpression)*
  963
+  = head:MultiplicativeExpression
  964
+    tail:(__ AdditiveOperator __ MultiplicativeExpression)* {
  965
+      var result = head;
  966
+      for (var i = 0; i < tail.length; i++) {
  967
+        result = {
  968
+          type:     "BinaryExpression",
  969
+          operator: tail[i][1],
  970
+          left:     result,
  971
+          right:    tail[i][3],
  972
+          source:   tail[i].slice(0, 3).join(""),
  973
+          toString: treeToString
  974
+        };
  975
+      }
  976
+      return result;
  977
+    }
757 978
 
758 979
 AdditiveOperator
759 980
   = "+" !("+" / "=") { return "+"; }
760 981
   / "-" !("-" / "=") { return "-"; }
761 982
 
762 983
 ShiftExpression
763  
-  = AdditiveExpression
764  
-    (__ ShiftOperator __ AdditiveExpression)*
  984
+  = head:AdditiveExpression
  985
+    tail:(__ ShiftOperator __ AdditiveExpression)* {
  986
+      var result = head;
  987
+      for (var i = 0; i < tail.length; i++) {
  988
+        result = {
  989
+          type:     "BinaryExpression",
  990
+          operator: tail[i][1],
  991
+          left:     result,
  992
+          right:    tail[i][3],
  993
+          source:   tail[i].slice(0, 3).join(""),
  994
+          toString: treeToString
  995
+        };
  996
+      }
  997
+      return result;
  998
+    }
765 999
 
766 1000
 ShiftOperator
767 1001
   = "<<"
@@ -769,8 +1003,21 @@ ShiftOperator
769 1003
   / ">>"
770 1004
 
771 1005
 RelationalExpression
772  
-  = ShiftExpression
773  
-    (__ RelationalOperator __ ShiftExpression)*
  1006
+  = head:ShiftExpression
  1007
+    tail:(__ RelationalOperator __ ShiftExpression)* {
  1008
+      var result = head;
  1009
+      for (var i = 0; i < tail.length; i++) {
  1010
+        result = {
  1011
+          type:     "BinaryExpression",
  1012
+          operator: tail[i][1],
  1013
+          left:     result,
  1014
+          right:    tail[i][3],
  1015
+          source:   tail[i].slice(0, 3).join(""),
  1016
+          toString: treeToString
  1017
+        };
  1018
+      }
  1019
+      return result;
  1020
+    }
774 1021
 
775 1022
 RelationalOperator
776 1023
   = "<="
@@ -781,8 +1028,21 @@ RelationalOperator
781 1028
   / InToken
782 1029
 
783 1030
 RelationalExpressionNoIn
784  
-  = ShiftExpression
785  
-    (__ RelationalOperatorNoIn __ ShiftExpression)*
  1031
+  = head:ShiftExpression
  1032
+    tail:(__ RelationalOperatorNoIn __ ShiftExpression)* {
  1033
+      var result = head;
  1034
+      for (var i = 0; i < tail.length; i++) {
  1035
+        result = {
  1036
+          type:     "BinaryExpression",
  1037
+          operator: tail[i][1],
  1038
+          left:     result,
  1039
+          right:    tail[i][3],
  1040
+          source:   tail[i].slice(0, 3).join(""),
  1041
+          toString: treeToString
  1042
+        };
  1043
+      }
  1044
+      return result;
  1045
+    }
786 1046
 
787 1047
 RelationalOperatorNoIn
788 1048
   = "<="
@@ -792,12 +1052,38 @@ RelationalOperatorNoIn
792 1052
   / InstanceofToken
793 1053
 
794 1054
 EqualityExpression
795  
-  = RelationalExpression
796  
-    (__ EqualityOperator __ RelationalExpression)*
  1055
+  = head:RelationalExpression
  1056
+    tail:(__ EqualityOperator __ RelationalExpression)* {
  1057
+      var result = head;
  1058
+      for (var i = 0; i < tail.length; i++) {
  1059
+        result = {
  1060
+          type:     "BinaryExpression",
  1061
+          operator: tail[i][1],
  1062
+          left:     result,
  1063
+          right:    tail[i][3],
  1064
+          source:   tail[i].slice(0, 3).join(""),
  1065
+          toString: treeToString
  1066
+        };
  1067
+      }
  1068
+      return result;
  1069
+    }
797 1070
 
798 1071
 EqualityExpressionNoIn
799  
-  = RelationalExpressionNoIn
800  
-    (__ EqualityOperator __ RelationalExpressionNoIn)*
  1072
+  = head:RelationalExpressionNoIn
  1073
+    tail:(__ EqualityOperator __ RelationalExpressionNoIn)* {
  1074
+      var result = head;
  1075
+      for (var i = 0; i < tail.length; i++) {
  1076
+        result = {
  1077
+          type:     "BinaryExpression",
  1078
+          operator: tail[i][1],
  1079
+          left:     result,
  1080
+          right:    tail[i][3],
  1081
+          source:   tail[i].slice(0, 3).join(""),
  1082
+          toString: treeToString
  1083
+        };
  1084
+      }
  1085
+      return result;
  1086
+    }
801 1087
 
802 1088
 EqualityOperator
803 1089
   = "==="
@@ -806,82 +1092,248 @@ EqualityOperator
806 1092
   / "!="
807 1093
 
808 1094
 BitwiseANDExpression
809  
-  = EqualityExpression
810  
-    (__ BitwiseANDOperator __ EqualityExpression)*
  1095
+  = head:EqualityExpression
  1096
+    tail:(__ BitwiseANDOperator __ EqualityExpression)* {
  1097
+      var result = head;
  1098
+      for (var i = 0; i < tail.length; i++) {
  1099
+        result = {
  1100
+          type:     "BinaryExpression",
  1101
+          operator: tail[i][1],
  1102
+          left:     result,
  1103
+          right:    tail[i][3],
  1104
+          source:   tail[i].slice(0, 3).join(""),
  1105
+          toString: treeToString
  1106
+        };
  1107
+      }
  1108
+      return result;
  1109
+    }
811 1110
 
812 1111
 BitwiseANDExpressionNoIn
813  
-  = EqualityExpressionNoIn
814  
-    (__ BitwiseANDOperator __ EqualityExpressionNoIn)*
  1112
+  = head:EqualityExpressionNoIn
  1113
+    tail:(__ BitwiseANDOperator __ EqualityExpressionNoIn)* {
  1114
+      var result = head;
  1115
+      for (var i = 0; i < tail.length; i++) {
  1116
+        result = {
  1117
+          type:     "BinaryExpression",
  1118
+          operator: tail[i][1],
  1119
+          left:     result,
  1120
+          right:    tail[i][3],
  1121
+          source:   tail[i].slice(0, 3).join(""),
  1122
+          toString: treeToString
  1123
+        };
  1124
+      }
  1125
+      return result;
  1126
+    }
815 1127
 
816 1128
 BitwiseANDOperator
817 1129
   = "&" !("&" / "=") { return "&"; }
818 1130
 
819 1131
 BitwiseXORExpression
820  
-  = BitwiseANDExpression
821  
-    (__ BitwiseXOROperator __ BitwiseANDExpression)*
  1132
+  = head:BitwiseANDExpression
  1133
+    tail:(__ BitwiseXOROperator __ BitwiseANDExpression)* {
  1134
+      var result = head;
  1135
+      for (var i = 0; i < tail.length; i++) {
  1136
+        result = {
  1137
+          type:     "BinaryExpression",
  1138
+          operator: tail[i][1],
  1139
+          left:     result,
  1140
+          right:    tail[i][3],
  1141
+          source:   tail[i].slice(0, 3).join(""),
  1142
+          toString: treeToString
  1143
+        };
  1144
+      }
  1145
+      return result;
  1146
+    }
822 1147
 
823 1148
 BitwiseXORExpressionNoIn
824  
-  = BitwiseANDExpressionNoIn
825  
-    (__ BitwiseXOROperator __ BitwiseANDExpressionNoIn)*
  1149
+  = head:BitwiseANDExpressionNoIn
  1150
+    tail:(__ BitwiseXOROperator __ BitwiseANDExpressionNoIn)* {
  1151
+      var result = head;
  1152
+      for (var i = 0; i < tail.length; i++) {
  1153
+        result = {
  1154
+          type:     "BinaryExpression",
  1155
+          operator: tail[i][1],
  1156
+          left:     result,
  1157
+          right:    tail[i][3],
  1158
+          source:   tail[i].slice(0, 3).join(""),
  1159
+          toString: treeToString
  1160
+        };
  1161
+      }
  1162
+      return result;
  1163
+    }
826 1164
 
827 1165
 BitwiseXOROperator
828 1166
   = "^" !("^" / "=") { return "^"; }
829 1167
 
830 1168
 BitwiseORExpression
831  
-  = BitwiseXORExpression
832  
-    (__ BitwiseOROperator __ BitwiseXORExpression)*
  1169
+  = head:BitwiseXORExpression
  1170
+    tail:(__ BitwiseOROperator __ BitwiseXORExpression)* {
  1171
+      var result = head;
  1172
+      for (var i = 0; i < tail.length; i++) {
  1173
+        result = {
  1174
+          type:     "BinaryExpression",
  1175
+          operator: tail[i][1],
  1176
+          left:     result,
  1177
+          right:    tail[i][3],
  1178
+          source:   tail[i].slice(0, 3).join(""),
  1179
+          toString: treeToString
  1180
+        };
  1181
+      }
  1182
+      return result;
  1183
+    }
833 1184
 
834 1185
 BitwiseORExpressionNoIn
835  
-  = BitwiseXORExpressionNoIn
836  
-    (__ BitwiseOROperator __ BitwiseXORExpressionNoIn)*
  1186
+  = head:BitwiseXORExpressionNoIn
  1187
+    tail:(__ BitwiseOROperator __ BitwiseXORExpressionNoIn)* {
  1188
+      var result = head;
  1189
+      for (var i = 0; i < tail.length; i++) {
  1190
+        result = {
  1191
+          type:     "BinaryExpression",
  1192
+          operator: tail[i][1],
  1193
+          left:     result,
  1194
+          right:    tail[i][3],
  1195
+          source:   tail[i].slice(0, 3).join(""),
  1196
+          toString: treeToString
  1197
+        };
  1198
+      }
  1199
+      return result;
  1200
+    }
837 1201
 
838 1202
 BitwiseOROperator
839 1203
   = "|" !("|" / "=") { return "|"; }
840 1204
 
841 1205
 LogicalANDExpression
842  
-  = BitwiseORExpression
843  
-    (__ LogicalANDOperator __ BitwiseORExpression)*
  1206
+  = head:BitwiseORExpression
  1207
+    tail:(__ LogicalANDOperator __ BitwiseORExpression)* {
  1208
+      var result = head;
  1209
+      for (var i = 0; i < tail.length; i++) {
  1210
+        result = {
  1211
+          type:     "BinaryExpression",
  1212
+          operator: tail[i][1],
  1213
+          left:     result,
  1214
+          right:    tail[i][3],
  1215
+          source:   tail[i].slice(0, 3).join(""),
  1216
+          toString: treeToString
  1217
+        };
  1218
+      }
  1219
+      return result;
  1220
+    }
844 1221
 
845 1222
 LogicalANDExpressionNoIn
846  
-  = BitwiseORExpressionNoIn
847  
-    (__ LogicalANDOperator __ BitwiseORExpressionNoIn)*
  1223
+  = head:BitwiseORExpressionNoIn
  1224
+    tail:(__ LogicalANDOperator __ BitwiseORExpressionNoIn)* {
  1225
+      var result = head;
  1226
+      for (var i = 0; i < tail.length; i++) {
  1227
+        result = {
  1228
+          type:     "BinaryExpression",
  1229
+          operator: tail[i][1],
  1230
+          left:     result,
  1231
+          right:    tail[i][3],
  1232
+          source:   tail[i].slice(0, 3).join(""),
  1233
+          toString: treeToString
  1234
+        };
  1235
+      }
  1236
+      return result;
  1237
+    }
848 1238
 
849 1239
 LogicalANDOperator
850 1240
   = "&&" !"=" { return "&&"; }
851 1241
 
852 1242
 LogicalORExpression
853  
-  = LogicalANDExpression
854  
-    (__ LogicalOROperator __ LogicalANDExpression)*
  1243
+  = head:LogicalANDExpression
  1244
+    tail:(__ LogicalOROperator __ LogicalANDExpression)* {
  1245
+      var result = head;
  1246
+      for (var i = 0; i < tail.length; i++) {
  1247
+        result = {
  1248
+          type:     "BinaryExpression",
  1249
+          operator: tail[i][1],
  1250
+          left:     result,
  1251
+          right:    tail[i][3],
  1252
+          source:   tail[i].slice(0, 3).join(""),
  1253
+          toString: treeToString
  1254
+        };
  1255
+      }
  1256
+      return result;
  1257
+    }
855 1258
 
856 1259
 LogicalORExpressionNoIn
857  
-  = LogicalANDExpressionNoIn
858  
-    (__ LogicalOROperator __ LogicalANDExpressionNoIn)*
  1260
+  = head:LogicalANDExpressionNoIn
  1261
+    tail:(__ LogicalOROperator __ LogicalANDExpressionNoIn)* {
  1262
+      var result = head;
  1263
+      for (var i = 0; i < tail.length; i++) {
  1264
+        result = {
  1265
+          type:     "BinaryExpression",
  1266
+          operator: tail[i][1],
  1267
+          left:     result,
  1268
+          right:    tail[i][3],
  1269
+          source:   tail[i].slice(0, 3).join(""),
  1270
+          toString: treeToString
  1271
+        };
  1272
+      }
  1273
+      return result;
  1274
+    }
859 1275
 
860 1276
 LogicalOROperator
861 1277
   = "||" !"=" { return "||"; }
862 1278
 
863 1279
 ConditionalExpression
864  
-  = LogicalORExpression __
865  
-    "?" __ AssignmentExpression __
866  
-    ":" __ AssignmentExpression
  1280
+  = condition:LogicalORExpression w1:__
  1281
+    "?" w2:__ trueExpression:AssignmentExpression w3:__
  1282
+    ":" w4:__ falseExpression:AssignmentExpression {
  1283
+      return {
  1284
+        type:            "ConditionalExpression",
  1285
+        condition:       condition,
  1286
+        trueExpression:  trueExpression,
  1287
+        falseExpression: falseExpression,
  1288
+        source:          condition + w1 + "?" + w2 + trueExpression + w3 + ":" + w4 + falseExpression,
  1289
+        toString:        sourceToString
  1290
+      };
  1291
+    }
867 1292
   / LogicalORExpression
868 1293
 
869 1294
 ConditionalExpressionNoIn
870  
-  = LogicalORExpressionNoIn __
871  
-    "?" __ AssignmentExpressionNoIn __
872  
-    ":" __ AssignmentExpressionNoIn
  1295
+  = condition:LogicalORExpressionNoIn w1:__
  1296
+    "?" w2:__ trueExpression:AssignmentExpressionNoIn w3:__
  1297
+    ":" w4:__ falseExpression:AssignmentExpressionNoIn {
  1298
+      return {
  1299
+        type:            "ConditionalExpression",
  1300
+        condition:       condition,
  1301
+        trueExpression:  trueExpression,
  1302
+        falseExpression: falseExpression,
  1303
+        source:          condition + w1 + "?" + w2 + trueExpression + w3 + ":" + w4 + falseExpression,
  1304
+        toString:        sourceToString
  1305
+      };
  1306
+    }
873 1307
   / LogicalORExpressionNoIn
874 1308
 
875 1309
 AssignmentExpression
876  
-  = LeftHandSideExpression __
877  
-    AssignmentOperator __
878  
-    AssignmentExpression
  1310
+  = left:LeftHandSideExpression w1:__
  1311
+    operator:AssignmentOperator w2:__
  1312
+    right:AssignmentExpression {
  1313
+      return {
  1314
+        type:     "AssignmentExpression",
  1315
+        operator: operator,
  1316
+        left:     left,
  1317
+        right:    right,
  1318
+        source:   left + w1 + operator + w2 + right,
  1319
+        toString: sourceToString
  1320
+      };
  1321
+    }
879 1322
   / ConditionalExpression
880 1323
 
881 1324
 AssignmentExpressionNoIn
882  
-  = LeftHandSideExpression __
883  
-    AssignmentOperator __
884  
-    AssignmentExpressionNoIn
  1325
+  = left:LeftHandSideExpression w1:__
  1326
+    operator:AssignmentOperator w2:__
  1327
+    right:AssignmentExpressionNoIn {
  1328
+      return {
  1329
+        type:     "AssignmentExpression",
  1330
+        operator: operator,
  1331
+        left:     left,
  1332
+        right:    right,
  1333
+        source:   left + w1 + operator + w2 + right,
  1334
+        toString: sourceToString
  1335
+      };
  1336
+    }
885 1337
   / ConditionalExpressionNoIn
886 1338
 
887 1339
 AssignmentOperator
@@ -899,12 +1351,38 @@ AssignmentOperator
899 1351
   / "|="
900 1352
 
901 1353
 Expression
902  
-  = AssignmentExpression
903  
-    (__ "," __ AssignmentExpression)*
  1354
+  = head:AssignmentExpression
  1355
+    tail:(__ "," __ AssignmentExpression)* {
  1356
+      var result = head;
  1357
+      for (var i = 0; i < tail.length; i++) {
  1358
+        result = {
  1359
+          type:     "BinaryExpression",
  1360
+          operator: tail[i][1],
  1361
+          left:     result,
  1362
+          right:    tail[i][3],
  1363
+          source:   tail[i].slice(0, 3).join(""),
  1364
+          toString: treeToString
  1365
+        };
  1366
+      }
  1367
+      return result;
  1368
+    }
904 1369
 
905 1370
 ExpressionNoIn
906  
-  = AssignmentExpressionNoIn
907  
-    (__ "," __ AssignmentExpressionNoIn)*
  1371
+  = head:AssignmentExpressionNoIn
  1372
+    tail:(__ "," __ AssignmentExpressionNoIn)* {
  1373
+      var result = head;
  1374
+      for (var i = 0; i < tail.length; i++) {
  1375
+        result = {
  1376
+          type:     "BinaryExpression",
  1377
+          operator: tail[i][1],
  1378
+          left:     result,
  1379
+          right:    tail[i][3],
  1380
+          source:   tail[i].slice(0, 3).join(""),
  1381
+          toString: treeToString
  1382
+        };
  1383
+      }
  1384
+      return result;
  1385
+    }
908 1386
 
909 1387
 /* ===== A.4 Statements ===== */
910 1388
 
@@ -933,43 +1411,128 @@ Statement
933 1411
   / FunctionExpression
934 1412
 
935 1413
 Block
936  
-  = "{" __ (StatementList __)? "}"
  1414
+  = "{" w1:__ statements:(StatementList __)? "}" {
  1415
+      return {
  1416
+        type:       "Block",
  1417
+        statements: statements !== "" ? statements[0] : [],
  1418
+        source:     "{" + w1 + statements.join("") + "}",
  1419
+        toString:   sourceToString
  1420
+      };
  1421
+    }
937 1422
 
938 1423
 StatementList
939  
-  = Statement (__ Statement)*
  1424
+  = head:Statement tail:(__ Statement)* {
  1425
+      var result = [head];
  1426
+      result.source = head.toString();
  1427
+      for (var i = 0; i < tail.length; i++) {
  1428
+        result.push(tail[i][1]);
  1429
+        result.source += tail[i].join("");
  1430
+      }
  1431
+      result.toString = sourceToString;
  1432
+      return result;
  1433
+    }
940 1434
 
941 1435
 VariableStatement
942  
-  = VarToken __ VariableDeclarationList EOS
  1436
+  = VarToken w:__ declarations:VariableDeclarationList eos:EOS {
  1437
+      return {
  1438
+        type:         "VariableStatement",
  1439
+        declarations: declarations,
  1440
+        source:       "var" + w + declarations.source + eos,
  1441
+        toString:     sourceToString
  1442
+      };
  1443
+    }
943 1444
 
944 1445
 VariableDeclarationList
945  
-  = VariableDeclaration (__ "," __ VariableDeclaration)*
  1446
+  = head:VariableDeclaration tail:(__ "," __ VariableDeclaration)* {
  1447
+      var result = [head];
  1448
+      result.source = head.toString();
  1449
+      for (var i = 0; i < tail.length; i++) {
  1450
+        result.push(tail[i][3]);
  1451
+        result.source += tail[i].join("");
  1452
+      }
  1453
+      result.toString = sourceToString;
  1454
+      return result;
  1455
+    }
946 1456
 
947 1457
 VariableDeclarationListNoIn
948  
-  = VariableDeclarationNoIn (__ "," __ VariableDeclarationNoIn)*
  1458
+  = head:VariableDeclarationNoIn tail:(__ "," __ VariableDeclarationNoIn)* {
  1459
+      var result = [head];
  1460
+      result.source = head.toString();
  1461
+      for (var i = 0; i < tail.length; i++) {
  1462
+        result.push(tail[i][3]);
  1463
+        result.source += tail[i].join("");
  1464
+      }
  1465
+      result.toString = sourceToString;
  1466
+      return result;
  1467
+    }
949 1468
 
950 1469
 VariableDeclaration
951  
-  = Identifier __ Initialiser?
  1470
+  = name:Identifier w:__ value:Initialiser? {
  1471
+      return {
  1472
+        type:  "VariableDeclaration",
  1473
+        name:  name,
  1474
+        value: value.expression || null,
  1475
+        source:   name + w + value,
  1476
+        toString: sourceToString
  1477
+      };
  1478
+    }
952 1479
 
953 1480
 VariableDeclarationNoIn
954  
-  = Identifier __ InitialiserNoIn?
  1481
+  = name:Identifier w:__ value:InitialiserNoIn? {
  1482
+      return {
  1483
+        type:  "VariableDeclaration",
  1484
+        name:  name,
  1485
+        value: value.expression || null,
  1486
+        source:   name + w + value,
  1487
+        toString: sourceToString
  1488
+      };
  1489
+    }
955 1490
 
956 1491
 Initialiser
957  
-  = "=" (!"=") __ AssignmentExpression
  1492
+  = "=" (!"=") w:__ expression:AssignmentExpression {
  1493
+    return {
  1494
+      expression: expression,
  1495
+      source:     "=" + w + expression,
  1496
+      toString:   sourceToString
  1497
+    };
  1498
+  }
958 1499
 
959 1500
 InitialiserNoIn
960  
-  = "=" (!"=") __ AssignmentExpressionNoIn
  1501
+  = "=" (!"=") w:__ expression:AssignmentExpressionNoIn {
  1502
+    return {
  1503
+      expression: expression,
  1504
+      source:     "=" + w + expression,