open Polycell open FrCore include Common type input = Polycell.t Event.t type output = unit type 'a event = (input, 'a Event.t) sf type 'a behavior = (input, 'a) sf type time = Unique.id let time_context = Unique.create () type context = { mutable free_id: int; mutable sfs: (int * (input, output) sf) list; mutable locked: bool; queue: (context -> unit) Queue.t; } let lock_fun = ref ignore let unlock_fun = ref ignore let sync f a = !lock_fun (); let r = try f a with e -> !unlock_fun (); raise e in !unlock_fun (); r let enqueue c f = if not (sync (fun c -> let locked = c.locked in if locked then Queue.add f c.queue else c.locked <- true; locked) c) then begin f c; try while true do (sync (fun c -> try Queue.take c.queue with Queue.Empty -> c.locked <- false; raise Exit) c) c done with Exit -> () end let create_context () = { free_id = 0; sfs = []; queue = Queue.create (); locked = false } (* should this not be reentrant? *) let copy_context c = { c with free_id = c.free_id; queue = Queue.create (); locked = false } let _time_now = ref (Unique.gen time_context) let cycle context input = let time' = !_time_now in _time_now := Unique.gen time_context; context.sfs <- List.fold_left (fun sfs' (id, sf) -> let sf', _ = reactimate sf input in if is_constant sf then sfs' else (id, sf') :: sfs') [] context.sfs; _time_now := time' (* TODO: re-figure this stuff out *) let fix_stack = Stack.create () let fix_defer f arg = try f arg with Undefined_signal -> Stack.push (f, arg) fix_stack let fix_unwind () = try while not (Stack.is_empty fix_stack) do let f, arg = Stack.top fix_stack in (try f arg with Undefined_signal -> raise Exit); ignore (Stack.pop fix_stack) done with Exit -> () let memoize f = (* here we should use a stack that mirrors the reentrancy stack so that memoizations aren't lost *BUT* since events are only memoized when they occur, and behaviors remain the same, our memoizations aren't lost (this is of course assuming any changes in the subcontext don't overlap those of the parent) *) let memo = ref None in fun i -> match !memo with | Some (i', o) when i' =* i -> o | _ -> let o = f i in memo := Some (i, o); o let memoizeq f = let memo = ref None in fun i -> match !memo with | Some (i', o) when i' == i -> o | _ -> let o = f i in memo := Some (i, o); o let memoize_t f = let f = memoizeq (fun (i, t) -> f i) in fun i -> f (i, !_time_now) let never = never let now: unit event = now () let tag_e v e = e >>> arr (Event.tag v) let map_e f e = e >>> arr (Event.map (memoize_t f)) let filter_e f e = e >>> arr (Event.filter (memoize_t f)) let zip_e a b = (a &&& b) >>> arr2 Event.join let unzip_e e = e >>> arr (Event.map fst), e >>> arr (Event.map snd) let par_e l = par l >>> arr Event.cat let merge_e l = par l >>> arr (List.fold_left Event.lmerge Event.none) let snapshot_e s e = (s &&& e) >>> arr2 Event.get let once_e e = e >>> once let changes b = b >>> changes let changesq b = b >>> changesq let delta f b = b >>> delta (memoize_t f) let when_e b = b >>> edge () let edge_e b = b >>> FrCore.delta (fun a b -> if a = None then b else None) >>> arr Event.may let accum_e i e = e >>> arr (memoize_t (Event.map memoize_t)) >>> accum i let collect_e f i e = e >>> collect (memoize_t f) i let switch_e i e = (identity &&& e) >>> rswitch i let collapse_e b = (identity &&& b) >>> rcollapse let fix_e g f = let s = fix g f in fix_unwind (); s let may_e e = e >>> arr Event.may let snapshot_b b e = (b &&& e) >>> arr2 Event.tag let latch b e = (b &&& e) >>> latch let hold i e = e >>> hold i let gate_b b e = (b &&& e) >>> gate let track i b = b >>> track i let zip_b a b = a &&& b let unzip_b b = b >>> arr fst, b >>> arr snd let par_b = par let accum_b i e = hold i (accum_e i e) let collect_b f i e = hold i (collect_e f i e) let switch_b = switch_e let sswitch_b g f i e = (identity &&& e) >>> srswitch g f i let collapse_b = collapse_e let scollapse_b g i b = (identity &&& b) >>> srcollapse g i let fix_b = fix_e let lift0 a = constant a let lift1 f a = a >>> arr (memoize f) let lift2 f a b = (a &&& b) >>> arr (memoize (fun (a, b) -> f a b)) let lift3 f a b c = (a &&& b &&& c) >>> arr (memoize (fun ((a, b), c) -> f a b c)) let lift1q f a = a >>> arr (memoizeq f) let lift2q f a b = (a &&& b) >>> arr (memoizeq (fun (a, b) -> f a b)) let lift3q f a b c = (a &&& b &&& c) >>> arr (memoizeq (fun ((a, b), c) -> f a b c)) type 'a event_receiver = 'a -> Polycell.t type 'a cell = 'a event_receiver let event_receiver () = let id = gen_id () and unreachable = ref false in (* if our receiver is unreachable, then we can go constant *) let finalise_receiver _ = unreachable := true in let receiver = box id in Gc.finalise finalise_receiver receiver; let signal = const_arr (fun i -> (* make sure the event doesn't get stuck in the "occuring" state * not sure if this is actually possible, but better to be safe *) !unreachable && i = Event.none, Event.map_filter (unbox id) i) in receiver, signal let send_event_in context r v = enqueue context (fun context -> cycle context (Event.return (r v))) let new_cell i = let r, e = event_receiver () in r, hold i e let set_cell_in = send_event_in let event_source start stop = let id = gen_id () and handle = ref None in (* if our signal is unreachable, then we can stop the sender NOTE: can be stronger: unreachable -> not in context *) let finalise_signal _ = match !handle with Some h -> stop h; handle := None | None -> () in let receiver = box id in let signal = arr (fun i -> (* we're being used; make sure our sender is active *) if !handle = None then handle := Some (start receiver); Event.map_filter (unbox id) i) in Gc.finalise finalise_signal signal; signal let behavior_source force start stop = let id = gen_id () and handle = ref None in (* if our signal is unreachable, then we can stop the sender NOTE: can be stronger: unreachable -> not in context *) let finalise_signal _ = match !handle with Some h -> stop h; handle := None | None -> () in let receiver = box id in let signal = arr (fun i -> (* we're being used; make sure our sender is active *) if !handle = None then begin (* our sender is inactive, so we shouldn't be seeing any input *) assert (Event.map_filter (unbox id) i = Event.none); handle := Some (start receiver); Event.return (force ()) end else Event.map_filter (unbox id) i) in Gc.finalise finalise_signal signal; (* is there a way we can do this without needing a force () here? *) hold (force ()) signal type simple_endpoint = int let gen_handler_id context = let id = context.free_id in context.free_id <- context.free_id + 1; id let register_e_in context sf = let id = sync gen_handler_id context in enqueue context (fun context -> (* NOT constant (), or it will be consted *) let sf = sf >>> arr ignore in fix_defer (fun () -> let sf', _ = reactimate sf Event.none in if not (is_constant sf) then context.sfs <- (id, sf') :: context.sfs) ()); id let register_b_in = register_e_in let unregister_in context id = enqueue context (fun context -> context.sfs <- List.remove_assoc id context.sfs) module Mixed = struct type 'a t = { behavior: 'a behavior; event: 'a event; } let construct b e = { behavior = b; event = e } let of_event e = { behavior = lift0 None; event = map_e some e; } let of_behavior b = { behavior = b; event = never; } let with_event m e = { m with event = e } let with_behavior m b = { m with behavior = b } let behavior_part m = m.behavior let event_part m = m.event let destruct m = m.behavior, m.event let nothing = { behavior = lift0 None; event = never } let map f m = { behavior = lift1 f m.behavior; event = map_e f m.event; } let zip a b = { behavior = zip_b a.behavior b.behavior; event = merge_e [ zip_e a.event b.event; zip_e a.event (snapshot_b b.behavior a.event); zip_e (snapshot_b a.behavior b.event) b.event ] } let merge f a b = map (uncurry2 f) (zip a b) let snapshot m e = merge_e [map_e fst (zip_e m.event e); snapshot_b m.behavior e] let unzip m = let ab, bb = unzip_b m.behavior and ae, be = unzip_e m.event in { behavior = ab; event = ae }, { behavior = bb; event = be } let par l = { behavior = par_b (List.map behavior_part l); event = par_e (List.map event_part l); } let may i m = { behavior = track i m.behavior; event = may_e m.event; } let switch i e = { behavior = switch_b i.behavior (map_e behavior_part e); event = switch_e i.event (map_e event_part e); } let collapse b = { behavior = collapse_b (lift1 behavior_part b); event = collapse_e (lift1 event_part b); } let meta m = { behavior = collapse_b (lift1 behavior_part m.behavior); event = merge_e [ may_e (snapshot (switch nothing (map_e (map some) m.event)) m.event); collapse_e (lift1 event_part m.behavior) ] } let fix g f = FrCore.fix (fun a -> let m = g a in m.behavior &&& m.event) (fun s -> f { behavior = s >>> arr fst; event = s >>> arr snd }) end type 'a mixed = 'a Mixed.t