/** * LambdaList constructor for {@link Subr}. * * @param reqCount Number of required parameters * @param optCount Number of optional parameters * @param rest if true, then a function uses rest parameter * @param keys List of keywords for keyword parameters * @param allowOtherKeys if true, then a function accepts a keyword not defined in <code>keys * </code> */ public LambdaList(int reqCount, int optCount, boolean rest, Object keys, boolean allowOtherKeys) { int keyCount = Lists.length(keys); // whole: not supported in SUBR this.whole = null; // req this.required = new Required[reqCount]; for (int i = 0; i < reqCount; i++) { this.required[i] = new Required(genVar()); } // opt this.optional = new Optional[optCount]; for (int i = 0; i < optCount; i++) { this.optional[i] = new Optional(genVar(), Symbols.NIL, genVar()); } // rest if (rest) { this.rest = new Rest(genVar()); } else { this.rest = null; } // key this.keyword = new Keyword[keyCount]; this.allowOtherKeys = false; for (int i = 0; i < keyCount; i++) { Symbol key = Data.symbol(Lists.car(keys)); // System.out.println("key = "+key); // if (key == Symbols.LK_ALLOW_OTHER_KEYS) { // //System.out.println("allowOtherKeys = true"); // this.allowOtherKeys = true; // keys = Lists.cdr(keys); // if (!Lists.isEnd(keys)) { // throw new ProgramException // ("no variable is allowed right after "+ // "&allow-other-keys: ~S.", // Lists.list(keys)); // } // } // else { // this.keyword[i] = new Keyword // (genVar(), key, Symbols.NIL, genVar()); // keys = Lists.cdr(keys); // } this.keyword[i] = new Keyword(genVar(), key, Symbols.NIL, genVar()); keys = Lists.cdr(keys); } // this.allowOtherKeys = allowOtherKeys; // aux: not supported in SUBR this.aux = new Aux[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); } } }