internal ArgSpecs copy(Env env) { ArgSpecs a = (ArgSpecs)MemberwiseClone(); a.env = env; return(a); }
internal Closure(Cons args,Env env,Interpreter interpreter,Loc loc) { this.interpreter = interpreter; this.loc = loc; ArgSpecs specs = analyzeArgSpec((Cons)args.first,env,loc); //create an env expanded by params in which to analyze body Env env2 = new Env(specs.parameters, null, env, interpreter); this.argSpecs = specs; this.body = interpreter.analyze(new Cons(interpreter.BLOCK,args.rest), env2,loc); this.env = env; }
internal Closure(Cons args, Env env, Interpreter interpreter, Loc loc) { this.interpreter = interpreter; this.loc = loc; ArgSpecs specs = analyzeArgSpec((Cons)args.first, env, loc); //create an env expanded by params in which to analyze body Env env2 = new Env(specs.parameters, null, env); this.argSpecs = specs; this.body = interpreter.analyze(new Cons(interpreter.BLOCK, args.rest), env2, loc); this.env = env; }
//parse out params from spec (which may contain &optional, &key, &rest, initforms etc internal ArgSpecs analyzeArgSpec(Cons arglist, Env env,Loc loc) { //count the params int nParams = 0; Cons a = arglist; while(a!=null) { Object p = a.first; if(p!=interpreter.AMPOPT && p!=interpreter.AMPKEY && p!=interpreter.AMPREST) ++nParams; a = a.rest; } ArgSpecs ret = new ArgSpecs(env); ret.parameters = new Parameter[nParams]; Parameter.Spec state = Parameter.Spec.REQ; int param = 0; a = arglist; while(a!=null) { Object p = a.first; switch(state) { case Parameter.Spec.REQ: if(p==interpreter.AMPOPT) state = Parameter.Spec.OPT; else if(p==interpreter.AMPKEY) state = Parameter.Spec.KEY; else if(p==interpreter.AMPREST) state = Parameter.Spec.REST; else { if(p is Symbol) { ret.parameters[param++] = new Parameter((Symbol)p,Parameter.Spec.REQ,null); ++ret.numReq; } else if(p is Cons) { ret.parameters[param] = new Parameter((Symbol)((Cons)p).first,Parameter.Spec.REQ,null); ret.parameters[param].typeSpec = interpreter.eval(Cons.Second((Cons)p),env); ++param; ++ret.numReq; } } break; case Parameter.Spec.OPT: if(p==interpreter.AMPOPT) throw new Exception("&optional can appear only once in arg list"); else if(p==interpreter.AMPKEY) state = Parameter.Spec.KEY; else if(p==interpreter.AMPREST) state = Parameter.Spec.REST; else { if(p is Symbol) { ret.parameters[param++] = new Parameter((Symbol)p,Parameter.Spec.OPT,null); ++ret.numOpt; } else if(p is Cons) { ret.parameters[param++] = new Parameter((Symbol)((Cons)p).first,Parameter.Spec.OPT, interpreter.analyze(Cons.Second((Cons)p),env,loc)); ++ret.numOpt; } else throw new Exception("&optional parameters must be symbols or (symbol init-form)"); } break; case Parameter.Spec.KEY: if(p==interpreter.AMPOPT) throw new Exception("&optional must appear before &key in arg list"); else if(p==interpreter.AMPKEY) throw new Exception("&key can appear only once in arg list"); else if(p==interpreter.AMPREST) state = Parameter.Spec.REST; else { if(p is Symbol) { ret.parameters[param] = new Parameter((Symbol)p,Parameter.Spec.KEY,null); ret.parameters[param].key = interpreter.intern(":" + ((Symbol)p).name); ++param; ++ret.numKey; } else if(p is Cons) { ret.parameters[param] = new Parameter((Symbol)((Cons)p).first,Parameter.Spec.KEY, interpreter.analyze(Cons.Second((Cons)p),env,loc)); ret.parameters[param].key = interpreter.intern(":" + ((Symbol)((Cons)p).first).name); ++param; ++ret.numKey; } else throw new Exception("&key parameters must be symbols or (symbol init-form)"); } break; case Parameter.Spec.REST: if(p==interpreter.AMPOPT) throw new Exception("&optional must appear before &rest in arg list"); else if(p==interpreter.AMPKEY) throw new Exception("&key must appear before &rest in arg list"); else if(p==interpreter.AMPREST) throw new Exception("&rest can appear only once in arg list"); else { if(!(p is Symbol)) throw new Exception("&rest parameter must be a symbol"); else { if(ret.numRest > 0) //already got a rest param throw new Exception("Only one &rest arg can be specified"); ret.parameters[param++] = new Parameter((Symbol)p,Parameter.Spec.REST,null); ++ret.numRest; } } break; } a = a.rest; } return ret; }
//parse out params from spec (which may contain &optional, &key, &rest, initforms etc internal ArgSpecs analyzeArgSpec(Cons arglist, Env env, Loc loc) { //count the params int nParams = 0; Cons a = arglist; while (a != null) { Object p = a.first; if (p != interpreter.AMPOPT && p != interpreter.AMPKEY && p != interpreter.AMPREST) { ++nParams; } a = a.rest; } ArgSpecs ret = new ArgSpecs(env); ret.parameters = new Parameter[nParams]; Parameter.Spec state = Parameter.Spec.REQ; int param = 0; a = arglist; while (a != null) { Object p = a.first; switch (state) { case Parameter.Spec.REQ: if (p == interpreter.AMPOPT) { state = Parameter.Spec.OPT; } else if (p == interpreter.AMPKEY) { state = Parameter.Spec.KEY; } else if (p == interpreter.AMPREST) { state = Parameter.Spec.REST; } else { if (p is Symbol) { ret.parameters[param++] = new Parameter((Symbol)p, Parameter.Spec.REQ, null); ++ret.numReq; } else if (p is Cons) { ret.parameters[param] = new Parameter((Symbol)((Cons)p).first, Parameter.Spec.REQ, null); ret.parameters[param].typeSpec = interpreter.eval(Cons.Second((Cons)p), env); ++param; ++ret.numReq; } } break; case Parameter.Spec.OPT: if (p == interpreter.AMPOPT) { throw new Exception("&optional can appear only once in arg list"); } else if (p == interpreter.AMPKEY) { state = Parameter.Spec.KEY; } else if (p == interpreter.AMPREST) { state = Parameter.Spec.REST; } else { if (p is Symbol) { ret.parameters[param++] = new Parameter((Symbol)p, Parameter.Spec.OPT, null); ++ret.numOpt; } else if (p is Cons) { ret.parameters[param++] = new Parameter((Symbol)((Cons)p).first, Parameter.Spec.OPT, interpreter.analyze(Cons.Second((Cons)p), env, loc)); ++ret.numOpt; } else { throw new Exception("&optional parameters must be symbols or (symbol init-form)"); } } break; case Parameter.Spec.KEY: if (p == interpreter.AMPOPT) { throw new Exception("&optional must appear before &key in arg list"); } else if (p == interpreter.AMPKEY) { throw new Exception("&key can appear only once in arg list"); } else if (p == interpreter.AMPREST) { state = Parameter.Spec.REST; } else { if (p is Symbol) { ret.parameters[param] = new Parameter((Symbol)p, Parameter.Spec.KEY, null); ret.parameters[param].key = interpreter.intern(":" + ((Symbol)p).name); ++param; ++ret.numKey; } else if (p is Cons) { ret.parameters[param] = new Parameter((Symbol)((Cons)p).first, Parameter.Spec.KEY, interpreter.analyze(Cons.Second((Cons)p), env, loc)); ret.parameters[param].key = interpreter.intern(":" + ((Symbol)((Cons)p).first).name); ++param; ++ret.numKey; } else { throw new Exception("&key parameters must be symbols or (symbol init-form)"); } } break; case Parameter.Spec.REST: if (p == interpreter.AMPOPT) { throw new Exception("&optional must appear before &rest in arg list"); } else if (p == interpreter.AMPKEY) { throw new Exception("&key must appear before &rest in arg list"); } else if (p == interpreter.AMPREST) { throw new Exception("&rest can appear only once in arg list"); } else { if (!(p is Symbol)) { throw new Exception("&rest parameter must be a symbol"); } else { if (ret.numRest > 0) //already got a rest param { throw new Exception("Only one &rest arg can be specified"); } ret.parameters[param++] = new Parameter((Symbol)p, Parameter.Spec.REST, null); ++ret.numRest; } } break; } a = a.rest; } return(ret); }