下面来实现一个极简的递归解释器,运行下面的代码:

解析代码

  1. function test(i) {
  2. if(i==0){
  3. return 0
  4. }
  5. if(i==1) {
  6. return 1
  7. }
  8. return test(i - 2) + test(i - 1)
  9. }
  10. let res = test(7)
  11. console.log(res)

运行结果

image.png

解释器代码

  1. const ast = require('./source.json')
  2. // console.log(ast)
  3. let all = {
  4. store: [],
  5. env: []
  6. }
  7. function createEnvironment() {
  8. let store = {};
  9. all.store.push(store);
  10. return {
  11. get(key) {
  12. return store[key];
  13. },
  14. set(key, object) {
  15. store[key] = object;
  16. }
  17. };
  18. }
  19. function createEnclosedEnvironment(outer) {
  20. let env = createEnvironment();
  21. all.env.push(env)
  22. return {
  23. get(key) {
  24. let value = env.get(key);
  25. return value !== undefined /*易错*/ ? value : outer.get(key);
  26. },
  27. set(key, object) {
  28. env.set(key, object);
  29. }
  30. };
  31. }
  32. function run(ast, env) {
  33. switch (ast.type) {
  34. case "Program":
  35. return run_statement(ast.body, env)
  36. case "ReturnStatement":
  37. // console.log(ast, env)
  38. console.log("-------------------------------------")
  39. return evaluateReturnStatement(ast, env)
  40. default:
  41. let res = evaluateExpression(ast, env);
  42. return res;
  43. }
  44. }
  45. function evaluateReturnStatement(expression, env) {
  46. return {
  47. kind: "Return",
  48. value: evaluateExpression(expression.argument, env)
  49. }
  50. }
  51. function evaluateExpression(expression, env) {
  52. switch (expression.type) {
  53. case "IfStatement": {
  54. return evaluateIfElseExpression(expression, env)
  55. }
  56. case "BinaryExpression": {
  57. return evaluateBinaryExpression(expression, env)
  58. }
  59. case "Identifier": {
  60. return evaluateIdentifier(expression, env); // 简化处理
  61. }
  62. case "Literal": {
  63. return expression.value // 简化处理
  64. }
  65. case "CallExpression": {
  66. let call = env.get(expression.callee.name);
  67. if (call) {
  68. let args = get_args(expression.arguments, env)
  69. return evaluateCallExpression(call, args, env);
  70. } else {
  71. throw new Error("not found function!")
  72. }
  73. }
  74. }
  75. }
  76. function evaluateIdentifier(expression, env) {
  77. if (!expression.name) return null;
  78. let identifierValue = env.get(expression.name);
  79. if (identifierValue !== undefined /*易错*/ ) return identifierValue;
  80. }
  81. function evaluateBinaryExpression(expression, env) {
  82. if (!expression.left || !expression.operator || !expression.right) {
  83. return null;
  84. }
  85. let left = evaluateExpression(expression.left, env);
  86. // 可能为{kind: "Return", value: xx}
  87. if (typeof left === "object") {
  88. left = left.value
  89. }
  90. let right = evaluateExpression(expression.right, env);
  91. if (typeof right === "object") {
  92. right = right.value
  93. }
  94. let ops = `${left} ${expression.operator} ${right}`;
  95. let res = eval(ops)
  96. console.log(ops, res)
  97. return res;
  98. }
  99. function evaluateIfElseExpression(expression, env) {
  100. if (!expression.test || !expression.consequent) return null;
  101. let test = evaluateExpression(expression.test, env);
  102. // if (test.kind === ObjectKind.Error) return test;
  103. if (test && expression.consequent.body) {
  104. return evaluateStatements(expression.consequent.body, env);
  105. } else if (expression.alternative /*else 可能函数内部调用函数*/ ) {
  106. return evaluateStatements(expression.alternative.statements, env);
  107. }
  108. return null;
  109. }
  110. function evaluateCallExpression(call, args, env) {
  111. call.env = env;
  112. return applyFunction(call, args);
  113. }
  114. function run_statement(statements, env) {
  115. for (let i of statements) {
  116. switch (i.type) {
  117. case "FunctionDeclaration": {
  118. env.set(i.id.name, i);
  119. break;
  120. }
  121. case "VariableDeclaration": {
  122. for (let dec of i.declarations) {
  123. if (dec.init.type === "CallExpression") { // 执行函数
  124. let call = env.get(dec.init.callee.name);
  125. if (call) {
  126. let args = get_args(dec.init.arguments, env)
  127. let res = evaluateCallExpression(call, args, env);
  128. if (typeof res === "object") { // 可能为{kind: "Return", value: xx}
  129. res = res.value
  130. }
  131. env.set(dec.id.name, res);
  132. } else {
  133. throw new Error("not found function!")
  134. }
  135. } else {
  136. env[dec.id.name] = dec.init;
  137. }
  138. }
  139. break;
  140. }
  141. case "ExpressionStatement": { // console.log
  142. if (i.expression) {
  143. let args = [];
  144. for (let item of i.expression.arguments) {
  145. args.push(env.get(item.name))
  146. }
  147. let opt = `${i.expression.callee.object.name}.${i.expression.callee.property.name}(${args.join(",")})`
  148. console.log(opt)
  149. eval(opt)
  150. }
  151. break;
  152. }
  153. default: {
  154. console.log(i)
  155. }
  156. }
  157. }
  158. }
  159. function applyFunction(fn, args) {
  160. let {
  161. body,
  162. params
  163. } = fn;
  164. let env = fn.env;
  165. if (env && params && args) env = encloseEnvironment(params, args, env);
  166. if (env && body) return evaluateStatements(body.body, env);
  167. return null;
  168. }
  169. function encloseEnvironment(params, args, outer) {
  170. let env = createEnclosedEnvironment(outer);
  171. for (let i = 0; i < params.length; i++) {
  172. env.set(params[i].name, args[i]);
  173. }
  174. return env;
  175. }
  176. function evaluateStatements(statements, env) {
  177. let object = null;
  178. for (let statement of statements) {
  179. object = run(statement, env);
  180. if (object && object.kind === "Return") return object;
  181. }
  182. return object.value;
  183. }
  184. function get_args(arguments, env) {
  185. let output = []
  186. for (let arg of arguments) {
  187. output.push(evaluateExpression(arg, env))
  188. }
  189. return output;
  190. }
  191. const env = createEnvironment();
  192. run(ast, env)

在线AST

  1. {
  2. "type": "Program",
  3. "start": 0,
  4. "end": 150,
  5. "body": [
  6. {
  7. "type": "FunctionDeclaration",
  8. "start": 0,
  9. "end": 113,
  10. "id": {
  11. "type": "Identifier",
  12. "start": 9,
  13. "end": 13,
  14. "name": "test"
  15. },
  16. "expression": false,
  17. "generator": false,
  18. "async": false,
  19. "params": [
  20. {
  21. "type": "Identifier",
  22. "start": 14,
  23. "end": 15,
  24. "name": "i"
  25. }
  26. ],
  27. "body": {
  28. "type": "BlockStatement",
  29. "start": 17,
  30. "end": 113,
  31. "body": [
  32. {
  33. "type": "IfStatement",
  34. "start": 21,
  35. "end": 46,
  36. "test": {
  37. "type": "BinaryExpression",
  38. "start": 24,
  39. "end": 28,
  40. "left": {
  41. "type": "Identifier",
  42. "start": 24,
  43. "end": 25,
  44. "name": "i"
  45. },
  46. "operator": "==",
  47. "right": {
  48. "type": "Literal",
  49. "start": 27,
  50. "end": 28,
  51. "value": 0,
  52. "raw": "0"
  53. }
  54. },
  55. "consequent": {
  56. "type": "BlockStatement",
  57. "start": 29,
  58. "end": 46,
  59. "body": [
  60. {
  61. "type": "ReturnStatement",
  62. "start": 34,
  63. "end": 42,
  64. "argument": {
  65. "type": "Literal",
  66. "start": 41,
  67. "end": 42,
  68. "value": 0,
  69. "raw": "0"
  70. }
  71. }
  72. ]
  73. },
  74. "alternate": null
  75. },
  76. {
  77. "type": "IfStatement",
  78. "start": 49,
  79. "end": 76,
  80. "test": {
  81. "type": "BinaryExpression",
  82. "start": 52,
  83. "end": 56,
  84. "left": {
  85. "type": "Identifier",
  86. "start": 52,
  87. "end": 53,
  88. "name": "i"
  89. },
  90. "operator": "==",
  91. "right": {
  92. "type": "Literal",
  93. "start": 55,
  94. "end": 56,
  95. "value": 1,
  96. "raw": "1"
  97. }
  98. },
  99. "consequent": {
  100. "type": "BlockStatement",
  101. "start": 58,
  102. "end": 76,
  103. "body": [
  104. {
  105. "type": "ReturnStatement",
  106. "start": 64,
  107. "end": 72,
  108. "argument": {
  109. "type": "Literal",
  110. "start": 71,
  111. "end": 72,
  112. "value": 1,
  113. "raw": "1"
  114. }
  115. }
  116. ]
  117. },
  118. "alternate": null
  119. },
  120. {
  121. "type": "ReturnStatement",
  122. "start": 79,
  123. "end": 111,
  124. "argument": {
  125. "type": "BinaryExpression",
  126. "start": 86,
  127. "end": 111,
  128. "left": {
  129. "type": "CallExpression",
  130. "start": 86,
  131. "end": 97,
  132. "callee": {
  133. "type": "Identifier",
  134. "start": 86,
  135. "end": 90,
  136. "name": "test"
  137. },
  138. "arguments": [
  139. {
  140. "type": "BinaryExpression",
  141. "start": 91,
  142. "end": 96,
  143. "left": {
  144. "type": "Identifier",
  145. "start": 91,
  146. "end": 92,
  147. "name": "i"
  148. },
  149. "operator": "-",
  150. "right": {
  151. "type": "Literal",
  152. "start": 95,
  153. "end": 96,
  154. "value": 2,
  155. "raw": "2"
  156. }
  157. }
  158. ],
  159. "optional": false
  160. },
  161. "operator": "+",
  162. "right": {
  163. "type": "CallExpression",
  164. "start": 100,
  165. "end": 111,
  166. "callee": {
  167. "type": "Identifier",
  168. "start": 100,
  169. "end": 104,
  170. "name": "test"
  171. },
  172. "arguments": [
  173. {
  174. "type": "BinaryExpression",
  175. "start": 105,
  176. "end": 110,
  177. "left": {
  178. "type": "Identifier",
  179. "start": 105,
  180. "end": 106,
  181. "name": "i"
  182. },
  183. "operator": "-",
  184. "right": {
  185. "type": "Literal",
  186. "start": 109,
  187. "end": 110,
  188. "value": 1,
  189. "raw": "1"
  190. }
  191. }
  192. ],
  193. "optional": false
  194. }
  195. }
  196. }
  197. ]
  198. }
  199. },
  200. {
  201. "type": "VariableDeclaration",
  202. "start": 115,
  203. "end": 132,
  204. "declarations": [
  205. {
  206. "type": "VariableDeclarator",
  207. "start": 119,
  208. "end": 132,
  209. "id": {
  210. "type": "Identifier",
  211. "start": 119,
  212. "end": 122,
  213. "name": "res"
  214. },
  215. "init": {
  216. "type": "CallExpression",
  217. "start": 125,
  218. "end": 132,
  219. "callee": {
  220. "type": "Identifier",
  221. "start": 125,
  222. "end": 129,
  223. "name": "test"
  224. },
  225. "arguments": [
  226. {
  227. "type": "Literal",
  228. "start": 130,
  229. "end": 131,
  230. "value": 7,
  231. "raw": "7"
  232. }
  233. ],
  234. "optional": false
  235. }
  236. }
  237. ],
  238. "kind": "let"
  239. },
  240. {
  241. "type": "ExpressionStatement",
  242. "start": 134,
  243. "end": 150,
  244. "expression": {
  245. "type": "CallExpression",
  246. "start": 134,
  247. "end": 150,
  248. "callee": {
  249. "type": "MemberExpression",
  250. "start": 134,
  251. "end": 145,
  252. "object": {
  253. "type": "Identifier",
  254. "start": 134,
  255. "end": 141,
  256. "name": "console"
  257. },
  258. "property": {
  259. "type": "Identifier",
  260. "start": 142,
  261. "end": 145,
  262. "name": "log"
  263. },
  264. "computed": false,
  265. "optional": false
  266. },
  267. "arguments": [
  268. {
  269. "type": "Identifier",
  270. "start": 146,
  271. "end": 149,
  272. "name": "res"
  273. }
  274. ],
  275. "optional": false
  276. }
  277. }
  278. ],
  279. "sourceType": "module"
  280. }