001: package gnu.expr;
002:
003: import gnu.mapping.*;
004: import gnu.bytecode.CodeAttr;
005: import gnu.bytecode.Type;
006: import gnu.lists.*;
007: import gnu.text.Lexer;
008:
009: /**
010: * Contains various language-dependent methods.
011: * Also contains "global" state about the executation environment,
012: * such as the global Environment. There can be multiple Interpreters
013: * associated with different threads, representing mutiple top-levels.
014: * (However, this functionality is incomplete.)
015: */
016:
017: public abstract class Interpreter {
018: public static Interpreter defaultInterpreter = null;
019:
020: public static Interpreter getInterpreter() {
021: return defaultInterpreter;
022: }
023:
024: // These will be moved from here. FIXME
025: static public final Boolean trueObject = Boolean.TRUE;
026: static public final Boolean falseObject = Boolean.FALSE;
027:
028: static public final Undefined undefinedObject = new Undefined()
029: .getInstance();
030: static public final Object voidObject = Values.empty;
031:
032: static public final String quote_sym = "quote";
033: static public final String unquote_sym = "unquote";
034: static public final String unquotesplicing_sym = "unquote-splicing";
035: static public final String quasiquote_sym = "quasiquote";
036:
037: /**
038: * List of known languages and their Interpreter classes.
039: * Each element is one or more language names, or filename extensions,
040: * followed by the name of the Interpreter sub-class.
041: * The table is searched from the beginning.
042: */
043:
044: static String[][] languages = {
045: { "scheme", ".scm", ".sc", "kawa.standard.Scheme" },
046: { "emacs", "elisp", "emacs-lisp", ".el",
047: "gnu.jemacs.lang.ELisp" },
048: { "xquery", ".xql", "gnu.xquery.lang.XQuery" },
049: { "commonlisp", "common-lisp", "clisp", "lisp", ".lisp",
050: ".lsp", ".cl", "gnu.commonlisp.lang.CommonLisp" } };
051:
052: /** Get a list of all available languages */
053:
054: public static String[][] getLanguages() {
055: return languages;
056: }
057:
058: /** Look for an interpreter for a language with the given name or extension.
059: * If name is null, look for the first language available. */
060: public static Interpreter getInstance(String name) {
061: int langCount = languages.length;
062: for (int i = 0; i < langCount; i++) {
063: String[] names = languages[i];
064: int nameCount = names.length - 1;
065: for (int j = nameCount; --j >= 0;) {
066: if (name == null || names[j].equalsIgnoreCase(name)) {
067: Class langClass;
068: try {
069: langClass = Class.forName(names[nameCount]);
070: } catch (ClassNotFoundException ex) {
071: // In the future, we may support languages names that
072: // can be implemented by more than one Interpreter,
073: // so don't give up yet.
074: break;
075: }
076: return getInstance(name, langClass);
077: }
078: }
079: }
080: return null;
081: }
082:
083: protected Interpreter() {
084: gnu.lists.Convert.setInstance(KawaConvert.getInstance());
085: }
086:
087: public static Interpreter getInstance(String langName,
088: Class langClass) {
089: try {
090: java.lang.reflect.Method method = langClass
091: .getDeclaredMethod("getInstance", new Class[0]);
092: return (Interpreter) method.invoke(null, Values.noArgs);
093: } catch (Exception ex) {
094: if (langName == null)
095: langName = langClass.getName();
096: throw new WrappedException("getInstance for '" + langName
097: + "' failed", ex);
098: }
099: }
100:
101: /** Test if a value is considered "true" in this language. */
102: public boolean isTrue(Object value) {
103: return value != Boolean.FALSE;
104: }
105:
106: public Object booleanObject(boolean b) {
107: return b ? Boolean.TRUE : Boolean.FALSE;
108: }
109:
110: /** The value to return for a "void" result. */
111: public Object noValue() {
112: return Values.empty;
113: }
114:
115: /** True if functions are in a separate anme space from variable.
116: * Is true for e.g. Common Lisp, Emacs Lisp; false for Scheme. */
117: public boolean hasSeparateFunctionNamespace() {
118: return false;
119: }
120:
121: protected Environment environ;
122:
123: public Environment getEnvironment() {
124: return environ;
125: }
126:
127: public void setEnvironment(Environment environ) {
128: this .environ = environ;
129: }
130:
131: public void define(String sym, Object p) {
132: environ.define(sym, p);
133: }
134:
135: public Object lookup(String name) {
136: return environ.get(name);
137: }
138:
139: public abstract Object read(InPort in) throws java.io.IOException,
140: gnu.text.SyntaxException;
141:
142: public void print(Object obj, OutPort out) {
143: print(obj, out, false);
144: }
145:
146: public void print(Object value, OutPort out, boolean readable) {
147: if (value == Values.empty)
148: return;
149: FormatToConsumer saveFormat = out.objectFormat;
150: try {
151: out.objectFormat = getFormat(readable);
152: if (value instanceof Values) {
153: Object[] values = ((Values) value).getValues();
154: for (int i = 0; i < values.length; i++)
155: out.println(values[i]);
156: } else
157: out.println(value);
158: } finally {
159: out.objectFormat = saveFormat;
160: }
161: }
162:
163: public abstract FormatToConsumer getFormat(boolean readable);
164:
165: public Consumer getOutputConsumer(OutPort out) {
166: out.objectFormat = getFormat(false);
167: return out;
168: }
169:
170: public Environment getNewEnvironment() {
171: return new Environment(environ);
172: }
173:
174: public abstract String getName();
175:
176: public abstract Lexer getLexer(InPort inp,
177: gnu.text.SourceMessages messages);
178:
179: public abstract ModuleExp parse(Environment env, Lexer lexer)
180: throws java.io.IOException, gnu.text.SyntaxException;
181:
182: public abstract ModuleExp parseFile(InPort port,
183: gnu.text.SourceMessages messages);
184:
185: public abstract Type getTypeFor(Class clas);
186:
187: public static Type string2Type(String name) {
188: Type t;
189: if (name.endsWith("[]")) {
190: t = string2Type(name.substring(0, name.length() - 2));
191: if (t == null)
192: return null;
193: t = gnu.bytecode.ArrayType.make(t);
194: } else if (gnu.bytecode.Type.isValidJavaTypeName(name))
195: t = gnu.bytecode.Type.getType(name);
196: else
197: return null;
198: return t;
199: }
200:
201: public Type getTypeFor(String name) {
202: return string2Type(name);
203: }
204:
205: /** "Coerce" a language-specific "type specifier" object to a Type. */
206: public Type asType(Object spec) {
207: if (!(spec instanceof Type)) {
208: if (spec instanceof Class)
209: return getTypeFor((Class) spec);
210: if (spec instanceof String || spec instanceof Binding)
211: return getTypeFor(spec.toString());
212: if (spec instanceof CharSeq)
213: return gnu.bytecode.ClassType.make(spec.toString());
214: }
215: return (Type) spec;
216: }
217:
218: public Type getTypeFor(Expression exp) {
219: if (exp instanceof QuoteExp) {
220: try {
221: return asType(((QuoteExp) exp).getValue());
222: } catch (Exception ex) {
223: return null;
224: }
225: } else if (exp instanceof ReferenceExp) {
226: ReferenceExp rexp = (ReferenceExp) exp;
227: Declaration decl = rexp.getBinding();
228: if (decl != null && !decl.getFlag(Declaration.IS_UNKNOWN))
229: return getTypeFor(decl.getValue());
230: String name = rexp.getName();
231: Object val = Environment.getCurrent().get(name);
232: if (val instanceof Type)
233: return (Type) val;
234: int len = name.length();
235: if (len > 2 && name.charAt(0) == '<'
236: && name.charAt(len - 1) == '>')
237: return getTypeFor(name.substring(1, len - 1));
238: } else if (exp instanceof ClassExp) {
239: return ((ClassExp) exp).getType();
240: }
241: return null;
242: }
243:
244: public static final int VALUE_NAMESPACE = 1 << 0;
245: public static final int FUNCTION_NAMESPACE = 1 << 1;
246:
247: /** Return the namespace (e.g value or function) of a Declaration.
248: * Return a bitmask of all the namespces "covered" by the Declaration.
249: */
250: public int getNamespaceOf(Declaration decl) {
251: return VALUE_NAMESPACE;
252: }
253:
254: public void emitPushBoolean(boolean value, CodeAttr code) {
255: code.emitGetStatic(value ? Compilation.trueConstant
256: : Compilation.falseConstant);
257: }
258:
259: /** Generate code to test if an object is considered true.
260: * Assume the object has been pushed on the JVM stack.
261: * Generate code to push true or false as appropriate. */
262: public void emitCoerceToBoolean(CodeAttr code) {
263: emitPushBoolean(false, code);
264: code.emitIfNEq();
265: code.emitPushInt(1);
266: code.emitElse();
267: code.emitPushInt(0);
268: code.emitFi();
269: }
270:
271: public Object coerceFromObject(Class clas, Object obj) {
272: return getTypeFor(clas).coerceFromObject(obj);
273: }
274:
275: public Object coerceToObject(Class clas, Object obj) {
276: return getTypeFor(clas).coerceToObject(obj);
277: }
278:
279: public Object coerceToObject(int val) {
280: //return gnu.math.IntNum.make(val);
281: return null;
282: }
283:
284: public Procedure getPrompter() {
285: Binding pr = Environment.getCurrentBinding("default-prompter");
286: return pr == null ? null : pr.getProcedure();
287: }
288:
289: // The compiler finds registerEnvironment by using reflection.
290: //
291: // public static void registerEnvironment()
292: // { Environment.setCurrent(new ...().getEnvironment()); }
293: }
|