Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

pegjs

Package Overview
Dependencies
Maintainers
1
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pegjs - npm Package Compare versions

Comparing version 0.8.0 to 0.9.0

lib/compiler/asts.js

75

CHANGELOG.md

@@ -0,1 +1,76 @@

Change Log
==========
This file documents all notable changes to PEG.js. The releases follow [semantic
versioning](http://semver.org/).
0.9.0
-----
Released: August 30, 2015
### Major Changes
* **Tracing support.** Parsers can be compiled with support for tracing their
progress, which can help debugging complex grammars. This feature is
experimental and is expected to evolve over time as experience is gained.
[More details](https://github.com/pegjs/pegjs/commit/da57118a43a904f753d44d407994cf0b36358adc)
* **Infinite loop detection.** Grammar constructs that could cause infinite
loops in generated parsers are detected during compilation and cause errors.
* **Improved location information API.** The `line`, `column`, and `offset`
functions available in parser code were replaced by a single `location`
function which returns an object describing the current location. Similarly,
the `line`, `column`, and `offset` properties of exceptions were replaced by
a single `location` property. The location is no longer a single point but a
character range, which is meaningful mainly in actions where the range
covers action’s expression.
[More details](https://github.com/pegjs/pegjs/compare/e75f21dc8f0e66b3d87c4c19b3fcb8f89d9c3acd...eaca5f0acf97b66ef141fed84aa95d4e72e33757)
* **Improved error reporting.** All exceptions thrown when generating a parser
have associated location information. And all exceptions thrown by generated
parser and PEG.js itself have a stack trace (the `stack` property) in
environments that support `Error.captureStackTrace`.
* **Strict mode code**. All PEG.js and generated parser code is written using
[JavaScript strict mode](https://developer.mozilla.org/cs/docs/Web/JavaScript/Reference/Strict_mode).
### Minor Changes
* Labels behave like block-scoped variables. This means parser code can see
labels defined outside expressions containing code.
* Empty sequences are no longer allowed.
* Label names can’t be JavaScript reserved words.
* Rule and label names can contain Unicode characters like in JavaScript.
* Rules have to be separated either by `;` or a newline (until now, any
whitespace was enough).
* The PEG.js grammar and all the example grammars were completely rewritten.
This rewrite included a number of cleanups, formatting changes, naming
changes, and bug fixes.
* The parser object can now be accessed as `parser` in parser code.
* Location information computation is faster.
* Added support for Node.js >= 0.10.x, io.js, and Edge. Removed support for
Node.js < 0.10.x.
### Bug Fixes
* Fixed left recursion detector which missed many cases.
* Fixed escaping of U+0100—U+107F and U+1000—U+107F in generated code and
error messages.
* Renamed `parse` and `SyntaxError` to `peg$parse` and `peg$SyntaxError` to
mark them as internal identifiers.
[Complete set of changes](https://github.com/pegjs/pegjs/compare/v0.8.0...v0.9.0)
0.8.0

@@ -2,0 +77,0 @@ -----

27

lib/compiler.js

@@ -1,4 +0,7 @@

var utils = require("./utils");
"use strict";
module.exports = {
var arrays = require("./utils/arrays"),
objects = require("./utils/objects");
var compiler = {
/*

@@ -14,3 +17,4 @@ * Compiler passes.

reportMissingRules: require("./compiler/passes/report-missing-rules"),
reportLeftRecursion: require("./compiler/passes/report-left-recursion")
reportLeftRecursion: require("./compiler/passes/report-left-recursion"),
reportInfiniteLoops: require("./compiler/passes/report-infinite-loops")
},

@@ -33,16 +37,9 @@ transform: {

compile: function(ast, passes) {
var options = arguments.length > 2 ? utils.clone(arguments[2]) : {},
var options = arguments.length > 2 ? objects.clone(arguments[2]) : {},
stage;
/*
* Extracted into a function just to silence JSHint complaining about
* creating functions in a loop.
*/
function runPass(pass) {
pass(ast, options);
}
utils.defaults(options, {
objects.defaults(options, {
allowedStartRules: [ast.rules[0].name],
cache: false,
trace: false,
optimize: "speed",

@@ -54,3 +51,3 @@ output: "parser"

if (passes.hasOwnProperty(stage)) {
utils.each(passes[stage], runPass);
arrays.each(passes[stage], function(p) { p(ast, options); });
}

@@ -65,1 +62,3 @@ }

};
module.exports = compiler;

@@ -0,46 +1,54 @@

"use strict";
/* Bytecode instruction opcodes. */
module.exports = {
var opcodes = {
/* Stack Manipulation */
PUSH: 0, // PUSH c
PUSH_CURR_POS: 1, // PUSH_CURR_POS
POP: 2, // POP
POP_CURR_POS: 3, // POP_CURR_POS
POP_N: 4, // POP_N n
NIP: 5, // NIP
APPEND: 6, // APPEND
WRAP: 7, // WRAP n
TEXT: 8, // TEXT
PUSH_UNDEFINED: 1, // PUSH_UNDEFINED
PUSH_NULL: 2, // PUSH_NULL
PUSH_FAILED: 3, // PUSH_FAILED
PUSH_EMPTY_ARRAY: 4, // PUSH_EMPTY_ARRAY
PUSH_CURR_POS: 5, // PUSH_CURR_POS
POP: 6, // POP
POP_CURR_POS: 7, // POP_CURR_POS
POP_N: 8, // POP_N n
NIP: 9, // NIP
APPEND: 10, // APPEND
WRAP: 11, // WRAP n
TEXT: 12, // TEXT
/* Conditions and Loops */
IF: 9, // IF t, f
IF_ERROR: 10, // IF_ERROR t, f
IF_NOT_ERROR: 11, // IF_NOT_ERROR t, f
WHILE_NOT_ERROR: 12, // WHILE_NOT_ERROR b
IF: 13, // IF t, f
IF_ERROR: 14, // IF_ERROR t, f
IF_NOT_ERROR: 15, // IF_NOT_ERROR t, f
WHILE_NOT_ERROR: 16, // WHILE_NOT_ERROR b
/* Matching */
MATCH_ANY: 13, // MATCH_ANY a, f, ...
MATCH_STRING: 14, // MATCH_STRING s, a, f, ...
MATCH_STRING_IC: 15, // MATCH_STRING_IC s, a, f, ...
MATCH_REGEXP: 16, // MATCH_REGEXP r, a, f, ...
ACCEPT_N: 17, // ACCEPT_N n
ACCEPT_STRING: 18, // ACCEPT_STRING s
FAIL: 19, // FAIL e
MATCH_ANY: 17, // MATCH_ANY a, f, ...
MATCH_STRING: 18, // MATCH_STRING s, a, f, ...
MATCH_STRING_IC: 19, // MATCH_STRING_IC s, a, f, ...
MATCH_REGEXP: 20, // MATCH_REGEXP r, a, f, ...
ACCEPT_N: 21, // ACCEPT_N n
ACCEPT_STRING: 22, // ACCEPT_STRING s
FAIL: 23, // FAIL e
/* Calls */
REPORT_SAVED_POS: 20, // REPORT_SAVED_POS p
REPORT_CURR_POS: 21, // REPORT_CURR_POS
CALL: 22, // CALL f, n, pc, p1, p2, ..., pN
LOAD_SAVED_POS: 24, // LOAD_SAVED_POS p
UPDATE_SAVED_POS: 25, // UPDATE_SAVED_POS
CALL: 26, // CALL f, n, pc, p1, p2, ..., pN
/* Rules */
RULE: 23, // RULE r
RULE: 27, // RULE r
/* Failure Reporting */
SILENT_FAILS_ON: 24, // SILENT_FAILS_ON
SILENT_FAILS_OFF: 25 // SILENT_FAILS_FF
SILENT_FAILS_ON: 28, // SILENT_FAILS_ON
SILENT_FAILS_OFF: 29 // SILENT_FAILS_OFF
};
module.exports = opcodes;

@@ -1,4 +0,10 @@

var utils = require("../../utils"),
op = require("../opcodes");
"use strict";
var arrays = require("../../utils/arrays"),
objects = require("../../utils/objects"),
asts = require("../asts"),
visitor = require("../visitor"),
op = require("../opcodes"),
js = require("../javascript");
/* Generates bytecode.

@@ -16,19 +22,35 @@ *

*
* [1] PUSH_CURR_POS
* [1] PUSH_UNDEFINED
*
* stack.push(undefined);
*
* [2] PUSH_NULL
*
* stack.push(null);
*
* [3] PUSH_FAILED
*
* stack.push(FAILED);
*
* [4] PUSH_EMPTY_ARRAY
*
* stack.push([]);
*
* [5] PUSH_CURR_POS
*
* stack.push(currPos);
*
* [2] POP
* [6] POP
*
* stack.pop();
*
* [3] POP_CURR_POS
* [7] POP_CURR_POS
*
* currPos = stack.pop();
*
* [4] POP_N n
* [8] POP_N n
*
* stack.pop(n);
*
* [5] NIP
* [9] NIP
*

@@ -39,3 +61,3 @@ * value = stack.pop();

*
* [6] APPEND
* [10] APPEND
*

@@ -47,10 +69,9 @@ * value = stack.pop();

*
* [7] WRAP n
* [11] WRAP n
*
* stack.push(stack.pop(n));
*
* [8] TEXT
* [12] TEXT
*
* stack.pop();
* stack.push(input.substring(stack.top(), currPos));
* stack.push(input.substring(stack.pop(), currPos));
*

@@ -60,3 +81,3 @@ * Conditions and Loops

*
* [9] IF t, f
* [13] IF t, f
*

@@ -69,3 +90,3 @@ * if (stack.top()) {

*
* [10] IF_ERROR t, f
* [14] IF_ERROR t, f
*

@@ -78,3 +99,3 @@ * if (stack.top() === FAILED) {

*
* [11] IF_NOT_ERROR t, f
* [15] IF_NOT_ERROR t, f
*

@@ -87,3 +108,3 @@ * if (stack.top() !== FAILED) {

*
* [12] WHILE_NOT_ERROR b
* [16] WHILE_NOT_ERROR b
*

@@ -97,3 +118,3 @@ * while(stack.top() !== FAILED) {

*
* [13] MATCH_ANY a, f, ...
* [17] MATCH_ANY a, f, ...
*

@@ -106,3 +127,3 @@ * if (input.length > currPos) {

*
* [14] MATCH_STRING s, a, f, ...
* [18] MATCH_STRING s, a, f, ...
*

@@ -115,3 +136,3 @@ * if (input.substr(currPos, consts[s].length) === consts[s]) {

*
* [15] MATCH_STRING_IC s, a, f, ...
* [19] MATCH_STRING_IC s, a, f, ...
*

@@ -124,3 +145,3 @@ * if (input.substr(currPos, consts[s].length).toLowerCase() === consts[s]) {

*
* [16] MATCH_REGEXP r, a, f, ...
* [20] MATCH_REGEXP r, a, f, ...
*

@@ -133,3 +154,3 @@ * if (consts[r].test(input.charAt(currPos))) {

*
* [17] ACCEPT_N n
* [21] ACCEPT_N n
*

@@ -139,3 +160,3 @@ * stack.push(input.substring(currPos, n));

*
* [18] ACCEPT_STRING s
* [22] ACCEPT_STRING s
*

@@ -145,3 +166,3 @@ * stack.push(consts[s]);

*
* [19] FAIL e
* [23] FAIL e
*

@@ -154,11 +175,11 @@ * stack.push(FAILED);

*
* [20] REPORT_SAVED_POS p
* [24] LOAD_SAVED_POS p
*
* reportedPos = stack[p];
* savedPos = stack[p];
*
* [21] REPORT_CURR_POS
* [25] UPDATE_SAVED_POS
*
* reportedPos = currPos;
* savedPos = currPos;
*
* [22] CALL f, n, pc, p1, p2, ..., pN
* [26] CALL f, n, pc, p1, p2, ..., pN
*

@@ -172,3 +193,3 @@ * value = consts[f](stack[p1], ..., stack[pN]);

*
* [23] RULE r
* [27] RULE r
*

@@ -180,15 +201,15 @@ * stack.push(parseRule(r));

*
* [24] SILENT_FAILS_ON
* [28] SILENT_FAILS_ON
*
* silentFails++;
*
* [25] SILENT_FAILS_OFF
* [29] SILENT_FAILS_OFF
*
* silentFails--;
*/
module.exports = function(ast) {
function generateBytecode(ast) {
var consts = [];
function addConst(value) {
var index = utils.indexOf(consts, function(c) { return c === value; });
var index = arrays.indexOf(consts, value);

@@ -221,3 +242,3 @@ return index === -1 ? consts.push(value) - 1 : index;

function buildCall(functionIndex, delta, env, sp) {
var params = utils.map( utils.values(env), function(p) { return sp - p; });
var params = arrays.map(objects.values(env), function(p) { return sp - p; });

@@ -228,5 +249,2 @@ return [op.CALL, functionIndex, delta, params.length].concat(params);

function buildSimplePredicate(expression, negative, context) {
var undefinedIndex = addConst('void 0'),
failedIndex = addConst('peg$FAILED');
return buildSequence(

@@ -237,3 +255,3 @@ [op.PUSH_CURR_POS],

sp: context.sp + 1,
env: { },
env: objects.clone(context.env),
action: null

@@ -247,3 +265,3 @@ }),

[negative ? op.POP : op.POP_CURR_POS],
[op.PUSH, undefinedIndex]
[op.PUSH_UNDEFINED]
),

@@ -253,3 +271,3 @@ buildSequence(

[negative ? op.POP_CURR_POS : op.POP],
[op.PUSH, failedIndex]
[op.PUSH_FAILED]
)

@@ -261,8 +279,6 @@ )

function buildSemanticPredicate(code, negative, context) {
var functionIndex = addFunctionConst(utils.keys(context.env), code),
undefinedIndex = addConst('void 0'),
failedIndex = addConst('peg$FAILED');
var functionIndex = addFunctionConst(objects.keys(context.env), code);
return buildSequence(
[op.REPORT_CURR_POS],
[op.UPDATE_SAVED_POS],
buildCall(functionIndex, 0, context.env, context.sp),

@@ -273,7 +289,7 @@ buildCondition(

[op.POP],
[op.PUSH, negative ? failedIndex : undefinedIndex]
negative ? [op.PUSH_FAILED] : [op.PUSH_UNDEFINED]
),
buildSequence(
[op.POP],
[op.PUSH, negative ? undefinedIndex : failedIndex]
negative ? [op.PUSH_UNDEFINED] : [op.PUSH_FAILED]
)

@@ -291,5 +307,5 @@ )

var generate = utils.buildNodeVisitor({
var generate = visitor.build({
grammar: function(node) {
utils.each(node.rules, generate);
arrays.each(node.rules, generate);

@@ -301,5 +317,5 @@ node.consts = consts;

node.bytecode = generate(node.expression, {
sp: -1, // stack pointer
env: { }, // mapping of label names to stack positions
action: null // action nodes pass themselves to children here
sp: -1, // stack pointer
env: { }, // mapping of label names to stack positions
action: null // action nodes pass themselves to children here
});

@@ -310,3 +326,3 @@ },

var nameIndex = addConst(
'{ type: "other", description: ' + utils.quote(node.name) + ' }'
'{ type: "other", description: "' + js.stringEscape(node.name) + '" }'
);

@@ -333,3 +349,3 @@

sp: context.sp,
env: { },
env: objects.clone(context.env),
action: null

@@ -354,3 +370,3 @@ }),

action: function(node, context) {
var env = { },
var env = objects.clone(context.env),
emitCall = node.expression.type !== "sequence"

@@ -363,3 +379,3 @@ || node.expression.elements.length === 0,

}),
functionIndex = addFunctionConst(utils.keys(env), node.code);
functionIndex = addFunctionConst(objects.keys(env), node.code);

@@ -373,3 +389,3 @@ return emitCall

buildSequence(
[op.REPORT_SAVED_POS, 1],
[op.LOAD_SAVED_POS, 1],
buildCall(functionIndex, 1, env, context.sp + 2)

@@ -385,4 +401,2 @@ ),

sequence: function(node, context) {
var emptyArrayIndex;
function buildElementsCode(elements, context) {

@@ -410,3 +424,3 @@ var processedCount, functionIndex;

[op.POP_CURR_POS],
[op.PUSH, failedIndex]
[op.PUSH_FAILED]
)

@@ -418,3 +432,3 @@ )

functionIndex = addFunctionConst(
utils.keys(context.env),
objects.keys(context.env),
context.action.code

@@ -424,3 +438,3 @@ );

return buildSequence(
[op.REPORT_SAVED_POS, node.elements.length],
[op.LOAD_SAVED_POS, node.elements.length],
buildCall(

@@ -440,21 +454,15 @@ functionIndex,

if (node.elements.length > 0) {
failedIndex = addConst('peg$FAILED');
return buildSequence(
[op.PUSH_CURR_POS],
buildElementsCode(node.elements, {
sp: context.sp + 1,
env: context.env,
action: context.action
})
);
} else {
emptyArrayIndex = addConst('[]');
return [op.PUSH, emptyArrayIndex];
}
return buildSequence(
[op.PUSH_CURR_POS],
buildElementsCode(node.elements, {
sp: context.sp + 1,
env: context.env,
action: context.action
})
);
},
labeled: function(node, context) {
var env = objects.clone(context.env);
context.env[node.label] = context.sp + 1;

@@ -464,3 +472,3 @@

sp: context.sp,
env: { },
env: env,
action: null

@@ -475,7 +483,10 @@ });

sp: context.sp + 1,
env: { },
env: objects.clone(context.env),
action: null
}),
buildCondition([op.IF_NOT_ERROR], [op.TEXT], []),
[op.NIP]
buildCondition(
[op.IF_NOT_ERROR],
buildSequence([op.POP], [op.TEXT]),
[op.NIP]
)
);

@@ -492,17 +503,7 @@ },

semantic_and: function(node, context) {
return buildSemanticPredicate(node.code, false, context);
},
semantic_not: function(node, context) {
return buildSemanticPredicate(node.code, true, context);
},
optional: function(node, context) {
var nullIndex = addConst('null');
return buildSequence(
generate(node.expression, {
sp: context.sp,
env: { },
env: objects.clone(context.env),
action: null

@@ -512,3 +513,3 @@ }),

[op.IF_ERROR],
buildSequence([op.POP], [op.PUSH, nullIndex]),
buildSequence([op.POP], [op.PUSH_NULL]),
[]

@@ -520,6 +521,5 @@ )

zero_or_more: function(node, context) {
var emptyArrayIndex = addConst('[]');
expressionCode = generate(node.expression, {
var expressionCode = generate(node.expression, {
sp: context.sp + 1,
env: { },
env: objects.clone(context.env),
action: null

@@ -529,3 +529,3 @@ });

return buildSequence(
[op.PUSH, emptyArrayIndex],
[op.PUSH_EMPTY_ARRAY],
expressionCode,

@@ -538,7 +538,5 @@ buildAppendLoop(expressionCode),

one_or_more: function(node, context) {
var emptyArrayIndex = addConst('[]');
failedIndex = addConst('peg$FAILED');
expressionCode = generate(node.expression, {
var expressionCode = generate(node.expression, {
sp: context.sp + 1,
env: { },
env: objects.clone(context.env),
action: null

@@ -548,3 +546,3 @@ });

return buildSequence(
[op.PUSH, emptyArrayIndex],
[op.PUSH_EMPTY_ARRAY],
expressionCode,

@@ -554,3 +552,3 @@ buildCondition(

buildSequence(buildAppendLoop(expressionCode), [op.POP]),
buildSequence([op.POP], [op.POP], [op.PUSH, failedIndex])
buildSequence([op.POP], [op.POP], [op.PUSH_FAILED])
)

@@ -560,4 +558,12 @@ );

semantic_and: function(node, context) {
return buildSemanticPredicate(node.code, false, context);
},
semantic_not: function(node, context) {
return buildSemanticPredicate(node.code, true, context);
},
rule_ref: function(node) {
return [op.RULE, utils.indexOfRuleByName(ast, node.name)];
return [op.RULE, asts.indexOfRule(ast, node.name)];
},

@@ -569,5 +575,7 @@

if (node.value.length > 0) {
stringIndex = addConst(node.ignoreCase
? utils.quote(node.value.toLowerCase())
: utils.quote(node.value)
stringIndex = addConst('"'
+ js.stringEscape(
node.ignoreCase ? node.value.toLowerCase() : node.value
)
+ '"'
);

@@ -577,4 +585,6 @@ expectedIndex = addConst([

'type: "literal",',
'value: ' + utils.quote(node.value) + ',',
'description: ' + utils.quote(utils.quote(node.value)),
'value: "' + js.stringEscape(node.value) + '",',
'description: "'
+ js.stringEscape('"' + js.stringEscape(node.value) + '"')
+ '"',
'}'

@@ -610,8 +620,8 @@ ].join(' '));

+ (node.inverted ? '^' : '')
+ utils.map(node.parts, function(part) {
+ arrays.map(node.parts, function(part) {
return part instanceof Array
? utils.quoteForRegexpClass(part[0])
? js.regexpClassEscape(part[0])
+ '-'
+ utils.quoteForRegexpClass(part[1])
: utils.quoteForRegexpClass(part);
+ js.regexpClassEscape(part[1])
: js.regexpClassEscape(part);
}).join('')

@@ -631,4 +641,4 @@ + ']/' + (node.ignoreCase ? 'i' : '');

'type: "class",',
'value: ' + utils.quote(node.rawText) + ',',
'description: ' + utils.quote(node.rawText),
'value: "' + js.stringEscape(node.rawText) + '",',
'description: "' + js.stringEscape(node.rawText) + '"',
'}'

@@ -656,2 +666,4 @@ ].join(' '));

generate(ast);
};
}
module.exports = generateBytecode;

@@ -1,6 +0,10 @@

var utils = require("../../utils"),
op = require("../opcodes");
"use strict";
var arrays = require("../../utils/arrays"),
asts = require("../asts"),
op = require("../opcodes"),
js = require("../javascript");
/* Generates parser JavaScript code. */
module.exports = function(ast, options) {
function generateJavascript(ast, options) {
/* These only indent non-empty lines to avoid trailing whitespace. */

@@ -20,17 +24,14 @@ function indent2(code) { return code.replace(/^(.+)$/gm, ' $1'); }

'peg$bytecode = [',
indent2(utils.map(
ast.rules,
function(rule) {
return 'peg$decode('
+ utils.quote(utils.map(
rule.bytecode,
function(b) { return String.fromCharCode(b + 32); }
).join(''))
+ ')';
}
).join(',\n')),
indent2(arrays.map(ast.rules, function(rule) {
return 'peg$decode("'
+ js.stringEscape(arrays.map(
rule.bytecode,
function(b) { return String.fromCharCode(b + 32); }
).join(''))
+ '")';
}).join(',\n')),
'],'
].join('\n');
} else {
return utils.map(
return arrays.map(
ast.consts,

@@ -42,20 +43,94 @@ function(c, i) { return 'peg$c' + i + ' = ' + c + ','; }

function generateCacheHeader(ruleIndexCode) {
return [
'var key = peg$currPos * ' + ast.rules.length + ' + ' + ruleIndexCode + ',',
' cached = peg$cache[key];',
'',
'if (cached) {',
' peg$currPos = cached.nextPos;',
' return cached.result;',
'}',
''
].join('\n');
function generateRuleHeader(ruleNameCode, ruleIndexCode) {
var parts = [];
parts.push('');
if (options.trace) {
parts.push([
'peg$tracer.trace({',
' type: "rule.enter",',
' rule: ' + ruleNameCode + ',',
' location: peg$computeLocation(startPos, startPos)',
'});',
''
].join('\n'));
}
if (options.cache) {
parts.push([
'var key = peg$currPos * ' + ast.rules.length + ' + ' + ruleIndexCode + ',',
' cached = peg$resultsCache[key];',
'',
'if (cached) {',
' peg$currPos = cached.nextPos;',
'',
].join('\n'));
if (options.trace) {
parts.push([
'if (cached.result !== peg$FAILED) {',
' peg$tracer.trace({',
' type: "rule.match",',
' rule: ' + ruleNameCode + ',',
' result: cached.result,',
' location: peg$computeLocation(startPos, peg$currPos)',
' });',
'} else {',
' peg$tracer.trace({',
' type: "rule.fail",',
' rule: ' + ruleNameCode + ',',
' location: peg$computeLocation(startPos, startPos)',
' });',
'}',
''
].join('\n'));
}
parts.push([
' return cached.result;',
'}',
''
].join('\n'));
}
return parts.join('\n');
}
function generateCacheFooter(resultCode) {
return [
function generateRuleFooter(ruleNameCode, resultCode) {
var parts = [];
if (options.cache) {
parts.push([
'',
'peg$resultsCache[key] = { nextPos: peg$currPos, result: ' + resultCode + ' };'
].join('\n'));
}
if (options.trace) {
parts.push([
'',
'if (' + resultCode + ' !== peg$FAILED) {',
' peg$tracer.trace({',
' type: "rule.match",',
' rule: ' + ruleNameCode + ',',
' result: ' + resultCode + ',',
' location: peg$computeLocation(startPos, peg$currPos)',
' });',
'} else {',
' peg$tracer.trace({',
' type: "rule.fail",',
' rule: ' + ruleNameCode + ',',
' location: peg$computeLocation(startPos, startPos)',
' });',
'}'
].join('\n'));
}
parts.push([
'',
'peg$cache[key] = { nextPos: peg$currPos, result: ' + resultCode + ' };'
].join('\n');
'return ' + resultCode + ';'
].join('\n'));
return parts.join('\n');
}

@@ -139,21 +214,30 @@

'function peg$parseRule(index) {',
' var bc = peg$bytecode[index],',
' ip = 0,',
' ips = [],',
' end = bc.length,',
' ends = [],',
' stack = [],',
' params, i;',
''
].join('\n'));
if (options.cache) {
parts.push(indent2(generateCacheHeader('index')));
if (options.trace) {
parts.push([
' var bc = peg$bytecode[index],',
' ip = 0,',
' ips = [],',
' end = bc.length,',
' ends = [],',
' stack = [],',
' startPos = peg$currPos,',
' params, i;',
].join('\n'));
} else {
parts.push([
' var bc = peg$bytecode[index],',
' ip = 0,',
' ips = [],',
' end = bc.length,',
' ends = [],',
' stack = [],',
' params, i;',
].join('\n'));
}
parts.push(indent2(generateRuleHeader('peg$ruleNames[index]', 'index')));
parts.push([
' function protect(object) {',
' return Object.prototype.toString.apply(object) === "[object Array]" ? [] : object;',
' }',
'',
/*

@@ -169,12 +253,28 @@ * The point of the outer loop and the |ips| & |ends| stacks is to avoid

' switch (bc[ip]) {',
' case ' + op.PUSH + ':', // PUSH c
/*
* Hack: One of the constants can be an empty array. It needs to be cloned
* because it can be modified later on the stack by |APPEND|.
*/
' stack.push(protect(peg$consts[bc[ip + 1]]));',
' case ' + op.PUSH + ':', // PUSH c
' stack.push(peg$consts[bc[ip + 1]]);',
' ip += 2;',
' break;',
'',
' case ' + op.PUSH_CURR_POS + ':', // PUSH_CURR_POS
' case ' + op.PUSH_UNDEFINED + ':', // PUSH_UNDEFINED
' stack.push(void 0);',
' ip++;',
' break;',
'',
' case ' + op.PUSH_NULL + ':', // PUSH_NULL
' stack.push(null);',
' ip++;',
' break;',
'',
' case ' + op.PUSH_FAILED + ':', // PUSH_FAILED
' stack.push(peg$FAILED);',
' ip++;',
' break;',
'',
' case ' + op.PUSH_EMPTY_ARRAY + ':', // PUSH_EMPTY_ARRAY
' stack.push([]);',
' ip++;',
' break;',
'',
' case ' + op.PUSH_CURR_POS + ':', // PUSH_CURR_POS
' stack.push(peg$currPos);',

@@ -184,3 +284,3 @@ ' ip++;',

'',
' case ' + op.POP + ':', // POP
' case ' + op.POP + ':', // POP
' stack.pop();',

@@ -190,3 +290,3 @@ ' ip++;',

'',
' case ' + op.POP_CURR_POS + ':', // POP_CURR_POS
' case ' + op.POP_CURR_POS + ':', // POP_CURR_POS
' peg$currPos = stack.pop();',

@@ -196,3 +296,3 @@ ' ip++;',

'',
' case ' + op.POP_N + ':', // POP_N n
' case ' + op.POP_N + ':', // POP_N n
' stack.length -= bc[ip + 1];',

@@ -202,3 +302,3 @@ ' ip += 2;',

'',
' case ' + op.NIP + ':', // NIP
' case ' + op.NIP + ':', // NIP
' stack.splice(-2, 1);',

@@ -208,3 +308,3 @@ ' ip++;',

'',
' case ' + op.APPEND + ':', // APPEND
' case ' + op.APPEND + ':', // APPEND
' stack[stack.length - 2].push(stack.pop());',

@@ -214,3 +314,3 @@ ' ip++;',

'',
' case ' + op.WRAP + ':', // WRAP n
' case ' + op.WRAP + ':', // WRAP n
' stack.push(stack.splice(stack.length - bc[ip + 1], bc[ip + 1]));',

@@ -220,12 +320,11 @@ ' ip += 2;',

'',
' case ' + op.TEXT + ':', // TEXT
' stack.pop();',
' stack.push(input.substring(stack[stack.length - 1], peg$currPos));',
' case ' + op.TEXT + ':', // TEXT
' stack.push(input.substring(stack.pop(), peg$currPos));',
' ip++;',
' break;',
'',
' case ' + op.IF + ':', // IF t, f
' case ' + op.IF + ':', // IF t, f
indent10(generateCondition('stack[stack.length - 1]', 0)),
'',
' case ' + op.IF_ERROR + ':', // IF_ERROR t, f
' case ' + op.IF_ERROR + ':', // IF_ERROR t, f
indent10(generateCondition(

@@ -236,3 +335,3 @@ 'stack[stack.length - 1] === peg$FAILED',

'',
' case ' + op.IF_NOT_ERROR + ':', // IF_NOT_ERROR t, f
' case ' + op.IF_NOT_ERROR + ':', // IF_NOT_ERROR t, f
indent10(

@@ -243,9 +342,9 @@ generateCondition('stack[stack.length - 1] !== peg$FAILED',

'',
' case ' + op.WHILE_NOT_ERROR + ':', // WHILE_NOT_ERROR b
' case ' + op.WHILE_NOT_ERROR + ':', // WHILE_NOT_ERROR b
indent10(generateLoop('stack[stack.length - 1] !== peg$FAILED')),
'',
' case ' + op.MATCH_ANY + ':', // MATCH_ANY a, f, ...
' case ' + op.MATCH_ANY + ':', // MATCH_ANY a, f, ...
indent10(generateCondition('input.length > peg$currPos', 0)),
'',
' case ' + op.MATCH_STRING + ':', // MATCH_STRING s, a, f, ...
' case ' + op.MATCH_STRING + ':', // MATCH_STRING s, a, f, ...
indent10(generateCondition(

@@ -256,3 +355,3 @@ 'input.substr(peg$currPos, peg$consts[bc[ip + 1]].length) === peg$consts[bc[ip + 1]]',

'',
' case ' + op.MATCH_STRING_IC + ':', // MATCH_STRING_IC s, a, f, ...
' case ' + op.MATCH_STRING_IC + ':', // MATCH_STRING_IC s, a, f, ...
indent10(generateCondition(

@@ -263,3 +362,3 @@ 'input.substr(peg$currPos, peg$consts[bc[ip + 1]].length).toLowerCase() === peg$consts[bc[ip + 1]]',

'',
' case ' + op.MATCH_REGEXP + ':', // MATCH_REGEXP r, a, f, ...
' case ' + op.MATCH_REGEXP + ':', // MATCH_REGEXP r, a, f, ...
indent10(generateCondition(

@@ -270,3 +369,3 @@ 'peg$consts[bc[ip + 1]].test(input.charAt(peg$currPos))',

'',
' case ' + op.ACCEPT_N + ':', // ACCEPT_N n
' case ' + op.ACCEPT_N + ':', // ACCEPT_N n
' stack.push(input.substr(peg$currPos, bc[ip + 1]));',

@@ -277,3 +376,3 @@ ' peg$currPos += bc[ip + 1];',

'',
' case ' + op.ACCEPT_STRING + ':', // ACCEPT_STRING s
' case ' + op.ACCEPT_STRING + ':', // ACCEPT_STRING s
' stack.push(peg$consts[bc[ip + 1]]);',

@@ -284,3 +383,3 @@ ' peg$currPos += peg$consts[bc[ip + 1]].length;',

'',
' case ' + op.FAIL + ':', // FAIL e
' case ' + op.FAIL + ':', // FAIL e
' stack.push(peg$FAILED);',

@@ -293,16 +392,16 @@ ' if (peg$silentFails === 0) {',

'',
' case ' + op.REPORT_SAVED_POS + ':', // REPORT_SAVED_POS p
' peg$reportedPos = stack[stack.length - 1 - bc[ip + 1]];',
' case ' + op.LOAD_SAVED_POS + ':', // LOAD_SAVED_POS p
' peg$savedPos = stack[stack.length - 1 - bc[ip + 1]];',
' ip += 2;',
' break;',
'',
' case ' + op.REPORT_CURR_POS + ':', // REPORT_CURR_POS
' peg$reportedPos = peg$currPos;',
' case ' + op.UPDATE_SAVED_POS + ':', // UPDATE_SAVED_POS
' peg$savedPos = peg$currPos;',
' ip++;',
' break;',
'',
' case ' + op.CALL + ':', // CALL f, n, pc, p1, p2, ..., pN
' case ' + op.CALL + ':', // CALL f, n, pc, p1, p2, ..., pN
indent10(generateCall()),
'',
' case ' + op.RULE + ':', // RULE r
' case ' + op.RULE + ':', // RULE r
' stack.push(peg$parseRule(bc[ip + 1]));',

@@ -312,3 +411,3 @@ ' ip += 2;',

'',
' case ' + op.SILENT_FAILS_ON + ':', // SILENT_FAILS_ON
' case ' + op.SILENT_FAILS_ON + ':', // SILENT_FAILS_ON
' peg$silentFails++;',

@@ -318,3 +417,3 @@ ' ip++;',

'',
' case ' + op.SILENT_FAILS_OFF + ':', // SILENT_FAILS_OFF
' case ' + op.SILENT_FAILS_OFF + ':', // SILENT_FAILS_OFF
' peg$silentFails--;',

@@ -338,12 +437,5 @@ ' ip++;',

if (options.cache) {
parts.push(indent2(generateCacheFooter('stack[0]')));
}
parts.push(indent2(generateRuleFooter('peg$ruleNames[index]', 'stack[0]')));
parts.push('}');
parts.push([
'',
' return stack[0];',
'}'
].join('\n'));
return parts.join('\n');

@@ -377,3 +469,3 @@ }

n = arguments[0];
values = utils.map(utils.range(this.sp - n + 1, this.sp + 1), s);
values = arrays.map(arrays.range(this.sp - n + 1, this.sp + 1), s);
this.sp -= n;

@@ -459,5 +551,5 @@

var value = c(bc[ip + 1]) + '('
+ utils.map(
+ arrays.map(
bc.slice(ip + baseLength, ip + baseLength + paramsLength),
stackIndex
function(p) { return stack.index(p); }
).join(', ')

@@ -470,25 +562,10 @@ + ')';

/*
* Extracted into a function just to silence JSHint complaining about
* creating functions in a loop.
*/
function stackIndex(p) {
return stack.index(p);
}
while (ip < end) {
switch (bc[ip]) {
case op.PUSH: // PUSH c
/*
* Hack: One of the constants can be an empty array. It needs to be
* handled specially because it can be modified later on the stack
* by |APPEND|.
*/
parts.push(
stack.push(ast.consts[bc[ip + 1]] === "[]" ? "[]" : c(bc[ip + 1]))
);
case op.PUSH: // PUSH c
parts.push(stack.push(c(bc[ip + 1])));
ip += 2;
break;
case op.PUSH_CURR_POS: // PUSH_CURR_POS
case op.PUSH_CURR_POS: // PUSH_CURR_POS
parts.push(stack.push('peg$currPos'));

@@ -498,3 +575,23 @@ ip++;

case op.POP: // POP
case op.PUSH_UNDEFINED: // PUSH_UNDEFINED
parts.push(stack.push('void 0'));
ip++;
break;
case op.PUSH_NULL: // PUSH_NULL
parts.push(stack.push('null'));
ip++;
break;
case op.PUSH_FAILED: // PUSH_FAILED
parts.push(stack.push('peg$FAILED'));
ip++;
break;
case op.PUSH_EMPTY_ARRAY: // PUSH_EMPTY_ARRAY
parts.push(stack.push('[]'));
ip++;
break;
case op.POP: // POP
stack.pop();

@@ -504,3 +601,3 @@ ip++;

case op.POP_CURR_POS: // POP_CURR_POS
case op.POP_CURR_POS: // POP_CURR_POS
parts.push('peg$currPos = ' + stack.pop() + ';');

@@ -510,3 +607,3 @@ ip++;

case op.POP_N: // POP_N n
case op.POP_N: // POP_N n
stack.pop(bc[ip + 1]);

@@ -516,3 +613,3 @@ ip += 2;

case op.NIP: // NIP
case op.NIP: // NIP
value = stack.pop();

@@ -524,3 +621,3 @@ stack.pop();

case op.APPEND: // APPEND
case op.APPEND: // APPEND
value = stack.pop();

@@ -531,3 +628,3 @@ parts.push(stack.top() + '.push(' + value + ');');

case op.WRAP: // WRAP n
case op.WRAP: // WRAP n
parts.push(

@@ -539,6 +636,5 @@ stack.push('[' + stack.pop(bc[ip + 1]).join(', ') + ']')

case op.TEXT: // TEXT
stack.pop();
case op.TEXT: // TEXT
parts.push(
stack.push('input.substring(' + stack.top() + ', peg$currPos)')
stack.push('input.substring(' + stack.pop() + ', peg$currPos)')
);

@@ -548,23 +644,23 @@ ip++;

case op.IF: // IF t, f
case op.IF: // IF t, f
compileCondition(stack.top(), 0);
break;
case op.IF_ERROR: // IF_ERROR t, f
case op.IF_ERROR: // IF_ERROR t, f
compileCondition(stack.top() + ' === peg$FAILED', 0);
break;
case op.IF_NOT_ERROR: // IF_NOT_ERROR t, f
case op.IF_NOT_ERROR: // IF_NOT_ERROR t, f
compileCondition(stack.top() + ' !== peg$FAILED', 0);
break;
case op.WHILE_NOT_ERROR: // WHILE_NOT_ERROR b
case op.WHILE_NOT_ERROR: // WHILE_NOT_ERROR b
compileLoop(stack.top() + ' !== peg$FAILED', 0);
break;
case op.MATCH_ANY: // MATCH_ANY a, f, ...
case op.MATCH_ANY: // MATCH_ANY a, f, ...
compileCondition('input.length > peg$currPos', 0);
break;
case op.MATCH_STRING: // MATCH_STRING s, a, f, ...
case op.MATCH_STRING: // MATCH_STRING s, a, f, ...
compileCondition(

@@ -582,3 +678,3 @@ eval(ast.consts[bc[ip + 1]]).length > 1

case op.MATCH_STRING_IC: // MATCH_STRING_IC s, a, f, ...
case op.MATCH_STRING_IC: // MATCH_STRING_IC s, a, f, ...
compileCondition(

@@ -593,3 +689,3 @@ 'input.substr(peg$currPos, '

case op.MATCH_REGEXP: // MATCH_REGEXP r, a, f, ...
case op.MATCH_REGEXP: // MATCH_REGEXP r, a, f, ...
compileCondition(

@@ -601,3 +697,3 @@ c(bc[ip + 1]) + '.test(input.charAt(peg$currPos))',

case op.ACCEPT_N: // ACCEPT_N n
case op.ACCEPT_N: // ACCEPT_N n
parts.push(stack.push(

@@ -616,3 +712,3 @@ bc[ip + 1] > 1

case op.ACCEPT_STRING: // ACCEPT_STRING s
case op.ACCEPT_STRING: // ACCEPT_STRING s
parts.push(stack.push(c(bc[ip + 1])));

@@ -627,3 +723,3 @@ parts.push(

case op.FAIL: // FAIL e
case op.FAIL: // FAIL e
parts.push(stack.push('peg$FAILED'));

@@ -634,17 +730,17 @@ parts.push('if (peg$silentFails === 0) { peg$fail(' + c(bc[ip + 1]) + '); }');

case op.REPORT_SAVED_POS: // REPORT_SAVED_POS p
parts.push('peg$reportedPos = ' + stack.index(bc[ip + 1]) + ';');
case op.LOAD_SAVED_POS: // LOAD_SAVED_POS p
parts.push('peg$savedPos = ' + stack.index(bc[ip + 1]) + ';');
ip += 2;
break;
case op.REPORT_CURR_POS: // REPORT_CURR_POS
parts.push('peg$reportedPos = peg$currPos;');
case op.UPDATE_SAVED_POS: // UPDATE_SAVED_POS
parts.push('peg$savedPos = peg$currPos;');
ip++;
break;
case op.CALL: // CALL f, n, pc, p1, p2, ..., pN
case op.CALL: // CALL f, n, pc, p1, p2, ..., pN
compileCall();
break;
case op.RULE: // RULE r
case op.RULE: // RULE r
parts.push(stack.push("peg$parse" + ast.rules[bc[ip + 1]].name + "()"));

@@ -654,3 +750,3 @@ ip += 2;

case op.SILENT_FAILS_ON: // SILENT_FAILS_ON
case op.SILENT_FAILS_ON: // SILENT_FAILS_ON
parts.push('peg$silentFails++;');

@@ -660,3 +756,3 @@ ip++;

case op.SILENT_FAILS_OFF: // SILENT_FAILS_OFF
case op.SILENT_FAILS_OFF: // SILENT_FAILS_OFF
parts.push('peg$silentFails--;');

@@ -676,26 +772,27 @@ ip++;

parts.push([
'function peg$parse' + rule.name + '() {',
' var ' + utils.map(utils.range(0, stack.maxSp + 1), s).join(', ') + ';',
''
].join('\n'));
parts.push('function peg$parse' + rule.name + '() {');
if (options.cache) {
parts.push(indent2(
generateCacheHeader(utils.indexOfRuleByName(ast, rule.name))
));
if (options.trace) {
parts.push([
' var ' + arrays.map(arrays.range(0, stack.maxSp + 1), s).join(', ') + ',',
' startPos = peg$currPos;'
].join('\n'));
} else {
parts.push(
' var ' + arrays.map(arrays.range(0, stack.maxSp + 1), s).join(', ') + ';'
);
}
parts.push(indent2(generateRuleHeader(
'"' + js.stringEscape(rule.name) + '"',
asts.indexOfRule(ast, rule.name)
)));
parts.push(indent2(code));
parts.push(indent2(generateRuleFooter(
'"' + js.stringEscape(rule.name) + '"',
s(0)
)));
if (options.cache) {
parts.push(indent2(generateCacheFooter(s(0))));
}
parts.push('}');
parts.push([
'',
' return ' + s(0) + ';',
'}'
].join('\n'));
return parts.join('\n');

@@ -706,10 +803,13 @@ }

startRuleIndices, startRuleIndex,
startRuleFunctions, startRuleFunction;
startRuleFunctions, startRuleFunction,
ruleNames;
parts.push([
'(function() {',
' "use strict";',
'',
' /*',
' * Generated by PEG.js 0.8.0.',
' * Generated by PEG.js 0.9.0.',
' *',
' * http://pegjs.majda.cz/',
' * http://pegjs.org/',
' */',

@@ -723,17 +823,80 @@ '',

'',
' function SyntaxError(message, expected, found, offset, line, column) {',
' function peg$SyntaxError(message, expected, found, location) {',
' this.message = message;',
' this.expected = expected;',
' this.found = found;',
' this.offset = offset;',
' this.line = line;',
' this.column = column;',
' this.location = location;',
' this.name = "SyntaxError";',
'',
' this.name = "SyntaxError";',
' if (typeof Error.captureStackTrace === "function") {',
' Error.captureStackTrace(this, peg$SyntaxError);',
' }',
' }',
'',
' peg$subclass(SyntaxError, Error);',
'',
' function parse(input) {',
' peg$subclass(peg$SyntaxError, Error);',
''
].join('\n'));
if (options.trace) {
parts.push([
' function peg$DefaultTracer() {',
' this.indentLevel = 0;',
' }',
'',
' peg$DefaultTracer.prototype.trace = function(event) {',
' var that = this;',
'',
' function log(event) {',
' function repeat(string, n) {',
' var result = "", i;',
'',
' for (i = 0; i < n; i++) {',
' result += string;',
' }',
'',
' return result;',
' }',
'',
' function pad(string, length) {',
' return string + repeat(" ", length - string.length);',
' }',
'',
' if (typeof console === "object") {', // IE 8-10
' console.log(',
' event.location.start.line + ":" + event.location.start.column + "-"',
' + event.location.end.line + ":" + event.location.end.column + " "',
' + pad(event.type, 10) + " "',
' + repeat(" ", that.indentLevel) + event.rule',
' );',
' }',
' }',
'',
' switch (event.type) {',
' case "rule.enter":',
' log(event);',
' this.indentLevel++;',
' break;',
'',
' case "rule.match":',
' this.indentLevel--;',
' log(event);',
' break;',
'',
' case "rule.fail":',
' this.indentLevel--;',
' log(event);',
' break;',
'',
' default:',
' throw new Error("Invalid event type: " + event.type + ".");',
' }',
' };',
''
].join('\n'));
}
parts.push([
' function peg$parse(input) {',
' var options = arguments.length > 1 ? arguments[1] : {},',
' parser = this,',
'',

@@ -746,8 +909,8 @@ ' peg$FAILED = {},',

startRuleIndices = '{ '
+ utils.map(
+ arrays.map(
options.allowedStartRules,
function(r) { return r + ': ' + utils.indexOfRuleByName(ast, r); }
function(r) { return r + ': ' + asts.indexOfRule(ast, r); }
).join(', ')
+ ' }';
startRuleIndex = utils.indexOfRuleByName(ast, options.allowedStartRules[0]);
startRuleIndex = asts.indexOfRule(ast, options.allowedStartRules[0]);

@@ -760,3 +923,3 @@ parts.push([

startRuleFunctions = '{ '
+ utils.map(
+ arrays.map(
options.allowedStartRules,

@@ -781,8 +944,7 @@ function(r) { return r + ': peg$parse' + r; }

' peg$currPos = 0,',
' peg$reportedPos = 0,',
' peg$cachedPos = 0,',
' peg$cachedPosDetails = { line: 1, column: 1, seenCR: false },',
' peg$savedPos = 0,',
' peg$posDetailsCache = [{ line: 1, column: 1, seenCR: false }],',
' peg$maxFailPos = 0,',
' peg$maxFailExpected = [],',
' peg$silentFails = 0,', // 0 = report failures, > 0 = silence failures
' peg$silentFails = 0,', // 0 = report failures, > 0 = silence failures
''

@@ -792,5 +954,29 @@ ].join('\n'));

if (options.cache) {
parts.push(' peg$cache = {},');
parts.push([
' peg$resultsCache = {},',
''
].join('\n'));
}
if (options.trace) {
if (options.optimize === "size") {
ruleNames = '['
+ arrays.map(
ast.rules,
function(r) { return '"' + js.stringEscape(r.name) + '"'; }
).join(', ')
+ ']';
parts.push([
' peg$ruleNames = ' + ruleNames + ',',
''
].join('\n'));
}
parts.push([
' peg$tracer = "tracer" in options ? options.tracer : new peg$DefaultTracer(),',
''
].join('\n'));
}
parts.push([

@@ -826,17 +1012,9 @@ ' peg$result;',

' function text() {',
' return input.substring(peg$reportedPos, peg$currPos);',
' return input.substring(peg$savedPos, peg$currPos);',
' }',
'',
' function offset() {',
' return peg$reportedPos;',
' function location() {',
' return peg$computeLocation(peg$savedPos, peg$currPos);',
' }',
'',
' function line() {',
' return peg$computePosDetails(peg$reportedPos).line;',
' }',
'',
' function column() {',
' return peg$computePosDetails(peg$reportedPos).column;',
' }',
'',
' function expected(description) {',

@@ -846,3 +1024,4 @@ ' throw peg$buildException(',

' [{ type: "other", description: description }],',
' peg$reportedPos',
' input.substring(peg$savedPos, peg$currPos),',
' peg$computeLocation(peg$savedPos, peg$currPos)',
' );',

@@ -852,10 +1031,30 @@ ' }',

' function error(message) {',
' throw peg$buildException(message, null, peg$reportedPos);',
' throw peg$buildException(',
' message,',
' null,',
' input.substring(peg$savedPos, peg$currPos),',
' peg$computeLocation(peg$savedPos, peg$currPos)',
' );',
' }',
'',
' function peg$computePosDetails(pos) {',
' function advance(details, startPos, endPos) {',
' var p, ch;',
' var details = peg$posDetailsCache[pos],',
' p, ch;',
'',
' for (p = startPos; p < endPos; p++) {',
' if (details) {',
' return details;',
' } else {',
' p = pos - 1;',
' while (!peg$posDetailsCache[p]) {',
' p--;',
' }',
'',
' details = peg$posDetailsCache[p];',
' details = {',
' line: details.line,',
' column: details.column,',
' seenCR: details.seenCR',
' };',
'',
' while (p < pos) {',
' ch = input.charAt(p);',

@@ -874,15 +1073,27 @@ ' if (ch === "\\n") {',

' }',
'',
' p++;',
' }',
'',
' peg$posDetailsCache[pos] = details;',
' return details;',
' }',
' }',
'',
' if (peg$cachedPos !== pos) {',
' if (peg$cachedPos > pos) {',
' peg$cachedPos = 0;',
' peg$cachedPosDetails = { line: 1, column: 1, seenCR: false };',
' function peg$computeLocation(startPos, endPos) {',
' var startPosDetails = peg$computePosDetails(startPos),',
' endPosDetails = peg$computePosDetails(endPos);',
'',
' return {',
' start: {',
' offset: startPos,',
' line: startPosDetails.line,',
' column: startPosDetails.column',
' },',
' end: {',
' offset: endPos,',
' line: endPosDetails.line,',
' column: endPosDetails.column',
' }',
' advance(peg$cachedPosDetails, peg$cachedPos, pos);',
' peg$cachedPos = pos;',
' }',
'',
' return peg$cachedPosDetails;',
' };',
' }',

@@ -901,3 +1112,3 @@ '',

'',
' function peg$buildException(message, expected, pos) {',
' function peg$buildException(message, expected, found, location) {',
' function cleanupExpected(expected) {',

@@ -945,13 +1156,13 @@ ' var i = 1;',

' return s',
' .replace(/\\\\/g, \'\\\\\\\\\')', // backslash
' .replace(/"/g, \'\\\\"\')', // closing double quote
' .replace(/\\x08/g, \'\\\\b\')', // backspace
' .replace(/\\t/g, \'\\\\t\')', // horizontal tab
' .replace(/\\n/g, \'\\\\n\')', // line feed
' .replace(/\\f/g, \'\\\\f\')', // form feed
' .replace(/\\r/g, \'\\\\r\')', // carriage return
' .replace(/\\\\/g, \'\\\\\\\\\')', // backslash
' .replace(/"/g, \'\\\\"\')', // closing double quote
' .replace(/\\x08/g, \'\\\\b\')', // backspace
' .replace(/\\t/g, \'\\\\t\')', // horizontal tab
' .replace(/\\n/g, \'\\\\n\')', // line feed
' .replace(/\\f/g, \'\\\\f\')', // form feed
' .replace(/\\r/g, \'\\\\r\')', // carriage return
' .replace(/[\\x00-\\x07\\x0B\\x0E\\x0F]/g, function(ch) { return \'\\\\x0\' + hex(ch); })',
' .replace(/[\\x10-\\x1F\\x80-\\xFF]/g, function(ch) { return \'\\\\x\' + hex(ch); })',
' .replace(/[\\u0180-\\u0FFF]/g, function(ch) { return \'\\\\u0\' + hex(ch); })',
' .replace(/[\\u1080-\\uFFFF]/g, function(ch) { return \'\\\\u\' + hex(ch); });',
' .replace(/[\\u0100-\\u0FFF]/g, function(ch) { return \'\\\\u0\' + hex(ch); })',
' .replace(/[\\u1000-\\uFFFF]/g, function(ch) { return \'\\\\u\' + hex(ch); });',
' }',

@@ -977,5 +1188,2 @@ '',

'',
' var posDetails = peg$computePosDetails(pos),',
' found = pos < input.length ? input.charAt(pos) : null;',
'',
' if (expected !== null) {',

@@ -985,9 +1193,7 @@ ' cleanupExpected(expected);',

'',
' return new SyntaxError(',
' return new peg$SyntaxError(',
' message !== null ? message : buildMessage(expected, found),',
' expected,',
' found,',
' pos,',
' posDetails.line,',
' posDetails.column',
' location',
' );',

@@ -1002,3 +1208,3 @@ ' }',

} else {
utils.each(ast.rules, function(rule) {
arrays.each(ast.rules, function(rule) {
parts.push(indent4(generateRuleFunction(rule)));

@@ -1029,9 +1235,30 @@ parts.push('');

'',
' throw peg$buildException(null, peg$maxFailExpected, peg$maxFailPos);',
' throw peg$buildException(',
' null,',
' peg$maxFailExpected,',
' peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,',
' peg$maxFailPos < input.length',
' ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)',
' : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)',
' );',
' }',
' }',
'',
' return {',
' SyntaxError: SyntaxError,',
' parse: parse',
' return {'
].join('\n'));
if (options.trace) {
parts.push([
' SyntaxError: peg$SyntaxError,',
' DefaultTracer: peg$DefaultTracer,',
' parse: peg$parse'
].join('\n'));
} else {
parts.push([
' SyntaxError: peg$SyntaxError,',
' parse: peg$parse'
].join('\n'));
}
parts.push([
' };',

@@ -1042,2 +1269,4 @@ '})()'

ast.code = parts.join('\n');
};
}
module.exports = generateJavascript;

@@ -1,7 +0,10 @@

var utils = require("../../utils");
"use strict";
var arrays = require("../../utils/arrays"),
visitor = require("../visitor");
/*
* Removes proxy rules -- that is, rules that only delegate to other rule.
*/
module.exports = function(ast, options) {
function removeProxyRules(ast, options) {
function isProxyRule(node) {

@@ -12,46 +15,11 @@ return node.type === "rule" && node.expression.type === "rule_ref";

function replaceRuleRefs(ast, from, to) {
function nop() {}
function replaceInExpression(node, from, to) {
replace(node.expression, from, to);
}
function replaceInSubnodes(propertyName) {
return function(node, from, to) {
utils.each(node[propertyName], function(subnode) {
replace(subnode, from, to);
});
};
}
var replace = utils.buildNodeVisitor({
grammar: replaceInSubnodes("rules"),
rule: replaceInExpression,
named: replaceInExpression,
choice: replaceInSubnodes("alternatives"),
sequence: replaceInSubnodes("elements"),
labeled: replaceInExpression,
text: replaceInExpression,
simple_and: replaceInExpression,
simple_not: replaceInExpression,
semantic_and: nop,
semantic_not: nop,
optional: replaceInExpression,
zero_or_more: replaceInExpression,
one_or_more: replaceInExpression,
action: replaceInExpression,
rule_ref:
function(node, from, to) {
if (node.name === from) {
node.name = to;
}
},
literal: nop,
"class": nop,
any: nop
var replace = visitor.build({
rule_ref: function(node) {
if (node.name === from) {
node.name = to;
}
}
});
replace(ast, from, to);
replace(ast);
}

@@ -61,6 +29,6 @@

utils.each(ast.rules, function(rule, i) {
arrays.each(ast.rules, function(rule, i) {
if (isProxyRule(rule)) {
replaceRuleRefs(ast, rule.name, rule.expression.name);
if (!utils.contains(options.allowedStartRules, rule.name)) {
if (!arrays.contains(options.allowedStartRules, rule.name)) {
indices.push(i);

@@ -73,5 +41,5 @@ }

utils.each(indices, function(index) {
ast.rules.splice(index, 1);
});
};
arrays.each(indices, function(i) { ast.rules.splice(i, 1); });
}
module.exports = removeProxyRules;

@@ -1,65 +0,53 @@

var utils = require("../../utils"),
GrammarError = require("../../grammar-error");
"use strict";
/* Checks that no left recursion is present. */
module.exports = function(ast) {
function nop() {}
var arrays = require("../../utils/arrays"),
GrammarError = require("../../grammar-error"),
asts = require("../asts"),
visitor = require("../visitor");
function checkExpression(node, appliedRules) {
check(node.expression, appliedRules);
}
/*
* Reports left recursion in the grammar, which prevents infinite recursion in
* the generated parser.
*
* Both direct and indirect recursion is detected. The pass also correctly
* reports cases like this:
*
* start = "a"? start
*
* In general, if a rule reference can be reached without consuming any input,
* it can lead to left recursion.
*/
function reportLeftRecursion(ast) {
var visitedRules = [];
function checkSubnodes(propertyName) {
return function(node, appliedRules) {
utils.each(node[propertyName], function(subnode) {
check(subnode, appliedRules);
});
};
}
var check = visitor.build({
rule: function(node) {
visitedRules.push(node.name);
check(node.expression);
visitedRules.pop(node.name);
},
var check = utils.buildNodeVisitor({
grammar: checkSubnodes("rules"),
sequence: function(node) {
arrays.every(node.elements, function(element) {
check(element);
rule:
function(node, appliedRules) {
check(node.expression, appliedRules.concat(node.name));
},
return !asts.alwaysAdvancesOnSuccess(ast, element);
});
},
named: checkExpression,
choice: checkSubnodes("alternatives"),
action: checkExpression,
rule_ref: function(node) {
if (arrays.contains(visitedRules, node.name)) {
throw new GrammarError(
"Left recursion detected for rule \"" + node.name + "\".",
node.location
);
}
sequence:
function(node, appliedRules) {
if (node.elements.length > 0) {
check(node.elements[0], appliedRules);
}
},
check(asts.findRule(ast, node.name));
}
});
labeled: checkExpression,
text: checkExpression,
simple_and: checkExpression,
simple_not: checkExpression,
semantic_and: nop,
semantic_not: nop,
optional: checkExpression,
zero_or_more: checkExpression,
one_or_more: checkExpression,
check(ast);
}
rule_ref:
function(node, appliedRules) {
if (utils.contains(appliedRules, node.name)) {
throw new GrammarError(
"Left recursion detected for rule \"" + node.name + "\"."
);
}
check(utils.findRuleByName(ast, node.name), appliedRules);
},
literal: nop,
"class": nop,
any: nop
});
check(ast, []);
};
module.exports = reportLeftRecursion;

@@ -1,46 +0,23 @@

var utils = require("../../utils"),
GrammarError = require("../../grammar-error");
"use strict";
var GrammarError = require("../../grammar-error"),
asts = require("../asts"),
visitor = require("../visitor");
/* Checks that all referenced rules exist. */
module.exports = function(ast) {
function nop() {}
function checkExpression(node) { check(node.expression); }
function checkSubnodes(propertyName) {
return function(node) { utils.each(node[propertyName], check); };
}
var check = utils.buildNodeVisitor({
grammar: checkSubnodes("rules"),
rule: checkExpression,
named: checkExpression,
choice: checkSubnodes("alternatives"),
action: checkExpression,
sequence: checkSubnodes("elements"),
labeled: checkExpression,
text: checkExpression,
simple_and: checkExpression,
simple_not: checkExpression,
semantic_and: nop,
semantic_not: nop,
optional: checkExpression,
zero_or_more: checkExpression,
one_or_more: checkExpression,
rule_ref:
function(node) {
if (!utils.findRuleByName(ast, node.name)) {
throw new GrammarError(
"Referenced rule \"" + node.name + "\" does not exist."
);
}
},
literal: nop,
"class": nop,
any: nop
function reportMissingRules(ast) {
var check = visitor.build({
rule_ref: function(node) {
if (!asts.findRule(ast, node.name)) {
throw new GrammarError(
"Referenced rule \"" + node.name + "\" does not exist.",
node.location
);
}
}
});
check(ast);
};
}
module.exports = reportMissingRules;

@@ -1,9 +0,18 @@

var utils = require("./utils");
"use strict";
var classes = require("./utils/classes");
/* Thrown when the grammar contains an error. */
module.exports = function(message) {
function GrammarError(message, location) {
this.name = "GrammarError";
this.message = message;
};
this.location = location;
utils.subclass(module.exports, Error);
if (typeof Error.captureStackTrace === "function") {
Error.captureStackTrace(this, GrammarError);
}
}
classes.subclass(GrammarError, Error);
module.exports = GrammarError;

@@ -1,6 +0,9 @@

var utils = require("./utils");
"use strict";
module.exports = {
var arrays = require("./utils/arrays"),
objects = require("./utils/objects");
var PEG = {
/* PEG.js version (uses semantic versioning). */
VERSION: "0.8.0",
VERSION: "0.9.0",

@@ -28,3 +31,3 @@ GrammarError: require("./grammar-error"),

if (passes.hasOwnProperty(stage)) {
converted[stage] = utils.values(passes[stage]);
converted[stage] = objects.values(passes[stage]);
}

@@ -36,3 +39,3 @@ }

var options = arguments.length > 1 ? utils.clone(arguments[1]) : {},
var options = arguments.length > 1 ? objects.clone(arguments[1]) : {},
plugins = "plugins" in options ? options.plugins : [],

@@ -44,3 +47,3 @@ config = {

utils.each(plugins, function(p) { p.use(config, options); });
arrays.each(plugins, function(p) { p.use(config, options); });

@@ -54,1 +57,3 @@ return this.compiler.compile(

};
module.exports = PEG;
{
"name": "pegjs",
"version": "0.8.0",
"version": "0.9.0",
"description": "Parser generator for JavaScript",
"homepage": "http://pegjs.majda.cz/",
"homepage": "http://pegjs.org/",
"license": "MIT",
"author": {

@@ -22,3 +23,6 @@ "name": "David Majda",

"lib/compiler.js",
"lib/compiler/asts.js",
"lib/compiler/javascript.js",
"lib/compiler/opcodes.js",
"lib/compiler/visitor.js",
"lib/compiler/passes/generate-bytecode.js",

@@ -28,2 +32,3 @@ "lib/compiler/passes/generate-javascript.js",

"lib/compiler/passes/report-left-recursion.js",
"lib/compiler/passes/report-infinite-loops.js",
"lib/compiler/passes/report-missing-rules.js",

@@ -33,3 +38,5 @@ "lib/grammar-error.js",

"lib/peg.js",
"lib/utils.js",
"lib/utils/arrays.js",
"lib/utils/classes.js",
"lib/utils/objects.js",
"package.json"

@@ -40,16 +47,16 @@ ],

"scripts": {
"test": "make spec"
"test": "make hint && make spec"
},
"repository": {
"type": "git",
"url": "http://github.com/dmajda/pegjs.git"
"url": "http://github.com/pegjs/pegjs.git"
},
"devDependencies": {
"jasmine-node": "= 1.11.0",
"uglify-js": "= 2.4.7",
"jshint": "= 2.3.0"
"jasmine-node": "= 1.14.5",
"uglify-js": "= 2.4.24",
"jshint": "= 2.8.0"
},
"engines": {
"node": ">= 0.8"
"node": ">= 0.10.0"
}
}

@@ -18,4 +18,4 @@ PEG.js

— more powerful than traditional LL(*k*) and LR(*k*) parsers
* Usable [from your browser](http://pegjs.majda.cz/online), from the command
line, or via JavaScript API
* Usable [from your browser](http://pegjs.org/online), from the command line,
or via JavaScript API

@@ -25,3 +25,3 @@ Getting Started

[Online version](http://pegjs.majda.cz/online) is the easiest way to generate a
[Online version](http://pegjs.org/online) is the easiest way to generate a
parser. Just enter your grammar, try parsing few inputs, and download generated

@@ -48,5 +48,7 @@ parser code.

[Download](http://pegjs.majda.cz/#download) the PEG.js library (regular or
minified version).
[Download](http://pegjs.org/#download) the PEG.js library (regular or minified
version) or install it using Bower:
$ bower install pegjs
Generating a Parser

@@ -70,3 +72,3 @@ -------------------

If you omit both input and ouptut file, standard input and output are used.
If you omit both input and output file, standard input and output are used.

@@ -90,2 +92,3 @@ By default, the parser object is assigned to `module.exports`, which makes the

pass to `PEG.buildParser`
* `--trace` — makes the parser trace its progress

@@ -132,4 +135,4 @@ ### JavaScript API

value depends on the grammar used to build the parser) or throw an exception if
the input is invalid. The exception will contain `offset`, `line`, `column`,
`expected`, `found` and `message` properties with more details about the error.
the input is invalid. The exception will contain `location`, `expected`, `found`
and `message` properties with more details about the error.

@@ -141,5 +144,6 @@ parser.parse("abba"); // returns ["a", "b", "b", "a"]

You can tweak parser behavior by passing a second parameter with an options
object to the `parse` method. Only one option is currently supported:
object to the `parse` method. The following options are supported:
* `startRule` — name of the rule to start parsing from
* `tracer` — tracer to use

@@ -192,9 +196,10 @@ Parsers can also support their own custom options.

Rules can be preceded by an *initializer* — a piece of JavaScript code in curly
braces (“{” and “}”). This code is executed before the generated parser starts
parsing. All variables and functions defined in the initializer are accessible
in rule actions and semantic predicates. The code inside the initializer can
access options passed to the parser using the `options` variable. Curly braces
in the initializer code must be balanced. Let's look at the example grammar
from above using a simple initializer.
The first rule can be preceded by an *initializer* — a piece of JavaScript code
in curly braces (“{” and “}”). This code is executed before the generated parser
starts parsing. All variables and functions defined in the initializer are
accessible in rule actions and semantic predicates. The code inside the
initializer can access the parser object using the `parser` variable and options
passed to the parser using the `options` variable. Curly braces in the
initializer code must be balanced. Let's look at the example grammar from above
using a simple initializer.

@@ -291,3 +296,4 @@ {

in an array. The matching is greedy, i.e. the parser tries to match the
expression as many times as possible.
expression as many times as possible. Unlike in regular expressions, there is no
backtracking.

@@ -298,3 +304,4 @@ #### *expression* +

in an array. The matching is greedy, i.e. the parser tries to match the
expression as many times as possible.
expression as many times as possible. Unlike in regular expressions, there is no
backtracking.

@@ -304,3 +311,4 @@ #### *expression* ?

Try to match the expression. If the match succeeds, return its match result,
otherwise return `null`.
otherwise return `null`. Unlike in regular expressions, there is no
backtracking.

@@ -330,10 +338,17 @@ #### & *expression*

The code inside the predicate can also access the current parse position using
the `offset` function. It returns a zero-based character index into the input
string. The code can also access the current line and column using the `line`
and `column` functions. Both return one-based indexes.
The code inside the predicate can also access location information using the
`location` function. It returns an object like this:
The code inside the predicate can also access options passed to the parser using
the `options` variable.
{
start: { offset: 23, line: 5, column: 6 },
end: { offset: 23, line: 5, column: 6 }
}
The `start` and `end` properties both refer to the current parse position. The
`offset` property contains an offset as a zero-based index and `line` and
`column` properties contain a line and a column as one-based indices.
The code inside the predicate can also access the parser object using the
`parser` variable and options passed to the parser using the `options` variable.
Note that curly braces in the predicate code must be balanced.

@@ -353,10 +368,17 @@

The code inside the predicate can also access the current parse position using
the `offset` function. It returns a zero-based character index into the input
string. The code can also access the current line and column using the `line`
and `column` functions. Both return one-based indexes.
The code inside the predicate can also access location information using the
`location` function. It returns an object like this:
The code inside the predicate can also access options passed to the parser using
the `options` variable.
{
start: { offset: 23, line: 5, column: 6 },
end: { offset: 23, line: 5, column: 6 }
}
The `start` and `end` properties both refer to the current parse position. The
`offset` property contains an offset as a zero-based index and `line` and
`column` properties contain a line and a column as one-based indices.
The code inside the predicate can also access the parser object using the
`parser` variable and options passed to the parser using the `options` variable.
Note that curly braces in the predicate code must be balanced.

@@ -408,11 +430,19 @@

The code inside the action can also access the parse position at the beginning
of the action's expression using the `offset` function. It returns a zero-based
character index into the input string. The code can also access the line and
column at the beginning of the action's expression using the `line` and `column`
functions. Both return one-based indexes.
The code inside the action can also access options passed to the parser using
the `options` variable.
The code inside the action can also access location information using the
`location` function. It returns an object like this:
{
start: { offset: 23, line: 5, column: 6 },
end: { offset: 25, line: 5, column: 8 }
}
The `start` property refers to the position at the beginning of the expression,
the `end` property refers to position after the end of the expression. The
`offset` property contains an offset as a zero-based index and `line` and
`column` properties contain a line and a column as one-based indices.
The code inside the action can also access the parser object using the `parser`
variable and options passed to the parser using the `options` variable.
Note that curly braces in the action code must be balanced.

@@ -432,4 +462,6 @@

* Node.js 0.8.0+
* IE 8+
* Node.js 0.10.0+
* io.js
* Internet Explorer 8+
* Edge
* Firefox

@@ -443,7 +475,7 @@ * Chrome

* [Project website](http://pegjs.majda.cz/)
* [Wiki](https://github.com/dmajda/pegjs/wiki)
* [Source code](https://github.com/dmajda/pegjs)
* [Project website](http://pegjs.org/)
* [Wiki](https://github.com/pegjs/pegjs/wiki)
* [Source code](https://github.com/pegjs/pegjs)
* [Trello board](https://trello.com/board/peg-js/50a8eba48cf95d4957006b01)
* [Issue tracker](https://github.com/dmajda/pegjs/issues)
* [Issue tracker](https://github.com/pegjs/pegjs/issues)
* [Google Group](http://groups.google.com/group/pegjs)

@@ -453,8 +485,12 @@ * [Twitter](http://twitter.com/peg_js)

PEG.js is developed by [David Majda](http://majda.cz/)
([@dmajda](http://twitter.com/dmajda)). You are welcome to contribute code.
Unless your contribution is really trivial you should get in touch with me first
— this can prevent wasted effort on both sides. You can send code both as a
patch or a GitHub pull request.
([@dmajda](http://twitter.com/dmajda)). The [Bower
package](https://github.com/pegjs/bower) is maintained by [Michel
Krämer](http://www.michel-kraemer.com/)
([@michelkraemer](https://twitter.com/michelkraemer)).
You are welcome to contribute code. Unless your contribution is really trivial
you should get in touch with me first — this can prevent wasted effort on both
sides. You can send code both as a patch or a GitHub pull request.
Note that PEG.js is still very much work in progress. There are no compatibility
guarantees until version 1.0.

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc