You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
4.2 KiB
JavaScript
118 lines
4.2 KiB
JavaScript
7 years ago
|
var unparse = require('escodegen').generate;
|
||
|
|
||
|
module.exports = function (ast, vars) {
|
||
|
if (!vars) vars = {};
|
||
|
var FAIL = {};
|
||
|
|
||
|
var result = (function walk (node) {
|
||
|
if (node.type === 'Literal') {
|
||
|
return node.value;
|
||
|
}
|
||
|
else if (node.type === 'UnaryExpression'){
|
||
|
var val = walk(node.argument)
|
||
|
if (node.operator === '+') return +val
|
||
|
if (node.operator === '-') return -val
|
||
|
if (node.operator === '~') return ~val
|
||
|
if (node.operator === '!') return !val
|
||
|
return FAIL
|
||
|
}
|
||
|
else if (node.type === 'ArrayExpression') {
|
||
|
var xs = [];
|
||
|
for (var i = 0, l = node.elements.length; i < l; i++) {
|
||
|
var x = walk(node.elements[i]);
|
||
|
if (x === FAIL) return FAIL;
|
||
|
xs.push(x);
|
||
|
}
|
||
|
return xs;
|
||
|
}
|
||
|
else if (node.type === 'ObjectExpression') {
|
||
|
var obj = {};
|
||
|
for (var i = 0; i < node.properties.length; i++) {
|
||
|
var prop = node.properties[i];
|
||
|
var value = prop.value === null
|
||
|
? prop.value
|
||
|
: walk(prop.value)
|
||
|
;
|
||
|
if (value === FAIL) return FAIL;
|
||
|
obj[prop.key.value || prop.key.name] = value;
|
||
|
}
|
||
|
return obj;
|
||
|
}
|
||
|
else if (node.type === 'BinaryExpression' ||
|
||
|
node.type === 'LogicalExpression') {
|
||
|
var l = walk(node.left);
|
||
|
if (l === FAIL) return FAIL;
|
||
|
var r = walk(node.right);
|
||
|
if (r === FAIL) return FAIL;
|
||
|
|
||
|
var op = node.operator;
|
||
|
if (op === '==') return l == r;
|
||
|
if (op === '===') return l === r;
|
||
|
if (op === '!=') return l != r;
|
||
|
if (op === '!==') return l !== r;
|
||
|
if (op === '+') return l + r;
|
||
|
if (op === '-') return l - r;
|
||
|
if (op === '*') return l * r;
|
||
|
if (op === '/') return l / r;
|
||
|
if (op === '%') return l % r;
|
||
|
if (op === '<') return l < r;
|
||
|
if (op === '<=') return l <= r;
|
||
|
if (op === '>') return l > r;
|
||
|
if (op === '>=') return l >= r;
|
||
|
if (op === '|') return l | r;
|
||
|
if (op === '&') return l & r;
|
||
|
if (op === '^') return l ^ r;
|
||
|
if (op === '&&') return l && r;
|
||
|
if (op === '||') return l || r;
|
||
|
|
||
|
return FAIL;
|
||
|
}
|
||
|
else if (node.type === 'Identifier') {
|
||
|
if ({}.hasOwnProperty.call(vars, node.name)) {
|
||
|
return vars[node.name];
|
||
|
}
|
||
|
else return FAIL;
|
||
|
}
|
||
|
else if (node.type === 'CallExpression') {
|
||
|
var callee = walk(node.callee);
|
||
|
if (callee === FAIL) return FAIL;
|
||
|
|
||
|
var ctx = node.callee.object ? walk(node.callee.object) : FAIL;
|
||
|
if (ctx === FAIL) ctx = null;
|
||
|
|
||
|
var args = [];
|
||
|
for (var i = 0, l = node.arguments.length; i < l; i++) {
|
||
|
var x = walk(node.arguments[i]);
|
||
|
if (x === FAIL) return FAIL;
|
||
|
args.push(x);
|
||
|
}
|
||
|
return callee.apply(ctx, args);
|
||
|
}
|
||
|
else if (node.type === 'MemberExpression') {
|
||
|
var obj = walk(node.object);
|
||
|
if (obj === FAIL) return FAIL;
|
||
|
if (node.property.type === 'Identifier') {
|
||
|
return obj[node.property.name];
|
||
|
}
|
||
|
var prop = walk(node.property);
|
||
|
if (prop === FAIL) return FAIL;
|
||
|
return obj[prop];
|
||
|
}
|
||
|
else if (node.type === 'ConditionalExpression') {
|
||
|
var val = walk(node.test)
|
||
|
if (val === FAIL) return FAIL;
|
||
|
return val ? walk(node.consequent) : walk(node.alternate)
|
||
|
}
|
||
|
else if (node.type === 'FunctionExpression') {
|
||
|
var keys = Object.keys(vars);
|
||
|
var vals = keys.map(function(key) {
|
||
|
return vars[key];
|
||
|
});
|
||
|
return Function(keys.join(', '), 'return ' + unparse(node)).apply(null, vals);
|
||
|
}
|
||
|
else return FAIL;
|
||
|
})(ast);
|
||
|
|
||
|
return result === FAIL ? undefined : result;
|
||
|
};
|