001: package kawa.lang;
002:
003: import gnu.mapping.*;
004: import gnu.expr.*;
005: import gnu.lists.*;
006: import java.io.*;
007:
008: /**
009: * Implement autoloading of Syntax (including macros).
010: * A named class is loaded, and apply requests are forwarded to it.
011: * @author Per Bothner
012: */
013:
014: public class AutoloadSyntax extends Syntax implements Externalizable {
015: /** The name of the class that defines the macro/builtin.
016: * It must be the name of a class in the CLASSPATH (for example:
017: * "kawa.standard.list"). Either the class must extend Syntax
018: * (and have a default constructor), or the class must be a ModuleMody,
019: * (whose apply0 () is expected to define the Syntax in the
020: * global environment. */
021: String className;
022:
023: Environment env;
024:
025: /** The loaded syntax, or null if it has not yet been loaded. */
026: Syntax loaded;
027:
028: public AutoloadSyntax() {
029: }
030:
031: public AutoloadSyntax(String name, String className) {
032: super (name);
033: this .className = className;
034: }
035:
036: public AutoloadSyntax(String name, String className, Environment env) {
037: super (name);
038: this .className = className;
039: this .env = env;
040: }
041:
042: public void print(java.io.PrintWriter ps) {
043: ps.print(toString());
044: }
045:
046: public String toString() {
047: StringBuffer sbuf = new StringBuffer(100);
048: sbuf.append("#<syntax ");
049: if (getName() != null) {
050: sbuf.append(getName());
051: sbuf.append(' ');
052: }
053: if (loaded != null)
054: sbuf.append("autoloaded>");
055: else {
056: sbuf.append("autoload ");
057: sbuf.append(className);
058: sbuf.append(">");
059: }
060: return sbuf.toString();
061: }
062:
063: private void throw_error(String prefix) {
064: throw new GenericError(prefix + className
065: + " while autoloading "
066: + (getName() == null ? "" : getName().toString()));
067: }
068:
069: /** Load the class named in className. */
070: void load() {
071: String name = this .getName();
072: try {
073: Object value = Class.forName(className).newInstance();
074: if (value instanceof Syntax) {
075: loaded = (Syntax) value;
076: if (name != null && loaded.getName() == null)
077: loaded.setName(name);
078: } else
079: throw_error("failed to autoload valid syntax object ");
080: } catch (ClassNotFoundException ex) {
081: throw_error("failed to find class ");
082: } catch (InstantiationException ex) {
083: throw_error("failed to instantiate class ");
084: } catch (IllegalAccessException ex) {
085: throw_error("illegal access in class ");
086: } catch (UnboundLocationException e) {
087: throw_error("missing symbol '" + e.getMessage() + "' ");
088: } catch (WrongArguments ex) {
089: throw_error("type error");
090: }
091: }
092:
093: public void scanForm(Pair st, ScopeExp defs, Translator tr) {
094: if (loaded == null) {
095: try {
096: load();
097: } catch (RuntimeException e) {
098: tr.syntaxError(e.getMessage());
099: return;
100: }
101: }
102: loaded.scanForm(st, defs, tr);
103: }
104:
105: public Expression rewriteForm(Pair form, Translator tr) {
106: if (loaded == null) {
107: try {
108: load();
109: } catch (GenericError e) {
110: return tr.syntaxError(e.getMessage());
111: } catch (WrongType e) {
112: return tr.syntaxError(e.getMessage());
113: }
114: }
115: Syntax saveSyntax = tr.currentSyntax;
116: tr.currentSyntax = loaded;
117: try {
118: return loaded.rewriteForm(form, tr);
119: } finally {
120: tr.currentSyntax = saveSyntax;
121: }
122: }
123:
124: public void writeExternal(ObjectOutput out) throws IOException {
125: out.writeObject(getName());
126: out.writeObject(className);
127: }
128:
129: public void readExternal(ObjectInput in) throws IOException,
130: ClassNotFoundException {
131: setName((String) in.readObject());
132: className = (String) in.readObject();
133: }
134: }
|