Utility functions cleanup: Split lib/utils.js

Split lib/utils.js into multiple files. Some of the functions were
generic, these were moved into files in lib/utils. Other funtions were
specific for the compiler, these were moved to files in lib/compiler.

This commit only moves functions around -- there is no renaming and
cleanup performed. Both will come later.
redux
David Majda 10 years ago
parent ff8e877fce
commit 5adad3ae12

@ -5,10 +5,15 @@ PEGJS_VERSION = `cat $(VERSION_FILE)`
# ===== Modules =====
# Order matters -- dependencies must be listed before modules dependent on them.
MODULES = utils \
MODULES = utils/arrays \
utils/objects \
utils/classes \
grammar-error \
parser \
compiler/asts \
compiler/visitor \
compiler/opcodes \
compiler/javascript \
compiler/passes/generate-bytecode \
compiler/passes/generate-javascript \
compiler/passes/remove-proxy-rules \

@ -1,4 +1,5 @@
var utils = require("./utils");
var arrays = require("./utils/arrays"),
objects = require("./utils/objects");
var compiler = {
/*
@ -29,10 +30,10 @@ var compiler = {
* cause its malfunction.
*/
compile: function(ast, passes) {
var options = arguments.length > 2 ? utils.clone(arguments[2]) : {},
var options = arguments.length > 2 ? objects.clone(arguments[2]) : {},
stage;
utils.defaults(options, {
objects.defaults(options, {
allowedStartRules: [ast.rules[0].name],
cache: false,
optimize: "speed",
@ -41,7 +42,7 @@ var compiler = {
for (stage in passes) {
if (passes.hasOwnProperty(stage)) {
utils.each(passes[stage], function(p) { p(ast, options); });
arrays.each(passes[stage], function(p) { p(ast, options); });
}
}

@ -0,0 +1,14 @@
var arrays = require("../utils/arrays");
/* AST utilities. */
var asts = {
findRuleByName: function(ast, name) {
return arrays.find(ast.rules, function(r) { return r.name === name; });
},
indexOfRuleByName: function(ast, name) {
return arrays.indexOf(ast.rules, function(r) { return r.name === name; });
}
};
module.exports = asts;

@ -0,0 +1,99 @@
/* JavaScript code generation helpers. */
var javascript = {
/*
* Returns a string padded on the left to a desired length with a character.
*
* The code needs to be in sync with the code template in the compilation
* function for "action" nodes.
*/
padLeft: function(input, padding, length) {
var result = input;
var padLength = length - input.length;
for (var i = 0; i < padLength; i++) {
result = padding + result;
}
return result;
},
/*
* Returns an escape sequence for given character. Uses \x for characters <=
* 0xFF to save space, \u for the rest.
*
* The code needs to be in sync with the code template in the compilation
* function for "action" nodes.
*/
escape: function(ch) {
var charCode = ch.charCodeAt(0);
var escapeChar;
var length;
if (charCode <= 0xFF) {
escapeChar = 'x';
length = 2;
} else {
escapeChar = 'u';
length = 4;
}
return '\\' + escapeChar + javascript.padLeft(charCode.toString(16).toUpperCase(), '0', length);
},
/*
* Surrounds the string with quotes and escapes characters inside so that the
* result is a valid JavaScript string.
*
* The code needs to be in sync with the code template in the compilation
* function for "action" nodes.
*/
quote: 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 "\0" and "\v" escape sequences are not used because JSHint does
* not like the first and IE the second.
*/
return '"' + s
.replace(/\\/g, '\\\\') // backslash
.replace(/"/g, '\\"') // closing quote character
.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-\x1F\x80-\uFFFF]/g, javascript.escape)
+ '"';
},
/*
* Escapes characters inside the string so that it can be used as a list of
* characters in a character class of a regular expression.
*/
quoteForRegexpClass: 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(/[\x01-\x08\x0E-\x1F\x80-\uFFFF]/g, javascript.escape);
}
};
module.exports = javascript;

@ -1,5 +1,9 @@
var utils = require("../../utils"),
op = require("../opcodes");
var arrays = require("../../utils/arrays"),
objects = require("../../utils/objects"),
asts = require("../asts"),
visitor = require("../visitor"),
op = require("../opcodes"),
js = require("../javascript");
/* Generates bytecode.
*
@ -173,7 +177,7 @@ function generateBytecode(ast) {
var consts = [];
function addConst(value) {
var index = utils.indexOf(consts, function(c) { return c === value; });
var index = arrays.indexOf(consts, function(c) { return c === value; });
return index === -1 ? consts.push(value) - 1 : index;
}
@ -201,7 +205,7 @@ function generateBytecode(ast) {
}
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; });
return [op.CALL, functionIndex, delta, params.length].concat(params);
}
@ -236,7 +240,7 @@ function generateBytecode(ast) {
}
function buildSemanticPredicate(code, negative, context) {
var functionIndex = addFunctionConst(utils.keys(context.env), code),
var functionIndex = addFunctionConst(objects.keys(context.env), code),
undefinedIndex = addConst('void 0'),
failedIndex = addConst('peg$FAILED');
@ -264,9 +268,9 @@ function generateBytecode(ast) {
);
}
var generate = utils.buildNodeVisitor({
var generate = visitor.buildNodeVisitor({
grammar: function(node) {
utils.each(node.rules, generate);
arrays.each(node.rules, generate);
node.consts = consts;
},
@ -281,7 +285,7 @@ function generateBytecode(ast) {
named: function(node, context) {
var nameIndex = addConst(
'{ type: "other", description: ' + utils.quote(node.name) + ' }'
'{ type: "other", description: ' + js.quote(node.name) + ' }'
);
/*
@ -331,7 +335,7 @@ function generateBytecode(ast) {
env: env,
action: node
}),
functionIndex = addFunctionConst(utils.keys(env), node.code);
functionIndex = addFunctionConst(objects.keys(env), node.code);
return emitCall
? buildSequence(
@ -380,7 +384,7 @@ function generateBytecode(ast) {
} else {
if (context.action) {
functionIndex = addFunctionConst(
utils.keys(context.env),
objects.keys(context.env),
context.action.code
);
@ -505,7 +509,7 @@ function generateBytecode(ast) {
},
rule_ref: function(node) {
return [op.RULE, utils.indexOfRuleByName(ast, node.name)];
return [op.RULE, asts.indexOfRuleByName(ast, node.name)];
},
literal: function(node) {
@ -513,14 +517,14 @@ function generateBytecode(ast) {
if (node.value.length > 0) {
stringIndex = addConst(node.ignoreCase
? utils.quote(node.value.toLowerCase())
: utils.quote(node.value)
? js.quote(node.value.toLowerCase())
: js.quote(node.value)
);
expectedIndex = addConst([
'{',
'type: "literal",',
'value: ' + utils.quote(node.value) + ',',
'description: ' + utils.quote(utils.quote(node.value)),
'value: ' + js.quote(node.value) + ',',
'description: ' + js.quote(js.quote(node.value)),
'}'
].join(' '));
@ -551,12 +555,12 @@ function generateBytecode(ast) {
if (node.parts.length > 0) {
regexp = '/^['
+ (node.inverted ? '^' : '')
+ utils.map(node.parts, function(part) {
+ arrays.map(node.parts, function(part) {
return part instanceof Array
? utils.quoteForRegexpClass(part[0])
? js.quoteForRegexpClass(part[0])
+ '-'
+ utils.quoteForRegexpClass(part[1])
: utils.quoteForRegexpClass(part);
+ js.quoteForRegexpClass(part[1])
: js.quoteForRegexpClass(part);
}).join('')
+ ']/' + (node.ignoreCase ? 'i' : '');
} else {
@ -571,8 +575,8 @@ function generateBytecode(ast) {
expectedIndex = addConst([
'{',
'type: "class",',
'value: ' + utils.quote(node.rawText) + ',',
'description: ' + utils.quote(node.rawText),
'value: ' + js.quote(node.rawText) + ',',
'description: ' + js.quote(node.rawText),
'}'
].join(' '));

@ -1,5 +1,7 @@
var utils = require("../../utils"),
op = require("../opcodes");
var arrays = require("../../utils/arrays"),
asts = require("../asts"),
op = require("../opcodes"),
js = require("../javascript");
/* Generates parser JavaScript code. */
function generateJavaScript(ast, options) {
@ -17,11 +19,11 @@ function generateJavaScript(ast, options) {
'],',
'',
'peg$bytecode = [',
indent2(utils.map(
indent2(arrays.map(
ast.rules,
function(rule) {
return 'peg$decode('
+ utils.quote(utils.map(
+ js.quote(arrays.map(
rule.bytecode,
function(b) { return String.fromCharCode(b + 32); }
).join(''))
@ -31,7 +33,7 @@ function generateJavaScript(ast, options) {
'],'
].join('\n');
} else {
return utils.map(
return arrays.map(
ast.consts,
function(c, i) { return 'peg$c' + i + ' = ' + c + ','; }
).join('\n');
@ -352,7 +354,7 @@ function generateJavaScript(ast, options) {
return s(this.sp--);
} else {
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;
return values;
@ -433,7 +435,7 @@ function generateJavaScript(ast, options) {
paramsLength = bc[ip + baseLength - 1];
var value = c(bc[ip + 1]) + '('
+ utils.map(
+ arrays.map(
bc.slice(ip + baseLength, ip + baseLength + paramsLength),
function(p) { return stack.index(p); }
).join(', ')
@ -626,13 +628,13 @@ function generateJavaScript(ast, options) {
parts.push([
'function peg$parse' + rule.name + '() {',
' var ' + utils.map(utils.range(0, stack.maxSp + 1), s).join(', ') + ';',
' var ' + arrays.map(arrays.range(0, stack.maxSp + 1), s).join(', ') + ';',
''
].join('\n'));
if (options.cache) {
parts.push(indent2(
generateCacheHeader(utils.indexOfRuleByName(ast, rule.name))
generateCacheHeader(asts.indexOfRuleByName(ast, rule.name))
));
}
@ -692,12 +694,12 @@ function generateJavaScript(ast, options) {
if (options.optimize === "size") {
startRuleIndices = '{ '
+ utils.map(
+ arrays.map(
options.allowedStartRules,
function(r) { return r + ': ' + utils.indexOfRuleByName(ast, r); }
function(r) { return r + ': ' + asts.indexOfRuleByName(ast, r); }
).join(', ')
+ ' }';
startRuleIndex = utils.indexOfRuleByName(ast, options.allowedStartRules[0]);
startRuleIndex = asts.indexOfRuleByName(ast, options.allowedStartRules[0]);
parts.push([
' peg$startRuleIndices = ' + startRuleIndices + ',',
@ -705,7 +707,7 @@ function generateJavaScript(ast, options) {
].join('\n'));
} else {
startRuleFunctions = '{ '
+ utils.map(
+ arrays.map(
options.allowedStartRules,
function(r) { return r + ': peg$parse' + r; }
).join(', ')
@ -936,7 +938,7 @@ function generateJavaScript(ast, options) {
parts.push(indent4(generateInterpreter()));
parts.push('');
} else {
utils.each(ast.rules, function(rule) {
arrays.each(ast.rules, function(rule) {
parts.push(indent4(generateRuleFunction(rule)));
parts.push('');
});

@ -1,4 +1,5 @@
var utils = require("../../utils");
var arrays = require("../../utils/arrays"),
visitor = require("../visitor");
/*
* Removes proxy rules -- that is, rules that only delegate to other rule.
@ -17,13 +18,13 @@ function removeProxyRules(ast, options) {
function replaceInSubnodes(propertyName) {
return function(node, from, to) {
utils.each(node[propertyName], function(subnode) {
arrays.each(node[propertyName], function(subnode) {
replace(subnode, from, to);
});
};
}
var replace = utils.buildNodeVisitor({
var replace = visitor.buildNodeVisitor({
grammar: replaceInSubnodes("rules"),
rule: replaceInExpression,
named: replaceInExpression,
@ -57,10 +58,10 @@ function removeProxyRules(ast, options) {
var indices = [];
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);
}
}
@ -68,7 +69,7 @@ function removeProxyRules(ast, options) {
indices.reverse();
utils.each(indices, function(index) {
arrays.each(indices, function(index) {
ast.rules.splice(index, 1);
});
}

@ -1,5 +1,7 @@
var utils = require("../../utils"),
GrammarError = require("../../grammar-error");
var arrays = require("../../utils/arrays"),
GrammarError = require("../../grammar-error"),
asts = require("../asts"),
visitor = require("../visitor");
/* Checks that no left recursion is present. */
function reportLeftRecursion(ast) {
@ -11,13 +13,13 @@ function reportLeftRecursion(ast) {
function checkSubnodes(propertyName) {
return function(node, appliedRules) {
utils.each(node[propertyName], function(subnode) {
arrays.each(node[propertyName], function(subnode) {
check(subnode, appliedRules);
});
};
}
var check = utils.buildNodeVisitor({
var check = visitor.buildNodeVisitor({
grammar: checkSubnodes("rules"),
rule:
@ -48,12 +50,12 @@ function reportLeftRecursion(ast) {
rule_ref:
function(node, appliedRules) {
if (utils.contains(appliedRules, node.name)) {
if (arrays.contains(appliedRules, node.name)) {
throw new GrammarError(
"Left recursion detected for rule \"" + node.name + "\"."
);
}
check(utils.findRuleByName(ast, node.name), appliedRules);
check(asts.findRuleByName(ast, node.name), appliedRules);
},
literal: nop,

@ -1,5 +1,7 @@
var utils = require("../../utils"),
GrammarError = require("../../grammar-error");
var arrays = require("../../utils/arrays"),
GrammarError = require("../../grammar-error"),
asts = require("../asts"),
visitor = require("../visitor");
/* Checks that all referenced rules exist. */
function reportMissingRules(ast) {
@ -8,10 +10,10 @@ function reportMissingRules(ast) {
function checkExpression(node) { check(node.expression); }
function checkSubnodes(propertyName) {
return function(node) { utils.each(node[propertyName], check); };
return function(node) { arrays.each(node[propertyName], check); };
}
var check = utils.buildNodeVisitor({
var check = visitor.buildNodeVisitor({
grammar: checkSubnodes("rules"),
rule: checkExpression,
named: checkExpression,
@ -30,7 +32,7 @@ function reportMissingRules(ast) {
rule_ref:
function(node) {
if (!utils.findRuleByName(ast, node.name)) {
if (!asts.findRuleByName(ast, node.name)) {
throw new GrammarError(
"Referenced rule \"" + node.name + "\" does not exist."
);

@ -0,0 +1,17 @@
/* Simple AST node visitor builder. */
var visitor = {
/*
* Builds a node visitor -- a function which takes a node and any number of
* other parameters, calls an appropriate function according to the node type,
* passes it all its parameters and returns its value. The functions for
* various node types are passed in a parameter to |buildNodeVisitor| as a
* hash.
*/
buildNodeVisitor: function(functions) {
return function(node) {
return functions[node.type].apply(null, arguments);
};
}
};
module.exports = visitor;

@ -1,4 +1,4 @@
var utils = require("./utils");
var classes = require("./utils/classes");
/* Thrown when the grammar contains an error. */
function GrammarError(message) {
@ -6,6 +6,6 @@ function GrammarError(message) {
this.message = message;
}
utils.subclass(GrammarError, Error);
classes.subclass(GrammarError, Error);
module.exports = GrammarError;

@ -1,4 +1,5 @@
var utils = require("./utils");
var arrays = require("./utils/arrays"),
objects = require("./utils/objects");
var PEG = {
/* PEG.js version (uses semantic versioning). */
@ -25,21 +26,21 @@ var PEG = {
for (stage in passes) {
if (passes.hasOwnProperty(stage)) {
converted[stage] = utils.values(passes[stage]);
converted[stage] = objects.values(passes[stage]);
}
}
return converted;
}
var options = arguments.length > 1 ? utils.clone(arguments[1]) : {},
var options = arguments.length > 1 ? objects.clone(arguments[1]) : {},
plugins = "plugins" in options ? options.plugins : [],
config = {
parser: this.parser,
passes: convertPasses(this.compiler.passes)
};
utils.each(plugins, function(p) { p.use(config, options); });
arrays.each(plugins, function(p) { p.use(config, options); });
return this.compiler.compile(
config.parser.parse(grammar),

@ -1,236 +0,0 @@
var utils = {
/* Like Python's |range|, but without |step|. */
range: function(start, stop) {
if (stop === undefined) {
stop = start;
start = 0;
}
var result = new Array(Math.max(0, stop - start));
for (var i = 0, j = start; j < stop; i++, j++) {
result[i] = j;
}
return result;
},
find: function(array, callback) {
var length = array.length;
for (var i = 0; i < length; i++) {
if (callback(array[i])) {
return array[i];
}
}
},
indexOf: function(array, callback) {
var length = array.length;
for (var i = 0; i < length; i++) {
if (callback(array[i])) {
return i;
}
}
return -1;
},
contains: function(array, value) {
/*
* Stupid IE does not have Array.prototype.indexOf, otherwise this function
* would be a one-liner.
*/
var length = array.length;
for (var i = 0; i < length; i++) {
if (array[i] === value) {
return true;
}
}
return false;
},
each: function(array, callback) {
var length = array.length;
for (var i = 0; i < length; i++) {
callback(array[i], i);
}
},
map: function(array, callback) {
var result = [];
var length = array.length;
for (var i = 0; i < length; i++) {
result[i] = callback(array[i], i);
}
return result;
},
pluck: function(array, key) {
return utils.map(array, function (e) { return e[key]; });
},
keys: function(object) {
var result = [];
for (var key in object) {
if (object.hasOwnProperty(key)) {
result.push(key);
}
}
return result;
},
values: function(object) {
var result = [];
for (var key in object) {
if (object.hasOwnProperty(key)) {
result.push(object[key]);
}
}
return result;
},
clone: function(object) {
var result = {};
for (var key in object) {
if (object.hasOwnProperty(key)) {
result[key] = object[key];
}
}
return result;
},
defaults: function(object, defaults) {
for (var key in defaults) {
if (defaults.hasOwnProperty(key)) {
if (!(key in object)) {
object[key] = defaults[key];
}
}
}
},
/*
* The code needs to be in sync with the code template in the compilation
* function for "action" nodes.
*/
subclass: function(child, parent) {
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor();
},
/*
* Returns a string padded on the left to a desired length with a character.
*
* The code needs to be in sync with the code template in the compilation
* function for "action" nodes.
*/
padLeft: function(input, padding, length) {
var result = input;
var padLength = length - input.length;
for (var i = 0; i < padLength; i++) {
result = padding + result;
}
return result;
},
/*
* Returns an escape sequence for given character. Uses \x for characters <=
* 0xFF to save space, \u for the rest.
*
* The code needs to be in sync with the code template in the compilation
* function for "action" nodes.
*/
escape: function(ch) {
var charCode = ch.charCodeAt(0);
var escapeChar;
var length;
if (charCode <= 0xFF) {
escapeChar = 'x';
length = 2;
} else {
escapeChar = 'u';
length = 4;
}
return '\\' + escapeChar + utils.padLeft(charCode.toString(16).toUpperCase(), '0', length);
},
/*
* Surrounds the string with quotes and escapes characters inside so that the
* result is a valid JavaScript string.
*
* The code needs to be in sync with the code template in the compilation
* function for "action" nodes.
*/
quote: 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 "\0" and "\v" escape sequences are not used because JSHint does
* not like the first and IE the second.
*/
return '"' + s
.replace(/\\/g, '\\\\') // backslash
.replace(/"/g, '\\"') // closing quote character
.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-\x1F\x80-\uFFFF]/g, utils.escape)
+ '"';
},
/*
* Escapes characters inside the string so that it can be used as a list of
* characters in a character class of a regular expression.
*/
quoteForRegexpClass: 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(/[\x01-\x08\x0E-\x1F\x80-\uFFFF]/g, utils.escape);
},
/*
* Builds a node visitor -- a function which takes a node and any number of
* other parameters, calls an appropriate function according to the node type,
* passes it all its parameters and returns its value. The functions for
* various node types are passed in a parameter to |buildNodeVisitor| as a
* hash.
*/
buildNodeVisitor: function(functions) {
return function(node) {
return functions[node.type].apply(null, arguments);
};
},
findRuleByName: function(ast, name) {
return utils.find(ast.rules, function(r) { return r.name === name; });
},
indexOfRuleByName: function(ast, name) {
return utils.indexOf(ast.rules, function(r) { return r.name === name; });
}
};
module.exports = utils;

@ -0,0 +1,71 @@
/* Array utilities. */
var arrays = {
/* Like Python's |range|, but without |step|. */
range: function(start, stop) {
if (stop === undefined) {
stop = start;
start = 0;
}
var result = new Array(Math.max(0, stop - start));
for (var i = 0, j = start; j < stop; i++, j++) {
result[i] = j;
}
return result;
},
find: function(array, callback) {
var length = array.length;
for (var i = 0; i < length; i++) {
if (callback(array[i])) {
return array[i];
}
}
},
indexOf: function(array, callback) {
var length = array.length;
for (var i = 0; i < length; i++) {
if (callback(array[i])) {
return i;
}
}
return -1;
},
contains: function(array, value) {
/*
* Stupid IE does not have Array.prototype.indexOf, otherwise this function
* would be a one-liner.
*/
var length = array.length;
for (var i = 0; i < length; i++) {
if (array[i] === value) {
return true;
}
}
return false;
},
each: function(array, callback) {
var length = array.length;
for (var i = 0; i < length; i++) {
callback(array[i], i);
}
},
map: function(array, callback) {
var result = [];
var length = array.length;
for (var i = 0; i < length; i++) {
result[i] = callback(array[i], i);
}
return result;
},
pluck: function(array, key) {
return arrays.map(array, function (e) { return e[key]; });
}
};
module.exports = arrays;

@ -0,0 +1,14 @@
/* Class utilities */
var classes = {
/*
* The code needs to be in sync with the code template in the compilation
* function for "action" nodes.
*/
subclass: function(child, parent) {
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor();
},
};
module.exports = classes;

@ -0,0 +1,44 @@
/* Object utilities. */
var objects = {
keys: function(object) {
var result = [];
for (var key in object) {
if (object.hasOwnProperty(key)) {
result.push(key);
}
}
return result;
},
values: function(object) {
var result = [];
for (var key in object) {
if (object.hasOwnProperty(key)) {
result.push(object[key]);
}
}
return result;
},
clone: function(object) {
var result = {};
for (var key in object) {
if (object.hasOwnProperty(key)) {
result[key] = object[key];
}
}
return result;
},
defaults: function(object, defaults) {
for (var key in defaults) {
if (defaults.hasOwnProperty(key)) {
if (!(key in object)) {
object[key] = defaults[key];
}
}
}
}
};
module.exports = objects;

@ -19,7 +19,10 @@
"examples/javascript.pegjs",
"examples/json.pegjs",
"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",
"lib/compiler/passes/generate-javascript.js",
"lib/compiler/passes/remove-proxy-rules.js",
@ -28,7 +31,9 @@
"lib/grammar-error.js",
"lib/parser.js",
"lib/peg.js",
"lib/utils.js",
"lib/utils/arrays.js",
"lib/utils/classes.js",
"lib/utils/objects.js",
"package.json"
],
"main": "lib/peg",

Loading…
Cancel
Save