下面来实现一个极简的递归解释器,运行下面的代码:
解析代码
function test(i) { if(i==0){ return 0 } if(i==1) { return 1 } return test(i - 2) + test(i - 1)}let res = test(7)console.log(res)
运行结果
解释器代码
const ast = require('./source.json')// console.log(ast)let all = { store: [], env: []}function createEnvironment() { let store = {}; all.store.push(store); return { get(key) { return store[key]; }, set(key, object) { store[key] = object; } };}function createEnclosedEnvironment(outer) { let env = createEnvironment(); all.env.push(env) return { get(key) { let value = env.get(key); return value !== undefined /*易错*/ ? value : outer.get(key); }, set(key, object) { env.set(key, object); } };}function run(ast, env) { switch (ast.type) { case "Program": return run_statement(ast.body, env) case "ReturnStatement": // console.log(ast, env) console.log("-------------------------------------") return evaluateReturnStatement(ast, env) default: let res = evaluateExpression(ast, env); return res; }}function evaluateReturnStatement(expression, env) { return { kind: "Return", value: evaluateExpression(expression.argument, env) }}function evaluateExpression(expression, env) { switch (expression.type) { case "IfStatement": { return evaluateIfElseExpression(expression, env) } case "BinaryExpression": { return evaluateBinaryExpression(expression, env) } case "Identifier": { return evaluateIdentifier(expression, env); // 简化处理 } case "Literal": { return expression.value // 简化处理 } case "CallExpression": { let call = env.get(expression.callee.name); if (call) { let args = get_args(expression.arguments, env) return evaluateCallExpression(call, args, env); } else { throw new Error("not found function!") } } }}function evaluateIdentifier(expression, env) { if (!expression.name) return null; let identifierValue = env.get(expression.name); if (identifierValue !== undefined /*易错*/ ) return identifierValue;}function evaluateBinaryExpression(expression, env) { if (!expression.left || !expression.operator || !expression.right) { return null; } let left = evaluateExpression(expression.left, env); // 可能为{kind: "Return", value: xx} if (typeof left === "object") { left = left.value } let right = evaluateExpression(expression.right, env); if (typeof right === "object") { right = right.value } let ops = `${left} ${expression.operator} ${right}`; let res = eval(ops) console.log(ops, res) return res;}function evaluateIfElseExpression(expression, env) { if (!expression.test || !expression.consequent) return null; let test = evaluateExpression(expression.test, env); // if (test.kind === ObjectKind.Error) return test; if (test && expression.consequent.body) { return evaluateStatements(expression.consequent.body, env); } else if (expression.alternative /*else 可能函数内部调用函数*/ ) { return evaluateStatements(expression.alternative.statements, env); } return null;}function evaluateCallExpression(call, args, env) { call.env = env; return applyFunction(call, args);}function run_statement(statements, env) { for (let i of statements) { switch (i.type) { case "FunctionDeclaration": { env.set(i.id.name, i); break; } case "VariableDeclaration": { for (let dec of i.declarations) { if (dec.init.type === "CallExpression") { // 执行函数 let call = env.get(dec.init.callee.name); if (call) { let args = get_args(dec.init.arguments, env) let res = evaluateCallExpression(call, args, env); if (typeof res === "object") { // 可能为{kind: "Return", value: xx} res = res.value } env.set(dec.id.name, res); } else { throw new Error("not found function!") } } else { env[dec.id.name] = dec.init; } } break; } case "ExpressionStatement": { // console.log if (i.expression) { let args = []; for (let item of i.expression.arguments) { args.push(env.get(item.name)) } let opt = `${i.expression.callee.object.name}.${i.expression.callee.property.name}(${args.join(",")})` console.log(opt) eval(opt) } break; } default: { console.log(i) } } }}function applyFunction(fn, args) { let { body, params } = fn; let env = fn.env; if (env && params && args) env = encloseEnvironment(params, args, env); if (env && body) return evaluateStatements(body.body, env); return null;}function encloseEnvironment(params, args, outer) { let env = createEnclosedEnvironment(outer); for (let i = 0; i < params.length; i++) { env.set(params[i].name, args[i]); } return env;}function evaluateStatements(statements, env) { let object = null; for (let statement of statements) { object = run(statement, env); if (object && object.kind === "Return") return object; } return object.value;}function get_args(arguments, env) { let output = [] for (let arg of arguments) { output.push(evaluateExpression(arg, env)) } return output;}const env = createEnvironment();run(ast, env)
{ "type": "Program", "start": 0, "end": 150, "body": [ { "type": "FunctionDeclaration", "start": 0, "end": 113, "id": { "type": "Identifier", "start": 9, "end": 13, "name": "test" }, "expression": false, "generator": false, "async": false, "params": [ { "type": "Identifier", "start": 14, "end": 15, "name": "i" } ], "body": { "type": "BlockStatement", "start": 17, "end": 113, "body": [ { "type": "IfStatement", "start": 21, "end": 46, "test": { "type": "BinaryExpression", "start": 24, "end": 28, "left": { "type": "Identifier", "start": 24, "end": 25, "name": "i" }, "operator": "==", "right": { "type": "Literal", "start": 27, "end": 28, "value": 0, "raw": "0" } }, "consequent": { "type": "BlockStatement", "start": 29, "end": 46, "body": [ { "type": "ReturnStatement", "start": 34, "end": 42, "argument": { "type": "Literal", "start": 41, "end": 42, "value": 0, "raw": "0" } } ] }, "alternate": null }, { "type": "IfStatement", "start": 49, "end": 76, "test": { "type": "BinaryExpression", "start": 52, "end": 56, "left": { "type": "Identifier", "start": 52, "end": 53, "name": "i" }, "operator": "==", "right": { "type": "Literal", "start": 55, "end": 56, "value": 1, "raw": "1" } }, "consequent": { "type": "BlockStatement", "start": 58, "end": 76, "body": [ { "type": "ReturnStatement", "start": 64, "end": 72, "argument": { "type": "Literal", "start": 71, "end": 72, "value": 1, "raw": "1" } } ] }, "alternate": null }, { "type": "ReturnStatement", "start": 79, "end": 111, "argument": { "type": "BinaryExpression", "start": 86, "end": 111, "left": { "type": "CallExpression", "start": 86, "end": 97, "callee": { "type": "Identifier", "start": 86, "end": 90, "name": "test" }, "arguments": [ { "type": "BinaryExpression", "start": 91, "end": 96, "left": { "type": "Identifier", "start": 91, "end": 92, "name": "i" }, "operator": "-", "right": { "type": "Literal", "start": 95, "end": 96, "value": 2, "raw": "2" } } ], "optional": false }, "operator": "+", "right": { "type": "CallExpression", "start": 100, "end": 111, "callee": { "type": "Identifier", "start": 100, "end": 104, "name": "test" }, "arguments": [ { "type": "BinaryExpression", "start": 105, "end": 110, "left": { "type": "Identifier", "start": 105, "end": 106, "name": "i" }, "operator": "-", "right": { "type": "Literal", "start": 109, "end": 110, "value": 1, "raw": "1" } } ], "optional": false } } } ] } }, { "type": "VariableDeclaration", "start": 115, "end": 132, "declarations": [ { "type": "VariableDeclarator", "start": 119, "end": 132, "id": { "type": "Identifier", "start": 119, "end": 122, "name": "res" }, "init": { "type": "CallExpression", "start": 125, "end": 132, "callee": { "type": "Identifier", "start": 125, "end": 129, "name": "test" }, "arguments": [ { "type": "Literal", "start": 130, "end": 131, "value": 7, "raw": "7" } ], "optional": false } } ], "kind": "let" }, { "type": "ExpressionStatement", "start": 134, "end": 150, "expression": { "type": "CallExpression", "start": 134, "end": 150, "callee": { "type": "MemberExpression", "start": 134, "end": 145, "object": { "type": "Identifier", "start": 134, "end": 141, "name": "console" }, "property": { "type": "Identifier", "start": 142, "end": 145, "name": "log" }, "computed": false, "optional": false }, "arguments": [ { "type": "Identifier", "start": 146, "end": 149, "name": "res" } ], "optional": false } } ], "sourceType": "module"}