dynwind.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /* Copyright (C) 1995, 1996, 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2, or (at your option)
  6. * any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; see the file COPYING. If not, write to
  15. * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. * Boston, MA 02111-1307 USA
  17. *
  18. * As a special exception, the Free Software Foundation gives permission
  19. * for additional uses of the text contained in its release of GUILE.
  20. *
  21. * The exception is that, if you link the GUILE library with other files
  22. * to produce an executable, this does not by itself cause the
  23. * resulting executable to be covered by the GNU General Public License.
  24. * Your use of that executable is in no way restricted on account of
  25. * linking the GUILE library code into it.
  26. *
  27. * This exception does not however invalidate any other reasons why
  28. * the executable file might be covered by the GNU General Public License.
  29. *
  30. * This exception applies only to the code released by the
  31. * Free Software Foundation under the name GUILE. If you copy
  32. * code from other Free Software Foundation releases into a copy of
  33. * GUILE, as the General Public License permits, the exception does
  34. * not apply to the code that you add in this way. To avoid misleading
  35. * anyone as to the status of such modified files, you must delete
  36. * this exception notice from them.
  37. *
  38. * If you write modifications of your own for GUILE, it is your choice
  39. * whether to permit this exception to apply to your modifications.
  40. * If you do not wish that, delete this exception notice. */
  41. #include <stdio.h>
  42. #include "libguile/_scm.h"
  43. #include "libguile/eval.h"
  44. #include "libguile/alist.h"
  45. #include "libguile/fluids.h"
  46. #include "libguile/ports.h"
  47. #include "libguile/smob.h"
  48. #include "libguile/dynwind.h"
  49. /* {Dynamic wind}
  50. Things that can be on the wind list:
  51. (enter-proc . leave-proc) dynamic-wind
  52. (tag . jmpbuf) catch
  53. (tag . lazy-catch) lazy-catch
  54. tag is either a symbol or a boolean
  55. ((fluid ...) . (value ...)) with-fluids
  56. */
  57. SCM_DEFINE (scm_dynamic_wind, "dynamic-wind", 3, 0, 0,
  58. (SCM thunk1, SCM thunk2, SCM thunk3),
  59. "All three arguments must be 0-argument procedures.\n\n"
  60. "@var{in-guard} is called, then @var{thunk}, then @var{out-guard}.\n\n"
  61. "If, any time during the execution of @var{thunk}, the continuation\n"
  62. "of the @code{dynamic-wind} expression is escaped non-locally, @var{out-guard}\n"
  63. "is called. If the continuation of the dynamic-wind is re-entered,\n"
  64. "@var{in-guard} is called. Thus @var{in-guard} and @var{out-guard} may\n"
  65. "be called any number of times.\n\n"
  66. "@example\n"
  67. "(define x 'normal-binding)\n"
  68. "@result{} x\n\n"
  69. "(define a-cont (call-with-current-continuation \n"
  70. " (lambda (escape)\n"
  71. " (let ((old-x x))\n"
  72. " (dynamic-wind\n"
  73. " ;; in-guard:\n"
  74. " ;;\n"
  75. " (lambda () (set! x 'special-binding))\n\n"
  76. " ;; thunk\n"
  77. " ;;\n"
  78. " (lambda () (display x) (newline)\n"
  79. " (call-with-current-continuation escape)\n"
  80. " (display x) (newline)\n"
  81. " x)\n\n"
  82. " ;; out-guard:\n"
  83. " ;;\n"
  84. " (lambda () (set! x old-x)))))))\n\n"
  85. ";; Prints: \n"
  86. "special-binding\n"
  87. ";; Evaluates to:\n"
  88. "@result{} a-cont\n\n"
  89. "x\n"
  90. "@result{} normal-binding\n\n"
  91. "(a-cont #f)\n"
  92. ";; Prints:\n"
  93. "special-binding\n"
  94. ";; Evaluates to:\n"
  95. "@result{} a-cont ;; the value of the (define a-cont...)\n\n"
  96. "x\n"
  97. "@result{} normal-binding\n\n"
  98. "a-cont\n"
  99. "@result{} special-binding\n"
  100. "@end example\n"
  101. "")
  102. #define FUNC_NAME s_scm_dynamic_wind
  103. {
  104. SCM ans;
  105. SCM_ASSERT (SCM_NFALSEP (scm_thunk_p (thunk3)),
  106. thunk3,
  107. SCM_ARG3, FUNC_NAME);
  108. scm_apply (thunk1, SCM_EOL, SCM_EOL);
  109. scm_dynwinds = scm_acons (thunk1, thunk3, scm_dynwinds);
  110. ans = scm_apply (thunk2, SCM_EOL, SCM_EOL);
  111. scm_dynwinds = SCM_CDR (scm_dynwinds);
  112. scm_apply (thunk3, SCM_EOL, SCM_EOL);
  113. return ans;
  114. }
  115. #undef FUNC_NAME
  116. /* The implementation of a C-callable dynamic-wind,
  117. * scm_internal_dynamic_wind, requires packaging of C pointers in a
  118. * smob. Objects of this type are pushed onto the dynwind chain.
  119. */
  120. #define SCM_GUARDSP(obj) SCM_SMOB_PREDICATE (tc16_guards, obj)
  121. #define SCM_BEFORE_GUARD(obj) ((scm_guard_t) SCM_CELL_WORD (obj, 1))
  122. #define SCM_AFTER_GUARD(obj) ((scm_guard_t) SCM_CELL_WORD (obj, 2))
  123. #define SCM_GUARD_DATA(obj) ((void *) SCM_CELL_WORD (obj, 3))
  124. static long tc16_guards;
  125. static int
  126. printguards (SCM exp, SCM port, scm_print_state *pstate)
  127. {
  128. scm_puts ("#<guards ", port);
  129. scm_intprint (SCM_UNPACK (SCM_CDR (exp)), 16, port);
  130. scm_putc ('>', port);
  131. return 1;
  132. }
  133. SCM
  134. scm_internal_dynamic_wind (scm_guard_t before,
  135. scm_inner_t inner,
  136. scm_guard_t after,
  137. void *inner_data,
  138. void *guard_data)
  139. {
  140. SCM guards, ans;
  141. before (guard_data);
  142. SCM_NEWSMOB3 (guards, tc16_guards, (scm_bits_t) before,
  143. (scm_bits_t) after, (scm_bits_t) guard_data);
  144. scm_dynwinds = scm_acons (guards, SCM_BOOL_F, scm_dynwinds);
  145. ans = inner (inner_data);
  146. scm_dynwinds = SCM_CDR (scm_dynwinds);
  147. after (guard_data);
  148. return ans;
  149. }
  150. #ifdef GUILE_DEBUG
  151. SCM_DEFINE (scm_wind_chain, "wind-chain", 0, 0, 0,
  152. (),
  153. "")
  154. #define FUNC_NAME s_scm_wind_chain
  155. {
  156. return scm_dynwinds;
  157. }
  158. #undef FUNC_NAME
  159. #endif
  160. static void
  161. scm_swap_bindings (SCM glocs, SCM vals)
  162. {
  163. SCM tmp;
  164. while (SCM_NIMP (vals))
  165. {
  166. tmp = SCM_GLOC_VAL (SCM_CAR (glocs));
  167. SCM_SETCDR (SCM_PACK (SCM_UNPACK (SCM_CAR (glocs)) - 1L),
  168. SCM_CAR (vals));
  169. SCM_SETCAR (vals, tmp);
  170. glocs = SCM_CDR (glocs);
  171. vals = SCM_CDR (vals);
  172. }
  173. }
  174. void
  175. scm_dowinds (SCM to, long delta)
  176. {
  177. tail:
  178. if (SCM_EQ_P (to, scm_dynwinds));
  179. else if (0 > delta)
  180. {
  181. SCM wind_elt;
  182. SCM wind_key;
  183. scm_dowinds (SCM_CDR (to), 1 + delta);
  184. wind_elt = SCM_CAR (to);
  185. #if 0
  186. if (SCM_INUMP (wind_elt))
  187. {
  188. scm_cross_dynwind_binding_scope (wind_elt, 0);
  189. }
  190. else
  191. #endif
  192. {
  193. wind_key = SCM_CAR (wind_elt);
  194. /* key = #t | symbol | thunk | list of glocs | list of fluids */
  195. if (SCM_NIMP (wind_key))
  196. {
  197. if (SCM_TYP3 (wind_key) == scm_tc3_cons_gloc)
  198. scm_swap_bindings (wind_key, SCM_CDR (wind_elt));
  199. else if (SCM_TYP3 (wind_key) == scm_tc3_cons)
  200. scm_swap_fluids (wind_key, SCM_CDR (wind_elt));
  201. else if (SCM_GUARDSP (wind_key))
  202. SCM_BEFORE_GUARD (wind_key) (SCM_GUARD_DATA (wind_key));
  203. else if (SCM_TYP3 (wind_key) == scm_tc3_closure)
  204. scm_apply (wind_key, SCM_EOL, SCM_EOL);
  205. }
  206. }
  207. scm_dynwinds = to;
  208. }
  209. else
  210. {
  211. SCM from;
  212. SCM wind_elt;
  213. SCM wind_key;
  214. from = SCM_CDR (SCM_CAR (scm_dynwinds));
  215. wind_elt = SCM_CAR (scm_dynwinds);
  216. scm_dynwinds = SCM_CDR (scm_dynwinds);
  217. #if 0
  218. if (SCM_INUMP (wind_elt))
  219. {
  220. scm_cross_dynwind_binding_scope (wind_elt, 0);
  221. }
  222. else
  223. #endif
  224. {
  225. wind_key = SCM_CAR (wind_elt);
  226. if (SCM_NIMP (wind_key))
  227. {
  228. if (SCM_TYP3 (wind_key) == scm_tc3_cons_gloc)
  229. scm_swap_bindings (wind_key, from);
  230. else if (SCM_TYP3 (wind_key) == scm_tc3_cons)
  231. scm_swap_fluids_reverse (wind_key, from);
  232. else if (SCM_GUARDSP (wind_key))
  233. SCM_AFTER_GUARD (wind_key) (SCM_GUARD_DATA (wind_key));
  234. else if (SCM_TYP3 (wind_key) == scm_tc3_closure)
  235. scm_apply (from, SCM_EOL, SCM_EOL);
  236. }
  237. }
  238. delta--;
  239. goto tail; /* scm_dowinds(to, delta-1); */
  240. }
  241. }
  242. void
  243. scm_init_dynwind ()
  244. {
  245. tc16_guards = scm_make_smob_type_mfpe ("guards", 0,
  246. NULL, scm_free0, printguards, NULL);
  247. #include "libguile/dynwind.x"
  248. }
  249. /*
  250. Local Variables:
  251. c-file-style: "gnu"
  252. End:
  253. */