Guest User

Untitled

a guest
Jan 20th, 2018
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.68 KB | None | 0 0
  1. const acorn = require("acorn")
  2. const walk = require("acorn/dist/walk")
  3.  
  4. var getTarget = function (field, st, cb) {
  5.  
  6. // next lets see its an identifier, if so, its right on one of the state objects
  7. var isId = field.type == 'Identifier';
  8. var name = field.name;
  9. var value, obj, prop;
  10.  
  11. var isObj = field.hasOwnProperty('object') && field.hasOwnProperty('property');
  12.  
  13.  
  14. if (isId) {
  15. // we keep track of how many we found to avoid duplicates in different objects
  16. var found = 0;
  17.  
  18. var len = st.refs && st.refs.length;
  19. for (var i = 0; i < len; i++) {
  20. var ref = st.refs[i];
  21. if (ref && ref[name] != undefined) {
  22. obj = ref;
  23. prop = name;
  24. value = ref[name];
  25. found++;
  26. }
  27. }
  28. if (found > 1) throw new Error('environment has duplicate keys named ' + name);
  29. return cb(value, obj, prop);
  30. }
  31. if (isObj) {
  32. // if we didn't find it we'll try
  33. obj = field.object && field.object.value;
  34.  
  35. if (!obj) {
  36. var found = 0;
  37.  
  38. var len = st.refs && st.refs.length;
  39. for (var i = 0; i < len; i++) {
  40. var ref = st.refs[i];
  41. if (ref && ref[field.object.name] != undefined) {
  42. obj = ref[field.object.name];
  43. found++;
  44. }
  45. }
  46. if (found > 1) throw new Error('environment has duplicate keys named ' + name);
  47. }
  48.  
  49. prop = field.property && (field.property.name || field.property.value);
  50. if (obj) {
  51. value = obj[prop];
  52. } else {
  53. throw new Error('no such object ' + obj)
  54. }
  55. return cb(value, obj, prop);
  56. }
  57.  
  58. // see if we set a value on the node from a prior operation.
  59. if (field.hasOwnProperty('value')) return cb(field.value);
  60.  
  61. }
  62.  
  63. var handlers = {
  64. ExpressionStatement: function (node, st) {
  65. getTarget(node.expression, st, function (v) {
  66. st.result = v;
  67. })
  68. },
  69. ObjectExpression: function (node, st) {
  70. var obj = {};
  71. if (node.properties) {
  72. for (var i = 0; i < node.properties.length; i++) {
  73. var val = node.properties[i].value;
  74. obj[node.properties[i].key.name] = val && val.value;
  75. }
  76. }
  77. node.value = obj;
  78. },
  79. SequenceExpression: function (node, st) {
  80. node.value = (node.expressions && node.expressions.length) ? node.expressions[node.expressions.length - 1].value : null;
  81. },
  82. AssignmentExpression: function (node, st) {
  83. // var operator = node.operator, prefix = node.prefix, obj = node.left.object && node.left.object.value,
  84. // prop = node.left.property && node.left.property.name || node.left.name, val = node.right.value;
  85.  
  86. var operator = node.operator, obj, prop, val;
  87.  
  88. getTarget(node.left, st, function (v, o, p) {
  89. obj = o;
  90. prop = p;
  91. });
  92. getTarget(node.right, st, function (v, o, p) {
  93. val = v;
  94. });
  95.  
  96. if (!obj)
  97. throw new Error('cannot operate on variables like "' + prop + '" must be an object in the environment');
  98.  
  99. if (operator == '=') {
  100. obj[prop] = val;
  101. node.value = val;
  102. } else {
  103. throw new Error('operator ' + operator + ' not recognized for assignment operation')
  104. }
  105. },
  106. ConditionalExpression: function (node, st) {
  107. node.value = (node.test.value) ? node.consequent.value : node.alternate.value;
  108. },
  109. UpdateExpression: function (node, st) {
  110. var obj, prop, value, operator = node.operator, prefix = node.prefix;
  111. getTarget(node.argument, st, function (val, o, p) {
  112. obj = o;
  113. prop = p;
  114. value = val;
  115. });
  116. var newVal = value;
  117. switch (operator) {
  118. case '++':
  119. newVal = ++obj[prop];
  120. break;
  121. case '--':
  122. newVal = --obj[prop];
  123. break;
  124. default :
  125. throw new Error('update using operator ' + operator + ' not supported');
  126. }
  127. node.value = (prefix) ? newVal : value;
  128. },
  129. UnaryExpression: function (node, st) {
  130. var obj, prop, value, operator = node.operator;
  131. getTarget(node.argument, st, function (val, o, p) {
  132. obj = o;
  133. prop = p;
  134. value = val;
  135. });
  136. var newVal = value;
  137. switch (operator) {
  138. case '!':
  139. newVal = !obj[prop];
  140. break;
  141. case '~':
  142. newVal = ~obj[prop];
  143. break;
  144. case '-':
  145. newVal = -obj[prop];
  146. break;
  147. case 'empty':
  148. newVal = obj === null || prop === null || obj === undefined || prop === undefined || obj[prop] === null || obj[prop] === undefined || obj[prop].length === 0;
  149. break;
  150. default :
  151. throw new Error('unary using operator ' + operator + ' not supported');
  152. }
  153. node.value = newVal;
  154. },
  155. MemberExpression: function (node, st) {
  156. // if (!node.value){
  157. // look it up in state
  158. // var obj = st[node.object.name];
  159. var obj, prop, value, operator = node.operator, prefix = node.prefix;
  160. getTarget(node, st, function (val, o, p) {
  161. obj = o;
  162. prop = p;
  163. value = val;
  164. });
  165. node.object.value = obj;
  166. node.property.value = prop;
  167. if (obj)
  168. node.value = obj[prop];
  169. // }
  170. },
  171. Identifier: function (node, st) {
  172. // if (!node.value){
  173. // look it up in state
  174. // var obj = st[node.object.name];
  175. var obj, prop, value, operator = node.operator, prefix = node.prefix;
  176. getTarget(node, st, function (val, o, p) {
  177. obj = o;
  178. prop = p;
  179. value = val;
  180. });
  181.  
  182. if (!node.object)
  183. node.object = {};
  184.  
  185. node.object.value = obj;
  186. if (!node.property)
  187. node.property = {};
  188.  
  189. node.property.value = prop;
  190. if (obj)
  191. node.value = obj[prop];
  192. // }
  193. },
  194. CallExpression: function (node, st) {
  195. // var func = node.callee.name;
  196. // var found = 0;
  197.  
  198. var args = [];
  199. if (node.args) {
  200. for (var i = 0; i < node.args.length; i++) {
  201. args.push(node.args[i].value);
  202. }
  203. }
  204.  
  205. var obj, prop;
  206. getTarget(node.callee, st, function (val, o, p) {
  207. obj = o;
  208. prop = p;
  209. })
  210. if (typeof obj[prop] == 'function') {
  211. node.value = obj[prop].apply(obj, args)
  212. } else {
  213. throw new Error('property ' + prop + ' on ' + node.callee.name + ' is not a function');
  214. }
  215. },
  216. ArrayExpression: function (node, st) {
  217. var arr = [];
  218. if (node.elements) {
  219. for (var i = 0; i < node.elements.length; i++) {
  220. arr.push(node.elements[i].value);
  221. }
  222. }
  223. node.value = arr;
  224. },
  225. LogicalExpression: function (node, st) {
  226. var left, right, operator = node.operator, result = null;
  227. getTarget(node.left, st, function (val) {
  228. left = val;
  229. })
  230. getTarget(node.right, st, function (val) {
  231. right = val;
  232. });
  233. switch (operator) {
  234. case 'and':
  235. case '&&':
  236. result = left && right;
  237. break;
  238. case 'or':
  239. case '||':
  240. result = left || right;
  241. break;
  242. }
  243. node.value = result;
  244. },
  245. BinaryExpression: function (node, st) {
  246. var left, right, operator = node.operator, result = null;
  247. getTarget(node.left, st, function (val) {
  248. left = val;
  249. })
  250. getTarget(node.right, st, function (val) {
  251. right = val;
  252. });
  253. switch (operator) {
  254. // case '=':
  255. // result = left = right;
  256. // break;
  257. case '+':
  258. result = left + right;
  259. break;
  260. case '-':
  261. result = left - right;
  262. break;
  263. case '*':
  264. result = left * right;
  265. break;
  266. case 'div':
  267. case '/':
  268. result = left / right;
  269. break;
  270. case 'mod':
  271. case '%':
  272. result = left % right;
  273. break;
  274. case 'eq':
  275. case '==':
  276. result = left == right;
  277. break;
  278. case '===':
  279. result = left === right;
  280. break;
  281. case 'ne':
  282. case '!=':
  283. result = left != right;
  284. break;
  285. case '!==':
  286. result = left !== right;
  287. break;
  288. case 'gt':
  289. case '>':
  290. result = left > right;
  291. break;
  292. case 'lt':
  293. case '<':
  294. result = left < right;
  295. break;
  296. case 'ge':
  297. case '>=':
  298. result = left >= right;
  299. break;
  300. case 'le':
  301. case '<=':
  302. result = left <= right;
  303. break;
  304. case '&':
  305. result = left & right;
  306. break;
  307. case '|':
  308. result = left | right;
  309. break;
  310. case '^':
  311. result = left ^ right;
  312. break;
  313. case '>>':
  314. result = left >> right;
  315. break;
  316. case '>>>':
  317. result = left >>> right;
  318. break;
  319. case '<<':
  320. result = left << right;
  321. break;
  322. case 'and':
  323. case '&&':
  324. result = left && right;
  325. break;
  326. case 'or':
  327. case '||':
  328. result = left || right;
  329. break;
  330. default:
  331. throw new Error('operator ' + operator + ' not supported');
  332. }
  333. node.value = result;
  334. }
  335. };
  336.  
  337. const run = (p, obj1, obj2) => {
  338. var args = Array.prototype.slice.call(arguments, 1);
  339. var input = {refs: args};
  340. walk.simple(p, handlers, null, input);
  341. return input.result;
  342. }
  343.  
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350. const parsed = acorn.parse("1 + 1");
  351. // helper function for traversal
  352. run(parsed);
Add Comment
Please, Sign In to add comment