特殊形式
specialForms
对象用于定义 Egg 中的特殊语法。该对象将单词和求解这种形式的函数关联起来。目前该对象为空,现在让我们添加if
。
specialForms.if = (args, scope) => {
if (args.length != 3) {
throw new SyntaxError("Wrong number of args to if");
} else if (evaluate(args[0], scope) !== false) {
return evaluate(args[1], scope);
} else {
return evaluate(args[2], scope);
}
};
Egg 的if
语句需要三个参数。Egg 会求解第一个参数,若结果不是false
,则求解第二个参数,否则求解第三个参数。相较于 JavaScript 中的if
语句,Egg 的if
形式更类似于 JavaScript 中的?:
运算符。这是一条表达式,而非语句,它会产生一个值,即第二个或第三个参数的结果。
Egg 和 JavaScript 在处理条件值时也有些差异。Egg 不会将 0 或空字符串作为假,只有当值确实为false
时,测试结果才为假。
我们之所以需要将if
表达为特殊形式,而非普通函数,是因为函数的所有参数需要在函数调用前求值完毕,而if
则只应该根据第一个参数的值,确定求解第二个还是第三个参数。while
的形式也是类似的。
specialForms.while = (args, scope) => {
if (args.length != 2) {
throw new SyntaxError("Wrong number of args to while");
}
while (evaluate(args[0], scope) !== false) {
evaluate(args[1], scope);
}
// Since undefined does not exist in Egg, we return false,
// for lack of a meaningful result.
return false;
};
另一个基本的积木是do
,会自顶向下执行其所有参数。整个do
表达式的值是最后一个参数的值。
specialForms.do = (args, scope) => {
let value = false;
for (let arg of args) {
value = evaluate(arg, scope);
}
};
我们还需要创建名为define
的形式,来创建绑定对绑定赋值。define
的第一个参数是一个单词,第二个参数是一个会产生值的表达式,并将第二个参数的计算结果赋值给第一个参数。由于define
也是个表达式,因此必须返回一个值。我们则规定define
应该将我们赋予绑定的值返回(就像 JavaScript 中的=
运算符一样)。
specialForms.define = (args, scope) => {
if (args.length != 2 || args[0].type != "word") {
throw new SyntaxError("Incorrect use of define");
}
let value = evaluate(args[1], scope);
scope[args[0].name] = value;
return value;
};