001: package kawa.lang;
002:
003: import gnu.mapping.*;
004: import gnu.expr.*;
005: import java.io.*;
006:
007: /**
008: * Implement autoloading of Procedures.
009: * A named class is loaded, and apply requests are forwarded to it.
010: * @author Per Bothner
011: */
012:
013: public class AutoloadProcedure extends Procedure implements
014: Externalizable {
015: /** The name of the class that defines the procedure.
016: * It must be the name of a class in the CLASSPATH (for example:
017: * "kawa.standard.list"), and the class must extend Procedure,
018: * and have a default constructor.
019: * If the Procedure is a ModuleMody, apply0() is applied,
020: * and that is expected to define the Procedure in the global environment. */
021: String className;
022:
023: Language language;
024:
025: /** The loaded procedure, or null if it has not yet been loaded. */
026: Procedure loaded;
027:
028: public AutoloadProcedure() {
029: }
030:
031: public AutoloadProcedure(String name, String className) {
032: super (name);
033: this .className = className;
034: }
035:
036: public AutoloadProcedure(String name, String className,
037: Language language) {
038: super (name);
039: this .className = className;
040: this .language = language;
041: }
042:
043: public void print(java.io.PrintWriter ps) {
044: ps.print("#<procedure ");
045: String name = getName();
046: if (name != null) {
047: ps.print(name);
048: // ps.print (' ');
049: }
050: /*
051: if (loaded != null)
052: ps.print ("autoloaded");
053: else
054: {
055: ps.print ("autoload ");
056: ps.print (className);
057: }
058: */
059: ps.print('>');
060: }
061:
062: private void throw_error(String prefix) {
063: loaded = null;
064: String name = getName();
065: throw new RuntimeException(prefix + className
066: + " while autoloading "
067: + (name == null ? "" : name.toString()));
068: }
069:
070: /** Load the class named in className. */
071: void load() {
072: Object name = this .getSymbol();
073: try {
074: loaded = (Procedure) Class.forName(className).newInstance();
075: if (loaded == this )
076: throw_error("circularity detected");
077: if (name != null) {
078: try {
079: Object property = (language
080: .hasSeparateFunctionNamespace() ? EnvironmentKey.FUNCTION
081: : null);
082: // Should use something like isFunctionBound FIXME
083: Environment env = language.getLangEnvironment();
084: Symbol sym = (name instanceof Symbol ? (Symbol) name
085: : env.getSymbol(name.toString()));
086: env.put(sym, property, loaded);
087: } catch (UnboundLocationException ex) {
088: }
089: if (loaded.getSymbol() == null)
090: loaded.setSymbol(name);
091: }
092: } catch (ClassNotFoundException ex) {
093: throw_error("failed to find class ");
094: } catch (InstantiationException ex) {
095: throw_error("failed to instantiate class ");
096: } catch (IllegalAccessException ex) {
097: throw_error("illegal access in class ");
098: }
099: }
100:
101: public Procedure getLoaded() {
102: if (loaded == null)
103: load();
104: return loaded;
105: }
106:
107: public int numArgs() {
108: return getLoaded().numArgs();
109: }
110:
111: public Object apply0() throws Throwable {
112: return getLoaded().apply0();
113: }
114:
115: public Object apply1(Object arg1) throws Throwable {
116: return getLoaded().apply1(arg1);
117: }
118:
119: public Object apply2(Object arg1, Object arg2) throws Throwable {
120: return getLoaded().apply2(arg1, arg2);
121: }
122:
123: public Object apply3(Object arg1, Object arg2, Object arg3)
124: throws Throwable {
125: return getLoaded().apply3(arg1, arg2, arg3);
126: }
127:
128: public Object apply4(Object arg1, Object arg2, Object arg3,
129: Object arg4) throws Throwable {
130: return getLoaded().apply4(arg1, arg2, arg3, arg4);
131: }
132:
133: public Object applyN(Object[] args) throws Throwable {
134: if (loaded == null)
135: load();
136: if (loaded instanceof AutoloadProcedure)
137: throw new InternalError("circularity in autoload of "
138: + getName());
139: return loaded.applyN(args);
140: }
141:
142: public Procedure getSetter() {
143: if (loaded == null)
144: load();
145: if (loaded instanceof HasSetter)
146: return loaded.getSetter();
147: return super .getSetter();
148: }
149:
150: public void writeExternal(ObjectOutput out) throws IOException {
151: out.writeObject(getName());
152: out.writeObject(className);
153: }
154:
155: public void readExternal(ObjectInput in) throws IOException,
156: ClassNotFoundException {
157: setName((String) in.readObject());
158: className = (String) in.readObject();
159: }
160:
161: public Object getProperty(Object key, Object defaultValue) {
162: Object value = super.getProperty(key, null);
163: if (value != null)
164: return value;
165: return getLoaded().getProperty(key, defaultValue);
166: }
167: }
|