Serializable CEK state: cek-freeze and cek-thaw
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
Freeze a CEK state to pure s-expressions. Thaw it back to a live state and resume with cek-run. Full round-trip through SX text works: freeze → sx-serialize → sx-parse → thaw → resume → same result. - cek-freeze: serialize control/env/kont/value to SX dicts - cek-thaw: reconstruct live state from frozen SX - Native functions serialize as (primitive "name"), looked up on resume - Lambdas serialize as (lambda (params) body) - Environments serialize as flat dicts of visible bindings - Continuation frames serialize as typed dicts Enables: localStorage persistence, content-addressed computation, cross-machine migration, time-travel debugging. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4586,6 +4586,110 @@ def trampoline_cek(val):
|
||||
else:
|
||||
return val
|
||||
|
||||
# primitive-name
|
||||
def primitive_name(f):
|
||||
_cells = {}
|
||||
if sx_truthy(is_lambda(f)):
|
||||
return lambda_name(f)
|
||||
else:
|
||||
_cells['result'] = NIL
|
||||
names = ['+', '-', '*', '/', '=', '<', '>', '<=', '>=', 'not', 'and', 'or', 'str', 'len', 'first', 'rest', 'nth', 'list', 'cons', 'append', 'map', 'filter', 'reduce', 'for-each', 'some', 'every?', 'get', 'keys', 'dict', 'dict?', 'has-key?', 'assoc', 'empty?', 'nil?', 'number?', 'string?', 'list?', 'type-of', 'identity', 'inc', 'dec', 'mod', 'join', 'split', 'slice', 'contains?', 'starts-with?', 'upper', 'lower', 'trim', 'replace', 'format']
|
||||
for name in names:
|
||||
if sx_truthy((is_nil(_cells['result']) if not sx_truthy(is_nil(_cells['result'])) else (is_primitive(name) if not sx_truthy(is_primitive(name)) else is_identical(f, get_primitive(name))))):
|
||||
_cells['result'] = name
|
||||
return _cells['result']
|
||||
|
||||
# cek-serialize-value
|
||||
def cek_serialize_value(val):
|
||||
if sx_truthy(is_nil(val)):
|
||||
return NIL
|
||||
elif sx_truthy(number_p(val)):
|
||||
return val
|
||||
elif sx_truthy(string_p(val)):
|
||||
return val
|
||||
elif sx_truthy((type_of(val) == 'boolean')):
|
||||
return val
|
||||
elif sx_truthy((type_of(val) == 'symbol')):
|
||||
return val
|
||||
elif sx_truthy((type_of(val) == 'keyword')):
|
||||
return val
|
||||
elif sx_truthy(list_p(val)):
|
||||
return map(cek_serialize_value, val)
|
||||
elif sx_truthy(is_lambda(val)):
|
||||
return [make_symbol('lambda'), lambda_params(val), lambda_body(val)]
|
||||
elif sx_truthy(is_callable(val)):
|
||||
return [make_symbol('primitive'), (primitive_name(val) if sx_truthy(primitive_name(val)) else '?')]
|
||||
elif sx_truthy(dict_p(val)):
|
||||
return cek_serialize_env(val)
|
||||
else:
|
||||
return sx_str(val)
|
||||
|
||||
# cek-serialize-env
|
||||
def cek_serialize_env(env):
|
||||
result = {}
|
||||
ks = keys(env)
|
||||
for k in ks:
|
||||
result[k] = cek_serialize_value(get(env, k))
|
||||
return result
|
||||
|
||||
# cek-serialize-frame
|
||||
def cek_serialize_frame(frame):
|
||||
result = {}
|
||||
ks = keys(frame)
|
||||
for k in ks:
|
||||
v = get(frame, k)
|
||||
result[k] = (v if sx_truthy((k == 'type')) else (v if sx_truthy((k == 'tag')) else (cek_serialize_value(v) if sx_truthy((k == 'f')) else (cek_serialize_env(v) if sx_truthy((k == 'env')) else (map(cek_serialize_value, v) if sx_truthy((k == 'evaled')) else (v if sx_truthy((k == 'remaining')) else (map(cek_serialize_value, v) if sx_truthy((k == 'results')) else (v if sx_truthy((k == 'raw-args')) else (cek_serialize_value(v) if sx_truthy((k == 'current-item')) else (v if sx_truthy((k == 'name')) else (cek_serialize_value(v) if sx_truthy((k == 'update-fn')) else (v if sx_truthy((k == 'first-render')) else cek_serialize_value(v)))))))))))))
|
||||
return result
|
||||
|
||||
# cek-freeze
|
||||
def cek_freeze(state):
|
||||
return {'phase': get(state, 'phase'), 'control': get(state, 'control'), 'value': cek_serialize_value(get(state, 'value')), 'env': cek_serialize_env(get(state, 'env')), 'kont': map(cek_serialize_frame, get(state, 'kont'))}
|
||||
|
||||
# cek-thaw-value
|
||||
def cek_thaw_value(val):
|
||||
if sx_truthy(is_nil(val)):
|
||||
return NIL
|
||||
elif sx_truthy(number_p(val)):
|
||||
return val
|
||||
elif sx_truthy(string_p(val)):
|
||||
return val
|
||||
elif sx_truthy((type_of(val) == 'boolean')):
|
||||
return val
|
||||
elif sx_truthy((type_of(val) == 'symbol')):
|
||||
return val
|
||||
elif sx_truthy((type_of(val) == 'keyword')):
|
||||
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'))))):
|
||||
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'))))):
|
||||
return make_lambda(nth(val, 1), nth(val, 2), {})
|
||||
elif sx_truthy(list_p(val)):
|
||||
return map(cek_thaw_value, val)
|
||||
elif sx_truthy(dict_p(val)):
|
||||
return cek_thaw_env(val)
|
||||
else:
|
||||
return val
|
||||
|
||||
# cek-thaw-env
|
||||
def cek_thaw_env(frozen_env):
|
||||
result = make_env()
|
||||
for k in keys(frozen_env):
|
||||
result[k] = cek_thaw_value(get(frozen_env, k))
|
||||
return result
|
||||
|
||||
# cek-thaw-frame
|
||||
def cek_thaw_frame(frozen_frame):
|
||||
result = {}
|
||||
ks = keys(frozen_frame)
|
||||
for k in ks:
|
||||
v = get(frozen_frame, k)
|
||||
result[k] = (v if sx_truthy((k == 'type')) else (v if sx_truthy((k == 'tag')) else (cek_thaw_value(v) if sx_truthy((k == 'f')) else (cek_thaw_env(v) if sx_truthy((k == 'env')) else (map(cek_thaw_value, v) if sx_truthy((k == 'evaled')) else (v if sx_truthy((k == 'remaining')) else (map(cek_thaw_value, v) if sx_truthy((k == 'results')) else (v if sx_truthy((k == 'raw-args')) else (cek_thaw_value(v) if sx_truthy((k == 'current-item')) else (v if sx_truthy((k == 'name')) else (cek_thaw_value(v) if sx_truthy((k == 'update-fn')) else (v if sx_truthy((k == 'first-render')) else cek_thaw_value(v)))))))))))))
|
||||
return result
|
||||
|
||||
# cek-thaw
|
||||
def cek_thaw(frozen):
|
||||
return {'phase': get(frozen, 'phase'), 'control': get(frozen, 'control'), 'value': cek_thaw_value(get(frozen, 'value')), 'env': cek_thaw_env(get(frozen, 'env')), 'kont': map(cek_thaw_frame, get(frozen, 'kont'))}
|
||||
|
||||
|
||||
# === Transpiled from signals (reactive signal runtime) ===
|
||||
|
||||
|
||||
Reference in New Issue
Block a user