特殊形式
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;};
