Register append! and dict-set! as proper primitives
Previously these mutating operations were internal helpers in the JS bootstrapper but not declared in primitives.sx or registered in the Python evaluator. Now properly specced and available in both hosts. Removes mock injections from cache tests — they use real primitives. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
// =========================================================================
|
||||
|
||||
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
||||
var SX_VERSION = "2026-03-07T00:04:07Z";
|
||||
var SX_VERSION = "2026-03-07T00:20:00Z";
|
||||
|
||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||
@@ -177,7 +177,8 @@
|
||||
function envExtend(env) { return merge(env); }
|
||||
function envMerge(base, overlay) { return merge(base, overlay); }
|
||||
|
||||
function dictSet(d, k, v) { d[k] = v; }
|
||||
function dictSet(d, k, v) { d[k] = v; return v; }
|
||||
PRIMITIVES["dict-set!"] = dictSet;
|
||||
function dictGet(d, k) { var v = d[k]; return v !== undefined ? v : NIL; }
|
||||
|
||||
// Render-expression detection — lets the evaluator delegate to the active adapter.
|
||||
@@ -452,6 +453,7 @@
|
||||
var range = PRIMITIVES["range"];
|
||||
function zip(a, b) { var r = []; for (var i = 0; i < Math.min(a.length, b.length); i++) r.push([a[i], b[i]]); return r; }
|
||||
function append_b(arr, x) { arr.push(x); return arr; }
|
||||
PRIMITIVES["append!"] = append_b;
|
||||
var apply = function(f, args) { return f.apply(null, args); };
|
||||
|
||||
// Additional primitive aliases used by adapter/engine transpiled code
|
||||
|
||||
@@ -386,6 +386,11 @@ def prim_cons(x: Any, coll: Any) -> list:
|
||||
def prim_append(coll: Any, x: Any) -> list:
|
||||
return list(coll) + [x] if coll else [x]
|
||||
|
||||
@register_primitive("append!")
|
||||
def prim_append_mut(coll: Any, x: Any) -> list:
|
||||
coll.append(x)
|
||||
return coll
|
||||
|
||||
@register_primitive("chunk-every")
|
||||
def prim_chunk_every(coll: Any, n: Any) -> list:
|
||||
n = int(n)
|
||||
@@ -439,6 +444,13 @@ def prim_dissoc(d: Any, *keys_to_remove: Any) -> dict:
|
||||
result.pop(key, None)
|
||||
return result
|
||||
|
||||
@register_primitive("dict-set!")
|
||||
def prim_dict_set_mut(d: Any, key: Any, val: Any) -> Any:
|
||||
if isinstance(key, Keyword):
|
||||
key = key.name
|
||||
d[key] = val
|
||||
return val
|
||||
|
||||
@register_primitive("into")
|
||||
def prim_into(target: Any, coll: Any) -> Any:
|
||||
if isinstance(target, list):
|
||||
|
||||
@@ -1711,7 +1711,8 @@ PLATFORM_JS_PRE = '''
|
||||
function envExtend(env) { return merge(env); }
|
||||
function envMerge(base, overlay) { return merge(base, overlay); }
|
||||
|
||||
function dictSet(d, k, v) { d[k] = v; }
|
||||
function dictSet(d, k, v) { d[k] = v; return v; }
|
||||
PRIMITIVES["dict-set!"] = dictSet;
|
||||
function dictGet(d, k) { var v = d[k]; return v !== undefined ? v : NIL; }
|
||||
|
||||
// Render-expression detection — lets the evaluator delegate to the active adapter.
|
||||
@@ -1791,6 +1792,7 @@ PLATFORM_JS_POST = '''
|
||||
var range = PRIMITIVES["range"];
|
||||
function zip(a, b) { var r = []; for (var i = 0; i < Math.min(a.length, b.length); i++) r.push([a[i], b[i]]); return r; }
|
||||
function append_b(arr, x) { arr.push(x); return arr; }
|
||||
PRIMITIVES["append!"] = append_b;
|
||||
var apply = function(f, args) { return f.apply(null, args); };
|
||||
|
||||
// Additional primitive aliases used by adapter/engine transpiled code
|
||||
|
||||
@@ -384,6 +384,11 @@
|
||||
:returns "list"
|
||||
:doc "Append x to end of coll (returns new list).")
|
||||
|
||||
(define-primitive "append!"
|
||||
:params (coll x)
|
||||
:returns "list"
|
||||
:doc "Mutate coll by appending x in-place. Returns coll.")
|
||||
|
||||
(define-primitive "chunk-every"
|
||||
:params (coll n)
|
||||
:returns "list"
|
||||
@@ -426,6 +431,11 @@
|
||||
:returns "dict"
|
||||
:doc "Return new dict with keys removed.")
|
||||
|
||||
(define-primitive "dict-set!"
|
||||
:params (d key val)
|
||||
:returns "any"
|
||||
:doc "Mutate dict d by setting key to val in-place. Returns val.")
|
||||
|
||||
(define-primitive "into"
|
||||
:params (target coll)
|
||||
:returns "any"
|
||||
|
||||
@@ -305,16 +305,6 @@ class TestDataCache:
|
||||
self._time = current_time_ms
|
||||
env["now-ms"] = lambda: self._time
|
||||
|
||||
# Mutating primitives needed by cache (available in JS, not bare Python)
|
||||
def _dict_set(d, k, v):
|
||||
d[k] = v
|
||||
return v
|
||||
def _append_b(lst, item):
|
||||
lst.append(item)
|
||||
return lst
|
||||
env["dict-set!"] = _dict_set
|
||||
env["append!"] = _append_b
|
||||
|
||||
# Define the cache functions from orchestration.sx
|
||||
cache_src = """
|
||||
(define _page-data-cache (dict))
|
||||
|
||||
Reference in New Issue
Block a user