catch-throw.red 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. %
  2. % CATCH-THROW.RED - Common Lisp dynamic non-local exits
  3. %
  4. % Author: Eric Benson
  5. % Symbolic Computation Group
  6. % Computer Science Dept.
  7. % University of Utah
  8. % Date: 12 October 1982
  9. % Copyright (c) 1982 University of Utah
  10. %
  11. % Edit by Cris Perdue, 23 Feb 1983 1624-PST
  12. % Modified the stack overflow warning message
  13. % Edit by Cris Perdue, 16 Feb 1983 1032-PST
  14. % Changed catch stack overflow checking to give a continuable error
  15. % when stack gets low, Reset when all out.
  16. % Edit by Cris Perdue, 4 Feb 1983 1209-PST
  17. % Moved ERRSET to ERROR-ERRORSET from here.
  18. % Edit by Cris Perdue, 3 Feb 1983 1520-PST
  19. % Changed catch stack overflow to talk about the CATCH stack. (!)
  20. % Deleted definition of "errset".
  21. % <PSL.KERNEL>CATCH-THROW.RED.13, 21-Dec-82 15:55:26, Edit by BENSON
  22. % Added %clear-catch-stack
  23. % <PSL.KERNEL>CATCH-THROW.RED.13, 16-Dec-82 09:58:59, Edit by BENSON
  24. % Error not within ErrorSet now causes fatal error, not infinite loop
  25. fluid '(ThrowSignal!*
  26. EMSG!*
  27. ThrowTag!*);
  28. macro procedure catch!-all u;
  29. (lambda(fn, forms);
  30. list(list('lambda, '(!&!&Value!&!&),
  31. list('cond, list('ThrowSignal!*,
  32. list('Apply,
  33. fn,
  34. '(list ThrowTag!* !&!&Value!&!&))),
  35. '(t !&!&Value!&!&))),
  36. 'catch . nil . forms))(cadr U, cddr U);
  37. macro procedure unwind!-all u;
  38. (lambda(fn, forms);
  39. list(list('lambda, '(!&!&Value!&!&),
  40. list('Apply,
  41. fn,
  42. '(list (and ThrowSignal!* ThrowTag!*)
  43. !&!&Value!&!&))),
  44. 'catch . nil . forms))(cadr U, cddr U);
  45. macro procedure unwind!-protect u;
  46. (lambda(protected_form, cleanup_forms);
  47. list(list('lambda, '(!&!&Value!&!&),
  48. list('lambda, '(!&!&Thrown!&!& !&!&Tag!&!&),
  49. 'progn . cleanup_forms,
  50. '(cond (!&!&Thrown!&!&
  51. (!%Throw !&!&Tag!&!& !&!&Value!&!&))
  52. (t !&!&Value!&!&)))
  53. . '(ThrowSignal!* ThrowTag!*)),
  54. list('catch, ''!$unwind!-protect!$, protected_form)))(cadr U,cddr U);
  55. off R2I;
  56. % This funny definition is due to a PA1FN for CATCH
  57. fexpr procedure Catch U;
  58. (lambda(Tag, Forms);
  59. Catch(Eval Tag, EvProgN Forms))(car U, cdr U);
  60. on R2I;
  61. % Temporary compatibility package.
  62. macro procedure !*Catch U;
  63. 'Catch . cdr U;
  64. expr procedure !*Throw(x,y);
  65. throw(x,y);
  66. on Syslisp;
  67. % Size is in terms of number of frames
  68. internal WConst CatchStackSize = 400;
  69. internal WArray CatchStack[CatchStackSize*4];
  70. internal WVar CatchStackPtr = &CatchStack[0];
  71. CompileTime <<
  72. smacro procedure CatchPop();
  73. CatchStackPtr := &CatchStackPtr[-4];
  74. smacro procedure CatchStackDecrement X;
  75. &X[-4];
  76. % Rather large for a smacro, used only from CatchSetupAux /csp
  77. % Tests structured for fast usual execution /csp
  78. % Random constant 5 for "reserve" catch stack frames /csp
  79. smacro procedure CatchPush(Tag, PC, SP, Env);
  80. << CatchStackPtr := &CatchStackPtr[4];
  81. if CatchStackPtr >= &CatchStack[(CatchStackSize-5)*4] then
  82. << if CatchStackPtr = &CatchStack[(CatchStackSize-5)*4] then
  83. ContinuableError(99,"Catch-throw stack overflow (warning)", NIL);
  84. if CatchStackPtr >= &CatchStack[CatchStackSize*4] then
  85. << (LispVar EMSG!*) := "Catch stack overflow";
  86. reset() >> >>;
  87. CatchStackPtr[0] := Tag;
  88. CatchStackPtr[1] := PC;
  89. CatchStackPtr[2] := SP;
  90. CatchStackPtr[3] := Env >>;
  91. smacro procedure CatchTopTag();
  92. CatchStackPtr[0];
  93. smacro procedure CatchTagAt X;
  94. X[0];
  95. smacro procedure CatchTopPC();
  96. CatchStackPtr[1];
  97. smacro procedure CatchTopSP();
  98. CatchStackPtr[2];
  99. smacro procedure CatchTopEnv();
  100. CatchStackPtr[3];
  101. flag('(CatchSetupAux ThrowAux FindCatchMarkAndThrow), 'InternalFunction);
  102. >>;
  103. % CatchSetup puts the return address in reg 2, the stack pointer in reg 3
  104. % and calls CatchSetupAux
  105. lap '((!*entry CatchSetup expr 1) %. CatchSetup(Tag)
  106. (!*MOVE (MEMORY (reg st) (WConst 0)) (reg 2))
  107. (!*MOVE (reg st) (reg 3))
  108. (!*JCALL CatchSetupAux)
  109. );
  110. syslsp procedure CatchSetupAux(Tag, PC, SP);
  111. begin scalar Previous;
  112. Previous := CatchStackPtr;
  113. CatchPush(Tag, PC, SP, CaptureEnvironment());
  114. LispVar ThrowSignal!* := NIL;
  115. return Previous;
  116. end;
  117. syslsp procedure !%UnCatch Previous;
  118. << CatchStackPtr := Previous;
  119. LispVar ThrowSignal!* := NIL >>;
  120. syslsp procedure !%clear!-catch!-stack();
  121. CatchStackPtr := &CatchStack[0];
  122. syslsp procedure !%Throw(Tag, Value);
  123. begin scalar TopTag;
  124. TopTag := CatchTopTag();
  125. return if not (null TopTag
  126. or TopTag eq '!$unwind!-protect!$
  127. or Tag eq TopTag) then
  128. << CatchPop();
  129. !%Throw(Tag, Value) >>
  130. else begin scalar PC, SP;
  131. PC := CatchTopPC();
  132. SP := CatchTopSP();
  133. RestoreEnvironment CatchTopEnv();
  134. CatchPop();
  135. LispVar ThrowSignal!* := T;
  136. LispVar ThrowTag!* := Tag;
  137. return ThrowAux(Value, PC, SP);
  138. end;
  139. end;
  140. lap '((!*entry ThrowAux expr 3)
  141. (!*MOVE (reg 3) (reg st))
  142. (!*MOVE (reg 2) (MEMORY (reg st) (WConst 0)))
  143. (!*EXIT 0)
  144. );
  145. syslsp procedure Throw(Tag, Value);
  146. FindCatchMarkAndThrow(Tag, Value, CatchStackPtr);
  147. % Throw to $Error$ that doesn't have a catch can't cause a normal error
  148. % else an infinite loop will result. Changed to use FatalError instead.
  149. syslsp procedure FindCatchMarkAndThrow(Tag, Value, P);
  150. if P = &CatchStack[0] then
  151. if not (Tag eq '!$Error!$) then
  152. ContError(99,
  153. "Catch tag %r not found in Throw",
  154. Tag,
  155. Throw(Tag, Value))
  156. else FatalError "Error not within ErrorSet"
  157. else if null CatchTagAt P or Tag eq CatchTagAt P then
  158. !%Throw(Tag, Value)
  159. else FindCatchMarkAndThrow(Tag, Value, CatchStackDecrement P);
  160. off Syslisp;
  161. END;