initial commit taken from gitlab.lrz.de

This commit is contained in:
privatereese
2018-08-24 18:09:42 +02:00
parent ae54ed4c48
commit fc05486403
28494 changed files with 2159823 additions and 0 deletions

65
node_modules/pegjs/lib/compiler/asts.js generated vendored Normal file
View File

@@ -0,0 +1,65 @@
"use strict";
var arrays = require("../utils/arrays"),
visitor = require("./visitor");
/* AST utilities. */
var asts = {
findRule: function(ast, name) {
return arrays.find(ast.rules, function(r) { return r.name === name; });
},
indexOfRule: function(ast, name) {
return arrays.indexOf(ast.rules, function(r) { return r.name === name; });
},
alwaysConsumesOnSuccess: function(ast, node) {
function consumesTrue() { return true; }
function consumesFalse() { return false; }
function consumesExpression(node) {
return consumes(node.expression);
}
var consumes = visitor.build({
rule: consumesExpression,
named: consumesExpression,
choice: function(node) {
return arrays.every(node.alternatives, consumes);
},
action: consumesExpression,
sequence: function(node) {
return arrays.some(node.elements, consumes);
},
labeled: consumesExpression,
text: consumesExpression,
simple_and: consumesFalse,
simple_not: consumesFalse,
optional: consumesFalse,
zero_or_more: consumesFalse,
one_or_more: consumesExpression,
group: consumesExpression,
semantic_and: consumesFalse,
semantic_not: consumesFalse,
rule_ref: function(node) {
return consumes(asts.findRule(ast, node.name));
},
literal: function(node) {
return node.value !== "";
},
"class": consumesTrue,
any: consumesTrue
});
return consumes(node);
}
};
module.exports = asts;

73
node_modules/pegjs/lib/compiler/index.js generated vendored Normal file
View File

@@ -0,0 +1,73 @@
"use strict";
var arrays = require("../utils/arrays"),
objects = require("../utils/objects");
var compiler = {
/*
* AST node visitor builder. Useful mainly for plugins which manipulate the
* AST.
*/
visitor: require("./visitor"),
/*
* Compiler passes.
*
* 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
* |peg.GrammarError|.
*/
passes: {
check: {
reportUndefinedRules: require("./passes/report-undefined-rules"),
reportDuplicateRules: require("./passes/report-duplicate-rules"),
reportDuplicateLabels: require("./passes/report-duplicate-labels"),
reportInfiniteRecursion: require("./passes/report-infinite-recursion"),
reportInfiniteRepetition: require("./passes/report-infinite-repetition")
},
transform: {
removeProxyRules: require("./passes/remove-proxy-rules")
},
generate: {
generateBytecode: require("./passes/generate-bytecode"),
generateJS: require("./passes/generate-js")
}
},
/*
* 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
* during the generation and some may protrude to the generated parser and
* cause its malfunction.
*/
compile: function(ast, passes, options) {
options = options !== void 0 ? options : {};
var stage;
options = objects.clone(options);
objects.defaults(options, {
allowedStartRules: [ast.rules[0].name],
cache: false,
dependencies: {},
exportVar: null,
format: "bare",
optimize: "speed",
output: "parser",
trace: false
});
for (stage in passes) {
if (passes.hasOwnProperty(stage)) {
arrays.each(passes[stage], function(p) { p(ast, options); });
}
}
switch (options.output) {
case "parser": return eval(ast.code);
case "source": return ast.code;
}
}
};
module.exports = compiler;

58
node_modules/pegjs/lib/compiler/js.js generated vendored Normal file
View File

@@ -0,0 +1,58 @@
"use strict";
function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }
/* JavaScript code generation helpers. */
var js = {
stringEscape: function(s) {
/*
* ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a string
* literal except for the closing quote character, backslash, carriage
* return, line separator, paragraph separator, and line feed. Any character
* may appear in the form of an escape sequence.
*
* For portability, we also escape all control and non-ASCII characters.
* Note that the "\v" escape sequence is not used because IE does not like
* it.
*/
return s
.replace(/\\/g, '\\\\') // backslash
.replace(/"/g, '\\"') // closing double quote
.replace(/\0/g, '\\0') // null
.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-\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
.replace(/[\x10-\x1F\x7F-\xFF]/g, function(ch) { return '\\x' + hex(ch); })
.replace(/[\u0100-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); })
.replace(/[\u1000-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); });
},
regexpClassEscape: function(s) {
/*
* Based on ECMA-262, 5th ed., 7.8.5 & 15.10.1.
*
* For portability, we also escape all control and non-ASCII characters.
*/
return s
.replace(/\\/g, '\\\\') // backslash
.replace(/\//g, '\\/') // closing slash
.replace(/\]/g, '\\]') // closing bracket
.replace(/\^/g, '\\^') // caret
.replace(/-/g, '\\-') // dash
.replace(/\0/g, '\\0') // null
.replace(/\t/g, '\\t') // horizontal tab
.replace(/\n/g, '\\n') // line feed
.replace(/\v/g, '\\x0B') // vertical tab
.replace(/\f/g, '\\f') // form feed
.replace(/\r/g, '\\r') // carriage return
.replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
.replace(/[\x10-\x1F\x7F-\xFF]/g, function(ch) { return '\\x' + hex(ch); })
.replace(/[\u0100-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); })
.replace(/[\u1000-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); });
}
};
module.exports = js;

54
node_modules/pegjs/lib/compiler/opcodes.js generated vendored Normal file
View File

@@ -0,0 +1,54 @@
"use strict";
/* Bytecode instruction opcodes. */
var opcodes = {
/* Stack Manipulation */
PUSH: 0, // PUSH c
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: 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: 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 */
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: 27, // RULE r
/* Failure Reporting */
SILENT_FAILS_ON: 28, // SILENT_FAILS_ON
SILENT_FAILS_OFF: 29 // SILENT_FAILS_OFF
};
module.exports = opcodes;

View File

@@ -0,0 +1,631 @@
"use strict";
var arrays = require("../../utils/arrays"),
objects = require("../../utils/objects"),
asts = require("../asts"),
visitor = require("../visitor"),
op = require("../opcodes"),
js = require("../js");
/* Generates bytecode.
*
* Instructions
* ============
*
* Stack Manipulation
* ------------------
*
* [0] PUSH c
*
* stack.push(consts[c]);
*
* [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);
*
* [6] POP
*
* stack.pop();
*
* [7] POP_CURR_POS
*
* currPos = stack.pop();
*
* [8] POP_N n
*
* stack.pop(n);
*
* [9] NIP
*
* value = stack.pop();
* stack.pop();
* stack.push(value);
*
* [10] APPEND
*
* value = stack.pop();
* array = stack.pop();
* array.push(value);
* stack.push(array);
*
* [11] WRAP n
*
* stack.push(stack.pop(n));
*
* [12] TEXT
*
* stack.push(input.substring(stack.pop(), currPos));
*
* Conditions and Loops
* --------------------
*
* [13] IF t, f
*
* if (stack.top()) {
* interpret(ip + 3, ip + 3 + t);
* } else {
* interpret(ip + 3 + t, ip + 3 + t + f);
* }
*
* [14] IF_ERROR t, f
*
* if (stack.top() === FAILED) {
* interpret(ip + 3, ip + 3 + t);
* } else {
* interpret(ip + 3 + t, ip + 3 + t + f);
* }
*
* [15] IF_NOT_ERROR t, f
*
* if (stack.top() !== FAILED) {
* interpret(ip + 3, ip + 3 + t);
* } else {
* interpret(ip + 3 + t, ip + 3 + t + f);
* }
*
* [16] WHILE_NOT_ERROR b
*
* while(stack.top() !== FAILED) {
* interpret(ip + 2, ip + 2 + b);
* }
*
* Matching
* --------
*
* [17] MATCH_ANY a, f, ...
*
* if (input.length > currPos) {
* interpret(ip + 3, ip + 3 + a);
* } else {
* interpret(ip + 3 + a, ip + 3 + a + f);
* }
*
* [18] MATCH_STRING s, a, f, ...
*
* if (input.substr(currPos, consts[s].length) === consts[s]) {
* interpret(ip + 4, ip + 4 + a);
* } else {
* interpret(ip + 4 + a, ip + 4 + a + f);
* }
*
* [19] MATCH_STRING_IC s, a, f, ...
*
* if (input.substr(currPos, consts[s].length).toLowerCase() === consts[s]) {
* interpret(ip + 4, ip + 4 + a);
* } else {
* interpret(ip + 4 + a, ip + 4 + a + f);
* }
*
* [20] MATCH_REGEXP r, a, f, ...
*
* if (consts[r].test(input.charAt(currPos))) {
* interpret(ip + 4, ip + 4 + a);
* } else {
* interpret(ip + 4 + a, ip + 4 + a + f);
* }
*
* [21] ACCEPT_N n
*
* stack.push(input.substring(currPos, n));
* currPos += n;
*
* [22] ACCEPT_STRING s
*
* stack.push(consts[s]);
* currPos += consts[s].length;
*
* [23] FAIL e
*
* stack.push(FAILED);
* fail(consts[e]);
*
* Calls
* -----
*
* [24] LOAD_SAVED_POS p
*
* savedPos = stack[p];
*
* [25] UPDATE_SAVED_POS
*
* savedPos = currPos;
*
* [26] CALL f, n, pc, p1, p2, ..., pN
*
* value = consts[f](stack[p1], ..., stack[pN]);
* stack.pop(n);
* stack.push(value);
*
* Rules
* -----
*
* [27] RULE r
*
* stack.push(parseRule(r));
*
* Failure Reporting
* -----------------
*
* [28] SILENT_FAILS_ON
*
* silentFails++;
*
* [29] SILENT_FAILS_OFF
*
* silentFails--;
*/
function generateBytecode(ast) {
var consts = [];
function addConst(value) {
var index = arrays.indexOf(consts, value);
return index === -1 ? consts.push(value) - 1 : index;
}
function addFunctionConst(params, code) {
return addConst(
"function(" + params.join(", ") + ") {" + code + "}"
);
}
function buildSequence() {
return Array.prototype.concat.apply([], arguments);
}
function buildCondition(condCode, thenCode, elseCode) {
return condCode.concat(
[thenCode.length, elseCode.length],
thenCode,
elseCode
);
}
function buildLoop(condCode, bodyCode) {
return condCode.concat([bodyCode.length], bodyCode);
}
function buildCall(functionIndex, delta, env, sp) {
var params = arrays.map(objects.values(env), function(p) { return sp - p; });
return [op.CALL, functionIndex, delta, params.length].concat(params);
}
function buildSimplePredicate(expression, negative, context) {
return buildSequence(
[op.PUSH_CURR_POS],
[op.SILENT_FAILS_ON],
generate(expression, {
sp: context.sp + 1,
env: objects.clone(context.env),
action: null
}),
[op.SILENT_FAILS_OFF],
buildCondition(
[negative ? op.IF_ERROR : op.IF_NOT_ERROR],
buildSequence(
[op.POP],
[negative ? op.POP : op.POP_CURR_POS],
[op.PUSH_UNDEFINED]
),
buildSequence(
[op.POP],
[negative ? op.POP_CURR_POS : op.POP],
[op.PUSH_FAILED]
)
)
);
}
function buildSemanticPredicate(code, negative, context) {
var functionIndex = addFunctionConst(objects.keys(context.env), code);
return buildSequence(
[op.UPDATE_SAVED_POS],
buildCall(functionIndex, 0, context.env, context.sp),
buildCondition(
[op.IF],
buildSequence(
[op.POP],
negative ? [op.PUSH_FAILED] : [op.PUSH_UNDEFINED]
),
buildSequence(
[op.POP],
negative ? [op.PUSH_UNDEFINED] : [op.PUSH_FAILED]
)
)
);
}
function buildAppendLoop(expressionCode) {
return buildLoop(
[op.WHILE_NOT_ERROR],
buildSequence([op.APPEND], expressionCode)
);
}
var generate = visitor.build({
grammar: function(node) {
arrays.each(node.rules, generate);
node.consts = consts;
},
rule: function(node) {
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
});
},
named: function(node, context) {
var nameIndex = addConst(
'peg$otherExpectation("' + js.stringEscape(node.name) + '")'
);
/*
* 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
* dedicated instruction that would just report the failure and not touch
* the stack.
*/
return buildSequence(
[op.SILENT_FAILS_ON],
generate(node.expression, context),
[op.SILENT_FAILS_OFF],
buildCondition([op.IF_ERROR], [op.FAIL, nameIndex], [])
);
},
choice: function(node, context) {
function buildAlternativesCode(alternatives, context) {
return buildSequence(
generate(alternatives[0], {
sp: context.sp,
env: objects.clone(context.env),
action: null
}),
alternatives.length > 1
? buildCondition(
[op.IF_ERROR],
buildSequence(
[op.POP],
buildAlternativesCode(alternatives.slice(1), context)
),
[]
)
: []
);
}
return buildAlternativesCode(node.alternatives, context);
},
action: function(node, context) {
var env = objects.clone(context.env),
emitCall = node.expression.type !== "sequence"
|| node.expression.elements.length === 0,
expressionCode = generate(node.expression, {
sp: context.sp + (emitCall ? 1 : 0),
env: env,
action: node
}),
functionIndex = addFunctionConst(objects.keys(env), node.code);
return emitCall
? buildSequence(
[op.PUSH_CURR_POS],
expressionCode,
buildCondition(
[op.IF_NOT_ERROR],
buildSequence(
[op.LOAD_SAVED_POS, 1],
buildCall(functionIndex, 1, env, context.sp + 2)
),
[]
),
[op.NIP]
)
: expressionCode;
},
sequence: function(node, context) {
function buildElementsCode(elements, context) {
var processedCount, functionIndex;
if (elements.length > 0) {
processedCount = node.elements.length - elements.slice(1).length;
return buildSequence(
generate(elements[0], {
sp: context.sp,
env: context.env,
action: null
}),
buildCondition(
[op.IF_NOT_ERROR],
buildElementsCode(elements.slice(1), {
sp: context.sp + 1,
env: context.env,
action: context.action
}),
buildSequence(
processedCount > 1 ? [op.POP_N, processedCount] : [op.POP],
[op.POP_CURR_POS],
[op.PUSH_FAILED]
)
)
);
} else {
if (context.action) {
functionIndex = addFunctionConst(
objects.keys(context.env),
context.action.code
);
return buildSequence(
[op.LOAD_SAVED_POS, node.elements.length],
buildCall(
functionIndex,
node.elements.length,
context.env,
context.sp
),
[op.NIP]
);
} else {
return buildSequence([op.WRAP, node.elements.length], [op.NIP]);
}
}
}
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;
return generate(node.expression, {
sp: context.sp,
env: env,
action: null
});
},
text: function(node, context) {
return buildSequence(
[op.PUSH_CURR_POS],
generate(node.expression, {
sp: context.sp + 1,
env: objects.clone(context.env),
action: null
}),
buildCondition(
[op.IF_NOT_ERROR],
buildSequence([op.POP], [op.TEXT]),
[op.NIP]
)
);
},
simple_and: function(node, context) {
return buildSimplePredicate(node.expression, false, context);
},
simple_not: function(node, context) {
return buildSimplePredicate(node.expression, true, context);
},
optional: function(node, context) {
return buildSequence(
generate(node.expression, {
sp: context.sp,
env: objects.clone(context.env),
action: null
}),
buildCondition(
[op.IF_ERROR],
buildSequence([op.POP], [op.PUSH_NULL]),
[]
)
);
},
zero_or_more: function(node, context) {
var expressionCode = generate(node.expression, {
sp: context.sp + 1,
env: objects.clone(context.env),
action: null
});
return buildSequence(
[op.PUSH_EMPTY_ARRAY],
expressionCode,
buildAppendLoop(expressionCode),
[op.POP]
);
},
one_or_more: function(node, context) {
var expressionCode = generate(node.expression, {
sp: context.sp + 1,
env: objects.clone(context.env),
action: null
});
return buildSequence(
[op.PUSH_EMPTY_ARRAY],
expressionCode,
buildCondition(
[op.IF_NOT_ERROR],
buildSequence(buildAppendLoop(expressionCode), [op.POP]),
buildSequence([op.POP], [op.POP], [op.PUSH_FAILED])
)
);
},
group: function(node, context) {
return generate(node.expression, {
sp: context.sp,
env: objects.clone(context.env),
action: null
});
},
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, asts.indexOfRule(ast, node.name)];
},
literal: function(node) {
var stringIndex, expectedIndex;
if (node.value.length > 0) {
stringIndex = addConst('"'
+ js.stringEscape(
node.ignoreCase ? node.value.toLowerCase() : node.value
)
+ '"'
);
expectedIndex = addConst(
'peg$literalExpectation('
+ '"' + js.stringEscape(node.value) + '", '
+ node.ignoreCase
+ ')'
);
/*
* For case-sensitive strings the value must match the beginning of the
* 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|.
*/
return buildCondition(
node.ignoreCase
? [op.MATCH_STRING_IC, stringIndex]
: [op.MATCH_STRING, stringIndex],
node.ignoreCase
? [op.ACCEPT_N, node.value.length]
: [op.ACCEPT_STRING, stringIndex],
[op.FAIL, expectedIndex]
);
} else {
stringIndex = addConst('""');
return [op.PUSH, stringIndex];
}
},
"class": function(node) {
var regexp, parts, regexpIndex, expectedIndex;
if (node.parts.length > 0) {
regexp = '/^['
+ (node.inverted ? '^' : '')
+ arrays.map(node.parts, function(part) {
return part instanceof Array
? js.regexpClassEscape(part[0])
+ '-'
+ js.regexpClassEscape(part[1])
: js.regexpClassEscape(part);
}).join('')
+ ']/' + (node.ignoreCase ? 'i' : '');
} else {
/*
* IE considers regexps /[]/ and /[^]/ as syntactically invalid, so we
* translate them into equivalents it can handle.
*/
regexp = node.inverted ? '/^[\\S\\s]/' : '/^(?!)/';
}
parts = '['
+ arrays.map(node.parts, function(part) {
return part instanceof Array
? '["' + js.stringEscape(part[0]) + '", "' + js.stringEscape(part[1]) + '"]'
: '"' + js.stringEscape(part) + '"';
}).join(', ')
+ ']';
regexpIndex = addConst(regexp);
expectedIndex = addConst(
'peg$classExpectation('
+ parts + ', '
+ node.inverted + ', '
+ node.ignoreCase
+ ')'
);
return buildCondition(
[op.MATCH_REGEXP, regexpIndex],
[op.ACCEPT_N, 1],
[op.FAIL, expectedIndex]
);
},
any: function() {
var expectedIndex = addConst('peg$anyExpectation()');
return buildCondition(
[op.MATCH_ANY],
[op.ACCEPT_N, 1],
[op.FAIL, expectedIndex]
);
}
});
generate(ast);
}
module.exports = generateBytecode;

1394
node_modules/pegjs/lib/compiler/passes/generate-js.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,42 @@
"use strict";
var arrays = require("../../utils/arrays"),
visitor = require("../visitor");
/*
* Removes proxy rules -- that is, rules that only delegate to other rule.
*/
function removeProxyRules(ast, options) {
function isProxyRule(node) {
return node.type === "rule" && node.expression.type === "rule_ref";
}
function replaceRuleRefs(ast, from, to) {
var replace = visitor.build({
rule_ref: function(node) {
if (node.name === from) {
node.name = to;
}
}
});
replace(ast);
}
var indices = [];
arrays.each(ast.rules, function(rule, i) {
if (isProxyRule(rule)) {
replaceRuleRefs(ast, rule.name, rule.expression.name);
if (!arrays.contains(options.allowedStartRules, rule.name)) {
indices.push(i);
}
}
});
indices.reverse();
arrays.each(indices, function(i) { ast.rules.splice(i, 1); });
}
module.exports = removeProxyRules;

View File

@@ -0,0 +1,54 @@
"use strict";
var GrammarError = require("../../grammar-error"),
arrays = require("../../utils/arrays"),
objects = require("../../utils/objects"),
visitor = require("../visitor");
/* Checks that each label is defined only once within each scope. */
function reportDuplicateLabels(ast) {
function checkExpressionWithClonedEnv(node, env) {
check(node.expression, objects.clone(env));
}
var check = visitor.build({
rule: function(node) {
check(node.expression, { });
},
choice: function(node, env) {
arrays.each(node.alternatives, function(alternative) {
check(alternative, objects.clone(env));
});
},
action: checkExpressionWithClonedEnv,
labeled: function(node, env) {
if (env.hasOwnProperty(node.label)) {
throw new GrammarError(
"Label \"" + node.label + "\" is already defined "
+ "at line " + env[node.label].start.line + ", "
+ "column " + env[node.label].start.column + ".",
node.location
);
}
check(node.expression, env);
env[node.label] = node.location;
},
text: checkExpressionWithClonedEnv,
simple_and: checkExpressionWithClonedEnv,
simple_not: checkExpressionWithClonedEnv,
optional: checkExpressionWithClonedEnv,
zero_or_more: checkExpressionWithClonedEnv,
one_or_more: checkExpressionWithClonedEnv,
group: checkExpressionWithClonedEnv
});
check(ast);
}
module.exports = reportDuplicateLabels;

View File

@@ -0,0 +1,28 @@
"use strict";
var GrammarError = require("../../grammar-error"),
visitor = require("../visitor");
/* Checks that each rule is defined only once. */
function reportDuplicateRules(ast) {
var rules = {};
var check = visitor.build({
rule: function(node) {
if (rules.hasOwnProperty(node.name)) {
throw new GrammarError(
"Rule \"" + node.name + "\" is already defined "
+ "at line " + rules[node.name].start.line + ", "
+ "column " + rules[node.name].start.column + ".",
node.location
);
}
rules[node.name] = node.location;
}
});
check(ast);
}
module.exports = reportDuplicateRules;

View File

@@ -0,0 +1,57 @@
"use strict";
var arrays = require("../../utils/arrays"),
GrammarError = require("../../grammar-error"),
asts = require("../asts"),
visitor = require("../visitor");
/*
* 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 reportInfiniteRecursion(ast) {
var visitedRules = [];
var check = visitor.build({
rule: function(node) {
visitedRules.push(node.name);
check(node.expression);
visitedRules.pop(node.name);
},
sequence: function(node) {
arrays.every(node.elements, function(element) {
check(element);
return !asts.alwaysConsumesOnSuccess(ast, element);
});
},
rule_ref: function(node) {
if (arrays.contains(visitedRules, node.name)) {
visitedRules.push(node.name);
throw new GrammarError(
"Possible infinite loop when parsing (left recursion: "
+ visitedRules.join(" -> ")
+ ").",
node.location
);
}
check(asts.findRule(ast, node.name));
}
});
check(ast);
}
module.exports = reportInfiniteRecursion;

View File

@@ -0,0 +1,35 @@
"use strict";
var GrammarError = require("../../grammar-error"),
asts = require("../asts"),
visitor = require("../visitor");
/*
* Reports expressions that don't consume any input inside |*| or |+| in the
* grammar, which prevents infinite loops in the generated parser.
*/
function reportInfiniteRepetition(ast) {
var check = visitor.build({
zero_or_more: function(node) {
if (!asts.alwaysConsumesOnSuccess(ast, node.expression)) {
throw new GrammarError(
"Possible infinite loop when parsing (repetition used with an expression that may not consume any input).",
node.location
);
}
},
one_or_more: function(node) {
if (!asts.alwaysConsumesOnSuccess(ast, node.expression)) {
throw new GrammarError(
"Possible infinite loop when parsing (repetition used with an expression that may not consume any input).",
node.location
);
}
}
});
check(ast);
}
module.exports = reportInfiniteRepetition;

View File

@@ -0,0 +1,23 @@
"use strict";
var GrammarError = require("../../grammar-error"),
asts = require("../asts"),
visitor = require("../visitor");
/* Checks that all referenced rules exist. */
function reportUndefinedRules(ast) {
var check = visitor.build({
rule_ref: function(node) {
if (!asts.findRule(ast, node.name)) {
throw new GrammarError(
"Rule \"" + node.name + "\" is not defined.",
node.location
);
}
}
});
check(ast);
}
module.exports = reportUndefinedRules;

72
node_modules/pegjs/lib/compiler/visitor.js generated vendored Normal file
View File

@@ -0,0 +1,72 @@
"use strict";
var objects = require("../utils/objects"),
arrays = require("../utils/arrays");
/* Simple AST node visitor builder. */
var visitor = {
build: function(functions) {
function visit(node) {
return functions[node.type].apply(null, arguments);
}
function visitNop() { }
function visitExpression(node) {
var extraArgs = Array.prototype.slice.call(arguments, 1);
visit.apply(null, [node.expression].concat(extraArgs));
}
function visitChildren(property) {
return function(node) {
var extraArgs = Array.prototype.slice.call(arguments, 1);
arrays.each(node[property], function(child) {
visit.apply(null, [child].concat(extraArgs));
});
};
}
var DEFAULT_FUNCTIONS = {
grammar: function(node) {
var extraArgs = Array.prototype.slice.call(arguments, 1);
if (node.initializer) {
visit.apply(null, [node.initializer].concat(extraArgs));
}
arrays.each(node.rules, function(rule) {
visit.apply(null, [rule].concat(extraArgs));
});
},
initializer: visitNop,
rule: visitExpression,
named: visitExpression,
choice: visitChildren("alternatives"),
action: visitExpression,
sequence: visitChildren("elements"),
labeled: visitExpression,
text: visitExpression,
simple_and: visitExpression,
simple_not: visitExpression,
optional: visitExpression,
zero_or_more: visitExpression,
one_or_more: visitExpression,
group: visitExpression,
semantic_and: visitNop,
semantic_not: visitNop,
rule_ref: visitNop,
literal: visitNop,
"class": visitNop,
any: visitNop
};
objects.defaults(functions, DEFAULT_FUNCTIONS);
return visit;
}
};
module.exports = visitor;