环境
evaluate
所接受的作用域是一个对象,它的名称对应绑定名称,它的值对应这些绑定所绑定的值。 我们定义一个对象来表示全局作用域。
我们需要先定义布尔绑定才能使用之前定义的if
语句。由于只有两个布尔值,因此我们不需要为其定义特殊语法。我们简单地将true
、false
两个名称与其值绑定即可。
const topEnv = Object.create(null);
topScope.true = true;
topScope.false = false;
我们现在可以求解一个简单的表达式来对布尔值求反。
let prog = parse(`if(true, false, true)`);
console.log(evaluate(prog, topScope));
// → false
为了提供基本的算术和比较运算符,我们也添加一些函数值到作用域中。为了确保代码短小,我们在循环中使用Function
来合成一批运算符,而不是分别定义所有运算符。
for (let op of ["+", "-", "*", "/", "==", "<", ">"]) {
topScope[op] = Function("a, b", `return a ${op} b;`);
}
输出也是一个实用的功能,因此我们将console.log
包装在一个函数中,并称之为print
。
topScope.print = value => {
console.log(value);
return value;
};
这样一来我们就有足够的基本工具来编写简单的程序了。下面的函数提供了一个便利的方式来编写并运行程序。它创建一个新的环境对象,并解析执行我们赋予它的单个程序。
function run(program) {
return evaluate(parse(program), Object.create(topScope));
}
我们将使用对象原型链来表示嵌套的作用域,以便程序可以在不改变顶级作用域的情况下,向其局部作用域添加绑定。
run(`
do(define(total, 0),
define(count, 1),
while(<(count, 11),
do(define(total, +(total, count)),
define(count, +(count, 1)))),
print(total))
`);
// → 55
我们之前已经多次看到过这个程序,该程序计算数字 1 到 10 的和,只不过这里使用 Egg 语言表达。很明显,相较于实现同样功能的 JavaScript 代码,这个程序并不优雅,但对于一个不足 150 行代码的程序来说已经很不错了。
当前内容版权归 wizardforcel 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 wizardforcel .