001: package kawa.lang;
002:
003: import gnu.expr.*;
004: import gnu.mapping.*;
005: import gnu.lists.*;
006: import java.io.*;
007: import gnu.text.Printable;
008:
009: public class Macro extends Syntax implements Printable, Externalizable {
010: public Object expander;
011:
012: Object instance;
013:
014: private boolean hygienic = true;
015:
016: private ScopeExp capturedScope;
017:
018: public ScopeExp getCapturedScope() {
019: if (capturedScope == null) {
020: if (instance instanceof ModuleExp) // possibly if immediate.
021: capturedScope = (ModuleExp) instance;
022: else if (instance != null)
023: capturedScope = ModuleInfo.findFromInstance(instance)
024: .getModuleExp();
025: }
026: return capturedScope;
027: }
028:
029: public void setCapturedScope(ScopeExp scope) {
030: capturedScope = scope;
031: }
032:
033: public static Macro make(Declaration decl) {
034: Macro mac = new Macro(decl.getSymbol());
035: decl.setSyntax();
036: mac.capturedScope = decl.context;
037: return mac;
038: }
039:
040: public static Macro makeNonHygienic(Object name, Procedure expander) {
041: Macro mac = new Macro(name, expander);
042: mac.hygienic = false;
043: return mac;
044: }
045:
046: public static Macro makeNonHygienic(Object name,
047: Procedure expander, Object instance) {
048: Macro mac = new Macro(name, expander);
049: mac.hygienic = false;
050: mac.instance = instance;
051: return mac;
052: }
053:
054: public static Macro make(Object name, Procedure expander) {
055: Macro mac = new Macro(name, expander);
056: return mac;
057: }
058:
059: public static Macro make(Object name, Procedure expander,
060: Object instance) {
061: Macro mac = new Macro(name, expander);
062: mac.instance = instance;
063: return mac;
064: }
065:
066: public final boolean isHygienic() {
067: return hygienic;
068: }
069:
070: public final void setHygienic(boolean hygienic) {
071: this .hygienic = hygienic;
072: }
073:
074: public Macro() {
075: }
076:
077: /** Copy constructor. */
078: public Macro(Macro old) {
079: name = old.name;
080: expander = old.expander;
081: hygienic = old.hygienic;
082: }
083:
084: public Macro(Object name, Procedure expander) {
085: super (name);
086: this .expander = new QuoteExp(expander);
087: }
088:
089: public Macro(Object name) {
090: super (name);
091: }
092:
093: /* FIXME redundant */
094: public gnu.expr.Expression rewriteForm(Pair form, Translator tr) {
095: return tr.rewrite(expand(form, tr));
096: }
097:
098: public gnu.expr.Expression rewriteForm(Object form, Translator tr) {
099: return tr.rewrite(expand(form, tr));
100: }
101:
102: public String toString() {
103: return "#<macro " + getName() + '>';
104: }
105:
106: public void print(Consumer out) {
107: out.write("#<macro ");
108: out.write(getName());
109: out.write('>');
110: }
111:
112: public Object expand(Object form, Translator tr) {
113: try {
114: Procedure pr;
115: Object exp = expander;
116: if (exp instanceof Procedure
117: && !(exp instanceof Expression))
118: pr = (Procedure) exp;
119: else {
120: if (!(exp instanceof Expression)) {
121: Macro savedMacro = tr.currentMacroDefinition;
122: tr.currentMacroDefinition = this ;
123: try {
124: exp = tr.rewrite(exp);
125: expander = exp;
126: } finally {
127: tr.currentMacroDefinition = savedMacro;
128: }
129: }
130: /* DEBUGGING:
131: if (exp instanceof LambdaExp)
132: {
133: System.err.println("expand "+this+" expander:"+exp);
134: System.err.flush();
135: OutPort dout = OutPort.errDefault();
136: dout.flush();
137: ((Expression) exp).print(dout);
138: dout.println(']');
139: dout.flush();
140: }
141: */
142: pr = (Procedure) ((Expression) exp).eval(tr
143: .getGlobalEnvironment());
144: }
145: Object result;
146: if (!hygienic) {
147: form = Quote.quote(form, tr);
148: int nargs = Translator.listLength(form);
149: if (nargs <= 0)
150: return tr
151: .syntaxError("invalid macro argument list to "
152: + this );
153: Object[] args = new Object[nargs - 1];
154: for (int i = 0; i < nargs; i++) {
155: Pair pair = (Pair) form;
156: if (i > 0)
157: args[i - 1] = pair.car;
158: form = pair.cdr;
159: }
160: result = pr.applyN(args);
161: } else
162: result = pr.apply1(form);
163: if (form instanceof PairWithPosition
164: && result instanceof Pair
165: && !(result instanceof PairWithPosition)) {
166: Pair p = (Pair) result;
167: result = new PairWithPosition((PairWithPosition) form,
168: p.car, p.cdr);
169: }
170: return result;
171: } catch (Throwable ex) {
172: ex.printStackTrace();
173: return tr.syntaxError("evaluating syntax transformer '"
174: + getName() + "' threw " + ex);
175: }
176: }
177:
178: public void scanForm(Pair st, ScopeExp defs, Translator tr) {
179: String save_filename = tr.getFileName();
180: int save_line = tr.getLineNumber();
181: int save_column = tr.getColumnNumber();
182: Syntax saveSyntax = tr.currentSyntax;
183: try {
184: tr.setLine(st);
185: tr.currentSyntax = this ;
186: Object x = expand(st, tr);
187: tr.scanForm(x, defs);
188: } finally {
189: tr.setLine(save_filename, save_line, save_column);
190: tr.currentSyntax = saveSyntax;
191: }
192: }
193:
194: /**
195: * @serialData Write the name followed by the expansion procedure,
196: * both using writeObject.
197: */
198: public void writeExternal(ObjectOutput out) throws IOException {
199: out.writeObject(getName());
200: out.writeObject(((QuoteExp) expander).getValue());
201: }
202:
203: public void readExternal(ObjectInput in) throws IOException,
204: ClassNotFoundException {
205: setName((String) in.readObject());
206: expander = new QuoteExp(in.readObject());
207: }
208: }
|