Add Freeze/Thaw page under CEK Machine with live demo
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled

Documents and demonstrates serializable CEK state. Type an expression,
step to any point, click Freeze to see the frozen SX. Click Thaw to
resume from the frozen state and get the result.

- New page at /sx/(geography.(cek.freeze))
- Nav entry under CEK Machine
- Interactive island demo with step/run/freeze/thaw buttons
- Documentation: the idea, freeze format, thaw/resume, what it enables

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-14 22:14:33 +00:00
parent b03c84b962
commit a759f4da3b
8 changed files with 203 additions and 20 deletions

View File

@@ -14,7 +14,7 @@
// =========================================================================
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
var SX_VERSION = "2026-03-14T22:10:44Z";
var SX_VERSION = "2026-03-14T22:31:34Z";
function isNil(x) { return x === NIL || x === null || x === undefined; }
function isSxTruthy(x) { return x !== false && !isNil(x); }
@@ -352,6 +352,8 @@
PRIMITIVES["even?"] = function(n) { return n % 2 === 0; };
PRIMITIVES["zero?"] = function(n) { return n === 0; };
PRIMITIVES["boolean?"] = function(x) { return x === true || x === false; };
PRIMITIVES["symbol?"] = function(x) { return x != null && x._sym === true; };
PRIMITIVES["keyword?"] = function(x) { return x != null && x._kw === true; };
PRIMITIVES["component-affinity"] = componentAffinity;
@@ -525,7 +527,14 @@
function mapDict(fn, d) { var r = {}; for (var k in d) r[k] = fn(k, d[k]); return r; }
// Predicate aliases used by transpiled code
// Both naming conventions: isX (from js-renames) and x_p (from js-mangle of x?)
var isNumber = PRIMITIVES["number?"]; var number_p = isNumber;
var isString = PRIMITIVES["string?"]; var string_p = isString;
var isBoolean = PRIMITIVES["boolean?"]; var boolean_p = isBoolean;
var isDict = PRIMITIVES["dict?"];
var isList = PRIMITIVES["list?"]; var list_p = isList;
var isKeyword = PRIMITIVES["keyword?"]; var keyword_p = isKeyword;
var isSymbol = PRIMITIVES["symbol?"]; var symbol_p = isSymbol;
// List primitives used directly by transpiled code
var len = PRIMITIVES["len"];
@@ -5295,7 +5304,7 @@ PRIMITIVES["trampoline-cek"] = trampolineCek;
PRIMITIVES["primitive-name"] = primitiveName;
// cek-serialize-value
var cekSerializeValue = function(val) { return (isSxTruthy(isNil(val)) ? NIL : (isSxTruthy(isNumber(val)) ? val : (isSxTruthy(isString(val)) ? val : (isSxTruthy((typeOf(val) == "boolean")) ? val : (isSxTruthy((typeOf(val) == "symbol")) ? val : (isSxTruthy((typeOf(val) == "keyword")) ? val : (isSxTruthy(isList(val)) ? map(cekSerializeValue, val) : (isSxTruthy(isLambda(val)) ? [makeSymbol("lambda"), lambdaParams(val), lambdaBody(val)] : (isSxTruthy(isCallable(val)) ? [makeSymbol("primitive"), sxOr(primitiveName(val), "?")] : (isSxTruthy(isDict(val)) ? cekSerializeEnv(val) : (String(val)))))))))))); };
var cekSerializeValue = function(val) { return (isSxTruthy(isNil(val)) ? NIL : (isSxTruthy(isNumber(val)) ? val : (isSxTruthy(isString(val)) ? val : (isSxTruthy(boolean_p(val)) ? val : (isSxTruthy(symbol_p(val)) ? val : (isSxTruthy(keyword_p(val)) ? val : (isSxTruthy(isList(val)) ? map(cekSerializeValue, val) : (isSxTruthy(isLambda(val)) ? [makeSymbol("lambda"), lambdaParams(val), lambdaBody(val)] : (isSxTruthy(isCallable(val)) ? [makeSymbol("primitive"), sxOr(primitiveName(val), "?")] : (isSxTruthy(isDict(val)) ? cekSerializeEnv(val) : (String(val)))))))))))); };
PRIMITIVES["cek-serialize-value"] = cekSerializeValue;
// cek-serialize-env
@@ -5324,7 +5333,7 @@ PRIMITIVES["cek-serialize-frame"] = cekSerializeFrame;
PRIMITIVES["cek-freeze"] = cekFreeze;
// cek-thaw-value
var cekThawValue = function(val) { return (isSxTruthy(isNil(val)) ? NIL : (isSxTruthy(isNumber(val)) ? val : (isSxTruthy(isString(val)) ? val : (isSxTruthy((typeOf(val) == "boolean")) ? val : (isSxTruthy((typeOf(val) == "symbol")) ? val : (isSxTruthy((typeOf(val) == "keyword")) ? val : (isSxTruthy((isSxTruthy(isList(val)) && isSxTruthy(!isSxTruthy(isEmpty(val))) && isSxTruthy((typeOf(first(val)) == "symbol")) && (symbolName(first(val)) == "primitive"))) ? getPrimitive(nth(val, 1)) : (isSxTruthy((isSxTruthy(isList(val)) && isSxTruthy(!isSxTruthy(isEmpty(val))) && isSxTruthy((typeOf(first(val)) == "symbol")) && (symbolName(first(val)) == "lambda"))) ? makeLambda(nth(val, 1), nth(val, 2), {}) : (isSxTruthy(isList(val)) ? map(cekThawValue, val) : (isSxTruthy(isDict(val)) ? cekThawEnv(val) : val)))))))))); };
var cekThawValue = function(val) { return (isSxTruthy(isNil(val)) ? NIL : (isSxTruthy(isNumber(val)) ? val : (isSxTruthy(isString(val)) ? val : (isSxTruthy(boolean_p(val)) ? val : (isSxTruthy(symbol_p(val)) ? val : (isSxTruthy(keyword_p(val)) ? val : (isSxTruthy((isSxTruthy(isList(val)) && isSxTruthy(!isSxTruthy(isEmpty(val))) && isSxTruthy(symbol_p(first(val))) && (symbolName(first(val)) == "primitive"))) ? getPrimitive(nth(val, 1)) : (isSxTruthy((isSxTruthy(isList(val)) && isSxTruthy(!isSxTruthy(isEmpty(val))) && isSxTruthy(symbol_p(first(val))) && (symbolName(first(val)) == "lambda"))) ? makeLambda(nth(val, 1), nth(val, 2), {}) : (isSxTruthy(isList(val)) ? map(cekThawValue, val) : (isSxTruthy(isDict(val)) ? cekThawEnv(val) : val)))))))))); };
PRIMITIVES["cek-thaw-value"] = cekThawValue;
// cek-thaw-env

View File

@@ -1074,9 +1074,9 @@
(nil? val) nil
(number? val) val
(string? val) val
(= (type-of val) "boolean") val
(= (type-of val) "symbol") val
(= (type-of val) "keyword") val
(boolean? val) val
(symbol? val) val
(keyword? val) val
(list? val) (map cek-serialize-value val)
(lambda? val) (list (make-symbol "lambda")
(lambda-params val)
@@ -1137,17 +1137,17 @@
(nil? val) nil
(number? val) val
(string? val) val
(= (type-of val) "boolean") val
(= (type-of val) "symbol") val
(= (type-of val) "keyword") val
(boolean? val) val
(symbol? val) val
(keyword? val) val
;; (primitive "name") → look up native function
(and (list? val) (not (empty? val))
(= (type-of (first val)) "symbol")
(symbol? (first val))
(= (symbol-name (first val)) "primitive"))
(get-primitive (nth val 1))
;; (lambda (params) body) → reconstruct Lambda
(and (list? val) (not (empty? val))
(= (type-of (first val)) "symbol")
(symbol? (first val))
(= (symbol-name (first val)) "lambda"))
(make-lambda (nth val 1) (nth val 2) (dict))
(list? val) (map cek-thaw-value val)

View File

@@ -951,6 +951,8 @@ PRIMITIVES_JS_MODULES: dict[str, str] = {
PRIMITIVES["even?"] = function(n) { return n % 2 === 0; };
PRIMITIVES["zero?"] = function(n) { return n === 0; };
PRIMITIVES["boolean?"] = function(x) { return x === true || x === false; };
PRIMITIVES["symbol?"] = function(x) { return x != null && x._sym === true; };
PRIMITIVES["keyword?"] = function(x) { return x != null && x._kw === true; };
PRIMITIVES["component-affinity"] = componentAffinity;
''',
@@ -1353,7 +1355,14 @@ PLATFORM_JS_POST = '''
function mapDict(fn, d) { var r = {}; for (var k in d) r[k] = fn(k, d[k]); return r; }
// Predicate aliases used by transpiled code
// Both naming conventions: isX (from js-renames) and x_p (from js-mangle of x?)
var isNumber = PRIMITIVES["number?"]; var number_p = isNumber;
var isString = PRIMITIVES["string?"]; var string_p = isString;
var isBoolean = PRIMITIVES["boolean?"]; var boolean_p = isBoolean;
var isDict = PRIMITIVES["dict?"];
var isList = PRIMITIVES["list?"]; var list_p = isList;
var isKeyword = PRIMITIVES["keyword?"]; var keyword_p = isKeyword;
var isSymbol = PRIMITIVES["symbol?"]; var symbol_p = isSymbol;
// List primitives used directly by transpiled code
var len = PRIMITIVES["len"];

View File

@@ -721,6 +721,9 @@ PRIMITIVES["number?"] = lambda x: isinstance(x, (int, float)) and not isinstance
PRIMITIVES["string?"] = lambda x: isinstance(x, str)
PRIMITIVES["list?"] = lambda x: isinstance(x, _b_list)
PRIMITIVES["dict?"] = lambda x: isinstance(x, _b_dict)
PRIMITIVES["boolean?"] = lambda x: isinstance(x, bool)
PRIMITIVES["symbol?"] = lambda x: isinstance(x, Symbol)
PRIMITIVES["keyword?"] = lambda x: isinstance(x, Keyword)
PRIMITIVES["continuation?"] = lambda x: isinstance(x, Continuation)
PRIMITIVES["empty?"] = lambda c: (
c is None or c is NIL or
@@ -1010,6 +1013,12 @@ parse_int = PRIMITIVES["parse-int"]
upper = PRIMITIVES["upper"]
has_key_p = PRIMITIVES["has-key?"]
dict_p = PRIMITIVES["dict?"]
boolean_p = PRIMITIVES["boolean?"]
symbol_p = PRIMITIVES["symbol?"]
keyword_p = PRIMITIVES["keyword?"]
number_p = PRIMITIVES["number?"]
string_p = PRIMITIVES["string?"]
list_p = PRIMITIVES["list?"]
dissoc = PRIMITIVES["dissoc"]
index_of = PRIMITIVES["index-of"]
lower = PRIMITIVES["lower"]

View File

@@ -692,6 +692,9 @@ PRIMITIVES["number?"] = lambda x: isinstance(x, (int, float)) and not isinstance
PRIMITIVES["string?"] = lambda x: isinstance(x, str)
PRIMITIVES["list?"] = lambda x: isinstance(x, _b_list)
PRIMITIVES["dict?"] = lambda x: isinstance(x, _b_dict)
PRIMITIVES["boolean?"] = lambda x: isinstance(x, bool)
PRIMITIVES["symbol?"] = lambda x: isinstance(x, Symbol)
PRIMITIVES["keyword?"] = lambda x: isinstance(x, Keyword)
PRIMITIVES["continuation?"] = lambda x: isinstance(x, Continuation)
PRIMITIVES["empty?"] = lambda c: (
c is None or c is NIL or
@@ -930,6 +933,12 @@ parse_int = PRIMITIVES["parse-int"]
upper = PRIMITIVES["upper"]
has_key_p = PRIMITIVES["has-key?"]
dict_p = PRIMITIVES["dict?"]
boolean_p = PRIMITIVES["boolean?"]
symbol_p = PRIMITIVES["symbol?"]
keyword_p = PRIMITIVES["keyword?"]
number_p = PRIMITIVES["number?"]
string_p = PRIMITIVES["string?"]
list_p = PRIMITIVES["list?"]
dissoc = PRIMITIVES["dissoc"]
index_of = PRIMITIVES["index-of"]
lower = PRIMITIVES["lower"]
@@ -4607,11 +4616,11 @@ def cek_serialize_value(val):
return val
elif sx_truthy(string_p(val)):
return val
elif sx_truthy((type_of(val) == 'boolean')):
elif sx_truthy(boolean_p(val)):
return val
elif sx_truthy((type_of(val) == 'symbol')):
elif sx_truthy(symbol_p(val)):
return val
elif sx_truthy((type_of(val) == 'keyword')):
elif sx_truthy(keyword_p(val)):
return val
elif sx_truthy(list_p(val)):
return map(cek_serialize_value, val)
@@ -4653,15 +4662,15 @@ def cek_thaw_value(val):
return val
elif sx_truthy(string_p(val)):
return val
elif sx_truthy((type_of(val) == 'boolean')):
elif sx_truthy(boolean_p(val)):
return val
elif sx_truthy((type_of(val) == 'symbol')):
elif sx_truthy(symbol_p(val)):
return val
elif sx_truthy((type_of(val) == 'keyword')):
elif sx_truthy(keyword_p(val)):
return val
elif sx_truthy((list_p(val) if not sx_truthy(list_p(val)) else ((not sx_truthy(empty_p(val))) if not sx_truthy((not sx_truthy(empty_p(val)))) else ((type_of(first(val)) == 'symbol') if not sx_truthy((type_of(first(val)) == 'symbol')) else (symbol_name(first(val)) == 'primitive'))))):
elif sx_truthy((list_p(val) if not sx_truthy(list_p(val)) else ((not sx_truthy(empty_p(val))) if not sx_truthy((not sx_truthy(empty_p(val)))) else (symbol_p(first(val)) if not sx_truthy(symbol_p(first(val))) else (symbol_name(first(val)) == 'primitive'))))):
return get_primitive(nth(val, 1))
elif sx_truthy((list_p(val) if not sx_truthy(list_p(val)) else ((not sx_truthy(empty_p(val))) if not sx_truthy((not sx_truthy(empty_p(val)))) else ((type_of(first(val)) == 'symbol') if not sx_truthy((type_of(first(val)) == 'symbol')) else (symbol_name(first(val)) == 'lambda'))))):
elif sx_truthy((list_p(val) if not sx_truthy(list_p(val)) else ((not sx_truthy(empty_p(val))) if not sx_truthy((not sx_truthy(empty_p(val)))) else (symbol_p(first(val)) if not sx_truthy(symbol_p(first(val))) else (symbol_name(first(val)) == 'lambda'))))):
return make_lambda(nth(val, 1), nth(val, 2), {})
elif sx_truthy(list_p(val)):
return map(cek_thaw_value, val)