Collapse reactive islands into scopes: replace TrackingContext and *island-scope* with scope-push!/scope-pop!/context
Reactive tracking (deref/computed/effect dep discovery) and island lifecycle now use the general scoped effects system instead of parallel infrastructure. Two scope names: "sx-reactive" for tracking context, "sx-island-scope" for island disposable collection. Eliminates ~98 net lines: _TrackingContext class, 7 tracking context platform functions (Python + JS), *island-scope* global, and corresponding RENAME_MAP entries. All 20 signal tests pass (17 original + 3 new scope integration tests), plus CEK/continuation/type tests clean. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -440,17 +440,6 @@ class _Signal:
|
||||
self.deps = []
|
||||
|
||||
|
||||
class _TrackingContext:
|
||||
"""Context for discovering signal dependencies."""
|
||||
__slots__ = ("notify_fn", "deps")
|
||||
def __init__(self, notify_fn):
|
||||
self.notify_fn = notify_fn
|
||||
self.deps = []
|
||||
|
||||
|
||||
_tracking_context = None
|
||||
|
||||
|
||||
def make_signal(value):
|
||||
return _Signal(value)
|
||||
|
||||
@@ -491,33 +480,6 @@ def signal_set_deps(s, deps):
|
||||
s.deps = list(deps) if isinstance(deps, list) else []
|
||||
|
||||
|
||||
def set_tracking_context(ctx):
|
||||
global _tracking_context
|
||||
_tracking_context = ctx
|
||||
|
||||
|
||||
def get_tracking_context():
|
||||
global _tracking_context
|
||||
return _tracking_context if _tracking_context is not None else NIL
|
||||
|
||||
|
||||
def make_tracking_context(notify_fn):
|
||||
return _TrackingContext(notify_fn)
|
||||
|
||||
|
||||
def tracking_context_deps(ctx):
|
||||
return ctx.deps if isinstance(ctx, _TrackingContext) else []
|
||||
|
||||
|
||||
def tracking_context_add_dep(ctx, s):
|
||||
if isinstance(ctx, _TrackingContext) and s not in ctx.deps:
|
||||
ctx.deps.append(s)
|
||||
|
||||
|
||||
def tracking_context_notify_fn(ctx):
|
||||
return ctx.notify_fn if isinstance(ctx, _TrackingContext) else NIL
|
||||
|
||||
|
||||
def invoke(f, *args):
|
||||
"""Call f with args — handles both native callables and SX lambdas.
|
||||
|
||||
@@ -3503,10 +3465,13 @@ def deref(s):
|
||||
if sx_truthy((not sx_truthy(is_signal(s)))):
|
||||
return s
|
||||
else:
|
||||
ctx = get_tracking_context()
|
||||
ctx = sx_context('sx-reactive', NIL)
|
||||
if sx_truthy(ctx):
|
||||
tracking_context_add_dep(ctx, s)
|
||||
signal_add_sub(s, tracking_context_notify_fn(ctx))
|
||||
dep_list = get(ctx, 'deps')
|
||||
notify_fn = get(ctx, 'notify')
|
||||
if sx_truthy((not sx_truthy(contains_p(dep_list, s)))):
|
||||
dep_list.append(s)
|
||||
signal_add_sub(s, notify_fn)
|
||||
return signal_value(s)
|
||||
|
||||
# reset!
|
||||
@@ -3538,7 +3503,7 @@ def computed(compute_fn):
|
||||
recompute = _sx_fn(lambda : (
|
||||
for_each(lambda dep: signal_remove_sub(dep, recompute), signal_deps(s)),
|
||||
signal_set_deps(s, []),
|
||||
(lambda ctx: (lambda prev: _sx_begin(set_tracking_context(ctx), (lambda new_val: _sx_begin(set_tracking_context(prev), signal_set_deps(s, tracking_context_deps(ctx)), (lambda old: _sx_begin(signal_set_value(s, new_val), (notify_subscribers(s) if sx_truthy((not sx_truthy(is_identical(old, new_val)))) else NIL)))(signal_value(s))))(invoke(compute_fn))))(get_tracking_context()))(make_tracking_context(recompute))
|
||||
(lambda ctx: _sx_begin(scope_push('sx-reactive', ctx), (lambda new_val: _sx_begin(scope_pop('sx-reactive'), signal_set_deps(s, get(ctx, 'deps')), (lambda old: _sx_begin(signal_set_value(s, new_val), (notify_subscribers(s) if sx_truthy((not sx_truthy(is_identical(old, new_val)))) else NIL)))(signal_value(s))))(invoke(compute_fn))))({'deps': [], 'notify': recompute})
|
||||
)[-1])
|
||||
recompute()
|
||||
register_in_scope(lambda : dispose_computed(s))
|
||||
@@ -3550,7 +3515,7 @@ def effect(effect_fn):
|
||||
_cells['deps'] = []
|
||||
_cells['disposed'] = False
|
||||
_cells['cleanup_fn'] = NIL
|
||||
run_effect = lambda : (_sx_begin((invoke(_cells['cleanup_fn']) if sx_truthy(_cells['cleanup_fn']) else NIL), for_each(lambda dep: signal_remove_sub(dep, run_effect), _cells['deps']), _sx_cell_set(_cells, 'deps', []), (lambda ctx: (lambda prev: _sx_begin(set_tracking_context(ctx), (lambda result: _sx_begin(set_tracking_context(prev), _sx_cell_set(_cells, 'deps', tracking_context_deps(ctx)), (_sx_cell_set(_cells, 'cleanup_fn', result) if sx_truthy(is_callable(result)) else NIL)))(invoke(effect_fn))))(get_tracking_context()))(make_tracking_context(run_effect))) if sx_truthy((not sx_truthy(_cells['disposed']))) else NIL)
|
||||
run_effect = lambda : (_sx_begin((invoke(_cells['cleanup_fn']) if sx_truthy(_cells['cleanup_fn']) else NIL), for_each(lambda dep: signal_remove_sub(dep, run_effect), _cells['deps']), _sx_cell_set(_cells, 'deps', []), (lambda ctx: _sx_begin(scope_push('sx-reactive', ctx), (lambda result: _sx_begin(scope_pop('sx-reactive'), _sx_cell_set(_cells, 'deps', get(ctx, 'deps')), (_sx_cell_set(_cells, 'cleanup_fn', result) if sx_truthy(is_callable(result)) else NIL)))(invoke(effect_fn))))({'deps': [], 'notify': run_effect})) if sx_truthy((not sx_truthy(_cells['disposed']))) else NIL)
|
||||
run_effect()
|
||||
dispose_fn = _sx_fn(lambda : (
|
||||
_sx_cell_set(_cells, 'disposed', True),
|
||||
@@ -3610,21 +3575,18 @@ def dispose_computed(s):
|
||||
return signal_set_deps(s, [])
|
||||
return NIL
|
||||
|
||||
# *island-scope*
|
||||
_island_scope = NIL
|
||||
|
||||
# with-island-scope
|
||||
def with_island_scope(scope_fn, body_fn):
|
||||
prev = _island_scope
|
||||
_island_scope = scope_fn
|
||||
scope_push('sx-island-scope', scope_fn)
|
||||
result = body_fn()
|
||||
_island_scope = prev
|
||||
scope_pop('sx-island-scope')
|
||||
return result
|
||||
|
||||
# register-in-scope
|
||||
def register_in_scope(disposable):
|
||||
if sx_truthy(_island_scope):
|
||||
return _island_scope(disposable)
|
||||
collector = sx_context('sx-island-scope', NIL)
|
||||
if sx_truthy(collector):
|
||||
return invoke(collector, disposable)
|
||||
return NIL
|
||||
|
||||
# with-marsh-scope
|
||||
|
||||
Reference in New Issue
Block a user