syntax_case.java 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. package kawa.standard;
  2. import kawa.lang.*;
  3. import gnu.lists.*;
  4. import gnu.expr.*;
  5. import gnu.math.IntNum;
  6. import gnu.bytecode.*;
  7. public class syntax_case extends Syntax
  8. {
  9. public static final syntax_case syntax_case = new syntax_case();
  10. static { syntax_case.setName("syntax-case"); }
  11. PrimProcedure call_error;
  12. Expression rewriteClauses (Object clauses, syntax_case_work work,
  13. Translator tr)
  14. {
  15. Language language = tr.getLanguage();
  16. if (clauses == LList.Empty)
  17. {
  18. /*
  19. // FIXME - throw exception instead?? perhaps SyntaxException?
  20. return new QuoteExp(new Pair("quote",
  21. new Pair("((no match in syntax-case))",
  22. LList.Empty)));
  23. */
  24. Expression[] args = new Expression[2];
  25. args[0] = new QuoteExp("syntax-case");
  26. args[1] = new ReferenceExp(work.inputExpression);
  27. if (call_error == null)
  28. {
  29. ClassType clas = ClassType.make("kawa.standard.syntax_case");
  30. Type[] argtypes = new Type[2];
  31. argtypes[0] = Compilation.javaStringType;
  32. argtypes[1] = Type.objectType;
  33. Method method = clas.addMethod("error", argtypes,
  34. Type.objectType,
  35. Access.PUBLIC|Access.STATIC);
  36. call_error = new PrimProcedure(method, language);
  37. }
  38. return new ApplyExp(call_error, args);
  39. }
  40. Object savePos = tr.pushPositionOf(clauses);
  41. Object clause;
  42. try
  43. {
  44. if (! (clauses instanceof Pair)
  45. || ! ((clause = ((Pair) clauses).getCar()) instanceof Pair))
  46. return tr.syntaxError("syntax-case: bad clause list");
  47. Pair pair = (Pair) clause;
  48. PatternScope clauseScope = PatternScope.push(tr);
  49. clauseScope.matchArray = tr.matchArray;
  50. tr.push(clauseScope);
  51. SyntaxForm syntax = null;
  52. Object tail = pair.getCdr();
  53. while (tail instanceof SyntaxForm)
  54. {
  55. syntax = (SyntaxForm) tail;
  56. tail = syntax.getDatum();
  57. }
  58. // Check for nonsense before bothering to analyze the pattern.
  59. if (! (tail instanceof Pair))
  60. return tr.syntaxError("missing syntax-case output expression");
  61. int outerVarCount = clauseScope.pattern_names.size();
  62. SyntaxPattern pattern
  63. = new SyntaxPattern(pair.getCar(), work.literal_identifiers, tr);
  64. int varCount = pattern.varCount();
  65. if (varCount > work.maxVars)
  66. work.maxVars = varCount;
  67. BlockExp block = new BlockExp();
  68. Expression[] args = new Expression[4];
  69. args[0] = new QuoteExp(pattern);
  70. args[1] = new ReferenceExp(work.inputExpression);
  71. args[2] = new ReferenceExp(tr.matchArray);
  72. args[3] = new QuoteExp(IntNum.zero());
  73. Expression tryMatch
  74. = new ApplyExp(new PrimProcedure(Pattern.matchPatternMethod, language), args);
  75. Expression output;
  76. pair = (Pair) tail;
  77. if (pair.getCdr() == LList.Empty)
  78. output = tr.rewrite_car(pair, syntax);
  79. else
  80. {
  81. Expression fender = tr.rewrite_car(pair, syntax);
  82. if (! (pair.getCdr() instanceof Pair
  83. && (pair = (Pair) pair.getCdr()).getCdr() == LList.Empty))
  84. return tr.syntaxError("syntax-case: bad clause");
  85. output = new IfExp(fender, tr.rewrite_car(pair, syntax),
  86. new ExitExp(block));
  87. }
  88. clauseScope.setBody(output);
  89. tr.pop(clauseScope);
  90. PatternScope.pop(tr);
  91. block.setBody(new IfExp(tryMatch, clauseScope, new ExitExp(block)),
  92. rewriteClauses(((Pair) clauses).getCdr(), work, tr));
  93. return block;
  94. }
  95. finally
  96. {
  97. tr.popPositionOf(savePos);
  98. }
  99. }
  100. private static final Method allocVars =
  101. ClassType.make("kawa.lang.SyntaxPattern")
  102. .getDeclaredMethod("allocVars", 2);
  103. public Expression rewriteForm (Pair form, Translator tr)
  104. {
  105. syntax_case_work work = new syntax_case_work();
  106. Object obj = form.getCdr();
  107. if (obj instanceof Pair && ((Pair)obj).getCdr() instanceof Pair)
  108. {
  109. tr.letStart();
  110. form = (Pair) obj;
  111. work.inputExpression = tr.letVariable(null, null, tr.rewrite(form.getCar()));
  112. work.inputExpression.setCanRead(true);
  113. tr.letEnter();
  114. LetExp let2 = new LetExp();
  115. Declaration matchArrayOuter = tr.matchArray;
  116. Declaration matchArray = let2.addDeclaration((String) null);
  117. matchArray.setType(Compilation.objArrayType);
  118. matchArray.setCanRead(true);
  119. tr.matchArray = matchArray;
  120. obj = form.getCdr();
  121. form = (Pair) obj;
  122. work.literal_identifiers
  123. = SyntaxPattern.getLiteralsList(form.getCar(), null, tr);
  124. obj = form.getCdr();
  125. try
  126. {
  127. tr.push(let2);
  128. let2.setBody(rewriteClauses(obj, work, tr));
  129. Expression[] args = new Expression[] {
  130. new QuoteExp(IntNum.make(work.maxVars)),
  131. (matchArrayOuter == null ? QuoteExp.nullExp
  132. : new ReferenceExp(matchArrayOuter))};
  133. matchArray.setInitValue(new ApplyExp(allocVars, args));
  134. matchArray.noteValueUnknown();
  135. tr.pop(let2);
  136. return tr.letDone(let2);
  137. }
  138. finally
  139. {
  140. tr.matchArray = matchArrayOuter;
  141. }
  142. }
  143. return tr.syntaxError("insufficiant arguments to syntax-case");
  144. }
  145. /** Called (at run-time) if syntax-case has no match. */
  146. public static Object error(String kind, Object arg)
  147. {
  148. Translator tr = (Translator) Compilation.getCurrent();
  149. if (tr == null)
  150. throw new RuntimeException("no match in syntax-case");
  151. Syntax syntax = tr.getCurrentSyntax();
  152. String name = syntax == null ? "some syntax" : syntax.getName();
  153. String msg = "no matching case while expanding " + name;
  154. return tr.syntaxError(msg);
  155. }
  156. }
  157. class syntax_case_work
  158. {
  159. LetExp let;
  160. Object[] literal_identifiers;
  161. /** A temporary to hold the value of the input expression. */
  162. Declaration inputExpression;
  163. /** The maximum of the varCount() for the patterns seen so far. */
  164. int maxVars;
  165. }