下面来实现一个极简的递归解释器,运行下面的代码:
解析代码
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"
}