Unify scoped effects: scope as general primitive, provide as sugar
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 12m54s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 12m54s
- Add `scope` special form to eval.sx: (scope name body...) or (scope name :value v body...) — general dynamic scope primitive - `provide` becomes sugar: (provide name value body...) calls scope - Rename provide-push!/provide-pop! to scope-push!/scope-pop! throughout all adapters (async, dom, html, sx) and platform implementations - Update boundary.sx: Tier 5 now "Scoped effects" with scope-push!/ scope-pop! as primary, provide-push!/provide-pop! as aliases - Add scope form handling to async adapter and aser wire format - Update sx-browser.js, sx_ref.py (bootstrapped output) - Add scopes.sx docs page, update provide/spreads/demo docs - Update nav-data, page-functions, docs page definitions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -883,8 +883,7 @@ PREAMBLE = '''\
|
||||
function SxSpread(attrs) { this.attrs = attrs || {}; }
|
||||
SxSpread.prototype._spread = true;
|
||||
|
||||
var _collectBuckets = {};
|
||||
var _provideStacks = {};
|
||||
var _scopeStacks = {};
|
||||
|
||||
function isSym(x) { return x != null && x._sym === true; }
|
||||
function isKw(x) { return x != null && x._kw === true; }
|
||||
@@ -1098,14 +1097,17 @@ PRIMITIVES_JS_MODULES: dict[str, str] = {
|
||||
''',
|
||||
|
||||
"stdlib.spread": '''
|
||||
// stdlib.spread — spread + collect primitives
|
||||
// stdlib.spread — spread + collect + scope primitives
|
||||
PRIMITIVES["make-spread"] = makeSpread;
|
||||
PRIMITIVES["spread?"] = isSpread;
|
||||
PRIMITIVES["spread-attrs"] = spreadAttrs;
|
||||
PRIMITIVES["collect!"] = sxCollect;
|
||||
PRIMITIVES["collected"] = sxCollected;
|
||||
PRIMITIVES["clear-collected!"] = sxClearCollected;
|
||||
// provide/context/emit! — render-time dynamic scope
|
||||
// scope — unified render-time dynamic scope
|
||||
PRIMITIVES["scope-push!"] = scopePush;
|
||||
PRIMITIVES["scope-pop!"] = scopePop;
|
||||
// provide-push!/provide-pop! — aliases for scope-push!/scope-pop!
|
||||
PRIMITIVES["provide-push!"] = providePush;
|
||||
PRIMITIVES["provide-pop!"] = providePop;
|
||||
PRIMITIVES["context"] = sxContext;
|
||||
@@ -1174,44 +1176,54 @@ PLATFORM_JS_PRE = '''
|
||||
function isSpread(x) { return x != null && x._spread === true; }
|
||||
function spreadAttrs(s) { return s && s._spread ? s.attrs : {}; }
|
||||
|
||||
function sxCollect(bucket, value) {
|
||||
if (!_collectBuckets[bucket]) _collectBuckets[bucket] = [];
|
||||
var items = _collectBuckets[bucket];
|
||||
if (items.indexOf(value) === -1) items.push(value);
|
||||
function scopePush(name, value) {
|
||||
if (!_scopeStacks[name]) _scopeStacks[name] = [];
|
||||
_scopeStacks[name].push({value: value !== undefined ? value : NIL, emitted: [], dedup: false});
|
||||
}
|
||||
function sxCollected(bucket) {
|
||||
return _collectBuckets[bucket] ? _collectBuckets[bucket].slice() : [];
|
||||
}
|
||||
function sxClearCollected(bucket) {
|
||||
if (_collectBuckets[bucket]) _collectBuckets[bucket] = [];
|
||||
function scopePop(name) {
|
||||
if (_scopeStacks[name] && _scopeStacks[name].length) _scopeStacks[name].pop();
|
||||
}
|
||||
// Aliases — provide-push!/provide-pop! map to scope-push!/scope-pop!
|
||||
var providePush = scopePush;
|
||||
var providePop = scopePop;
|
||||
|
||||
function providePush(name, value) {
|
||||
if (!_provideStacks[name]) _provideStacks[name] = [];
|
||||
_provideStacks[name].push({value: value !== undefined ? value : NIL, emitted: []});
|
||||
}
|
||||
function providePop(name) {
|
||||
if (_provideStacks[name] && _provideStacks[name].length) _provideStacks[name].pop();
|
||||
}
|
||||
function sxContext(name) {
|
||||
if (_provideStacks[name] && _provideStacks[name].length) {
|
||||
return _provideStacks[name][_provideStacks[name].length - 1].value;
|
||||
if (_scopeStacks[name] && _scopeStacks[name].length) {
|
||||
return _scopeStacks[name][_scopeStacks[name].length - 1].value;
|
||||
}
|
||||
if (arguments.length > 1) return arguments[1];
|
||||
throw new Error("No provider for: " + name);
|
||||
}
|
||||
function sxEmit(name, value) {
|
||||
if (_provideStacks[name] && _provideStacks[name].length) {
|
||||
_provideStacks[name][_provideStacks[name].length - 1].emitted.push(value);
|
||||
if (_scopeStacks[name] && _scopeStacks[name].length) {
|
||||
var entry = _scopeStacks[name][_scopeStacks[name].length - 1];
|
||||
if (entry.dedup && entry.emitted.indexOf(value) !== -1) return NIL;
|
||||
entry.emitted.push(value);
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
function sxEmitted(name) {
|
||||
if (_provideStacks[name] && _provideStacks[name].length) {
|
||||
return _provideStacks[name][_provideStacks[name].length - 1].emitted.slice();
|
||||
if (_scopeStacks[name] && _scopeStacks[name].length) {
|
||||
return _scopeStacks[name][_scopeStacks[name].length - 1].emitted.slice();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
function sxCollect(bucket, value) {
|
||||
if (!_scopeStacks[bucket] || !_scopeStacks[bucket].length) {
|
||||
if (!_scopeStacks[bucket]) _scopeStacks[bucket] = [];
|
||||
_scopeStacks[bucket].push({value: NIL, emitted: [], dedup: true});
|
||||
}
|
||||
var entry = _scopeStacks[bucket][_scopeStacks[bucket].length - 1];
|
||||
if (entry.emitted.indexOf(value) === -1) entry.emitted.push(value);
|
||||
}
|
||||
function sxCollected(bucket) {
|
||||
return sxEmitted(bucket);
|
||||
}
|
||||
function sxClearCollected(bucket) {
|
||||
if (_scopeStacks[bucket] && _scopeStacks[bucket].length) {
|
||||
_scopeStacks[bucket][_scopeStacks[bucket].length - 1].emitted = [];
|
||||
}
|
||||
}
|
||||
|
||||
function lambdaParams(f) { return f.params; }
|
||||
function lambdaBody(f) { return f.body; }
|
||||
@@ -3244,6 +3256,8 @@ def public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, has_boot, has
|
||||
api_lines.append(' collect: sxCollect,')
|
||||
api_lines.append(' collected: sxCollected,')
|
||||
api_lines.append(' clearCollected: sxClearCollected,')
|
||||
api_lines.append(' scopePush: scopePush,')
|
||||
api_lines.append(' scopePop: scopePop,')
|
||||
api_lines.append(' providePush: providePush,')
|
||||
api_lines.append(' providePop: providePop,')
|
||||
api_lines.append(' context: sxContext,')
|
||||
|
||||
Reference in New Issue
Block a user