001: package gnu.mapping;
002:
003: /**
004: * The abstract parent for all Scheme functions.
005: * @author Per Bothner
006: */
007:
008: public abstract class Procedure implements Named {
009: /** If non-null, a sequence of (key, value)-pairs. */
010: private Object[] properties;
011:
012: private static final String nameKey = "name";
013: private static final String setterKey = "setter";
014:
015: public String getName() {
016: return (String) getProperty(nameKey, null);
017: }
018:
019: /** @deprecated */
020: public final String name() {
021: return getName();
022: }
023:
024: public final void setName(String name) {
025: setProperty(nameKey, name);
026: }
027:
028: public Procedure() {
029: }
030:
031: public Procedure(String n) {
032: setName(n);
033: }
034:
035: public abstract Object applyN(Object[] args) throws Throwable;
036:
037: public abstract Object apply0() throws Throwable;
038:
039: public abstract Object apply1(Object arg1) throws Throwable;
040:
041: public abstract Object apply2(Object arg1, Object arg2)
042: throws Throwable;
043:
044: public abstract Object apply3(Object arg1, Object arg2, Object arg3)
045: throws Throwable;
046:
047: public abstract Object apply4(Object arg1, Object arg2,
048: Object arg3, Object arg4) throws Throwable;
049:
050: /** Minimum number of arguments required. */
051: public final int minArgs() {
052: return numArgs() & 0xFFF;
053: }
054:
055: /** Maximum number of arguments allowed, or -1 for unlimited. */
056: public final int maxArgs() {
057: return numArgs() >> 12;
058: }
059:
060: /** Check that the number of arguments in a call is valid.
061: * @param proc the Procedure being called
062: * @param argCount the number of arguments in the call
063: * @return nothing, if the number of arguments is ok
064: * @exception WrongArguments there are too many or too
065: * few actual arguments
066: */
067: public static void checkArgCount(Procedure proc, int argCount) {
068: int num = proc.numArgs();
069: if (argCount < (num & 0xFFF)
070: || (num >= 0 && argCount > (num >> 12)))
071: throw new WrongArguments(proc, argCount);
072: }
073:
074: /** Return minArgs()|(maxArgs<<12). */
075:
076: /* We use a single virtual function to reduce the number of methods
077: * in the system, as well as the number of virtual method table entries.
078: * We shift by 12 so the number can normally be represented using a
079: * sipush instruction, without requiring a constant pool entry.
080: */
081: public int numArgs() {
082: return 0xfffff000;
083: }
084:
085: /* CPS: ??
086: public void apply1(Object arg, CallContext stack, CallFrame rlink, int rpc)
087: {
088: context.value = apply1(arg);
089: context.frame = rlink;
090: context.pc = rpc;
091: }
092: */
093:
094: public void apply(Runnable ctx) throws Throwable {
095: }
096:
097: public Procedure getSetter() {
098: return null;
099: }
100:
101: public void set0(Object result) throws Throwable {
102: }
103:
104: public void set1(Object arg1, Object value) throws Throwable {
105: }
106:
107: public void setN(Object[] args) throws Throwable {
108: }
109:
110: /** Call this Procedure using the explicit-CallContext-convention.
111: * The input arguments are (by default) in stack.args;
112: * the result is (by default) left in stack.value. */
113: /*
114: public void apply (CallContext ctx) throws Throwable
115: {
116: Object result;
117: int count = ctx.count;
118: if (ctx.where == 0 && count != 0)
119: result = applyN(ctx.values);
120: else
121: {
122: switch (count)
123: {
124: case 0:
125: result = apply0();
126: break;
127: case 1:
128: result = apply1(ctx.getNextArg());
129: break;
130: case 2:
131: result = apply2(ctx.getNextArg(), ctx.getNextArg());
132: break;
133: case 3:
134: result = apply3(ctx.getNextArg(), ctx.getNextArg(),
135: ctx.getNextArg());
136: break;
137: case 4:
138: result = apply4(ctx.getNextArg(), ctx.getNextArg(),
139: ctx.getNextArg(), ctx.getNextArg());
140: break;
141: default:
142: result = applyN(ctx.getArgs());
143: break;
144: }
145: }
146: ctx.writeValue(result);
147: }
148:
149: public Procedure getSetter()
150: {
151: if (! (this instanceof HasSetter))
152: {
153: Object setter = getProperty(setterKey, null);
154: if (setter instanceof Procedure)
155: return (Procedure) setter;
156: throw new RuntimeException("procedure '"+getName()+ "' has no setter");
157: }
158: int num_args = numArgs();
159: if (num_args == 0x0000)
160: return new Setter0(this);
161: if (num_args == 0x1001)
162: return new Setter1(this);
163: return new Setter(this);
164: }
165:
166: public void setSetter (Procedure setter)
167: {
168: if (this instanceof HasSetter)
169: throw new RuntimeException("procedure '"+getName()+
170: "' has builtin setter - cannot be modified");
171: setProperty(Procedure.setterKey, setter);
172: }
173:
174: /** If HasSetter, the Procedure is called in the LHS of an assignment. */
175: /*
176: public void set0(Object result) throws Throwable
177: {
178: getSetter().apply1(result);
179: }
180:
181: public void set1(Object arg1, Object value) throws Throwable
182: {
183: getSetter().apply2(arg1, value);
184: }
185:
186: public void setN (Object[] args) throws Throwable
187: {
188: getSetter().applyN(args);
189: }
190: */
191:
192: public String toString() {
193: StringBuffer sbuf = new StringBuffer();
194: sbuf.append("#<procedure ");
195: String n = getName();
196: if (n == null)
197: n = getClass().getName();
198: sbuf.append(n);
199: sbuf.append('>');
200: return sbuf.toString();
201: }
202:
203: public Object getProperty(Object key, Object defaultValue) {
204: if (properties != null) {
205: for (int i = properties.length; (i -= 2) >= 0;) {
206: if (properties[i] == key)
207: return properties[i + 1];
208: }
209: }
210: return defaultValue;
211: }
212:
213: public synchronized void setProperty(Object key, Object value) {
214: properties = setProperty(properties, key, value);
215: }
216:
217: /** Given a property list, update it.
218: * @param properties the input property list
219: * @param key
220: * @param value associate this with key in result
221: * @return updated property list (maybe the same as the input)
222: */
223: public static Object[] setProperty(Object[] properties, Object key,
224: Object value) {
225: int avail;
226: Object[] props = properties;
227: if (props == null) {
228: properties = props = new Object[10];
229: avail = 0;
230: } else {
231: avail = -1;
232: for (int i = props.length; (i -= 2) >= 0;) {
233: Object k = props[i];
234: if (k == key) {
235: Object old = props[i + 1];
236: props[i + 1] = value;
237: return properties;
238: } else if (k == null)
239: avail = i;
240: }
241: if (avail < 0) {
242: avail = props.length;
243: properties = new Object[2 * avail];
244: System.arraycopy(props, 0, properties, 0, avail);
245: props = properties;
246: }
247: }
248: props[avail] = key;
249: props[avail + 1] = value;
250: return properties;
251: }
252:
253: public Object removeProperty(Object key) {
254: Object[] props = properties;
255: if (props == null)
256: return null;
257: for (int i = props.length; (i -= 2) >= 0;) {
258: Object k = props[i];
259: if (k == key) {
260: Object old = props[i + 1];
261: props[i] = null;
262: props[i + 1] = null;
263: return old;
264: }
265: }
266: return null;
267: }
268: }
|