Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- const acorn = require("acorn")
- const walk = require("acorn/dist/walk")
- var getTarget = function (field, st, cb) {
- // next lets see its an identifier, if so, its right on one of the state objects
- var isId = field.type == 'Identifier';
- var name = field.name;
- var value, obj, prop;
- var isObj = field.hasOwnProperty('object') && field.hasOwnProperty('property');
- if (isId) {
- // we keep track of how many we found to avoid duplicates in different objects
- var found = 0;
- var len = st.refs && st.refs.length;
- for (var i = 0; i < len; i++) {
- var ref = st.refs[i];
- if (ref && ref[name] != undefined) {
- obj = ref;
- prop = name;
- value = ref[name];
- found++;
- }
- }
- if (found > 1) throw new Error('environment has duplicate keys named ' + name);
- return cb(value, obj, prop);
- }
- if (isObj) {
- // if we didn't find it we'll try
- obj = field.object && field.object.value;
- if (!obj) {
- var found = 0;
- var len = st.refs && st.refs.length;
- for (var i = 0; i < len; i++) {
- var ref = st.refs[i];
- if (ref && ref[field.object.name] != undefined) {
- obj = ref[field.object.name];
- found++;
- }
- }
- if (found > 1) throw new Error('environment has duplicate keys named ' + name);
- }
- prop = field.property && (field.property.name || field.property.value);
- if (obj) {
- value = obj[prop];
- } else {
- throw new Error('no such object ' + obj)
- }
- return cb(value, obj, prop);
- }
- // see if we set a value on the node from a prior operation.
- if (field.hasOwnProperty('value')) return cb(field.value);
- }
- var handlers = {
- ExpressionStatement: function (node, st) {
- getTarget(node.expression, st, function (v) {
- st.result = v;
- })
- },
- ObjectExpression: function (node, st) {
- var obj = {};
- if (node.properties) {
- for (var i = 0; i < node.properties.length; i++) {
- var val = node.properties[i].value;
- obj[node.properties[i].key.name] = val && val.value;
- }
- }
- node.value = obj;
- },
- SequenceExpression: function (node, st) {
- node.value = (node.expressions && node.expressions.length) ? node.expressions[node.expressions.length - 1].value : null;
- },
- AssignmentExpression: function (node, st) {
- // var operator = node.operator, prefix = node.prefix, obj = node.left.object && node.left.object.value,
- // prop = node.left.property && node.left.property.name || node.left.name, val = node.right.value;
- var operator = node.operator, obj, prop, val;
- getTarget(node.left, st, function (v, o, p) {
- obj = o;
- prop = p;
- });
- getTarget(node.right, st, function (v, o, p) {
- val = v;
- });
- if (!obj)
- throw new Error('cannot operate on variables like "' + prop + '" must be an object in the environment');
- if (operator == '=') {
- obj[prop] = val;
- node.value = val;
- } else {
- throw new Error('operator ' + operator + ' not recognized for assignment operation')
- }
- },
- ConditionalExpression: function (node, st) {
- node.value = (node.test.value) ? node.consequent.value : node.alternate.value;
- },
- UpdateExpression: function (node, st) {
- var obj, prop, value, operator = node.operator, prefix = node.prefix;
- getTarget(node.argument, st, function (val, o, p) {
- obj = o;
- prop = p;
- value = val;
- });
- var newVal = value;
- switch (operator) {
- case '++':
- newVal = ++obj[prop];
- break;
- case '--':
- newVal = --obj[prop];
- break;
- default :
- throw new Error('update using operator ' + operator + ' not supported');
- }
- node.value = (prefix) ? newVal : value;
- },
- UnaryExpression: function (node, st) {
- var obj, prop, value, operator = node.operator;
- getTarget(node.argument, st, function (val, o, p) {
- obj = o;
- prop = p;
- value = val;
- });
- var newVal = value;
- switch (operator) {
- case '!':
- newVal = !obj[prop];
- break;
- case '~':
- newVal = ~obj[prop];
- break;
- case '-':
- newVal = -obj[prop];
- break;
- case 'empty':
- newVal = obj === null || prop === null || obj === undefined || prop === undefined || obj[prop] === null || obj[prop] === undefined || obj[prop].length === 0;
- break;
- default :
- throw new Error('unary using operator ' + operator + ' not supported');
- }
- node.value = newVal;
- },
- MemberExpression: function (node, st) {
- // if (!node.value){
- // look it up in state
- // var obj = st[node.object.name];
- var obj, prop, value, operator = node.operator, prefix = node.prefix;
- getTarget(node, st, function (val, o, p) {
- obj = o;
- prop = p;
- value = val;
- });
- node.object.value = obj;
- node.property.value = prop;
- if (obj)
- node.value = obj[prop];
- // }
- },
- Identifier: function (node, st) {
- // if (!node.value){
- // look it up in state
- // var obj = st[node.object.name];
- var obj, prop, value, operator = node.operator, prefix = node.prefix;
- getTarget(node, st, function (val, o, p) {
- obj = o;
- prop = p;
- value = val;
- });
- if (!node.object)
- node.object = {};
- node.object.value = obj;
- if (!node.property)
- node.property = {};
- node.property.value = prop;
- if (obj)
- node.value = obj[prop];
- // }
- },
- CallExpression: function (node, st) {
- // var func = node.callee.name;
- // var found = 0;
- var args = [];
- if (node.args) {
- for (var i = 0; i < node.args.length; i++) {
- args.push(node.args[i].value);
- }
- }
- var obj, prop;
- getTarget(node.callee, st, function (val, o, p) {
- obj = o;
- prop = p;
- })
- if (typeof obj[prop] == 'function') {
- node.value = obj[prop].apply(obj, args)
- } else {
- throw new Error('property ' + prop + ' on ' + node.callee.name + ' is not a function');
- }
- },
- ArrayExpression: function (node, st) {
- var arr = [];
- if (node.elements) {
- for (var i = 0; i < node.elements.length; i++) {
- arr.push(node.elements[i].value);
- }
- }
- node.value = arr;
- },
- LogicalExpression: function (node, st) {
- var left, right, operator = node.operator, result = null;
- getTarget(node.left, st, function (val) {
- left = val;
- })
- getTarget(node.right, st, function (val) {
- right = val;
- });
- switch (operator) {
- case 'and':
- case '&&':
- result = left && right;
- break;
- case 'or':
- case '||':
- result = left || right;
- break;
- }
- node.value = result;
- },
- BinaryExpression: function (node, st) {
- var left, right, operator = node.operator, result = null;
- getTarget(node.left, st, function (val) {
- left = val;
- })
- getTarget(node.right, st, function (val) {
- right = val;
- });
- switch (operator) {
- // case '=':
- // result = left = right;
- // break;
- case '+':
- result = left + right;
- break;
- case '-':
- result = left - right;
- break;
- case '*':
- result = left * right;
- break;
- case 'div':
- case '/':
- result = left / right;
- break;
- case 'mod':
- case '%':
- result = left % right;
- break;
- case 'eq':
- case '==':
- result = left == right;
- break;
- case '===':
- result = left === right;
- break;
- case 'ne':
- case '!=':
- result = left != right;
- break;
- case '!==':
- result = left !== right;
- break;
- case 'gt':
- case '>':
- result = left > right;
- break;
- case 'lt':
- case '<':
- result = left < right;
- break;
- case 'ge':
- case '>=':
- result = left >= right;
- break;
- case 'le':
- case '<=':
- result = left <= right;
- break;
- case '&':
- result = left & right;
- break;
- case '|':
- result = left | right;
- break;
- case '^':
- result = left ^ right;
- break;
- case '>>':
- result = left >> right;
- break;
- case '>>>':
- result = left >>> right;
- break;
- case '<<':
- result = left << right;
- break;
- case 'and':
- case '&&':
- result = left && right;
- break;
- case 'or':
- case '||':
- result = left || right;
- break;
- default:
- throw new Error('operator ' + operator + ' not supported');
- }
- node.value = result;
- }
- };
- const run = (p, obj1, obj2) => {
- var args = Array.prototype.slice.call(arguments, 1);
- var input = {refs: args};
- walk.simple(p, handlers, null, input);
- return input.result;
- }
- const parsed = acorn.parse("1 + 1");
- // helper function for traversal
- run(parsed);
Add Comment
Please, Sign In to add comment