From ee8c121676a3fc6494a30d98dc90e91ac001de3b Mon Sep 17 00:00:00 2001 From: David Majda Date: Mon, 31 May 2010 12:40:24 +0200 Subject: [PATCH] Use labeled expressions and variables instead of $1, $2, etc. Labeled expressions lead to more maintainable code and also will allow certain optimizations (we can ignore results of expressions not passed to the actions). This does not speed up the benchmark suite execution statistically significantly on V8. Detailed results (benchmark suite totals): --------------------------------- Test # Before After --------------------------------- 1 28.43 kB/s 28.46 kB/s 2 28.38 kB/s 28.56 kB/s 3 28.22 kB/s 28.58 kB/s 4 28.76 kB/s 28.55 kB/s 5 28.57 kB/s 28.48 kB/s --------------------------------- Average 28.47 kB/s 28.53 kB/s --------------------------------- Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.55 Safari/533.4 --- examples/arithmetics.pegjs | 8 +- examples/css.pegjs | 290 +++++++------ examples/javascript.pegjs | 857 ++++++++++++++++++++----------------- examples/json.pegjs | 62 +-- lib/compiler.js | 42 +- lib/metagrammar.js | 213 +++++---- lib/metagrammar.pegjs | 189 ++++---- test/compiler-test.js | 80 ++-- 8 files changed, 954 insertions(+), 787 deletions(-) diff --git a/examples/arithmetics.pegjs b/examples/arithmetics.pegjs index be7fffc..52fae2a 100644 --- a/examples/arithmetics.pegjs +++ b/examples/arithmetics.pegjs @@ -7,16 +7,16 @@ start = additive additive - = multiplicative "+" additive { return $1 + $3; } + = left:multiplicative "+" right:additive { return left + right; } / multiplicative multiplicative - = primary "*" multiplicative { return $1 * $3; } + = left:primary "*" right:multiplicative { return left * right; } / primary primary = integer - / "(" additive ")" { return $2; } + / "(" additive:additive ")" { return additive; } integer "integer" - = [0-9]+ { return parseInt($1.join(""), 10); } + = digits:[0-9]+ { return parseInt(digits.join(""), 10); } diff --git a/examples/css.pegjs b/examples/css.pegjs index 18fe7b8..5a8bd07 100644 --- a/examples/css.pegjs +++ b/examples/css.pegjs @@ -15,106 +15,114 @@ /* ===== Syntactical Elements ===== */ start - = stylesheet comment* { return $1; } + = stylesheet:stylesheet comment* { return stylesheet; } stylesheet - = (CHARSET_SYM STRING ";")? (S / CDO / CDC)* - (import (CDO S* / CDC S*)*)* - ((ruleset / media / page) (CDO S* / CDC S*)*)* { - var imports = []; - for (var i = 0; i < $3.length; i++) { - imports.push($3[i][0]); + = charset:(CHARSET_SYM STRING ";")? (S / CDO / CDC)* + imports:(import (CDO S* / CDC S*)*)* + rules:((ruleset / media / page) (CDO S* / CDC S*)*)* { + var importsConverted = []; + for (var i = 0; i < imports.length; i++) { + importsConverted.push(imports[i][0]); } - var rules = []; - for (i = 0; i < $4.length; i++) { - rules.push($4[i][0]); + var rulesConverted = []; + for (i = 0; i < rules.length; i++) { + rulesConverted.push(rules[i][0]); } return { type: "stylesheet", - charset: $1 !== "" ? $1[1] : null, - imports: imports, - rules: rules + charset: charset !== "" ? charset[1] : null, + imports: importsConverted, + rules: rulesConverted }; } import - = IMPORT_SYM S* (STRING / URI) S* media_list? ";" S* { + = IMPORT_SYM S* href:(STRING / URI) S* media:media_list? ";" S* { return { type: "import_rule", - href: $3, - media: $5 !== "" ? $5 : [] + href: href, + media: media !== "" ? media : [] }; } media - = MEDIA_SYM S* media_list "{" S* ruleset* "}" S* { + = MEDIA_SYM S* media:media_list "{" S* rules:ruleset* "}" S* { return { type: "media_rule", - media: $3, - rules: $6 + media: media, + rules: rules }; } media_list - = medium ("," S* medium)* { - var result = [$1]; - for (var i = 0; i < $2.length; i++) { - result.push($2[i][2]); + = head:medium tail:("," S* medium)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][2]); } return result; } medium - = IDENT S* { return $1; } + = ident:IDENT S* { return ident; } page - = PAGE_SYM S* pseudo_page? "{" S* declaration? (";" S* declaration?)* "}" S* { - var declarations = $6 !== "" ? [$6] : []; - for (var i = 0; i < $7.length; i++) { - if ($7[i][2] !== "") { - declarations.push($7[i][2]); + = PAGE_SYM S* qualifier:pseudo_page? + "{" S* + declarationsHead:declaration? + declarationsTail:(";" S* declaration?)* + "}" S* { + var declarations = declarationsHead !== "" ? [declarationsHead] : []; + for (var i = 0; i < declarationsTail.length; i++) { + if (declarationsTail[i][2] !== "") { + declarations.push(declarationsTail[i][2]); } } return { type: "page_rule", - qualifier: $3 !== "" ? $3 : null, + qualifier: qualifier !== "" ? qualifier : null, declarations: declarations }; } pseudo_page - = ":" IDENT S* { return $2; } + = ":" ident:IDENT S* { return ident; } operator - = "/" S* { return $1; } - / "," S* { return $1; } + = "/" S* { return "/"; } + / "," S* { return ","; } combinator - = "+" S* { return $1; } - / ">" S* { return $1; } + = "+" S* { return "+"; } + / ">" S* { return ">"; } unary_operator = "+" / "-" property - = IDENT S* { return $1; } + = ident:IDENT S* { return ident; } ruleset - = selector ("," S* selector)* - "{" S* declaration? (";" S* declaration?)* "}" S* { - var selectors = [$1]; - for (var i = 0; i < $2.length; i++) { - selectors.push($2[i][2]); + = selectorsHead:selector + selectorsTail:("," S* selector)* + "{" S* + declarationsHead:declaration? + declarationsTail:(";" S* declaration?)* + "}" S* { + var selectors = [selectorsHead]; + for (var i = 0; i < selectorsTail.length; i++) { + selectors.push(selectorsTail[i][2]); } - var declarations = $5 !== "" ? [$5] : []; - for (i = 0; i < $6.length; i++) { - if ($6[i][2] !== "") { - declarations.push($6[i][2]); + var declarations = declarationsHead !== "" ? [declarationsHead] : []; + for (i = 0; i < declarationsTail.length; i++) { + if (declarationsTail[i][2] !== "") { + declarations.push(declarationsTail[i][2]); } } @@ -126,40 +134,40 @@ ruleset } selector - = simple_selector S* combinator selector { + = left:simple_selector S* combinator:combinator right:selector { return { type: "selector", - combinator: $3, - left: $1, - right: $4 + combinator: combinator, + left: left, + right: right }; } - / simple_selector S* selector { + / left:simple_selector S* right:selector { return { type: "selector", combinator: " ", - left: $1, - right: $3 + left: left, + right: right }; } - / simple_selector S* { return $1; } + / selector:simple_selector S* { return selector; } simple_selector - = element_name - ( - HASH { return { type: "ID selector", id: $1.substr(1) }; } + = element:element_name + qualifiers:( + id:HASH { return { type: "ID selector", id: id.substr(1) }; } / class / attrib / pseudo )* { return { type: "simple_selector", - element: $1, - qualifiers: $2 + element: element, + qualifiers: qualifiers }; } - / ( - HASH { return { type: "ID selector", id: $1.substr(1) }; } + / qualifiers:( + id:HASH { return { type: "ID selector", id: id.substr(1) }; } / class / attrib / pseudo @@ -167,34 +175,40 @@ simple_selector return { type: "simple_selector", element: "*", - qualifiers: $1 + qualifiers: qualifiers }; } class - = "." IDENT { return { type: "class_selector", "class": $2 }; } + = "." class:IDENT { return { type: "class_selector", "class": class }; } element_name = IDENT / '*' attrib - = "[" S* IDENT S* (('=' / INCLUDES / DASHMATCH) S* (IDENT / STRING) S*)? "]" { + = "[" S* + attribute:IDENT S* + operatorAndValue:( + ('=' / INCLUDES / DASHMATCH) S* + (IDENT / STRING) S* + )? + "]" { return { type: "attribute_selector", - attribute: $3, - operator: $5 !== "" ? $5[0] : null, - value: $5 !== "" ? $5[2] : null + attribute: attribute, + operator: operatorAndValue !== "" ? operatorAndValue[0] : null, + value: operatorAndValue !== "" ? operatorAndValue[2] : null }; } pseudo = ":" - ( - FUNCTION S* (IDENT S*)? ")" { + value:( + name:FUNCTION S* params:(IDENT S*)? ")" { return { type: "function", - name: $1, - params: $3 !== "" ? [$3[0]] : [] + name: name, + params: params !== "" ? [params[0]] : [] }; } / IDENT @@ -206,17 +220,17 @@ pseudo */ return { type: "pseudo_selector", - value: $2 + value: value }; } declaration - = property ":" S* expr prio? { + = property:property ":" S* expression:expr important:prio? { return { type: "declaration", - property: $1, - expression: $4, - important: $5 !== "" ? true : false + property: property, + expression: expression, + important: important !== "" ? true : false }; } @@ -224,22 +238,22 @@ prio = IMPORTANT_SYM S* expr - = term (operator? term)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:term tail:(operator? term)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "expression", - operator: $2[i][0], + operator: tail[i][0], left: result, - right: $2[i][1] + right: tail[i][1] }; } return result; } term - = unary_operator? - ( + = operator:unary_operator? + value:( EMS S* / EXS S* / LENGTH S* @@ -248,24 +262,24 @@ term / FREQ S* / PERCENTAGE S* / NUMBER S* - ) { return { type: "value", value: $1 + $2[0] }; } - / URI S* { return { type: "uri", value: $1 }; } + ) { return { type: "value", value: operator + value[0] }; } + / value:URI S* { return { type: "uri", value: value }; } / function / hexcolor - / STRING S* { return { type: "string", value: $1 }; } - / IDENT S* { return { type: "ident", value: $1 }; } + / value:STRING S* { return { type: "string", value: value }; } + / value:IDENT S* { return { type: "ident", value: value }; } function - = FUNCTION S* expr ")" S* { + = name:FUNCTION S* params:expr ")" S* { return { type: "function", - name: $1, - params: $3 + name: name, + params: params }; } hexcolor - = HASH S* { return { type: "hexcolor", value: $1}; } + = value:HASH S* { return { type: "hexcolor", value: value}; } /* ===== Lexical Elements ===== */ @@ -278,13 +292,13 @@ nonascii = [\x80-\xFF] unicode - = "\\" h h? h? h? h? h? ("\r\n" / [ \t\r\n\f])? { - return String.fromCharCode(parseInt("0x" + $2 + $3 + $4 + $5 + $6 + $7)); + = "\\" h1:h h2:h? h3:h? h4:h? h5:h? h6:h? ("\r\n" / [ \t\r\n\f])? { + return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4 + h5 + h6)); } escape = unicode - / "\\" [^\r\n\f0-9a-fA-F] { return $2; } + / "\\" char:[^\r\n\f0-9a-fA-F] { return char; } nmstart = [_a-zA-Z] @@ -297,29 +311,33 @@ nmchar / escape integer - = [0-9]+ { return parseInt($1.join("")); } + = digits:[0-9]+ { return parseInt(digits.join("")); } float - = [0-9]* "." [0-9]+ { return parseFloat($1.join("") + $2 + $3.join("")); } + = before:[0-9]* "." after:[0-9]+ { + return parseFloat(before.join("") + "." + after.join("")); + } string1 - = '"' ([^\n\r\f\\"] / "\\" nl { return $2 } / escape)* '"' { - return $2.join(""); + = '"' chars:([^\n\r\f\\"] / "\\" nl:nl { return nl } / escape)* '"' { + return chars.join(""); } string2 - = "'" ([^\n\r\f\\'] / "\\" nl { return $2 } / escape)* "'" { - return $2.join(""); + = "'" chars:([^\n\r\f\\'] / "\\" nl:nl { return nl } / escape)* "'" { + return chars.join(""); } comment = "/*" [^*]* "*"+ ([^/*] [^*]* "*"+)* "/" ident - = "-"? nmstart nmchar* { return $1 + $2 + $3.join(""); } + = dash:"-"? nmstart:nmstart nmchars:nmchar* { + return dash + nmstart + nmchars.join(""); + } name - = nmchar+ { return $1.join(""); } + = nmchars:nmchar+ { return nmchars.join(""); } num = float @@ -330,7 +348,7 @@ string / string2 url - = ([!#$%&*-~] / nonascii / escape)* { return $1.join(""); } + = chars:([!#$%&*-~] / nonascii / escape)* { return chars.join(""); } s = [ \t\r\n\f]+ @@ -368,91 +386,91 @@ G = [gG] / "\\" "0"? "0"? "0"? "0"? "47" ("\r\n" / [ \t\r\n\f])? { return "G"; } / "\\" "0"? "0"? "0"? "0"? "67" ("\r\n" / [ \t\r\n\f])? { return "g"; } - / "\\" [gG] { return $2; } + / "\\" char:[gG] { return char; } H - = [hH] + = h:[hH] / "\\" "0"? "0"? "0"? "0"? "48" ("\r\n" / [ \t\r\n\f])? { return "H"; } / "\\" "0"? "0"? "0"? "0"? "68" ("\r\n" / [ \t\r\n\f])? { return "h"; } - / "\\" [hH] { return $2; } + / "\\" char:[hH] { return char; } I - = [iI] + = i:[iI] / "\\" "0"? "0"? "0"? "0"? "49" ("\r\n" / [ \t\r\n\f])? { return "I"; } / "\\" "0"? "0"? "0"? "0"? "69" ("\r\n" / [ \t\r\n\f])? { return "i"; } - / "\\" [iI] { return $2; } + / "\\" char:[iI] { return char; } K = [kK] / "\\" "0"? "0"? "0"? "0"? "4" [bB] ("\r\n" / [ \t\r\n\f])? { return "K"; } / "\\" "0"? "0"? "0"? "0"? "6" [bB] ("\r\n" / [ \t\r\n\f])? { return "k"; } - / "\\" [kK] { return $2; } + / "\\" char:[kK] { return char; } L = [lL] / "\\" "0"? "0"? "0"? "0"? "4" [cC] ("\r\n" / [ \t\r\n\f])? { return "L"; } / "\\" "0"? "0"? "0"? "0"? "6" [cC] ("\r\n" / [ \t\r\n\f])? { return "l"; } - / "\\" [lL] { return $2; } + / "\\" char:[lL] { return char; } M = [mM] / "\\" "0"? "0"? "0"? "0"? "4" [dD] ("\r\n" / [ \t\r\n\f])? { return "M"; } / "\\" "0"? "0"? "0"? "0"? "6" [dD] ("\r\n" / [ \t\r\n\f])? { return "m"; } - / "\\" [mM] { return $2; } + / "\\" char:[mM] { return char; } N = [nN] / "\\" "0"? "0"? "0"? "0"? "4" [eE] ("\r\n" / [ \t\r\n\f])? { return "N"; } / "\\" "0"? "0"? "0"? "0"? "6" [eE] ("\r\n" / [ \t\r\n\f])? { return "n"; } - / "\\" [nN] { return $2; } + / "\\" char:[nN] { return char; } O = [oO] / "\\" "0"? "0"? "0"? "0"? "4" [fF] ("\r\n" / [ \t\r\n\f])? { return "O"; } / "\\" "0"? "0"? "0"? "0"? "6" [fF] ("\r\n" / [ \t\r\n\f])? { return "o"; } - / "\\" [oO] { return $2; } + / "\\" char:[oO] { return char; } P = [pP] / "\\" "0"? "0"? "0"? "0"? "50" ("\r\n" / [ \t\r\n\f])? { return "P"; } / "\\" "0"? "0"? "0"? "0"? "70" ("\r\n" / [ \t\r\n\f])? { return "p"; } - / "\\" [pP] { return $2; } + / "\\" char:[pP] { return char; } R = [rR] / "\\" "0"? "0"? "0"? "0"? "52" ("\r\n" / [ \t\r\n\f])? { return "R"; } / "\\" "0"? "0"? "0"? "0"? "72" ("\r\n" / [ \t\r\n\f])? { return "r"; } - / "\\" [rR] { return $2; } + / "\\" char:[rR] { return char; } S_ = [sS] / "\\" "0"? "0"? "0"? "0"? "53" ("\r\n" / [ \t\r\n\f])? { return "S"; } / "\\" "0"? "0"? "0"? "0"? "73" ("\r\n" / [ \t\r\n\f])? { return "s"; } - / "\\" [sS] { return $2; } + / "\\" char:[sS] { return char; } T = [tT] / "\\" "0"? "0"? "0"? "0"? "54" ("\r\n" / [ \t\r\n\f])? { return "T"; } / "\\" "0"? "0"? "0"? "0"? "74" ("\r\n" / [ \t\r\n\f])? { return "t"; } - / "\\" [tT] { return $2; } + / "\\" char:[tT] { return char; } U = [uU] / "\\" "0"? "0"? "0"? "0"? "55" ("\r\n" / [ \t\r\n\f])? { return "U"; } / "\\" "0"? "0"? "0"? "0"? "75" ("\r\n" / [ \t\r\n\f])? { return "u"; } - / "\\" [uU] { return $2; } + / "\\" char:[uU] { return char; } X = [xX] / "\\" "0"? "0"? "0"? "0"? "58" ("\r\n" / [ \t\r\n\f])? { return "X"; } / "\\" "0"? "0"? "0"? "0"? "78" ("\r\n" / [ \t\r\n\f])? { return "x"; } - / "\\" [xX] { return $2; } + / "\\" char:[xX] { return char; } Z = [zZ] / "\\" "0"? "0"? "0"? "0"? "5" [aA] ("\r\n" / [ \t\r\n\f])? { return "Z"; } / "\\" "0"? "0"? "0"? "0"? "7" [aA] ("\r\n" / [ \t\r\n\f])? { return "z"; } - / "\\" [zZ] { return $2; } + / "\\" char:[zZ] { return char; } /* Tokens */ @@ -472,13 +490,13 @@ DASHMATCH "|=" = comment* "|=" STRING "string" - = comment* string { return $2; } + = comment* string:string { return string; } IDENT "identifier" - = comment* ident { return $2; } + = comment* ident:ident { return ident; } HASH "hash" - = comment* "#" name { return $2 + $3; } + = comment* "#" name:name { return "#" + name; } IMPORT_SYM "@import" = comment* "@" I M P O R T @@ -497,36 +515,40 @@ IMPORTANT_SYM "!important" = comment* "!" (s / comment)* I M P O R T A N T { return "!important"; } EMS "length" - = comment* num E M { return $2 + $3 + $4; } + = comment* num:num e:E m:M { return num + e + m; } EXS "length" - = comment* num E X { return $2 + $3 + $4; } + = comment* num:num e:E x:X { return num + e + x; } LENGTH "length" - = comment* num (P X / C M / M M / I N / P T / P C) { - return $2 + $3.join(""); + = comment* num:num unit:(P X / C M / M M / I N / P T / P C) { + return num + unit.join(""); } ANGLE "angle" - = comment* num (D E G / R A D / G R A D) { return $2 + $3.join(""); } + = comment* num:num unit:(D E G / R A D / G R A D) { + return num + unit.join(""); + } TIME "time" - = comment* num (M S_ { return $1 + $2; } / S_) { return $2 + $3; } + = comment* num:num unit:(m:M s:S_ { return m + s; } / S_) { + return num + unit; + } FREQ "frequency" - = comment* num (H Z / K H Z) { return $2 + $3.join(""); } + = comment* num:num unit:(H Z / K H Z) { return num + unit.join(""); } DIMENSION "dimension" - = comment* num ident { return $2 + $3; } + = comment* num:num unit:ident { return num + unit; } PERCENTAGE "percentage" - = comment* num "%" { return $2 + $3; } + = comment* num:num "%" { return num + "%"; } NUMBER "number" - = comment* num { return $2; } + = comment* num:num { return num; } URI "uri" - = comment* U R L "(" w (string / url) w ")" { return $7; } + = comment* U R L "(" w value:(string / url) w ")" { return value; } FUNCTION "function" - = comment* ident "(" { return $2; } + = comment* name:ident "(" { return name; } diff --git a/examples/javascript.pegjs b/examples/javascript.pegjs index 838e9ff..1de4bd0 100644 --- a/examples/javascript.pegjs +++ b/examples/javascript.pegjs @@ -46,7 +46,7 @@ */ start - = __ Program __ { return $2; } + = __ program:Program __ { return program; } /* ===== A.1 Lexical Grammar ===== */ @@ -81,16 +81,18 @@ SingleLineComment = "//" (!LineTerminator SourceCharacter)* Identifier "identifier" - = !ReservedWord IdentifierName { return $2; } + = !ReservedWord name:IdentifierName { return name; } IdentifierName "identifier" - = IdentifierStart IdentifierPart* { return $1 + $2.join(""); } + = start:IdentifierStart parts:IdentifierPart* { + return start + parts.join(""); + } IdentifierStart = UnicodeLetter / "$" / "_" - / "\\" UnicodeEscapeSequence { return $2; } + / "\\" sequence:UnicodeEscapeSequence { return sequence; } IdentifierPart = IdentifierStart @@ -174,8 +176,18 @@ FutureReservedWord Literal = NullLiteral / BooleanLiteral - / NumericLiteral { return { type: "NumericLiteral", value: $1 }; } - / StringLiteral { return { type: "StringLiteral", value: $1 }; } + / value:NumericLiteral { + return { + type: "NumericLiteral", + value: value + }; + } + / value:StringLiteral { + return { + type: "StringLiteral", + value: value + }; + } / RegularExpressionLiteral NullLiteral @@ -186,24 +198,29 @@ BooleanLiteral / FalseToken { return { type: "BooleanLiteral", value: false }; } NumericLiteral "number" - = (HexIntegerLiteral / DecimalLiteral) !IdentifierStart { return $1; } + = literal:(HexIntegerLiteral / DecimalLiteral) !IdentifierStart { + return literal; + } DecimalLiteral - = DecimalIntegerLiteral "." DecimalDigits? ExponentPart? { - return parseFloat($1 + $2 + $3 + $4); + = before:DecimalIntegerLiteral + "." + after:DecimalDigits? + exponent:ExponentPart? { + return parseFloat(before + "." + after + exponent); } - / "." DecimalDigits ExponentPart? { - return parseFloat($1 + $2 + $3); + / "." after:DecimalDigits exponent:ExponentPart? { + return parseFloat("." + after + exponent); } - / DecimalIntegerLiteral ExponentPart? { - return parseFloat($1 + $2); + / before:DecimalIntegerLiteral exponent:ExponentPart? { + return parseFloat(before + exponent); } DecimalIntegerLiteral - = "0" / NonZeroDigit DecimalDigits? { return $1 + $2; } + = "0" / digit:NonZeroDigit digits:DecimalDigits? { return digit + digits; } DecimalDigits - = DecimalDigit+ { return $1.join(""); } + = digits:DecimalDigit+ { return digits.join(""); } DecimalDigit = [0-9] @@ -212,43 +229,45 @@ NonZeroDigit = [1-9] ExponentPart - = ExponentIndicator SignedInteger { return $1 + $2; } + = indicator:ExponentIndicator integer:SignedInteger { + return indicator + integer; + } ExponentIndicator = [eE] SignedInteger - = [-+]? DecimalDigits { return $1 + $2; } + = sign:[-+]? digits:DecimalDigits { return sign + digits; } HexIntegerLiteral - = "0" [xX] HexDigit+ { return parseInt($1 + $2 + $3.join("")); } + = "0" [xX] digits:HexDigit+ { return parseInt("0x" + dgits.join("")); } HexDigit = [0-9a-fA-F] StringLiteral "string" - = ('"' DoubleStringCharacters? '"' / "'" SingleStringCharacters? "'") { - return $1[1]; + = parts:('"' DoubleStringCharacters? '"' / "'" SingleStringCharacters? "'") { + return parts[1]; } DoubleStringCharacters - = DoubleStringCharacter+ { return $1.join(""); } + = chars:DoubleStringCharacter+ { return chars.join(""); } SingleStringCharacters - = SingleStringCharacter+ { return $1.join(""); } + = chars:SingleStringCharacter+ { return chars.join(""); } DoubleStringCharacter - = !('"' / "\\" / LineTerminator) SourceCharacter { return $2; } - / "\\" EscapeSequence { return $2; } + = !('"' / "\\" / LineTerminator) char:SourceCharacter { return char; } + / "\\" sequence:EscapeSequence { return sequence; } / LineContinuation SingleStringCharacter - = !("'" / "\\" / LineTerminator) SourceCharacter { return $2; } - / "\\" EscapeSequence { return $2; } + = !("'" / "\\" / LineTerminator) char:SourceCharacter { return char; } + / "\\" sequence:EscapeSequence { return sequence; } / LineContinuation LineContinuation - = "\\" LineTerminatorSequence { return $2; } + = "\\" sequence:LineTerminatorSequence { return sequence; } EscapeSequence = CharacterEscapeSequence @@ -261,8 +280,8 @@ CharacterEscapeSequence / NonEscapeCharacter SingleEscapeCharacter - = ['"\\bfnrtv] { - return $1 + = char:['"\\bfnrtv] { + return char .replace("b", "\b") .replace("f", "\f") .replace("n", "\n") @@ -272,7 +291,7 @@ SingleEscapeCharacter } NonEscapeCharacter - = (!EscapeCharacter / LineTerminator) SourceCharacter { return $2; } + = (!EscapeCharacter / LineTerminator) char:SourceCharacter { return char; } EscapeCharacter = SingleEscapeCharacter @@ -281,37 +300,39 @@ EscapeCharacter / "u" HexEscapeSequence - = "x" HexDigit HexDigit { - return String.fromCharCode(parseInt("0x" + $2 + $3)); + = "x" h1:HexDigit h2:HexDigit { + return String.fromCharCode(parseInt("0x" + h1 + h2)); } UnicodeEscapeSequence - = "u" HexDigit HexDigit HexDigit HexDigit { - return String.fromCharCode(parseInt("0x" + $2 + $3 + $4 + $5)); + = "u" h1:HexDigit h2:HexDigit h3:HexDigit h4:HexDigit { + return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4)); } RegularExpressionLiteral "regular expression" - = "/" RegularExpressionBody "/" RegularExpressionFlags { + = "/" body:RegularExpressionBody "/" flags:RegularExpressionFlags { return { type: "RegularExpressionLiteral", - body: $2, - flags: $4 + body: body, + flags: flags }; } RegularExpressionBody - = RegularExpressionFirstChar RegularExpressionChars { return $1 + $2; } + = char:RegularExpressionFirstChar chars:RegularExpressionChars { + return char + chars; + } RegularExpressionChars - = RegularExpressionChar* { return $1.join(""); } + = chars:RegularExpressionChar* { return chars.join(""); } RegularExpressionFirstChar - = ![*\\/[] RegularExpressionNonTerminator { return $2; } + = ![*\\/[] char:RegularExpressionNonTerminator { return char; } / RegularExpressionBackslashSequence / RegularExpressionClass RegularExpressionChar - = ![\\/[] RegularExpressionNonTerminator { return $2; } + = ![\\/[] char:RegularExpressionNonTerminator { return char; } / RegularExpressionBackslashSequence / RegularExpressionClass @@ -320,57 +341,57 @@ RegularExpressionChar * "RegularExpressionNonTerminator". */ RegularExpressionBackslashSequence - = "\\" RegularExpressionNonTerminator { return $1 + $2; } + = "\\" char:RegularExpressionNonTerminator { return "\\" + char; } RegularExpressionNonTerminator - = !LineTerminator SourceCharacter { return $2; } + = !LineTerminator char:SourceCharacter { return char; } RegularExpressionClass - = "[" RegularExpressionClassChars "]" { return $1 + $2 + $3; } + = "[" chars:RegularExpressionClassChars "]" { return "[" + chars + "]"; } RegularExpressionClassChars - = RegularExpressionClassChar* { return $1.join(""); } + = chars:RegularExpressionClassChar* { return chars.join(""); } RegularExpressionClassChar - = ![\]\\] RegularExpressionNonTerminator { return $2; } + = ![\]\\] char:RegularExpressionNonTerminator { return char; } / RegularExpressionBackslashSequence RegularExpressionFlags - = IdentifierPart* { return $1.join(""); } + = parts:IdentifierPart* { return parts.join(""); } /* Tokens */ -BreakToken = "break" !IdentifierPart -CaseToken = "case" !IdentifierPart -CatchToken = "catch" !IdentifierPart -ContinueToken = "continue" !IdentifierPart -DebuggerToken = "debugger" !IdentifierPart -DefaultToken = "default" !IdentifierPart -DeleteToken = "delete" !IdentifierPart { return $1; } -DoToken = "do" !IdentifierPart -ElseToken = "else" !IdentifierPart -FalseToken = "false" !IdentifierPart -FinallyToken = "finally" !IdentifierPart -ForToken = "for" !IdentifierPart -FunctionToken = "function" !IdentifierPart -GetToken = "get" !IdentifierPart -IfToken = "if" !IdentifierPart -InstanceofToken = "instanceof" !IdentifierPart { return $1; } -InToken = "in" !IdentifierPart { return $1; } -NewToken = "new" !IdentifierPart -NullToken = "null" !IdentifierPart -ReturnToken = "return" !IdentifierPart -SetToken = "set" !IdentifierPart -SwitchToken = "switch" !IdentifierPart -ThisToken = "this" !IdentifierPart -ThrowToken = "throw" !IdentifierPart -TrueToken = "true" !IdentifierPart -TryToken = "try" !IdentifierPart -TypeofToken = "typeof" !IdentifierPart { return $1; } -VarToken = "var" !IdentifierPart -VoidToken = "void" !IdentifierPart { return $1; } -WhileToken = "while" !IdentifierPart -WithToken = "with" !IdentifierPart +BreakToken = "break" !IdentifierPart +CaseToken = "case" !IdentifierPart +CatchToken = "catch" !IdentifierPart +ContinueToken = "continue" !IdentifierPart +DebuggerToken = "debugger" !IdentifierPart +DefaultToken = "default" !IdentifierPart +DeleteToken = "delete" !IdentifierPart { return "delete"; } +DoToken = "do" !IdentifierPart +ElseToken = "else" !IdentifierPart +FalseToken = "false" !IdentifierPart +FinallyToken = "finally" !IdentifierPart +ForToken = "for" !IdentifierPart +FunctionToken = "function" !IdentifierPart +GetToken = "get" !IdentifierPart +IfToken = "if" !IdentifierPart +InstanceofToken = "instanceof" !IdentifierPart { return "instanceof"; } +InToken = "in" !IdentifierPart { return "in"; } +NewToken = "new" !IdentifierPart +NullToken = "null" !IdentifierPart +ReturnToken = "return" !IdentifierPart +SetToken = "set" !IdentifierPart +SwitchToken = "switch" !IdentifierPart +ThisToken = "this" !IdentifierPart +ThrowToken = "throw" !IdentifierPart +TrueToken = "true" !IdentifierPart +TryToken = "try" !IdentifierPart +TypeofToken = "typeof" !IdentifierPart { return "typeof"; } +VarToken = "var" !IdentifierPart +VoidToken = "void" !IdentifierPart { return "void"; } +WhileToken = "while" !IdentifierPart +WithToken = "with" !IdentifierPart /* * Unicode Character Categories @@ -455,27 +476,28 @@ __ /* ===== A.3 Expressions ===== */ PrimaryExpression - = ThisToken { return { type: "This" }; } - / Identifier { return { type: "Variable", name: $1 }; } + = ThisToken { return { type: "This" }; } + / name:Identifier { return { type: "Variable", name: name }; } / Literal / ArrayLiteral / ObjectLiteral - / "(" __ Expression __ ")" { return $3; } + / "(" __ expression:Expression __ ")" { return expression; } ArrayLiteral - = "[" __ ElementList? __ (Elision __)? "]" { + = "[" __ elements:ElementList? __ (Elision __)? "]" { return { type: "ArrayLiteral", - elements: $3 !== "" ? $3 : [] + elements: elements !== "" ? elements : [] }; } ElementList - = (Elision __)? AssignmentExpression - (__ "," __ Elision? __ AssignmentExpression)* { - var result = [$2]; - for (var i = 0; i < $3.length; i++) { - result.push($3[i][5]); + = (Elision __)? + head:AssignmentExpression + tail:(__ "," __ Elision? __ AssignmentExpression)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][5]); } return result; } @@ -484,45 +506,47 @@ Elision = "," (__ ",")* ObjectLiteral - = "{" __ (PropertyNameAndValueList __ ("," __)?)? "}" { + = "{" __ properties:(PropertyNameAndValueList __ ("," __)?)? "}" { return { type: "ObjectLiteral", - properties: $3 !== "" ? $3[0] : [] + properties: properties !== "" ? properties[0] : [] }; } PropertyNameAndValueList - = PropertyAssignment (__ "," __ PropertyAssignment)* { - var result = [$1]; - for (var i = 0; i < $2.length; i++) { - result.push($2[i][3]); + = head:PropertyAssignment tail:(__ "," __ PropertyAssignment)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][3]); } return result; } PropertyAssignment - = PropertyName __ ":" __ AssignmentExpression { + = name:PropertyName __ ":" __ value:AssignmentExpression { return { type: "PropertyAssignment", - name: $1, - value: $5 + name: name, + value: value }; } - / GetToken __ PropertyName __ "(" __ ")" __ "{" __ FunctionBody __ "}" { + / GetToken __ name:PropertyName __ + "(" __ ")" __ + "{" __ body:FunctionBody __ "}" { return { type: "GetterDefinition", - name: $3, - body: $11 + name: name, + body: body }; } - / SetToken __ PropertyName __ - "(" __ PropertySetParameterList __ ")" __ - "{" __ FunctionBody __ "}" { + / SetToken __ name:PropertyName __ + "(" __ param:PropertySetParameterList __ ")" __ + "{" __ body:FunctionBody __ "}" { return { type: "SetterDefinition", - name: $3, - param: $7, - body: $13 + name: name, + param: param, + body: body }; } @@ -535,27 +559,27 @@ PropertySetParameterList = Identifier MemberExpression - = ( + = base:( PrimaryExpression / FunctionExpression - / NewToken __ MemberExpression __ Arguments { + / NewToken __ constructor:MemberExpression __ arguments:Arguments { return { type: "NewOperator", - constructor: $3, - arguments: $5 + constructor: constructor, + arguments: arguments }; } ) - ( - __ "[" __ Expression __ "]" { return $4; } - / __ "." __ IdentifierName { return $4; } + accessors:( + __ "[" __ name:Expression __ "]" { return name; } + / __ "." __ name:IdentifierName { return name; } )* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + var result = base; + for (var i = 0; i < accessors.length; i++) { result = { type: "PropertyAccess", base: result, - name: $2[i] + name: accessors[i] }; } return result; @@ -563,76 +587,80 @@ MemberExpression NewExpression = MemberExpression - / NewToken __ NewExpression { + / NewToken __ constructor:NewExpression { return { type: "NewOperator", - constructor: $3, + constructor: constructor, arguments: [] }; } CallExpression - = ( - MemberExpression __ Arguments { + = base:( + name:MemberExpression __ arguments:Arguments { return { type: "FunctionCall", - name: $1, - arguments: $3 + name: name, + arguments: arguments }; } ) - ( - __ Arguments { + argumentsOrAccessors:( + __ arguments:Arguments { return { type: "FunctionCallArguments", - arguments: $2 + arguments: arguments }; } - / __ "[" __ Expression __ "]" { + / __ "[" __ name:Expression __ "]" { return { type: "PropertyAccessProperty", - name: $4 + name: name }; } - / __ "." __ IdentifierName { + / __ "." __ name:IdentifierName { return { type: "PropertyAccessProperty", - name: $4 + name: name }; } )* { - var result = $1; - for (var i = 0; i < $2.length; i++) { - switch ($2[i].type) { + var result = base; + for (var i = 0; i < argumentsOrAccessors.length; i++) { + switch (argumentsOrAccessors[i].type) { case "FunctionCallArguments": result = { type: "FuctionCall", name: result, - arguments: $2[i].arguments + arguments: argumentsOrAccessors[i].arguments }; break; case "PropertyAccessProperty": result = { type: "PropertyAccess", base: result, - name: $2[i].name + name: argumentsOrAccessors[i].name }; break; default: - throw new Error("Invalid expression type: " + $2[i].type); + throw new Error( + "Invalid expression type: " + argumentsOrAccessors[i].type + ); } } return result; } Arguments - = "(" __ ArgumentList? __ ")" { return $3 !== "" ? $3 : []; } + = "(" __ arguments:ArgumentList? __ ")" { + return arguments !== "" ? arguments : []; + } ArgumentList - = AssignmentExpression (__ "," __ AssignmentExpression)* { - var result = [$1]; - for (var i = 0; i < $2.length; i++) { - result.push($2[i][3]); + = head:AssignmentExpression tail:(__ "," __ AssignmentExpression)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][3]); } return result; } @@ -642,11 +670,11 @@ LeftHandSideExpression / NewExpression PostfixExpression - = LeftHandSideExpression _ PostfixOperator { + = expression:LeftHandSideExpression _ operator:PostfixOperator { return { type: "PostfixExpression", - operator: $3, - expression: $1 + operator: operator, + expression: expression }; } / LeftHandSideExpression @@ -657,11 +685,11 @@ PostfixOperator UnaryExpression = PostfixExpression - / UnaryOperator __ UnaryExpression { + / operator:UnaryOperator __ expression:UnaryExpression { return { type: "UnaryExpression", - operator: $1, - expression: $3 + operator: operator, + expression: expression }; } @@ -677,49 +705,52 @@ UnaryOperator / "!" MultiplicativeExpression - = UnaryExpression (__ MultiplicativeOperator __ UnaryExpression)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:UnaryExpression + tail:(__ MultiplicativeOperator __ UnaryExpression)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; } MultiplicativeOperator - = ("*" / "/" / "%") !"=" { return $1; } + = operator:("*" / "/" / "%") !"=" { return operator; } AdditiveExpression - = MultiplicativeExpression (__ AdditiveOperator __ MultiplicativeExpression)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:MultiplicativeExpression + tail:(__ AdditiveOperator __ MultiplicativeExpression)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; } AdditiveOperator - = "+" !("+" / "=") { return $1; } - / "-" !("-" / "=") { return $1; } + = "+" !("+" / "=") { return "+"; } + / "-" !("-" / "=") { return "-"; } ShiftExpression - = AdditiveExpression (__ ShiftOperator __ AdditiveExpression)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:AdditiveExpression + tail:(__ ShiftOperator __ AdditiveExpression)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; @@ -731,14 +762,15 @@ ShiftOperator / ">>" RelationalExpression - = ShiftExpression (__ RelationalOperator __ ShiftExpression)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:ShiftExpression + tail:(__ RelationalOperator __ ShiftExpression)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; @@ -753,14 +785,15 @@ RelationalOperator / InToken RelationalExpressionNoIn - = ShiftExpression (__ RelationalOperatorNoIn __ ShiftExpression)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:ShiftExpression + tail:(__ RelationalOperatorNoIn __ ShiftExpression)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; @@ -774,28 +807,30 @@ RelationalOperatorNoIn / InstanceofToken EqualityExpression - = RelationalExpression (__ EqualityOperator __ RelationalExpression)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:RelationalExpression + tail:(__ EqualityOperator __ RelationalExpression)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; } EqualityExpressionNoIn - = RelationalExpressionNoIn (__ EqualityOperator __ RelationalExpressionNoIn)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:RelationalExpressionNoIn + tail:(__ EqualityOperator __ RelationalExpressionNoIn)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; @@ -808,210 +843,224 @@ EqualityOperator / "!=" BitwiseANDExpression - = EqualityExpression (__ BitwiseANDOperator __ EqualityExpression)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:EqualityExpression + tail:(__ BitwiseANDOperator __ EqualityExpression)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; } BitwiseANDExpressionNoIn - = EqualityExpressionNoIn (__ BitwiseANDOperator __ EqualityExpressionNoIn)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:EqualityExpressionNoIn + tail:(__ BitwiseANDOperator __ EqualityExpressionNoIn)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; } BitwiseANDOperator - = "&" !("&" / "=") { return $1; } + = "&" !("&" / "=") { return "&"; } BitwiseXORExpression - = BitwiseANDExpression (__ BitwiseXOROperator __ BitwiseANDExpression)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:BitwiseANDExpression + tail:(__ BitwiseXOROperator __ BitwiseANDExpression)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; } BitwiseXORExpressionNoIn - = BitwiseANDExpressionNoIn (__ BitwiseXOROperator __ BitwiseANDExpressionNoIn)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:BitwiseANDExpressionNoIn + tail:(__ BitwiseXOROperator __ BitwiseANDExpressionNoIn)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; } BitwiseXOROperator - = "^" !("^" / "=") { return $1; } + = "^" !("^" / "=") { return "^"; } BitwiseORExpression - = BitwiseXORExpression (__ BitwiseOROperator __ BitwiseXORExpression)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:BitwiseXORExpression + tail:(__ BitwiseOROperator __ BitwiseXORExpression)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; } BitwiseORExpressionNoIn - = BitwiseXORExpressionNoIn (__ BitwiseOROperator __ BitwiseXORExpressionNoIn)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:BitwiseXORExpressionNoIn + tail:(__ BitwiseOROperator __ BitwiseXORExpressionNoIn)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; } BitwiseOROperator - = "|" !("|" / "=") { return $1; } + = "|" !("|" / "=") { return "|"; } LogicalANDExpression - = BitwiseORExpression (__ LogicalANDOperator __ BitwiseORExpression)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:BitwiseORExpression + tail:(__ LogicalANDOperator __ BitwiseORExpression)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; } LogicalANDExpressionNoIn - = BitwiseORExpressionNoIn (__ LogicalANDOperator __ BitwiseORExpressionNoIn)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:BitwiseORExpressionNoIn + tail:(__ LogicalANDOperator __ BitwiseORExpressionNoIn)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; } LogicalANDOperator - = "&&" !"=" { return $1; } + = "&&" !"=" { return "&&"; } LogicalORExpression - = LogicalANDExpression (__ LogicalOROperator __ LogicalANDExpression)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:LogicalANDExpression + tail:(__ LogicalOROperator __ LogicalANDExpression)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; } LogicalORExpressionNoIn - = LogicalANDExpressionNoIn (__ LogicalOROperator __ LogicalANDExpressionNoIn)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:LogicalANDExpressionNoIn + tail:(__ LogicalOROperator __ LogicalANDExpressionNoIn)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; } LogicalOROperator - = "||" !"=" { return $1; } + = "||" !"=" { return "||"; } ConditionalExpression - = LogicalORExpression __ - "?" __ AssignmentExpression __ - ":" __ AssignmentExpression { + = condition:LogicalORExpression __ + "?" __ trueExpression:AssignmentExpression __ + ":" __ falseExpression:AssignmentExpression { return { type: "ConditionalExpression", - condition: $1, - trueExpression: $5, - falseExpression: $9 + condition: condition, + trueExpression: trueExpression, + falseExpression: falseExpression }; } / LogicalORExpression ConditionalExpressionNoIn - = LogicalORExpressionNoIn __ - "?" __ AssignmentExpressionNoIn __ - ":" __ AssignmentExpressionNoIn { + = condition:LogicalORExpressionNoIn __ + "?" __ trueExpression:AssignmentExpressionNoIn __ + ":" __ falseExpression:AssignmentExpressionNoIn { return { type: "ConditionalExpression", - condition: $1, - trueExpression: $5, - falseExpression: $9 + condition: condition, + trueExpression: trueExpression, + falseExpression: falseExpression }; } / LogicalORExpressionNoIn AssignmentExpression - = LeftHandSideExpression __ AssignmentOperator __ AssignmentExpression { + = left:LeftHandSideExpression __ + operator:AssignmentOperator __ + right:AssignmentExpression { return { type: "AssignmentExpression", - operator: $3, - left: $1, - right: $5 + operator: operator, + left: left, + right: right }; } / ConditionalExpression AssignmentExpressionNoIn - = LeftHandSideExpression __ AssignmentOperator __ AssignmentExpressionNoIn { + = left:LeftHandSideExpression __ + operator:AssignmentOperator __ + right:AssignmentExpressionNoIn { return { type: "AssignmentExpression", - operator: $3, - left: $1, - right: $5 + operator: operator, + left: left, + right: right }; } / ConditionalExpressionNoIn AssignmentOperator - = "=" (!"=") { return $1; } + = "=" (!"=") { return "="; } / "*=" / "/=" / "%=" @@ -1025,28 +1074,30 @@ AssignmentOperator / "|=" Expression - = AssignmentExpression (__ "," __ AssignmentExpression)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:AssignmentExpression + tail:(__ "," __ AssignmentExpression)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; } ExpressionNoIn - = AssignmentExpressionNoIn (__ "," __ AssignmentExpressionNoIn)* { - var result = $1; - for (var i = 0; i < $2.length; i++) { + = head:AssignmentExpressionNoIn + tail:(__ "," __ AssignmentExpressionNoIn)* { + var result = head; + for (var i = 0; i < tail.length; i++) { result = { type: "BinaryExpression", - operator: $2[i][1], + operator: tail[i][1], left: result, - right: $2[i][3] + right: tail[i][3] }; } return result; @@ -1079,85 +1130,88 @@ Statement / FunctionExpression Block - = "{" __ (StatementList __)? "}" { + = "{" __ statements:(StatementList __)? "}" { return { type: "Block", - statements: $3 !== "" ? $3[0] : [] + statements: statements !== "" ? statements[0] : [] }; } StatementList - = Statement (__ Statement)* { - var result = [$1]; - for (var i = 0; i < $2.length; i++) { - result.push($2[i][1]); + = head:Statement tail:(__ Statement)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][1]); } return result; } VariableStatement - = VarToken __ VariableDeclarationList EOS { + = VarToken __ declarations:VariableDeclarationList EOS { return { type: "VariableStatement", - declarations: $3 + declarations: declarations }; } VariableDeclarationList - = VariableDeclaration (__ "," __ VariableDeclaration)* { - var result = [$1]; - for (var i = 0; i < $2.length; i++) { - result.push($2[i][3]); + = head:VariableDeclaration tail:(__ "," __ VariableDeclaration)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][3]); } return result; } VariableDeclarationListNoIn - = VariableDeclarationNoIn (__ "," __ VariableDeclarationNoIn)* { - var result = [$1]; - for (var i = 0; i < $2.length; i++) { - result.push($2[i][3]); + = head:VariableDeclarationNoIn tail:(__ "," __ VariableDeclarationNoIn)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][3]); } return result; } VariableDeclaration - = Identifier __ Initialiser? { + = name:Identifier __ value:Initialiser? { return { type: "VariableDeclaration", - name: $1, - value: $3 !== "" ? $3 : null + name: name, + value: value !== "" ? value : null }; } VariableDeclarationNoIn - = Identifier __ InitialiserNoIn? { + = name:Identifier __ value:InitialiserNoIn? { return { type: "VariableDeclaration", - name: $1, - value: $3 !== "" ? $3 : null + name: name, + value: value !== "" ? value : null }; } Initialiser - = "=" (!"=") __ AssignmentExpression { return $4; } + = "=" (!"=") __ expression:AssignmentExpression { return expression; } InitialiserNoIn - = "=" (!"=") __ AssignmentExpressionNoIn { return $4; } + = "=" (!"=") __ expression:AssignmentExpressionNoIn { return expression; } EmptyStatement = ";" { return { type: "EmptyStatement" }; } ExpressionStatement - = !("{" / FunctionToken) Expression EOS { return $2; } + = !("{" / FunctionToken) expression:Expression EOS { return expression; } IfStatement - = IfToken __ "(" __ Expression __ ")" __ Statement (__ ElseToken __ Statement)? { + = IfToken __ + "(" __ condition:Expression __ ")" __ + ifStatement:Statement + elseStatement:(__ ElseToken __ Statement)? { return { type: "IfStatement", - condition: $5, - ifStatement: $9, - elseStatement: $10 !== "" ? $10[3] : null + condition: condition, + ifStatement: ifStatement, + elseStatement: elseStatement !== "" ? elseStatement[3] : null }; } @@ -1168,222 +1222,229 @@ IterationStatement / ForInStatement DoWhileStatement - = DoToken __ Statement __ WhileToken __ "(" __ Expression __ ")" EOS { + = DoToken __ + statement:Statement __ + WhileToken __ "(" __ condition:Expression __ ")" EOS { return { type: "DoWhileStatement", - condition: $9, - statement: $3 + condition: condition, + statement: statement }; } WhileStatement - = WhileToken __ "(" __ Expression __ ")" __ Statement { + = WhileToken __ "(" __ condition:Expression __ ")" __ statement:Statement { return { type: "WhileStatement", - condition: $5, - statement: $9 + condition: condition, + statement: statement }; } ForStatement = ForToken __ "(" __ - ( - VarToken __ VariableDeclarationListNoIn { + initializer:( + VarToken __ declarations:VariableDeclarationListNoIn { return { type: "VariableStatement", - declarations: $3 + declarations: declarations }; } / ExpressionNoIn? ) __ ";" __ - Expression? __ + test:Expression? __ ";" __ - Expression? __ + counter:Expression? __ ")" __ - Statement + statement:Statement { return { type: "ForStatement", - initializer: $5 !== "" ? $5 : null, - test: $9 !== "" ? $9 : null, - counter: $13 !== "" ? $13 : null, - statement: $17 + initializer: initializer !== "" ? initializer : null, + test: test !== "" ? test : null, + counter: counter !== "" ? counter : null, + statement: statement }; } ForInStatement = ForToken __ "(" __ - ( - VarToken __ VariableDeclarationNoIn { return $3; } + iterator:( + VarToken __ declaration:VariableDeclarationNoIn { return declaration; } / LeftHandSideExpression ) __ InToken __ - Expression __ + collection:Expression __ ")" __ - Statement + statement:Statement { return { type: "ForInStatement", - iterator: $5, - collection: $9, - statement: $13 + iterator: iterator, + collection: collection, + statement: statement }; } ContinueStatement = ContinueToken _ - ( - Identifier EOS { return $1; } - / EOSNoLineTerminator { return ""; } + label:( + identifier:Identifier EOS { return identifier; } + / EOSNoLineTerminator { return ""; } ) { return { type: "ContinueStatement", - label: $3 !== "" ? $3 : null + label: label !== "" ? label : null }; } BreakStatement = BreakToken _ - ( - Identifier EOS { return $1; } - / EOSNoLineTerminator { return ""; } + label:( + identifier:Identifier EOS { return identifier; } + / EOSNoLineTerminator { return ""; } ) { return { type: "BreakStatement", - label: $3 !== "" ? $3 : null + label: label !== "" ? label : null }; } ReturnStatement = ReturnToken _ - ( - Expression EOS { return $1; } - / EOSNoLineTerminator { return ""; } + value:( + expression:Expression EOS { return expression; } + / EOSNoLineTerminator { return ""; } ) { return { type: "ReturnStatement", - value: $3 !== "" ? $3 : null + value: value !== "" ? value : null }; } WithStatement - = WithToken __ "(" __ Expression __ ")" __ Statement { + = WithToken __ "(" __ environment:Expression __ ")" __ statement:Statement { return { type: "WithStatement", - environment: $5, - statement: $9 + environment: environment, + statement: statement }; } SwitchStatement - = SwitchToken __ "(" __ Expression __ ")" __ CaseBlock { + = SwitchToken __ "(" __ expression:Expression __ ")" __ clauses:CaseBlock { return { type: "SwitchStatement", - expression: $5, - clauses: $9 + expression: expression, + clauses: clauses }; } CaseBlock - = "{" __ CaseClauses? (__ DefaultClause __ CaseClauses?)? __ "}" { - var clausesBefore = $3 !== "" ? $3 : []; - if ($4 !== "") { - var defaultClause = $4[1]; - var clausesAfter = $4[3] !== "" ? $4[3] : []; + = "{" __ + before:CaseClauses? + defaultAndAfter:(__ DefaultClause __ CaseClauses?)? __ + "}" { + var before = before !== "" ? before : []; + if (defaultAndAfter !== "") { + var defaultClause = defaultAndAfter[1]; + var clausesAfter = defaultAndAfter[3] !== "" + ? defaultAndAfter[3] + : []; } else { var defaultClause = null; var clausesAfter = []; } - return (defaultClause ? clausesBefore.concat(defaultClause) : clausesBefore).concat(clausesAfter); + return (defaultClause ? before.concat(defaultClause) : before).concat(clausesAfter); } CaseClauses - = CaseClause (__ CaseClause)* { - var result = [$1]; - for (var i = 0; i < $2.length; i++) { - result.push($2[i][1]); + = head:CaseClause tail:(__ CaseClause)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][1]); } return result; } CaseClause - = CaseToken __ Expression __ ":" (__ StatementList)? { + = CaseToken __ selector:Expression __ ":" statements:(__ StatementList)? { return { type: "CaseClause", - selector: $3, - statements: $6 !== "" ? $6[1] : [] + selector: selector, + statements: statements !== "" ? statements[1] : [] }; } DefaultClause - = DefaultToken __ ":" (__ StatementList)? { + = DefaultToken __ ":" statements:(__ StatementList)? { return { type: "DefaultClause", - statements: $4 !== "" ? $4[1] : [] + statements: statements !== "" ? statements[1] : [] }; } LabelledStatement - = Identifier __ ":" __ Statement { + = label:Identifier __ ":" __ statement:Statement { return { type: "LabelledStatement", - label: $1, - statement: $5 + label: label, + statement: statement }; } ThrowStatement - = ThrowToken _ Expression EOSNoLineTerminator { + = ThrowToken _ exception:Expression EOSNoLineTerminator { return { type: "ThrowStatement", - exception: $3 + exception: exception }; } TryStatement - = TryToken __ Block __ Catch __ Finally { + = TryToken __ block:Block __ catch_:Catch __ finally_:Finally { return { type: "TryStatement", - block: $3, - "catch": $5, - "finally": $7 + block: block, + "catch": catch_, + "finally": finally_ }; } - / TryToken __ Block __ Catch { + / TryToken __ block:Block __ catch_:Catch { return { type: "TryStatement", - block: $3, - "catch": $5, + block: block, + "catch": catch_, "finally": null }; } - / TryToken __ Block __ Finally { + / TryToken __ block:Block __ finally_:Finally { return { type: "TryStatement", - block: $3, + block: block, "catch": null, - "finally": $5 + "finally": finally_ }; } Catch - = CatchToken __ "(" __ Identifier __ ")" __ Block { + = CatchToken __ "(" __ identifier:Identifier __ ")" __ block:Block { return { type: "Catch", - identifier: $5, - block: $9 + identifier: identifier, + block: block }; } Finally - = FinallyToken __ Block { + = FinallyToken __ block:Block { return { type: "Finally", - block: $3 + block: block }; } @@ -1393,54 +1454,54 @@ DebuggerStatement /* ===== A.5 Functions and Programs ===== */ FunctionDeclaration - = FunctionToken __ Identifier __ - "(" __ FormalParameterList? __ ")" __ - "{" __ FunctionBody __ "}" { + = FunctionToken __ name:Identifier __ + "(" __ params:FormalParameterList? __ ")" __ + "{" __ elements:FunctionBody __ "}" { return { type: "Function", - name: $3, - params: $7 !== "" ? $7 : [], - elements: $13 + name: name, + params: params !== "" ? params : [], + elements: elements }; } FunctionExpression - = FunctionToken __ Identifier? __ - "(" __ FormalParameterList? __ ")" __ - "{" __ FunctionBody __ "}" { + = FunctionToken __ name:Identifier? __ + "(" __ params:FormalParameterList? __ ")" __ + "{" __ elements:FunctionBody __ "}" { return { type: "Function", - name: $3 !== "" ? $3 : null, - params: $7 !== "" ? $7 : [], - elements: $13 + name: name !== "" ? name : null, + params: params !== "" ? params : [], + elements: elements }; } FormalParameterList - = Identifier (__ "," __ Identifier)* { - var result = [$1]; - for (var i = 0; i < $2.length; i++) { - result.push($2[i][3]); + = head:Identifier tail:(__ "," __ Identifier)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][3]); } return result; } FunctionBody - = SourceElements? { return $1 !== "" ? $1 : []; } + = elements:SourceElements? { return elements !== "" ? elements : []; } Program - = SourceElements? { + = elements:SourceElements? { return { type: "Program", - elements: $1 !== "" ? $1 : [] + elements: elements !== "" ? elements : [] }; } SourceElements - = SourceElement (__ SourceElement)* { - var result = [$1]; - for (var i = 0; i < $2.length; i++) { - result.push($2[i][1]); + = head:SourceElement tail:(__ SourceElement)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][1]); } return result; } diff --git a/examples/json.pegjs b/examples/json.pegjs index 6bfa538..0e06fc1 100644 --- a/examples/json.pegjs +++ b/examples/json.pegjs @@ -3,34 +3,34 @@ /* ===== Syntactical Elements ===== */ start - = _ object { return $2; } + = _ object:object { return object; } object - = "{" _ "}" _ { return {}; } - / "{" _ members "}" _ { return $3; } + = "{" _ "}" _ { return {}; } + / "{" _ members:members "}" _ { return members; } members - = pair ("," _ pair)* { + = head:pair tail:("," _ pair)* { var result = {}; - result[$1[0]] = $1[1]; - for (var i = 0; i < $2.length; i++) { - result[$2[i][2][0]] = $2[i][2][1]; + result[head[0]] = head[1]; + for (var i = 0; i < tail.length; i++) { + result[tail[i][2][0]] = tail[i][2][1]; } return result; } pair - = string ":" _ value { return [$1, $4]; } + = name:string ":" _ value:value { return [name, value]; } array - = "[" _ "]" _ { return []; } - / "[" _ elements "]" _ { return $3; } + = "[" _ "]" _ { return []; } + / "[" _ elements:elements "]" _ { return elements; } elements - = value ("," _ value)* { - var result = [$1]; - for (var i = 0; i < $2.length; i++) { - result.push($2[i][2]); + = head:value tail:("," _ value)* { + var result = [head]; + for (var i = 0; i < tail.length; i++) { + result.push(tail[i][2]); } return result; } @@ -48,11 +48,11 @@ value /* ===== Lexical Elements ===== */ string "string" - = '"' '"' _ { return ""; } - / '"' chars '"' _ { return $2; } + = '"' '"' _ { return ""; } + / '"' chars:chars '"' _ { return chars; } chars - = char+ { return $1.join(""); } + = chars:char+ { return chars.join(""); } char // In the original JSON grammar: "any-Unicode-character-except-"-or-\-or-control-character" @@ -65,33 +65,33 @@ char / "\\n" { return "\n"; } / "\\r" { return "\r"; } / "\\t" { return "\t"; } - / "\\u" hexDigit hexDigit hexDigit hexDigit { - return String.fromCharCode(parseInt("0x" + $2 + $3 + $4 + $5)); + / "\\u" h1:hexDigit h2:hexDigit h3:hexDigit h4:hexDigit { + return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4)); } number "number" - = int frac exp _ { return parseFloat($1 + $2 + $3); } - / int frac _ { return parseFloat($1 + $2); } - / int exp _ { return parseFloat($1 + $2); } - / int _ { return parseFloat($1); } + = int:int frac:frac exp:exp _ { return parseFloat(int + frac + exp); } + / int:int frac:frac _ { return parseFloat(int + frac); } + / int:int exp:exp _ { return parseFloat(int + exp); } + / int:int _ { return parseFloat(int); } int - = digit19 digits { return $1 + $2; } - / digit - / "-" digit19 digits { return $1 + $2 + $3; } - / "-" digit { return $1 + $2; } + = digit19:digit19 digits:digits { return digit19 + digits; } + / digit:digit + / "-" digit19:digit19 digits:digits { return "-" + digit19 + digits; } + / "-" digit:digit { return "-" + digit; } frac - = "." digits { return $1 + $2; } + = "." digits:digits { return "." + digits; } exp - = e digits { return $1 + $2; } + = e:e digits:digits { return e + digits; } digits - = digit+ { return $1.join(""); } + = digits:digit+ { return digits.join(""); } e - = [eE] [+-]? { return $1 + $2; } + = e:[eE] sign:[+-]? { return e + sign; } /* * The following rules are not present in the original JSON gramar, but they are diff --git a/lib/compiler.js b/lib/compiler.js index 0698700..af54255 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -716,7 +716,7 @@ PEG.Compiler = { * In case of sequences, we splat their elements into function arguments * one by one. Example: * - * start: "a" "b" "c" { alert(arguments.length) } // => 3 + * start: a:"a" b:"b" c:"c" { alert(arguments.length) } // => 3 * * This behavior is reflected in this function. */ @@ -724,38 +724,36 @@ PEG.Compiler = { var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); if (node.expression.type === "sequence") { - var params = PEG.ArrayUtils.map( - PEG.ArrayUtils.range(1, node.expression.elements.length + 1), - function(n) { return "$" + n; } - ).join(", "); - - var invocationCode = PEG.Compiler.formatCode( - "(function(${params}) { ${action} }).apply(null, ${expressionResultVar})", - { - params: params, - action: node.action, - expressionResultVar: expressionResultVar + var formalParams = []; + var actualParams = []; + + var elements = node.expression.elements; + var elementsLength = elements.length; + for (var i = 0; i < elementsLength; i++) { + if (elements[i].type === "labeled") { + formalParams.push(elements[i].label); + actualParams.push(expressionResultVar + "[" + i + "]"); } - ); + } + } else if (node.expression.type === "labeled") { + var formalParams = [node.expression.label]; + var actualParams = [expressionResultVar]; } else { - var invocationCode = PEG.Compiler.formatCode( - "(function($1) { ${action} })(${expressionResultVar})", - { - action: node.action, - expressionResultVar: expressionResultVar - } - ); + var formalParams = []; + var actualParams = []; } return PEG.Compiler.formatCode( "${expressionCode}", "var ${resultVar} = ${expressionResultVar} !== null", - " ? ${invocationCode}", + " ? (function(${formalParams}) { ${action} })(${actualParams})", " : null;", { expressionCode: PEG.Compiler.compileNode(node.expression, expressionResultVar), expressionResultVar: expressionResultVar, - invocationCode: invocationCode, + action: node.action, + formalParams: formalParams.join(", "), + actualParams: actualParams.join(", "), resultVar: resultVar } ); diff --git a/lib/metagrammar.js b/lib/metagrammar.js index f7f38a0..324f6e6 100644 --- a/lib/metagrammar.js +++ b/lib/metagrammar.js @@ -85,11 +85,11 @@ PEG.grammarParser = (function(){ this._pos = savedPos0; } var result0 = result1 !== null - ? (function($1, $2) { + ? (function(rules) { var result = {}; - PEG.ArrayUtils.each($2, function(rule) { result[rule.name] = rule; }); + PEG.ArrayUtils.each(rules, function(rule) { result[rule.name] = rule; }); return result; - }).apply(null, result1) + })(result1[1]) : null; @@ -157,14 +157,14 @@ PEG.grammarParser = (function(){ this._pos = savedPos1; } var result5 = result6 !== null - ? (function($1, $2, $3, $4) { + ? (function(name, displayName, expression) { return { type: "rule", - name: $1, - displayName: $2 !== "" ? $2 : null, - expression: $4 + name: name, + displayName: displayName !== "" ? displayName : null, + expression: expression }; - }).apply(null, result6) + })(result6[0], result6[1], result6[3]) : null; @@ -233,10 +233,10 @@ PEG.grammarParser = (function(){ this._pos = savedPos2; } var result13 = result14 !== null - ? (function($1, $2) { - if ($2.length > 0) { - var alternatives = [$1].concat(PEG.ArrayUtils.map( - $2, + ? (function(head, tail) { + if (tail.length > 0) { + var alternatives = [head].concat(PEG.ArrayUtils.map( + tail, function(element) { return element[1]; } )); return { @@ -244,9 +244,9 @@ PEG.grammarParser = (function(){ alternatives: alternatives } } else { - return $1; + return head; } - }).apply(null, result14) + })(result14[0], result14[1]) : null; @@ -289,19 +289,19 @@ PEG.grammarParser = (function(){ this._pos = savedPos4; } var result24 = result25 !== null - ? (function($1, $2) { - var expression = $1.length != 1 + ? (function(elements, action) { + var expression = elements.length != 1 ? { type: "sequence", - elements: $1 + elements: elements } - : $1[0]; + : elements[0]; return { type: "action", expression: expression, - action: $2 + action: action }; - }).apply(null, result25) + })(result25[0], result25[1]) : null; if (result24 !== null) { var result20 = result24; @@ -313,13 +313,13 @@ PEG.grammarParser = (function(){ var result23 = this._parse_labeled(context); } var result21 = result22 !== null - ? (function($1) { - return $1.length != 1 + ? (function(elements) { + return elements.length != 1 ? { type: "sequence", - elements: $1 + elements: elements } - : $1[0]; + : elements[0]; })(result22) : null; if (result21 !== null) { @@ -370,13 +370,13 @@ PEG.grammarParser = (function(){ this._pos = savedPos5; } var result31 = result32 !== null - ? (function($1, $2, $3) { + ? (function(label, expression) { return { type: "labeled", - label: $1, - expression: $3 + label: label, + expression: expression }; - }).apply(null, result32) + })(result32[0], result32[2]) : null; if (result31 !== null) { var result29 = result31; @@ -424,7 +424,12 @@ PEG.grammarParser = (function(){ this._pos = savedPos7; } var result42 = result43 !== null - ? (function($1, $2) { return { type: "and_predicate", expression: $2 }; }).apply(null, result43) + ? (function(expression) { + return { + type: "and_predicate", + expression: expression + }; + })(result43[1]) : null; if (result42 !== null) { var result36 = result42; @@ -444,7 +449,12 @@ PEG.grammarParser = (function(){ this._pos = savedPos6; } var result38 = result39 !== null - ? (function($1, $2) { return { type: "not_predicate", expression: $2 }; }).apply(null, result39) + ? (function(expression) { + return { + type: "not_predicate", + expression: expression + }; + })(result39[1]) : null; if (result38 !== null) { var result36 = result38; @@ -493,7 +503,12 @@ PEG.grammarParser = (function(){ this._pos = savedPos10; } var result56 = result57 !== null - ? (function($1, $2) { return { type: "optional", expression: $1}; }).apply(null, result57) + ? (function(expression) { + return { + type: "optional", + expression: expression + }; + })(result57[0]) : null; if (result56 !== null) { var result46 = result56; @@ -513,7 +528,12 @@ PEG.grammarParser = (function(){ this._pos = savedPos9; } var result52 = result53 !== null - ? (function($1, $2) { return { type: "zero_or_more", expression: $1}; }).apply(null, result53) + ? (function(expression) { + return { + type: "zero_or_more", + expression: expression + }; + })(result53[0]) : null; if (result52 !== null) { var result46 = result52; @@ -533,7 +553,12 @@ PEG.grammarParser = (function(){ this._pos = savedPos8; } var result48 = result49 !== null - ? (function($1, $2) { return { type: "one_or_more", expression: $1}; }).apply(null, result49) + ? (function(expression) { + return { + type: "one_or_more", + expression: expression + }; + })(result49[0]) : null; if (result48 !== null) { var result46 = result48; @@ -624,21 +649,31 @@ PEG.grammarParser = (function(){ this._pos = savedPos12; } var result71 = result72 !== null - ? (function($1, $2) { return { type: "rule_ref", name: $1 }; }).apply(null, result72) + ? (function(name) { + return { + type: "rule_ref", + name: name + }; + })(result72[0]) : null; if (result71 !== null) { var result60 = result71; } else { var result70 = this._parse_literal(context); var result69 = result70 !== null - ? (function($1) { return { type: "literal", value: $1 }; })(result70) + ? (function(value) { + return { + type: "literal", + value: value + }; + })(result70) : null; if (result69 !== null) { var result60 = result69; } else { var result68 = this._parse_dot(context); var result67 = result68 !== null - ? (function($1) { return { type: "any" }; })(result68) + ? (function() { return { type: "any" }; })() : null; if (result67 !== null) { var result60 = result67; @@ -668,7 +703,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos11; } var result61 = result62 !== null - ? (function($1, $2, $3) { return $2; }).apply(null, result62) + ? (function(expression) { return expression; })(result62[1]) : null; if (result61 !== null) { var result60 = result61; @@ -716,7 +751,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos15; } var result80 = result81 !== null - ? (function($1, $2) { return $1.substr(1, $1.length - 2); }).apply(null, result81) + ? (function(braced) { return braced.substr(1, braced.length - 2); })(result81[0]) : null; context.reportMatchFailures = savedReportMatchFailures; if (context.reportMatchFailures && result80 === null) { @@ -803,7 +838,9 @@ PEG.grammarParser = (function(){ this._pos = savedPos16; } var result84 = result85 !== null - ? (function($1, $2, $3) { return $1 + $2.join("") + $3; }).apply(null, result85) + ? (function(parts) { + return "{" + parts.join("") + "}"; + })(result85[1]) : null; @@ -837,7 +874,7 @@ PEG.grammarParser = (function(){ var result93 = null; } var result92 = result93 !== null - ? (function($1) { return $1.join(""); })(result93) + ? (function(chars) { return chars.join(""); })(result93) : null; @@ -913,7 +950,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos17; } var result96 = result97 !== null - ? (function($1, $2) { return $1; }).apply(null, result97) + ? (function() { return "="; })() : null; @@ -959,7 +996,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos18; } var result100 = result101 !== null - ? (function($1, $2) { return $1; }).apply(null, result101) + ? (function() { return ":"; })() : null; @@ -1005,7 +1042,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos19; } var result104 = result105 !== null - ? (function($1, $2) { return $1; }).apply(null, result105) + ? (function() { return "/"; })() : null; @@ -1051,7 +1088,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos20; } var result108 = result109 !== null - ? (function($1, $2) { return $1; }).apply(null, result109) + ? (function() { return "&"; })() : null; @@ -1097,7 +1134,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos21; } var result112 = result113 !== null - ? (function($1, $2) { return $1; }).apply(null, result113) + ? (function() { return "!"; })() : null; @@ -1143,7 +1180,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos22; } var result116 = result117 !== null - ? (function($1, $2) { return $1; }).apply(null, result117) + ? (function() { return "?"; })() : null; @@ -1189,7 +1226,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos23; } var result120 = result121 !== null - ? (function($1, $2) { return $1; }).apply(null, result121) + ? (function() { return "*"; })() : null; @@ -1235,7 +1272,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos24; } var result124 = result125 !== null - ? (function($1, $2) { return $1; }).apply(null, result125) + ? (function() { return "+"; })() : null; @@ -1281,7 +1318,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos25; } var result128 = result129 !== null - ? (function($1, $2) { return $1; }).apply(null, result129) + ? (function() { return "("; })() : null; @@ -1327,7 +1364,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos26; } var result132 = result133 !== null - ? (function($1, $2) { return $1; }).apply(null, result133) + ? (function() { return ")"; })() : null; @@ -1373,7 +1410,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos27; } var result136 = result137 !== null - ? (function($1, $2) { return $1; }).apply(null, result137) + ? (function() { return "."; })() : null; @@ -1526,9 +1563,9 @@ PEG.grammarParser = (function(){ this._pos = savedPos28; } var result140 = result141 !== null - ? (function($1, $2, $3) { - return $1 + $2.join(""); - }).apply(null, result141) + ? (function(head, tail) { + return head + tail.join(""); + })(result141[0], result141[1]) : null; context.reportMatchFailures = savedReportMatchFailures; if (context.reportMatchFailures && result140 === null) { @@ -1579,7 +1616,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos29; } var result153 = result154 !== null - ? (function($1, $2) { return $1; }).apply(null, result154) + ? (function(literal) { return literal; })(result154[0]) : null; context.reportMatchFailures = savedReportMatchFailures; if (context.reportMatchFailures && result153 === null) { @@ -1646,7 +1683,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos30; } var result159 = result160 !== null - ? (function($1, $2, $3) { return $2.join(""); }).apply(null, result160) + ? (function(chars) { return chars.join(""); })(result160[1]) : null; @@ -1785,7 +1822,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos31; } var result172 = result173 !== null - ? (function($1, $2) { return $2; }).apply(null, result173) + ? (function(char_) { return char_; })(result173[1]) : null; @@ -1850,7 +1887,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos33; } var result180 = result181 !== null - ? (function($1, $2, $3) { return $2.join(""); }).apply(null, result181) + ? (function(chars) { return chars.join(""); })(result181[1]) : null; @@ -1989,7 +2026,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos34; } var result193 = result194 !== null - ? (function($1, $2) { return $2; }).apply(null, result194) + ? (function(char_) { return char_; })(result194[1]) : null; @@ -2096,23 +2133,25 @@ PEG.grammarParser = (function(){ this._pos = savedPos36; } var result201 = result202 !== null - ? (function($1, $2, $3, $4, $5) { - parts = PEG.ArrayUtils.map($3, function(part) { return part.data; }); + ? (function(inverted, parts) { + partsConverted = PEG.ArrayUtils.map(parts, function(part) { + return part.data; + }); rawText = "[" - + $2 - + PEG.ArrayUtils.map($3, function(part) { + + inverted + + PEG.ArrayUtils.map(parts, function(part) { return part.rawText; }).join("") + "]"; return { type: "class", - inverted: $2 === "^", - parts: parts, + inverted: inverted === "^", + parts: partsConverted, // FIXME: Get the raw text from the input directly. rawText: rawText }; - }).apply(null, result202) + })(result202[1], result202[2]) : null; context.reportMatchFailures = savedReportMatchFailures; if (context.reportMatchFailures && result201 === null) { @@ -2166,19 +2205,19 @@ PEG.grammarParser = (function(){ this._pos = savedPos37; } var result212 = result213 !== null - ? (function($1, $2, $3) { - if ($1.data.charCodeAt(0) > $3.data.charCodeAt(0)) { + ? (function(begin, end) { + if (begin.data.charCodeAt(0) > end.data.charCodeAt(0)) { throw new this.SyntaxError( - "Invalid character range: " + $1.rawText + "-" + $3.rawText + "." + "Invalid character range: " + begin.rawText + "-" + end.rawText + "." ); } return { - data: [$1.data, $3.data], + data: [begin.data, end.data], // FIXME: Get the raw text from the input directly. - rawText: $1.rawText + "-" + $3.rawText + rawText: begin.rawText + "-" + end.rawText } - }).apply(null, result213) + })(result213[0], result213[2]) : null; @@ -2203,11 +2242,11 @@ PEG.grammarParser = (function(){ var result218 = this._parse_bracketDelimitedCharacter(context); var result217 = result218 !== null - ? (function($1) { + ? (function(char_) { return { - data: $1, + data: char_, // FIXME: Get the raw text from the input directly. - rawText: PEG.RegExpUtils.quoteForClass($1) + rawText: PEG.RegExpUtils.quoteForClass(char_) }; })(result218) : null; @@ -2348,7 +2387,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos38; } var result226 = result227 !== null - ? (function($1, $2) { return $2; }).apply(null, result227) + ? (function(char_) { return char_; })(result227[1]) : null; @@ -2454,15 +2493,15 @@ PEG.grammarParser = (function(){ this._pos = savedPos40; } var result234 = result235 !== null - ? (function($1, $2, $3) { - return $3 + ? (function(char_) { + return char_ .replace("b", "\b") .replace("f", "\f") .replace("n", "\n") .replace("r", "\r") .replace("t", "\t") .replace("v", "\x0B") // IE does not recognize "\v". - }).apply(null, result235) + })(result235[2]) : null; @@ -2518,7 +2557,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos42; } var result244 = result245 !== null - ? (function($1, $2) { return "\0"; }).apply(null, result245) + ? (function() { return "\0"; })() : null; @@ -2570,9 +2609,9 @@ PEG.grammarParser = (function(){ this._pos = savedPos44; } var result249 = result250 !== null - ? (function($1, $2, $3) { - return String.fromCharCode(parseInt("0x" + $2 + $3)); - }).apply(null, result250) + ? (function(h1, h2) { + return String.fromCharCode(parseInt("0x" + h1 + h2)); + })(result250[1], result250[2]) : null; @@ -2636,9 +2675,9 @@ PEG.grammarParser = (function(){ this._pos = savedPos45; } var result254 = result255 !== null - ? (function($1, $2, $3, $4, $5) { - return String.fromCharCode(parseInt("0x" + $2 + $3 + $4 + $5)); - }).apply(null, result255) + ? (function(h1, h2, h3, h4) { + return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4)); + })(result255[1], result255[2], result255[3], result255[4]) : null; @@ -2684,7 +2723,7 @@ PEG.grammarParser = (function(){ this._pos = savedPos46; } var result261 = result262 !== null - ? (function($1, $2) { return $2; }).apply(null, result262) + ? (function(eol) { return eol; })(result262[1]) : null; diff --git a/lib/metagrammar.pegjs b/lib/metagrammar.pegjs index 27acd09..9fb170a 100644 --- a/lib/metagrammar.pegjs +++ b/lib/metagrammar.pegjs @@ -1,17 +1,17 @@ grammar - = __ rule+ { + = __ rules:rule+ { var result = {}; - PEG.ArrayUtils.each($2, function(rule) { result[rule.name] = rule; }); + PEG.ArrayUtils.each(rules, function(rule) { result[rule.name] = rule; }); return result; } rule - = identifier (literal / "") equals expression { + = name:identifier displayName:(literal / "") equals expression:expression { return { type: "rule", - name: $1, - displayName: $2 !== "" ? $2 : null, - expression: $4 + name: name, + displayName: displayName !== "" ? displayName : null, + expression: expression }; } @@ -19,10 +19,10 @@ expression = choice choice - = sequence (slash sequence)* { - if ($2.length > 0) { - var alternatives = [$1].concat(PEG.ArrayUtils.map( - $2, + = head:sequence tail:(slash sequence)* { + if (tail.length > 0) { + var alternatives = [head].concat(PEG.ArrayUtils.map( + tail, function(element) { return element[1]; } )); return { @@ -30,86 +30,123 @@ choice alternatives: alternatives } } else { - return $1; + return head; } } sequence - = labeled* action { - var expression = $1.length != 1 + = elements:labeled* action:action { + var expression = elements.length != 1 ? { type: "sequence", - elements: $1 + elements: elements } - : $1[0]; + : elements[0]; return { type: "action", expression: expression, - action: $2 + action: action }; } - / labeled* { - return $1.length != 1 + / elements:labeled* { + return elements.length != 1 ? { type: "sequence", - elements: $1 + elements: elements } - : $1[0]; + : elements[0]; } labeled - = identifier colon prefixed { + = label:identifier colon expression:prefixed { return { type: "labeled", - label: $1, - expression: $3 + label: label, + expression: expression }; } / prefixed prefixed - = and suffixed { return { type: "and_predicate", expression: $2 }; } - / not suffixed { return { type: "not_predicate", expression: $2 }; } + = and expression:suffixed { + return { + type: "and_predicate", + expression: expression + }; + } + / not expression:suffixed { + return { + type: "not_predicate", + expression: expression + }; + } / suffixed suffixed - = primary question { return { type: "optional", expression: $1}; } - / primary star { return { type: "zero_or_more", expression: $1}; } - / primary plus { return { type: "one_or_more", expression: $1}; } + = expression:primary question { + return { + type: "optional", + expression: expression + }; + } + / expression:primary star { + return { + type: "zero_or_more", + expression: expression + }; + } + / expression:primary plus { + return { + type: "one_or_more", + expression: expression + }; + } / primary primary - = identifier !(( literal / "") equals) { return { type: "rule_ref", name: $1 }; } - / literal { return { type: "literal", value: $1 }; } - / dot { return { type: "any" }; } + = name:identifier !(( literal / "") equals) { + return { + type: "rule_ref", + name: name + }; + } + / value:literal { + return { + type: "literal", + value: value + }; + } + / dot { return { type: "any" }; } / class - / lparen expression rparen { return $2; } + / lparen expression:expression rparen { return expression; } /* "Lexical" elements */ action "action" - = braced __ { return $1.substr(1, $1.length - 2); } + = braced:braced __ { return braced.substr(1, braced.length - 2); } braced - = "{" (braced / nonBraceCharacter)* "}" { return $1 + $2.join("") + $3; } + = "{" parts:(braced / nonBraceCharacter)* "}" { + return "{" + parts.join("") + "}"; + } nonBraceCharacters - = nonBraceCharacter+ { return $1.join(""); } + = chars:nonBraceCharacter+ { return chars.join(""); } nonBraceCharacter = [^{}] -equals = "=" __ { return $1; } -colon = ":" __ { return $1; } -slash = "/" __ { return $1; } -and = "&" __ { return $1; } -not = "!" __ { return $1; } -question = "?" __ { return $1; } -star = "*" __ { return $1; } -plus = "+" __ { return $1; } -lparen = "(" __ { return $1; } -rparen = ")" __ { return $1; } -dot = "." __ { return $1; } +equals = "=" __ { return "="; } +colon = ":" __ { return ":"; } +slash = "/" __ { return "/"; } +and = "&" __ { return "&"; } +not = "!" __ { return "!"; } +question = "?" __ { return "?"; } +star = "*" __ { return "*"; } +plus = "+" __ { return "+"; } +lparen = "(" __ { return "("; } +rparen = ")" __ { return ")"; } +dot = "." __ { return "."; } /* * Modelled after ECMA-262, 5th ed., 7.6, but much simplified: @@ -127,8 +164,8 @@ dot = "." __ { return $1; } * easier, there is no "philosophical" reason behind them. */ identifier "identifier" - = (letter / "_" / "$") (letter / digit / "_" / "$")* __ { - return $1 + $2.join(""); + = head:(letter / "_" / "$") tail:(letter / digit / "_" / "$")* __ { + return head + tail.join(""); } /* @@ -136,10 +173,10 @@ identifier "identifier" * vaguely). */ literal "literal" - = (doubleQuotedLiteral / singleQuotedLiteral) __ { return $1; } + = literal:(doubleQuotedLiteral / singleQuotedLiteral) __ { return literal; } doubleQuotedLiteral - = '"' doubleQuotedCharacter* '"' { return $2.join(""); } + = '"' chars:doubleQuotedCharacter* '"' { return chars.join(""); } doubleQuotedCharacter = simpleDoubleQuotedCharacter @@ -150,10 +187,10 @@ doubleQuotedCharacter / eolEscapeSequence simpleDoubleQuotedCharacter - = !('"' / "\\" / eolChar) . { return $2; } + = !('"' / "\\" / eolChar) char_:. { return char_; } singleQuotedLiteral - = "'" singleQuotedCharacter* "'" { return $2.join(""); } + = "'" chars:singleQuotedCharacter* "'" { return chars.join(""); } singleQuotedCharacter = simpleSingleQuotedCharacter @@ -164,48 +201,50 @@ singleQuotedCharacter / eolEscapeSequence simpleSingleQuotedCharacter - = !("'" / "\\" / eolChar) . { return $2; } + = !("'" / "\\" / eolChar) char_:. { return char_; } class "character class" - = "[" "^"? (classCharacterRange / classCharacter)* "]" __ { - parts = PEG.ArrayUtils.map($3, function(part) { return part.data; }); + = "[" inverted:"^"? parts:(classCharacterRange / classCharacter)* "]" __ { + partsConverted = PEG.ArrayUtils.map(parts, function(part) { + return part.data; + }); rawText = "[" - + $2 - + PEG.ArrayUtils.map($3, function(part) { + + inverted + + PEG.ArrayUtils.map(parts, function(part) { return part.rawText; }).join("") + "]"; return { type: "class", - inverted: $2 === "^", - parts: parts, + inverted: inverted === "^", + parts: partsConverted, // FIXME: Get the raw text from the input directly. rawText: rawText }; } classCharacterRange - = classCharacter "-" classCharacter { - if ($1.data.charCodeAt(0) > $3.data.charCodeAt(0)) { + = begin:classCharacter "-" end:classCharacter { + if (begin.data.charCodeAt(0) > end.data.charCodeAt(0)) { throw new this.SyntaxError( - "Invalid character range: " + $1.rawText + "-" + $3.rawText + "." + "Invalid character range: " + begin.rawText + "-" + end.rawText + "." ); } return { - data: [$1.data, $3.data], + data: [begin.data, end.data], // FIXME: Get the raw text from the input directly. - rawText: $1.rawText + "-" + $3.rawText + rawText: begin.rawText + "-" + end.rawText } } classCharacter - = bracketDelimitedCharacter { + = char_:bracketDelimitedCharacter { return { - data: $1, + data: char_, // FIXME: Get the raw text from the input directly. - rawText: PEG.RegExpUtils.quoteForClass($1) + rawText: PEG.RegExpUtils.quoteForClass(char_) }; } @@ -218,11 +257,11 @@ bracketDelimitedCharacter / eolEscapeSequence simpleBracketDelimitedCharacter - = !("]" / "\\" / eolChar) . { return $2; } + = !("]" / "\\" / eolChar) char_:. { return char_; } simpleEscapeSequence - = "\\" !(digit / "x" / "u" / eolChar) . { - return $3 + = "\\" !(digit / "x" / "u" / eolChar) char_:. { + return char_ .replace("b", "\b") .replace("f", "\f") .replace("n", "\n") @@ -235,17 +274,17 @@ zeroEscapeSequence = "\\0" !digit { return "\0"; } hexEscapeSequence - = "\\x" hexDigit hexDigit { - return String.fromCharCode(parseInt("0x" + $2 + $3)); + = "\\x" h1:hexDigit h2:hexDigit { + return String.fromCharCode(parseInt("0x" + h1 + h2)); } unicodeEscapeSequence - = "\\u" hexDigit hexDigit hexDigit hexDigit { - return String.fromCharCode(parseInt("0x" + $2 + $3 + $4 + $5)); + = "\\u" h1:hexDigit h2:hexDigit h3:hexDigit h4:hexDigit { + return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4)); } eolEscapeSequence - = "\\" eol { return $2; } + = "\\" eol:eol { return eol; } digit = [0-9] diff --git a/test/compiler-test.js b/test/compiler-test.js index 34aadd9..8e2a3bb 100644 --- a/test/compiler-test.js +++ b/test/compiler-test.js @@ -342,33 +342,41 @@ test("one or more expressions", function() { }); test("actions", function() { - var singleMatchParser = PEG.buildParser( - 'start = "a" { return Array.prototype.slice.call(arguments).join("").toUpperCase(); }' + var singleElementUnlabeledParser = PEG.buildParser( + 'start = "a" { return arguments.length; }' ); - parses(singleMatchParser, "a", "A"); + parses(singleElementUnlabeledParser, "a", 0); - var multiMatchParser = PEG.buildParser( - 'start = "a" "b" "c" { return Array.prototype.slice.call(arguments).join("").toUpperCase(); }' + var singleElementLabeledParser = PEG.buildParser( + 'start = a:"a" { return [arguments.length, a]; }' ); - parses(multiMatchParser, "abc", "ABC"); + parses(singleElementLabeledParser, "a", [1, "a"]); - var innerMatchParser = PEG.buildParser( - 'start = "a" ("b" "c" "d" { return Array.prototype.slice.call(arguments).join("").toUpperCase(); }) "e"' + var multiElementUnlabeledParser = PEG.buildParser( + 'start = "a" "b" "c" { return arguments.length; }' ); - parses(innerMatchParser, "abcde", ["a", "BCD", "e"]); + parses(multiElementUnlabeledParser, "abc", 0); + + var multiElementLabeledParser = PEG.buildParser( + 'start = a:"a" "b" c:"c" { return [arguments.length, a, c]; }' + ); + parses(multiElementLabeledParser, "abc", [2, "a", "c"]); + + var innerElementsUnlabeledParser = PEG.buildParser( + 'start = "a" ("b" "c" "d" { return arguments.length; }) "e"' + ); + parses(innerElementsUnlabeledParser, "abcde", ["a", 0, "e"]); + + var innerElementsLabeledParser = PEG.buildParser( + 'start = "a" (b:"b" "c" d:"d" { return [arguments.length, b, d]; }) "e"' + ); + parses(innerElementsLabeledParser, "abcde", ["a", [2, "b", "d"], "e"]); /* Test that the action is not called when its expression does not match. */ var notAMatchParser = PEG.buildParser( 'start = "a" { ok(false, "action got called when it should not be"); }' ); doesNotParse(notAMatchParser, "b"); - - var variablesParser = PEG.buildParser([ - 'start = "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" {', - ' return [$1, $2, $3, $4, $5, $6, $7, $8, $9, $10].join("").toUpperCase();', - ' }' - ].join("\n")); - parses(variablesParser, "abcdefghij", "ABCDEFGHIJ"); }); test("rule references", function() { @@ -580,9 +588,9 @@ test("error messages", function() { test("error positions", function() { var parser = PEG.buildParser([ - 'start = line (("\\r" / "\\n" / "\\u2028" / "\\u2029")+ line)*', - 'line = digit (" "+ digit)*', - 'digit = [0-9]+ { return $1.join(""); }' + 'start = line (("\\r" / "\\n" / "\\u2028" / "\\u2029")+ line)*', + 'line = digits (" "+ digits)*', + 'digits = digits:[0-9]+ { return digits.join(""); }' ].join("\n")); doesNotParseWithPos(parser, "a", 1, 1); @@ -611,21 +619,21 @@ test("arithmetics", function() { * Expr ← Sum */ var parser = PEG.buildParser([ - 'Value = [0-9]+ { return parseInt($1.join("")); }', - ' / "(" Expr ")" { return $2; }', - 'Product = Value (("*" / "/") Value)* {', - ' var result = $1;', - ' for (var i = 0; i < $2.length; i++) {', - ' if ($2[i][0] == "*") { result *= $2[i][1]; }', - ' if ($2[i][0] == "/") { result /= $2[i][1]; }', + 'Value = digits:[0-9]+ { return parseInt(digits.join("")); }', + ' / "(" expr:Expr ")" { return expr; }', + 'Product = head:Value tail:(("*" / "/") Value)* {', + ' var result = head;', + ' for (var i = 0; i < tail.length; i++) {', + ' if (tail[i][0] == "*") { result *= tail[i][1]; }', + ' if (tail[i][0] == "/") { result /= tail[i][1]; }', ' }', ' return result;', ' }', - 'Sum = Product (("+" / "-") Product)* {', - ' var result = $1;', - ' for (var i = 0; i < $2.length; i++) {', - ' if ($2[i][0] == "+") { result += $2[i][1]; }', - ' if ($2[i][0] == "-") { result -= $2[i][1]; }', + 'Sum = head:Product tail:(("+" / "-") Product)* {', + ' var result = head;', + ' for (var i = 0; i < tail.length; i++) {', + ' if (tail[i][0] == "+") { result += tail[i][1]; }', + ' if (tail[i][0] == "-") { result -= tail[i][1]; }', ' }', ' return result;', ' }', @@ -667,9 +675,9 @@ test("non-context-free language", function() { * B ← b B? c */ var parser = PEG.buildParser([ - 'S = &(A "c") "a"+ B !("a" / "b" / "c") { return $2.join("") + $3; }', - 'A = "a" A? "b" { return $1 + $2 + $3; }', - 'B = "b" B? "c" { return $1 + $2 + $3; }', + 'S = &(A "c") a:"a"+ B:B !("a" / "b" / "c") { return a.join("") + B; }', + 'A = a:"a" A:A? b:"b" { return a + A + b; }', + 'B = b:"b" B:B? c:"c" { return b + B + c; }', ].join("\n"), "S"); parses(parser, "abc", "abc"); @@ -693,9 +701,9 @@ test("nested comments", function() { var parser = PEG.buildParser([ 'Begin = "(*"', 'End = "*)"', - 'C = Begin N* End { return $1 + $2.join("") + $3; }', + 'C = begin:Begin ns:N* end:End { return begin + ns.join("") + end; }', 'N = C', - ' / (!Begin !End Z) { return $3; }', + ' / !Begin !End z:Z { return z; }', 'Z = .' ].join("\n"), "C");