diff --git a/homework/1/rename.js b/homework/1/rename.js index 0bbd947..e66d9e6 100644 --- a/homework/1/rename.js +++ b/homework/1/rename.js @@ -1,25 +1,45 @@ -const acorn = require('acorn'); -const astring = require('astring'); -const traverse = require('../../common/traverse'); +const acorn = require("acorn"); +const astring = require("astring"); +const traverse = require("../../common/traverse"); function transform(root, originName, targetName) { // 遍历所有节点 return traverse((node, ctx, next) => { - + // TODO: 作业代码写在这里 - if (node.type === 'xxx') { + + if (node.type === "Identifier") { + let rename = false; + + switch (ctx.type) { + case "MemberExpression": + if (ctx.object === node) { + rename = true; + } + break; + case "BinaryExpression": + case "FunctionDeclaration": + case "VariableDeclarator": + rename = true; + break; + } + + if (rename && node.name === originName) { + node.name = targetName; + } } + ctx = node; // 继续往下遍历 - return next(node, ctx) + return next(node, ctx); })(root); } function rename(code, originName, targetName) { const ast = acorn.parse(code, { ecmaVersion: 5, - }) - return astring.generate(transform(ast, originName, targetName)) + }); + return astring.generate(transform(ast, originName, targetName)); } -module.exports = rename \ No newline at end of file +module.exports = rename; diff --git a/homework/2/eval.js b/homework/2/eval.js index be527f5..7cc3654 100644 --- a/homework/2/eval.js +++ b/homework/2/eval.js @@ -1,19 +1,77 @@ -const acorn = require('acorn'); - +const acorn = require("acorn"); function evaluate(node, env) { + switch (node.type) { - case 'Literal': - // TODO: 补全作业代码 + case "Literal": + return node.value; + case "Identifier": + return env[node.name]; + case "BinaryExpression": + switch (node.operator) { + case "+": + return evaluate(node.left, env) + evaluate(node.right, env); + case "-": + return evaluate(node.left, env) - evaluate(node.right, env); + case "*": + return evaluate(node.left, env) * evaluate(node.right, env); + case "/": + return evaluate(node.left, env) / evaluate(node.right, env); + case "<=": + return evaluate(node.left, env) <= evaluate(node.right, env); + } + break; + case "ConditionalExpression": + if (evaluate(node.test, env)) { + return evaluate(node.consequent, env); + } else { + return evaluate(node.alternate, env); + } + case "LogicalExpression": + if (node.operator === "||") { + return evaluate(node.left, env) || evaluate(node.right, env); + } else if (node.operator === "&&") { + return evaluate(node.left, env) && evaluate(node.right, env); + } + break; + case "ExpressionStatement": + return evaluate(node.expression, env); + case "CallExpression": + return evaluate( + node.callee, + env + )(...node.arguments.map((arg) => evaluate(arg, env))); + case "ArrowFunctionExpression": + return function (...args) { + let argEnv = {}; + for (let i in node.params) { + argEnv[node.params[i].name] = args[i]; + } + return evaluate(node.body, { ...env, ...argEnv }); + }; + case "ObjectExpression": + const obj = {}; + for (const prop of node.properties) { + obj[prop.key.name] = evaluate(prop.value, env); + } + return obj; + case "ArrayExpression": + const arr = []; + for (const element of node.elements) { + arr.push(evaluate(element, env)); + } + return arr; } - throw new Error(`Unsupported Syntax ${node.type} at Location ${node.start}:${node.end}`); + throw new Error( + `Unsupported Syntax ${node.type} at Location ${node.start}:${node.end}` + ); } function customerEval(code, env = {}) { const node = acorn.parseExpressionAt(code, 0, { - ecmaVersion: 6 - }) - return evaluate(node, env) + ecmaVersion: 6, + }); + return evaluate(node, env); } -module.exports = customerEval \ No newline at end of file +module.exports = customerEval;