Replace ":" after a rule name with "="

I'll introduce labelled expressions shortly and I want to use ":" as a
label-expression separator. This change avoids conflict between the two
meanings of ":". (What would e.g. "foo: 'bar'" mean?  Rule "foo"
matching string "bar", or string "bar" labelled "foo"?)
redux
David Majda 14 years ago
parent 7fdf0492c7
commit 698564a3c2

@ -3,15 +3,15 @@
* "2*(3+4)". The parser generated from this grammar then computes their value. * "2*(3+4)". The parser generated from this grammar then computes their value.
*/ */
start : additive start = additive
additive : multiplicative "+" additive { return $1 + $3; } additive = multiplicative "+" additive { return $1 + $3; }
/ multiplicative / multiplicative
multiplicative : primary "*" multiplicative { return $1 * $3; } multiplicative = primary "*" multiplicative { return $1 * $3; }
/ primary / primary
primary : integer primary = integer
/ "(" additive ")" { return $2; } / "(" additive ")" { return $2; }
integer "integer" : [0-9]+ { return parseInt($1.join(""), 10); } integer "integer" = [0-9]+ { return parseInt($1.join(""), 10); }

@ -14,9 +14,9 @@
/* ===== Syntactical Elements ===== */ /* ===== Syntactical Elements ===== */
start: stylesheet comment* { return $1; } start = stylesheet comment* { return $1; }
stylesheet: stylesheet =
(CHARSET_SYM STRING ";")? (S / CDO / CDC)* (CHARSET_SYM STRING ";")? (S / CDO / CDC)*
(import (CDO S* / CDC S*)*)* (import (CDO S* / CDC S*)*)*
((ruleset / media / page) (CDO S* / CDC S*)*)* ((ruleset / media / page) (CDO S* / CDC S*)*)*
@ -39,7 +39,7 @@ stylesheet:
}; };
} }
import: IMPORT_SYM S* (STRING / URI) S* media_list? ";" S* { import = IMPORT_SYM S* (STRING / URI) S* media_list? ";" S* {
return { return {
type: "import_rule", type: "import_rule",
href: $3, href: $3,
@ -47,7 +47,7 @@ import: IMPORT_SYM S* (STRING / URI) S* media_list? ";" S* {
}; };
} }
media: MEDIA_SYM S* media_list "{" S* ruleset* "}" S* { media = MEDIA_SYM S* media_list "{" S* ruleset* "}" S* {
return { return {
type: "media_rule", type: "media_rule",
media: $3, media: $3,
@ -55,7 +55,7 @@ media: MEDIA_SYM S* media_list "{" S* ruleset* "}" S* {
}; };
} }
media_list: medium ("," S* medium)* { media_list = medium ("," S* medium)* {
var result = [$1]; var result = [$1];
for (var i = 0; i < $2.length; i++) { for (var i = 0; i < $2.length; i++) {
result.push($2[i][2]); result.push($2[i][2]);
@ -63,9 +63,9 @@ media_list: medium ("," S* medium)* {
return result; return result;
} }
medium: IDENT S* { return $1; } medium = IDENT S* { return $1; }
page: PAGE_SYM S* pseudo_page? "{" S* declaration? (";" S* declaration?)* "}" S* { page = PAGE_SYM S* pseudo_page? "{" S* declaration? (";" S* declaration?)* "}" S* {
var declarations = $6 !== "" ? [$6] : []; var declarations = $6 !== "" ? [$6] : [];
for (var i = 0; i < $7.length; i++) { for (var i = 0; i < $7.length; i++) {
if ($7[i][2] !== "") { if ($7[i][2] !== "") {
@ -80,21 +80,21 @@ page: PAGE_SYM S* pseudo_page? "{" S* declaration? (";" S* declaration?)* "}" S*
}; };
} }
pseudo_page: ":" IDENT S* { return $2; } pseudo_page = ":" IDENT S* { return $2; }
operator operator
: "/" S* { return $1; } = "/" S* { return $1; }
/ "," S* { return $1; } / "," S* { return $1; }
combinator combinator
: "+" S* { return $1; } = "+" S* { return $1; }
/ ">" S* { return $1; } / ">" S* { return $1; }
unary_operator: "+" / "-" unary_operator = "+" / "-"
property: IDENT S* { return $1; } property = IDENT S* { return $1; }
ruleset: selector ("," S* selector)* "{" S* declaration? (";" S* declaration?)* "}" S* { ruleset = selector ("," S* selector)* "{" S* declaration? (";" S* declaration?)* "}" S* {
var selectors = [$1]; var selectors = [$1];
for (var i = 0; i < $2.length; i++) { for (var i = 0; i < $2.length; i++) {
selectors.push($2[i][2]); selectors.push($2[i][2]);
@ -115,7 +115,7 @@ ruleset: selector ("," S* selector)* "{" S* declaration? (";" S* declaration?)*
} }
selector selector
: simple_selector S* combinator selector { = simple_selector S* combinator selector {
return { return {
type: "selector", type: "selector",
combinator: $3, combinator: $3,
@ -134,7 +134,7 @@ selector
/ simple_selector S* { return $1; } / simple_selector S* { return $1; }
simple_selector simple_selector
: element_name = element_name
( (
HASH { return { type: "ID selector", id: $1.substr(1) }; } HASH { return { type: "ID selector", id: $1.substr(1) }; }
/ class / class
@ -160,11 +160,11 @@ simple_selector
}; };
} }
class: "." IDENT { return { type: "class_selector", "class": $2 }; } class = "." IDENT { return { type: "class_selector", "class": $2 }; }
element_name: IDENT / '*' element_name = IDENT / '*'
attrib: "[" S* IDENT S* (('=' / INCLUDES / DASHMATCH) S* (IDENT / STRING) S*)? "]" { attrib = "[" S* IDENT S* (('=' / INCLUDES / DASHMATCH) S* (IDENT / STRING) S*)? "]" {
return { return {
type: "attribute_selector", type: "attribute_selector",
attribute: $3, attribute: $3,
@ -173,7 +173,7 @@ attrib: "[" S* IDENT S* (('=' / INCLUDES / DASHMATCH) S* (IDENT / STRING) S*)? "
}; };
} }
pseudo: pseudo =
":" ":"
( (
FUNCTION S* (IDENT S*)? ")" { FUNCTION S* (IDENT S*)? ")" {
@ -197,7 +197,7 @@ pseudo:
}; };
} }
declaration: property ":" S* expr prio? { declaration = property ":" S* expr prio? {
return { return {
type: "declaration", type: "declaration",
property: $1, property: $1,
@ -206,9 +206,9 @@ declaration: property ":" S* expr prio? {
}; };
} }
prio: IMPORTANT_SYM S* prio = IMPORTANT_SYM S*
expr: term (operator? term)* { expr = term (operator? term)* {
var result = $1; var result = $1;
for (var i = 0; i < $2.length; i++) { for (var i = 0; i < $2.length; i++) {
result = { result = {
@ -222,7 +222,7 @@ expr: term (operator? term)* {
} }
term term
: unary_operator? = unary_operator?
( (
EMS S* EMS S*
/ EXS S* / EXS S*
@ -239,7 +239,7 @@ term
/ STRING S* { return { type: "string", value: $1 }; } / STRING S* { return { type: "string", value: $1 }; }
/ IDENT S* { return { type: "ident", value: $1 }; } / IDENT S* { return { type: "ident", value: $1 }; }
function: FUNCTION S* expr ")" S* { function = FUNCTION S* expr ")" S* {
return { return {
type: "function", type: "function",
name: $1, name: $1,
@ -247,160 +247,160 @@ function: FUNCTION S* expr ")" S* {
}; };
} }
hexcolor: HASH S* { return { type: "hexcolor", value: $1}; } hexcolor = HASH S* { return { type: "hexcolor", value: $1}; }
/* ===== Lexical Elements ===== */ /* ===== Lexical Elements ===== */
/* Macros */ /* Macros */
h: [0-9a-fA-F] h = [0-9a-fA-F]
nonascii: [\x80-\xFF] nonascii = [\x80-\xFF]
unicode: "\\" h h? h? h? h? h? ("\r\n" / [ \t\r\n\f])? { unicode = "\\" h h? h? h? h? h? ("\r\n" / [ \t\r\n\f])? {
return String.fromCharCode(parseInt("0x" + $2 + $3 + $4 + $5 + $6 + $7)); return String.fromCharCode(parseInt("0x" + $2 + $3 + $4 + $5 + $6 + $7));
} }
escape: unicode / "\\" [^\r\n\f0-9a-fA-F] { return $2; } escape = unicode / "\\" [^\r\n\f0-9a-fA-F] { return $2; }
nmstart: [_a-zA-Z] / nonascii / escape nmstart = [_a-zA-Z] / nonascii / escape
nmchar: [_a-zA-Z0-9-] / nonascii / escape nmchar = [_a-zA-Z0-9-] / nonascii / escape
integer: [0-9]+ { return parseInt($1.join("")); } integer = [0-9]+ { return parseInt($1.join("")); }
float: [0-9]* "." [0-9]+ { return parseFloat($1.join("") + $2 + $3.join("")); } float = [0-9]* "." [0-9]+ { return parseFloat($1.join("") + $2 + $3.join("")); }
string1: '"' ([^\n\r\f\\"] / "\\" nl { return $2 } / escape)* '"' { return $2.join(""); } string1 = '"' ([^\n\r\f\\"] / "\\" nl { return $2 } / escape)* '"' { return $2.join(""); }
string2: "'" ([^\n\r\f\\'] / "\\" nl { return $2 } / escape)* "'" { return $2.join(""); } string2 = "'" ([^\n\r\f\\'] / "\\" nl { return $2 } / escape)* "'" { return $2.join(""); }
comment: "/*" [^*]* "*"+ ([^/*] [^*]* "*"+)* "/" comment = "/*" [^*]* "*"+ ([^/*] [^*]* "*"+)* "/"
ident: "-"? nmstart nmchar* { return $1 + $2 + $3.join(""); } ident = "-"? nmstart nmchar* { return $1 + $2 + $3.join(""); }
name: nmchar+ { return $1.join(""); } name = nmchar+ { return $1.join(""); }
num: float / integer num = float / integer
string: string1 / string2 string = string1 / string2
url: ([!#$%&*-~] / nonascii / escape)* { return $1.join(""); } url = ([!#$%&*-~] / nonascii / escape)* { return $1.join(""); }
s: [ \t\r\n\f]+ s = [ \t\r\n\f]+
w: s? w = s?
nl: "\n" / "\r\n" / "\r" / "\f" nl = "\n" / "\r\n" / "\r" / "\f"
A A
: [aA] = [aA]
/ "\\" "0"? "0"? "0"? "0"? "41" ("\r\n" / [ \t\r\n\f])? { return "A"; } / "\\" "0"? "0"? "0"? "0"? "41" ("\r\n" / [ \t\r\n\f])? { return "A"; }
/ "\\" "0"? "0"? "0"? "0"? "61" ("\r\n" / [ \t\r\n\f])? { return "a"; } / "\\" "0"? "0"? "0"? "0"? "61" ("\r\n" / [ \t\r\n\f])? { return "a"; }
C C
: [cC] = [cC]
/ "\\" "0"? "0"? "0"? "0"? "43" ("\r\n" / [ \t\r\n\f])? { return "C"; } / "\\" "0"? "0"? "0"? "0"? "43" ("\r\n" / [ \t\r\n\f])? { return "C"; }
/ "\\" "0"? "0"? "0"? "0"? "63" ("\r\n" / [ \t\r\n\f])? { return "c"; } / "\\" "0"? "0"? "0"? "0"? "63" ("\r\n" / [ \t\r\n\f])? { return "c"; }
D D
: [dD] = [dD]
/ "\\" "0"? "0"? "0"? "0"? "44" ("\r\n" / [ \t\r\n\f])? { return "D"; } / "\\" "0"? "0"? "0"? "0"? "44" ("\r\n" / [ \t\r\n\f])? { return "D"; }
/ "\\" "0"? "0"? "0"? "0"? "64" ("\r\n" / [ \t\r\n\f])? { return "d"; } / "\\" "0"? "0"? "0"? "0"? "64" ("\r\n" / [ \t\r\n\f])? { return "d"; }
E E
: [eE] = [eE]
/ "\\" "0"? "0"? "0"? "0"? "45" ("\r\n" / [ \t\r\n\f])? { return "E"; } / "\\" "0"? "0"? "0"? "0"? "45" ("\r\n" / [ \t\r\n\f])? { return "E"; }
/ "\\" "0"? "0"? "0"? "0"? "65" ("\r\n" / [ \t\r\n\f])? { return "e"; } / "\\" "0"? "0"? "0"? "0"? "65" ("\r\n" / [ \t\r\n\f])? { return "e"; }
G G
: [gG] = [gG]
/ "\\" "0"? "0"? "0"? "0"? "47" ("\r\n" / [ \t\r\n\f])? { return "G"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "67" ("\r\n" / [ \t\r\n\f])? { return "g"; }
/ "\\" [gG] { return $2; } / "\\" [gG] { return $2; }
H H
: [hH] = [hH]
/ "\\" "0"? "0"? "0"? "0"? "48" ("\r\n" / [ \t\r\n\f])? { return "H"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "68" ("\r\n" / [ \t\r\n\f])? { return "h"; }
/ "\\" [hH] { return $2; } / "\\" [hH] { return $2; }
I I
: [iI] = [iI]
/ "\\" "0"? "0"? "0"? "0"? "49" ("\r\n" / [ \t\r\n\f])? { return "I"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "69" ("\r\n" / [ \t\r\n\f])? { return "i"; }
/ "\\" [iI] { return $2; } / "\\" [iI] { return $2; }
K K
: [kK] = [kK]
/ "\\" "0"? "0"? "0"? "0"? "4" [bB] ("\r\n" / [ \t\r\n\f])? { return "K"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "6" [bB] ("\r\n" / [ \t\r\n\f])? { return "k"; }
/ "\\" [kK] { return $2; } / "\\" [kK] { return $2; }
L L
: [lL] = [lL]
/ "\\" "0"? "0"? "0"? "0"? "4" [cC] ("\r\n" / [ \t\r\n\f])? { return "L"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "6" [cC] ("\r\n" / [ \t\r\n\f])? { return "l"; }
/ "\\" [lL] { return $2; } / "\\" [lL] { return $2; }
M M
: [mM] = [mM]
/ "\\" "0"? "0"? "0"? "0"? "4" [dD] ("\r\n" / [ \t\r\n\f])? { return "M"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "6" [dD] ("\r\n" / [ \t\r\n\f])? { return "m"; }
/ "\\" [mM] { return $2; } / "\\" [mM] { return $2; }
N N
: [nN] = [nN]
/ "\\" "0"? "0"? "0"? "0"? "4" [eE] ("\r\n" / [ \t\r\n\f])? { return "N"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "6" [eE] ("\r\n" / [ \t\r\n\f])? { return "n"; }
/ "\\" [nN] { return $2; } / "\\" [nN] { return $2; }
O O
: [oO] = [oO]
/ "\\" "0"? "0"? "0"? "0"? "4" [fF] ("\r\n" / [ \t\r\n\f])? { return "O"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "6" [fF] ("\r\n" / [ \t\r\n\f])? { return "o"; }
/ "\\" [oO] { return $2; } / "\\" [oO] { return $2; }
P P
: [pP] = [pP]
/ "\\" "0"? "0"? "0"? "0"? "50" ("\r\n" / [ \t\r\n\f])? { return "P"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "70" ("\r\n" / [ \t\r\n\f])? { return "p"; }
/ "\\" [pP] { return $2; } / "\\" [pP] { return $2; }
R R
: [rR] = [rR]
/ "\\" "0"? "0"? "0"? "0"? "52" ("\r\n" / [ \t\r\n\f])? { return "R"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "72" ("\r\n" / [ \t\r\n\f])? { return "r"; }
/ "\\" [rR] { return $2; } / "\\" [rR] { return $2; }
S_ S_
: [sS] = [sS]
/ "\\" "0"? "0"? "0"? "0"? "53" ("\r\n" / [ \t\r\n\f])? { return "S"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "73" ("\r\n" / [ \t\r\n\f])? { return "s"; }
/ "\\" [sS] { return $2; } / "\\" [sS] { return $2; }
T T
: [tT] = [tT]
/ "\\" "0"? "0"? "0"? "0"? "54" ("\r\n" / [ \t\r\n\f])? { return "T"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "74" ("\r\n" / [ \t\r\n\f])? { return "t"; }
/ "\\" [tT] { return $2; } / "\\" [tT] { return $2; }
U U
: [uU] = [uU]
/ "\\" "0"? "0"? "0"? "0"? "55" ("\r\n" / [ \t\r\n\f])? { return "U"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "75" ("\r\n" / [ \t\r\n\f])? { return "u"; }
/ "\\" [uU] { return $2; } / "\\" [uU] { return $2; }
X X
: [xX] = [xX]
/ "\\" "0"? "0"? "0"? "0"? "58" ("\r\n" / [ \t\r\n\f])? { return "X"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "78" ("\r\n" / [ \t\r\n\f])? { return "x"; }
/ "\\" [xX] { return $2; } / "\\" [xX] { return $2; }
Z Z
: [zZ] = [zZ]
/ "\\" "0"? "0"? "0"? "0"? "5" [aA] ("\r\n" / [ \t\r\n\f])? { return "Z"; } / "\\" "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"; } / "\\" "0"? "0"? "0"? "0"? "7" [aA] ("\r\n" / [ \t\r\n\f])? { return "z"; }
/ "\\" [zZ] { return $2; } / "\\" [zZ] { return $2; }
/* Tokens */ /* Tokens */
S "whitespace" : comment* s S "whitespace" = comment* s
CDO "<!--" : comment* "<!--" CDO "<!--" = comment* "<!--"
CDC "-->" : comment* "-->" CDC "-->" = comment* "-->"
INCLUDES "~=" : comment* "~=" INCLUDES "~=" = comment* "~="
DASHMATCH "|=" : comment* "|=" DASHMATCH "|=" = comment* "|="
STRING "string" : comment* string { return $2; } STRING "string" = comment* string { return $2; }
IDENT "identifier" : comment* ident { return $2; } IDENT "identifier" = comment* ident { return $2; }
HASH "hash" : comment* "#" name { return $2 + $3; } HASH "hash" = comment* "#" name { return $2 + $3; }
IMPORT_SYM "@import" : comment* "@" I M P O R T IMPORT_SYM "@import" = comment* "@" I M P O R T
PAGE_SYM "@page" : comment* "@" P A G E PAGE_SYM "@page" = comment* "@" P A G E
MEDIA_SYM "@media" : comment* "@" M E D I A MEDIA_SYM "@media" = comment* "@" M E D I A
CHARSET_SYM "@charset" : comment* "@charset " CHARSET_SYM "@charset" = comment* "@charset "
/* Note: We replace "w" with "s" here to avoid infinite recursion. */ /* Note: We replace "w" with "s" here to avoid infinite recursion. */
IMPORTANT_SYM "!important" : comment* "!" (s / comment)* I M P O R T A N T { return "!important"; } 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; } EMS "length" = comment* num E M { return $2 + $3 + $4; }
EXS "length" : comment* num E X { return $2 + $3 + $4; } EXS "length" = comment* num E X { return $2 + $3 + $4; }
LENGTH "length" : comment* num (P X / C M / M M / I N / P T / P C) { return $2 + $3.join(""); } LENGTH "length" = comment* num (P X / C M / M M / I N / P T / P C) { return $2 + $3.join(""); }
ANGLE "angle" : comment* num (D E G / R A D / G R A D) { return $2 + $3.join(""); } ANGLE "angle" = comment* num (D E G / R A D / G R A D) { return $2 + $3.join(""); }
TIME "time" : comment* num (M S_ { return $1 + $2; } / S_) { return $2 + $3; } TIME "time" = comment* num (M S_ { return $1 + $2; } / S_) { return $2 + $3; }
FREQ "frequency" : comment* num (H Z / K H Z) { return $2 + $3.join(""); } FREQ "frequency" = comment* num (H Z / K H Z) { return $2 + $3.join(""); }
DIMENSION "dimension" : comment* num ident { return $2 + $3; } DIMENSION "dimension" = comment* num ident { return $2 + $3; }
PERCENTAGE "percentage" : comment* num "%" { return $2 + $3; } PERCENTAGE "percentage" = comment* num "%" { return $2 + $3; }
NUMBER "number" : comment* num { return $2; } NUMBER "number" = comment* num { return $2; }
URI "uri" : comment* U R L "(" w (string / url) w ")" { return $7; } URI "uri" = comment* U R L "(" w (string / url) w ")" { return $7; }
FUNCTION "function" : comment* ident "(" { return $2; } FUNCTION "function" = comment* ident "(" { return $2; }

File diff suppressed because one or more lines are too long

@ -2,13 +2,13 @@
/* ===== Syntactical Elements ===== */ /* ===== Syntactical Elements ===== */
start: _ object { return $2; } start = _ object { return $2; }
object object
: "{" _ "}" _ { return {}; } = "{" _ "}" _ { return {}; }
/ "{" _ members "}" _ { return $3; } / "{" _ members "}" _ { return $3; }
members: pair ("," _ pair)* { members = pair ("," _ pair)* {
var result = {}; var result = {};
result[$1[0]] = $1[1]; result[$1[0]] = $1[1];
for (var i = 0; i < $2.length; i++) { for (var i = 0; i < $2.length; i++) {
@ -17,13 +17,13 @@ members: pair ("," _ pair)* {
return result; return result;
} }
pair: string ":" _ value { return [$1, $4]; } pair = string ":" _ value { return [$1, $4]; }
array array
: "[" _ "]" _ { return []; } = "[" _ "]" _ { return []; }
/ "[" _ elements "]" _ { return $3; } / "[" _ elements "]" _ { return $3; }
elements: value ("," _ value)* { elements = value ("," _ value)* {
var result = [$1]; var result = [$1];
for (var i = 0; i < $2.length; i++) { for (var i = 0; i < $2.length; i++) {
result.push($2[i][2]); result.push($2[i][2]);
@ -32,7 +32,7 @@ elements: value ("," _ value)* {
} }
value value
: string = string
/ number / number
/ object / object
/ array / array
@ -44,14 +44,14 @@ value
/* ===== Lexical Elements ===== */ /* ===== Lexical Elements ===== */
string "string" string "string"
: '"' '"' _ { return ""; } = '"' '"' _ { return ""; }
/ '"' chars '"' _ { return $2; } / '"' chars '"' _ { return $2; }
chars: char+ { return $1.join(""); } chars = char+ { return $1.join(""); }
char char
// In the original JSON grammar: "any-Unicode-character-except-"-or-\-or-control-character" // In the original JSON grammar: "any-Unicode-character-except-"-or-\-or-control-character"
: [^"\\\0-\x1F\x7f] = [^"\\\0-\x1F\x7f]
/ '\\"' { return '"'; } / '\\"' { return '"'; }
/ "\\\\" { return "\\"; } / "\\\\" { return "\\"; }
/ "\\/" { return "/"; } / "\\/" { return "/"; }
@ -65,24 +65,24 @@ char
} }
number "number" number "number"
: int frac exp _ { return parseFloat($1 + $2 + $3); } = int frac exp _ { return parseFloat($1 + $2 + $3); }
/ int frac _ { return parseFloat($1 + $2); } / int frac _ { return parseFloat($1 + $2); }
/ int exp _ { return parseFloat($1 + $2); } / int exp _ { return parseFloat($1 + $2); }
/ int _ { return parseFloat($1); } / int _ { return parseFloat($1); }
int int
: digit19 digits { return $1 + $2; } = digit19 digits { return $1 + $2; }
/ digit / digit
/ "-" digit19 digits { return $1 + $2 + $3; } / "-" digit19 digits { return $1 + $2 + $3; }
/ "-" digit { return $1 + $2; } / "-" digit { return $1 + $2; }
frac: "." digits { return $1 + $2; } frac = "." digits { return $1 + $2; }
exp: e digits { return $1 + $2; } exp = e digits { return $1 + $2; }
digits: digit+ { return $1.join(""); } digits = digit+ { return $1.join(""); }
e: [eE] [+-]? { return $1 + $2; } e = [eE] [+-]? { return $1 + $2; }
/* /*
* The following rules are not present in the original JSON gramar, but they are * The following rules are not present in the original JSON gramar, but they are
@ -91,16 +91,16 @@ e: [eE] [+-]? { return $1 + $2; }
* FIXME: Define them according to ECMA-262, 5th ed. * FIXME: Define them according to ECMA-262, 5th ed.
*/ */
digit: [0-9] digit = [0-9]
digit19: [1-9] digit19 = [1-9]
hexDigit: [0-9a-fA-F] hexDigit = [0-9a-fA-F]
/* ===== Whitespace ===== */ /* ===== Whitespace ===== */
_ "whitespace": whitespace* _ "whitespace" = whitespace*
// Whitespace is undefined in the original JSON grammar, so I assume a simple // Whitespace is undefined in the original JSON grammar, so I assume a simple
// conventional definition consistent with ECMA-262, 5th ed. // conventional definition consistent with ECMA-262, 5th ed.
whitespace: [ \t\n\r] whitespace = [ \t\n\r]

@ -135,7 +135,7 @@ PEG.grammarParser = (function(){
}; };
} }
if (result8 !== null) { if (result8 !== null) {
var result9 = this._parse_colon(context); var result9 = this._parse_equals(context);
if (result9 !== null) { if (result9 !== null) {
var result10 = this._parse_choice(context); var result10 = this._parse_choice(context);
if (result10 !== null) { if (result10 !== null) {
@ -535,7 +535,7 @@ PEG.grammarParser = (function(){
}; };
} }
if (result69 !== null) { if (result69 !== null) {
var result70 = this._parse_colon(context); var result70 = this._parse_equals(context);
if (result70 !== null) { if (result70 !== null) {
var result68 = [result69, result70]; var result68 = [result69, result70];
} else { } else {
@ -819,8 +819,8 @@ PEG.grammarParser = (function(){
return result88; return result88;
}, },
_parse_colon: function(context) { _parse_equals: function(context) {
var cacheKey = "colon" + '@' + this._pos; var cacheKey = "equals" + '@' + this._pos;
var cachedResult = this._cache[cacheKey]; var cachedResult = this._cache[cacheKey];
if (cachedResult) { if (cachedResult) {
this._pos = cachedResult.nextPos; this._pos = cachedResult.nextPos;
@ -831,13 +831,13 @@ PEG.grammarParser = (function(){
var savedPos16 = this._pos; var savedPos16 = this._pos;
if (this._input.substr(this._pos, 1) === ":") { if (this._input.substr(this._pos, 1) === "=") {
var result91 = ":"; var result91 = "=";
this._pos += 1; this._pos += 1;
} else { } else {
var result91 = null; var result91 = null;
if (context.reportMatchFailures) { if (context.reportMatchFailures) {
this._matchFailed(this._quoteString(":")); this._matchFailed(this._quoteString("="));
} }
} }
if (result91 !== null) { if (result91 !== null) {

@ -1,10 +1,10 @@
grammar: __ rule+ { grammar = __ rule+ {
var result = {}; var result = {};
PEG.ArrayUtils.each($2, function(rule) { result[rule.name] = rule; }); PEG.ArrayUtils.each($2, function(rule) { result[rule.name] = rule; });
return result; return result;
} }
rule: identifier (literal / "") colon expression { rule = identifier (literal / "") equals expression {
return { return {
type: "rule", type: "rule",
name: $1, name: $1,
@ -13,9 +13,9 @@ rule: identifier (literal / "") colon expression {
}; };
} }
expression: choice expression = choice
choice: sequence (slash sequence)* { choice = sequence (slash sequence)* {
if ($2.length > 0) { if ($2.length > 0) {
var alternatives = [$1].concat(PEG.ArrayUtils.map( var alternatives = [$1].concat(PEG.ArrayUtils.map(
$2, $2,
@ -31,7 +31,7 @@ choice: sequence (slash sequence)* {
} }
sequence sequence
: prefixed* action { = prefixed* action {
var expression = $1.length != 1 var expression = $1.length != 1
? { ? {
type: "sequence", type: "sequence",
@ -54,43 +54,43 @@ sequence
} }
prefixed prefixed
: and suffixed { return { type: "and_predicate", expression: $2 }; } = and suffixed { return { type: "and_predicate", expression: $2 }; }
/ not suffixed { return { type: "not_predicate", expression: $2 }; } / not suffixed { return { type: "not_predicate", expression: $2 }; }
/ suffixed / suffixed
suffixed suffixed
: primary question { return { type: "optional", expression: $1}; } = primary question { return { type: "optional", expression: $1}; }
/ primary star { return { type: "zero_or_more", expression: $1}; } / primary star { return { type: "zero_or_more", expression: $1}; }
/ primary plus { return { type: "one_or_more", expression: $1}; } / primary plus { return { type: "one_or_more", expression: $1}; }
/ primary / primary
primary primary
: identifier !(( literal / "") colon) { return { type: "rule_ref", name: $1 }; } = identifier !(( literal / "") equals) { return { type: "rule_ref", name: $1 }; }
/ literal { return { type: "literal", value: $1 }; } / literal { return { type: "literal", value: $1 }; }
/ dot { return { type: "any" }; } / dot { return { type: "any" }; }
/ class / class
/ lparen expression rparen { return $2; } / lparen expression rparen { return $2; }
/* "Lexical" elements */ /* "Lexical" elements */
action "action": braced __ { return $1.substr(1, $1.length - 2); } action "action" = braced __ { return $1.substr(1, $1.length - 2); }
braced: "{" (braced / nonBraceCharacter)* "}" { return $1 + $2.join("") + $3; } braced = "{" (braced / nonBraceCharacter)* "}" { return $1 + $2.join("") + $3; }
nonBraceCharacters: nonBraceCharacter+ { return $1.join(""); } nonBraceCharacters = nonBraceCharacter+ { return $1.join(""); }
nonBraceCharacter: [^{}] nonBraceCharacter: [^{}]
colon: ":" __ { return $1; } equals = "=" __ { return $1; }
slash: "/" __ { return $1; } slash = "/" __ { return $1; }
and: "&" __ { return $1; } and = "&" __ { return $1; }
not: "!" __ { return $1; } not = "!" __ { return $1; }
question: "?" __ { return $1; } question = "?" __ { return $1; }
star: "*" __ { return $1; } star = "*" __ { return $1; }
plus: "+" __ { return $1; } plus = "+" __ { return $1; }
lparen: "(" __ { return $1; } lparen = "(" __ { return $1; }
rparen: ")" __ { return $1; } rparen = ")" __ { return $1; }
dot: "." __ { return $1; } dot = "." __ { return $1; }
/* /*
* Modelled after ECMA-262, 5th ed., 7.6, but much simplified: * Modelled after ECMA-262, 5th ed., 7.6, but much simplified:
@ -107,7 +107,7 @@ dot: "." __ { return $1; }
* The simplifications were made just to make the implementation little bit * The simplifications were made just to make the implementation little bit
* easier, there is no "philosophical" reason behind them. * easier, there is no "philosophical" reason behind them.
*/ */
identifier "identifier": (letter / "_" / "$") (letter / digit / "_" / "$")* __ { identifier "identifier" = (letter / "_" / "$") (letter / digit / "_" / "$")* __ {
return $1 + $2.join(""); return $1 + $2.join("");
} }
@ -115,33 +115,33 @@ identifier "identifier": (letter / "_" / "$") (letter / digit / "_" / "$")* __ {
* Modelled after ECMA-262, 5th ed., 7.8.4. (syntax & semantics, rules only * Modelled after ECMA-262, 5th ed., 7.8.4. (syntax & semantics, rules only
* vaguely). * vaguely).
*/ */
literal "literal": (doubleQuotedLiteral / singleQuotedLiteral) __ { return $1; } literal "literal" = (doubleQuotedLiteral / singleQuotedLiteral) __ { return $1; }
doubleQuotedLiteral: '"' doubleQuotedCharacter* '"' { return $2.join(""); } doubleQuotedLiteral = '"' doubleQuotedCharacter* '"' { return $2.join(""); }
doubleQuotedCharacter doubleQuotedCharacter
: simpleDoubleQuotedCharacter = simpleDoubleQuotedCharacter
/ simpleEscapeSequence / simpleEscapeSequence
/ zeroEscapeSequence / zeroEscapeSequence
/ hexEscapeSequence / hexEscapeSequence
/ unicodeEscapeSequence / unicodeEscapeSequence
/ eolEscapeSequence / eolEscapeSequence
simpleDoubleQuotedCharacter: !('"' / "\\" / eolChar) . { return $2; } simpleDoubleQuotedCharacter = !('"' / "\\" / eolChar) . { return $2; }
singleQuotedLiteral: "'" singleQuotedCharacter* "'" { return $2.join(""); } singleQuotedLiteral = "'" singleQuotedCharacter* "'" { return $2.join(""); }
singleQuotedCharacter singleQuotedCharacter
: simpleSingleQuotedCharacter = simpleSingleQuotedCharacter
/ simpleEscapeSequence / simpleEscapeSequence
/ zeroEscapeSequence / zeroEscapeSequence
/ hexEscapeSequence / hexEscapeSequence
/ unicodeEscapeSequence / unicodeEscapeSequence
/ eolEscapeSequence / eolEscapeSequence
simpleSingleQuotedCharacter: !("'" / "\\" / eolChar) . { return $2; } simpleSingleQuotedCharacter = !("'" / "\\" / eolChar) . { return $2; }
class "character class": "[" "^"? (classCharacterRange / classCharacter)* "]" __ { class "character class" = "[" "^"? (classCharacterRange / classCharacter)* "]" __ {
parts = PEG.ArrayUtils.map($3, function(part) { return part.data; }); parts = PEG.ArrayUtils.map($3, function(part) { return part.data; });
rawText = "[" rawText = "["
+ $2 + $2
@ -157,7 +157,7 @@ class "character class": "[" "^"? (classCharacterRange / classCharacter)* "]" __
}; };
} }
classCharacterRange: classCharacter "-" classCharacter { classCharacterRange = classCharacter "-" classCharacter {
if ($1.data.charCodeAt(0) > $3.data.charCodeAt(0)) { if ($1.data.charCodeAt(0) > $3.data.charCodeAt(0)) {
throw new this.SyntaxError( throw new this.SyntaxError(
"Invalid character range: " + $1.rawText + "-" + $3.rawText + "." "Invalid character range: " + $1.rawText + "-" + $3.rawText + "."
@ -171,7 +171,7 @@ classCharacterRange: classCharacter "-" classCharacter {
} }
} }
classCharacter: bracketDelimitedCharacter { classCharacter = bracketDelimitedCharacter {
return { return {
data: $1, data: $1,
// FIXME: Get the raw text from the input directly. // FIXME: Get the raw text from the input directly.
@ -180,16 +180,16 @@ classCharacter: bracketDelimitedCharacter {
} }
bracketDelimitedCharacter bracketDelimitedCharacter
: simpleBracketDelimitedCharacter = simpleBracketDelimitedCharacter
/ simpleEscapeSequence / simpleEscapeSequence
/ zeroEscapeSequence / zeroEscapeSequence
/ hexEscapeSequence / hexEscapeSequence
/ unicodeEscapeSequence / unicodeEscapeSequence
/ eolEscapeSequence / eolEscapeSequence
simpleBracketDelimitedCharacter: !("]" / "\\" / eolChar) . { return $2; } simpleBracketDelimitedCharacter = !("]" / "\\" / eolChar) . { return $2; }
simpleEscapeSequence: "\\" !(digit / "x" / "u" / eolChar) . { simpleEscapeSequence = "\\" !(digit / "x" / "u" / eolChar) . {
return $3 return $3
.replace("b", "\b") .replace("b", "\b")
.replace("f", "\f") .replace("f", "\f")
@ -199,41 +199,41 @@ simpleEscapeSequence: "\\" !(digit / "x" / "u" / eolChar) . {
.replace("v", "\x0B") // IE does not recognize "\v". .replace("v", "\x0B") // IE does not recognize "\v".
} }
zeroEscapeSequence: "\\0" !digit { return "\0"; } zeroEscapeSequence = "\\0" !digit { return "\0"; }
hexEscapeSequence: "\\x" hexDigit hexDigit { hexEscapeSequence = "\\x" hexDigit hexDigit {
return String.fromCharCode(parseInt("0x" + $2 + $3)); return String.fromCharCode(parseInt("0x" + $2 + $3));
} }
unicodeEscapeSequence: "\\u" hexDigit hexDigit hexDigit hexDigit { unicodeEscapeSequence = "\\u" hexDigit hexDigit hexDigit hexDigit {
return String.fromCharCode(parseInt("0x" + $2 + $3 + $4 + $5)); return String.fromCharCode(parseInt("0x" + $2 + $3 + $4 + $5));
} }
eolEscapeSequence: "\\" eol { return $2; } eolEscapeSequence = "\\" eol { return $2; }
digit: [0-9] digit = [0-9]
hexDigit: [0-9a-fA-F] hexDigit = [0-9a-fA-F]
letter: lowerCaseLetter / upperCaseLetter letter = lowerCaseLetter / upperCaseLetter
lowerCaseLetter: [a-z] lowerCaseLetter = [a-z]
upperCaseLetter: [A-Z] upperCaseLetter = [A-Z]
__: (whitespace / eol / comment)* __ = (whitespace / eol / comment)*
/* Modelled after ECMA-262, 5th ed., 7.4. */ /* Modelled after ECMA-262, 5th ed., 7.4. */
comment "comment": singleLineComment / multiLineComment comment "comment" = singleLineComment / multiLineComment
singleLineComment: "//" (!eolChar .)* singleLineComment = "//" (!eolChar .)*
multiLineComment: "/*" (!"*/" .)* "*/" multiLineComment = "/*" (!"*/" .)* "*/"
/* Modelled after ECMA-262, 5th ed., 7.3. */ /* Modelled after ECMA-262, 5th ed., 7.3. */
eol "end of line": "\n" / "\r\n" / "\r" / "\u2028" / "\u2029" eol "end of line" = "\n" / "\r\n" / "\r" / "\u2028" / "\u2029"
eolChar: [\n\r\u2028\u2029] eolChar = [\n\r\u2028\u2029]
/* Modelled after ECMA-262, 5th ed., 7.2. */ /* Modelled after ECMA-262, 5th ed., 7.2. */
whitespace "whitespace": [ \t\v\f\u00A0\uFEFF\u1680\u180E\u2000-\u200A\u202F\u205F\u3000] whitespace "whitespace" = [ \t\v\f\u00A0\uFEFF\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]

@ -193,7 +193,7 @@ test("buildParser reports syntax errors in the grammar", function() {
test("buildParser reports missing start rule", function() { test("buildParser reports missing start rule", function() {
throws( throws(
function() { PEG.buildParser('notStart: "abcd"'); }, function() { PEG.buildParser('notStart = "abcd"'); },
PEG.GrammarError, PEG.GrammarError,
{ message: "Missing \"start\" rule." } { message: "Missing \"start\" rule." }
); );
@ -201,17 +201,17 @@ test("buildParser reports missing start rule", function() {
test("buildParser reports missing referenced rules", function() { test("buildParser reports missing referenced rules", function() {
var grammars = [ var grammars = [
'start: missing', 'start = missing',
'start: missing / "a" / "b"', 'start = missing / "a" / "b"',
'start: "a" / "b" / missing', 'start = "a" / "b" / missing',
'start: missing "a" "b"', 'start = missing "a" "b"',
'start: "a" "b" missing', 'start = "a" "b" missing',
'start: &missing', 'start = &missing',
'start: !missing', 'start = !missing',
'start: missing?', 'start = missing?',
'start: missing*', 'start = missing*',
'start: missing+', 'start = missing+',
'start: missing { }' 'start = missing { }'
]; ];
PEG.ArrayUtils.each(grammars, function(grammar) { PEG.ArrayUtils.each(grammars, function(grammar) {
@ -226,19 +226,19 @@ test("buildParser reports missing referenced rules", function() {
test("buildParser reports left recursion", function() { test("buildParser reports left recursion", function() {
var grammars = [ var grammars = [
/* Direct */ /* Direct */
'start: start', 'start = start',
'start: start / "a" / "b"', 'start = start / "a" / "b"',
'start: "a" / "b" / start', 'start = "a" / "b" / start',
'start: start "a" "b"', 'start = start "a" "b"',
'start: &start', 'start = &start',
'start: !start', 'start = !start',
'start: start?', 'start = start?',
'start: start*', 'start = start*',
'start: start+', 'start = start+',
'start: start { }', 'start = start { }',
/* Indirect */ /* Indirect */
'start: stop\nstop: start' 'start = stop\nstop = start'
]; ];
PEG.ArrayUtils.each(grammars, function(grammar) { PEG.ArrayUtils.each(grammars, function(grammar) {
@ -251,7 +251,7 @@ test("buildParser reports left recursion", function() {
}); });
test("buildParser allows custom start rule", function() { test("buildParser allows custom start rule", function() {
var parser = PEG.buildParser('s: "abcd"', "s"); var parser = PEG.buildParser('s = "abcd"', "s");
parses(parser, "abcd", "abcd"); parses(parser, "abcd", "abcd");
}); });
@ -260,7 +260,7 @@ test("buildParser allows custom start rule", function() {
module("Generated Parser"); module("Generated Parser");
test("choices", function() { test("choices", function() {
var parser = PEG.buildParser('start: "a" / "b" / "c"'); var parser = PEG.buildParser('start = "a" / "b" / "c"');
parses(parser, "a", "a"); parses(parser, "a", "a");
parses(parser, "b", "b"); parses(parser, "b", "b");
parses(parser, "c", "c"); parses(parser, "c", "c");
@ -270,11 +270,11 @@ test("choices", function() {
}); });
test("sequences", function() { test("sequences", function() {
var emptySequenceParser = PEG.buildParser('start: '); var emptySequenceParser = PEG.buildParser('start = ');
parses(emptySequenceParser, "", []); parses(emptySequenceParser, "", []);
doesNotParse(emptySequenceParser, "abc"); doesNotParse(emptySequenceParser, "abc");
var nonEmptySequenceParser = PEG.buildParser('start: "a" "b" "c"'); var nonEmptySequenceParser = PEG.buildParser('start = "a" "b" "c"');
parses(nonEmptySequenceParser, "abc", ["a", "b", "c"]); parses(nonEmptySequenceParser, "abc", ["a", "b", "c"]);
doesNotParse(nonEmptySequenceParser, ""); doesNotParse(nonEmptySequenceParser, "");
doesNotParse(nonEmptySequenceParser, "ab"); doesNotParse(nonEmptySequenceParser, "ab");
@ -285,12 +285,12 @@ test("sequences", function() {
* Test that the parsing position returns after unsuccessful parsing of a * Test that the parsing position returns after unsuccessful parsing of a
* sequence. * sequence.
*/ */
var posTestParser = PEG.buildParser('start: ("a" "b") / "a"'); var posTestParser = PEG.buildParser('start = ("a" "b") / "a"');
parses(posTestParser, "a", "a"); parses(posTestParser, "a", "a");
}); });
test("and predicate", function() { test("and predicate", function() {
var parser = PEG.buildParser('start: "a" &"b" "b"'); var parser = PEG.buildParser('start = "a" &"b" "b"');
parses(parser, "ab", ["a", "", "b"]); parses(parser, "ab", ["a", "", "b"]);
doesNotParse(parser, "ac"); doesNotParse(parser, "ac");
@ -301,7 +301,7 @@ test("and predicate", function() {
}); });
test("not predicate", function() { test("not predicate", function() {
var parser = PEG.buildParser('start: "a" !"b"'); var parser = PEG.buildParser('start = "a" !"b"');
parses(parser, "a", ["a", ""]); parses(parser, "a", ["a", ""]);
doesNotParse(parser, "ab"); doesNotParse(parser, "ab");
@ -309,25 +309,25 @@ test("not predicate", function() {
* Test that the parsing position returns after successful parsing of a * Test that the parsing position returns after successful parsing of a
* predicate. * predicate.
*/ */
var posTestParser = PEG.buildParser('start: "a" !"b" "c"'); var posTestParser = PEG.buildParser('start = "a" !"b" "c"');
parses(posTestParser, "ac", ["a", "", "c"]); parses(posTestParser, "ac", ["a", "", "c"]);
}); });
test("optional expressions", function() { test("optional expressions", function() {
var parser = PEG.buildParser('start: "a"?'); var parser = PEG.buildParser('start = "a"?');
parses(parser, "", ""); parses(parser, "", "");
parses(parser, "a", "a"); parses(parser, "a", "a");
}); });
test("zero or more expressions", function() { test("zero or more expressions", function() {
var parser = PEG.buildParser('start: "a"*'); var parser = PEG.buildParser('start = "a"*');
parses(parser, "", []); parses(parser, "", []);
parses(parser, "a", ["a"]); parses(parser, "a", ["a"]);
parses(parser, "aaa", ["a", "a", "a"]); parses(parser, "aaa", ["a", "a", "a"]);
}); });
test("one or more expressions", function() { test("one or more expressions", function() {
var parser = PEG.buildParser('start: "a"+'); var parser = PEG.buildParser('start = "a"+');
doesNotParse(parser, ""); doesNotParse(parser, "");
parses(parser, "a", ["a"]); parses(parser, "a", ["a"]);
parses(parser, "aaa", ["a", "a", "a"]); parses(parser, "aaa", ["a", "a", "a"]);
@ -335,46 +335,46 @@ test("one or more expressions", function() {
test("actions", function() { test("actions", function() {
var singleMatchParser = PEG.buildParser( var singleMatchParser = PEG.buildParser(
'start: "a" { return Array.prototype.slice.call(arguments).join("").toUpperCase(); }' 'start = "a" { return Array.prototype.slice.call(arguments).join("").toUpperCase(); }'
); );
parses(singleMatchParser, "a", "A"); parses(singleMatchParser, "a", "A");
var multiMatchParser = PEG.buildParser( var multiMatchParser = PEG.buildParser(
'start: "a" "b" "c" { return Array.prototype.slice.call(arguments).join("").toUpperCase(); }' 'start = "a" "b" "c" { return Array.prototype.slice.call(arguments).join("").toUpperCase(); }'
); );
parses(multiMatchParser, "abc", "ABC"); parses(multiMatchParser, "abc", "ABC");
var innerMatchParser = PEG.buildParser( var innerMatchParser = PEG.buildParser(
'start: "a" ("b" "c" "d" { return Array.prototype.slice.call(arguments).join("").toUpperCase(); }) "e"' 'start = "a" ("b" "c" "d" { return Array.prototype.slice.call(arguments).join("").toUpperCase(); }) "e"'
); );
parses(innerMatchParser, "abcde", ["a", "BCD", "e"]); parses(innerMatchParser, "abcde", ["a", "BCD", "e"]);
/* Test that the action is not called when its expression does not match. */ /* Test that the action is not called when its expression does not match. */
var notAMatchParser = PEG.buildParser( var notAMatchParser = PEG.buildParser(
'start: "a" { ok(false, "action got called when it should not be"); }' 'start = "a" { ok(false, "action got called when it should not be"); }'
); );
doesNotParse(notAMatchParser, "b"); doesNotParse(notAMatchParser, "b");
var variablesParser = PEG.buildParser([ var variablesParser = PEG.buildParser([
'start: "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" {', 'start = "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" {',
' return [$1, $2, $3, $4, $5, $6, $7, $8, $9, $10].join("").toUpperCase();', ' return [$1, $2, $3, $4, $5, $6, $7, $8, $9, $10].join("").toUpperCase();',
' }' ' }'
].join("\n")); ].join("\n"));
parses(variablesParser, "abcdefghij", "ABCDEFGHIJ"); parses(variablesParser, "abcdefghij", "ABCDEFGHIJ");
}); });
test("rule references", function() { test("rule references", function() {
var parser = PEG.buildParser([ var parser = PEG.buildParser([
'start: static / dynamic', 'start = static / dynamic',
'static: "C" / "C++" / "Java" / "C#"', 'static = "C" / "C++" / "Java" / "C#"',
'dynamic: "Ruby" / "Python" / "JavaScript"' 'dynamic = "Ruby" / "Python" / "JavaScript"'
].join("\n")); ].join("\n"));
parses(parser, "Java", "Java"); parses(parser, "Java", "Java");
parses(parser, "Python", "Python"); parses(parser, "Python", "Python");
}); });
test("literals", function() { test("literals", function() {
var parser = PEG.buildParser('start: "abcd"'); var parser = PEG.buildParser('start = "abcd"');
parses(parser, "abcd", "abcd"); parses(parser, "abcd", "abcd");
doesNotParse(parser, ""); doesNotParse(parser, "");
doesNotParse(parser, "abc"); doesNotParse(parser, "abc");
@ -385,12 +385,12 @@ test("literals", function() {
* Test that the parsing position moves forward after successful parsing of * Test that the parsing position moves forward after successful parsing of
* a literal. * a literal.
*/ */
var posTestParser = PEG.buildParser('start: "a" "b"'); var posTestParser = PEG.buildParser('start = "a" "b"');
parses(posTestParser, "ab", ["a", "b"]); parses(posTestParser, "ab", ["a", "b"]);
}); });
test("anys", function() { test("anys", function() {
var parser = PEG.buildParser('start: .'); var parser = PEG.buildParser('start = .');
parses(parser, "a", "a"); parses(parser, "a", "a");
doesNotParse(parser, ""); doesNotParse(parser, "");
doesNotParse(parser, "ab"); doesNotParse(parser, "ab");
@ -399,17 +399,17 @@ test("anys", function() {
* Test that the parsing position moves forward after successful parsing of * Test that the parsing position moves forward after successful parsing of
* an any. * an any.
*/ */
var posTestParser = PEG.buildParser('start: . .'); var posTestParser = PEG.buildParser('start = . .');
parses(posTestParser, "ab", ["a", "b"]); parses(posTestParser, "ab", ["a", "b"]);
}); });
test("classes", function() { test("classes", function() {
var emptyClassParser = PEG.buildParser('start: []'); var emptyClassParser = PEG.buildParser('start = []');
doesNotParse(emptyClassParser, ""); doesNotParse(emptyClassParser, "");
doesNotParse(emptyClassParser, "a"); doesNotParse(emptyClassParser, "a");
doesNotParse(emptyClassParser, "ab"); doesNotParse(emptyClassParser, "ab");
var nonEmptyClassParser = PEG.buildParser('start: [ab-d]'); var nonEmptyClassParser = PEG.buildParser('start = [ab-d]');
parses(nonEmptyClassParser, "a", "a"); parses(nonEmptyClassParser, "a", "a");
parses(nonEmptyClassParser, "b", "b"); parses(nonEmptyClassParser, "b", "b");
parses(nonEmptyClassParser, "c", "c"); parses(nonEmptyClassParser, "c", "c");
@ -417,12 +417,12 @@ test("classes", function() {
doesNotParse(nonEmptyClassParser, ""); doesNotParse(nonEmptyClassParser, "");
doesNotParse(nonEmptyClassParser, "ab"); doesNotParse(nonEmptyClassParser, "ab");
var invertedEmptyClassParser = PEG.buildParser('start: [^]'); var invertedEmptyClassParser = PEG.buildParser('start = [^]');
doesNotParse(invertedEmptyClassParser, ""); doesNotParse(invertedEmptyClassParser, "");
parses(invertedEmptyClassParser, "a", "a"); parses(invertedEmptyClassParser, "a", "a");
doesNotParse(invertedEmptyClassParser, "ab"); doesNotParse(invertedEmptyClassParser, "ab");
var invertedNonEmptyClassParser = PEG.buildParser('start: [^ab-d]'); var invertedNonEmptyClassParser = PEG.buildParser('start = [^ab-d]');
doesNotParse(invertedNonEmptyClassParser, "a", "a"); doesNotParse(invertedNonEmptyClassParser, "a", "a");
doesNotParse(invertedNonEmptyClassParser, "b", "b"); doesNotParse(invertedNonEmptyClassParser, "b", "b");
doesNotParse(invertedNonEmptyClassParser, "c", "c"); doesNotParse(invertedNonEmptyClassParser, "c", "c");
@ -434,7 +434,7 @@ test("classes", function() {
* Test that the parsing position moves forward after successful parsing of * Test that the parsing position moves forward after successful parsing of
* a class. * a class.
*/ */
var posTestParser = PEG.buildParser('start: [ab-d] [ab-d]'); var posTestParser = PEG.buildParser('start = [ab-d] [ab-d]');
parses(posTestParser, "ab", ["a", "b"]); parses(posTestParser, "ab", ["a", "b"]);
}); });
@ -443,23 +443,23 @@ test("cache", function() {
* Should trigger a codepath where the cache is used (for the "a" rule). * Should trigger a codepath where the cache is used (for the "a" rule).
*/ */
var parser = PEG.buildParser([ var parser = PEG.buildParser([
'start: (a b) / (a c)', 'start = (a b) / (a c)',
'a: "a"', 'a = "a"',
'b: "b"', 'b = "b"',
'c: "c"' 'c = "c"'
].join("\n")); ].join("\n"));
parses(parser, "ac", ["a", "c"]); parses(parser, "ac", ["a", "c"]);
}); });
test("indempotence", function() { test("indempotence", function() {
var parser1 = PEG.buildParser('start: "abcd"'); var parser1 = PEG.buildParser('start = "abcd"');
var parser2 = PEG.buildParser('start: "abcd"'); var parser2 = PEG.buildParser('start = "abcd"');
strictEqual(parser1.toSource(), parser2.toSource()); strictEqual(parser1.toSource(), parser2.toSource());
}); });
test("error messages", function() { test("error messages", function() {
var literalParser = PEG.buildParser('start: "abcd"'); var literalParser = PEG.buildParser('start = "abcd"');
doesNotParseWithMessage( doesNotParseWithMessage(
literalParser, literalParser,
"", "",
@ -476,34 +476,34 @@ test("error messages", function() {
'Expected end of input but "e" found.' 'Expected end of input but "e" found.'
); );
var classParser = PEG.buildParser('start: [a-d]'); var classParser = PEG.buildParser('start = [a-d]');
doesNotParseWithMessage( doesNotParseWithMessage(
classParser, classParser,
"", "",
'Expected [a-d] but end of input found.' 'Expected [a-d] but end of input found.'
); );
var negativeClassParser = PEG.buildParser('start: [^a-d]'); var negativeClassParser = PEG.buildParser('start = [^a-d]');
doesNotParseWithMessage( doesNotParseWithMessage(
negativeClassParser, negativeClassParser,
"", "",
'Expected [^a-d] but end of input found.' 'Expected [^a-d] but end of input found.'
); );
var anyParser = PEG.buildParser('start: .'); var anyParser = PEG.buildParser('start = .');
doesNotParseWithMessage( doesNotParseWithMessage(
anyParser, anyParser,
"", "",
'Expected any character but end of input found.' 'Expected any character but end of input found.'
); );
var namedRuleWithLiteralParser = PEG.buildParser('start "digit": [0-9]'); var namedRuleWithLiteralParser = PEG.buildParser('start "digit" = [0-9]');
doesNotParseWithMessage( doesNotParseWithMessage(
namedRuleWithLiteralParser, namedRuleWithLiteralParser,
"a", "a",
'Expected digit but "a" found.' 'Expected digit but "a" found.'
); );
var namedRuleWithAnyParser = PEG.buildParser('start "whatever": .'); var namedRuleWithAnyParser = PEG.buildParser('start "whatever" = .');
doesNotParseWithMessage( doesNotParseWithMessage(
namedRuleWithAnyParser, namedRuleWithAnyParser,
"", "",
@ -511,8 +511,8 @@ test("error messages", function() {
); );
var namedRuleWithNamedRuleParser = PEG.buildParser([ var namedRuleWithNamedRuleParser = PEG.buildParser([
'start "digits": digit+', 'start "digits" = digit+',
'digit "digit": [0-9]' 'digit "digit" = [0-9]'
].join("\n")); ].join("\n"));
doesNotParseWithMessage( doesNotParseWithMessage(
namedRuleWithNamedRuleParser, namedRuleWithNamedRuleParser,
@ -520,49 +520,49 @@ test("error messages", function() {
'Expected digits but end of input found.' 'Expected digits but end of input found.'
); );
var choiceParser1 = PEG.buildParser('start: "a" / "b" / "c"'); var choiceParser1 = PEG.buildParser('start = "a" / "b" / "c"');
doesNotParseWithMessage( doesNotParseWithMessage(
choiceParser1, choiceParser1,
"def", "def",
'Expected "a", "b" or "c" but "d" found.' 'Expected "a", "b" or "c" but "d" found.'
); );
var choiceParser2 = PEG.buildParser('start: "a" "b" "c" / "a"'); var choiceParser2 = PEG.buildParser('start = "a" "b" "c" / "a"');
doesNotParseWithMessage( doesNotParseWithMessage(
choiceParser2, choiceParser2,
"abd", "abd",
'Expected "c" but "d" found.' 'Expected "c" but "d" found.'
); );
var notPredicateParser = PEG.buildParser('start: !"a" "b"'); var notPredicateParser = PEG.buildParser('start = !"a" "b"');
doesNotParseWithMessage( doesNotParseWithMessage(
notPredicateParser, notPredicateParser,
"c", "c",
'Expected "b" but "c" found.' 'Expected "b" but "c" found.'
); );
var andPredicateParser = PEG.buildParser('start: &"a" [a-b]'); var andPredicateParser = PEG.buildParser('start = &"a" [a-b]');
doesNotParseWithMessage( doesNotParseWithMessage(
andPredicateParser, andPredicateParser,
"c", "c",
'Expected end of input but "c" found.' 'Expected end of input but "c" found.'
); );
var emptyParser = PEG.buildParser('start: '); var emptyParser = PEG.buildParser('start = ');
doesNotParseWithMessage( doesNotParseWithMessage(
emptyParser, emptyParser,
"something", "something",
'Expected end of input but "s" found.' 'Expected end of input but "s" found.'
); );
var duplicateErrorParser = PEG.buildParser('start: "a" / "a"'); var duplicateErrorParser = PEG.buildParser('start = "a" / "a"');
doesNotParseWithMessage( doesNotParseWithMessage(
duplicateErrorParser, duplicateErrorParser,
"", "",
'Expected "a" but end of input found.' 'Expected "a" but end of input found.'
); );
var unsortedErrorsParser = PEG.buildParser('start: "b" / "a"'); var unsortedErrorsParser = PEG.buildParser('start = "b" / "a"');
doesNotParseWithMessage( doesNotParseWithMessage(
unsortedErrorsParser, unsortedErrorsParser,
"", "",
@ -572,9 +572,9 @@ test("error messages", function() {
test("error positions", function() { test("error positions", function() {
var parser = PEG.buildParser([ var parser = PEG.buildParser([
'start: line (("\\r" / "\\n" / "\\u2028" / "\\u2029")+ line)*', 'start = line (("\\r" / "\\n" / "\\u2028" / "\\u2029")+ line)*',
'line: digit (" "+ digit)*', 'line = digit (" "+ digit)*',
'digit: [0-9]+ { return $1.join(""); }' 'digit = [0-9]+ { return $1.join(""); }'
].join("\n")); ].join("\n"));
doesNotParseWithPos(parser, "a", 1, 1); doesNotParseWithPos(parser, "a", 1, 1);
@ -603,9 +603,9 @@ test("arithmetics", function() {
* Expr Sum * Expr Sum
*/ */
var parser = PEG.buildParser([ var parser = PEG.buildParser([
'Value : [0-9]+ { return parseInt($1.join("")); }', 'Value = [0-9]+ { return parseInt($1.join("")); }',
' / "(" Expr ")" { return $2; }', ' / "(" Expr ")" { return $2; }',
'Product : Value (("*" / "/") Value)* {', 'Product = Value (("*" / "/") Value)* {',
' var result = $1;', ' var result = $1;',
' for (var i = 0; i < $2.length; i++) {', ' for (var i = 0; i < $2.length; i++) {',
' if ($2[i][0] == "*") { result *= $2[i][1]; }', ' if ($2[i][0] == "*") { result *= $2[i][1]; }',
@ -613,7 +613,7 @@ test("arithmetics", function() {
' }', ' }',
' return result;', ' return result;',
' }', ' }',
'Sum : Product (("+" / "-") Product)* {', 'Sum = Product (("+" / "-") Product)* {',
' var result = $1;', ' var result = $1;',
' for (var i = 0; i < $2.length; i++) {', ' for (var i = 0; i < $2.length; i++) {',
' if ($2[i][0] == "+") { result += $2[i][1]; }', ' if ($2[i][0] == "+") { result += $2[i][1]; }',
@ -621,7 +621,7 @@ test("arithmetics", function() {
' }', ' }',
' return result;', ' return result;',
' }', ' }',
'Expr : Sum' 'Expr = Sum'
].join("\n"), "Expr"); ].join("\n"), "Expr");
/* Test "value" rule. */ /* Test "value" rule. */
@ -659,9 +659,9 @@ test("non-context-free language", function() {
* B b B? c * B b B? c
*/ */
var parser = PEG.buildParser([ var parser = PEG.buildParser([
'S: &(A "c") "a"+ B !("a" / "b" / "c") { return $2.join("") + $3; }', 'S = &(A "c") "a"+ B !("a" / "b" / "c") { return $2.join("") + $3; }',
'A: "a" A? "b" { return $1 + $2 + $3; }', 'A = "a" A? "b" { return $1 + $2 + $3; }',
'B: "b" B? "c" { return $1 + $2 + $3; }', 'B = "b" B? "c" { return $1 + $2 + $3; }',
].join("\n"), "S"); ].join("\n"), "S");
parses(parser, "abc", "abc"); parses(parser, "abc", "abc");
@ -683,12 +683,12 @@ test("nested comments", function() {
* Z any single character * Z any single character
*/ */
var parser = PEG.buildParser([ var parser = PEG.buildParser([
'Begin : "(*"', 'Begin = "(*"',
'End : "*)"', 'End = "*)"',
'C : Begin N* End { return $1 + $2.join("") + $3; }', 'C = Begin N* End { return $1 + $2.join("") + $3; }',
'N : C', 'N = C',
' / (!Begin !End Z) { return $3; }', ' / (!Begin !End Z) { return $3; }',
'Z : .' 'Z = .'
].join("\n"), "C"); ].join("\n"), "C");
parses(parser, "(**)", "(**)"); parses(parser, "(**)", "(**)");

@ -138,9 +138,9 @@ function actionGrammar(action) {
/* Canonical grammar is "a: \"abcd\";\nb: \"efgh\";\nc: \"ijkl\";". */ /* Canonical grammar is "a: \"abcd\";\nb: \"efgh\";\nc: \"ijkl\";". */
test("parses grammar", function() { test("parses grammar", function() {
grammarParserParses('a: "abcd"', { a: rule("a", null, literalAbcd) }); grammarParserParses('a = "abcd"', { a: rule("a", null, literalAbcd) });
grammarParserParses( grammarParserParses(
'a: "abcd"\nb: "efgh"\nc: "ijkl"', 'a = "abcd"\nb = "efgh"\nc = "ijkl"',
{ {
a: rule("a", null, literalAbcd), a: rule("a", null, literalAbcd),
b: rule("b", null, literalEfgh), b: rule("b", null, literalEfgh),
@ -152,11 +152,11 @@ test("parses grammar", function() {
/* Canonical rule is "a: \"abcd\"". */ /* Canonical rule is "a: \"abcd\"". */
test("parses rule", function() { test("parses rule", function() {
grammarParserParses( grammarParserParses(
'start: "abcd" / "efgh" / "ijkl"', 'start = "abcd" / "efgh" / "ijkl"',
oneRuleGrammar(choiceLiterals) oneRuleGrammar(choiceLiterals)
); );
grammarParserParses( grammarParserParses(
'start "start rule": "abcd" / "efgh" / "ijkl"', 'start "start rule" = "abcd" / "efgh" / "ijkl"',
{ {
start: rule("start", "start rule", choiceLiterals) start: rule("start", "start rule", choiceLiterals)
} }
@ -166,7 +166,7 @@ test("parses rule", function() {
/* Canonical expression is "\"abcd\" / \"efgh\" / \"ijkl\"". */ /* Canonical expression is "\"abcd\" / \"efgh\" / \"ijkl\"". */
test("parses expression", function() { test("parses expression", function() {
grammarParserParses( grammarParserParses(
'start: "abcd" / "efgh" / "ijkl"', 'start = "abcd" / "efgh" / "ijkl"',
oneRuleGrammar(choiceLiterals) oneRuleGrammar(choiceLiterals)
); );
}); });
@ -174,11 +174,11 @@ test("parses expression", function() {
/* Canonical choice is "\"abcd\" / \"efgh\" / \"ijkl\"". */ /* Canonical choice is "\"abcd\" / \"efgh\" / \"ijkl\"". */
test("parses choice", function() { test("parses choice", function() {
grammarParserParses( grammarParserParses(
'start: "abcd" "efgh" "ijkl"', 'start = "abcd" "efgh" "ijkl"',
oneRuleGrammar(sequenceLiterals) oneRuleGrammar(sequenceLiterals)
); );
grammarParserParses( grammarParserParses(
'start: "abcd" "efgh" "ijkl" / "abcd" "efgh" "ijkl" / "abcd" "efgh" "ijkl"', 'start = "abcd" "efgh" "ijkl" / "abcd" "efgh" "ijkl" / "abcd" "efgh" "ijkl"',
oneRuleGrammar(choice([ oneRuleGrammar(choice([
sequenceLiterals, sequenceLiterals,
sequenceLiterals, sequenceLiterals,
@ -190,341 +190,342 @@ test("parses choice", function() {
/* Canonical sequence is "\"abcd\" \"efgh\" \"ijkl\"". */ /* Canonical sequence is "\"abcd\" \"efgh\" \"ijkl\"". */
test("parses sequence", function() { test("parses sequence", function() {
grammarParserParses( grammarParserParses(
'start: { code }', 'start = { code }',
oneRuleGrammar(action(sequenceEmpty, " code ")) oneRuleGrammar(action(sequenceEmpty, " code "))
); );
grammarParserParses( grammarParserParses(
'start: !"abcd" { code }', 'start = !"abcd" { code }',
oneRuleGrammar(action(notAbcd, " code ")) oneRuleGrammar(action(notAbcd, " code "))
); );
grammarParserParses( grammarParserParses(
'start: !"abcd" !"efgh" !"ijkl" { code }', 'start = !"abcd" !"efgh" !"ijkl" { code }',
oneRuleGrammar(action(sequenceNots, " code ")) oneRuleGrammar(action(sequenceNots, " code "))
); );
grammarParserParses('start: ', oneRuleGrammar(sequenceEmpty)); grammarParserParses('start = ', oneRuleGrammar(sequenceEmpty));
grammarParserParses('start: !"abcd"', oneRuleGrammar(notAbcd)); grammarParserParses('start = !"abcd"', oneRuleGrammar(notAbcd));
grammarParserParses( grammarParserParses(
'start: !"abcd" !"efgh" !"ijkl"', 'start = !"abcd" !"efgh" !"ijkl"',
oneRuleGrammar(sequenceNots) oneRuleGrammar(sequenceNots)
); );
}); });
/* Canonical prefixed is "!\"abcd\"". */ /* Canonical prefixed is "!\"abcd\"". */
test("parses prefixed", function() { test("parses prefixed", function() {
grammarParserParses('start: &"abcd"?', oneRuleGrammar(andPredicate(optionalLiteral))); grammarParserParses('start = &"abcd"?', oneRuleGrammar(andPredicate(optionalLiteral)));
grammarParserParses('start: !"abcd"?', oneRuleGrammar(notPredicate(optionalLiteral))); grammarParserParses('start = !"abcd"?', oneRuleGrammar(notPredicate(optionalLiteral)));
grammarParserParses('start: "abcd"?', oneRuleGrammar(optionalLiteral)); grammarParserParses('start = "abcd"?', oneRuleGrammar(optionalLiteral));
}); });
/* Canonical suffixed is "\"abcd\"?". */ /* Canonical suffixed is "\"abcd\"?". */
test("parses suffixed", function() { test("parses suffixed", function() {
grammarParserParses('start: "abcd"?', oneRuleGrammar(optionalLiteral)); grammarParserParses('start = "abcd"?', oneRuleGrammar(optionalLiteral));
grammarParserParses('start: "abcd"*', oneRuleGrammar(zeroOrMore(literalAbcd))); grammarParserParses('start = "abcd"*', oneRuleGrammar(zeroOrMore(literalAbcd)));
grammarParserParses('start: "abcd"+', oneRuleGrammar(oneOrMore(literalAbcd))); grammarParserParses('start = "abcd"+', oneRuleGrammar(oneOrMore(literalAbcd)));
grammarParserParses('start: "abcd"', literalGrammar("abcd")); grammarParserParses('start = "abcd"', literalGrammar("abcd"));
}); });
/* Canonical primary is "\"abcd\"". */ /* Canonical primary is "\"abcd\"". */
test("parses primary", function() { test("parses primary", function() {
grammarParserParses('start: a', identifierGrammar("a")); grammarParserParses('start = a', identifierGrammar("a"));
grammarParserParses('start: "abcd"', literalGrammar("abcd")); grammarParserParses('start = "abcd"', literalGrammar("abcd"));
grammarParserParses('start: .', anyGrammar); grammarParserParses('start = .', anyGrammar);
grammarParserParses('start: [a-d]', classGrammar(false, [["a", "d"]], "[a-d]")); grammarParserParses('start = [a-d]', classGrammar(false, [["a", "d"]], "[a-d]"));
grammarParserParses('start: ("abcd")', literalGrammar("abcd")); grammarParserParses('start = ("abcd")', literalGrammar("abcd"));
}); });
/* Canonical action is "{ code }". */ /* Canonical action is "{ code }". */
test("parses action", function() { test("parses action", function() {
grammarParserParses('start: "a" { code }', actionGrammar(" code ")); grammarParserParses('start = "a" { code }', actionGrammar(" code "));
}); });
/* Canonical braced is "{ code }". */ /* Canonical braced is "{ code }". */
test("parses braced", function() { test("parses braced", function() {
grammarParserParses('start: "a" {}', actionGrammar("")); grammarParserParses('start = "a" {}', actionGrammar(""));
grammarParserParses('start: "a" {a}', actionGrammar("a")); grammarParserParses('start = "a" {a}', actionGrammar("a"));
grammarParserParses('start: "a" {{a}}', actionGrammar("{a}")); grammarParserParses('start = "a" {{a}}', actionGrammar("{a}"));
grammarParserParses('start: "a" {aaa}', actionGrammar("aaa")); grammarParserParses('start = "a" {aaa}', actionGrammar("aaa"));
}); });
/* Trivial character rules are not tested. */ /* Trivial character rules are not tested. */
/* Canonical identifier is "a". */ /* Canonical identifier is "a". */
test("parses identifier", function() { test("parses identifier", function() {
grammarParserParses('start: a', identifierGrammar("a")); grammarParserParses('start = a', identifierGrammar("a"));
grammarParserParses('start: z', identifierGrammar("z")); grammarParserParses('start = z', identifierGrammar("z"));
grammarParserParses('start: A', identifierGrammar("A")); grammarParserParses('start = A', identifierGrammar("A"));
grammarParserParses('start: Z', identifierGrammar("Z")); grammarParserParses('start = Z', identifierGrammar("Z"));
grammarParserParses('start: _', identifierGrammar("_")); grammarParserParses('start = _', identifierGrammar("_"));
grammarParserParses('start: $', identifierGrammar("$")); grammarParserParses('start = $', identifierGrammar("$"));
grammarParserParses('start: aa', identifierGrammar("aa")); grammarParserParses('start = aa', identifierGrammar("aa"));
grammarParserParses('start: az', identifierGrammar("az")); grammarParserParses('start = az', identifierGrammar("az"));
grammarParserParses('start: aA', identifierGrammar("aA")); grammarParserParses('start = aA', identifierGrammar("aA"));
grammarParserParses('start: aZ', identifierGrammar("aZ")); grammarParserParses('start = aZ', identifierGrammar("aZ"));
grammarParserParses('start: a0', identifierGrammar("a0")); grammarParserParses('start = a0', identifierGrammar("a0"));
grammarParserParses('start: a9', identifierGrammar("a9")); grammarParserParses('start = a9', identifierGrammar("a9"));
grammarParserParses('start: a_', identifierGrammar("a_")); grammarParserParses('start = a_', identifierGrammar("a_"));
grammarParserParses('start: a$', identifierGrammar("a$")); grammarParserParses('start = a$', identifierGrammar("a$"));
grammarParserParses('start: abcd', identifierGrammar("abcd")); grammarParserParses('start = abcd', identifierGrammar("abcd"));
grammarParserParses('start: a\n', identifierGrammar("a")); grammarParserParses('start = a\n', identifierGrammar("a"));
}); });
/* Canonical literal is "\"abcd\"". */ /* Canonical literal is "\"abcd\"". */
test("parses literal", function() { test("parses literal", function() {
grammarParserParses('start: "abcd"', literalGrammar("abcd")); grammarParserParses('start = "abcd"', literalGrammar("abcd"));
grammarParserParses("start: 'abcd'", literalGrammar("abcd")); grammarParserParses("start = 'abcd'", literalGrammar("abcd"));
}); });
/* Canonical doubleQuotedLiteral is "\"abcd\"". */ /* Canonical doubleQuotedLiteral is "\"abcd\"". */
test("parses doubleQuotedLiteral", function() { test("parses doubleQuotedLiteral", function() {
grammarParserParses('start: ""', literalGrammar("")); grammarParserParses('start = ""', literalGrammar(""));
grammarParserParses('start: "a"', literalGrammar("a")); grammarParserParses('start = "a"', literalGrammar("a"));
grammarParserParses('start: "abc"', literalGrammar("abc")); grammarParserParses('start = "abc"', literalGrammar("abc"));
grammarParserParses('start: "abcd"\n', literalGrammar("abcd")); grammarParserParses('start = "abcd"\n', literalGrammar("abcd"));
}); });
/* Canonical doubleQuotedCharacter is "a". */ /* Canonical doubleQuotedCharacter is "a". */
test("parses doubleQuotedCharacter", function() { test("parses doubleQuotedCharacter", function() {
grammarParserParses('start: "a"', literalGrammar("a")); grammarParserParses('start = "a"', literalGrammar("a"));
grammarParserParses('start: "\\n"', literalGrammar("\n")); grammarParserParses('start = "\\n"', literalGrammar("\n"));
grammarParserParses('start: "\\0"', literalGrammar("\0")); grammarParserParses('start = "\\0"', literalGrammar("\0"));
grammarParserParses('start: "\\x00"', literalGrammar("\x00")); grammarParserParses('start = "\\x00"', literalGrammar("\x00"));
grammarParserParses('start: "\\u0120"', literalGrammar("\u0120")); grammarParserParses('start = "\\u0120"', literalGrammar("\u0120"));
grammarParserParses('start: "\\\n"', literalGrammar("\n")); grammarParserParses('start = "\\\n"', literalGrammar("\n"));
}); });
/* Canonical simpleDoubleQuotedCharacter is "a". */ /* Canonical simpleDoubleQuotedCharacter is "a". */
test("parses simpleDoubleQuotedCharacter", function() { test("parses simpleDoubleQuotedCharacter", function() {
grammarParserParses('start: "a"', literalGrammar("a")); grammarParserParses('start = "a"', literalGrammar("a"));
grammarParserParses('start: "\'"', literalGrammar("'")); grammarParserParses('start = "\'"', literalGrammar("'"));
grammarParserDoesNotParse('start: """'); grammarParserDoesNotParse('start = """');
grammarParserDoesNotParse('start: "\\"'); grammarParserDoesNotParse('start = "\\"');
grammarParserDoesNotParse('start: "\n"'); grammarParserDoesNotParse('start = "\n"');
grammarParserDoesNotParse('start: "\r"'); grammarParserDoesNotParse('start = "\r"');
grammarParserDoesNotParse('start: "\u2028"'); grammarParserDoesNotParse('start = "\u2028"');
grammarParserDoesNotParse('start: "\u2029"'); grammarParserDoesNotParse('start = "\u2029"');
}); });
/* Canonical singleQuotedLiteral is "'abcd'". */ /* Canonical singleQuotedLiteral is "'abcd'". */
test("parses singleQuotedLiteral", function() { test("parses singleQuotedLiteral", function() {
grammarParserParses("start: ''", literalGrammar("")); grammarParserParses("start = ''", literalGrammar(""));
grammarParserParses("start: 'a'", literalGrammar("a")); grammarParserParses("start = 'a'", literalGrammar("a"));
grammarParserParses("start: 'abc'", literalGrammar("abc")); grammarParserParses("start = 'abc'", literalGrammar("abc"));
grammarParserParses("start: 'abcd'\n", literalGrammar("abcd")); grammarParserParses("start = 'abcd'\n", literalGrammar("abcd"));
}); });
/* Canonical singleQuotedCharacter is "a". */ /* Canonical singleQuotedCharacter is "a". */
test("parses singleQuotedCharacter", function() { test("parses singleQuotedCharacter", function() {
grammarParserParses("start: 'a'", literalGrammar("a")); grammarParserParses("start = 'a'", literalGrammar("a"));
grammarParserParses("start: '\\n'", literalGrammar("\n")); grammarParserParses("start = '\\n'", literalGrammar("\n"));
grammarParserParses("start: '\\0'", literalGrammar("\0")); grammarParserParses("start = '\\0'", literalGrammar("\0"));
grammarParserParses("start: '\\x00'", literalGrammar("\x00")); grammarParserParses("start = '\\x00'", literalGrammar("\x00"));
grammarParserParses("start: '\\u0120'", literalGrammar("\u0120")); grammarParserParses("start = '\\u0120'", literalGrammar("\u0120"));
grammarParserParses("start: '\\\n'", literalGrammar("\n")); grammarParserParses("start = '\\\n'", literalGrammar("\n"));
}); });
/* Canonical simpleSingleQuotedCharacter is "a". */ /* Canonical simpleSingleQuotedCharacter is "a". */
test("parses simpleSingleQuotedCharacter", function() { test("parses simpleSingleQuotedCharacter", function() {
grammarParserParses("start: 'a'", literalGrammar("a")); grammarParserParses("start = 'a'", literalGrammar("a"));
grammarParserParses("start: '\"'", literalGrammar("\"")); grammarParserParses("start = '\"'", literalGrammar("\""));
grammarParserDoesNotParse("start: '''"); grammarParserDoesNotParse("start = '''");
grammarParserDoesNotParse("start: '\\'"); grammarParserDoesNotParse("start = '\\'");
grammarParserDoesNotParse("start: '\n'"); grammarParserDoesNotParse("start = '\n'");
grammarParserDoesNotParse("start: '\r'"); grammarParserDoesNotParse("start = '\r'");
grammarParserDoesNotParse("start: '\u2028'"); grammarParserDoesNotParse("start = '\u2028'");
grammarParserDoesNotParse("start: '\u2029'"); grammarParserDoesNotParse("start = '\u2029'");
}); });
/* Canonical class is "[a-d]". */ /* Canonical class is "[a-d]". */
test("parses class", function() { test("parses class", function() {
grammarParserParses("start: []", classGrammar(false, [], "[]")); grammarParserParses("start = []", classGrammar(false, [], "[]"));
grammarParserParses("start: [a-d]", classGrammar(false, [["a", "d"]], "[a-d]")); grammarParserParses("start = [a-d]", classGrammar(false, [["a", "d"]], "[a-d]"));
grammarParserParses("start: [^a-d]", classGrammar(true, [["a", "d"]], "[^a-d]")); grammarParserParses("start = [^a-d]", classGrammar(true, [["a", "d"]], "[^a-d]"));
grammarParserParses("start: [a]", classGrammar(false, ["a"], "[a]")); grammarParserParses("start = [a]", classGrammar(false, ["a"], "[a]"));
grammarParserParses( grammarParserParses(
"start: [a-de-hi-l]", "start = [a-de-hi-l]",
classGrammar(false, [["a", "d"], ["e", "h"], ["i", "l"]], "[a-de-hi-l]") classGrammar(false, [["a", "d"], ["e", "h"], ["i", "l"]], "[a-de-hi-l]")
); );
grammarParserParses("start: [a-d]\n", classGrammar(false, [["a", "d"]], "[a-d]")); grammarParserParses("start = [a-d]\n", classGrammar(false, [["a", "d"]], "[a-d]"));
}); });
/* Canonical classCharacterRange is "a-d". */ /* Canonical classCharacterRange is "a-d". */
test("parses classCharacterRange", function() { test("parses classCharacterRange", function() {
grammarParserParses("start: [a-d]", classGrammar(false, [["a", "d"]], "[a-d]")); grammarParserParses("start = [a-d]", classGrammar(false, [["a", "d"]], "[a-d]"));
grammarParserParses("start: [a-a]", classGrammar(false, [["a", "a"]], "[a-a]")); grammarParserParses("start = [a-a]", classGrammar(false, [["a", "a"]], "[a-a]"));
grammarParserDoesNotParse("start = [b-a]");
grammarParserDoesNotParseWithMessage( grammarParserDoesNotParseWithMessage(
"start: [b-a]", "start = [b-a]",
"Invalid character range: b-a." "Invalid character range: b-a."
); );
}); });
/* Canonical classCharacter is "a". */ /* Canonical classCharacter is "a". */
test("parses classCharacter", function() { test("parses classCharacter", function() {
grammarParserParses("start: [a]", classGrammar(false, ["a"], "[a]")); grammarParserParses("start = [a]", classGrammar(false, ["a"], "[a]"));
}); });
/* Canonical bracketDelimitedCharacter is "a". */ /* Canonical bracketDelimitedCharacter is "a". */
test("parses bracketDelimitedCharacter", function() { test("parses bracketDelimitedCharacter", function() {
grammarParserParses("start: [a]", classGrammar(false, ["a"], "[a]")); grammarParserParses("start = [a]", classGrammar(false, ["a"], "[a]"));
grammarParserParses("start: [\\n]", classGrammar(false, ["\n"], "[\\n]")); grammarParserParses("start = [\\n]", classGrammar(false, ["\n"], "[\\n]"));
grammarParserParses("start: [\\0]", classGrammar(false, ["\0"], "[\\0]")); grammarParserParses("start = [\\0]", classGrammar(false, ["\0"], "[\\0]"));
grammarParserParses("start: [\\x00]", classGrammar(false, ["\0"], "[\\0]")); grammarParserParses("start = [\\x00]", classGrammar(false, ["\0"], "[\\0]"));
grammarParserParses("start: [\\u0120]", classGrammar(false, ["\u0120"], "[\u0120]")); grammarParserParses("start = [\\u0120]", classGrammar(false, ["\u0120"], "[\u0120]"));
grammarParserParses("start: [\\\n]", classGrammar(false, ["\n"], "[\\n]")); grammarParserParses("start = [\\\n]", classGrammar(false, ["\n"], "[\\n]"));
}); });
/* Canonical simpleBracketDelimiedCharacter is "a". */ /* Canonical simpleBracketDelimiedCharacter is "a". */
test("parses simpleBracketDelimitedCharacter", function() { test("parses simpleBracketDelimitedCharacter", function() {
grammarParserParses("start: [a]", classGrammar(false, ["a"], "[a]")); grammarParserParses("start = [a]", classGrammar(false, ["a"], "[a]"));
grammarParserParses("start: [[]", classGrammar(false, ["["], "[[]")); grammarParserParses("start = [[]", classGrammar(false, ["["], "[[]"));
grammarParserDoesNotParse("start: []]"); grammarParserDoesNotParse("start = []]");
grammarParserDoesNotParse("start: [\\]"); grammarParserDoesNotParse("start = [\\]");
grammarParserDoesNotParse("start: [\n]"); grammarParserDoesNotParse("start = [\n]");
grammarParserDoesNotParse("start: [\r]"); grammarParserDoesNotParse("start = [\r]");
grammarParserDoesNotParse("start: [\u2028]"); grammarParserDoesNotParse("start = [\u2028]");
grammarParserDoesNotParse("start: [\u2029]"); grammarParserDoesNotParse("start = [\u2029]");
}); });
/* Canonical simpleEscapeSequence is "\\n". */ /* Canonical simpleEscapeSequence is "\\n". */
test("parses simpleEscapeSequence", function() { test("parses simpleEscapeSequence", function() {
grammarParserParses('start: "\\\'"', literalGrammar("'")); grammarParserParses('start = "\\\'"', literalGrammar("'"));
grammarParserParses('start: "\\""', literalGrammar("\"")); grammarParserParses('start = "\\""', literalGrammar("\""));
grammarParserParses('start: "\\\\"', literalGrammar("\\")); grammarParserParses('start = "\\\\"', literalGrammar("\\"));
grammarParserParses('start: "\\b"', literalGrammar("\b")); grammarParserParses('start = "\\b"', literalGrammar("\b"));
grammarParserParses('start: "\\f"', literalGrammar("\f")); grammarParserParses('start = "\\f"', literalGrammar("\f"));
grammarParserParses('start: "\\n"', literalGrammar("\n")); grammarParserParses('start = "\\n"', literalGrammar("\n"));
grammarParserParses('start: "\\r"', literalGrammar("\r")); grammarParserParses('start = "\\r"', literalGrammar("\r"));
grammarParserParses('start: "\\t"', literalGrammar("\t")); grammarParserParses('start = "\\t"', literalGrammar("\t"));
/* IE does not recognize "\v". */ /* IE does not recognize "\v". */
grammarParserParses('start: "\\v"', literalGrammar("\x0B")); grammarParserParses('start = "\\v"', literalGrammar("\x0B"));
grammarParserParses('start: "\\a"', literalGrammar("a")); grammarParserParses('start = "\\a"', literalGrammar("a"));
}); });
/* Canonical zeroEscapeSequence is "\\0". */ /* Canonical zeroEscapeSequence is "\\0". */
test("parses zeroEscapeSequence", function() { test("parses zeroEscapeSequence", function() {
grammarParserParses('start: "\\0"', literalGrammar("\0")); grammarParserParses('start = "\\0"', literalGrammar("\0"));
grammarParserDoesNotParse('start: "\\00"'); grammarParserDoesNotParse('start = "\\00"');
grammarParserDoesNotParse('start: "\\09"'); grammarParserDoesNotParse('start = "\\09"');
}); });
/* Canonical hexEscapeSequence is "\\x00". */ /* Canonical hexEscapeSequence is "\\x00". */
test("parses hexEscapeSequence", function() { test("parses hexEscapeSequence", function() {
grammarParserParses('start: "\\x00"', literalGrammar("\x00")); grammarParserParses('start = "\\x00"', literalGrammar("\x00"));
grammarParserParses('start: "\\x09"', literalGrammar("\x09")); grammarParserParses('start = "\\x09"', literalGrammar("\x09"));
grammarParserParses('start: "\\x0a"', literalGrammar("\x0a")); grammarParserParses('start = "\\x0a"', literalGrammar("\x0a"));
grammarParserParses('start: "\\x0f"', literalGrammar("\x0f")); grammarParserParses('start = "\\x0f"', literalGrammar("\x0f"));
grammarParserParses('start: "\\x0A"', literalGrammar("\x0A")); grammarParserParses('start = "\\x0A"', literalGrammar("\x0A"));
grammarParserParses('start: "\\x0F"', literalGrammar("\x0F")); grammarParserParses('start = "\\x0F"', literalGrammar("\x0F"));
grammarParserDoesNotParse('start: "\\x0"'); grammarParserDoesNotParse('start = "\\x0"');
grammarParserParses('start: "\\x000"', literalGrammar("\x000")); grammarParserParses('start = "\\x000"', literalGrammar("\x000"));
}); });
/* Canonical unicodeEscapeSequence is "\\u0120". */ /* Canonical unicodeEscapeSequence is "\\u0120". */
test("parses unicodeEscapeSequence", function() { test("parses unicodeEscapeSequence", function() {
grammarParserParses('start: "\\u0120"', literalGrammar("\u0120")); grammarParserParses('start = "\\u0120"', literalGrammar("\u0120"));
grammarParserParses('start: "\\u0129"', literalGrammar("\u0129")); grammarParserParses('start = "\\u0129"', literalGrammar("\u0129"));
grammarParserParses('start: "\\u012a"', literalGrammar("\u012a")); grammarParserParses('start = "\\u012a"', literalGrammar("\u012a"));
grammarParserParses('start: "\\u012f"', literalGrammar("\u012f")); grammarParserParses('start = "\\u012f"', literalGrammar("\u012f"));
grammarParserParses('start: "\\u012A"', literalGrammar("\u012A")); grammarParserParses('start = "\\u012A"', literalGrammar("\u012A"));
grammarParserParses('start: "\\u012F"', literalGrammar("\u012F")); grammarParserParses('start = "\\u012F"', literalGrammar("\u012F"));
grammarParserDoesNotParse('start: "\\u012"'); grammarParserDoesNotParse('start = "\\u012"');
grammarParserParses('start: "\\u01234"', literalGrammar("\u01234")); grammarParserParses('start = "\\u01234"', literalGrammar("\u01234"));
}); });
/* Canonical eolEscapeSequence is "\\\n". */ /* Canonical eolEscapeSequence is "\\\n". */
test("parses eolEscapeSequence", function() { test("parses eolEscapeSequence", function() {
grammarParserParses('start: "\\\n"', literalGrammar("\n")); grammarParserParses('start = "\\\n"', literalGrammar("\n"));
grammarParserParses('start: "\\\r\n"', literalGrammar("\r\n")); grammarParserParses('start = "\\\r\n"', literalGrammar("\r\n"));
grammarParserParses('start: "\\\r"', literalGrammar("\r")); grammarParserParses('start = "\\\r"', literalGrammar("\r"));
grammarParserParses('start: "\\\u2028"', literalGrammar("\u2028")); grammarParserParses('start = "\\\u2028"', literalGrammar("\u2028"));
grammarParserParses('start: "\\\u2029"', literalGrammar("\u2029")); grammarParserParses('start = "\\\u2029"', literalGrammar("\u2029"));
}); });
/* Canonical __ is "\n". */ /* Canonical __ is "\n". */
test("parses __", function() { test("parses __", function() {
grammarParserParses('start:"abcd"', simpleGrammar); grammarParserParses('start ="abcd"', simpleGrammar);
grammarParserParses('start: "abcd"', simpleGrammar); grammarParserParses('start = "abcd"', simpleGrammar);
grammarParserParses('start:\n"abcd"', simpleGrammar); grammarParserParses('start =\n"abcd"', simpleGrammar);
grammarParserParses('start:/* comment */"abcd"', simpleGrammar); grammarParserParses('start =/* comment */"abcd"', simpleGrammar);
grammarParserParses('start: "abcd"', simpleGrammar); grammarParserParses('start = "abcd"', simpleGrammar);
}); });
/* Trivial character class rules are not tested. */ /* Trivial character class rules are not tested. */
/* Canonical comment is "\/* comment *\/". */ /* Canonical comment is "\/* comment *\/". */
test("parses comment", function() { test("parses comment", function() {
grammarParserParses('start:// comment\n"abcd"', simpleGrammar); grammarParserParses('start =// comment\n"abcd"', simpleGrammar);
grammarParserParses('start:/* comment */"abcd"', simpleGrammar); grammarParserParses('start =/* comment */"abcd"', simpleGrammar);
}); });
/* Canonical singleLineComment is "// comment". */ /* Canonical singleLineComment is "// comment". */
test("parses singleLineComment", function() { test("parses singleLineComment", function() {
grammarParserParses('start://\n"abcd"', simpleGrammar); grammarParserParses('start =//\n"abcd"', simpleGrammar);
grammarParserParses('start://a\n"abcd"', simpleGrammar); grammarParserParses('start =//a\n"abcd"', simpleGrammar);
grammarParserParses('start://aaa\n"abcd"', simpleGrammar); grammarParserParses('start =//aaa\n"abcd"', simpleGrammar);
grammarParserParses('start: "abcd"//', simpleGrammar); grammarParserParses('start = "abcd"//', simpleGrammar);
}); });
/* Canonical multiLineComment is "\/* comment *\/". */ /* Canonical multiLineComment is "\/* comment *\/". */
test("parses multiLineComment", function() { test("parses multiLineComment", function() {
grammarParserParses('start:/**/"abcd"', simpleGrammar); grammarParserParses('start =/**/"abcd"', simpleGrammar);
grammarParserParses('start:/*a*/"abcd"', simpleGrammar); grammarParserParses('start =/*a*/"abcd"', simpleGrammar);
grammarParserParses('start:/*aaa*/"abcd"', simpleGrammar); grammarParserParses('start =/*aaa*/"abcd"', simpleGrammar);
grammarParserParses('start:/*\n*/"abcd"', simpleGrammar); grammarParserParses('start =/*\n*/"abcd"', simpleGrammar);
grammarParserParses('start:/***/"abcd"', simpleGrammar); grammarParserParses('start =/***/"abcd"', simpleGrammar);
grammarParserParses('start:/*a/*/"abcd"', simpleGrammar); grammarParserParses('start =/*a/*/"abcd"', simpleGrammar);
grammarParserDoesNotParse('start:/*"abcd"'); grammarParserDoesNotParse('start =/*"abcd"');
grammarParserDoesNotParse('start:/*/"abcd"'); grammarParserDoesNotParse('start =/*/"abcd"');
grammarParserDoesNotParse('start:/*/**/*/"abcd"'); grammarParserDoesNotParse('start =/*/**/*/"abcd"');
}); });
/* Canonical eol is "\n". */ /* Canonical eol is "\n". */
test("parses eol", function() { test("parses eol", function() {
grammarParserParses('start:\n"abcd"', simpleGrammar); grammarParserParses('start =\n"abcd"', simpleGrammar);
grammarParserParses('start:\r\n"abcd"', simpleGrammar); grammarParserParses('start =\r\n"abcd"', simpleGrammar);
grammarParserParses('start:\r"abcd"', simpleGrammar); grammarParserParses('start =\r"abcd"', simpleGrammar);
grammarParserParses('start:\u2028"abcd"', simpleGrammar); grammarParserParses('start =\u2028"abcd"', simpleGrammar);
grammarParserParses('start:\u2029"abcd"', simpleGrammar); grammarParserParses('start =\u2029"abcd"', simpleGrammar);
}); });
/* Canonical eolChar is "\n". */ /* Canonical eolChar is "\n". */
test("parses eolChar", function() { test("parses eolChar", function() {
grammarParserParses('start:\n"abcd"', simpleGrammar); grammarParserParses('start =\n"abcd"', simpleGrammar);
grammarParserParses('start:\r"abcd"', simpleGrammar); grammarParserParses('start =\r"abcd"', simpleGrammar);
grammarParserParses('start:\u2028"abcd"', simpleGrammar); grammarParserParses('start =\u2028"abcd"', simpleGrammar);
grammarParserParses('start:\u2029"abcd"', simpleGrammar); grammarParserParses('start =\u2029"abcd"', simpleGrammar);
}); });
/* Canonical whitespace is " ". */ /* Canonical whitespace is " ". */
test("parses whitespace", function() { test("parses whitespace", function() {
grammarParserParses('start:\t"abcd"', simpleGrammar); grammarParserParses('start =\t"abcd"', simpleGrammar);
/* IE does not recognize "\v". */ /* IE does not recognize "\v". */
grammarParserParses('start:\x0B"abcd"', simpleGrammar); grammarParserParses('start =\x0B"abcd"', simpleGrammar);
grammarParserParses('start:\f"abcd"', simpleGrammar); grammarParserParses('start =\f"abcd"', simpleGrammar);
grammarParserParses('start: "abcd"', simpleGrammar); grammarParserParses('start = "abcd"', simpleGrammar);
grammarParserParses('start:\u00A0"abcd"', simpleGrammar); grammarParserParses('start =\u00A0"abcd"', simpleGrammar);
grammarParserParses('start:\uFEFF"abcd"', simpleGrammar); grammarParserParses('start =\uFEFF"abcd"', simpleGrammar);
grammarParserParses('start:\u1680"abcd"', simpleGrammar); grammarParserParses('start =\u1680"abcd"', simpleGrammar);
grammarParserParses('start:\u180E"abcd"', simpleGrammar); grammarParserParses('start =\u180E"abcd"', simpleGrammar);
grammarParserParses('start:\u2000"abcd"', simpleGrammar); grammarParserParses('start =\u2000"abcd"', simpleGrammar);
grammarParserParses('start:\u2001"abcd"', simpleGrammar); grammarParserParses('start =\u2001"abcd"', simpleGrammar);
grammarParserParses('start:\u2002"abcd"', simpleGrammar); grammarParserParses('start =\u2002"abcd"', simpleGrammar);
grammarParserParses('start:\u2003"abcd"', simpleGrammar); grammarParserParses('start =\u2003"abcd"', simpleGrammar);
grammarParserParses('start:\u2004"abcd"', simpleGrammar); grammarParserParses('start =\u2004"abcd"', simpleGrammar);
grammarParserParses('start:\u2005"abcd"', simpleGrammar); grammarParserParses('start =\u2005"abcd"', simpleGrammar);
grammarParserParses('start:\u2006"abcd"', simpleGrammar); grammarParserParses('start =\u2006"abcd"', simpleGrammar);
grammarParserParses('start:\u2007"abcd"', simpleGrammar); grammarParserParses('start =\u2007"abcd"', simpleGrammar);
grammarParserParses('start:\u2008"abcd"', simpleGrammar); grammarParserParses('start =\u2008"abcd"', simpleGrammar);
grammarParserParses('start:\u2009"abcd"', simpleGrammar); grammarParserParses('start =\u2009"abcd"', simpleGrammar);
grammarParserParses('start:\u200A"abcd"', simpleGrammar); grammarParserParses('start =\u200A"abcd"', simpleGrammar);
grammarParserParses('start:\u202F"abcd"', simpleGrammar); grammarParserParses('start =\u202F"abcd"', simpleGrammar);
grammarParserParses('start:\u205F"abcd"', simpleGrammar); grammarParserParses('start =\u205F"abcd"', simpleGrammar);
grammarParserParses('start:\u3000"abcd"', simpleGrammar); grammarParserParses('start =\u3000"abcd"', simpleGrammar);
}); });
})(); })();

Loading…
Cancel
Save