Use only "//" comments

See #443.
redux
David Majda 8 years ago
parent 1da6abc458
commit 6294bb5b13

@ -68,14 +68,12 @@ browser:
rm -f $(BROWSER_FILE_DEV) rm -f $(BROWSER_FILE_DEV)
rm -f $(BROWSER_FILE_MIN) rm -f $(BROWSER_FILE_MIN)
echo '/*' >> $(BROWSER_FILE_DEV) echo "// PEG.js $(PEGJS_VERSION)" >> $(BROWSER_FILE_DEV)
echo " * PEG.js $(PEGJS_VERSION)" >> $(BROWSER_FILE_DEV) echo '//' >> $(BROWSER_FILE_DEV)
echo ' *' >> $(BROWSER_FILE_DEV) echo '// http://pegjs.org/' >> $(BROWSER_FILE_DEV)
echo ' * http://pegjs.org/' >> $(BROWSER_FILE_DEV) echo '//' >> $(BROWSER_FILE_DEV)
echo ' *' >> $(BROWSER_FILE_DEV) echo '// Copyright (c) 2010-2016 David Majda' >> $(BROWSER_FILE_DEV)
echo ' * Copyright (c) 2010-2016 David Majda' >> $(BROWSER_FILE_DEV) echo '// Licensed under the MIT license.' >> $(BROWSER_FILE_DEV)
echo ' * Licensed under the MIT license.' >> $(BROWSER_FILE_DEV)
echo ' */' >> $(BROWSER_FILE_DEV)
$(BROWSERIFY) \ $(BROWSERIFY) \
--standalone peg \ --standalone peg \

@ -6,7 +6,7 @@ let Runner = require("./runner.js");
$("#run").click(() => { $("#run").click(() => {
"use strict"; "use strict";
/* Results Table Manipulation */ // Results Table Manipulation
let resultsTable = $("#results-table"); let resultsTable = $("#results-table");
@ -49,18 +49,16 @@ $("#run").click(() => {
); );
} }
/* Main */ // Main
/* // Each input is parsed multiple times and the results are averaged. We
* Each input is parsed multiple times and the results are averaged. We // do this for two reasons:
* do this for two reasons: //
* // 1. To warm up the interpreter (PEG.js-generated parsers will be
* 1. To warm up the interpreter (PEG.js-generated parsers will be // most likely used repeatedly, so it makes sense to measure
* most likely used repeatedly, so it makes sense to measure // performance after warming up).
* performance after warming up). //
* // 2. To minimize random errors.
* 2. To minimize random errors.
*/
let runCount = parseInt($("#run-count").val(), 10); let runCount = parseInt($("#run-count").val(), 10);
let options = { let options = {
@ -84,7 +82,7 @@ $("#run").click(() => {
}, },
testStart: function() { testStart: function() {
/* Nothing to do. */ // Nothing to do.
}, },
testFinish: function(benchmark, test, inputSize, parseTime) { testFinish: function(benchmark, test, inputSize, parseTime) {

@ -10,7 +10,7 @@ let fs = require("fs");
let benchmarks = require("./benchmarks.js"); let benchmarks = require("./benchmarks.js");
let Runner = require("./runner.js"); let Runner = require("./runner.js");
/* Results Table Manipulation */ // Results Table Manipulation
function dup(text, count) { function dup(text, count) {
let result = ""; let result = "";
@ -70,7 +70,7 @@ function writeTableFooter() {
console.log("└─────────────────────────────────────┴───────────┴────────────┴──────────────┘"); console.log("└─────────────────────────────────────┴───────────┴────────────┴──────────────┘");
} }
/* Helpers */ // Helpers
function printHelp() { function printHelp() {
console.log("Usage: run [options]"); console.log("Usage: run [options]");
@ -97,7 +97,7 @@ function abort(message) {
exitFailure(); exitFailure();
} }
/* Arguments */ // Arguments
let args = process.argv.slice(2); // Trim "node" and the script path. let args = process.argv.slice(2); // Trim "node" and the script path.
@ -109,7 +109,7 @@ function nextArg() {
args.shift(); args.shift();
} }
/* Main */ // Main
let runCount = 10; let runCount = 10;
let options = { let options = {
@ -169,7 +169,7 @@ Runner.run(benchmarks, runCount, options, {
}, },
testStart: function() { testStart: function() {
/* Nothing to do. */ // Nothing to do.
}, },
testFinish: function(benchmark, test, inputSize, parseTime) { testFinish: function(benchmark, test, inputSize, parseTime) {

@ -7,7 +7,7 @@ let peg = require("../lib/peg");
let Runner = { let Runner = {
run: function(benchmarks, runCount, options, callbacks) { run: function(benchmarks, runCount, options, callbacks) {
/* Queue */ // Queue
let Q = { let Q = {
functions: [], functions: [],
@ -20,29 +20,25 @@ let Runner = {
if (this.functions.length > 0) { if (this.functions.length > 0) {
this.functions.shift()(); this.functions.shift()();
/* // We can't use |arguments.callee| here because |this| would get
* We can't use |arguments.callee| here because |this| would get // messed-up in that case.
* messed-up in that case.
*/
setTimeout(() => { Q.run(); }, 0); setTimeout(() => { Q.run(); }, 0);
} }
} }
}; };
/* // The benchmark itself is factored out into several functions (some of them
* The benchmark itself is factored out into several functions (some of them // generated), which are enqueued and run one by one using |setTimeout|. We
* generated), which are enqueued and run one by one using |setTimeout|. We // do this for two reasons:
* do this for two reasons: //
* // 1. To avoid bowser mechanism for interrupting long-running scripts to
* 1. To avoid bowser mechanism for interrupting long-running scripts to // kick-in (or at least to not kick-in that often).
* kick-in (or at least to not kick-in that often). //
* // 2. To ensure progressive rendering of results in the browser (some
* 2. To ensure progressive rendering of results in the browser (some // browsers do not render at all when running JavaScript code).
* browsers do not render at all when running JavaScript code). //
* // The enqueued functions share state, which is all stored in the properties
* The enqueued functions share state, which is all stored in the properties // of the |state| object.
* of the |state| object.
*/
let state = {}; let state = {};
@ -104,7 +100,7 @@ let Runner = {
callbacks.finish(state.totalInputSize, state.totalParseTime); callbacks.finish(state.totalInputSize, state.totalParseTime);
} }
/* Main */ // Main
Q.add(initialize); Q.add(initialize);
benchmarks.forEach(benchmark => { benchmarks.forEach(benchmark => {

@ -5,11 +5,9 @@
"use strict"; "use strict";
/* // Small server whose main purpose is to ensure that both the benchmarked code
* Small server whose main purpose is to ensure that both the benchmarked code // and the benchmark get passed through Babel & Browserify before they are
* and the benchmark get passed through Babel & Browserify before they are // served to the browser.
* served to the browser.
*/
let express = require("express"); let express = require("express");
let logger = require("morgan"); let logger = require("morgan");

@ -6,7 +6,7 @@ let fs = require("fs");
let path = require("path"); let path = require("path");
let peg = require("../lib/peg"); let peg = require("../lib/peg");
/* Helpers */ // Helpers
function printVersion() { function printVersion() {
console.log("PEG.js " + peg.VERSION); console.log("PEG.js " + peg.VERSION);
@ -74,15 +74,13 @@ function addExtraOptions(options, json) {
}); });
} }
/* // Extracted into a function just to silence JSHint complaining about creating
* Extracted into a function just to silence JSHint complaining about creating // functions in a loop.
* functions in a loop.
*/
function trim(s) { function trim(s) {
return s.trim(); return s.trim();
} }
/* Arguments */ // Arguments
let args = process.argv.slice(2); // Trim "node" and the script path. let args = process.argv.slice(2); // Trim "node" and the script path.
@ -94,7 +92,7 @@ function nextArg() {
args.shift(); args.shift();
} }
/* Files */ // Files
function readStream(inputStream, callback) { function readStream(inputStream, callback) {
let input = ""; let input = "";
@ -102,7 +100,7 @@ function readStream(inputStream, callback) {
inputStream.on("end", () => { callback(input); }); inputStream.on("end", () => { callback(input); });
} }
/* Main */ // Main
let inputFile = null; let inputFile = null;
let outputFile = null; let outputFile = null;

@ -1,9 +1,7 @@
/* // Simple Arithmetics Grammar
* Simple Arithmetics Grammar // ==========================
* ========================== //
* // Accepts expressions like "2 * (3 + 4)" and computes their value.
* Accepts expressions like "2 * (3 + 4)" and computes their value.
*/
Expression Expression
= head:Term tail:(_ ("+" / "-") _ Term)* { = head:Term tail:(_ ("+" / "-") _ Term)* {

@ -1,23 +1,21 @@
/* // CSS Grammar
* CSS Grammar // ===========
* =========== //
* // Based on grammar from CSS 2.1 specification [1] (including the errata [2]).
* Based on grammar from CSS 2.1 specification [1] (including the errata [2]). // Generated parser builds a syntax tree composed of nested JavaScript objects,
* Generated parser builds a syntax tree composed of nested JavaScript objects, // vaguely inspired by CSS DOM [3]. The CSS DOM itself wasn't used as it is not
* vaguely inspired by CSS DOM [3]. The CSS DOM itself wasn't used as it is not // expressive enough (e.g. selectors are reflected as text, not structured
* expressive enough (e.g. selectors are reflected as text, not structured // objects) and somewhat cumbersome.
* objects) and somewhat cumbersome. //
* // Limitations:
* Limitations: //
* // * Many errors which should be recovered from according to the specification
* * Many errors which should be recovered from according to the specification // (e.g. malformed declarations or unexpected end of stylesheet) are fatal.
* (e.g. malformed declarations or unexpected end of stylesheet) are fatal. // This is a result of straightforward rewrite of the CSS grammar to PEG.js.
* This is a result of straightforward rewrite of the CSS grammar to PEG.js. //
* // [1] http://www.w3.org/TR/2011/REC-CSS2-20110607
* [1] http://www.w3.org/TR/2011/REC-CSS2-20110607 // [2] http://www.w3.org/Style/css2-updates/REC-CSS2-20110607-errata.html
* [2] http://www.w3.org/Style/css2-updates/REC-CSS2-20110607-errata.html // [3] http://www.w3.org/TR/DOM-Level-2-Style/css.html
* [3] http://www.w3.org/TR/DOM-Level-2-Style/css.html
*/
{ {
function extractOptional(optional, index) { function extractOptional(optional, index) {
@ -49,7 +47,7 @@
start start
= stylesheet:stylesheet comment* { return stylesheet; } = stylesheet:stylesheet comment* { return stylesheet; }
/* ----- G.1 Grammar ----- */ // ----- G.1 Grammar -----
stylesheet stylesheet
= charset:(CHARSET_SYM STRING ";")? (S / CDO / CDC)* = charset:(CHARSET_SYM STRING ";")? (S / CDO / CDC)*
@ -244,9 +242,9 @@ function
hexcolor hexcolor
= value:HASH S* { return { type: "Hexcolor", value: value }; } = value:HASH S* { return { type: "Hexcolor", value: value }; }
/* ----- G.2 Lexical scanner ----- */ // ----- G.2 Lexical scanner -----
/* Macros */ // Macros
h h
= [0-9a-f]i = [0-9a-f]i
@ -338,7 +336,7 @@ U = "u"i / "\\" "0"? "0"? "0"? "0"? [\x55\x75] ("\r\n" / [ \t\r\n\f])? / "\\u"i
X = "x"i / "\\" "0"? "0"? "0"? "0"? [\x58\x78] ("\r\n" / [ \t\r\n\f])? / "\\x"i { return "x"; } X = "x"i / "\\" "0"? "0"? "0"? "0"? [\x58\x78] ("\r\n" / [ \t\r\n\f])? / "\\x"i { return "x"; }
Z = "z"i / "\\" "0"? "0"? "0"? "0"? [\x5a\x7a] ("\r\n" / [ \t\r\n\f])? / "\\z"i { return "z"; } Z = "z"i / "\\" "0"? "0"? "0"? "0"? [\x5a\x7a] ("\r\n" / [ \t\r\n\f])? / "\\z"i { return "z"; }
/* Tokens */ // Tokens
S "whitespace" S "whitespace"
= comment* s = comment* s
@ -376,7 +374,7 @@ MEDIA_SYM "@media"
CHARSET_SYM "@charset" CHARSET_SYM "@charset"
= comment* "@charset " = comment* "@charset "
/* We use |s| instead of |w| here to avoid infinite recursion. */ // We use |s| instead of |w| here to avoid infinite recursion.
IMPORTANT_SYM "!important" IMPORTANT_SYM "!important"
= comment* "!" (s / comment)* I M P O R T A N T = comment* "!" (s / comment)* I M P O R T A N T

@ -1,36 +1,34 @@
/* // JavaScript Grammar
* JavaScript Grammar // ==================
* ================== //
* // Based on grammar from ECMA-262, 5.1 Edition [1]. Generated parser builds a
* Based on grammar from ECMA-262, 5.1 Edition [1]. Generated parser builds a // syntax tree compatible with the ESTree spec [2].
* syntax tree compatible with the ESTree spec [2]. //
* // Limitations:
* Limitations: //
* // * Non-BMP characters are completely ignored to avoid surrogate pair
* * Non-BMP characters are completely ignored to avoid surrogate pair // handling.
* handling. //
* // * One can create identifiers containing illegal characters using Unicode
* * One can create identifiers containing illegal characters using Unicode // escape sequences. For example, "abcd\u0020efgh" is not a valid
* escape sequences. For example, "abcd\u0020efgh" is not a valid // identifier, but it is accepted by the parser.
* identifier, but it is accepted by the parser. //
* // * Strict mode is not recognized. This means that within strict mode code,
* * Strict mode is not recognized. This means that within strict mode code, // "implements", "interface", "let", "package", "private", "protected",
* "implements", "interface", "let", "package", "private", "protected", // "public", "static" and "yield" can be used as names. Many other
* "public", "static" and "yield" can be used as names. Many other // restrictions and exceptions from Annex C are also not applied.
* restrictions and exceptions from Annex C are also not applied. //
* // All the limitations could be resolved, but the costs would likely outweigh
* All the limitations could be resolved, but the costs would likely outweigh // the benefits.
* the benefits. //
* // Many thanks to inimino [3] for his grammar [4] which helped me to solve some
* Many thanks to inimino [3] for his grammar [4] which helped me to solve some // problems (such as automatic semicolon insertion) and also served to double
* problems (such as automatic semicolon insertion) and also served to double // check that I converted the original grammar correctly.
* check that I converted the original grammar correctly. //
* // [1] http://www.ecma-international.org/publications/standards/Ecma-262.htm
* [1] http://www.ecma-international.org/publications/standards/Ecma-262.htm // [2] https://github.com/estree/estree
* [2] https://github.com/estree/estree // [3] http://inimino.org/~inimino/blog/
* [3] http://inimino.org/~inimino/blog/ // [4] http://boshi.inimino.org/3box/asof/1270029991384/PEG/ECMAScript_unified.peg
* [4] http://boshi.inimino.org/3box/asof/1270029991384/PEG/ECMAScript_unified.peg
*/
{ {
var TYPES_TO_PROPERTY_NAMES = { var TYPES_TO_PROPERTY_NAMES = {
@ -85,7 +83,7 @@
Start Start
= __ program:Program __ { return program; } = __ program:Program __ { return program; }
/* ----- A.1 Lexical Grammar ----- */ // ----- A.1 Lexical Grammar -----
SourceCharacter SourceCharacter
= . = .
@ -222,10 +220,8 @@ BooleanLiteral
= TrueToken { return { type: "Literal", value: true }; } = TrueToken { return { type: "Literal", value: true }; }
/ FalseToken { return { type: "Literal", value: false }; } / FalseToken { return { type: "Literal", value: false }; }
/* // The "!(IdentifierStart / DecimalDigit)" predicate is not part of the official
* The "!(IdentifierStart / DecimalDigit)" predicate is not part of the official // grammar, it comes from text in section 7.8.3.
* grammar, it comes from text in section 7.8.3.
*/
NumericLiteral "number" NumericLiteral "number"
= literal:HexIntegerLiteral !(IdentifierStart / DecimalDigit) { = literal:HexIntegerLiteral !(IdentifierStart / DecimalDigit) {
return literal; return literal;
@ -375,30 +371,28 @@ RegularExpressionClassChar
RegularExpressionFlags RegularExpressionFlags
= IdentifierPart* = IdentifierPart*
/* // Unicode Character Categories
* Unicode Character Categories //
* // Extracted from the following Unicode Character Database file:
* Extracted from the following Unicode Character Database file: //
* // http://www.unicode.org/Public/8.0.0/ucd/extracted/DerivedGeneralCategory.txt
* http://www.unicode.org/Public/8.0.0/ucd/extracted/DerivedGeneralCategory.txt //
* // Unix magic used:
* Unix magic used: //
* // grep "; $CATEGORY" DerivedGeneralCategory.txt | # Filter characters
* grep "; $CATEGORY" DerivedGeneralCategory.txt | # Filter characters // cut -f1 -d " " | # Extract code points
* cut -f1 -d " " | # Extract code points // grep -v '[0-9a-fA-F]\{5\}' | # Exclude non-BMP characters
* grep -v '[0-9a-fA-F]\{5\}' | # Exclude non-BMP characters // sed -e 's/\.\./-/' | # Adjust formatting
* sed -e 's/\.\./-/' | # Adjust formatting // sed -e 's/\([0-9a-fA-F]\{4\}\)/\\u\1/g' | # Adjust formatting
* sed -e 's/\([0-9a-fA-F]\{4\}\)/\\u\1/g' | # Adjust formatting // tr -d '\n' # Join lines
* tr -d '\n' # Join lines //
* // ECMA-262 allows using Unicode 3.0 or later, version 8.0.0 was the latest one
* ECMA-262 allows using Unicode 3.0 or later, version 8.0.0 was the latest one // at the time of writing.
* at the time of writing. //
* // Non-BMP characters are completely ignored to avoid surrogate pair handling
* Non-BMP characters are completely ignored to avoid surrogate pair handling // (detecting surrogate pairs isn't possible with a simple character class and
* (detecting surrogate pairs isn't possible with a simple character class and // other methods would degrade performance). I don't consider it a big deal as
* other methods would degrade performance). I don't consider it a big deal as // even parsers in JavaScript engines of common browsers seem to ignore them.
* even parsers in JavaScript engines of common browsers seem to ignore them.
*/
// Letter, Lowercase // Letter, Lowercase
Ll = [\u0061-\u007A\u00B5\u00DF-\u00F6\u00F8-\u00FF\u0101\u0103\u0105\u0107\u0109\u010B\u010D\u010F\u0111\u0113\u0115\u0117\u0119\u011B\u011D\u011F\u0121\u0123\u0125\u0127\u0129\u012B\u012D\u012F\u0131\u0133\u0135\u0137-\u0138\u013A\u013C\u013E\u0140\u0142\u0144\u0146\u0148-\u0149\u014B\u014D\u014F\u0151\u0153\u0155\u0157\u0159\u015B\u015D\u015F\u0161\u0163\u0165\u0167\u0169\u016B\u016D\u016F\u0171\u0173\u0175\u0177\u017A\u017C\u017E-\u0180\u0183\u0185\u0188\u018C-\u018D\u0192\u0195\u0199-\u019B\u019E\u01A1\u01A3\u01A5\u01A8\u01AA-\u01AB\u01AD\u01B0\u01B4\u01B6\u01B9-\u01BA\u01BD-\u01BF\u01C6\u01C9\u01CC\u01CE\u01D0\u01D2\u01D4\u01D6\u01D8\u01DA\u01DC-\u01DD\u01DF\u01E1\u01E3\u01E5\u01E7\u01E9\u01EB\u01ED\u01EF-\u01F0\u01F3\u01F5\u01F9\u01FB\u01FD\u01FF\u0201\u0203\u0205\u0207\u0209\u020B\u020D\u020F\u0211\u0213\u0215\u0217\u0219\u021B\u021D\u021F\u0221\u0223\u0225\u0227\u0229\u022B\u022D\u022F\u0231\u0233-\u0239\u023C\u023F-\u0240\u0242\u0247\u0249\u024B\u024D\u024F-\u0293\u0295-\u02AF\u0371\u0373\u0377\u037B-\u037D\u0390\u03AC-\u03CE\u03D0-\u03D1\u03D5-\u03D7\u03D9\u03DB\u03DD\u03DF\u03E1\u03E3\u03E5\u03E7\u03E9\u03EB\u03ED\u03EF-\u03F3\u03F5\u03F8\u03FB-\u03FC\u0430-\u045F\u0461\u0463\u0465\u0467\u0469\u046B\u046D\u046F\u0471\u0473\u0475\u0477\u0479\u047B\u047D\u047F\u0481\u048B\u048D\u048F\u0491\u0493\u0495\u0497\u0499\u049B\u049D\u049F\u04A1\u04A3\u04A5\u04A7\u04A9\u04AB\u04AD\u04AF\u04B1\u04B3\u04B5\u04B7\u04B9\u04BB\u04BD\u04BF\u04C2\u04C4\u04C6\u04C8\u04CA\u04CC\u04CE-\u04CF\u04D1\u04D3\u04D5\u04D7\u04D9\u04DB\u04DD\u04DF\u04E1\u04E3\u04E5\u04E7\u04E9\u04EB\u04ED\u04EF\u04F1\u04F3\u04F5\u04F7\u04F9\u04FB\u04FD\u04FF\u0501\u0503\u0505\u0507\u0509\u050B\u050D\u050F\u0511\u0513\u0515\u0517\u0519\u051B\u051D\u051F\u0521\u0523\u0525\u0527\u0529\u052B\u052D\u052F\u0561-\u0587\u13F8-\u13FD\u1D00-\u1D2B\u1D6B-\u1D77\u1D79-\u1D9A\u1E01\u1E03\u1E05\u1E07\u1E09\u1E0B\u1E0D\u1E0F\u1E11\u1E13\u1E15\u1E17\u1E19\u1E1B\u1E1D\u1E1F\u1E21\u1E23\u1E25\u1E27\u1E29\u1E2B\u1E2D\u1E2F\u1E31\u1E33\u1E35\u1E37\u1E39\u1E3B\u1E3D\u1E3F\u1E41\u1E43\u1E45\u1E47\u1E49\u1E4B\u1E4D\u1E4F\u1E51\u1E53\u1E55\u1E57\u1E59\u1E5B\u1E5D\u1E5F\u1E61\u1E63\u1E65\u1E67\u1E69\u1E6B\u1E6D\u1E6F\u1E71\u1E73\u1E75\u1E77\u1E79\u1E7B\u1E7D\u1E7F\u1E81\u1E83\u1E85\u1E87\u1E89\u1E8B\u1E8D\u1E8F\u1E91\u1E93\u1E95-\u1E9D\u1E9F\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9\u1EFB\u1EFD\u1EFF-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB0-\u1FB4\u1FB6-\u1FB7\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FC7\u1FD0-\u1FD3\u1FD6-\u1FD7\u1FE0-\u1FE7\u1FF2-\u1FF4\u1FF6-\u1FF7\u210A\u210E-\u210F\u2113\u212F\u2134\u2139\u213C-\u213D\u2146-\u2149\u214E\u2184\u2C30-\u2C5E\u2C61\u2C65-\u2C66\u2C68\u2C6A\u2C6C\u2C71\u2C73-\u2C74\u2C76-\u2C7B\u2C81\u2C83\u2C85\u2C87\u2C89\u2C8B\u2C8D\u2C8F\u2C91\u2C93\u2C95\u2C97\u2C99\u2C9B\u2C9D\u2C9F\u2CA1\u2CA3\u2CA5\u2CA7\u2CA9\u2CAB\u2CAD\u2CAF\u2CB1\u2CB3\u2CB5\u2CB7\u2CB9\u2CBB\u2CBD\u2CBF\u2CC1\u2CC3\u2CC5\u2CC7\u2CC9\u2CCB\u2CCD\u2CCF\u2CD1\u2CD3\u2CD5\u2CD7\u2CD9\u2CDB\u2CDD\u2CDF\u2CE1\u2CE3-\u2CE4\u2CEC\u2CEE\u2CF3\u2D00-\u2D25\u2D27\u2D2D\uA641\uA643\uA645\uA647\uA649\uA64B\uA64D\uA64F\uA651\uA653\uA655\uA657\uA659\uA65B\uA65D\uA65F\uA661\uA663\uA665\uA667\uA669\uA66B\uA66D\uA681\uA683\uA685\uA687\uA689\uA68B\uA68D\uA68F\uA691\uA693\uA695\uA697\uA699\uA69B\uA723\uA725\uA727\uA729\uA72B\uA72D\uA72F-\uA731\uA733\uA735\uA737\uA739\uA73B\uA73D\uA73F\uA741\uA743\uA745\uA747\uA749\uA74B\uA74D\uA74F\uA751\uA753\uA755\uA757\uA759\uA75B\uA75D\uA75F\uA761\uA763\uA765\uA767\uA769\uA76B\uA76D\uA76F\uA771-\uA778\uA77A\uA77C\uA77F\uA781\uA783\uA785\uA787\uA78C\uA78E\uA791\uA793-\uA795\uA797\uA799\uA79B\uA79D\uA79F\uA7A1\uA7A3\uA7A5\uA7A7\uA7A9\uA7B5\uA7B7\uA7FA\uAB30-\uAB5A\uAB60-\uAB65\uAB70-\uABBF\uFB00-\uFB06\uFB13-\uFB17\uFF41-\uFF5A] Ll = [\u0061-\u007A\u00B5\u00DF-\u00F6\u00F8-\u00FF\u0101\u0103\u0105\u0107\u0109\u010B\u010D\u010F\u0111\u0113\u0115\u0117\u0119\u011B\u011D\u011F\u0121\u0123\u0125\u0127\u0129\u012B\u012D\u012F\u0131\u0133\u0135\u0137-\u0138\u013A\u013C\u013E\u0140\u0142\u0144\u0146\u0148-\u0149\u014B\u014D\u014F\u0151\u0153\u0155\u0157\u0159\u015B\u015D\u015F\u0161\u0163\u0165\u0167\u0169\u016B\u016D\u016F\u0171\u0173\u0175\u0177\u017A\u017C\u017E-\u0180\u0183\u0185\u0188\u018C-\u018D\u0192\u0195\u0199-\u019B\u019E\u01A1\u01A3\u01A5\u01A8\u01AA-\u01AB\u01AD\u01B0\u01B4\u01B6\u01B9-\u01BA\u01BD-\u01BF\u01C6\u01C9\u01CC\u01CE\u01D0\u01D2\u01D4\u01D6\u01D8\u01DA\u01DC-\u01DD\u01DF\u01E1\u01E3\u01E5\u01E7\u01E9\u01EB\u01ED\u01EF-\u01F0\u01F3\u01F5\u01F9\u01FB\u01FD\u01FF\u0201\u0203\u0205\u0207\u0209\u020B\u020D\u020F\u0211\u0213\u0215\u0217\u0219\u021B\u021D\u021F\u0221\u0223\u0225\u0227\u0229\u022B\u022D\u022F\u0231\u0233-\u0239\u023C\u023F-\u0240\u0242\u0247\u0249\u024B\u024D\u024F-\u0293\u0295-\u02AF\u0371\u0373\u0377\u037B-\u037D\u0390\u03AC-\u03CE\u03D0-\u03D1\u03D5-\u03D7\u03D9\u03DB\u03DD\u03DF\u03E1\u03E3\u03E5\u03E7\u03E9\u03EB\u03ED\u03EF-\u03F3\u03F5\u03F8\u03FB-\u03FC\u0430-\u045F\u0461\u0463\u0465\u0467\u0469\u046B\u046D\u046F\u0471\u0473\u0475\u0477\u0479\u047B\u047D\u047F\u0481\u048B\u048D\u048F\u0491\u0493\u0495\u0497\u0499\u049B\u049D\u049F\u04A1\u04A3\u04A5\u04A7\u04A9\u04AB\u04AD\u04AF\u04B1\u04B3\u04B5\u04B7\u04B9\u04BB\u04BD\u04BF\u04C2\u04C4\u04C6\u04C8\u04CA\u04CC\u04CE-\u04CF\u04D1\u04D3\u04D5\u04D7\u04D9\u04DB\u04DD\u04DF\u04E1\u04E3\u04E5\u04E7\u04E9\u04EB\u04ED\u04EF\u04F1\u04F3\u04F5\u04F7\u04F9\u04FB\u04FD\u04FF\u0501\u0503\u0505\u0507\u0509\u050B\u050D\u050F\u0511\u0513\u0515\u0517\u0519\u051B\u051D\u051F\u0521\u0523\u0525\u0527\u0529\u052B\u052D\u052F\u0561-\u0587\u13F8-\u13FD\u1D00-\u1D2B\u1D6B-\u1D77\u1D79-\u1D9A\u1E01\u1E03\u1E05\u1E07\u1E09\u1E0B\u1E0D\u1E0F\u1E11\u1E13\u1E15\u1E17\u1E19\u1E1B\u1E1D\u1E1F\u1E21\u1E23\u1E25\u1E27\u1E29\u1E2B\u1E2D\u1E2F\u1E31\u1E33\u1E35\u1E37\u1E39\u1E3B\u1E3D\u1E3F\u1E41\u1E43\u1E45\u1E47\u1E49\u1E4B\u1E4D\u1E4F\u1E51\u1E53\u1E55\u1E57\u1E59\u1E5B\u1E5D\u1E5F\u1E61\u1E63\u1E65\u1E67\u1E69\u1E6B\u1E6D\u1E6F\u1E71\u1E73\u1E75\u1E77\u1E79\u1E7B\u1E7D\u1E7F\u1E81\u1E83\u1E85\u1E87\u1E89\u1E8B\u1E8D\u1E8F\u1E91\u1E93\u1E95-\u1E9D\u1E9F\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9\u1EFB\u1EFD\u1EFF-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB0-\u1FB4\u1FB6-\u1FB7\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FC7\u1FD0-\u1FD3\u1FD6-\u1FD7\u1FE0-\u1FE7\u1FF2-\u1FF4\u1FF6-\u1FF7\u210A\u210E-\u210F\u2113\u212F\u2134\u2139\u213C-\u213D\u2146-\u2149\u214E\u2184\u2C30-\u2C5E\u2C61\u2C65-\u2C66\u2C68\u2C6A\u2C6C\u2C71\u2C73-\u2C74\u2C76-\u2C7B\u2C81\u2C83\u2C85\u2C87\u2C89\u2C8B\u2C8D\u2C8F\u2C91\u2C93\u2C95\u2C97\u2C99\u2C9B\u2C9D\u2C9F\u2CA1\u2CA3\u2CA5\u2CA7\u2CA9\u2CAB\u2CAD\u2CAF\u2CB1\u2CB3\u2CB5\u2CB7\u2CB9\u2CBB\u2CBD\u2CBF\u2CC1\u2CC3\u2CC5\u2CC7\u2CC9\u2CCB\u2CCD\u2CCF\u2CD1\u2CD3\u2CD5\u2CD7\u2CD9\u2CDB\u2CDD\u2CDF\u2CE1\u2CE3-\u2CE4\u2CEC\u2CEE\u2CF3\u2D00-\u2D25\u2D27\u2D2D\uA641\uA643\uA645\uA647\uA649\uA64B\uA64D\uA64F\uA651\uA653\uA655\uA657\uA659\uA65B\uA65D\uA65F\uA661\uA663\uA665\uA667\uA669\uA66B\uA66D\uA681\uA683\uA685\uA687\uA689\uA68B\uA68D\uA68F\uA691\uA693\uA695\uA697\uA699\uA69B\uA723\uA725\uA727\uA729\uA72B\uA72D\uA72F-\uA731\uA733\uA735\uA737\uA739\uA73B\uA73D\uA73F\uA741\uA743\uA745\uA747\uA749\uA74B\uA74D\uA74F\uA751\uA753\uA755\uA757\uA759\uA75B\uA75D\uA75F\uA761\uA763\uA765\uA767\uA769\uA76B\uA76D\uA76F\uA771-\uA778\uA77A\uA77C\uA77F\uA781\uA783\uA785\uA787\uA78C\uA78E\uA791\uA793-\uA795\uA797\uA799\uA79B\uA79D\uA79F\uA7A1\uA7A3\uA7A5\uA7A7\uA7A9\uA7B5\uA7B7\uA7FA\uAB30-\uAB5A\uAB60-\uAB65\uAB70-\uABBF\uFB00-\uFB06\uFB13-\uFB17\uFF41-\uFF5A]
@ -433,7 +427,7 @@ Pc = [\u005F\u203F-\u2040\u2054\uFE33-\uFE34\uFE4D-\uFE4F\uFF3F]
// Separator, Space // Separator, Space
Zs = [\u0020\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000] Zs = [\u0020\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]
/* Tokens */ // Tokens
BreakToken = "break" !IdentifierPart BreakToken = "break" !IdentifierPart
CaseToken = "case" !IdentifierPart CaseToken = "case" !IdentifierPart
@ -474,7 +468,7 @@ VoidToken = "void" !IdentifierPart
WhileToken = "while" !IdentifierPart WhileToken = "while" !IdentifierPart
WithToken = "with" !IdentifierPart WithToken = "with" !IdentifierPart
/* Skipped */ // Skipped
__ __
= (WhiteSpace / LineTerminatorSequence / Comment)* = (WhiteSpace / LineTerminatorSequence / Comment)*
@ -482,7 +476,7 @@ __
_ _
= (WhiteSpace / MultiLineCommentNoLineTerminator)* = (WhiteSpace / MultiLineCommentNoLineTerminator)*
/* Automatic Semicolon Insertion */ // Automatic Semicolon Insertion
EOS EOS
= __ ";" = __ ";"
@ -493,11 +487,11 @@ EOS
EOF EOF
= !. = !.
/* ----- A.2 Number Conversions ----- */ // ----- A.2 Number Conversions -----
/* Irrelevant. */ // Irrelevant.
/* ----- A.3 Expressions ----- */ // ----- A.3 Expressions -----
PrimaryExpression PrimaryExpression
= ThisToken { return { type: "ThisExpression" }; } = ThisToken { return { type: "ThisExpression" }; }
@ -962,7 +956,7 @@ ExpressionNoIn
: head; : head;
} }
/* ----- A.4 Statements ----- */ // ----- A.4 Statements -----
Statement Statement
= Block = Block
@ -1274,7 +1268,7 @@ Finally
DebuggerStatement DebuggerStatement
= DebuggerToken EOS { return { type: "DebuggerStatement" }; } = DebuggerToken EOS { return { type: "DebuggerStatement" }; }
/* ----- A.5 Functions and Programs ----- */ // ----- A.5 Functions and Programs -----
FunctionDeclaration FunctionDeclaration
= FunctionToken __ id:Identifier __ = FunctionToken __ id:Identifier __
@ -1332,14 +1326,14 @@ SourceElement
= Statement = Statement
/ FunctionDeclaration / FunctionDeclaration
/* ----- A.6 Universal Resource Identifier Character Classes ----- */ // ----- A.6 Universal Resource Identifier Character Classes -----
/* Irrelevant. */ // Irrelevant.
/* ----- A.7 Regular Expressions ----- */ // ----- A.7 Regular Expressions -----
/* Irrelevant. */ // Irrelevant.
/* ----- A.8 JSON ----- */ // ----- A.8 JSON -----
/* Irrelevant. */ // Irrelevant.

@ -1,21 +1,19 @@
/* // JSON Grammar
* JSON Grammar // ============
* ============ //
* // Based on the grammar from RFC 7159 [1].
* Based on the grammar from RFC 7159 [1]. //
* // Note that JSON is also specified in ECMA-262 [2], ECMA-404 [3], and on the
* Note that JSON is also specified in ECMA-262 [2], ECMA-404 [3], and on the // JSON website [4] (somewhat informally). The RFC seems the most authoritative
* JSON website [4] (somewhat informally). The RFC seems the most authoritative // source, which is confirmed e.g. by [5].
* source, which is confirmed e.g. by [5]. //
* // [1] http://tools.ietf.org/html/rfc7159
* [1] http://tools.ietf.org/html/rfc7159 // [2] http://www.ecma-international.org/publications/standards/Ecma-262.htm
* [2] http://www.ecma-international.org/publications/standards/Ecma-262.htm // [3] http://www.ecma-international.org/publications/standards/Ecma-404.htm
* [3] http://www.ecma-international.org/publications/standards/Ecma-404.htm // [4] http://json.org/
* [4] http://json.org/ // [5] https://www.tbray.org/ongoing/When/201x/2014/03/05/RFC7159-JSON
* [5] https://www.tbray.org/ongoing/When/201x/2014/03/05/RFC7159-JSON
*/ // ----- 2. JSON Grammar -----
/* ----- 2. JSON Grammar ----- */
JSON_text JSON_text
= ws value:value ws { return value; } = ws value:value ws { return value; }
@ -29,7 +27,7 @@ value_separator = ws "," ws
ws "whitespace" = [ \t\n\r]* ws "whitespace" = [ \t\n\r]*
/* ----- 3. Values ----- */ // ----- 3. Values -----
value value
= false = false
@ -44,7 +42,7 @@ false = "false" { return false; }
null = "null" { return null; } null = "null" { return null; }
true = "true" { return true; } true = "true" { return true; }
/* ----- 4. Objects ----- */ // ----- 4. Objects -----
object object
= begin_object = begin_object
@ -69,7 +67,7 @@ member
return { name: name, value: value }; return { name: name, value: value };
} }
/* ----- 5. Arrays ----- */ // ----- 5. Arrays -----
array array
= begin_array = begin_array
@ -81,7 +79,7 @@ array
end_array end_array
{ return values !== null ? values : []; } { return values !== null ? values : []; }
/* ----- 6. Numbers ----- */ // ----- 6. Numbers -----
number "number" number "number"
= minus? int frac? exp? { return parseFloat(text()); } = minus? int frac? exp? { return parseFloat(text()); }
@ -96,7 +94,7 @@ minus = "-"
plus = "+" plus = "+"
zero = "0" zero = "0"
/* ----- 7. Strings ----- */ // ----- 7. Strings -----
string "string" string "string"
= quotation_mark chars:char* quotation_mark { return chars.join(""); } = quotation_mark chars:char* quotation_mark { return chars.join(""); }
@ -123,8 +121,8 @@ escape = "\\"
quotation_mark = '"' quotation_mark = '"'
unescaped = [^\0-\x1F\x22\x5C] unescaped = [^\0-\x1F\x22\x5C]
/* ----- Core ABNF Rules ----- */ // ----- Core ABNF Rules -----
/* See RFC 4234, Appendix B (http://tools.ietf.org/html/rfc4627). */ // See RFC 4234, Appendix B (http://tools.ietf.org/html/rfc4627).
DIGIT = [0-9] DIGIT = [0-9]
HEXDIG = [0-9a-f]i HEXDIG = [0-9a-f]i

@ -2,7 +2,7 @@
let visitor = require("./visitor"); let visitor = require("./visitor");
/* AST utilities. */ // AST utilities.
let asts = { let asts = {
findRule: function(ast, name) { findRule: function(ast, name) {
for (let i = 0; i < ast.rules.length; i++) { for (let i = 0; i < ast.rules.length; i++) {

@ -17,19 +17,15 @@ function processOptions(options, defaults) {
} }
let compiler = { let compiler = {
/* // AST node visitor builder. Useful mainly for plugins which manipulate the
* AST node visitor builder. Useful mainly for plugins which manipulate the // AST.
* AST.
*/
visitor: require("./visitor"), visitor: require("./visitor"),
/* // Compiler passes.
* Compiler passes. //
* // Each pass is a function that is passed the AST. It can perform checks on it
* Each pass is a function that is passed the AST. It can perform checks on it // or modify it as needed. If the pass encounters a semantic error, it throws
* or modify it as needed. If the pass encounters a semantic error, it throws // |peg.GrammarError|.
* |peg.GrammarError|.
*/
passes: { passes: {
check: { check: {
reportUndefinedRules: require("./passes/report-undefined-rules"), reportUndefinedRules: require("./passes/report-undefined-rules"),
@ -47,12 +43,10 @@ let compiler = {
} }
}, },
/* // Generates a parser from a specified grammar AST. Throws |peg.GrammarError|
* Generates a parser from a specified grammar AST. Throws |peg.GrammarError| // if the AST contains a semantic error. Note that not all errors are detected
* if the AST contains a semantic error. Note that not all errors are detected // during the generation and some may protrude to the generated parser and
* during the generation and some may protrude to the generated parser and // cause its malfunction.
* cause its malfunction.
*/
compile: function(ast, passes, options) { compile: function(ast, passes, options) {
options = options !== undefined ? options : {}; options = options !== undefined ? options : {};

@ -2,17 +2,15 @@
function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); } function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }
/* JavaScript code generation helpers. */ // JavaScript code generation helpers.
let js = { let js = {
stringEscape: function(s) { stringEscape: function(s) {
/* // ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a string
* ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a string // literal except for the closing quote character, backslash, carriage
* literal except for the closing quote character, backslash, carriage // return, line separator, paragraph separator, and line feed. Any character
* return, line separator, paragraph separator, and line feed. Any character // may appear in the form of an escape sequence.
* may appear in the form of an escape sequence. //
* // For portability, we also escape all control and non-ASCII characters.
* For portability, we also escape all control and non-ASCII characters.
*/
return s return s
.replace(/\\/g, '\\\\') // backslash .replace(/\\/g, '\\\\') // backslash
.replace(/"/g, '\\"') // closing double quote .replace(/"/g, '\\"') // closing double quote
@ -30,11 +28,9 @@ let js = {
}, },
regexpClassEscape: function(s) { regexpClassEscape: function(s) {
/* // Based on ECMA-262, 5th ed., 7.8.5 & 15.10.1.
* Based on ECMA-262, 5th ed., 7.8.5 & 15.10.1. //
* // For portability, we also escape all control and non-ASCII characters.
* For portability, we also escape all control and non-ASCII characters.
*/
return s return s
.replace(/\\/g, '\\\\') // backslash .replace(/\\/g, '\\\\') // backslash
.replace(/\//g, '\\/') // closing slash .replace(/\//g, '\\/') // closing slash

@ -1,8 +1,8 @@
"use strict"; "use strict";
/* Bytecode instruction opcodes. */ // Bytecode instruction opcodes.
let opcodes = { let opcodes = {
/* Stack Manipulation */ // Stack Manipulation
PUSH: 0, // PUSH c PUSH: 0, // PUSH c
PUSH_UNDEFINED: 1, // PUSH_UNDEFINED PUSH_UNDEFINED: 1, // PUSH_UNDEFINED
@ -18,14 +18,14 @@ let opcodes = {
WRAP: 11, // WRAP n WRAP: 11, // WRAP n
TEXT: 12, // TEXT TEXT: 12, // TEXT
/* Conditions and Loops */ // Conditions and Loops
IF: 13, // IF t, f IF: 13, // IF t, f
IF_ERROR: 14, // IF_ERROR t, f IF_ERROR: 14, // IF_ERROR t, f
IF_NOT_ERROR: 15, // IF_NOT_ERROR t, f IF_NOT_ERROR: 15, // IF_NOT_ERROR t, f
WHILE_NOT_ERROR: 16, // WHILE_NOT_ERROR b WHILE_NOT_ERROR: 16, // WHILE_NOT_ERROR b
/* Matching */ // Matching
MATCH_ANY: 17, // MATCH_ANY a, f, ... MATCH_ANY: 17, // MATCH_ANY a, f, ...
MATCH_STRING: 18, // MATCH_STRING s, a, f, ... MATCH_STRING: 18, // MATCH_STRING s, a, f, ...
@ -35,17 +35,17 @@ let opcodes = {
ACCEPT_STRING: 22, // ACCEPT_STRING s ACCEPT_STRING: 22, // ACCEPT_STRING s
FAIL: 23, // FAIL e FAIL: 23, // FAIL e
/* Calls */ // Calls
LOAD_SAVED_POS: 24, // LOAD_SAVED_POS p LOAD_SAVED_POS: 24, // LOAD_SAVED_POS p
UPDATE_SAVED_POS: 25, // UPDATE_SAVED_POS UPDATE_SAVED_POS: 25, // UPDATE_SAVED_POS
CALL: 26, // CALL f, n, pc, p1, p2, ..., pN CALL: 26, // CALL f, n, pc, p1, p2, ..., pN
/* Rules */ // Rules
RULE: 27, // RULE r RULE: 27, // RULE r
/* Failure Reporting */ // Failure Reporting
SILENT_FAILS_ON: 28, // SILENT_FAILS_ON SILENT_FAILS_ON: 28, // SILENT_FAILS_ON
SILENT_FAILS_OFF: 29 // SILENT_FAILS_OFF SILENT_FAILS_OFF: 29 // SILENT_FAILS_OFF

@ -5,189 +5,188 @@ let visitor = require("../visitor");
let op = require("../opcodes"); let op = require("../opcodes");
let js = require("../js"); let js = require("../js");
/* Generates bytecode. // Generates bytecode.
* //
* Instructions // Instructions
* ============ // ============
* //
* Stack Manipulation // Stack Manipulation
* ------------------ // ------------------
* //
* [0] PUSH c // [0] PUSH c
* //
* stack.push(consts[c]); // stack.push(consts[c]);
* //
* [1] PUSH_UNDEFINED // [1] PUSH_UNDEFINED
* //
* stack.push(undefined); // stack.push(undefined);
* //
* [2] PUSH_NULL // [2] PUSH_NULL
* //
* stack.push(null); // stack.push(null);
* //
* [3] PUSH_FAILED // [3] PUSH_FAILED
* //
* stack.push(FAILED); // stack.push(FAILED);
* //
* [4] PUSH_EMPTY_ARRAY // [4] PUSH_EMPTY_ARRAY
* //
* stack.push([]); // stack.push([]);
* //
* [5] PUSH_CURR_POS // [5] PUSH_CURR_POS
* //
* stack.push(currPos); // stack.push(currPos);
* //
* [6] POP // [6] POP
* //
* stack.pop(); // stack.pop();
* //
* [7] POP_CURR_POS // [7] POP_CURR_POS
* //
* currPos = stack.pop(); // currPos = stack.pop();
* //
* [8] POP_N n // [8] POP_N n
* //
* stack.pop(n); // stack.pop(n);
* //
* [9] NIP // [9] NIP
* //
* value = stack.pop(); // value = stack.pop();
* stack.pop(); // stack.pop();
* stack.push(value); // stack.push(value);
* //
* [10] APPEND // [10] APPEND
* //
* value = stack.pop(); // value = stack.pop();
* array = stack.pop(); // array = stack.pop();
* array.push(value); // array.push(value);
* stack.push(array); // stack.push(array);
* //
* [11] WRAP n // [11] WRAP n
* //
* stack.push(stack.pop(n)); // stack.push(stack.pop(n));
* //
* [12] TEXT // [12] TEXT
* //
* stack.push(input.substring(stack.pop(), currPos)); // stack.push(input.substring(stack.pop(), currPos));
* //
* Conditions and Loops // Conditions and Loops
* -------------------- // --------------------
* //
* [13] IF t, f // [13] IF t, f
* //
* if (stack.top()) { // if (stack.top()) {
* interpret(ip + 3, ip + 3 + t); // interpret(ip + 3, ip + 3 + t);
* } else { // } else {
* interpret(ip + 3 + t, ip + 3 + t + f); // interpret(ip + 3 + t, ip + 3 + t + f);
* } // }
* //
* [14] IF_ERROR t, f // [14] IF_ERROR t, f
* //
* if (stack.top() === FAILED) { // if (stack.top() === FAILED) {
* interpret(ip + 3, ip + 3 + t); // interpret(ip + 3, ip + 3 + t);
* } else { // } else {
* interpret(ip + 3 + t, ip + 3 + t + f); // interpret(ip + 3 + t, ip + 3 + t + f);
* } // }
* //
* [15] IF_NOT_ERROR t, f // [15] IF_NOT_ERROR t, f
* //
* if (stack.top() !== FAILED) { // if (stack.top() !== FAILED) {
* interpret(ip + 3, ip + 3 + t); // interpret(ip + 3, ip + 3 + t);
* } else { // } else {
* interpret(ip + 3 + t, ip + 3 + t + f); // interpret(ip + 3 + t, ip + 3 + t + f);
* } // }
* //
* [16] WHILE_NOT_ERROR b // [16] WHILE_NOT_ERROR b
* //
* while(stack.top() !== FAILED) { // while(stack.top() !== FAILED) {
* interpret(ip + 2, ip + 2 + b); // interpret(ip + 2, ip + 2 + b);
* } // }
* //
* Matching // Matching
* -------- // --------
* //
* [17] MATCH_ANY a, f, ... // [17] MATCH_ANY a, f, ...
* //
* if (input.length > currPos) { // if (input.length > currPos) {
* interpret(ip + 3, ip + 3 + a); // interpret(ip + 3, ip + 3 + a);
* } else { // } else {
* interpret(ip + 3 + a, ip + 3 + a + f); // interpret(ip + 3 + a, ip + 3 + a + f);
* } // }
* //
* [18] MATCH_STRING s, a, f, ... // [18] MATCH_STRING s, a, f, ...
* //
* if (input.substr(currPos, consts[s].length) === consts[s]) { // if (input.substr(currPos, consts[s].length) === consts[s]) {
* interpret(ip + 4, ip + 4 + a); // interpret(ip + 4, ip + 4 + a);
* } else { // } else {
* interpret(ip + 4 + a, ip + 4 + a + f); // interpret(ip + 4 + a, ip + 4 + a + f);
* } // }
* //
* [19] MATCH_STRING_IC s, a, f, ... // [19] MATCH_STRING_IC s, a, f, ...
* //
* if (input.substr(currPos, consts[s].length).toLowerCase() === consts[s]) { // if (input.substr(currPos, consts[s].length).toLowerCase() === consts[s]) {
* interpret(ip + 4, ip + 4 + a); // interpret(ip + 4, ip + 4 + a);
* } else { // } else {
* interpret(ip + 4 + a, ip + 4 + a + f); // interpret(ip + 4 + a, ip + 4 + a + f);
* } // }
* //
* [20] MATCH_REGEXP r, a, f, ... // [20] MATCH_REGEXP r, a, f, ...
* //
* if (consts[r].test(input.charAt(currPos))) { // if (consts[r].test(input.charAt(currPos))) {
* interpret(ip + 4, ip + 4 + a); // interpret(ip + 4, ip + 4 + a);
* } else { // } else {
* interpret(ip + 4 + a, ip + 4 + a + f); // interpret(ip + 4 + a, ip + 4 + a + f);
* } // }
* //
* [21] ACCEPT_N n // [21] ACCEPT_N n
* //
* stack.push(input.substring(currPos, n)); // stack.push(input.substring(currPos, n));
* currPos += n; // currPos += n;
* //
* [22] ACCEPT_STRING s // [22] ACCEPT_STRING s
* //
* stack.push(consts[s]); // stack.push(consts[s]);
* currPos += consts[s].length; // currPos += consts[s].length;
* //
* [23] FAIL e // [23] FAIL e
* //
* stack.push(FAILED); // stack.push(FAILED);
* fail(consts[e]); // fail(consts[e]);
* //
* Calls // Calls
* ----- // -----
* //
* [24] LOAD_SAVED_POS p // [24] LOAD_SAVED_POS p
* //
* savedPos = stack[p]; // savedPos = stack[p];
* //
* [25] UPDATE_SAVED_POS // [25] UPDATE_SAVED_POS
* //
* savedPos = currPos; // savedPos = currPos;
* //
* [26] CALL f, n, pc, p1, p2, ..., pN // [26] CALL f, n, pc, p1, p2, ..., pN
* //
* value = consts[f](stack[p1], ..., stack[pN]); // value = consts[f](stack[p1], ..., stack[pN]);
* stack.pop(n); // stack.pop(n);
* stack.push(value); // stack.push(value);
* //
* Rules // Rules
* ----- // -----
* //
* [27] RULE r // [27] RULE r
* //
* stack.push(parseRule(r)); // stack.push(parseRule(r));
* //
* Failure Reporting // Failure Reporting
* ----------------- // -----------------
* //
* [28] SILENT_FAILS_ON // [28] SILENT_FAILS_ON
* //
* silentFails++; // silentFails++;
* //
* [29] SILENT_FAILS_OFF // [29] SILENT_FAILS_OFF
* //
* silentFails--; // silentFails--;
*/
function generateBytecode(ast) { function generateBytecode(ast) {
let consts = []; let consts = [];
@ -308,12 +307,10 @@ function generateBytecode(ast) {
'peg$otherExpectation("' + js.stringEscape(node.name) + '")' 'peg$otherExpectation("' + js.stringEscape(node.name) + '")'
); );
/* // The code generated below is slightly suboptimal because |FAIL| pushes
* The code generated below is slightly suboptimal because |FAIL| pushes // to the stack, so we need to stick a |POP| in front of it. We lack a
* to the stack, so we need to stick a |POP| in front of it. We lack a // dedicated instruction that would just report the failure and not touch
* dedicated instruction that would just report the failure and not touch // the stack.
* the stack.
*/
return buildSequence( return buildSequence(
[op.SILENT_FAILS_ON], [op.SILENT_FAILS_ON],
generate(node.expression, context), generate(node.expression, context),
@ -551,11 +548,9 @@ function generateBytecode(ast) {
+ ')' + ')'
); );
/* // For case-sensitive strings the value must match the beginning of the
* For case-sensitive strings the value must match the beginning of the // remaining input exactly. As a result, we can use |ACCEPT_STRING| and
* remaining input exactly. As a result, we can use |ACCEPT_STRING| and // save one |substr| call that would be needed if we used |ACCEPT_N|.
* save one |substr| call that would be needed if we used |ACCEPT_N|.
*/
return buildCondition( return buildCondition(
node.ignoreCase node.ignoreCase
? [op.MATCH_STRING_IC, stringIndex] ? [op.MATCH_STRING_IC, stringIndex]

@ -4,9 +4,9 @@ let asts = require("../asts");
let op = require("../opcodes"); let op = require("../opcodes");
let js = require("../js"); let js = require("../js");
/* Generates parser JavaScript code. */ // Generates parser JavaScript code.
function generateJS(ast, options) { function generateJS(ast, options) {
/* These only indent non-empty lines to avoid trailing whitespace. */ // These only indent non-empty lines to avoid trailing whitespace.
function indent2(code) { return code.replace(/^(.+)$/gm, ' $1'); } function indent2(code) { return code.replace(/^(.+)$/gm, ' $1'); }
function indent10(code) { return code.replace(/^(.+)$/gm, ' $1'); } function indent10(code) { return code.replace(/^(.+)$/gm, ' $1'); }
@ -222,13 +222,11 @@ function generateJS(ast, options) {
parts.push(indent2(generateRuleHeader('peg$ruleNames[index]', 'index'))); parts.push(indent2(generateRuleHeader('peg$ruleNames[index]', 'index')));
parts.push([ parts.push([
/* // The point of the outer loop and the |ips| & |ends| stacks is to avoid
* The point of the outer loop and the |ips| & |ends| stacks is to avoid // recursive calls for interpreting parts of bytecode. In other words, we
* recursive calls for interpreting parts of bytecode. In other words, we // implement the |interpret| operation of the abstract machine without
* implement the |interpret| operation of the abstract machine without // function calls. Such calls would likely slow the parser down and more
* function calls. Such calls would likely slow the parser down and more // importantly cause stack overflows for complex grammars.
* importantly cause stack overflows for complex grammars.
*/
' while (true) {', ' while (true) {',
' while (ip < end) {', ' while (ip < end) {',
' switch (bc[ip]) {', ' switch (bc[ip]) {',
@ -1201,11 +1199,9 @@ function generateJS(ast, options) {
function generateWrapper(toplevelCode) { function generateWrapper(toplevelCode) {
function generateGeneratedByComment() { function generateGeneratedByComment() {
return [ return [
'/*', '// Generated by PEG.js 0.10.0.',
' * Generated by PEG.js 0.10.0.', '//',
' *', '// http://pegjs.org/'
' * http://pegjs.org/',
' */'
].join('\n'); ].join('\n');
} }

@ -2,9 +2,7 @@
let visitor = require("../visitor"); let visitor = require("../visitor");
/* // Removes proxy rules -- that is, rules that only delegate to other rule.
* Removes proxy rules -- that is, rules that only delegate to other rule.
*/
function removeProxyRules(ast, options) { function removeProxyRules(ast, options) {
function isProxyRule(node) { function isProxyRule(node) {
return node.type === "rule" && node.expression.type === "rule_ref"; return node.type === "rule" && node.expression.type === "rule_ref";

@ -3,7 +3,7 @@
let GrammarError = require("../../grammar-error"); let GrammarError = require("../../grammar-error");
let visitor = require("../visitor"); let visitor = require("../visitor");
/* Checks that each label is defined only once within each scope. */ // Checks that each label is defined only once within each scope.
function reportDuplicateLabels(ast) { function reportDuplicateLabels(ast) {
function cloneEnv(env) { function cloneEnv(env) {
let clone = {}; let clone = {};

@ -3,7 +3,7 @@
let GrammarError = require("../../grammar-error"); let GrammarError = require("../../grammar-error");
let visitor = require("../visitor"); let visitor = require("../visitor");
/* Checks that each rule is defined only once. */ // Checks that each rule is defined only once.
function reportDuplicateRules(ast) { function reportDuplicateRules(ast) {
let rules = {}; let rules = {};

@ -4,18 +4,16 @@ let GrammarError = require("../../grammar-error");
let asts = require("../asts"); let asts = require("../asts");
let visitor = require("../visitor"); let visitor = require("../visitor");
/* // Reports left recursion in the grammar, which prevents infinite recursion in
* Reports left recursion in the grammar, which prevents infinite recursion in // the generated parser.
* the generated parser. //
* // Both direct and indirect recursion is detected. The pass also correctly
* Both direct and indirect recursion is detected. The pass also correctly // reports cases like this:
* reports cases like this: //
* // start = "a"? start
* start = "a"? start //
* // In general, if a rule reference can be reached without consuming any input,
* In general, if a rule reference can be reached without consuming any input, // it can lead to left recursion.
* it can lead to left recursion.
*/
function reportInfiniteRecursion(ast) { function reportInfiniteRecursion(ast) {
let visitedRules = []; let visitedRules = [];

@ -4,10 +4,8 @@ let GrammarError = require("../../grammar-error");
let asts = require("../asts"); let asts = require("../asts");
let visitor = require("../visitor"); let visitor = require("../visitor");
/* // Reports expressions that don't consume any input inside |*| or |+| in the
* Reports expressions that don't consume any input inside |*| or |+| in the // grammar, which prevents infinite loops in the generated parser.
* grammar, which prevents infinite loops in the generated parser.
*/
function reportInfiniteRepetition(ast) { function reportInfiniteRepetition(ast) {
let check = visitor.build({ let check = visitor.build({
zero_or_more: function(node) { zero_or_more: function(node) {

@ -4,7 +4,7 @@ let GrammarError = require("../../grammar-error");
let asts = require("../asts"); let asts = require("../asts");
let visitor = require("../visitor"); let visitor = require("../visitor");
/* Checks that all referenced rules exist. */ // Checks that all referenced rules exist.
function reportUndefinedRules(ast) { function reportUndefinedRules(ast) {
let check = visitor.build({ let check = visitor.build({
rule_ref: function(node) { rule_ref: function(node) {

@ -1,6 +1,6 @@
"use strict"; "use strict";
/* Simple AST node visitor builder. */ // Simple AST node visitor builder.
let visitor = { let visitor = {
build: function(functions) { build: function(functions) {
function visit(node) { function visit(node) {

@ -1,6 +1,6 @@
"use strict"; "use strict";
/* Thrown when the grammar contains an error. */ // Thrown when the grammar contains an error.
class GrammarError { class GrammarError {
constructor(message, location) { constructor(message, location) {
this.name = "GrammarError"; this.name = "GrammarError";

@ -1,11 +1,9 @@
/* eslint-env node, amd */ /* eslint-env node, amd */
/* eslint no-unused-vars: 0 */ /* eslint no-unused-vars: 0 */
/* // Generated by PEG.js 0.10.0.
* Generated by PEG.js 0.10.0. //
* // http://pegjs.org/
* http://pegjs.org/
*/
"use strict"; "use strict";
@ -236,12 +234,10 @@ function peg$parse(input, options) {
var peg$c29 = ")"; var peg$c29 = ")";
var peg$c30 = peg$literalExpectation(")", false); var peg$c30 = peg$literalExpectation(")", false);
var peg$c31 = function(expression) { var peg$c31 = function(expression) {
/* // The purpose of the "group" AST node is just to isolate label scope. We
* The purpose of the "group" AST node is just to isolate label scope. We // don't need to put it around nodes that can't contain any labels or
* don't need to put it around nodes that can't contain any labels or // nodes that already isolate label scope themselves. This leaves us with
* nodes that already isolate label scope themselves. This leaves us with // "labeled" and "sequence".
* "labeled" and "sequence".
*/
return expression.type === 'labeled' || expression.type === 'sequence' return expression.type === 'labeled' || expression.type === 'sequence'
? { type: "group", expression: expression } ? { type: "group", expression: expression }
: expression; : expression;

@ -1,24 +1,22 @@
"use strict"; "use strict";
let peg = { let peg = {
/* PEG.js version (uses semantic versioning). */ // PEG.js version (uses semantic versioning).
VERSION: "0.10.0", VERSION: "0.10.0",
GrammarError: require("./grammar-error"), GrammarError: require("./grammar-error"),
parser: require("./parser"), parser: require("./parser"),
compiler: require("./compiler"), compiler: require("./compiler"),
/* // Generates a parser from a specified grammar and returns it.
* Generates a parser from a specified grammar and returns it. //
* // The grammar must be a string in the format described by the metagramar in
* The grammar must be a string in the format described by the metagramar in // the parser.pegjs file.
* the parser.pegjs file. //
* // Throws |peg.parser.SyntaxError| if the grammar contains a syntax error or
* Throws |peg.parser.SyntaxError| if the grammar contains a syntax error or // |peg.GrammarError| if it contains a semantic error. Note that not all
* |peg.GrammarError| if it contains a semantic error. Note that not all // errors are detected during the generation and some may protrude to the
* errors are detected during the generation and some may protrude to the // generated parser and cause its malfunction.
* generated parser and cause its malfunction.
*/
generate: function(grammar, options) { generate: function(grammar, options) {
options = options !== undefined ? options : {}; options = options !== undefined ? options : {};

@ -26,10 +26,8 @@ describe("PEG.js API", function() {
'c = "x"' 'c = "x"'
].join("\n"); ].join("\n");
/* // The |allowedStartRules| option is implemented separately for each
* The |allowedStartRules| option is implemented separately for each // optimization mode, so we need to test it in both.
* optimization mode, so we need to test it in both.
*/
describe("when optimizing for parsing speed", function() { describe("when optimizing for parsing speed", function() {
describe("when |allowedStartRules| is not set", function() { describe("when |allowedStartRules| is not set", function() {
@ -151,10 +149,8 @@ describe("PEG.js API", function() {
}); });
}); });
/* // The |optimize| option isn't tested because there is no meaningful way to
* The |optimize| option isn't tested because there is no meaningful way to // write the specs without turning this into a performance test.
* write the specs without turning this into a performance test.
*/
describe("output", function() { describe("output", function() {
let grammar = 'start = "a"'; let grammar = 'start = "a"';
@ -187,13 +183,11 @@ describe("PEG.js API", function() {
}); });
}); });
/* // The |format|, |exportVars|, and |dependencies| options are not tested
* The |format|, |exportVars|, and |dependencies| options are not tested // becasue there is no meaningful way to thest their effects without turning
* becasue there is no meaningful way to thest their effects without turning // this into an integration test.
* this into an integration test.
*/
/* The |plugins| option is tested in plugin API specs. */ // The |plugins| option is tested in plugin API specs.
it("accepts custom options", function() { it("accepts custom options", function() {
peg.generate('start = "a"', { foo: 42 }); peg.generate('start = "a"', { foo: 42 });

@ -120,10 +120,8 @@ describe("generated parser behavior", function() {
} }
}); });
/* // Stub out |console.log| so that the default tracer doesn't clutter
* Stub out |console.log| so that the default tracer doesn't clutter // test output.
* test output.
*/
if (typeof console === "object") { if (typeof console === "object") {
spyOn(console, "log"); spyOn(console, "log");
} }
@ -412,11 +410,9 @@ describe("generated parser behavior", function() {
describe("positive semantic predicate", function() { describe("positive semantic predicate", function() {
describe("when the code returns a truthy value", function() { describe("when the code returns a truthy value", function() {
it("returns |undefined|", function() { it("returns |undefined|", function() {
/* // The |""| is needed so that the parser doesn't return just
* The |""| is needed so that the parser doesn't return just // |undefined| which we can't compare against in |toParse| due to the
* |undefined| which we can't compare against in |toParse| due to the // way optional parameters work.
* way optional parameters work.
*/
let parser = peg.generate('start = &{ return true; } ""', options); let parser = peg.generate('start = &{ return true; } ""', options);
expect(parser).toParse("", [undefined, ""]); expect(parser).toParse("", [undefined, ""]);
@ -592,7 +588,7 @@ describe("generated parser behavior", function() {
end: { offset: 13, line: 7, column: 5 } end: { offset: 13, line: 7, column: 5 }
}); });
/* Newline representations */ // Newline representations
expect(parser).toParse("1\nx", { // Unix expect(parser).toParse("1\nx", { // Unix
start: { offset: 2, line: 2, column: 1 }, start: { offset: 2, line: 2, column: 1 },
end: { offset: 2, line: 2, column: 1 } end: { offset: 2, line: 2, column: 1 }
@ -608,11 +604,9 @@ describe("generated parser behavior", function() {
describe("negative semantic predicate", function() { describe("negative semantic predicate", function() {
describe("when the code returns a falsey value", function() { describe("when the code returns a falsey value", function() {
it("returns |undefined|", function() { it("returns |undefined|", function() {
/* // The |""| is needed so that the parser doesn't return just
* The |""| is needed so that the parser doesn't return just // |undefined| which we can't compare against in |toParse| due to the
* |undefined| which we can't compare against in |toParse| due to the // way optional parameters work.
* way optional parameters work.
*/
let parser = peg.generate('start = !{ return false; } ""', options); let parser = peg.generate('start = !{ return false; } ""', options);
expect(parser).toParse("", [undefined, ""]); expect(parser).toParse("", [undefined, ""]);
@ -788,7 +782,7 @@ describe("generated parser behavior", function() {
end: { offset: 13, line: 7, column: 5 } end: { offset: 13, line: 7, column: 5 }
}); });
/* Newline representations */ // Newline representations
expect(parser).toParse("1\nx", { // Unix expect(parser).toParse("1\nx", { // Unix
start: { offset: 2, line: 2, column: 1 }, start: { offset: 2, line: 2, column: 1 },
end: { offset: 2, line: 2, column: 1 } end: { offset: 2, line: 2, column: 1 }
@ -1166,7 +1160,7 @@ describe("generated parser behavior", function() {
end: { offset: 14, line: 7, column: 6 } end: { offset: 14, line: 7, column: 6 }
}); });
/* Newline representations */ // Newline representations
expect(parser).toParse("1\nx", { // Unix expect(parser).toParse("1\nx", { // Unix
start: { offset: 2, line: 2, column: 1 }, start: { offset: 2, line: 2, column: 1 },
end: { offset: 3, line: 2, column: 2 } end: { offset: 3, line: 2, column: 2 }
@ -1460,7 +1454,7 @@ describe("generated parser behavior", function() {
} }
}); });
/* Newline representations */ // Newline representations
expect(parser).toFailToParse("1\nx", { // Old Mac expect(parser).toFailToParse("1\nx", { // Old Mac
location: { location: {
start: { offset: 2, line: 2, column: 1 }, start: { offset: 2, line: 2, column: 1 },
@ -1477,18 +1471,14 @@ describe("generated parser behavior", function() {
}); });
}); });
/* // Following examples are from Wikipedia, see
* Following examples are from Wikipedia, see // http://en.wikipedia.org/w/index.php?title=Parsing_expression_grammar&oldid=335106938.
* http://en.wikipedia.org/w/index.php?title=Parsing_expression_grammar&oldid=335106938.
*/
describe("complex examples", function() { describe("complex examples", function() {
it("handles arithmetics example correctly", function() { it("handles arithmetics example correctly", function() {
/* // Value ← [0-9]+ / '(' Expr ')'
* Value [0-9]+ / '(' Expr ')' // Product ← Value (('*' / '/') Value)*
* Product Value (('*' / '/') Value)* // Sum ← Product (('+' / '-') Product)*
* Sum Product (('+' / '-') Product)* // Expr ← Sum
* Expr Sum
*/
let parser = peg.generate([ let parser = peg.generate([
'Expr = Sum', 'Expr = Sum',
'Sum = head:Product tail:(("+" / "-") Product)* {', 'Sum = head:Product tail:(("+" / "-") Product)* {',
@ -1507,40 +1497,39 @@ describe("generated parser behavior", function() {
' / "(" expr:Expr ")" { return expr; }' ' / "(" expr:Expr ")" { return expr; }'
].join("\n"), options); ].join("\n"), options);
/* The "value" rule */ // The "value" rule
expect(parser).toParse("0", 0); expect(parser).toParse("0", 0);
expect(parser).toParse("123", 123); expect(parser).toParse("123", 123);
expect(parser).toParse("(42+43)", 42+43); expect(parser).toParse("(42+43)", 42+43);
/* The "product" rule */ // The "product" rule
expect(parser).toParse("42", 42); expect(parser).toParse("42", 42);
expect(parser).toParse("42*43", 42*43); expect(parser).toParse("42*43", 42*43);
expect(parser).toParse("42*43*44*45", 42*43*44*45); expect(parser).toParse("42*43*44*45", 42*43*44*45);
expect(parser).toParse("42/43", 42/43); expect(parser).toParse("42/43", 42/43);
expect(parser).toParse("42/43/44/45", 42/43/44/45); expect(parser).toParse("42/43/44/45", 42/43/44/45);
/* The "sum" rule */ // The "sum" rule
expect(parser).toParse("42*43", 42*43); expect(parser).toParse("42*43", 42*43);
expect(parser).toParse("42*43+44*45", 42*43+44*45); expect(parser).toParse("42*43+44*45", 42*43+44*45);
expect(parser).toParse("42*43+44*45+46*47+48*49", 42*43+44*45+46*47+48*49); expect(parser).toParse("42*43+44*45+46*47+48*49", 42*43+44*45+46*47+48*49);
expect(parser).toParse("42*43-44*45", 42*43-44*45); expect(parser).toParse("42*43-44*45", 42*43-44*45);
expect(parser).toParse("42*43-44*45-46*47-48*49", 42*43-44*45-46*47-48*49); expect(parser).toParse("42*43-44*45-46*47-48*49", 42*43-44*45-46*47-48*49);
/* The "expr" rule */ // The "expr" rule
expect(parser).toParse("42+43", 42+43); expect(parser).toParse("42+43", 42+43);
/* Complex test */ // Complex test
expect(parser).toParse("(1+2)*(3+4)", (1+2)*(3+4)); expect(parser).toParse("(1+2)*(3+4)", (1+2)*(3+4));
}); });
it("handles non-context-free language correctly", function() { it("handles non-context-free language correctly", function() {
/* The following parsing expression grammar describes the classic // The following parsing expression grammar describes the classic
* non-context-free language { a^n b^n c^n : n >= 1 }: // non-context-free language { a^n b^n c^n : n >= 1 }:
* //
* S &(A c) a+ B !(a/b/c) // S ← &(A c) a+ B !(a/b/c)
* A a A? b // A ← a A? b
* B b B? c // B ← b B? c
*/
let parser = peg.generate([ let parser = peg.generate([
'S = &(A "c") a:"a"+ B:B !("a" / "b" / "c") { return a.join("") + B; }', '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].join(""); }', 'A = a:"a" A:A? b:"b" { return [a, A, b].join(""); }',
@ -1558,13 +1547,11 @@ describe("generated parser behavior", function() {
}); });
it("handles nested comments example correctly", function() { it("handles nested comments example correctly", function() {
/* // Begin ← "(*"
* Begin "(*" // End ← "*)"
* End "*)" // C ← Begin N* End
* C Begin N* End // N ← C / (!Begin !End Z)
* N C / (!Begin !End Z) // Z ← any single character
* Z any single character
*/
let parser = peg.generate([ let parser = peg.generate([
'C = begin:Begin ns:N* end:End { return begin + ns.join("") + end; }', 'C = begin:Begin ns:N* end:End { return begin + ns.join("") + end; }',
'N = C', 'N = C',

@ -5,11 +5,9 @@
"use strict"; "use strict";
/* // Small server whose main purpose is to ensure that both the specced code and
* Small server whose main purpose is to ensure that both the specced code and // the specs get passed through Babel & Browserify before they are served to the
* the specs get passed through Babel & Browserify before they are served to the // browser.
* browser.
*/
let express = require("express"); let express = require("express");
let logger = require("morgan"); let logger = require("morgan");

@ -39,7 +39,7 @@ describe("compiler pass |reportInfiniteRecursion|", function() {
expect(pass).not.toReportError('start = "" "" "a" start'); expect(pass).not.toReportError('start = "" "" "a" start');
}); });
/* Regression test for #359. */ // Regression test for #359.
it("reports left recursion when rule reference is wrapped in an expression", function() { it("reports left recursion when rule reference is wrapped in an expression", function() {
expect(pass).toReportError('start = "" start?'); expect(pass).toReportError('start = "" start?');
}); });

@ -236,7 +236,7 @@ describe("PEG.js grammar parser", function() {
}); });
}); });
/* Canonical Grammar is "a = \"abcd\"; b = \"efgh\"; c = \"ijkl\";". */ // Canonical Grammar is "a = \"abcd\"; b = \"efgh\"; c = \"ijkl\";".
it("parses Grammar", function() { it("parses Grammar", function() {
expect('\na = "abcd";\n').toParseAs( expect('\na = "abcd";\n').toParseAs(
{ type: "grammar", initializer: null, rules: [ruleA] } { type: "grammar", initializer: null, rules: [ruleA] }
@ -249,14 +249,14 @@ describe("PEG.js grammar parser", function() {
); );
}); });
/* Canonical Initializer is "{ code }". */ // Canonical Initializer is "{ code }".
it("parses Initializer", function() { it("parses Initializer", function() {
expect('{ code };start = "abcd"').toParseAs( expect('{ code };start = "abcd"').toParseAs(
{ type: "grammar", initializer: initializer, rules: [ruleStart] } { type: "grammar", initializer: initializer, rules: [ruleStart] }
); );
}); });
/* Canonical Rule is "a = \"abcd\";". */ // Canonical Rule is "a = \"abcd\";".
it("parses Rule", function() { it("parses Rule", function() {
expect('start\n=\n"abcd";').toParseAs( expect('start\n=\n"abcd";').toParseAs(
oneRuleGrammar(literalAbcd) oneRuleGrammar(literalAbcd)
@ -266,14 +266,14 @@ describe("PEG.js grammar parser", function() {
); );
}); });
/* Canonical Expression is "\"abcd\"". */ // Canonical Expression is "\"abcd\"".
it("parses Expression", function() { it("parses Expression", function() {
expect('start = "abcd" / "efgh" / "ijkl"').toParseAs( expect('start = "abcd" / "efgh" / "ijkl"').toParseAs(
oneRuleGrammar(choice) oneRuleGrammar(choice)
); );
}); });
/* Canonical ChoiceExpression is "\"abcd\" / \"efgh\" / \"ijkl\"". */ // Canonical ChoiceExpression is "\"abcd\" / \"efgh\" / \"ijkl\"".
it("parses ChoiceExpression", function() { it("parses ChoiceExpression", function() {
expect('start = "abcd" { code }').toParseAs( expect('start = "abcd" { code }').toParseAs(
oneRuleGrammar(actionAbcd) oneRuleGrammar(actionAbcd)
@ -288,7 +288,7 @@ describe("PEG.js grammar parser", function() {
); );
}); });
/* Canonical ActionExpression is "\"abcd\" { code }". */ // Canonical ActionExpression is "\"abcd\" { code }".
it("parses ActionExpression", function() { it("parses ActionExpression", function() {
expect('start = "abcd" "efgh" "ijkl"').toParseAs( expect('start = "abcd" "efgh" "ijkl"').toParseAs(
oneRuleGrammar(sequence) oneRuleGrammar(sequence)
@ -298,7 +298,7 @@ describe("PEG.js grammar parser", function() {
); );
}); });
/* Canonical SequenceExpression is "\"abcd\" \"efgh\" \"ijkl\"". */ // Canonical SequenceExpression is "\"abcd\" \"efgh\" \"ijkl\"".
it("parses SequenceExpression", function() { it("parses SequenceExpression", function() {
expect('start = a:"abcd"').toParseAs( expect('start = a:"abcd"').toParseAs(
oneRuleGrammar(labeledAbcd) oneRuleGrammar(labeledAbcd)
@ -311,39 +311,39 @@ describe("PEG.js grammar parser", function() {
); );
}); });
/* Canonical LabeledExpression is "a:\"abcd\"". */ // Canonical LabeledExpression is "a:\"abcd\"".
it("parses LabeledExpression", function() { it("parses LabeledExpression", function() {
expect('start = a\n:\n!"abcd"').toParseAs(oneRuleGrammar(labeledSimpleNot)); expect('start = a\n:\n!"abcd"').toParseAs(oneRuleGrammar(labeledSimpleNot));
expect('start = !"abcd"' ).toParseAs(oneRuleGrammar(simpleNotAbcd)); expect('start = !"abcd"' ).toParseAs(oneRuleGrammar(simpleNotAbcd));
}); });
/* Canonical PrefixedExpression is "!\"abcd\"". */ // Canonical PrefixedExpression is "!\"abcd\"".
it("parses PrefixedExpression", function() { it("parses PrefixedExpression", function() {
expect('start = !\n"abcd"?' ).toParseAs(oneRuleGrammar(simpleNotOptional)); expect('start = !\n"abcd"?' ).toParseAs(oneRuleGrammar(simpleNotOptional));
expect('start = "abcd"?' ).toParseAs(oneRuleGrammar(optional)); expect('start = "abcd"?' ).toParseAs(oneRuleGrammar(optional));
}); });
/* Canonical PrefixedOperator is "!". */ // Canonical PrefixedOperator is "!".
it("parses PrefixedOperator", function() { it("parses PrefixedOperator", function() {
expect('start = $"abcd"?').toParseAs(oneRuleGrammar(textOptional)); expect('start = $"abcd"?').toParseAs(oneRuleGrammar(textOptional));
expect('start = &"abcd"?').toParseAs(oneRuleGrammar(simpleAndOptional)); expect('start = &"abcd"?').toParseAs(oneRuleGrammar(simpleAndOptional));
expect('start = !"abcd"?').toParseAs(oneRuleGrammar(simpleNotOptional)); expect('start = !"abcd"?').toParseAs(oneRuleGrammar(simpleNotOptional));
}); });
/* Canonical SuffixedExpression is "\"ebcd\"?". */ // Canonical SuffixedExpression is "\"ebcd\"?".
it("parses SuffixedExpression", function() { it("parses SuffixedExpression", function() {
expect('start = "abcd"\n?').toParseAs(oneRuleGrammar(optional)); expect('start = "abcd"\n?').toParseAs(oneRuleGrammar(optional));
expect('start = "abcd"' ).toParseAs(oneRuleGrammar(literalAbcd)); expect('start = "abcd"' ).toParseAs(oneRuleGrammar(literalAbcd));
}); });
/* Canonical SuffixedOperator is "?". */ // Canonical SuffixedOperator is "?".
it("parses SuffixedOperator", function() { it("parses SuffixedOperator", function() {
expect('start = "abcd"?').toParseAs(oneRuleGrammar(optional)); expect('start = "abcd"?').toParseAs(oneRuleGrammar(optional));
expect('start = "abcd"*').toParseAs(oneRuleGrammar(zeroOrMore)); expect('start = "abcd"*').toParseAs(oneRuleGrammar(zeroOrMore));
expect('start = "abcd"+').toParseAs(oneRuleGrammar(oneOrMore)); expect('start = "abcd"+').toParseAs(oneRuleGrammar(oneOrMore));
}); });
/* Canonical PrimaryExpression is "\"abcd\"". */ // Canonical PrimaryExpression is "\"abcd\"".
it("parses PrimaryExpression", function() { it("parses PrimaryExpression", function() {
expect('start = "abcd"' ).toParseAs(trivialGrammar); expect('start = "abcd"' ).toParseAs(trivialGrammar);
expect('start = [a-d]' ).toParseAs(classGrammar([["a", "d"]], false, false)); expect('start = [a-d]' ).toParseAs(classGrammar([["a", "d"]], false, false));
@ -356,7 +356,7 @@ describe("PEG.js grammar parser", function() {
expect('start = (\n"abcd"\n)' ).toParseAs(trivialGrammar); expect('start = (\n"abcd"\n)' ).toParseAs(trivialGrammar);
}); });
/* Canonical RuleReferenceExpression is "a". */ // Canonical RuleReferenceExpression is "a".
it("parses RuleReferenceExpression", function() { it("parses RuleReferenceExpression", function() {
expect('start = a').toParseAs(ruleRefGrammar("a")); expect('start = a').toParseAs(ruleRefGrammar("a"));
@ -364,20 +364,20 @@ describe("PEG.js grammar parser", function() {
expect('start = a\n"abcd"\n=').toFailToParse(); expect('start = a\n"abcd"\n=').toFailToParse();
}); });
/* Canonical SemanticPredicateExpression is "!{ code }". */ // Canonical SemanticPredicateExpression is "!{ code }".
it("parses SemanticPredicateExpression", function() { it("parses SemanticPredicateExpression", function() {
expect('start = !\n{ code }').toParseAs(oneRuleGrammar(semanticNot)); expect('start = !\n{ code }').toParseAs(oneRuleGrammar(semanticNot));
}); });
/* Canonical SemanticPredicateOperator is "!". */ // Canonical SemanticPredicateOperator is "!".
it("parses SemanticPredicateOperator", function() { it("parses SemanticPredicateOperator", function() {
expect('start = &{ code }').toParseAs(oneRuleGrammar(semanticAnd)); expect('start = &{ code }').toParseAs(oneRuleGrammar(semanticAnd));
expect('start = !{ code }').toParseAs(oneRuleGrammar(semanticNot)); expect('start = !{ code }').toParseAs(oneRuleGrammar(semanticNot));
}); });
/* The SourceCharacter rule is not tested. */ // The SourceCharacter rule is not tested.
/* Canonical WhiteSpace is " ". */ // Canonical WhiteSpace is " ".
it("parses WhiteSpace", function() { it("parses WhiteSpace", function() {
expect('start =\t"abcd"' ).toParseAs(trivialGrammar); expect('start =\t"abcd"' ).toParseAs(trivialGrammar);
expect('start =\v"abcd"' ).toParseAs(trivialGrammar); expect('start =\v"abcd"' ).toParseAs(trivialGrammar);
@ -388,7 +388,7 @@ describe("PEG.js grammar parser", function() {
expect('start =\u1680"abcd"').toParseAs(trivialGrammar); expect('start =\u1680"abcd"').toParseAs(trivialGrammar);
}); });
/* Canonical LineTerminator is "\n". */ // Canonical LineTerminator is "\n".
it("parses LineTerminator", function() { it("parses LineTerminator", function() {
expect('start = "\n"' ).toFailToParse(); expect('start = "\n"' ).toFailToParse();
expect('start = "\r"' ).toFailToParse(); expect('start = "\r"' ).toFailToParse();
@ -396,7 +396,7 @@ describe("PEG.js grammar parser", function() {
expect('start = "\u2029"').toFailToParse(); expect('start = "\u2029"').toFailToParse();
}); });
/* Canonical LineTerminatorSequence is "\r\n". */ // Canonical LineTerminatorSequence is "\r\n".
it("parses LineTerminatorSequence", function() { it("parses LineTerminatorSequence", function() {
expect('start =\n"abcd"' ).toParseAs(trivialGrammar); expect('start =\n"abcd"' ).toParseAs(trivialGrammar);
expect('start =\r\n"abcd"' ).toParseAs(trivialGrammar); expect('start =\r\n"abcd"' ).toParseAs(trivialGrammar);
@ -430,7 +430,7 @@ describe("PEG.js grammar parser", function() {
expect('a = "abcd"/*\n*/\r\nb = "efgh"').toFailToParse(); expect('a = "abcd"/*\n*/\r\nb = "efgh"').toFailToParse();
}); });
/* Canonical SingleLineComment is "// comment". */ // Canonical SingleLineComment is "// comment".
it("parses SingleLineComment", function() { it("parses SingleLineComment", function() {
expect('start =//\n"abcd"' ).toParseAs(trivialGrammar); expect('start =//\n"abcd"' ).toParseAs(trivialGrammar);
expect('start =//a\n"abcd"' ).toParseAs(trivialGrammar); expect('start =//a\n"abcd"' ).toParseAs(trivialGrammar);
@ -439,19 +439,19 @@ describe("PEG.js grammar parser", function() {
expect('start =//\n@\n"abcd"').toFailToParse(); expect('start =//\n@\n"abcd"').toFailToParse();
}); });
/* Canonical Identifier is "a". */ // Canonical Identifier is "a".
it("parses Identifier", function() { it("parses Identifier", function() {
expect('start = a:"abcd"').toParseAs(oneRuleGrammar(labeledAbcd)); expect('start = a:"abcd"').toParseAs(oneRuleGrammar(labeledAbcd));
}); });
/* Canonical IdentifierName is "a". */ // Canonical IdentifierName is "a".
it("parses IdentifierName", function() { it("parses IdentifierName", function() {
expect('start = a' ).toParseAs(ruleRefGrammar("a")); expect('start = a' ).toParseAs(ruleRefGrammar("a"));
expect('start = ab' ).toParseAs(ruleRefGrammar("ab")); expect('start = ab' ).toParseAs(ruleRefGrammar("ab"));
expect('start = abcd').toParseAs(ruleRefGrammar("abcd")); expect('start = abcd').toParseAs(ruleRefGrammar("abcd"));
}); });
/* Canonical IdentifierStart is "a". */ // Canonical IdentifierStart is "a".
it("parses IdentifierStart", function() { it("parses IdentifierStart", function() {
expect('start = a' ).toParseAs(ruleRefGrammar("a")); expect('start = a' ).toParseAs(ruleRefGrammar("a"));
expect('start = $' ).toParseAs(ruleRefGrammar("$")); expect('start = $' ).toParseAs(ruleRefGrammar("$"));
@ -459,7 +459,7 @@ describe("PEG.js grammar parser", function() {
expect('start = \\u0061').toParseAs(ruleRefGrammar("a")); expect('start = \\u0061').toParseAs(ruleRefGrammar("a"));
}); });
/* Canonical IdentifierPart is "a". */ // Canonical IdentifierPart is "a".
it("parses IdentifierPart", function() { it("parses IdentifierPart", function() {
expect('start = aa' ).toParseAs(ruleRefGrammar("aa")); expect('start = aa' ).toParseAs(ruleRefGrammar("aa"));
expect('start = a\u0300').toParseAs(ruleRefGrammar("a\u0300")); expect('start = a\u0300').toParseAs(ruleRefGrammar("a\u0300"));
@ -469,15 +469,15 @@ describe("PEG.js grammar parser", function() {
expect('start = a\u200D').toParseAs(ruleRefGrammar("a\u200D")); expect('start = a\u200D').toParseAs(ruleRefGrammar("a\u200D"));
}); });
/* Unicode rules and reserved word rules are not tested. */ // Unicode rules and reserved word rules are not tested.
/* Canonical LiteralMatcher is "\"abcd\"". */ // Canonical LiteralMatcher is "\"abcd\"".
it("parses LiteralMatcher", function() { it("parses LiteralMatcher", function() {
expect('start = "abcd"' ).toParseAs(literalGrammar("abcd", false)); expect('start = "abcd"' ).toParseAs(literalGrammar("abcd", false));
expect('start = "abcd"i').toParseAs(literalGrammar("abcd", true)); expect('start = "abcd"i').toParseAs(literalGrammar("abcd", true));
}); });
/* Canonical StringLiteral is "\"abcd\"". */ // Canonical StringLiteral is "\"abcd\"".
it("parses StringLiteral", function() { it("parses StringLiteral", function() {
expect('start = ""' ).toParseAs(literalGrammar("", false)); expect('start = ""' ).toParseAs(literalGrammar("", false));
expect('start = "a"' ).toParseAs(literalGrammar("a", false)); expect('start = "a"' ).toParseAs(literalGrammar("a", false));
@ -488,7 +488,7 @@ describe("PEG.js grammar parser", function() {
expect("start = 'abc'").toParseAs(literalGrammar("abc", false)); expect("start = 'abc'").toParseAs(literalGrammar("abc", false));
}); });
/* Canonical DoubleStringCharacter is "a". */ // Canonical DoubleStringCharacter is "a".
it("parses DoubleStringCharacter", function() { it("parses DoubleStringCharacter", function() {
expect('start = "a"' ).toParseAs(literalGrammar("a", false)); expect('start = "a"' ).toParseAs(literalGrammar("a", false));
expect('start = "\\n"' ).toParseAs(literalGrammar("\n", false)); expect('start = "\\n"' ).toParseAs(literalGrammar("\n", false));
@ -499,7 +499,7 @@ describe("PEG.js grammar parser", function() {
expect('start = "\n"').toFailToParse(); expect('start = "\n"').toFailToParse();
}); });
/* Canonical SingleStringCharacter is "a". */ // Canonical SingleStringCharacter is "a".
it("parses SingleStringCharacter", function() { it("parses SingleStringCharacter", function() {
expect("start = 'a'" ).toParseAs(literalGrammar("a", false)); expect("start = 'a'" ).toParseAs(literalGrammar("a", false));
expect("start = '\\n'" ).toParseAs(literalGrammar("\n", false)); expect("start = '\\n'" ).toParseAs(literalGrammar("\n", false));
@ -510,7 +510,7 @@ describe("PEG.js grammar parser", function() {
expect("start = '\n'").toFailToParse(); expect("start = '\n'").toFailToParse();
}); });
/* Canonical CharacterClassMatcher is "[a-d]". */ // Canonical CharacterClassMatcher is "[a-d]".
it("parses CharacterClassMatcher", function() { it("parses CharacterClassMatcher", function() {
expect('start = []').toParseAs( expect('start = []').toParseAs(
classGrammar([], false, false) classGrammar([], false, false)
@ -540,7 +540,7 @@ describe("PEG.js grammar parser", function() {
); );
}); });
/* Canonical ClassCharacterRange is "a-d". */ // Canonical ClassCharacterRange is "a-d".
it("parses ClassCharacterRange", function() { it("parses ClassCharacterRange", function() {
expect('start = [a-d]').toParseAs(classGrammar([["a", "d"]], false, false)); expect('start = [a-d]').toParseAs(classGrammar([["a", "d"]], false, false));
@ -550,7 +550,7 @@ describe("PEG.js grammar parser", function() {
}); });
}); });
/* Canonical ClassCharacter is "a". */ // Canonical ClassCharacter is "a".
it("parses ClassCharacter", function() { it("parses ClassCharacter", function() {
expect('start = [a]' ).toParseAs(classGrammar(["a"], false, false)); expect('start = [a]' ).toParseAs(classGrammar(["a"], false, false));
expect('start = [\\n]' ).toParseAs(classGrammar(["\n"], false, false)); expect('start = [\\n]' ).toParseAs(classGrammar(["\n"], false, false));
@ -561,12 +561,12 @@ describe("PEG.js grammar parser", function() {
expect('start = [\n]').toFailToParse(); expect('start = [\n]').toFailToParse();
}); });
/* Canonical LineContinuation is "\\\n". */ // Canonical LineContinuation is "\\\n".
it("parses LineContinuation", function() { it("parses LineContinuation", function() {
expect('start = "\\\r\n"').toParseAs(literalGrammar("", false)); expect('start = "\\\r\n"').toParseAs(literalGrammar("", false));
}); });
/* Canonical EscapeSequence is "n". */ // Canonical EscapeSequence is "n".
it("parses EscapeSequence", function() { it("parses EscapeSequence", function() {
expect('start = "\\n"' ).toParseAs(literalGrammar("\n", false)); expect('start = "\\n"' ).toParseAs(literalGrammar("\n", false));
expect('start = "\\0"' ).toParseAs(literalGrammar("\x00", false)); expect('start = "\\0"' ).toParseAs(literalGrammar("\x00", false));
@ -576,13 +576,13 @@ describe("PEG.js grammar parser", function() {
expect('start = "\\09"').toFailToParse(); expect('start = "\\09"').toFailToParse();
}); });
/* Canonical CharacterEscapeSequence is "n". */ // Canonical CharacterEscapeSequence is "n".
it("parses CharacterEscapeSequence", function() { it("parses CharacterEscapeSequence", function() {
expect('start = "\\n"').toParseAs(literalGrammar("\n", false)); expect('start = "\\n"').toParseAs(literalGrammar("\n", false));
expect('start = "\\a"').toParseAs(literalGrammar("a", false)); expect('start = "\\a"').toParseAs(literalGrammar("a", false));
}); });
/* Canonical SingleEscapeCharacter is "n". */ // Canonical SingleEscapeCharacter is "n".
it("parses SingleEscapeCharacter", function() { it("parses SingleEscapeCharacter", function() {
expect('start = "\\\'"').toParseAs(literalGrammar("'", false)); expect('start = "\\\'"').toParseAs(literalGrammar("'", false));
expect('start = "\\""' ).toParseAs(literalGrammar('"', false)); expect('start = "\\""' ).toParseAs(literalGrammar('"', false));
@ -595,44 +595,40 @@ describe("PEG.js grammar parser", function() {
expect('start = "\\v"' ).toParseAs(literalGrammar("\v", false)); expect('start = "\\v"' ).toParseAs(literalGrammar("\v", false));
}); });
/* Canonical NonEscapeCharacter is "a". */ // Canonical NonEscapeCharacter is "a".
it("parses NonEscapeCharacter", function() { it("parses NonEscapeCharacter", function() {
expect('start = "\\a"').toParseAs(literalGrammar("a", false)); expect('start = "\\a"').toParseAs(literalGrammar("a", false));
/* // The negative predicate is impossible to test with PEG.js grammar
* The negative predicate is impossible to test with PEG.js grammar // structure.
* structure.
*/
}); });
/* // The EscapeCharacter rule is impossible to test with PEG.js grammar
* The EscapeCharacter rule is impossible to test with PEG.js grammar // structure.
* structure.
*/
/* Canonical HexEscapeSequence is "xFF". */ // Canonical HexEscapeSequence is "xFF".
it("parses HexEscapeSequence", function() { it("parses HexEscapeSequence", function() {
expect('start = "\\xFF"').toParseAs(literalGrammar("\xFF", false)); expect('start = "\\xFF"').toParseAs(literalGrammar("\xFF", false));
}); });
/* Canonical UnicodeEscapeSequence is "uFFFF". */ // Canonical UnicodeEscapeSequence is "uFFFF".
it("parses UnicodeEscapeSequence", function() { it("parses UnicodeEscapeSequence", function() {
expect('start = "\\uFFFF"').toParseAs(literalGrammar("\uFFFF", false)); expect('start = "\\uFFFF"').toParseAs(literalGrammar("\uFFFF", false));
}); });
/* Digit rules are not tested. */ // Digit rules are not tested.
/* Canonical AnyMatcher is ".". */ // Canonical AnyMatcher is ".".
it("parses AnyMatcher", function() { it("parses AnyMatcher", function() {
expect('start = .').toParseAs(anyGrammar()); expect('start = .').toParseAs(anyGrammar());
}); });
/* Canonical CodeBlock is "{ code }". */ // Canonical CodeBlock is "{ code }".
it("parses CodeBlock", function() { it("parses CodeBlock", function() {
expect('start = "abcd" { code }').toParseAs(actionGrammar(" code ")); expect('start = "abcd" { code }').toParseAs(actionGrammar(" code "));
}); });
/* Canonical Code is " code ". */ // Canonical Code is " code ".
it("parses Code", function() { it("parses Code", function() {
expect('start = "abcd" {a}' ).toParseAs(actionGrammar("a")); expect('start = "abcd" {a}' ).toParseAs(actionGrammar("a"));
expect('start = "abcd" {abc}' ).toParseAs(actionGrammar("abc")); expect('start = "abcd" {abc}' ).toParseAs(actionGrammar("abc"));
@ -643,9 +639,9 @@ describe("PEG.js grammar parser", function() {
expect('start = "abcd" {}}').toFailToParse(); expect('start = "abcd" {}}').toFailToParse();
}); });
/* Unicode character category rules and token rules are not tested. */ // Unicode character category rules and token rules are not tested.
/* Canonical __ is "\n". */ // Canonical __ is "\n".
it("parses __", function() { it("parses __", function() {
expect('start ="abcd"' ).toParseAs(trivialGrammar); expect('start ="abcd"' ).toParseAs(trivialGrammar);
expect('start = "abcd"' ).toParseAs(trivialGrammar); expect('start = "abcd"' ).toParseAs(trivialGrammar);
@ -654,7 +650,7 @@ describe("PEG.js grammar parser", function() {
expect('start = "abcd"' ).toParseAs(trivialGrammar); expect('start = "abcd"' ).toParseAs(trivialGrammar);
}); });
/* Canonical _ is " ". */ // Canonical _ is " ".
it("parses _", function() { it("parses _", function() {
expect('a = "abcd"\r\nb = "efgh"' ).toParseAs(twoRuleGrammar); expect('a = "abcd"\r\nb = "efgh"' ).toParseAs(twoRuleGrammar);
expect('a = "abcd" \r\nb = "efgh"' ).toParseAs(twoRuleGrammar); expect('a = "abcd" \r\nb = "efgh"' ).toParseAs(twoRuleGrammar);
@ -662,7 +658,7 @@ describe("PEG.js grammar parser", function() {
expect('a = "abcd" \r\nb = "efgh"' ).toParseAs(twoRuleGrammar); expect('a = "abcd" \r\nb = "efgh"' ).toParseAs(twoRuleGrammar);
}); });
/* Canonical EOS is ";". */ // Canonical EOS is ";".
it("parses EOS", function() { it("parses EOS", function() {
expect('a = "abcd"\n;b = "efgh"' ).toParseAs(twoRuleGrammar); expect('a = "abcd"\n;b = "efgh"' ).toParseAs(twoRuleGrammar);
expect('a = "abcd" \r\nb = "efgh"' ).toParseAs(twoRuleGrammar); expect('a = "abcd" \r\nb = "efgh"' ).toParseAs(twoRuleGrammar);
@ -670,7 +666,7 @@ describe("PEG.js grammar parser", function() {
expect('a = "abcd"\nb = "efgh"' ).toParseAs(twoRuleGrammar); expect('a = "abcd"\nb = "efgh"' ).toParseAs(twoRuleGrammar);
}); });
/* Canonical EOF is the end of input. */ // Canonical EOF is the end of input.
it("parses EOF", function() { it("parses EOF", function() {
expect('start = "abcd"\n').toParseAs(trivialGrammar); expect('start = "abcd"\n').toParseAs(trivialGrammar);
}); });

@ -1,27 +1,25 @@
/* // PEG.js Grammar
* PEG.js Grammar // ==============
* ============== //
* // PEG.js grammar syntax is designed to be simple, expressive, and similar to
* PEG.js grammar syntax is designed to be simple, expressive, and similar to // JavaScript where possible. This means that many rules, especially in the
* JavaScript where possible. This means that many rules, especially in the // lexical part, are based on the grammar from ECMA-262, 5.1 Edition [1]. Some
* lexical part, are based on the grammar from ECMA-262, 5.1 Edition [1]. Some // are directly taken or adapted from the JavaScript example grammar (see
* are directly taken or adapted from the JavaScript example grammar (see // examples/javascript.pegjs).
* examples/javascript.pegjs). //
* // Limitations:
* Limitations: //
* // * Non-BMP characters are completely ignored to avoid surrogate pair
* * Non-BMP characters are completely ignored to avoid surrogate pair // handling.
* handling. //
* // * One can create identifiers containing illegal characters using Unicode
* * One can create identifiers containing illegal characters using Unicode // escape sequences. For example, "abcd\u0020efgh" is not a valid
* escape sequences. For example, "abcd\u0020efgh" is not a valid // identifier, but it is accepted by the parser.
* identifier, but it is accepted by the parser. //
* // Both limitations could be resolved, but the costs would likely outweigh
* Both limitations could be resolved, but the costs would likely outweigh // the benefits.
* the benefits. //
* // [1] http://www.ecma-international.org/publications/standards/Ecma-262.htm
* [1] http://www.ecma-international.org/publications/standards/Ecma-262.htm
*/
{ {
const OPS_TO_PREFIXED_TYPES = { const OPS_TO_PREFIXED_TYPES = {
@ -54,7 +52,7 @@
} }
} }
/* ---- Syntactic Grammar ----- */ // ---- Syntactic Grammar -----
Grammar Grammar
= __ initializer:(Initializer __)? rules:(Rule __)+ { = __ initializer:(Initializer __)? rules:(Rule __)+ {
@ -177,12 +175,10 @@ PrimaryExpression
/ RuleReferenceExpression / RuleReferenceExpression
/ SemanticPredicateExpression / SemanticPredicateExpression
/ "(" __ expression:Expression __ ")" { / "(" __ expression:Expression __ ")" {
/* // The purpose of the "group" AST node is just to isolate label scope. We
* The purpose of the "group" AST node is just to isolate label scope. We // don't need to put it around nodes that can't contain any labels or
* don't need to put it around nodes that can't contain any labels or // nodes that already isolate label scope themselves. This leaves us with
* nodes that already isolate label scope themselves. This leaves us with // "labeled" and "sequence".
* "labeled" and "sequence".
*/
return expression.type === 'labeled' || expression.type === 'sequence' return expression.type === 'labeled' || expression.type === 'sequence'
? { type: "group", expression: expression } ? { type: "group", expression: expression }
: expression; : expression;
@ -206,7 +202,7 @@ SemanticPredicateOperator
= "&" = "&"
/ "!" / "!"
/* ---- Lexical Grammar ----- */ // ---- Lexical Grammar -----
SourceCharacter SourceCharacter
= . = .
@ -445,30 +441,28 @@ CodeBlock "code block"
Code Code
= $((![{}] SourceCharacter)+ / "{" Code "}")* = $((![{}] SourceCharacter)+ / "{" Code "}")*
/* // Unicode Character Categories
* Unicode Character Categories //
* // Extracted from the following Unicode Character Database file:
* Extracted from the following Unicode Character Database file: //
* // http://www.unicode.org/Public/8.0.0/ucd/extracted/DerivedGeneralCategory.txt
* http://www.unicode.org/Public/8.0.0/ucd/extracted/DerivedGeneralCategory.txt //
* // Unix magic used:
* Unix magic used: //
* // grep "; $CATEGORY" DerivedGeneralCategory.txt | # Filter characters
* grep "; $CATEGORY" DerivedGeneralCategory.txt | # Filter characters // cut -f1 -d " " | # Extract code points
* cut -f1 -d " " | # Extract code points // grep -v '[0-9a-fA-F]\{5\}' | # Exclude non-BMP characters
* grep -v '[0-9a-fA-F]\{5\}' | # Exclude non-BMP characters // sed -e 's/\.\./-/' | # Adjust formatting
* sed -e 's/\.\./-/' | # Adjust formatting // sed -e 's/\([0-9a-fA-F]\{4\}\)/\\u\1/g' | # Adjust formatting
* sed -e 's/\([0-9a-fA-F]\{4\}\)/\\u\1/g' | # Adjust formatting // tr -d '\n' # Join lines
* tr -d '\n' # Join lines //
* // ECMA-262 allows using Unicode 3.0 or later, version 8.0.0 was the latest one
* ECMA-262 allows using Unicode 3.0 or later, version 8.0.0 was the latest one // at the time of writing.
* at the time of writing. //
* // Non-BMP characters are completely ignored to avoid surrogate pair handling
* Non-BMP characters are completely ignored to avoid surrogate pair handling // (detecting surrogate pairs isn't possible with a simple character class and
* (detecting surrogate pairs isn't possible with a simple character class and // other methods would degrade performance). I don't consider it a big deal as
* other methods would degrade performance). I don't consider it a big deal as // even parsers in JavaScript engines of common browsers seem to ignore them.
* even parsers in JavaScript engines of common browsers seem to ignore them.
*/
// Letter, Lowercase // Letter, Lowercase
Ll = [\u0061-\u007A\u00B5\u00DF-\u00F6\u00F8-\u00FF\u0101\u0103\u0105\u0107\u0109\u010B\u010D\u010F\u0111\u0113\u0115\u0117\u0119\u011B\u011D\u011F\u0121\u0123\u0125\u0127\u0129\u012B\u012D\u012F\u0131\u0133\u0135\u0137-\u0138\u013A\u013C\u013E\u0140\u0142\u0144\u0146\u0148-\u0149\u014B\u014D\u014F\u0151\u0153\u0155\u0157\u0159\u015B\u015D\u015F\u0161\u0163\u0165\u0167\u0169\u016B\u016D\u016F\u0171\u0173\u0175\u0177\u017A\u017C\u017E-\u0180\u0183\u0185\u0188\u018C-\u018D\u0192\u0195\u0199-\u019B\u019E\u01A1\u01A3\u01A5\u01A8\u01AA-\u01AB\u01AD\u01B0\u01B4\u01B6\u01B9-\u01BA\u01BD-\u01BF\u01C6\u01C9\u01CC\u01CE\u01D0\u01D2\u01D4\u01D6\u01D8\u01DA\u01DC-\u01DD\u01DF\u01E1\u01E3\u01E5\u01E7\u01E9\u01EB\u01ED\u01EF-\u01F0\u01F3\u01F5\u01F9\u01FB\u01FD\u01FF\u0201\u0203\u0205\u0207\u0209\u020B\u020D\u020F\u0211\u0213\u0215\u0217\u0219\u021B\u021D\u021F\u0221\u0223\u0225\u0227\u0229\u022B\u022D\u022F\u0231\u0233-\u0239\u023C\u023F-\u0240\u0242\u0247\u0249\u024B\u024D\u024F-\u0293\u0295-\u02AF\u0371\u0373\u0377\u037B-\u037D\u0390\u03AC-\u03CE\u03D0-\u03D1\u03D5-\u03D7\u03D9\u03DB\u03DD\u03DF\u03E1\u03E3\u03E5\u03E7\u03E9\u03EB\u03ED\u03EF-\u03F3\u03F5\u03F8\u03FB-\u03FC\u0430-\u045F\u0461\u0463\u0465\u0467\u0469\u046B\u046D\u046F\u0471\u0473\u0475\u0477\u0479\u047B\u047D\u047F\u0481\u048B\u048D\u048F\u0491\u0493\u0495\u0497\u0499\u049B\u049D\u049F\u04A1\u04A3\u04A5\u04A7\u04A9\u04AB\u04AD\u04AF\u04B1\u04B3\u04B5\u04B7\u04B9\u04BB\u04BD\u04BF\u04C2\u04C4\u04C6\u04C8\u04CA\u04CC\u04CE-\u04CF\u04D1\u04D3\u04D5\u04D7\u04D9\u04DB\u04DD\u04DF\u04E1\u04E3\u04E5\u04E7\u04E9\u04EB\u04ED\u04EF\u04F1\u04F3\u04F5\u04F7\u04F9\u04FB\u04FD\u04FF\u0501\u0503\u0505\u0507\u0509\u050B\u050D\u050F\u0511\u0513\u0515\u0517\u0519\u051B\u051D\u051F\u0521\u0523\u0525\u0527\u0529\u052B\u052D\u052F\u0561-\u0587\u13F8-\u13FD\u1D00-\u1D2B\u1D6B-\u1D77\u1D79-\u1D9A\u1E01\u1E03\u1E05\u1E07\u1E09\u1E0B\u1E0D\u1E0F\u1E11\u1E13\u1E15\u1E17\u1E19\u1E1B\u1E1D\u1E1F\u1E21\u1E23\u1E25\u1E27\u1E29\u1E2B\u1E2D\u1E2F\u1E31\u1E33\u1E35\u1E37\u1E39\u1E3B\u1E3D\u1E3F\u1E41\u1E43\u1E45\u1E47\u1E49\u1E4B\u1E4D\u1E4F\u1E51\u1E53\u1E55\u1E57\u1E59\u1E5B\u1E5D\u1E5F\u1E61\u1E63\u1E65\u1E67\u1E69\u1E6B\u1E6D\u1E6F\u1E71\u1E73\u1E75\u1E77\u1E79\u1E7B\u1E7D\u1E7F\u1E81\u1E83\u1E85\u1E87\u1E89\u1E8B\u1E8D\u1E8F\u1E91\u1E93\u1E95-\u1E9D\u1E9F\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9\u1EFB\u1EFD\u1EFF-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB0-\u1FB4\u1FB6-\u1FB7\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FC7\u1FD0-\u1FD3\u1FD6-\u1FD7\u1FE0-\u1FE7\u1FF2-\u1FF4\u1FF6-\u1FF7\u210A\u210E-\u210F\u2113\u212F\u2134\u2139\u213C-\u213D\u2146-\u2149\u214E\u2184\u2C30-\u2C5E\u2C61\u2C65-\u2C66\u2C68\u2C6A\u2C6C\u2C71\u2C73-\u2C74\u2C76-\u2C7B\u2C81\u2C83\u2C85\u2C87\u2C89\u2C8B\u2C8D\u2C8F\u2C91\u2C93\u2C95\u2C97\u2C99\u2C9B\u2C9D\u2C9F\u2CA1\u2CA3\u2CA5\u2CA7\u2CA9\u2CAB\u2CAD\u2CAF\u2CB1\u2CB3\u2CB5\u2CB7\u2CB9\u2CBB\u2CBD\u2CBF\u2CC1\u2CC3\u2CC5\u2CC7\u2CC9\u2CCB\u2CCD\u2CCF\u2CD1\u2CD3\u2CD5\u2CD7\u2CD9\u2CDB\u2CDD\u2CDF\u2CE1\u2CE3-\u2CE4\u2CEC\u2CEE\u2CF3\u2D00-\u2D25\u2D27\u2D2D\uA641\uA643\uA645\uA647\uA649\uA64B\uA64D\uA64F\uA651\uA653\uA655\uA657\uA659\uA65B\uA65D\uA65F\uA661\uA663\uA665\uA667\uA669\uA66B\uA66D\uA681\uA683\uA685\uA687\uA689\uA68B\uA68D\uA68F\uA691\uA693\uA695\uA697\uA699\uA69B\uA723\uA725\uA727\uA729\uA72B\uA72D\uA72F-\uA731\uA733\uA735\uA737\uA739\uA73B\uA73D\uA73F\uA741\uA743\uA745\uA747\uA749\uA74B\uA74D\uA74F\uA751\uA753\uA755\uA757\uA759\uA75B\uA75D\uA75F\uA761\uA763\uA765\uA767\uA769\uA76B\uA76D\uA76F\uA771-\uA778\uA77A\uA77C\uA77F\uA781\uA783\uA785\uA787\uA78C\uA78E\uA791\uA793-\uA795\uA797\uA799\uA79B\uA79D\uA79F\uA7A1\uA7A3\uA7A5\uA7A7\uA7A9\uA7B5\uA7B7\uA7FA\uAB30-\uAB5A\uAB60-\uAB65\uAB70-\uABBF\uFB00-\uFB06\uFB13-\uFB17\uFF41-\uFF5A] Ll = [\u0061-\u007A\u00B5\u00DF-\u00F6\u00F8-\u00FF\u0101\u0103\u0105\u0107\u0109\u010B\u010D\u010F\u0111\u0113\u0115\u0117\u0119\u011B\u011D\u011F\u0121\u0123\u0125\u0127\u0129\u012B\u012D\u012F\u0131\u0133\u0135\u0137-\u0138\u013A\u013C\u013E\u0140\u0142\u0144\u0146\u0148-\u0149\u014B\u014D\u014F\u0151\u0153\u0155\u0157\u0159\u015B\u015D\u015F\u0161\u0163\u0165\u0167\u0169\u016B\u016D\u016F\u0171\u0173\u0175\u0177\u017A\u017C\u017E-\u0180\u0183\u0185\u0188\u018C-\u018D\u0192\u0195\u0199-\u019B\u019E\u01A1\u01A3\u01A5\u01A8\u01AA-\u01AB\u01AD\u01B0\u01B4\u01B6\u01B9-\u01BA\u01BD-\u01BF\u01C6\u01C9\u01CC\u01CE\u01D0\u01D2\u01D4\u01D6\u01D8\u01DA\u01DC-\u01DD\u01DF\u01E1\u01E3\u01E5\u01E7\u01E9\u01EB\u01ED\u01EF-\u01F0\u01F3\u01F5\u01F9\u01FB\u01FD\u01FF\u0201\u0203\u0205\u0207\u0209\u020B\u020D\u020F\u0211\u0213\u0215\u0217\u0219\u021B\u021D\u021F\u0221\u0223\u0225\u0227\u0229\u022B\u022D\u022F\u0231\u0233-\u0239\u023C\u023F-\u0240\u0242\u0247\u0249\u024B\u024D\u024F-\u0293\u0295-\u02AF\u0371\u0373\u0377\u037B-\u037D\u0390\u03AC-\u03CE\u03D0-\u03D1\u03D5-\u03D7\u03D9\u03DB\u03DD\u03DF\u03E1\u03E3\u03E5\u03E7\u03E9\u03EB\u03ED\u03EF-\u03F3\u03F5\u03F8\u03FB-\u03FC\u0430-\u045F\u0461\u0463\u0465\u0467\u0469\u046B\u046D\u046F\u0471\u0473\u0475\u0477\u0479\u047B\u047D\u047F\u0481\u048B\u048D\u048F\u0491\u0493\u0495\u0497\u0499\u049B\u049D\u049F\u04A1\u04A3\u04A5\u04A7\u04A9\u04AB\u04AD\u04AF\u04B1\u04B3\u04B5\u04B7\u04B9\u04BB\u04BD\u04BF\u04C2\u04C4\u04C6\u04C8\u04CA\u04CC\u04CE-\u04CF\u04D1\u04D3\u04D5\u04D7\u04D9\u04DB\u04DD\u04DF\u04E1\u04E3\u04E5\u04E7\u04E9\u04EB\u04ED\u04EF\u04F1\u04F3\u04F5\u04F7\u04F9\u04FB\u04FD\u04FF\u0501\u0503\u0505\u0507\u0509\u050B\u050D\u050F\u0511\u0513\u0515\u0517\u0519\u051B\u051D\u051F\u0521\u0523\u0525\u0527\u0529\u052B\u052D\u052F\u0561-\u0587\u13F8-\u13FD\u1D00-\u1D2B\u1D6B-\u1D77\u1D79-\u1D9A\u1E01\u1E03\u1E05\u1E07\u1E09\u1E0B\u1E0D\u1E0F\u1E11\u1E13\u1E15\u1E17\u1E19\u1E1B\u1E1D\u1E1F\u1E21\u1E23\u1E25\u1E27\u1E29\u1E2B\u1E2D\u1E2F\u1E31\u1E33\u1E35\u1E37\u1E39\u1E3B\u1E3D\u1E3F\u1E41\u1E43\u1E45\u1E47\u1E49\u1E4B\u1E4D\u1E4F\u1E51\u1E53\u1E55\u1E57\u1E59\u1E5B\u1E5D\u1E5F\u1E61\u1E63\u1E65\u1E67\u1E69\u1E6B\u1E6D\u1E6F\u1E71\u1E73\u1E75\u1E77\u1E79\u1E7B\u1E7D\u1E7F\u1E81\u1E83\u1E85\u1E87\u1E89\u1E8B\u1E8D\u1E8F\u1E91\u1E93\u1E95-\u1E9D\u1E9F\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9\u1EFB\u1EFD\u1EFF-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB0-\u1FB4\u1FB6-\u1FB7\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FC7\u1FD0-\u1FD3\u1FD6-\u1FD7\u1FE0-\u1FE7\u1FF2-\u1FF4\u1FF6-\u1FF7\u210A\u210E-\u210F\u2113\u212F\u2134\u2139\u213C-\u213D\u2146-\u2149\u214E\u2184\u2C30-\u2C5E\u2C61\u2C65-\u2C66\u2C68\u2C6A\u2C6C\u2C71\u2C73-\u2C74\u2C76-\u2C7B\u2C81\u2C83\u2C85\u2C87\u2C89\u2C8B\u2C8D\u2C8F\u2C91\u2C93\u2C95\u2C97\u2C99\u2C9B\u2C9D\u2C9F\u2CA1\u2CA3\u2CA5\u2CA7\u2CA9\u2CAB\u2CAD\u2CAF\u2CB1\u2CB3\u2CB5\u2CB7\u2CB9\u2CBB\u2CBD\u2CBF\u2CC1\u2CC3\u2CC5\u2CC7\u2CC9\u2CCB\u2CCD\u2CCF\u2CD1\u2CD3\u2CD5\u2CD7\u2CD9\u2CDB\u2CDD\u2CDF\u2CE1\u2CE3-\u2CE4\u2CEC\u2CEE\u2CF3\u2D00-\u2D25\u2D27\u2D2D\uA641\uA643\uA645\uA647\uA649\uA64B\uA64D\uA64F\uA651\uA653\uA655\uA657\uA659\uA65B\uA65D\uA65F\uA661\uA663\uA665\uA667\uA669\uA66B\uA66D\uA681\uA683\uA685\uA687\uA689\uA68B\uA68D\uA68F\uA691\uA693\uA695\uA697\uA699\uA69B\uA723\uA725\uA727\uA729\uA72B\uA72D\uA72F-\uA731\uA733\uA735\uA737\uA739\uA73B\uA73D\uA73F\uA741\uA743\uA745\uA747\uA749\uA74B\uA74D\uA74F\uA751\uA753\uA755\uA757\uA759\uA75B\uA75D\uA75F\uA761\uA763\uA765\uA767\uA769\uA76B\uA76D\uA76F\uA771-\uA778\uA77A\uA77C\uA77F\uA781\uA783\uA785\uA787\uA78C\uA78E\uA791\uA793-\uA795\uA797\uA799\uA79B\uA79D\uA79F\uA7A1\uA7A3\uA7A5\uA7A7\uA7A9\uA7B5\uA7B7\uA7FA\uAB30-\uAB5A\uAB60-\uAB65\uAB70-\uABBF\uFB00-\uFB06\uFB13-\uFB17\uFF41-\uFF5A]
@ -503,7 +497,7 @@ Pc = [\u005F\u203F-\u2040\u2054\uFE33-\uFE34\uFE4D-\uFE4F\uFF3F]
// Separator, Space // Separator, Space
Zs = [\u0020\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000] Zs = [\u0020\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]
/* Tokens */ // Tokens
BreakToken = "break" !IdentifierPart BreakToken = "break" !IdentifierPart
CaseToken = "case" !IdentifierPart CaseToken = "case" !IdentifierPart
@ -542,7 +536,7 @@ VoidToken = "void" !IdentifierPart
WhileToken = "while" !IdentifierPart WhileToken = "while" !IdentifierPart
WithToken = "with" !IdentifierPart WithToken = "with" !IdentifierPart
/* Skipped */ // Skipped
__ __
= (WhiteSpace / LineTerminatorSequence / Comment)* = (WhiteSpace / LineTerminatorSequence / Comment)*
@ -550,7 +544,7 @@ __
_ _
= (WhiteSpace / MultiLineCommentNoLineTerminator)* = (WhiteSpace / MultiLineCommentNoLineTerminator)*
/* Automatic Semicolon Insertion */ // Automatic Semicolon Insertion
EOS EOS
= __ ";" = __ ";"

Loading…
Cancel
Save