SyntaxRules.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. package kawa.lang;
  2. import gnu.expr.*;
  3. import gnu.kawa.format.Printable;
  4. import gnu.kawa.format.ReportFormat;
  5. import gnu.kawa.functions.DisplayFormat;
  6. import gnu.kawa.io.OutPort;
  7. import gnu.lists.*;
  8. import gnu.mapping.*;
  9. import gnu.text.*;
  10. import java.io.*;
  11. public class SyntaxRules extends Procedure1
  12. implements Printable, Externalizable {
  13. /** The list of literal identifiers as specified in the syntax-rules form.
  14. */
  15. Object[] literal_identifiers;
  16. SyntaxRule[] rules;
  17. /* The largest (num_variables+template_identifier.length) for any rule. */
  18. int maxVars = 0;
  19. public SyntaxRules() {
  20. }
  21. /** The compiler generates calls to this constructor. */
  22. public SyntaxRules(Object[] literal_identifiers, SyntaxRule[] rules,
  23. int maxVars, Object name) {
  24. this.literal_identifiers = literal_identifiers;
  25. this.rules = rules;
  26. this.maxVars = maxVars;
  27. if (name != null)
  28. this.setSymbol(name);
  29. }
  30. public SyntaxRules(Object ellipsis, Object[] literal_identifiers,
  31. Object srules, Translator tr) {
  32. Macro curMacro = tr.currentMacroDefinition;
  33. if (curMacro != null) {
  34. Object curName = curMacro.getSymbol();
  35. if (curName != null)
  36. this.setSymbol(curName);
  37. }
  38. this.literal_identifiers = literal_identifiers;
  39. int rules_count = Translator.listLength(srules);
  40. if (rules_count < 0) {
  41. rules_count = 0;
  42. tr.syntaxError ("missing or invalid syntax-rules");
  43. }
  44. this.rules = new SyntaxRule [rules_count];
  45. Pair rules_pair;
  46. // SyntaxForm, if any, wrapping rest of rules list.
  47. SyntaxForm rules_syntax = null;
  48. for (int i = 0; i < rules_count; i++, srules = rules_pair.getCdr()) {
  49. while (srules instanceof SyntaxForm) {
  50. rules_syntax = (SyntaxForm) srules;
  51. srules = rules_syntax.getDatum();
  52. }
  53. rules_pair = (Pair) srules;
  54. // SyntaxForm, if any, wrapping the current rule.
  55. SyntaxForm rule_syntax = rules_syntax;
  56. Object syntax_rule = rules_pair.getCar();
  57. while (syntax_rule instanceof SyntaxForm) {
  58. rule_syntax = (SyntaxForm) syntax_rule;
  59. syntax_rule = rule_syntax.getDatum();
  60. }
  61. if (! (syntax_rule instanceof Pair)) {
  62. tr.error('e', "missing pattern in syntax rule #" + i);
  63. return;
  64. }
  65. // SyntaxForm, if any, wrapping the current rule's pattern.
  66. SyntaxForm pattern_syntax = rule_syntax;
  67. Pair syntax_rule_pair = (Pair) syntax_rule;
  68. Object pattern = syntax_rule_pair.getCar();
  69. String save_filename = tr.getFileName();
  70. int save_line = tr.getLineNumber();
  71. int save_column = tr.getColumnNumber();
  72. try {
  73. // SyntaxForm, if any, wrapping the current rule's template.
  74. SyntaxForm template_syntax = rule_syntax;
  75. tr.setLine(syntax_rule_pair);
  76. syntax_rule = syntax_rule_pair.getCdr();
  77. while (syntax_rule instanceof SyntaxForm) {
  78. template_syntax = (SyntaxForm) syntax_rule;
  79. syntax_rule = template_syntax.getDatum();
  80. }
  81. if (! (syntax_rule instanceof Pair)) {
  82. tr.error('e', "missing template in syntax rule #" + i);
  83. return;
  84. }
  85. syntax_rule_pair = (Pair) syntax_rule;
  86. if (syntax_rule_pair.getCdr() != LList.Empty) {
  87. Object save = tr.pushPositionOf(syntax_rule_pair.getCdr());
  88. tr.error('e', "junk after syntax rule #" + i);
  89. tr.popPositionOf(save);
  90. return;
  91. }
  92. Object template = syntax_rule_pair.getCar();
  93. PatternScope patternScope = PatternScope.push(tr);
  94. tr.push(patternScope);
  95. try {
  96. while (pattern instanceof SyntaxForm) {
  97. pattern_syntax = (SyntaxForm) pattern;
  98. pattern = pattern_syntax.getDatum();
  99. }
  100. StringBuilder programbuf = new StringBuilder();
  101. // In R5RS syntax-rules, the initial name is neither a
  102. // pattern variable or a literal identifier, so ignore it.
  103. if (pattern instanceof Pair) {
  104. Pair p = (Pair) pattern;
  105. programbuf.append((char) ((1 << 3)
  106. | SyntaxPattern.MATCH_PAIR));
  107. programbuf.append((char) SyntaxPattern.MATCH_IGNORE);
  108. pattern = p.getCdr();
  109. } else {
  110. // Identifier macro? FIXME
  111. tr.error('e', "pattern does not start with name");
  112. return;
  113. }
  114. SyntaxPattern spattern =
  115. new SyntaxPattern(programbuf, pattern, pattern_syntax,
  116. ellipsis, literal_identifiers, tr);
  117. this.rules[i] =
  118. new SyntaxRule(spattern, template,
  119. template_syntax, ellipsis, tr);
  120. } finally {
  121. PatternScope.pop(tr);
  122. tr.pop();
  123. }
  124. } finally {
  125. tr.setLine(save_filename, save_line, save_column);
  126. }
  127. }
  128. // Calculate maxVars:
  129. for (int i = this.rules.length; --i >= 0; ) {
  130. int size = this.rules[i].patternNesting.length();
  131. if (size > maxVars)
  132. maxVars = size;
  133. }
  134. }
  135. /* Recursively translate a pattern in a syntax-rule to a Pattern object.
  136. * @param pattern the the pattern to translate
  137. * @param literal_identifiers the literals of the syntax-rule
  138. * @param nesting the depth of ... we are inside
  139. * @param tr the current Translator
  140. * @return the translated Pattern
  141. */
  142. public Object apply1(Object arg) {
  143. if (arg instanceof SyntaxForm) {
  144. SyntaxForm sf = (SyntaxForm) arg;
  145. Translator tr = (Translator) Compilation.getCurrent();
  146. ScopeExp save_scope = tr.currentScope();
  147. tr.setCurrentScope(sf.getScope());
  148. try {
  149. return expand(sf, tr);
  150. } finally {
  151. tr.setCurrentScope(save_scope);
  152. }
  153. } else
  154. return expand(arg, (Translator) Compilation.getCurrent());
  155. }
  156. /* DEBUGGING:
  157. private void printElement(Object el, StringBuffer sb) {
  158. if (el instanceof Object[]) {
  159. Object[] arr = (Object[]) el;
  160. sb.append('{');
  161. for (int i = 0; i < arr.length; i++) {
  162. if (i != 0)
  163. sb.append(", ");
  164. printElement(arr[i], sb);
  165. }
  166. sb.append('}');
  167. } else
  168. sb.append(el);
  169. }
  170. END DEBUGGING */
  171. public Object expand(Object obj, Translator tr) {
  172. Object[] vars = new Object[maxVars];
  173. Macro macro = (Macro) tr.getCurrentSyntax();
  174. /* DEBUGGING:
  175. System.err.println("match "+macro+" args:"+obj+" maxVars:"+maxVars);
  176. System.err.flush();
  177. */
  178. for (int i = 0; i < rules.length; i++) {
  179. SyntaxRule rule = rules[i];
  180. if (rule==null)
  181. return new ErrorExp("error defining "+macro);
  182. // check that literals have correct binding - FIXME!!
  183. Pattern pattern = rule.pattern;
  184. boolean matched = pattern.match (obj, vars, 0);
  185. if (matched) {
  186. if (true) { // DEBUGGING
  187. /*
  188. OutPort err = OutPort.errDefault();
  189. StringBuffer sb = new StringBuffer();
  190. sb.append("{Expand "+macro + " rule#" + i
  191. +" - matched variables: ");
  192. for (int j = 0; j < rule.pattern.varCount; j++) {
  193. if (j > 0) sb.append("; ");
  194. sb.append(j); sb.append(": ");
  195. printElement(vars[j], sb);
  196. }
  197. sb.append('}');
  198. err.println(sb);
  199. err.flush();
  200. */
  201. }
  202. if (true) {
  203. /* DEBUGGING:
  204. OutPort err = OutPort.errDefault();
  205. err.print("Expanding "); err.println(getName());
  206. rule.print_template_program(null, err);
  207. err.flush();
  208. */
  209. }
  210. Object expansion = rule.execute(vars, tr);
  211. if (false) { // DEBUGGING:
  212. OutPort err = OutPort.errDefault();
  213. err.print("{Expansion of ");
  214. err.print(macro);
  215. err.println(":");
  216. err.startLogicalBlock(" ", "}", 2);
  217. DisplayFormat.schemeWriteFormat.writeObject(expansion, err);
  218. err.endLogicalBlock("}");
  219. err.println();
  220. err.flush();
  221. }
  222. return expansion;
  223. }
  224. }
  225. /* DEBUGGING:
  226. System.err.println("no matching syntax-rule for "
  227. + getName());
  228. System.err.flush();
  229. */
  230. return tr.syntaxError ("no matching syntax-rule for "
  231. + getName());
  232. }
  233. public void print(Consumer out) {
  234. out.write("#<macro ");
  235. ReportFormat.print(getName(), out);
  236. out.write('>');
  237. }
  238. /**
  239. * @serialData Write literal_identifiers followed by rules,
  240. * using writeObject.
  241. */
  242. public void writeExternal(ObjectOutput out) throws IOException {
  243. out.writeObject(literal_identifiers);
  244. out.writeObject(rules);
  245. out.writeInt(maxVars);
  246. out.writeObject(getSymbol());
  247. }
  248. public void readExternal(ObjectInput in)
  249. throws IOException, ClassNotFoundException {
  250. literal_identifiers = (Object[]) in.readObject();
  251. rules = (SyntaxRule[]) in.readObject();
  252. maxVars = in.readInt();
  253. Object name = in.readObject();
  254. if (name != null)
  255. setSymbol(name);
  256. }
  257. }