mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-17 17:20:29 +02:00
with-dynamic-state compiler and VM support
* libguile/dynstack.h (SCM_DYNSTACK_TYPE_DYNAMIC_STATE): * libguile/dynstack.c (DYNAMIC_STATE_WORDS, DYNAMIC_STATE_STATE_BOX): (scm_dynstack_push_dynamic_state): (scm_dynstack_unwind_dynamic_state): New definitions. (scm_dynstack_unwind_1, scm_dynstack_wind_1): Add with-dynamic-state cases. * libguile/memoize.c (push_dynamic_state, pop_dynamic_state) (do_push_dynamic_state, do_pop_dynamic_state): New definitions. (memoize, scm_init_memoize): Handle push-dynamic-state and pop-dynamic-state. * libguile/vm-engine.c (push-dynamic-state, pop-dynamic-state): New opcodes. * module/ice-9/boot-9.scm (with-dynamic-state): New definition in Scheme so that the push-dynamic-state and pop-dynamic-state always run in the VM. * module/language/cps/compile-bytecode.scm (compile-function): * module/language/cps/effects-analysis.scm: * module/language/cps/types.scm: * module/language/tree-il/effects.scm (make-effects-analyzer): * module/language/tree-il/peval.scm (peval): * module/language/tree-il/primitives.scm (*interesting-primitive-names*): * module/system/vm/assembler.scm: Add support for with-dynamic-state to the compiler. * test-suite/tests/fluids.test ("dynamic states"): Add basic tests. * doc/ref/vm.texi (Dynamic Environment Instructions): Update.
This commit is contained in:
parent
aa84489d18
commit
7184c176b4
14 changed files with 260 additions and 5 deletions
|
@ -1204,6 +1204,18 @@ Set the value of the fluid in @var{dst} to the value in @var{src}.
|
||||||
Write the value of the current thread to @var{dst}.
|
Write the value of the current thread to @var{dst}.
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
|
@deftypefn Instruction {} push-dynamic-state s24:@var{state}
|
||||||
|
Save the current set of fluid bindings on the dynamic stack and instate
|
||||||
|
the bindings from @var{state} instead. @xref{Fluids and Dynamic
|
||||||
|
States}.
|
||||||
|
@end deftypefn
|
||||||
|
|
||||||
|
@deftypefn Instruction {} pop-dynamic-state x24:@var{_}
|
||||||
|
Restore a saved set of fluid bindings from the dynamic stack.
|
||||||
|
@code{push-dynamic-state} should always be balanced with
|
||||||
|
@code{pop-dynamic-state}.
|
||||||
|
@end deftypefn
|
||||||
|
|
||||||
|
|
||||||
@node Miscellaneous Instructions
|
@node Miscellaneous Instructions
|
||||||
@subsubsection Miscellaneous Instructions
|
@subsubsection Miscellaneous Instructions
|
||||||
|
@ -1237,6 +1249,17 @@ Pop the stack pointer by @var{count} words, discarding any values that
|
||||||
were stored there.
|
were stored there.
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
|
@deftypefn Instruction {} handle-interrupts x24:@var{_}
|
||||||
|
Handle pending asynchronous interrupts (asyncs). @xref{Asyncs}. The
|
||||||
|
compiler inserts @code{handle-interrupts} instructions before any call,
|
||||||
|
return, or loop back-edge.
|
||||||
|
@end deftypefn
|
||||||
|
|
||||||
|
@deftypefn Instruction {} return-from-interrupt x24:@var{_}
|
||||||
|
A special instruction to return from a call and also pop off the stack
|
||||||
|
frame from the call. Used when returning from asynchronous interrupts.
|
||||||
|
@end deftypefn
|
||||||
|
|
||||||
|
|
||||||
@node Inlined Scheme Instructions
|
@node Inlined Scheme Instructions
|
||||||
@subsubsection Inlined Scheme Instructions
|
@subsubsection Inlined Scheme Instructions
|
||||||
|
|
|
@ -53,6 +53,9 @@
|
||||||
#define WITH_FLUID_FLUID(top) (SCM_PACK ((top)[0]))
|
#define WITH_FLUID_FLUID(top) (SCM_PACK ((top)[0]))
|
||||||
#define WITH_FLUID_VALUE_BOX(top) (SCM_PACK ((top)[1]))
|
#define WITH_FLUID_VALUE_BOX(top) (SCM_PACK ((top)[1]))
|
||||||
|
|
||||||
|
#define DYNAMIC_STATE_WORDS 1
|
||||||
|
#define DYNAMIC_STATE_STATE_BOX(top) (SCM_PACK ((top)[0]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -230,6 +233,22 @@ dynstack_pop (scm_t_dynstack *dynstack, scm_t_bits **words)
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
scm_dynstack_push_dynamic_state (scm_t_dynstack *dynstack, SCM state,
|
||||||
|
scm_t_dynamic_state *dynamic_state)
|
||||||
|
{
|
||||||
|
scm_t_bits *words;
|
||||||
|
SCM state_box;
|
||||||
|
|
||||||
|
if (SCM_UNLIKELY (scm_is_false (scm_dynamic_state_p (state))))
|
||||||
|
scm_wrong_type_arg ("with-dynamic-state", 0, state);
|
||||||
|
|
||||||
|
state_box = scm_make_variable (scm_set_current_dynamic_state (state));
|
||||||
|
words = push_dynstack_entry (dynstack, SCM_DYNSTACK_TYPE_DYNAMIC_STATE, 0,
|
||||||
|
DYNAMIC_STATE_WORDS);
|
||||||
|
words[0] = SCM_UNPACK (state_box);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
scm_dynstack_pop (scm_t_dynstack *dynstack)
|
scm_dynstack_pop (scm_t_dynstack *dynstack)
|
||||||
{
|
{
|
||||||
|
@ -305,6 +324,12 @@ scm_dynstack_wind_1 (scm_t_dynstack *dynstack, scm_t_bits *item)
|
||||||
scm_call_0 (DYNWIND_ENTER (item));
|
scm_call_0 (DYNWIND_ENTER (item));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SCM_DYNSTACK_TYPE_DYNAMIC_STATE:
|
||||||
|
scm_variable_set_x (DYNAMIC_STATE_STATE_BOX (item),
|
||||||
|
scm_set_current_dynamic_state
|
||||||
|
(scm_variable_ref (DYNAMIC_STATE_STATE_BOX (item))));
|
||||||
|
break;
|
||||||
|
|
||||||
case SCM_DYNSTACK_TYPE_NONE:
|
case SCM_DYNSTACK_TYPE_NONE:
|
||||||
default:
|
default:
|
||||||
abort ();
|
abort ();
|
||||||
|
@ -362,6 +387,13 @@ scm_dynstack_unwind_1 (scm_t_dynstack *dynstack)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SCM_DYNSTACK_TYPE_DYNAMIC_STATE:
|
||||||
|
scm_variable_set_x (DYNAMIC_STATE_STATE_BOX (words),
|
||||||
|
scm_set_current_dynamic_state
|
||||||
|
(scm_variable_ref (DYNAMIC_STATE_STATE_BOX (words))));
|
||||||
|
clear_scm_t_bits (words, DYNAMIC_STATE_WORDS);
|
||||||
|
break;
|
||||||
|
|
||||||
case SCM_DYNSTACK_TYPE_NONE:
|
case SCM_DYNSTACK_TYPE_NONE:
|
||||||
default:
|
default:
|
||||||
abort ();
|
abort ();
|
||||||
|
@ -542,6 +574,25 @@ scm_dynstack_unwind_fluid (scm_t_dynstack *dynstack,
|
||||||
clear_scm_t_bits (words, len);
|
clear_scm_t_bits (words, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
scm_dynstack_unwind_dynamic_state (scm_t_dynstack *dynstack,
|
||||||
|
scm_t_dynamic_state *dynamic_state)
|
||||||
|
{
|
||||||
|
scm_t_bits tag, *words;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
tag = dynstack_pop (dynstack, &words);
|
||||||
|
len = SCM_DYNSTACK_TAG_LEN (tag);
|
||||||
|
|
||||||
|
assert (SCM_DYNSTACK_TAG_TYPE (tag) == SCM_DYNSTACK_TYPE_DYNAMIC_STATE);
|
||||||
|
assert (len == DYNAMIC_STATE_WORDS);
|
||||||
|
|
||||||
|
scm_variable_set_x (DYNAMIC_STATE_STATE_BOX (words),
|
||||||
|
scm_set_current_dynamic_state
|
||||||
|
(scm_variable_ref (DYNAMIC_STATE_STATE_BOX (words))));
|
||||||
|
clear_scm_t_bits (words, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Local Variables:
|
Local Variables:
|
||||||
|
|
|
@ -81,6 +81,7 @@ typedef enum {
|
||||||
SCM_DYNSTACK_TYPE_WITH_FLUID,
|
SCM_DYNSTACK_TYPE_WITH_FLUID,
|
||||||
SCM_DYNSTACK_TYPE_PROMPT,
|
SCM_DYNSTACK_TYPE_PROMPT,
|
||||||
SCM_DYNSTACK_TYPE_DYNWIND,
|
SCM_DYNSTACK_TYPE_DYNWIND,
|
||||||
|
SCM_DYNSTACK_TYPE_DYNAMIC_STATE,
|
||||||
} scm_t_dynstack_item_type;
|
} scm_t_dynstack_item_type;
|
||||||
|
|
||||||
#define SCM_DYNSTACK_TAG_TYPE_MASK 0xf
|
#define SCM_DYNSTACK_TAG_TYPE_MASK 0xf
|
||||||
|
@ -150,6 +151,8 @@ SCM_INTERNAL void scm_dynstack_push_unwinder (scm_t_dynstack *,
|
||||||
SCM_INTERNAL void scm_dynstack_push_fluid (
|
SCM_INTERNAL void scm_dynstack_push_fluid (
|
||||||
scm_t_dynstack *, SCM fluid, SCM value,
|
scm_t_dynstack *, SCM fluid, SCM value,
|
||||||
scm_t_dynamic_state *dynamic_state);
|
scm_t_dynamic_state *dynamic_state);
|
||||||
|
SCM_INTERNAL void scm_dynstack_push_dynamic_state (scm_t_dynstack *, SCM,
|
||||||
|
scm_t_dynamic_state *);
|
||||||
SCM_INTERNAL void scm_dynstack_push_prompt (scm_t_dynstack *,
|
SCM_INTERNAL void scm_dynstack_push_prompt (scm_t_dynstack *,
|
||||||
scm_t_dynstack_prompt_flags,
|
scm_t_dynstack_prompt_flags,
|
||||||
SCM key,
|
SCM key,
|
||||||
|
@ -188,6 +191,8 @@ SCM_INTERNAL scm_t_bits* scm_dynstack_unwind_fork (scm_t_dynstack *,
|
||||||
SCM_INTERNAL void scm_dynstack_unwind_frame (scm_t_dynstack *);
|
SCM_INTERNAL void scm_dynstack_unwind_frame (scm_t_dynstack *);
|
||||||
SCM_INTERNAL void scm_dynstack_unwind_fluid
|
SCM_INTERNAL void scm_dynstack_unwind_fluid
|
||||||
(scm_t_dynstack *dynstack, scm_t_dynamic_state *dynamic_state);
|
(scm_t_dynstack *dynstack, scm_t_dynamic_state *dynamic_state);
|
||||||
|
SCM_INTERNAL void scm_dynstack_unwind_dynamic_state
|
||||||
|
(scm_t_dynstack *dynstack, scm_t_dynamic_state *dynamic_state);
|
||||||
|
|
||||||
SCM_INTERNAL scm_t_bits* scm_dynstack_find_prompt (scm_t_dynstack *, SCM,
|
SCM_INTERNAL scm_t_bits* scm_dynstack_find_prompt (scm_t_dynstack *, SCM,
|
||||||
scm_t_dynstack_prompt_flags *,
|
scm_t_dynstack_prompt_flags *,
|
||||||
|
|
|
@ -68,6 +68,8 @@ static SCM wind;
|
||||||
static SCM unwind;
|
static SCM unwind;
|
||||||
static SCM push_fluid;
|
static SCM push_fluid;
|
||||||
static SCM pop_fluid;
|
static SCM pop_fluid;
|
||||||
|
static SCM push_dynamic_state;
|
||||||
|
static SCM pop_dynamic_state;
|
||||||
|
|
||||||
static SCM
|
static SCM
|
||||||
do_wind (SCM in, SCM out)
|
do_wind (SCM in, SCM out)
|
||||||
|
@ -100,6 +102,24 @@ do_pop_fluid (void)
|
||||||
return SCM_UNSPECIFIED;
|
return SCM_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SCM
|
||||||
|
do_push_dynamic_state (SCM state)
|
||||||
|
{
|
||||||
|
scm_i_thread *thread = SCM_I_CURRENT_THREAD;
|
||||||
|
scm_dynstack_push_dynamic_state (&thread->dynstack, state,
|
||||||
|
thread->dynamic_state);
|
||||||
|
return SCM_UNSPECIFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SCM
|
||||||
|
do_pop_dynamic_state (void)
|
||||||
|
{
|
||||||
|
scm_i_thread *thread = SCM_I_CURRENT_THREAD;
|
||||||
|
scm_dynstack_unwind_dynamic_state (&thread->dynstack,
|
||||||
|
thread->dynamic_state);
|
||||||
|
return SCM_UNSPECIFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -482,6 +502,14 @@ memoize (SCM exp, SCM env)
|
||||||
else if (nargs == 0
|
else if (nargs == 0
|
||||||
&& scm_is_eq (name, scm_from_latin1_symbol ("pop-fluid")))
|
&& scm_is_eq (name, scm_from_latin1_symbol ("pop-fluid")))
|
||||||
return MAKMEMO_CALL (MAKMEMO_QUOTE (pop_fluid), SCM_EOL);
|
return MAKMEMO_CALL (MAKMEMO_QUOTE (pop_fluid), SCM_EOL);
|
||||||
|
else if (nargs == 1
|
||||||
|
&& scm_is_eq (name,
|
||||||
|
scm_from_latin1_symbol ("push-dynamic-state")))
|
||||||
|
return MAKMEMO_CALL (MAKMEMO_QUOTE (push_dynamic_state), args);
|
||||||
|
else if (nargs == 0
|
||||||
|
&& scm_is_eq (name,
|
||||||
|
scm_from_latin1_symbol ("pop-dynamic-state")))
|
||||||
|
return MAKMEMO_CALL (MAKMEMO_QUOTE (pop_dynamic_state), SCM_EOL);
|
||||||
else if (scm_is_eq (scm_current_module (), scm_the_root_module ()))
|
else if (scm_is_eq (scm_current_module (), scm_the_root_module ()))
|
||||||
return MAKMEMO_CALL (maybe_makmemo_capture_module
|
return MAKMEMO_CALL (maybe_makmemo_capture_module
|
||||||
(MAKMEMO_BOX_REF
|
(MAKMEMO_BOX_REF
|
||||||
|
@ -869,6 +897,10 @@ scm_init_memoize ()
|
||||||
unwind = scm_c_make_gsubr ("unwind", 0, 0, 0, do_unwind);
|
unwind = scm_c_make_gsubr ("unwind", 0, 0, 0, do_unwind);
|
||||||
push_fluid = scm_c_make_gsubr ("push-fluid", 2, 0, 0, do_push_fluid);
|
push_fluid = scm_c_make_gsubr ("push-fluid", 2, 0, 0, do_push_fluid);
|
||||||
pop_fluid = scm_c_make_gsubr ("pop-fluid", 0, 0, 0, do_pop_fluid);
|
pop_fluid = scm_c_make_gsubr ("pop-fluid", 0, 0, 0, do_pop_fluid);
|
||||||
|
push_dynamic_state = scm_c_make_gsubr ("push-dynamic_state", 1, 0, 0,
|
||||||
|
do_push_dynamic_state);
|
||||||
|
pop_dynamic_state = scm_c_make_gsubr ("pop-dynamic_state", 0, 0, 0,
|
||||||
|
do_pop_dynamic_state);
|
||||||
|
|
||||||
list_of_guile = scm_list_1 (scm_from_latin1_symbol ("guile"));
|
list_of_guile = scm_list_1 (scm_from_latin1_symbol ("guile"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3921,8 +3921,35 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
|
||||||
NEXT (0);
|
NEXT (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
VM_DEFINE_OP (185, unused_185, NULL, NOP)
|
/* push-dynamic-state state:24
|
||||||
VM_DEFINE_OP (186, unused_186, NULL, NOP)
|
*
|
||||||
|
* Save the current fluid bindings on the dynamic stack, and use STATE
|
||||||
|
* instead.
|
||||||
|
*/
|
||||||
|
VM_DEFINE_OP (185, push_dynamic_state, "push-dynamic-state", OP1 (X8_S24))
|
||||||
|
{
|
||||||
|
scm_t_uint32 state;
|
||||||
|
|
||||||
|
UNPACK_24 (op, state);
|
||||||
|
|
||||||
|
SYNC_IP ();
|
||||||
|
scm_dynstack_push_dynamic_state (&thread->dynstack, SP_REF (state),
|
||||||
|
thread->dynamic_state);
|
||||||
|
NEXT (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pop-dynamic-state _:24
|
||||||
|
*
|
||||||
|
* Restore the saved fluid bindings from the dynamic stack.
|
||||||
|
*/
|
||||||
|
VM_DEFINE_OP (186, pop_dynamic_state, "pop-dynamic-state", OP1 (X32))
|
||||||
|
{
|
||||||
|
SYNC_IP ();
|
||||||
|
scm_dynstack_unwind_dynamic_state (&thread->dynstack,
|
||||||
|
thread->dynamic_state);
|
||||||
|
NEXT (1);
|
||||||
|
}
|
||||||
|
|
||||||
VM_DEFINE_OP (187, unused_187, NULL, NOP)
|
VM_DEFINE_OP (187, unused_187, NULL, NOP)
|
||||||
VM_DEFINE_OP (188, unused_188, NULL, NOP)
|
VM_DEFINE_OP (188, unused_188, NULL, NOP)
|
||||||
VM_DEFINE_OP (189, unused_189, NULL, NOP)
|
VM_DEFINE_OP (189, unused_189, NULL, NOP)
|
||||||
|
|
|
@ -154,6 +154,15 @@ a-cont
|
||||||
((@@ primitive pop-fluid))
|
((@@ primitive pop-fluid))
|
||||||
(apply values vals))))
|
(apply values vals))))
|
||||||
|
|
||||||
|
(define (with-dynamic-state state thunk)
|
||||||
|
"Call @var{proc} while @var{state} is the current dynamic state object.
|
||||||
|
@var{thunk} must be a procedure of no arguments."
|
||||||
|
((@@ primitive push-dynamic-state) state)
|
||||||
|
(call-with-values thunk
|
||||||
|
(lambda vals
|
||||||
|
((@@ primitive pop-dynamic-state))
|
||||||
|
(apply values vals))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;; {Simple Debugging Tools}
|
;;; {Simple Debugging Tools}
|
||||||
|
|
|
@ -330,6 +330,10 @@
|
||||||
(emit-push-fluid asm (from-sp (slot fluid)) (from-sp (slot val))))
|
(emit-push-fluid asm (from-sp (slot fluid)) (from-sp (slot val))))
|
||||||
(($ $primcall 'pop-fluid ())
|
(($ $primcall 'pop-fluid ())
|
||||||
(emit-pop-fluid asm))
|
(emit-pop-fluid asm))
|
||||||
|
(($ $primcall 'push-dynamic-state (state))
|
||||||
|
(emit-push-dynamic-state asm (from-sp (slot state))))
|
||||||
|
(($ $primcall 'pop-dynamic-state ())
|
||||||
|
(emit-pop-dynamic-state asm))
|
||||||
(($ $primcall 'wind (winder unwinder))
|
(($ $primcall 'wind (winder unwinder))
|
||||||
(emit-wind asm (from-sp (slot winder)) (from-sp (slot unwinder))))
|
(emit-wind asm (from-sp (slot winder)) (from-sp (slot unwinder))))
|
||||||
(($ $primcall 'bv-u8-set! (bv idx val))
|
(($ $primcall 'bv-u8-set! (bv idx val))
|
||||||
|
|
|
@ -287,7 +287,9 @@ is or might be a read or a write to the same location as A."
|
||||||
((fluid-ref f) (&read-object &fluid) &type-check)
|
((fluid-ref f) (&read-object &fluid) &type-check)
|
||||||
((fluid-set! f v) (&write-object &fluid) &type-check)
|
((fluid-set! f v) (&write-object &fluid) &type-check)
|
||||||
((push-fluid f v) (&write-object &fluid) &type-check)
|
((push-fluid f v) (&write-object &fluid) &type-check)
|
||||||
((pop-fluid) (&write-object &fluid) &type-check))
|
((pop-fluid) (&write-object &fluid))
|
||||||
|
((push-dynamic-state state) (&write-object &fluid) &type-check)
|
||||||
|
((pop-dynamic-state) (&write-object &fluid)))
|
||||||
|
|
||||||
;; Threads. Calls cause &all-effects, which reflects the fact that any
|
;; Threads. Calls cause &all-effects, which reflects the fact that any
|
||||||
;; call can capture a partial continuation and reinstate it on another
|
;; call can capture a partial continuation and reinstate it on another
|
||||||
|
|
|
@ -558,7 +558,9 @@ minimum, and maximum."
|
||||||
((fluid-ref (&fluid 1)) &all-types)
|
((fluid-ref (&fluid 1)) &all-types)
|
||||||
((fluid-set! (&fluid 0 1) &all-types))
|
((fluid-set! (&fluid 0 1) &all-types))
|
||||||
((push-fluid (&fluid 0 1) &all-types))
|
((push-fluid (&fluid 0 1) &all-types))
|
||||||
((pop-fluid)))
|
((pop-fluid))
|
||||||
|
((push-dynamic-state &all-types))
|
||||||
|
((pop-dynamic-state)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -360,6 +360,14 @@ of an expression."
|
||||||
(($ <primcall> _ 'pop-fluid ())
|
(($ <primcall> _ 'pop-fluid ())
|
||||||
(logior (cause &fluid)))
|
(logior (cause &fluid)))
|
||||||
|
|
||||||
|
(($ <primcall> _ 'push-dynamic-state (state))
|
||||||
|
(logior (compute-effects state)
|
||||||
|
(cause &type-check)
|
||||||
|
(cause &fluid)))
|
||||||
|
|
||||||
|
(($ <primcall> _ 'pop-dynamic-state ())
|
||||||
|
(logior (cause &fluid)))
|
||||||
|
|
||||||
(($ <primcall> _ 'car (x))
|
(($ <primcall> _ 'car (x))
|
||||||
(logior (compute-effects x)
|
(logior (compute-effects x)
|
||||||
(cause &type-check)
|
(cause &type-check)
|
||||||
|
|
|
@ -1219,6 +1219,19 @@ top-level bindings from ENV and return the resulting expression."
|
||||||
(make-call src thunk '())
|
(make-call src thunk '())
|
||||||
(make-primcall src 'pop-fluid '()))))))))
|
(make-primcall src 'pop-fluid '()))))))))
|
||||||
|
|
||||||
|
(($ <primcall> src 'with-dynamic-state (state thunk))
|
||||||
|
(for-tail
|
||||||
|
(with-temporaries
|
||||||
|
src (list state thunk) 1 constant-expression?
|
||||||
|
(match-lambda
|
||||||
|
((state thunk)
|
||||||
|
(make-seq src
|
||||||
|
(make-primcall src 'push-dynamic-state (list state))
|
||||||
|
(make-begin0 src
|
||||||
|
(make-call src thunk '())
|
||||||
|
(make-primcall src 'pop-dynamic-state
|
||||||
|
'()))))))))
|
||||||
|
|
||||||
(($ <primcall> src 'values exps)
|
(($ <primcall> src 'values exps)
|
||||||
(cond
|
(cond
|
||||||
((null? exps)
|
((null? exps)
|
||||||
|
|
|
@ -84,7 +84,7 @@
|
||||||
|
|
||||||
current-module define!
|
current-module define!
|
||||||
|
|
||||||
current-thread fluid-ref fluid-set! with-fluid*
|
current-thread fluid-ref fluid-set! with-fluid* with-dynamic-state
|
||||||
|
|
||||||
call-with-prompt
|
call-with-prompt
|
||||||
abort-to-prompt* abort-to-prompt
|
abort-to-prompt* abort-to-prompt
|
||||||
|
|
|
@ -122,6 +122,8 @@
|
||||||
emit-unwind
|
emit-unwind
|
||||||
emit-push-fluid
|
emit-push-fluid
|
||||||
emit-pop-fluid
|
emit-pop-fluid
|
||||||
|
emit-push-dynamic-state
|
||||||
|
emit-pop-dynamic-state
|
||||||
emit-current-thread
|
emit-current-thread
|
||||||
emit-fluid-ref
|
emit-fluid-ref
|
||||||
emit-fluid-set!
|
emit-fluid-set!
|
||||||
|
|
|
@ -184,3 +184,80 @@
|
||||||
(catch #t
|
(catch #t
|
||||||
(lambda () (fluid-ref fluid))
|
(lambda () (fluid-ref fluid))
|
||||||
(lambda (key . args) #t)))))
|
(lambda (key . args) #t)))))
|
||||||
|
|
||||||
|
(with-test-prefix "dynamic states"
|
||||||
|
(pass-if "basics"
|
||||||
|
(dynamic-state? (current-dynamic-state)))
|
||||||
|
|
||||||
|
(pass-if "with a fluid (basic)"
|
||||||
|
(let ((fluid (make-fluid #f))
|
||||||
|
(state (current-dynamic-state)))
|
||||||
|
(with-dynamic-state
|
||||||
|
state
|
||||||
|
(lambda ()
|
||||||
|
(eqv? (fluid-ref fluid) #f)))))
|
||||||
|
|
||||||
|
(pass-if "with a fluid (set outer)"
|
||||||
|
(let ((fluid (make-fluid #f))
|
||||||
|
(state (current-dynamic-state)))
|
||||||
|
(fluid-set! fluid #t)
|
||||||
|
(and (with-dynamic-state
|
||||||
|
state
|
||||||
|
(lambda ()
|
||||||
|
(eqv? (fluid-ref fluid) #f)))
|
||||||
|
(eqv? (fluid-ref fluid) #t))))
|
||||||
|
|
||||||
|
(pass-if "with a fluid (set inner)"
|
||||||
|
(let ((fluid (make-fluid #f))
|
||||||
|
(state (current-dynamic-state)))
|
||||||
|
(and (with-dynamic-state
|
||||||
|
state
|
||||||
|
(lambda ()
|
||||||
|
(fluid-set! fluid #t)
|
||||||
|
(eqv? (fluid-ref fluid) #t)))
|
||||||
|
(eqv? (fluid-ref fluid) #f))))
|
||||||
|
|
||||||
|
(pass-if "dynstate captured (1)"
|
||||||
|
(let ((fluid (make-fluid #f))
|
||||||
|
(state (current-dynamic-state))
|
||||||
|
(tag (make-prompt-tag "hey")))
|
||||||
|
(let ((k (call-with-prompt tag
|
||||||
|
(lambda ()
|
||||||
|
(with-dynamic-state
|
||||||
|
state
|
||||||
|
(lambda ()
|
||||||
|
(abort-to-prompt tag)
|
||||||
|
(fluid-ref fluid))))
|
||||||
|
(lambda (k) k))))
|
||||||
|
(eqv? (k) #f))))
|
||||||
|
|
||||||
|
(pass-if "dynstate captured (2)"
|
||||||
|
(let ((fluid (make-fluid #f))
|
||||||
|
(state (current-dynamic-state))
|
||||||
|
(tag (make-prompt-tag "hey")))
|
||||||
|
(let ((k (call-with-prompt tag
|
||||||
|
(lambda ()
|
||||||
|
(with-dynamic-state
|
||||||
|
state
|
||||||
|
(lambda ()
|
||||||
|
(abort-to-prompt tag)
|
||||||
|
(fluid-ref fluid))))
|
||||||
|
(lambda (k) k))))
|
||||||
|
(fluid-set! fluid #t)
|
||||||
|
(eqv? (k) #f))))
|
||||||
|
|
||||||
|
(pass-if "dynstate captured (3)"
|
||||||
|
(let ((fluid (make-fluid #f))
|
||||||
|
(state (current-dynamic-state))
|
||||||
|
(tag (make-prompt-tag "hey")))
|
||||||
|
(let ((k (call-with-prompt tag
|
||||||
|
(lambda ()
|
||||||
|
(with-dynamic-state
|
||||||
|
state
|
||||||
|
(lambda ()
|
||||||
|
(fluid-set! fluid #t)
|
||||||
|
(abort-to-prompt tag)
|
||||||
|
(fluid-ref fluid))))
|
||||||
|
(lambda (k) k))))
|
||||||
|
(and (eqv? (fluid-ref fluid) #f)
|
||||||
|
(eqv? (k) #t))))))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue