001: package kawa.lang;
002:
003: import gnu.mapping.*;
004: import gnu.expr.*;
005: import gnu.lists.*;
006: import java.io.*;
007: import gnu.text.*;
008:
009: public class SyntaxRules extends Procedure1 implements Printable,
010: Externalizable {
011: /** The list of literal identifiers.
012: * The 0'th element is name of the macro being defined;
013: * the rest are as specied in the syntax-rules form. */
014: Object[] literal_identifiers;
015:
016: SyntaxRule[] rules;
017:
018: /* The largest (num_variables+template_identifier.length) for any rule. */
019: int maxVars = 0;
020:
021: public SyntaxRules() {
022: }
023:
024: /** The compiler generates calls to this constructor. */
025: public SyntaxRules(Object[] literal_identifiers,
026: SyntaxRule[] rules, int maxVars) {
027: this .literal_identifiers = literal_identifiers;
028: this .rules = rules;
029: this .maxVars = maxVars;
030: }
031:
032: public SyntaxRules(Object[] literal_identifiers, Object srules,
033: Translator tr) {
034: this .literal_identifiers = literal_identifiers;
035: int rules_count = Translator.listLength(srules);
036: if (rules_count < 0) {
037: rules_count = 0;
038: tr.syntaxError("missing or invalid syntax-rules");
039: }
040: this .rules = new SyntaxRule[rules_count];
041: Pair rules_pair;
042: // SyntaxForm, if any, wrapping rest of rules list.
043: SyntaxForm rules_syntax = null;
044: for (int i = 0; i < rules_count; i++, srules = rules_pair.cdr) {
045: while (srules instanceof SyntaxForm) {
046: rules_syntax = (SyntaxForm) srules;
047: srules = rules_syntax.form;
048: }
049: rules_pair = (Pair) srules;
050:
051: // SyntaxForm, if any, wrapping the current rule.
052: SyntaxForm rule_syntax = rules_syntax;
053: Object syntax_rule = rules_pair.car;
054: while (syntax_rule instanceof SyntaxForm) {
055: rule_syntax = (SyntaxForm) syntax_rule;
056: syntax_rule = rule_syntax.form;
057: }
058: if (!(syntax_rule instanceof Pair)) {
059: tr.syntaxError("missing pattern in " + i
060: + "'th syntax rule");
061: return;
062: }
063: // SyntaxForm, if any, wrapping the current rule's pattern.
064: SyntaxForm pattern_syntax = rule_syntax;
065: Pair syntax_rule_pair = (Pair) syntax_rule;
066: Object pattern = syntax_rule_pair.car;
067:
068: String save_filename = tr.getFileName();
069: int save_line = tr.getLineNumber();
070: int save_column = tr.getColumnNumber();
071:
072: try {
073: // SyntaxForm, if any, wrapping the current rule's template.
074: SyntaxForm template_syntax = rule_syntax;
075: tr.setLine(syntax_rule_pair);
076: syntax_rule = syntax_rule_pair.cdr;
077: while (syntax_rule instanceof SyntaxForm) {
078: template_syntax = (SyntaxForm) syntax_rule;
079: syntax_rule = template_syntax.form;
080: }
081: if (!(syntax_rule instanceof Pair)) {
082: tr.syntaxError("missing template in " + i
083: + "'th syntax rule");
084: return;
085: }
086: syntax_rule_pair = (Pair) syntax_rule;
087: if (syntax_rule_pair.cdr != LList.Empty) {
088: tr.syntaxError("junk after " + i
089: + "'th syntax rule");
090: return;
091: }
092: Object template = syntax_rule_pair.car;
093:
094: PatternScope patternScope = PatternScope.push(tr);
095: tr.push(patternScope);
096:
097: while (pattern instanceof SyntaxForm) {
098: pattern_syntax = (SyntaxForm) pattern;
099: pattern = pattern_syntax.form;
100: }
101:
102: StringBuffer programbuf = new StringBuffer();
103:
104: // In R5RS syntax-rules, the initial name is neither a
105: // pattern variable or a literal identifier, so ingore it.
106: if (pattern instanceof Pair) {
107: // ?? FIXME
108: literal_identifiers[0] = ((Pair) pattern).car;
109:
110: Pair p = (Pair) pattern;
111: programbuf
112: .append((char) ((1 << 3) | SyntaxPattern.MATCH_PAIR));
113: programbuf
114: .append((char) SyntaxPattern.MATCH_IGNORE);
115: pattern = p.cdr;
116: } else {
117: // Identifier macro? FIXME
118: tr.syntaxError("pattern does not start with name");
119: return;
120: }
121: SyntaxPattern spattern = new SyntaxPattern(programbuf,
122: pattern, pattern_syntax, literal_identifiers,
123: tr);
124:
125: this .rules[i] = new SyntaxRule(spattern, template,
126: template_syntax, tr);
127:
128: PatternScope.pop(tr);
129: tr.pop();
130: } finally {
131: tr.setLine(save_filename, save_line, save_column);
132: }
133: }
134:
135: // Calculate maxVars:
136: for (int i = this .rules.length; --i >= 0;) {
137: int size = this .rules[i].patternNesting.length();
138: if (size > maxVars)
139: maxVars = size;
140: }
141: }
142:
143: /* --- Recursively translate a pattern in a syntax-rule to a Pattern object.
144: * @param pattern the the pattern to translate
145: * @param literal_identifiers the literals of the syntax-rule
146: * @param nesting the depth of ... we are inside
147: * @param tr the current Translator
148: * @return the translated Pattern
149: */
150:
151: public Object apply1(Object arg) {
152: if (arg instanceof SyntaxForm) {
153: SyntaxForm sf = (SyntaxForm) arg;
154: Translator tr = (Translator) Compilation.getCurrent();
155: ScopeExp save_scope = tr.currentScope();
156: tr.setCurrentScope(sf.scope);
157: try {
158: return expand(sf, tr);
159: } finally {
160: tr.setCurrentScope(save_scope);
161: }
162: } else
163: return expand(arg, (Translator) Compilation.getCurrent());
164: }
165:
166: /* DEBUGGING:
167: private void printElement (Object el, StringBuffer sb)
168: {
169: if (el instanceof Object[])
170: {
171: Object[] arr = (Object[]) el;
172: sb.append('{');
173: for (int i = 0; i < arr.length; i++)
174: {
175: if (i != 0)
176: sb.append(", ");
177: printElement(arr[i], sb);
178: }
179: sb.append('}');
180: }
181: else
182: sb.append(el);
183: }
184: END DEBUGGING */
185:
186: public Object expand(Object obj, Translator tr) {
187: Object[] vars = new Object[maxVars];
188: Macro macro = (Macro) tr.getCurrentSyntax();
189: /* DEBUGGING:
190: System.err.println("match "+macro+" args:"+obj+" maxVars:"+maxVars);
191: System.err.flush();
192: */
193: for (int i = 0; i < rules.length; i++) {
194: SyntaxRule rule = rules[i];
195: if (rule == null)
196: return new ErrorExp("error defining " + macro);
197: // check that literals have correct binding - FIXME!!
198: Pattern pattern = rule.pattern;
199: boolean matched = pattern.match(obj, vars, 0);
200: if (matched) {
201: if (true) // DEBUGGING
202: {
203: /*
204: OutPort err = OutPort.errDefault();
205: StringBuffer sb = new StringBuffer();
206: sb.append("{Expand "+macro + " rule#" + i
207: +" - matched variables: ");
208: for (int j = 0; j < rule.pattern.varCount; j++)
209: {
210: if (j > 0) sb.append("; ");
211: sb.append(j); sb.append(": ");
212: printElement(vars[j], sb);
213: }
214: sb.append('}');
215: err.println(sb);
216: err.flush();
217: */
218: }
219:
220: if (true) {
221: /* DEBUGGING:
222: OutPort err = OutPort.errDefault();
223: err.print("Expanding "); err.println(literal_identifiers[0]);
224: rule.print_template_program(null, err);
225: err.flush();
226: */
227: }
228: Object expansion = rule.execute(vars, tr, TemplateScope
229: .make(tr));
230:
231: if (false) // DEBUGGING:
232: {
233: OutPort err = OutPort.errDefault();
234: err.print("{Expansion of ");
235: err.print(macro);
236: err.println(":");
237: err.startLogicalBlock(" ", "}", 2);
238: kawa.standard.Scheme.writeFormat.writeObject(
239: expansion, err);
240: err.endLogicalBlock("}");
241: err.println();
242: err.flush();
243: }
244: return expansion;
245: }
246: }
247: /* DEBUGGING:
248: System.err.println("no matching syntax-rule for "
249: + literal_identifiers[0]);
250: System.err.flush();
251: */
252: return tr.syntaxError("no matching syntax-rule for "
253: + literal_identifiers[0]);
254: }
255:
256: public void print(Consumer out) {
257: out.write("#<macro ");
258: ReportFormat.print(literal_identifiers[0], out);
259: out.write('>');
260: }
261:
262: /**
263: * @serialData Write literal_identifiers followed by rules,
264: * using writeObject.
265: */
266: public void writeExternal(ObjectOutput out) throws IOException {
267: out.writeObject(literal_identifiers);
268: out.writeObject(rules);
269: out.writeInt(maxVars);
270: }
271:
272: public void readExternal(ObjectInput in) throws IOException,
273: ClassNotFoundException {
274: literal_identifiers = (Object[]) in.readObject();
275: rules = (SyntaxRule[]) in.readObject();
276: maxVars = in.readInt();
277: }
278: }
|