commando.html5/node_modules/burrito/index.js

209 lines
5.1 KiB
JavaScript

var uglify = require('uglify-js');
var parser = uglify.parser;
var parse = function (expr) {
if (typeof expr !== 'string') throw 'expression should be a string';
try {
var ast = parser.parse.apply(null, arguments);
}
catch (err) {
if (err.message === undefined
|| err.line === undefined
|| err.col === undefined
|| err.pos === undefined
) { throw err }
var e = new SyntaxError(
err.message
+ '\n at line ' + err.line + ':' + err.col + ' in expression:\n\n'
+ ' ' + expr.split(/\r?\n/)[err.line]
);
e.original = err;
e.line = err.line;
e.col = err.col;
e.pos = err.pos;
throw e;
}
return ast;
};
var deparse = function (ast, b) {
return uglify.uglify.gen_code(ast, { beautify : b });
};
var traverse = require('traverse');
var vm = require('vm');
var burrito = module.exports = function (code, cb) {
var ast = Array_isArray(code)
? code // already an ast
: parse(code.toString(), false, true)
;
var ast_ = traverse(ast).map(function mapper () {
wrapNode(this, cb);
});
return deparse(parse(deparse(ast_)), true);
};
var wrapNode = burrito.wrapNode = function (state, cb) {
var node = state.node;
var ann = Array_isArray(node) && node[0]
&& typeof node[0] === 'object' && node[0].name
? node[0]
: null
;
if (!ann) return undefined;
var self = {
name : ann.name,
node : node,
start : node[0].start,
end : node[0].end,
value : node.slice(1),
state : state
};
self.wrap = function (s) {
var subsrc = deparse(
traverse(node).map(function (x) {
if (!this.isRoot) wrapNode(this, cb)
})
);
if (self.name === 'binary') {
var a = deparse(traverse(node[2]).map(function (x) {
if (!this.isRoot) wrapNode(this, cb)
}));
var b = deparse(traverse(node[3]).map(function (x) {
if (!this.isRoot) wrapNode(this, cb)
}));
}
var src = '';
if (typeof s === 'function') {
if (self.name === 'binary') {
src = s(subsrc, a, b);
}
else {
src = s(subsrc);
}
}
else {
src = s.toString()
.replace(/%s/g, function () {
return subsrc
})
;
if (self.name === 'binary') {
src = src
.replace(/%a/g, function () { return a })
.replace(/%b/g, function () { return b })
;
}
}
var expr = parse(src);
state.update(expr, true);
};
var cache = {};
self.parent = state.isRoot ? null : function () {
if (!cache.parent) {
var s = state;
var x;
do {
s = s.parent;
if (s) x = wrapNode(s);
} while (s && !x);
cache.parent = x;
}
return cache.parent;
};
self.source = function () {
if (!cache.source) cache.source = deparse(node);
return cache.source;
};
self.label = function () {
return burrito.label(self);
};
if (cb) cb.call(state, self);
if (self.node[0].name === 'conditional') {
self.wrap('[%s][0]');
}
return self;
}
burrito.microwave = function (code, context, cb) {
if (!cb) { cb = context; context = {} };
if (!context) context = {};
var src = burrito(code, cb);
return vm.runInNewContext(src, context);
};
burrito.generateName = function (len) {
var name = '';
var lower = '$'.charCodeAt(0);
var upper = 'z'.charCodeAt(0);
while (name.length < len) {
var c = String.fromCharCode(Math.floor(
Math.random() * (upper - lower + 1) + lower
));
if ((name + c).match(/^[A-Za-z_$][A-Za-z0-9_$]*$/)) name += c;
}
return name;
};
burrito.parse = parse;
burrito.deparse = deparse;
burrito.label = function (node) {
if (node.name === 'call') {
if (typeof node.value[0] === 'string') {
return node.value[0];
}
else if (node.value[0] && typeof node.value[0][1] === 'string') {
return node.value[0][1];
}
else if (node.value[0][0] === 'dot') {
return node.value[0][node.value[0].length - 1];
}
else {
return null;
}
}
else if (node.name === 'var') {
return node.value[0].map(function (x) { return x[0] });
}
else if (node.name === 'defun') {
return node.value[0];
}
else if (node.name === 'function') {
return node.value[0];
}
else {
return null;
}
};
var Array_isArray = Array.isArray || function isArray (xs) {
return Object.prototype.toString.call(xs) === '[object Array]';
};