特殊形式

specialForms对象用于定义 Egg 中的特殊语法。该对象将单词和求解这种形式的函数关联起来。目前该对象为空,现在让我们添加if

  1. specialForms.if = (args, scope) => {
  2. if (args.length != 3) {
  3. throw new SyntaxError("Wrong number of args to if");
  4. } else if (evaluate(args[0], scope) !== false) {
  5. return evaluate(args[1], scope);
  6. } else {
  7. return evaluate(args[2], scope);
  8. }
  9. };

Egg 的if语句需要三个参数。Egg 会求解第一个参数,若结果不是false,则求解第二个参数,否则求解第三个参数。相较于 JavaScript 中的if语句,Egg 的if形式更类似于 JavaScript 中的?:运算符。这是一条表达式,而非语句,它会产生一个值,即第二个或第三个参数的结果。

Egg 和 JavaScript 在处理条件值时也有些差异。Egg 不会将 0 或空字符串作为假,只有当值确实为false时,测试结果才为假。

我们之所以需要将if表达为特殊形式,而非普通函数,是因为函数的所有参数需要在函数调用前求值完毕,而if则只应该根据第一个参数的值,确定求解第二个还是第三个参数。while的形式也是类似的。

  1. specialForms.while = (args, scope) => {
  2. if (args.length != 2) {
  3. throw new SyntaxError("Wrong number of args to while");
  4. }
  5. while (evaluate(args[0], scope) !== false) {
  6. evaluate(args[1], scope);
  7. }
  8. // Since undefined does not exist in Egg, we return false,
  9. // for lack of a meaningful result.
  10. return false;
  11. };

另一个基本的积木是do,会自顶向下执行其所有参数。整个do表达式的值是最后一个参数的值。

  1. specialForms.do = (args, scope) => {
  2. let value = false;
  3. for (let arg of args) {
  4. value = evaluate(arg, scope);
  5. }
  6. };

我们还需要创建名为define的形式,来创建绑定对绑定赋值。define的第一个参数是一个单词,第二个参数是一个会产生值的表达式,并将第二个参数的计算结果赋值给第一个参数。由于define也是个表达式,因此必须返回一个值。我们则规定define应该将我们赋予绑定的值返回(就像 JavaScript 中的=运算符一样)。

  1. specialForms.define = (args, scope) => {
  2. if (args.length != 2 || args[0].type != "word") {
  3. throw new SyntaxError("Incorrect use of define");
  4. }
  5. let value = evaluate(args[1], scope);
  6. scope[args[0].name] = value;
  7. return value;
  8. };