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; };