SyntaxPattern.java 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. package kawa.lang;
  2. import gnu.mapping.*;
  3. import gnu.expr.*;
  4. import gnu.kawa.io.OutPort;
  5. import gnu.lists.*;
  6. import java.util.Vector;
  7. import gnu.kawa.functions.DisplayFormat;
  8. import gnu.text.*;
  9. import java.io.*;
  10. /** This encodes a pattern from a Scheem syntax-case or syntax-rules. */
  11. public class SyntaxPattern extends Pattern implements Externalizable
  12. {
  13. /** An encoding of the pattern in a compact form.
  14. * This is a sequence of "matching instructions". These have a 3-bit
  15. * "opcode", which is one of the <code>MATCH_XXX</code> cosntants.
  16. * The leaves 13 bits available as an operand; if that isn't enough the
  17. * <code>MATCH_WIDE</code> "instruction" can be used to modify the
  18. * following instruction. */
  19. String program;
  20. /** A string (if non-null) of the form FILENAME:LINENUMBER. */
  21. String fileLine;
  22. public static final SimpleSymbol underscoreSymbol = Symbol.valueOf("_");
  23. /** This 3-bit "opcode" is used for shorter operand-less instructions. */
  24. static final int MATCH_MISC = 0;
  25. /** Matches <code>List.Empty</code>. */
  26. static final int MATCH_NIL = (1<<3)+MATCH_MISC;
  27. /** Matches a vector (FVector).
  28. * Matches a vector v if the following list pattern (at pc+1)
  29. * matches (vector->list v). */
  30. static final int MATCH_VECTOR = (2<<3)+MATCH_MISC;
  31. /** Match anything and ignore it. */
  32. static final int MATCH_IGNORE = (3<<3)+MATCH_MISC;
  33. /** The instruction <code>8*i+MATCH_WIDE</code> is a prefix.
  34. * It causes <code>i&lt;&lt;13</code> to be added to the parameter
  35. * (<code>i</code>) of the following instruction. */
  36. static final int MATCH_WIDE = 1;
  37. /** The instruction <code>8*i+MATCH_EQUALS</code> matches the literal values literals[i]. */
  38. static final int MATCH_EQUALS = 2;
  39. /** The instruction <code>8*i+MATCH_ANY</code> matches any form,
  40. * It sets <code>vars[i]</code> to the matched form. */
  41. static final int MATCH_ANY = 3;
  42. /** The instruction <code>8*i+MATCH_PAIR</code> matches a Pair.
  43. * Its <code>car</code> must match the pattern at <code>pc+1</code>, while
  44. * its <code>cdr</code> must match the mattern at <code>pc+1+i</code>. */
  45. static final int MATCH_PAIR = 4;
  46. /** The instruction <code>8*i+MATCH_LREPEAT</code> matches a repeated
  47. * pattern. The repeated sub-pattern starts at <code>pc+1</code>,
  48. * and is <code>i</code> chars long. Following that (at <code>pc+1+i</code>)
  49. * is the index of the first pattern variable in the sub-pattern,
  50. * followed by the count of pattern variables in the sub-pattern.
  51. * (Both are shifted left by 3 in case we need <code>MATCH_WIDE</code>).
  52. * This is followed either by a <code>MATCH_NIL</code> (in which case
  53. * all remaining elements must match the repeated sub-pattern),
  54. * or by a <code>MATCH_LENGTH</code> (which must match the tail). */
  55. static final int MATCH_LREPEAT = 5;
  56. /** The instruction <code>8*i+MATCH_LENGTH</code> matches a pure list
  57. * of length <code>2*i</code> or an impure list of <code>2*i+1</code> pairs.
  58. * It is followed by a pattern which must also match. */
  59. static final int MATCH_LENGTH = 6;
  60. /** The instruction <code>8*i+MATCH_CAR</code> matches the car of a Pair,
  61. * It sets <code>vars[i]</code> to the Pair itself. */
  62. static final int MATCH_ANY_CAR = 7;
  63. Object[] literals;
  64. int varCount;
  65. public int varCount() { return varCount; }
  66. /** Control logging to standard error on successful pattern match. */
  67. public static boolean printSyntaxPatternMatch;
  68. public boolean match(Object obj, Object[] vars, int start_vars) {
  69. boolean r = match(obj, vars, start_vars, 0, null);
  70. if (printSyntaxPatternMatch && r) {
  71. OutPort log = OutPort.errDefault();
  72. log.startLogicalBlock("{syntax-pattern ", false, "}");
  73. log.setIndentation(-14, false);
  74. if (fileLine != null) {
  75. log.print(fileLine);
  76. }
  77. log.writeSpaceLinear();
  78. log.print("match ");
  79. DisplayFormat.schemeWriteFormat.writeObject(obj, log);
  80. if (r) {
  81. log.print(" -> vars: ");
  82. for (int i = start_vars; i < vars.length; i++) {
  83. log.writeSpaceLinear();
  84. log.print(i);
  85. log.print(": ");
  86. DisplayFormat.schemeWriteFormat.writeObject(vars[i], log);
  87. }
  88. }
  89. else
  90. log.println(" -> failed");
  91. log.endLogicalBlock("}");
  92. log.println();
  93. }
  94. return r;
  95. }
  96. public SyntaxPattern (String program, Object[] literals,
  97. int varCount, String fileLine)
  98. {
  99. this.program = program;
  100. this.literals = literals;
  101. this.varCount = varCount;
  102. this.fileLine = fileLine;
  103. }
  104. public SyntaxPattern (Object pattern,
  105. Object[] literal_identifiers, Translator tr)
  106. {
  107. this(new StringBuilder(), pattern,
  108. null, SyntaxRule.dots3Symbol, literal_identifiers, tr);
  109. }
  110. SyntaxPattern(StringBuilder programbuf, Object pattern, SyntaxForm syntax,
  111. Object ellipsis, Object[] literal_identifiers,
  112. Translator tr)
  113. {
  114. Vector literalsbuf = new Vector();
  115. translate(pattern, programbuf, ellipsis,
  116. literal_identifiers, 0, literalsbuf, null, '\0', tr);
  117. program = programbuf.toString();
  118. literals = new Object[literalsbuf.size()];
  119. literalsbuf.copyInto(literals);
  120. varCount = tr.patternScope.pattern_names.size();
  121. String filename = tr.getFileName();
  122. if (filename != null) {
  123. int sl = filename.replace(File.separatorChar, '/').lastIndexOf('/');
  124. fileLine = sl >= 0 ? filename.substring(sl+1) : filename;
  125. int line = tr.getLineNumber();
  126. if (line > 0)
  127. fileLine = fileLine + ':' + line;
  128. }
  129. /* DEBUGGING:
  130. System.err.print("{translated pattern");
  131. Macro macro = tr.currentMacroDefinition;
  132. if (macro != null)
  133. {
  134. System.err.print(" for ");
  135. System.err.print(macro);
  136. }
  137. String file = filename;
  138. if (file != null)
  139. {
  140. System.err.print(" file=");
  141. System.err.print(file);
  142. }
  143. if (line > 0)
  144. {
  145. System.err.print(" line=");
  146. System.err.print(line);
  147. }
  148. System.err.print(" vars=");
  149. System.err.print(varCount);
  150. System.err.println(':');
  151. disassemble();
  152. */
  153. }
  154. public void disassemble ()
  155. {
  156. disassemble(OutPort.errDefault(), (Translator) Compilation.getCurrent(),
  157. 0, program.length());
  158. }
  159. public void disassemble (java.io.PrintWriter ps, Translator tr)
  160. {
  161. disassemble(ps, tr, 0, program.length());
  162. }
  163. void disassemble (java.io.PrintWriter ps, Translator tr, int start, int limit)
  164. {
  165. Vector pattern_names = null;
  166. if (tr != null && tr.patternScope != null)
  167. pattern_names = tr.patternScope.pattern_names;
  168. int value = 0;
  169. for (int i = start; i < limit; )
  170. {
  171. char ch = program.charAt(i);
  172. ps.print(" " + i + ": " + (int)ch);
  173. i++;
  174. int opcode = ch & 7;
  175. value = (value << 13) | (ch >> 3);
  176. switch (opcode)
  177. {
  178. case MATCH_WIDE:
  179. ps.println(" - WIDE "+value);
  180. continue;
  181. case MATCH_EQUALS:
  182. ps.print(" - EQUALS["+value+"]");
  183. if (literals != null && value >= 0 && value < literals.length)
  184. ps.print(literals[value]);
  185. ps.println();
  186. break;
  187. case MATCH_ANY:
  188. case MATCH_ANY_CAR:
  189. ps.print((opcode == MATCH_ANY ? " - ANY[" : " - ANY_CAR[")
  190. +value+"]");
  191. if (pattern_names != null
  192. && value >= 0 && value < pattern_names.size())
  193. ps.print(pattern_names.elementAt(value));
  194. ps.println();
  195. break;
  196. case MATCH_PAIR:
  197. ps.println(" - PAIR["+value+"]");
  198. break;
  199. case MATCH_LREPEAT:
  200. ps.println(" - LREPEAT["+value+"]");
  201. disassemble(ps, tr, i, i+value);
  202. i += value;
  203. ps.println(" " + i + ": - repeat first var:"+(program.charAt(i++)>>3));
  204. ps.println(" " + i + ": - repeast nested vars:"+(program.charAt(i++)>>3));
  205. break;
  206. case MATCH_LENGTH:
  207. ps.println(" - LENGTH "+(value>>1)+" pairs. "
  208. + (((value&1)==0?"pure list":"impure list")));
  209. break;
  210. case MATCH_MISC:
  211. ps.print("[misc ch:"+(int)ch+" n:"+(int)(MATCH_NIL)+"]");
  212. if (ch == MATCH_NIL)
  213. {
  214. ps.println(" - NIL");
  215. break;
  216. }
  217. if (ch == MATCH_VECTOR)
  218. {
  219. ps.println(" - VECTOR");
  220. break;
  221. }
  222. if (ch == MATCH_IGNORE)
  223. {
  224. ps.println(" - IGNORE");
  225. break;
  226. }
  227. default:
  228. ps.println(" - "+opcode+'/'+value);
  229. break;
  230. }
  231. value = 0;
  232. }
  233. }
  234. /**
  235. * @param context 'V' : vector elements; 'P' : car of Pair; '\0' : other.
  236. */
  237. void translate (Object pattern, StringBuilder program,
  238. Object ellipsis, Object[] literal_identifiers, int nesting,
  239. Vector literals, SyntaxForm syntax,
  240. char context,
  241. Translator tr)
  242. {
  243. PatternScope patternScope = tr.patternScope;
  244. Vector patternNames = patternScope.pattern_names;
  245. for (;;)
  246. {
  247. while (pattern instanceof SyntaxForm)
  248. {
  249. syntax = (SyntaxForm) pattern;
  250. pattern = syntax.getDatum();
  251. }
  252. if (pattern instanceof Pair)
  253. {
  254. Object savePos = tr.pushPositionOf(pattern);
  255. try
  256. {
  257. int start_pc = program.length();
  258. program.append((char) MATCH_PAIR);
  259. Pair pair = (Pair) pattern;
  260. SyntaxForm car_syntax = syntax;
  261. Object next = pair.getCdr();
  262. while (next instanceof SyntaxForm)
  263. {
  264. syntax = (SyntaxForm) next;
  265. next = syntax.getDatum();
  266. }
  267. boolean repeat = false;
  268. if (next instanceof Pair) {
  269. Pair nextPair = (Pair) next;
  270. Object nextCar = nextPair.getCar();
  271. if (literalIdentifierEq(nextCar, syntax == null ? null : syntax.getScope(), ellipsis, null)) {
  272. repeat = true;
  273. next = nextPair.getCdr();
  274. while (next instanceof SyntaxForm)
  275. {
  276. syntax = (SyntaxForm) next;
  277. next = syntax.getDatum();
  278. }
  279. }
  280. }
  281. int subvar0 = patternNames.size();
  282. if (context == 'P')
  283. context = '\0';
  284. translate(pair.getCar(), program,
  285. ellipsis, literal_identifiers,
  286. repeat ? nesting + 1 : nesting,
  287. literals, car_syntax,
  288. context == 'V' ? '\0' : 'P', tr);
  289. int subvarN = patternNames.size() - subvar0;
  290. int width = ((program.length() - start_pc - 1) << 3)
  291. | (repeat ? MATCH_LREPEAT : MATCH_PAIR);
  292. if (width > 0xFFFF)
  293. start_pc += insertInt(start_pc, program,
  294. (width >> 13) + MATCH_WIDE);
  295. program.setCharAt(start_pc, (char) width);
  296. int restLength = Translator.listLength(next);
  297. if (restLength == Integer.MIN_VALUE)
  298. {
  299. tr.syntaxError("cyclic pattern list");
  300. return;
  301. }
  302. if (repeat)
  303. {
  304. addInt(program, subvar0 << 3);
  305. addInt(program, subvarN << 3);
  306. if (next == LList.Empty)
  307. {
  308. program.append((char) MATCH_NIL);
  309. return;
  310. }
  311. else
  312. {
  313. // Map a signed int to an unsigned.
  314. restLength = restLength >= 0 ? restLength << 1
  315. : ((-restLength) << 1) - 1;
  316. addInt(program, (restLength << 3) | MATCH_LENGTH);
  317. }
  318. }
  319. pattern = next;
  320. continue;
  321. }
  322. finally
  323. {
  324. tr.popPositionOf(savePos);
  325. }
  326. }
  327. else if (pattern instanceof Symbol && ! (pattern instanceof Keyword))
  328. {
  329. ScopeExp current = tr.currentScope();
  330. ScopeExp scope1 = syntax == null ? current : syntax.getScope();
  331. for (int j = literal_identifiers.length; --j >= 0; )
  332. {
  333. ScopeExp scope2;
  334. Object literal = literal_identifiers[j];
  335. if (literal instanceof SyntaxForm)
  336. {
  337. SyntaxForm syntax2 = (SyntaxForm) literal;
  338. literal = syntax2.getDatum();
  339. scope2 = syntax2.getScope();
  340. }
  341. else if (tr.currentMacroDefinition != null)
  342. scope2 = tr.currentMacroDefinition.getCapturedScope();
  343. else
  344. scope2 = current;
  345. if (literalIdentifierEq(pattern, scope1,
  346. literal, scope2))
  347. {
  348. int i = SyntaxTemplate.indexOf(literals, pattern);
  349. if (i < 0)
  350. {
  351. i = literals.size();
  352. literals.addElement(pattern);
  353. }
  354. addInt(program, (i << 3) | MATCH_EQUALS);
  355. return;
  356. }
  357. }
  358. if (literalIdentifierEq(pattern, scope1, underscoreSymbol, null)) {
  359. program.append((char) MATCH_IGNORE);
  360. return;
  361. }
  362. if (patternNames.contains(pattern))
  363. tr.syntaxError("duplicated pattern variable " + pattern);
  364. int i = patternNames.size();
  365. patternNames.addElement(pattern);
  366. boolean matchCar = context == 'P';
  367. int n = (nesting << 1) + (matchCar ? 1 : 0);
  368. patternScope.patternNesting.append((char) n);
  369. Declaration decl = patternScope.addDeclaration(pattern);
  370. decl.setInitValue(QuoteExp.undefined_exp);
  371. decl.setLocation(tr);
  372. tr.push(decl);
  373. addInt(program, (i << 3) | (matchCar ? MATCH_ANY_CAR : MATCH_ANY));
  374. return;
  375. }
  376. else if (pattern == LList.Empty)
  377. {
  378. program.append((char) MATCH_NIL);
  379. return;
  380. }
  381. else if (pattern instanceof FVector)
  382. {
  383. program.append((char) MATCH_VECTOR);
  384. pattern = LList.makeList((FVector) pattern);
  385. context = 'V';
  386. continue;
  387. }
  388. else
  389. {
  390. int i = SyntaxTemplate.indexOf(literals, pattern);
  391. if (i < 0)
  392. {
  393. i = literals.size();
  394. literals.addElement(pattern);
  395. }
  396. addInt(program, (i << 3) | MATCH_EQUALS);
  397. return;
  398. }
  399. }
  400. }
  401. private static void addInt (StringBuilder sbuf, int val)
  402. {
  403. if (val > 0xFFFF)
  404. addInt(sbuf, (val << 13) + MATCH_WIDE);
  405. sbuf.append((char) (val));
  406. }
  407. private static int insertInt (int offset, StringBuilder sbuf, int val)
  408. {
  409. if (val > 0xFFFF)
  410. offset += insertInt(offset, sbuf, (val << 13) + MATCH_WIDE);
  411. sbuf.insert(offset, (char) (val));
  412. return offset+1;
  413. }
  414. /** Match the <code>car</code> of a <code>Pair</code>.
  415. * This special case (instead of of just matching the <code>car</code>
  416. * directly), is so we can copy <code>PairWithPosition</code> line number
  417. * info into the output of a template. */
  418. boolean match_car (Pair p, Object[] vars, int start_vars,
  419. int pc, SyntaxForm syntax)
  420. {
  421. int pc_start = pc;
  422. char ch;
  423. int value = (ch = program.charAt(pc++)) >> 3;
  424. while ((ch & 7) == MATCH_WIDE)
  425. value = (value << 13) | ((ch = program.charAt(pc++)) >> 3);
  426. if ((ch & 7) == MATCH_ANY_CAR)
  427. {
  428. if (syntax != null && ! (p.getCar() instanceof SyntaxForm))
  429. p = Translator.makePair(p, SyntaxForms.fromDatum(p.getCar(), syntax), p.getCdr());
  430. vars[start_vars + value] = p;
  431. return true;
  432. }
  433. return match (p.getCar(), vars, start_vars, pc_start, syntax);
  434. }
  435. public boolean match (Object obj, Object[] vars, int start_vars,
  436. int pc, SyntaxForm syntax)
  437. {
  438. int value = 0;
  439. Pair p;
  440. for (;;)
  441. {
  442. while (obj instanceof SyntaxForm)
  443. {
  444. syntax = (SyntaxForm) obj;
  445. obj = syntax.getDatum();
  446. }
  447. char ch = program.charAt(pc++);
  448. int opcode = ch & 7;
  449. value = (value << 13) | (ch >> 3);
  450. switch (opcode)
  451. {
  452. case MATCH_WIDE:
  453. continue;
  454. case MATCH_MISC:
  455. if (ch == MATCH_NIL)
  456. return obj == LList.Empty;
  457. else if (ch == MATCH_VECTOR)
  458. {
  459. if (! (obj instanceof FVector))
  460. return false;
  461. return match(LList.makeList((FVector) obj),
  462. vars, start_vars, pc, syntax);
  463. }
  464. else if (ch == MATCH_IGNORE)
  465. return true;
  466. else
  467. throw new Error("unknown pattern opcode");
  468. case MATCH_NIL:
  469. return obj == LList.Empty;
  470. case MATCH_LENGTH:
  471. int npairs = value>>1;
  472. Object o = obj;
  473. for (int i = 0;;i++)
  474. {
  475. while (o instanceof SyntaxForm)
  476. o = ((SyntaxForm) o).getDatum();
  477. if (i == npairs)
  478. {
  479. if ((value&1) == 0 ? o != LList.Empty : o instanceof Pair)
  480. return false;
  481. break;
  482. }
  483. else if (o instanceof Pair)
  484. o = ((Pair) o).getCdr();
  485. else
  486. return false;
  487. }
  488. value = 0;
  489. continue;
  490. case MATCH_PAIR:
  491. if (! (obj instanceof Pair))
  492. return false;
  493. p = (Pair) obj;
  494. if (! match_car(p, vars, start_vars, pc, syntax))
  495. return false;
  496. pc += value;
  497. value = 0;
  498. obj = p.getCdr();
  499. continue;
  500. case MATCH_LREPEAT:
  501. int repeat_pc = pc;
  502. pc += value;
  503. int subvar0 = (ch = program.charAt(pc++)) >> 3;
  504. while ((ch & 0x7) == MATCH_WIDE)
  505. subvar0 = (subvar0 << 13) | ((ch = program.charAt(pc++)) >> 3);
  506. subvar0 += start_vars;
  507. int subvarN = program.charAt(pc++) >> 3;
  508. while ((ch & 0x7) == MATCH_WIDE)
  509. subvarN = (subvarN << 13) | ((ch = program.charAt(pc++)) >> 3);
  510. ch = program.charAt(pc++);
  511. boolean listRequired = true;
  512. int pairsRequired;
  513. if (ch == MATCH_NIL)
  514. {
  515. pairsRequired = 0;
  516. }
  517. else
  518. {
  519. value = ch >> 3;
  520. while ((ch & 0x7) == MATCH_WIDE)
  521. value = (value << 13) | ((ch = program.charAt(pc++)) >> 3);
  522. if ((value & 1) != 0)
  523. listRequired = false;
  524. pairsRequired = value >> 1;
  525. }
  526. int pairsValue = Translator.listLength(obj);
  527. boolean listValue;
  528. if (pairsValue >= 0)
  529. listValue = true;
  530. else
  531. {
  532. listValue = false;
  533. pairsValue = -1-pairsValue;
  534. }
  535. if (pairsValue < pairsRequired || (listRequired && ! listValue))
  536. return false;
  537. int repeat_count = pairsValue - pairsRequired;
  538. Object[][] arrays = new Object[subvarN][];
  539. for (int j = 0; j < subvarN; j++)
  540. arrays[j] = new Object[repeat_count];
  541. for (int i = 0; i < repeat_count; i++)
  542. {
  543. while (obj instanceof SyntaxForm)
  544. {
  545. syntax = (SyntaxForm) obj;
  546. obj = syntax.getDatum();
  547. }
  548. p = (Pair) obj;
  549. if (! match_car (p, vars, start_vars, repeat_pc, syntax))
  550. return false;
  551. obj = p.getCdr();
  552. for (int j = 0; j < subvarN; j++)
  553. arrays[j][i] = vars[subvar0+j];
  554. }
  555. for (int j = 0; j < subvarN; j++)
  556. vars[subvar0+j] = arrays[j];
  557. value = 0;
  558. if (pairsRequired == 0 && listRequired)
  559. return true;
  560. continue;
  561. case MATCH_EQUALS:
  562. Object lit = literals[value];
  563. Translator tr = (Translator) Compilation.getCurrent();
  564. Syntax curSyntax = tr.getCurrentSyntax();
  565. ScopeExp sc1 = curSyntax instanceof Macro
  566. ? ((Macro) curSyntax).getCapturedScope()
  567. : null;
  568. ScopeExp sc2 = syntax == null ? tr.currentScope()
  569. : syntax.getScope();
  570. return literalIdentifierEq(lit, sc1, obj, sc2);
  571. case MATCH_ANY:
  572. if (syntax != null)
  573. obj = SyntaxForms.fromDatum(obj, syntax);
  574. vars[start_vars + value] = obj;
  575. return true;
  576. case MATCH_ANY_CAR: // Disallowed here.
  577. default:
  578. disassemble();
  579. throw new Error("unrecognized pattern opcode @pc:"+pc);
  580. }
  581. }
  582. }
  583. public void writeExternal(ObjectOutput out) throws IOException
  584. {
  585. out.writeObject(program);
  586. out.writeObject(literals);
  587. out.writeInt(varCount);
  588. out.writeUTF(fileLine == null ? "" : fileLine);
  589. }
  590. public void readExternal(ObjectInput in)
  591. throws IOException, ClassNotFoundException
  592. {
  593. literals = (Object[]) in.readObject();
  594. program = (String) in.readObject();
  595. varCount = in.readInt();
  596. String fline = in.readUTF();
  597. if (fline != null)
  598. fileLine = fline;
  599. }
  600. /** The compiler calls this method to implement syntax-case. */
  601. public static Object[] allocVars (int varCount, Object[] outer) {
  602. Object[] vars = new Object[varCount];
  603. if (outer != null) {
  604. int toCopy = outer.length;
  605. if (toCopy > varCount)
  606. toCopy = varCount;
  607. System.arraycopy(outer, 0, vars, 0, toCopy);
  608. }
  609. return vars;
  610. }
  611. public static boolean literalIdentifierEq(Object id1, ScopeExp sc1,
  612. Object id2, ScopeExp sc2) {
  613. if (id1 instanceof SyntaxForm) {
  614. SyntaxForm form1 = (SyntaxForm) id1;
  615. id1 = form1.getDatum();
  616. sc1 = form1.getScope();
  617. }
  618. if (id2 instanceof SyntaxForm) {
  619. SyntaxForm form2 = (SyntaxForm) id2;
  620. id2 = form2.getDatum();
  621. sc2 = form2.getScope();
  622. }
  623. if (id1 != id2 && (id1 == null || id2 == null || ! id1.equals(id2)))
  624. return false;
  625. if (sc1 == sc2)
  626. return true;
  627. Declaration d1 = null, d2 = null;
  628. // Ending the look before we get to ModuleExp isn't really right,
  629. // but it's a hassle dealing the global Environment.
  630. // FIXME when we re-do the library/globals implementation.
  631. while (sc1 != null && ! (sc1 instanceof ModuleExp))
  632. {
  633. d1 = sc1.lookup(id1);
  634. if (d1 != null)
  635. break;
  636. sc1 = sc1.getOuter();
  637. }
  638. while (sc2 != null && ! (sc2 instanceof ModuleExp))
  639. {
  640. d2 = sc2.lookup(id2);
  641. if (d2 != null)
  642. break;
  643. sc2 = sc2.getOuter();
  644. }
  645. return d1 == d2;
  646. }
  647. /** Parse the literals list in a syntax-rules or syntax-case. */
  648. public static Object[] getLiteralsList (Object list,
  649. SyntaxForm syntax, Translator tr)
  650. {
  651. Object savePos = tr.pushPositionOf(list);
  652. int count = Translator.listLength(list);
  653. if (count < 0)
  654. {
  655. tr.error('e', "missing or malformed literals list");
  656. count = 0;
  657. }
  658. Object[] literals = new Object[count];
  659. for (int i = 0; i < count; i++)
  660. {
  661. while (list instanceof SyntaxForm)
  662. {
  663. syntax = (SyntaxForm) list;
  664. list = syntax.getDatum();
  665. }
  666. Pair pair = (Pair) list;
  667. tr.pushPositionOf(pair);
  668. Object literal = pair.getCar();
  669. Object wrapped = SyntaxForms.fromDatumIfNeeded(literal, syntax);
  670. literal = Translator.stripSyntax(literal);
  671. if (! (literal instanceof Symbol))
  672. tr.error('e', "non-symbol '"+literal+"' in literals list");
  673. literals[i] = wrapped;
  674. list = pair.getCdr();
  675. }
  676. tr.popPositionOf(savePos);
  677. return literals;
  678. }
  679. public String toString() {
  680. StringBuilder sbuf = new StringBuilder("#<syntax-pattern");
  681. if (fileLine != null) {
  682. sbuf.append(' ');
  683. sbuf.append(fileLine);
  684. }
  685. sbuf.append('>');
  686. return sbuf.toString();
  687. }
  688. }