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
parent
ff8e877fce
commit
5adad3ae12
@ -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;
|
@ -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,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;
|
Loading…
Reference in New Issue