Example #1
0
  /**
   * LambdaList constructor for {@link Expr}.
   *
   * @param params List which represents a LambdaList
   * @param env
   */
  public LambdaList(Object params, Env env) {
    // if (Logger.tracelevelp(env))
    //    Logger.trace("[lambdaList] params=~S",
    //                 Lists.list(params), env);
    if (params == null) throw new NullPointerException("params is null");
    if (env == null) throw new NullPointerException("env is null");
    this.params = params;

    /*
     * parse params
     */
    Object obj = null;
    Object var = null;
    Object initform = null;
    Symbol svar = null;
    Symbol key = null;
    ArrayList tmp = new ArrayList();
    int wholeCount = 0;
    int reqCount = 0;
    int optCount = 0;
    int restCount = 0;
    int keyCount = 0;
    int allowOtherKeysCount = 0;
    int auxCount = 0;
    int step = BEGIN;
    while (true) {
      switch (step) {
        case BEGIN:
          if (params == Symbols.NIL) {
            step = END;
          } else if (Data.isAtom(params)) {
            step = REST;
            params = Lists.list(params);
          } else {
            obj = Lists.car(params);
            if (obj == Symbols.LK_WHOLE) {
              step = WHOLE;
              params = Lists.cdr(params);
            } else if (obj == Symbols.LK_OPTIONAL) {
              step = OPTIONAL;
              params = Lists.cdr(params);
            } else if (obj == Symbols.LK_REST || obj == Symbols.LK_BODY) {
              step = REST;
              params = Lists.cdr(params);
            } else if (obj == Symbols.LK_KEY) {
              step = KEYWORD;
              params = Lists.cdr(params);
            } else if (obj == Symbols.LK_AUX) {
              step = AUX;
              params = Lists.cdr(params);
            } else {
              step = REQUIRED;
            }
          }
          break;
        case WHOLE:
          /*
           * params pattern:
           * [&whole var]
           */
          if (Lists.isEnd(params)) {
            throw new ProgramException("whole parameter not exists", Symbols.NIL);
          }
          obj = Lists.car(params);
          var = Data.isPair(obj) ? new LambdaList(obj, env) : obj;
          tmp.add(new Whole(var));
          wholeCount++;
          params = Lists.cdr(params);
          if (params == Symbols.NIL) {
            step = END;
          } else if (Data.isAtom(params)) {
            step = REST;
            params = Lists.list(params);
          } else {
            obj = Lists.car(params);
            if (obj == Symbols.LK_OPTIONAL) {
              step = OPTIONAL;
              params = Lists.cdr(params);
            } else if (obj == Symbols.LK_REST || obj == Symbols.LK_BODY) {
              step = REST;
              params = Lists.cdr(params);
            } else if (obj == Symbols.LK_KEY) {
              step = KEYWORD;
              params = Lists.cdr(params);
            } else if (obj == Symbols.LK_AUX) {
              step = AUX;
              params = Lists.cdr(params);
            } else {
              step = REQUIRED;
            }
          }
          break;
        case REQUIRED:
          /*
           * params pattern:
           * {var}*
           */
          if (params == Symbols.NIL) {
            step = END;
          } else if (Data.isAtom(params)) {
            step = REST;
            params = Lists.list(params);
          } else {
            /* !Lists.isEnd(params) */
            obj = Lists.car(params);
            if (obj == Symbols.LK_OPTIONAL) {
              step = OPTIONAL;
              params = Lists.cdr(params);
            } else if (obj == Symbols.LK_REST || obj == Symbols.LK_BODY) {
              step = REST;
              params = Lists.cdr(params);
            } else if (obj == Symbols.LK_KEY) {
              step = KEYWORD;
              params = Lists.cdr(params);
            } else if (obj == Symbols.LK_AUX) {
              step = AUX;
              params = Lists.cdr(params);
            } else {
              var = Data.isPair(obj) ? new LambdaList(obj, env) : obj;
              tmp.add(new Required(var));
              reqCount++;

              step = REQUIRED;
              params = Lists.cdr(params);
            }
          }
          break;
        case OPTIONAL:
          /*
           * params pattern:
           * [&optional {var | (var [initform [svar]])}*]
           */
          if (params == Symbols.NIL) {
            step = END;
          } else if (Data.isAtom(params)) {
            step = REST;
            params = Lists.list(params);
          } else {
            /* !Lists.isEnd(params) */
            obj = Lists.car(params);
            if (obj == Symbols.LK_REST || obj == Symbols.LK_BODY) {
              step = REST;
              params = Lists.cdr(params);
            } else if (obj == Symbols.LK_KEY) {
              step = KEYWORD;
              params = Lists.cdr(params);
            } else if (obj == Symbols.LK_AUX) {
              step = AUX;
              params = Lists.cdr(params);
            } else {
              if (Data.isSymbol(obj)) {
                /*
                 * obj pattern:
                 * var <symbol>
                 */
                var = Data.symbol(obj);
                initform = Symbols.NIL;
                svar = NOT_SPECIFIED;
              } else {
                /*
                 * obj pattern:
                 * (var [initform [svar]])
                 */
                var =
                    Data.isPair(Lists.car(obj))
                        ? new LambdaList(Lists.car(obj), env)
                        : Lists.car(obj);
                initform = Lists.cadr(obj);
                svar = Lists.isEnd(Lists.cddr(obj)) ? NOT_SPECIFIED : Data.symbol(Lists.caddr(obj));
              }
              tmp.add(new Optional(var, initform, svar));
              optCount++;
              step = OPTIONAL;
              params = Lists.cdr(params);
            }
          }
          break;
        case REST:
          /*
           * params pattern:
           * [&rest var]
           */
          if (Lists.isEnd(params)) {
            throw new ProgramException("rest parameter not exists", Symbols.NIL);
          }
          obj = Lists.car(params);
          var = Data.isPair(obj) ? new LambdaList(obj, env) : obj;
          tmp.add(new Rest(var));
          restCount++;
          params = Lists.cdr(params);
          if (Lists.isEnd(params)) {
            step = END;
          } else {
            obj = Lists.car(params);
            if (obj == Symbols.LK_KEY) {
              step = KEYWORD;
              params = Lists.cdr(params);
            } else if (obj == Symbols.LK_AUX) {
              step = AUX;
              params = Lists.cdr(params);
            } else {
              throw new ProgramException(
                  "unacceptable variable: ~S" + " (expected: &key, &aux or empty)",
                  Lists.list(obj));
            }
          }
          break;
        case KEYWORD:
          /*
           * params pattern:
           * [&key {var | ({var | (keyword var)} [initform [svar]])}*]
           */
          if (Lists.isEnd(params)) {
            step = END;
          } else {
            obj = Lists.car(params);
            if (obj == Symbols.LK_ALLOW_OTHER_KEYS) {
              step = ALLOW_OTHER_KEYS;
              params = Lists.cdr(params);
            } else if (obj == Symbols.LK_AUX) {
              step = AUX;
              params = Lists.cdr(params);
            } else {
              if (Data.isSymbol(obj)) {
                /*
                 * obj pattern:
                 * var <symbol>
                 */
                var = Data.symbol(obj);
                initform = Symbols.NIL;
                svar = NOT_SPECIFIED;
                key = toKeyword(Data.symbol(var), env);
              } else {
                /*
                 * obj pattern:
                 * ({var | (keyword var)} [initform [svar]])
                 */
                var =
                    Data.isSymbol(Lists.car(obj))
                        ? Lists.car(obj)
                        : Data.isSymbol(Lists.cadar(obj))
                            ? Lists.cadar(obj)
                            : new LambdaList(Lists.cadar(obj), env);
                initform = Lists.cadr(obj);
                svar = Lists.isEnd(Lists.cddr(obj)) ? NOT_SPECIFIED : Data.symbol(Lists.caddr(obj));
                key =
                    Data.isSymbol(Lists.car(obj))
                        ? toKeyword(Data.symbol(var), env)
                        : Data.symbol(Lists.caar(obj));
              }
              tmp.add(new Keyword(var, key, initform, svar));
              keyCount++;
              step = KEYWORD;
              params = Lists.cdr(params);
            }
          }
          break;
        case ALLOW_OTHER_KEYS:
          // System.out.println("in ALLOW_OTHER_KEYS");
          allowOtherKeysCount++;
          if (Lists.isEnd(params)) {
            // System.out.println("-> END");
            step = END;
          } else {
            obj = Lists.car(params);
            // System.out.println("-> obj="+obj);
            if (obj == Symbols.LK_AUX) {
              step = AUX;
              params = Lists.cdr(params);
            } else {
              throw new ProgramException(
                  "unacceptable variable: ~S" + " (expected: &aux or empty)", Lists.list(obj));
            }
          }
          break;
        case AUX:
          /*
           * params pattern:
           * [&aux {var | (var [initform])}*]
           */
          if (Lists.isEnd(params)) {
            step = END;
          } else {
            obj = Lists.car(params);
            if (Data.isSymbol(obj)) {
              /*
               * obj pattern:
               * var <symbol>
               */
              var = Data.symbol(obj);
              initform = Symbols.NIL;
            } else {
              /*
               * obj pattern:
               * (var [initform])
               */
              var =
                  Data.isSymbol(Lists.car(obj))
                      ? Lists.car(obj)
                      : new LambdaList(Lists.car(obj), env);
              initform = Lists.cadr(obj);
            }
            tmp.add(new Aux(var, initform));
            auxCount++;
            step = AUX;
            params = Lists.cdr(params);
          }
          break;
        case END:
          Iterator it = tmp.iterator();
          this.required = new Required[reqCount];
          this.optional = new Optional[optCount];
          this.keyword = new Keyword[keyCount];
          this.aux = new Aux[auxCount];

          // fill whole param
          this.whole = (wholeCount > 0) ? (Whole) it.next() : null;
          // fill required params
          for (int i = 0; i < reqCount; i++) this.required[i] = (Required) it.next();
          // fill optional params
          for (int i = 0; i < optCount; i++) this.optional[i] = (Optional) it.next();
          // fill rest param
          this.rest = (restCount > 0) ? (Rest) it.next() : null;
          // fill keyword params
          for (int i = 0; i < keyCount; i++) this.keyword[i] = (Keyword) it.next();
          // fill allowOtherKeys flag
          this.allowOtherKeys = (allowOtherKeysCount > 0);
          // fill aux params
          for (int i = 0; i < auxCount; i++) this.aux[i] = (Aux) it.next();
          return;
        default:
          throw new NotReachedException("unacceptable step: " + step, Symbols.NIL);
      }
    }
  }