Source code: com/memoire/silk/SilkSchemeUtils.java
1
2
3 package com.memoire.silk;
4 import com.memoire.silk.*;
5
6
7
8 /** @author Peter Norvig, peter@norvig.com http://www.norvig.com
9 * Copyright 1998 Peter Norvig, see http://www.norvig.com/license.html **/
10
11 import java.io.*;
12
13 public abstract class SilkSchemeUtils {
14
15 /** Same as Boolean.TRUE. **/
16 public static final Boolean TRUE = Boolean.TRUE;
17 /** Same as Boolean.FALSE. **/
18 public static final Boolean FALSE = Boolean.FALSE;
19
20 public static Double ZERO = new Double(0.0);
21 public static Double ONE = new Double(1.0);
22 //////////////// Conversion Routines ////////////////
23
24 // The following convert or coerce objects to the right type.
25
26 /** Convert boolean to Boolean. **/
27 public static Boolean truth(boolean x) { return x ? TRUE : FALSE; }
28
29 /** Convert SilkScheme object to boolean. Only #f is false, others are true. **/
30 public static boolean truth(Object x) { return x != FALSE; }
31
32 /** Convert double to Double. Caches 0 and 1; makes new for others. **/
33 public static Double num(double x) {
34 return (x == 0.0) ? ZERO : (x == 1.0) ? ONE : new Double(x); }
35
36 /** Converts a SilkScheme object to a double, or calls error. **/
37 public static double num(Object x) {
38 if (x instanceof Number) return ((Number)x).doubleValue();
39 else return num(error("expected a number, got: " + x));
40 }
41
42 /** Converts a SilkScheme object to a char, or calls error. **/
43 public static char chr(Object x) {
44 if (x instanceof Character) return ((Character)x).charValue();
45 else return chr(error("expected a char, got: " + x));
46 }
47
48 /** Converts a char to a Character. **/
49 public static Character chr(char ch) {
50 return new Character(ch);
51 }
52
53 /** Coerces a SilkScheme object to a SilkScheme string, which is a char[]. **/
54 public static char[] str(Object x) {
55 if (x instanceof char[]) return (char[])x;
56 else return str(error("expected a string, got: " + x));
57 }
58
59 /** Coerces a SilkScheme object to a SilkScheme symbol, which is a string. **/
60 public static String sym(Object x) {
61 if (x instanceof String) return (String)x;
62 else return sym(error("expected a symbol, got: " + x));
63 }
64
65 /** Coerces a SilkScheme object to a SilkScheme vector, which is a Object[]. **/
66 public static Object[] vec(Object x) {
67 if (x instanceof Object[]) return (Object[])x;
68 else return vec(error("expected a vector, got: " + x));
69 }
70
71 /** Coerces a SilkScheme object to a SilkScheme input port, which is an SilkInputPort.
72 * If the argument is null, returns interpreter.input. **/
73 public static SilkInputPort inPort(Object x, SilkScheme interp) {
74 if (x == null) return interp.input;
75 else if (x instanceof SilkInputPort) return (SilkInputPort)x;
76 else return inPort(error("expected an input port, got: " + x), interp);
77 }
78
79 /** Coerces a SilkScheme object to a SilkScheme input port, which is a PrintWriter.
80 * If the argument is null, returns System.out. **/
81 public static PrintWriter outPort(Object x, SilkScheme interp) {
82 if (x == null) return interp.output;
83 else if (x instanceof PrintWriter) return (PrintWriter)x;
84 else return outPort(error("expected an output port, got: " + x), interp);
85 }
86
87 //////////////// Error Routines ////////////////
88
89 /** A continuable error. Prints an error message and then prompts for
90 * a value to eval and return. **/
91 public static Object error(String message) {
92 System.err.println("**** ERROR: " + message);
93 throw new RuntimeException(message);
94 }
95
96 public static Object warn(String message) {
97 System.err.println("**** WARNING: " + message);
98 return "<warn>";
99 }
100
101 //////////////// Basic manipulation Routines ////////////////
102
103 // The following are used throughout the code.
104
105 /** Like Common Lisp first; car of a SilkPair, or null for anything else. **/
106 public static Object first(Object x) {
107 return (x instanceof SilkPair) ? ((SilkPair)x).first : null;
108 }
109
110 /** Like Common Lisp rest; car of a SilkPair, or null for anything else. **/
111 public static Object rest(Object x) {
112 return (x instanceof SilkPair) ? ((SilkPair)x).rest : null;
113 }
114
115 /** Like Common Lisp (setf (first ... **/
116 public static Object setFirst(Object x, Object y) {
117 return (x instanceof SilkPair) ? ((SilkPair)x).first = y
118 : error("Attempt to set-car of a non-SilkPair:" + stringify(x));
119 }
120
121 /** Like Common Lisp (setf (rest ... **/
122 public static Object setRest(Object x, Object y) {
123 return (x instanceof SilkPair) ? ((SilkPair)x).rest = y
124 : error("Attempt to set-cdr of a non-SilkPair:" + stringify(x));
125 }
126
127 /** Like Common Lisp second. **/
128 public static Object second(Object x) {
129 return first(rest(x));
130 }
131
132 /** Like Common Lisp third. **/
133 public static Object third(Object x) {
134 return first(rest(rest(x)));
135 }
136
137 /** Creates a two element list. **/
138 public static SilkPair list(Object a, Object b) {
139 return new SilkPair(a, new SilkPair(b, null));
140 }
141
142 /** Creates a one element list. **/
143 public static SilkPair list(Object a) {
144 return new SilkPair(a, null);
145 }
146
147 /** listStar(args) is like Common Lisp (apply #'list* args) **/
148 public static Object listStar(Object args) {
149 if (rest(args) == null) return first(args);
150 else return cons(first(args), listStar(rest(args)));
151 }
152
153 /** cons(x, y) is the same as new SilkPair(x, y). **/
154 public static SilkPair cons(Object a, Object b) {
155 return new SilkPair(a, b);
156 }
157
158 /** Reverse the elements of a list. **/
159 public static Object reverse(Object x) {
160 Object result = null;
161 while (x instanceof SilkPair) {
162 result = cons(first(x), result);
163 x = rest(x);
164 }
165 return result;
166 }
167
168 /** Check if two objects are equal. **/
169 public static boolean equal(Object x, Object y) {
170 if (x == null || y == null) {
171 return x == y;
172 } else if (x instanceof char[]) {
173 if (!(y instanceof char[])) return false;
174 char[] xc = (char[])x, yc = (char[])y;
175 if (xc.length != yc.length) return false;
176 for (int i = xc.length - 1; i >= 0; i--) {
177 if (xc[i] != yc[i]) return false;
178 }
179 return true;
180 } else if (x instanceof Object[]) {
181 if (!(y instanceof Object[])) return false;
182 Object[] xo = (Object[])x, yo = (Object[])y;
183 if (xo.length != yo.length) return false;
184 for (int i = xo.length - 1; i >= 0; i--) {
185 if (!equal(xo[i],yo[i])) return false;
186 }
187 return true;
188 } else {
189 return x.equals(y);
190 }
191 }
192
193 /** Check if two objects are == or are equal numbers or characters. **/
194 public static boolean eqv(Object x, Object y) {
195 return x == y
196 || (x instanceof Double && x.equals(y))
197 || (x instanceof Character && x.equals(y));
198 }
199
200 /** The length of a list, or zero for a non-list. **/
201 public static int length(Object x) {
202 int len = 0;
203 while (x instanceof SilkPair) {
204 len++;
205 x = ((SilkPair)x).rest;
206 }
207 return len;
208 }
209
210 /** Convert a list of characters to a SilkScheme string, which is a char[]. **/
211 public static char[] listToString(Object chars) {
212 char[] str = new char[length(chars)];
213 for (int i = 0; chars instanceof SilkPair; i++) {
214 str[i] = chr(first(chars));
215 chars = rest(chars);
216 }
217 return str;
218 }
219
220 /** Convert a list of Objects to a SilkScheme vector, which is a Object[]. **/
221 public static Object[] listToVector(Object objs) {
222 Object[] vec = new Object[length(objs)];
223 for (int i = 0; objs instanceof SilkPair; i++) {
224 vec[i] = first(objs);
225 objs = rest(objs);
226 }
227 return vec;
228 }
229
230 /** Write the object to a port. If quoted is true, use "str" and #\c,
231 * otherwise use str and c. **/
232 public static Object write(Object x, PrintWriter port, boolean quoted) {
233 port.print(stringify(x, quoted));
234 port.flush();
235 return x;
236 }
237
238 /** Convert a vector to a List. **/
239 public static SilkPair vectorToList(Object x) {
240 if (x instanceof Object[]) {
241 Object[] vec = (Object[])x;
242 SilkPair result = null;
243 for (int i = vec.length - 1; i >= 0; i--)
244 result = cons(vec[i], result);
245 return result;
246 } else {
247 error("expected a vector, got: " + x);
248 return null;
249 }
250 }
251
252 /** Convert a SilkScheme object to its printed representation, as
253 * a java String (not a SilkScheme string). If quoted is true, use "str" and #\c,
254 * otherwise use str and c. You need to pass in a StringBuffer that is used
255 * to accumulate the results. (If the interface didn't work that way, the
256 * system would use lots of little internal StringBuffers. But note that
257 * you can still call <tt>stringify(x)</tt> and a new StringBuffer will
258 * be created for you. **/
259
260 static void stringify(Object x, boolean quoted, StringBuffer buf) {
261 if (x == null)
262 buf.append("()");
263 else if (x instanceof Double) {
264 double d = ((Double)x).doubleValue();
265 if (Math.round(d) == d) buf.append((long)d); else buf.append(d);
266 } else if (x instanceof Character) {
267 if (quoted) buf.append("#\\");
268 buf.append(x);
269 } else if (x instanceof SilkPair) {
270 ((SilkPair)x).stringifySilkPair(quoted, buf);
271 } else if (x instanceof char[]) {
272 char[] chars = (char[])x;
273 if (quoted) buf.append('"');
274 for (int i = 0; i < chars.length; i++) {
275 if (quoted && chars[i] == '"') buf.append('\\');
276 buf.append(chars[i]);
277 }
278 if (quoted) buf.append('"');
279 } else if (x instanceof Object[]) {
280 Object[] v = (Object[])x;
281 buf.append("#(");
282 for (int i=0; i<v.length; i++) {
283 stringify(v[i], quoted, buf);
284 if (i != v.length-1) buf.append(' ');
285 }
286 buf.append(')');
287 } else if (x == TRUE) {
288 buf.append("#t");
289 } else if (x == FALSE) {
290 buf.append("#f");
291 } else {
292 buf.append(x);
293 }
294 }
295
296 /** Convert x to a Java String giving its external representation.
297 * Strings and characters are quoted. **/
298 static String stringify(Object x) { return stringify(x, true); }
299
300 /** Convert x to a Java String giving its external representation.
301 * Strings and characters are quoted iff <tt>quoted</tt> is true.. **/
302 static String stringify(Object x, boolean quoted) {
303 StringBuffer buf = new StringBuffer();
304 stringify(x, quoted, buf);
305 return buf.toString();
306 }
307
308 /** For debugging purposes, prints output. **/
309 static Object p(Object x) {
310 System.out.println(stringify(x));
311 return x;
312 }
313
314 /** For debugging purposes, prints output. **/
315 static Object p(String msg, Object x) {
316 System.out.println(msg + ": " + stringify(x));
317 return x;
318 }
319 }