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
redux
David Majda 15 years ago
parent 52704593cd
commit ee8c121676

@ -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); }

@ -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; }

File diff suppressed because it is too large Load Diff

@ -3,34 +3,34 @@
/* ===== Syntactical Elements ===== */
start
= _ object { return $2; }
= _ object:object { return object; }
object
= "{" _ "}" _ { return {}; }
/ "{" _ members "}" _ { return $3; }
/ "{" _ 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; }
/ "[" _ 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;
}
@ -49,10 +49,10 @@ value
string "string"
= '"' '"' _ { return ""; }
/ '"' chars '"' _ { return $2; }
/ '"' 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

@ -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 formalParams = [];
var actualParams = [];
var invocationCode = PEG.Compiler.formatCode(
"(function(${params}) { ${action} }).apply(null, ${expressionResultVar})",
{
params: params,
action: node.action,
expressionResultVar: expressionResultVar
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 {
var invocationCode = PEG.Compiler.formatCode(
"(function($1) { ${action} })(${expressionResultVar})",
{
action: node.action,
expressionResultVar: expressionResultVar
}
);
} else if (node.expression.type === "labeled") {
var formalParams = [node.expression.label];
var actualParams = [expressionResultVar];
} else {
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
}
);

@ -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;

@ -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 }; }
= 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]

@ -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() {
@ -581,8 +589,8 @@ 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(""); }'
'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");

Loading…
Cancel
Save