01: package jsint;
02:
03: /** A closure is a user-defined procedure. It is "closed" over the
04: * environment in which it was created. To apply the procedure, bind
05: * the parameters to the passed in variables, and evaluate the body.
06: * @author Peter Norvig, Copyright 2000, peter@norvig.com, <a href="license.txt">license</a>
07: * subsequently modified by Jscheme project members
08: * licensed under zlib licence (see license.txt)
09: */
10:
11: public class Closure extends Procedure implements Cloneable {
12:
13: Object body;
14: LexicalEnvironment lexenv;
15: Object parms;
16:
17: /** Make a closure from a body and the analyze time environment it
18: was defined in. To create a closure at execute time, use .copy()
19: **/
20: public Closure(Object parms, Object body, LexicalEnvironment lexenv) {
21: this .parms = parms;
22: this .body = body;
23: this .lexenv = lexenv;
24: this .computeArgs(parms, 0);
25: }
26:
27: /** Compute minArgs and maxArgs from the parameter list **/
28: private void computeArgs(Object parms, int min) {
29: if (U.isPair(parms))
30: computeArgs(((Pair) parms).rest, min + 1);
31: else if (parms == Pair.EMPTY) {
32: this .minArgs = min;
33: this .maxArgs = min;
34: } else {
35: this .minArgs = min;
36: this .maxArgs = Integer.MAX_VALUE;
37: }
38: }
39:
40: /** Apply a closure to a vector of arguments. Do this by creating a
41: * new LexicalEnvironment containing the arguments, and then
42: * evaluating the body of the closure in that new frame.
43: **/
44: public Object apply(Object[] args) {
45: return Scheme.currentEvaluator().execute(body,
46: new LexicalEnvironment(parms, args, lexenv));
47: }
48:
49: /** Make a copy, but with a runtime environment. **/
50: public Closure copy(LexicalEnvironment lexenv) {
51: Closure c = null;
52: try {
53: c = (Closure) this .clone();
54: } catch (CloneNotSupportedException e) {
55: E.error("internal error: no clone");
56: }
57: c.lexenv = lexenv;
58: return c;
59: }
60:
61: public String toString() {
62: return "(lambda " + this .name + " " + U.stringify(parms)
63: + "...)";
64: }
65:
66: public Object setName(Object name) {
67: super .setName(name);
68: identifyInternalClosures(name.toString(), 0, body);
69: return name;
70: }
71:
72: /** To aid debugging, label internal closures with <name>~<count>. **/
73: private static int identifyInternalClosures(String name, int count,
74: Object body) {
75: if (body instanceof Closure) {
76: Closure c = (Closure) body;
77: if (c.name == "??")
78: c.name = name + "~" + count++;
79: return identifyInternalClosures(name, count, c.body);
80: } else if (body instanceof Object[]) {
81: Object[] exp = (Object[]) body;
82: for (int i = 0; i < exp.length; i++)
83: count = identifyInternalClosures(name, count, exp[i]);
84: return count;
85: } else
86: return count;
87: }
88: }
|