From 72eaefac135502233e5c7c70265a8472dda37078 Mon Sep 17 00:00:00 2001 From: giles Date: Sun, 15 Mar 2026 02:26:18 +0000 Subject: [PATCH] Phase 4: Move web framework files to web/ and web/tests/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit signals.sx, engine.sx, orchestration.sx, boot.sx, router.sx, deps.sx, forms.sx, page-helpers.sx, adapters, boundary files → web/ Web tests → web/tests/ Test runners updated with _SPEC_TESTS and _WEB_TESTS paths. All 89 tests pass (20 signal + 43 CEK + 26 CEK reactive). Both bootstrappers build fully (5993 Python lines, 387KB JS). Co-Authored-By: Claude Opus 4.6 (1M context) --- hosts/python/bootstrap.py | 2 +- hosts/python/tests/run_cek_reactive_tests.py | 12 +- hosts/python/tests/run_cek_tests.py | 10 +- hosts/python/tests/run_continuation_tests.py | 6 +- hosts/python/tests/run_signal_tests.py | 6 +- hosts/python/tests/run_type_tests.py | 6 +- shared/static/scripts/sx-browser.js | 2 +- shared/sx/ref/sx_ref.py | 2084 ++++++++++++++++++ web/{ => tests}/test-aser.sx | 0 web/{ => tests}/test-cek-reactive.sx | 0 web/{ => tests}/test-deps.sx | 0 web/{ => tests}/test-engine.sx | 0 web/{ => tests}/test-orchestration.sx | 0 web/{ => tests}/test-router.sx | 0 web/{ => tests}/test-signals.sx | 0 15 files changed, 2111 insertions(+), 17 deletions(-) rename web/{ => tests}/test-aser.sx (100%) rename web/{ => tests}/test-cek-reactive.sx (100%) rename web/{ => tests}/test-deps.sx (100%) rename web/{ => tests}/test-engine.sx (100%) rename web/{ => tests}/test-orchestration.sx (100%) rename web/{ => tests}/test-router.sx (100%) rename web/{ => tests}/test-signals.sx (100%) diff --git a/hosts/python/bootstrap.py b/hosts/python/bootstrap.py index d478f4a..74b7a63 100644 --- a/hosts/python/bootstrap.py +++ b/hosts/python/bootstrap.py @@ -1440,7 +1440,7 @@ def compile_ref_to_py( prim_modules.append(m) ref_dir = os.path.join(os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..")), "shared", "sx", "ref") - _project = os.path.abspath(os.path.join(ref_dir, "..", "..")) + _project = os.path.abspath(os.path.join(ref_dir, "..", "..", "..")) _source_dirs = [ os.path.join(_project, "spec"), os.path.join(_project, "web"), diff --git a/hosts/python/tests/run_cek_reactive_tests.py b/hosts/python/tests/run_cek_reactive_tests.py index 73ef725..0855371 100644 --- a/hosts/python/tests/run_cek_reactive_tests.py +++ b/hosts/python/tests/run_cek_reactive_tests.py @@ -5,6 +5,8 @@ import os, sys _HERE = os.path.dirname(os.path.abspath(__file__)) _PROJECT = os.path.abspath(os.path.join(_HERE, "..", "..", "..")) +_SPEC_TESTS = os.path.join(_PROJECT, "spec", "tests") +_WEB_TESTS = os.path.join(_PROJECT, "web", "tests") sys.path.insert(0, _PROJECT) sys.setrecursionlimit(20000) @@ -212,25 +214,25 @@ for name in ["sf-defhandler", "sf-defpage", "sf-defquery", "sf-defaction"]: env[name] = lambda args, e, _n=name: NIL # Load test framework -with open(os.path.join(_HERE, "test-framework.sx")) as f: +with open(os.path.join(_SPEC_TESTS, "test-framework.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) # Load signals module print("Loading signals.sx ...") -with open(os.path.join(_HERE, "signals.sx")) as f: +with open(os.path.join(_PROJECT, "web", "signals.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) # Load frames module print("Loading frames.sx ...") -with open(os.path.join(_HERE, "frames.sx")) as f: +with open(os.path.join(_PROJECT, "spec", "frames.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) # Load CEK module print("Loading cek.sx ...") -with open(os.path.join(_HERE, "cek.sx")) as f: +with open(os.path.join(_PROJECT, "spec", "cek.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) @@ -239,7 +241,7 @@ print("=" * 60) print("Running test-cek-reactive.sx") print("=" * 60) -with open(os.path.join(_HERE, "test-cek-reactive.sx")) as f: +with open(os.path.join(_WEB_TESTS, "test-cek-reactive.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) diff --git a/hosts/python/tests/run_cek_tests.py b/hosts/python/tests/run_cek_tests.py index 9ea2df8..dfecd5e 100644 --- a/hosts/python/tests/run_cek_tests.py +++ b/hosts/python/tests/run_cek_tests.py @@ -5,6 +5,8 @@ import os, sys _HERE = os.path.dirname(os.path.abspath(__file__)) _PROJECT = os.path.abspath(os.path.join(_HERE, "..", "..", "..")) +_SPEC_TESTS = os.path.join(_PROJECT, "spec", "tests") +_WEB_TESTS = os.path.join(_PROJECT, "web", "tests") sys.path.insert(0, _PROJECT) from shared.sx.ref.sx_ref import sx_parse as parse_all @@ -223,19 +225,19 @@ for name in ["sf-defhandler", "sf-defpage", "sf-defquery", "sf-defaction"]: env[name] = lambda args, e, _n=name: NIL # Load test framework -with open(os.path.join(_HERE, "test-framework.sx")) as f: +with open(os.path.join(_SPEC_TESTS, "test-framework.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) # Load frames module print("Loading frames.sx ...") -with open(os.path.join(_HERE, "frames.sx")) as f: +with open(os.path.join(_PROJECT, "spec", "frames.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) # Load CEK module print("Loading cek.sx ...") -with open(os.path.join(_HERE, "cek.sx")) as f: +with open(os.path.join(_PROJECT, "spec", "cek.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) @@ -255,7 +257,7 @@ print("=" * 60) print("Running test-cek.sx") print("=" * 60) -with open(os.path.join(_HERE, "test-cek.sx")) as f: +with open(os.path.join(_SPEC_TESTS, "test-cek.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) diff --git a/hosts/python/tests/run_continuation_tests.py b/hosts/python/tests/run_continuation_tests.py index 80f547a..0daeb28 100644 --- a/hosts/python/tests/run_continuation_tests.py +++ b/hosts/python/tests/run_continuation_tests.py @@ -5,6 +5,8 @@ import os, sys, subprocess, tempfile _HERE = os.path.dirname(os.path.abspath(__file__)) _PROJECT = os.path.abspath(os.path.join(_HERE, "..", "..", "..")) +_SPEC_TESTS = os.path.join(_PROJECT, "spec", "tests") +_WEB_TESTS = os.path.join(_PROJECT, "web", "tests") sys.path.insert(0, _PROJECT) # Bootstrap a fresh sx_ref with continuations enabled @@ -87,7 +89,7 @@ env["push-suite"] = _push_suite env["pop-suite"] = _pop_suite # Load test framework -with open(os.path.join(_HERE, "test-framework.sx")) as f: +with open(os.path.join(_SPEC_TESTS, "test-framework.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) @@ -96,7 +98,7 @@ print("=" * 60) print("Running test-continuations.sx") print("=" * 60) -with open(os.path.join(_HERE, "test-continuations.sx")) as f: +with open(os.path.join(_SPEC_TESTS, "test-continuations.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) diff --git a/hosts/python/tests/run_signal_tests.py b/hosts/python/tests/run_signal_tests.py index 80f0ce7..668bc88 100644 --- a/hosts/python/tests/run_signal_tests.py +++ b/hosts/python/tests/run_signal_tests.py @@ -10,6 +10,8 @@ import os, sys _HERE = os.path.dirname(os.path.abspath(__file__)) _PROJECT = os.path.abspath(os.path.join(_HERE, "..", "..", "..")) +_SPEC_TESTS = os.path.join(_PROJECT, "spec", "tests") +_WEB_TESTS = os.path.join(_PROJECT, "web", "tests") sys.path.insert(0, _PROJECT) from shared.sx.ref.sx_ref import sx_parse as parse_all @@ -143,7 +145,7 @@ env["register-in-scope"] = sx_ref.register_in_scope env["callable?"] = sx_ref.is_callable # Load test framework -with open(os.path.join(_HERE, "test-framework.sx")) as f: +with open(os.path.join(_SPEC_TESTS, "test-framework.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) @@ -152,7 +154,7 @@ print("=" * 60) print("Running test-signals.sx") print("=" * 60) -with open(os.path.join(_HERE, "test-signals.sx")) as f: +with open(os.path.join(_WEB_TESTS, "test-signals.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) diff --git a/hosts/python/tests/run_type_tests.py b/hosts/python/tests/run_type_tests.py index 59c39be..612b073 100644 --- a/hosts/python/tests/run_type_tests.py +++ b/hosts/python/tests/run_type_tests.py @@ -5,6 +5,8 @@ import os, sys _HERE = os.path.dirname(os.path.abspath(__file__)) _PROJECT = os.path.abspath(os.path.join(_HERE, "..", "..", "..")) +_SPEC_TESTS = os.path.join(_PROJECT, "spec", "tests") +_WEB_TESTS = os.path.join(_PROJECT, "web", "tests") sys.path.insert(0, _PROJECT) from shared.sx.ref.sx_ref import sx_parse as parse_all @@ -167,7 +169,7 @@ env["env-has?"] = env_has env["env-set!"] = env_set # Load test framework (macros + assertion helpers) -with open(os.path.join(_HERE, "test-framework.sx")) as f: +with open(os.path.join(_SPEC_TESTS, "test-framework.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) @@ -181,7 +183,7 @@ print("=" * 60) print("Running test-types.sx") print("=" * 60) -with open(os.path.join(_HERE, "test-types.sx")) as f: +with open(os.path.join(_SPEC_TESTS, "test-types.sx")) as f: for expr in parse_all(f.read()): trampoline(eval_expr(expr, env)) diff --git a/shared/static/scripts/sx-browser.js b/shared/static/scripts/sx-browser.js index 5c3b46b..e6615bd 100644 --- a/shared/static/scripts/sx-browser.js +++ b/shared/static/scripts/sx-browser.js @@ -14,7 +14,7 @@ // ========================================================================= var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } }); - var SX_VERSION = "2026-03-15T02:18:33Z"; + var SX_VERSION = "2026-03-15T02:24:46Z"; function isNil(x) { return x === NIL || x === null || x === undefined; } function isSxTruthy(x) { return x !== false && !isNil(x); } diff --git a/shared/sx/ref/sx_ref.py b/shared/sx/ref/sx_ref.py index 2e269f9..70a81cf 100644 --- a/shared/sx/ref/sx_ref.py +++ b/shared/sx/ref/sx_ref.py @@ -1242,6 +1242,711 @@ async def async_eval_slot_to_sx(expr, env, ctx=None): _expand_components_cv.reset(token) +# === Transpiled from eval === + +# trampoline +def trampoline(val): + result = val + if sx_truthy(is_thunk(result)): + return trampoline(eval_expr(thunk_expr(result), thunk_env(result))) + else: + return result + +# eval-expr +def eval_expr(expr, env): + _match = type_of(expr) + if _match == 'number': + return expr + elif _match == 'string': + return expr + elif _match == 'boolean': + return expr + elif _match == 'nil': + return NIL + elif _match == 'symbol': + name = symbol_name(expr) + if sx_truthy(env_has(env, name)): + return env_get(env, name) + elif sx_truthy(is_primitive(name)): + return get_primitive(name) + elif sx_truthy((name == 'true')): + return True + elif sx_truthy((name == 'false')): + return False + elif sx_truthy((name == 'nil')): + return NIL + else: + debug_log('Undefined symbol:', name, 'primitive?:', is_primitive(name)) + return error(sx_str('Undefined symbol: ', name)) + elif _match == 'keyword': + return keyword_name(expr) + elif _match == 'dict': + return map_dict(lambda k, v: trampoline(eval_expr(v, env)), expr) + elif _match == 'list': + if sx_truthy(empty_p(expr)): + return [] + else: + return eval_list(expr, env) + else: + return expr + +# eval-list +def eval_list(expr, env): + head = first(expr) + args = rest(expr) + if sx_truthy((not sx_truthy(((type_of(head) == 'symbol') if sx_truthy((type_of(head) == 'symbol')) else ((type_of(head) == 'lambda') if sx_truthy((type_of(head) == 'lambda')) else (type_of(head) == 'list')))))): + return map(lambda x: trampoline(eval_expr(x, env)), expr) + else: + if sx_truthy((type_of(head) == 'symbol')): + name = symbol_name(head) + if sx_truthy((name == 'if')): + return sf_if(args, env) + elif sx_truthy((name == 'when')): + return sf_when(args, env) + elif sx_truthy((name == 'cond')): + return sf_cond(args, env) + elif sx_truthy((name == 'case')): + return sf_case(args, env) + elif sx_truthy((name == 'and')): + return sf_and(args, env) + elif sx_truthy((name == 'or')): + return sf_or(args, env) + elif sx_truthy((name == 'let')): + return sf_let(args, env) + elif sx_truthy((name == 'let*')): + return sf_let(args, env) + elif sx_truthy((name == 'letrec')): + return sf_letrec(args, env) + elif sx_truthy((name == 'lambda')): + return sf_lambda(args, env) + elif sx_truthy((name == 'fn')): + return sf_lambda(args, env) + elif sx_truthy((name == 'define')): + return sf_define(args, env) + elif sx_truthy((name == 'defcomp')): + return sf_defcomp(args, env) + elif sx_truthy((name == 'defisland')): + return sf_defisland(args, env) + elif sx_truthy((name == 'defmacro')): + return sf_defmacro(args, env) + elif sx_truthy((name == 'defstyle')): + return sf_defstyle(args, env) + elif sx_truthy((name == 'defhandler')): + return sf_defhandler(args, env) + elif sx_truthy((name == 'defpage')): + return sf_defpage(args, env) + elif sx_truthy((name == 'defquery')): + return sf_defquery(args, env) + elif sx_truthy((name == 'defaction')): + return sf_defaction(args, env) + elif sx_truthy((name == 'deftype')): + return sf_deftype(args, env) + elif sx_truthy((name == 'defeffect')): + return sf_defeffect(args, env) + elif sx_truthy((name == 'begin')): + return sf_begin(args, env) + elif sx_truthy((name == 'do')): + return sf_begin(args, env) + elif sx_truthy((name == 'quote')): + return sf_quote(args, env) + elif sx_truthy((name == 'quasiquote')): + return sf_quasiquote(args, env) + elif sx_truthy((name == '->')): + return sf_thread_first(args, env) + elif sx_truthy((name == 'set!')): + return sf_set_bang(args, env) + elif sx_truthy((name == 'reset')): + return sf_reset(args, env) + elif sx_truthy((name == 'shift')): + return sf_shift(args, env) + elif sx_truthy((name == 'dynamic-wind')): + return sf_dynamic_wind(args, env) + elif sx_truthy((name == 'scope')): + return sf_scope(args, env) + elif sx_truthy((name == 'provide')): + return sf_provide(args, env) + elif sx_truthy((name == 'map')): + return ho_map(args, env) + elif sx_truthy((name == 'map-indexed')): + return ho_map_indexed(args, env) + elif sx_truthy((name == 'filter')): + return ho_filter(args, env) + elif sx_truthy((name == 'reduce')): + return ho_reduce(args, env) + elif sx_truthy((name == 'some')): + return ho_some(args, env) + elif sx_truthy((name == 'every?')): + return ho_every(args, env) + elif sx_truthy((name == 'for-each')): + return ho_for_each(args, env) + elif sx_truthy((env_has(env, name) if not sx_truthy(env_has(env, name)) else is_macro(env_get(env, name)))): + mac = env_get(env, name) + return make_thunk(expand_macro(mac, args, env), env) + elif sx_truthy((render_active_p() if not sx_truthy(render_active_p()) else is_render_expr(expr))): + return render_expr(expr, env) + else: + return eval_call(head, args, env) + else: + return eval_call(head, args, env) + +# eval-call +def eval_call(head, args, env): + f = trampoline(eval_expr(head, env)) + evaluated_args = map(lambda a: trampoline(eval_expr(a, env)), args) + if sx_truthy((is_callable(f) if not sx_truthy(is_callable(f)) else ((not sx_truthy(is_lambda(f))) if not sx_truthy((not sx_truthy(is_lambda(f)))) else ((not sx_truthy(is_component(f))) if not sx_truthy((not sx_truthy(is_component(f)))) else (not sx_truthy(is_island(f))))))): + return apply(f, evaluated_args) + elif sx_truthy(is_lambda(f)): + return call_lambda(f, evaluated_args, env) + elif sx_truthy(is_component(f)): + return call_component(f, args, env) + elif sx_truthy(is_island(f)): + return call_component(f, args, env) + else: + return error(sx_str('Not callable: ', inspect(f))) + +# call-lambda +def call_lambda(f, args, caller_env): + params = lambda_params(f) + local = env_merge(lambda_closure(f), caller_env) + if sx_truthy((len(args) > len(params))): + return error(sx_str((lambda_name(f) if sx_truthy(lambda_name(f)) else 'lambda'), ' expects ', len(params), ' args, got ', len(args))) + else: + for pair in zip(params, args): + local[first(pair)] = nth(pair, 1) + for p in slice(params, len(args)): + local[p] = NIL + return make_thunk(lambda_body(f), local) + +# call-component +def call_component(comp, raw_args, env): + parsed = parse_keyword_args(raw_args, env) + kwargs = first(parsed) + children = nth(parsed, 1) + local = env_merge(component_closure(comp), env) + for p in component_params(comp): + local[p] = (dict_get(kwargs, p) if sx_truthy(dict_get(kwargs, p)) else NIL) + if sx_truthy(component_has_children(comp)): + local['children'] = children + return make_thunk(component_body(comp), local) + +# parse-keyword-args +def parse_keyword_args(raw_args, env): + kwargs = {} + children = [] + i = 0 + reduce(lambda state, arg: (lambda idx: (lambda skip: (assoc(state, 'skip', False, 'i', (idx + 1)) if sx_truthy(skip) else (_sx_begin(_sx_dict_set(kwargs, keyword_name(arg), trampoline(eval_expr(nth(raw_args, (idx + 1)), env))), assoc(state, 'skip', True, 'i', (idx + 1))) if sx_truthy(((type_of(arg) == 'keyword') if not sx_truthy((type_of(arg) == 'keyword')) else ((idx + 1) < len(raw_args)))) else _sx_begin(_sx_append(children, trampoline(eval_expr(arg, env))), assoc(state, 'i', (idx + 1))))))(get(state, 'skip')))(get(state, 'i')), {'i': 0, 'skip': False}, raw_args) + return [kwargs, children] + +# sf-if +def sf_if(args, env): + condition = trampoline(eval_expr(first(args), env)) + if sx_truthy((condition if not sx_truthy(condition) else (not sx_truthy(is_nil(condition))))): + return make_thunk(nth(args, 1), env) + else: + if sx_truthy((len(args) > 2)): + return make_thunk(nth(args, 2), env) + else: + return NIL + +# sf-when +def sf_when(args, env): + condition = trampoline(eval_expr(first(args), env)) + if sx_truthy((condition if not sx_truthy(condition) else (not sx_truthy(is_nil(condition))))): + for e in slice(args, 1, (len(args) - 1)): + trampoline(eval_expr(e, env)) + return make_thunk(last(args), env) + else: + return NIL + +# cond-scheme? +def cond_scheme_p(clauses): + return every_p(lambda c: ((type_of(c) == 'list') if not sx_truthy((type_of(c) == 'list')) else (len(c) == 2)), clauses) + +# sf-cond +def sf_cond(args, env): + if sx_truthy(cond_scheme_p(args)): + return sf_cond_scheme(args, env) + else: + return sf_cond_clojure(args, env) + +# sf-cond-scheme +def sf_cond_scheme(clauses, env): + if sx_truthy(empty_p(clauses)): + return NIL + else: + clause = first(clauses) + test = first(clause) + body = nth(clause, 1) + if sx_truthy((((type_of(test) == 'symbol') if not sx_truthy((type_of(test) == 'symbol')) else ((symbol_name(test) == 'else') if sx_truthy((symbol_name(test) == 'else')) else (symbol_name(test) == ':else'))) if sx_truthy(((type_of(test) == 'symbol') if not sx_truthy((type_of(test) == 'symbol')) else ((symbol_name(test) == 'else') if sx_truthy((symbol_name(test) == 'else')) else (symbol_name(test) == ':else')))) else ((type_of(test) == 'keyword') if not sx_truthy((type_of(test) == 'keyword')) else (keyword_name(test) == 'else')))): + return make_thunk(body, env) + else: + if sx_truthy(trampoline(eval_expr(test, env))): + return make_thunk(body, env) + else: + return sf_cond_scheme(rest(clauses), env) + +# sf-cond-clojure +def sf_cond_clojure(clauses, env): + if sx_truthy((len(clauses) < 2)): + return NIL + else: + test = first(clauses) + body = nth(clauses, 1) + if sx_truthy((((type_of(test) == 'keyword') if not sx_truthy((type_of(test) == 'keyword')) else (keyword_name(test) == 'else')) if sx_truthy(((type_of(test) == 'keyword') if not sx_truthy((type_of(test) == 'keyword')) else (keyword_name(test) == 'else'))) else ((type_of(test) == 'symbol') if not sx_truthy((type_of(test) == 'symbol')) else ((symbol_name(test) == 'else') if sx_truthy((symbol_name(test) == 'else')) else (symbol_name(test) == ':else'))))): + return make_thunk(body, env) + else: + if sx_truthy(trampoline(eval_expr(test, env))): + return make_thunk(body, env) + else: + return sf_cond_clojure(slice(clauses, 2), env) + +# sf-case +def sf_case(args, env): + match_val = trampoline(eval_expr(first(args), env)) + clauses = rest(args) + return sf_case_loop(match_val, clauses, env) + +# sf-case-loop +def sf_case_loop(match_val, clauses, env): + if sx_truthy((len(clauses) < 2)): + return NIL + else: + test = first(clauses) + body = nth(clauses, 1) + if sx_truthy((((type_of(test) == 'keyword') if not sx_truthy((type_of(test) == 'keyword')) else (keyword_name(test) == 'else')) if sx_truthy(((type_of(test) == 'keyword') if not sx_truthy((type_of(test) == 'keyword')) else (keyword_name(test) == 'else'))) else ((type_of(test) == 'symbol') if not sx_truthy((type_of(test) == 'symbol')) else ((symbol_name(test) == 'else') if sx_truthy((symbol_name(test) == 'else')) else (symbol_name(test) == ':else'))))): + return make_thunk(body, env) + else: + if sx_truthy((match_val == trampoline(eval_expr(test, env)))): + return make_thunk(body, env) + else: + return sf_case_loop(match_val, slice(clauses, 2), env) + +# sf-and +def sf_and(args, env): + if sx_truthy(empty_p(args)): + return True + else: + val = trampoline(eval_expr(first(args), env)) + if sx_truthy((not sx_truthy(val))): + return val + else: + if sx_truthy((len(args) == 1)): + return val + else: + return sf_and(rest(args), env) + +# sf-or +def sf_or(args, env): + if sx_truthy(empty_p(args)): + return False + else: + val = trampoline(eval_expr(first(args), env)) + if sx_truthy(val): + return val + else: + return sf_or(rest(args), env) + +# sf-let +def sf_let(args, env): + if sx_truthy((type_of(first(args)) == 'symbol')): + return sf_named_let(args, env) + else: + bindings = first(args) + body = rest(args) + local = env_extend(env) + if sx_truthy(((type_of(first(bindings)) == 'list') if not sx_truthy((type_of(first(bindings)) == 'list')) else (len(first(bindings)) == 2))): + for binding in bindings: + vname = (symbol_name(first(binding)) if sx_truthy((type_of(first(binding)) == 'symbol')) else first(binding)) + local[vname] = trampoline(eval_expr(nth(binding, 1), local)) + else: + i = 0 + reduce(lambda acc, pair_idx: (lambda vname: (lambda val_expr: _sx_dict_set(local, vname, trampoline(eval_expr(val_expr, local))))(nth(bindings, ((pair_idx * 2) + 1))))((symbol_name(nth(bindings, (pair_idx * 2))) if sx_truthy((type_of(nth(bindings, (pair_idx * 2))) == 'symbol')) else nth(bindings, (pair_idx * 2)))), NIL, range(0, (len(bindings) / 2))) + for e in slice(body, 0, (len(body) - 1)): + trampoline(eval_expr(e, local)) + return make_thunk(last(body), local) + +# sf-named-let +def sf_named_let(args, env): + loop_name = symbol_name(first(args)) + bindings = nth(args, 1) + body = slice(args, 2) + params = [] + inits = [] + if sx_truthy(((type_of(first(bindings)) == 'list') if not sx_truthy((type_of(first(bindings)) == 'list')) else (len(first(bindings)) == 2))): + for binding in bindings: + params.append((symbol_name(first(binding)) if sx_truthy((type_of(first(binding)) == 'symbol')) else first(binding))) + inits.append(nth(binding, 1)) + else: + reduce(lambda acc, pair_idx: _sx_begin(_sx_append(params, (symbol_name(nth(bindings, (pair_idx * 2))) if sx_truthy((type_of(nth(bindings, (pair_idx * 2))) == 'symbol')) else nth(bindings, (pair_idx * 2)))), _sx_append(inits, nth(bindings, ((pair_idx * 2) + 1)))), NIL, range(0, (len(bindings) / 2))) + loop_body = (first(body) if sx_truthy((len(body) == 1)) else cons(make_symbol('begin'), body)) + loop_fn = make_lambda(params, loop_body, env) + loop_fn.name = loop_name + lambda_closure(loop_fn)[loop_name] = loop_fn + init_vals = map(lambda e: trampoline(eval_expr(e, env)), inits) + return call_lambda(loop_fn, init_vals, env) + +# sf-lambda +def sf_lambda(args, env): + params_expr = first(args) + body_exprs = rest(args) + body = (first(body_exprs) if sx_truthy((len(body_exprs) == 1)) else cons(make_symbol('begin'), body_exprs)) + param_names = map(lambda p: (symbol_name(p) if sx_truthy((type_of(p) == 'symbol')) else (symbol_name(first(p)) if sx_truthy(((type_of(p) == 'list') if not sx_truthy((type_of(p) == 'list')) else ((len(p) == 3) if not sx_truthy((len(p) == 3)) else ((type_of(nth(p, 1)) == 'keyword') if not sx_truthy((type_of(nth(p, 1)) == 'keyword')) else (keyword_name(nth(p, 1)) == 'as'))))) else p)), params_expr) + return make_lambda(param_names, body, env) + +# sf-define +def sf_define(args, env): + name_sym = first(args) + has_effects = ((len(args) >= 4) if not sx_truthy((len(args) >= 4)) else ((type_of(nth(args, 1)) == 'keyword') if not sx_truthy((type_of(nth(args, 1)) == 'keyword')) else (keyword_name(nth(args, 1)) == 'effects'))) + val_idx = (3 if sx_truthy(((len(args) >= 4) if not sx_truthy((len(args) >= 4)) else ((type_of(nth(args, 1)) == 'keyword') if not sx_truthy((type_of(nth(args, 1)) == 'keyword')) else (keyword_name(nth(args, 1)) == 'effects')))) else 1) + value = trampoline(eval_expr(nth(args, val_idx), env)) + if sx_truthy((is_lambda(value) if not sx_truthy(is_lambda(value)) else is_nil(lambda_name(value)))): + value.name = symbol_name(name_sym) + env[symbol_name(name_sym)] = value + if sx_truthy(has_effects): + effects_raw = nth(args, 2) + effect_list = (map(lambda e: (symbol_name(e) if sx_truthy((type_of(e) == 'symbol')) else sx_str(e)), effects_raw) if sx_truthy((type_of(effects_raw) == 'list')) else [sx_str(effects_raw)]) + effect_anns = (env_get(env, '*effect-annotations*') if sx_truthy(env_has(env, '*effect-annotations*')) else {}) + effect_anns[symbol_name(name_sym)] = effect_list + env['*effect-annotations*'] = effect_anns + return value + +# sf-defcomp +def sf_defcomp(args, env): + name_sym = first(args) + params_raw = nth(args, 1) + body = last(args) + comp_name = strip_prefix(symbol_name(name_sym), '~') + parsed = parse_comp_params(params_raw) + params = first(parsed) + has_children = nth(parsed, 1) + param_types = nth(parsed, 2) + affinity = defcomp_kwarg(args, 'affinity', 'auto') + comp = make_component(comp_name, params, has_children, body, env, affinity) + effects = defcomp_kwarg(args, 'effects', NIL) + if sx_truthy(((not sx_truthy(is_nil(param_types))) if not sx_truthy((not sx_truthy(is_nil(param_types)))) else (not sx_truthy(empty_p(keys(param_types)))))): + component_set_param_types(comp, param_types) + if sx_truthy((not sx_truthy(is_nil(effects)))): + effect_list = (map(lambda e: (symbol_name(e) if sx_truthy((type_of(e) == 'symbol')) else sx_str(e)), effects) if sx_truthy((type_of(effects) == 'list')) else [sx_str(effects)]) + effect_anns = (env_get(env, '*effect-annotations*') if sx_truthy(env_has(env, '*effect-annotations*')) else {}) + effect_anns[symbol_name(name_sym)] = effect_list + env['*effect-annotations*'] = effect_anns + env[symbol_name(name_sym)] = comp + return comp + +# defcomp-kwarg +def defcomp_kwarg(args, key, default_): + _cells = {} + end = (len(args) - 1) + _cells['result'] = default_ + for i in range(2, end, 1): + if sx_truthy(((type_of(nth(args, i)) == 'keyword') if not sx_truthy((type_of(nth(args, i)) == 'keyword')) else ((keyword_name(nth(args, i)) == key) if not sx_truthy((keyword_name(nth(args, i)) == key)) else ((i + 1) < end)))): + val = nth(args, (i + 1)) + _cells['result'] = (keyword_name(val) if sx_truthy((type_of(val) == 'keyword')) else val) + return _cells['result'] + +# parse-comp-params +def parse_comp_params(params_expr): + _cells = {} + params = [] + param_types = {} + _cells['has_children'] = False + _cells['in_key'] = False + for p in params_expr: + if sx_truthy(((type_of(p) == 'list') if not sx_truthy((type_of(p) == 'list')) else ((len(p) == 3) if not sx_truthy((len(p) == 3)) else ((type_of(first(p)) == 'symbol') if not sx_truthy((type_of(first(p)) == 'symbol')) else ((type_of(nth(p, 1)) == 'keyword') if not sx_truthy((type_of(nth(p, 1)) == 'keyword')) else (keyword_name(nth(p, 1)) == 'as')))))): + name = symbol_name(first(p)) + ptype = nth(p, 2) + type_val = (symbol_name(ptype) if sx_truthy((type_of(ptype) == 'symbol')) else ptype) + if sx_truthy((not sx_truthy(_cells['has_children']))): + params.append(name) + param_types[name] = type_val + else: + if sx_truthy((type_of(p) == 'symbol')): + name = symbol_name(p) + if sx_truthy((name == '&key')): + _cells['in_key'] = True + elif sx_truthy((name == '&rest')): + _cells['has_children'] = True + elif sx_truthy((name == '&children')): + _cells['has_children'] = True + elif sx_truthy(_cells['has_children']): + NIL + elif sx_truthy(_cells['in_key']): + params.append(name) + else: + params.append(name) + return [params, _cells['has_children'], param_types] + +# sf-defisland +def sf_defisland(args, env): + name_sym = first(args) + params_raw = nth(args, 1) + body = last(args) + comp_name = strip_prefix(symbol_name(name_sym), '~') + parsed = parse_comp_params(params_raw) + params = first(parsed) + has_children = nth(parsed, 1) + island = make_island(comp_name, params, has_children, body, env) + env[symbol_name(name_sym)] = island + return island + +# sf-defmacro +def sf_defmacro(args, env): + name_sym = first(args) + params_raw = nth(args, 1) + body = nth(args, 2) + parsed = parse_macro_params(params_raw) + params = first(parsed) + rest_param = nth(parsed, 1) + mac = make_macro(params, rest_param, body, env, symbol_name(name_sym)) + env[symbol_name(name_sym)] = mac + return mac + +# parse-macro-params +def parse_macro_params(params_expr): + _cells = {} + params = [] + _cells['rest_param'] = NIL + reduce(lambda state, p: (assoc(state, 'in-rest', True) if sx_truthy(((type_of(p) == 'symbol') if not sx_truthy((type_of(p) == 'symbol')) else (symbol_name(p) == '&rest'))) else (_sx_begin(_sx_cell_set(_cells, 'rest_param', (symbol_name(p) if sx_truthy((type_of(p) == 'symbol')) else p)), state) if sx_truthy(get(state, 'in-rest')) else _sx_begin(_sx_append(params, (symbol_name(p) if sx_truthy((type_of(p) == 'symbol')) else p)), state))), {'in-rest': False}, params_expr) + return [params, _cells['rest_param']] + +# sf-defstyle +def sf_defstyle(args, env): + name_sym = first(args) + value = trampoline(eval_expr(nth(args, 1), env)) + env[symbol_name(name_sym)] = value + return value + +# make-type-def +def make_type_def(name, params, body): + return {'name': name, 'params': params, 'body': body} + +# normalize-type-body +def normalize_type_body(body): + if sx_truthy(is_nil(body)): + return 'nil' + elif sx_truthy((type_of(body) == 'symbol')): + return symbol_name(body) + elif sx_truthy((type_of(body) == 'string')): + return body + elif sx_truthy((type_of(body) == 'keyword')): + return keyword_name(body) + elif sx_truthy((type_of(body) == 'dict')): + return map_dict(lambda k, v: normalize_type_body(v), body) + elif sx_truthy((type_of(body) == 'list')): + if sx_truthy(empty_p(body)): + return 'any' + else: + head = first(body) + head_name = (symbol_name(head) if sx_truthy((type_of(head) == 'symbol')) else sx_str(head)) + if sx_truthy((head_name == 'union')): + return cons('or', map(normalize_type_body, rest(body))) + else: + return cons(head_name, map(normalize_type_body, rest(body))) + else: + return sx_str(body) + +# sf-deftype +def sf_deftype(args, env): + name_or_form = first(args) + body_expr = nth(args, 1) + type_name = NIL + type_params = [] + if sx_truthy((type_of(name_or_form) == 'symbol')): + type_name = symbol_name(name_or_form) + else: + if sx_truthy((type_of(name_or_form) == 'list')): + type_name = symbol_name(first(name_or_form)) + type_params = map(lambda p: (symbol_name(p) if sx_truthy((type_of(p) == 'symbol')) else sx_str(p)), rest(name_or_form)) + body = normalize_type_body(body_expr) + registry = (env_get(env, '*type-registry*') if sx_truthy(env_has(env, '*type-registry*')) else {}) + registry[type_name] = make_type_def(type_name, type_params, body) + env['*type-registry*'] = registry + return NIL + +# sf-defeffect +def sf_defeffect(args, env): + effect_name = (symbol_name(first(args)) if sx_truthy((type_of(first(args)) == 'symbol')) else sx_str(first(args))) + registry = (env_get(env, '*effect-registry*') if sx_truthy(env_has(env, '*effect-registry*')) else []) + if sx_truthy((not sx_truthy(contains_p(registry, effect_name)))): + registry.append(effect_name) + env['*effect-registry*'] = registry + return NIL + +# sf-begin +def sf_begin(args, env): + if sx_truthy(empty_p(args)): + return NIL + else: + for e in slice(args, 0, (len(args) - 1)): + trampoline(eval_expr(e, env)) + return make_thunk(last(args), env) + +# sf-quote +def sf_quote(args, env): + if sx_truthy(empty_p(args)): + return NIL + else: + return first(args) + +# sf-quasiquote +def sf_quasiquote(args, env): + return qq_expand(first(args), env) + +# qq-expand +def qq_expand(template, env): + if sx_truthy((not sx_truthy((type_of(template) == 'list')))): + return template + else: + if sx_truthy(empty_p(template)): + return [] + else: + head = first(template) + if sx_truthy(((type_of(head) == 'symbol') if not sx_truthy((type_of(head) == 'symbol')) else (symbol_name(head) == 'unquote'))): + return trampoline(eval_expr(nth(template, 1), env)) + else: + return reduce(lambda result, item: ((lambda spliced: (concat(result, spliced) if sx_truthy((type_of(spliced) == 'list')) else (result if sx_truthy(is_nil(spliced)) else concat(result, [spliced]))))(trampoline(eval_expr(nth(item, 1), env))) if sx_truthy(((type_of(item) == 'list') if not sx_truthy((type_of(item) == 'list')) else ((len(item) == 2) if not sx_truthy((len(item) == 2)) else ((type_of(first(item)) == 'symbol') if not sx_truthy((type_of(first(item)) == 'symbol')) else (symbol_name(first(item)) == 'splice-unquote'))))) else concat(result, [qq_expand(item, env)])), [], template) + +# sf-thread-first +def sf_thread_first(args, env): + val = trampoline(eval_expr(first(args), env)) + return reduce(lambda result, form: ((lambda f: (lambda rest_args: (lambda all_args: (apply(f, all_args) if sx_truthy((is_callable(f) if not sx_truthy(is_callable(f)) else (not sx_truthy(is_lambda(f))))) else (trampoline(call_lambda(f, all_args, env)) if sx_truthy(is_lambda(f)) else error(sx_str('-> form not callable: ', inspect(f))))))(cons(result, rest_args)))(map(lambda a: trampoline(eval_expr(a, env)), rest(form))))(trampoline(eval_expr(first(form), env))) if sx_truthy((type_of(form) == 'list')) else (lambda f: (f(result) if sx_truthy((is_callable(f) if not sx_truthy(is_callable(f)) else (not sx_truthy(is_lambda(f))))) else (trampoline(call_lambda(f, [result], env)) if sx_truthy(is_lambda(f)) else error(sx_str('-> form not callable: ', inspect(f))))))(trampoline(eval_expr(form, env)))), val, rest(args)) + +# sf-set! +def sf_set_bang(args, env): + name = symbol_name(first(args)) + value = trampoline(eval_expr(nth(args, 1), env)) + env[name] = value + return value + +# sf-letrec +def sf_letrec(args, env): + bindings = first(args) + body = rest(args) + local = env_extend(env) + names = [] + val_exprs = [] + if sx_truthy(((type_of(first(bindings)) == 'list') if not sx_truthy((type_of(first(bindings)) == 'list')) else (len(first(bindings)) == 2))): + for binding in bindings: + vname = (symbol_name(first(binding)) if sx_truthy((type_of(first(binding)) == 'symbol')) else first(binding)) + names.append(vname) + val_exprs.append(nth(binding, 1)) + local[vname] = NIL + else: + reduce(lambda acc, pair_idx: (lambda vname: (lambda val_expr: _sx_begin(_sx_append(names, vname), _sx_append(val_exprs, val_expr), _sx_dict_set(local, vname, NIL)))(nth(bindings, ((pair_idx * 2) + 1))))((symbol_name(nth(bindings, (pair_idx * 2))) if sx_truthy((type_of(nth(bindings, (pair_idx * 2))) == 'symbol')) else nth(bindings, (pair_idx * 2)))), NIL, range(0, (len(bindings) / 2))) + values = map(lambda e: trampoline(eval_expr(e, local)), val_exprs) + for pair in zip(names, values): + local[first(pair)] = nth(pair, 1) + for val in values: + if sx_truthy(is_lambda(val)): + for n in names: + lambda_closure(val)[n] = env_get(local, n) + for e in slice(body, 0, (len(body) - 1)): + trampoline(eval_expr(e, local)) + return make_thunk(last(body), local) + +# sf-dynamic-wind +def sf_dynamic_wind(args, env): + before = trampoline(eval_expr(first(args), env)) + body = trampoline(eval_expr(nth(args, 1), env)) + after = trampoline(eval_expr(nth(args, 2), env)) + return dynamic_wind_call(before, body, after, env) + +# sf-scope +def sf_scope(args, env): + _cells = {} + name = trampoline(eval_expr(first(args), env)) + rest = slice(args, 1) + val = NIL + body_exprs = NIL + if sx_truthy(((len(rest) >= 2) if not sx_truthy((len(rest) >= 2)) else ((type_of(first(rest)) == 'keyword') if not sx_truthy((type_of(first(rest)) == 'keyword')) else (keyword_name(first(rest)) == 'value')))): + val = trampoline(eval_expr(nth(rest, 1), env)) + body_exprs = slice(rest, 2) + else: + body_exprs = rest + scope_push(name, val) + _cells['result'] = NIL + for e in body_exprs: + _cells['result'] = trampoline(eval_expr(e, env)) + scope_pop(name) + return _cells['result'] + +# sf-provide +def sf_provide(args, env): + _cells = {} + name = trampoline(eval_expr(first(args), env)) + val = trampoline(eval_expr(nth(args, 1), env)) + body_exprs = slice(args, 2) + _cells['result'] = NIL + scope_push(name, val) + for e in body_exprs: + _cells['result'] = trampoline(eval_expr(e, env)) + scope_pop(name) + return _cells['result'] + +# expand-macro +def expand_macro(mac, raw_args, env): + local = env_merge(macro_closure(mac), env) + for pair in map_indexed(lambda i, p: [p, i], macro_params(mac)): + local[first(pair)] = (nth(raw_args, nth(pair, 1)) if sx_truthy((nth(pair, 1) < len(raw_args))) else NIL) + if sx_truthy(macro_rest_param(mac)): + local[macro_rest_param(mac)] = slice(raw_args, len(macro_params(mac))) + return trampoline(eval_expr(macro_body(mac), local)) + +# call-fn +def call_fn(f, args, env): + if sx_truthy(is_lambda(f)): + return trampoline(call_lambda(f, args, env)) + elif sx_truthy(is_callable(f)): + return apply(f, args) + else: + return error(sx_str('Not callable in HO form: ', inspect(f))) + +# ho-map +def ho_map(args, env): + f = trampoline(eval_expr(first(args), env)) + coll = trampoline(eval_expr(nth(args, 1), env)) + return map(lambda item: call_fn(f, [item], env), coll) + +# ho-map-indexed +def ho_map_indexed(args, env): + f = trampoline(eval_expr(first(args), env)) + coll = trampoline(eval_expr(nth(args, 1), env)) + return map_indexed(lambda i, item: call_fn(f, [i, item], env), coll) + +# ho-filter +def ho_filter(args, env): + f = trampoline(eval_expr(first(args), env)) + coll = trampoline(eval_expr(nth(args, 1), env)) + return filter(lambda item: call_fn(f, [item], env), coll) + +# ho-reduce +def ho_reduce(args, env): + f = trampoline(eval_expr(first(args), env)) + init = trampoline(eval_expr(nth(args, 1), env)) + coll = trampoline(eval_expr(nth(args, 2), env)) + return reduce(lambda acc, item: call_fn(f, [acc, item], env), init, coll) + +# ho-some +def ho_some(args, env): + f = trampoline(eval_expr(first(args), env)) + coll = trampoline(eval_expr(nth(args, 1), env)) + return some(lambda item: call_fn(f, [item], env), coll) + +# ho-every +def ho_every(args, env): + f = trampoline(eval_expr(first(args), env)) + coll = trampoline(eval_expr(nth(args, 1), env)) + return every_p(lambda item: call_fn(f, [item], env), coll) + +# ho-for-each +def ho_for_each(args, env): + f = trampoline(eval_expr(first(args), env)) + coll = trampoline(eval_expr(nth(args, 1), env)) + for item in coll: + call_fn(f, [item], env) + return NIL + + # === Transpiled from forms (server definition forms) === # parse-key-params @@ -1369,6 +2074,374 @@ def validate_stream_data(data): return ((type_of(data) == 'list') if not sx_truthy((type_of(data) == 'list')) else every_p(lambda item: (type_of(item) == 'dict'), data)) +# === Transpiled from render (core) === + +# HTML_TAGS +HTML_TAGS = ['html', 'head', 'body', 'title', 'meta', 'link', 'script', 'style', 'noscript', 'header', 'nav', 'main', 'section', 'article', 'aside', 'footer', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hgroup', 'div', 'p', 'blockquote', 'pre', 'figure', 'figcaption', 'address', 'details', 'summary', 'a', 'span', 'em', 'strong', 'small', 'b', 'i', 'u', 's', 'mark', 'sub', 'sup', 'abbr', 'cite', 'code', 'time', 'br', 'wbr', 'hr', 'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'table', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td', 'caption', 'colgroup', 'col', 'form', 'input', 'textarea', 'select', 'option', 'optgroup', 'button', 'label', 'fieldset', 'legend', 'output', 'datalist', 'img', 'video', 'audio', 'source', 'picture', 'canvas', 'iframe', 'svg', 'math', 'path', 'circle', 'ellipse', 'rect', 'line', 'polyline', 'polygon', 'text', 'tspan', 'g', 'defs', 'use', 'clipPath', 'mask', 'pattern', 'linearGradient', 'radialGradient', 'stop', 'filter', 'feGaussianBlur', 'feOffset', 'feBlend', 'feColorMatrix', 'feComposite', 'feMerge', 'feMergeNode', 'feTurbulence', 'feComponentTransfer', 'feFuncR', 'feFuncG', 'feFuncB', 'feFuncA', 'feDisplacementMap', 'feFlood', 'feImage', 'feMorphology', 'feSpecularLighting', 'feDiffuseLighting', 'fePointLight', 'feSpotLight', 'feDistantLight', 'animate', 'animateTransform', 'foreignObject', 'template', 'slot', 'dialog', 'menu'] + +# VOID_ELEMENTS +VOID_ELEMENTS = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'] + +# BOOLEAN_ATTRS +BOOLEAN_ATTRS = ['async', 'autofocus', 'autoplay', 'checked', 'controls', 'default', 'defer', 'disabled', 'formnovalidate', 'hidden', 'inert', 'ismap', 'loop', 'multiple', 'muted', 'nomodule', 'novalidate', 'open', 'playsinline', 'readonly', 'required', 'reversed', 'selected'] + +# definition-form? +def is_definition_form(name): + return ((name == 'define') if sx_truthy((name == 'define')) else ((name == 'defcomp') if sx_truthy((name == 'defcomp')) else ((name == 'defisland') if sx_truthy((name == 'defisland')) else ((name == 'defmacro') if sx_truthy((name == 'defmacro')) else ((name == 'defstyle') if sx_truthy((name == 'defstyle')) else ((name == 'defhandler') if sx_truthy((name == 'defhandler')) else ((name == 'deftype') if sx_truthy((name == 'deftype')) else (name == 'defeffect')))))))) + +# parse-element-args +def parse_element_args(args, env): + attrs = {} + children = [] + reduce(lambda state, arg: (lambda skip: (assoc(state, 'skip', False, 'i', (get(state, 'i') + 1)) if sx_truthy(skip) else ((lambda val: _sx_begin(_sx_dict_set(attrs, keyword_name(arg), val), assoc(state, 'skip', True, 'i', (get(state, 'i') + 1))))(trampoline(eval_expr(nth(args, (get(state, 'i') + 1)), env))) if sx_truthy(((type_of(arg) == 'keyword') if not sx_truthy((type_of(arg) == 'keyword')) else ((get(state, 'i') + 1) < len(args)))) else _sx_begin(_sx_append(children, arg), assoc(state, 'i', (get(state, 'i') + 1))))))(get(state, 'skip')), {'i': 0, 'skip': False}, args) + return [attrs, children] + +# render-attrs +def render_attrs(attrs): + return join('', map(lambda key: (lambda val: (sx_str(' ', key) if sx_truthy((contains_p(BOOLEAN_ATTRS, key) if not sx_truthy(contains_p(BOOLEAN_ATTRS, key)) else val)) else ('' if sx_truthy((contains_p(BOOLEAN_ATTRS, key) if not sx_truthy(contains_p(BOOLEAN_ATTRS, key)) else (not sx_truthy(val)))) else ('' if sx_truthy(is_nil(val)) else sx_str(' ', key, '="', escape_attr(sx_str(val)), '"')))))(dict_get(attrs, key)), keys(attrs))) + +# eval-cond +def eval_cond(clauses, env): + if sx_truthy(cond_scheme_p(clauses)): + return eval_cond_scheme(clauses, env) + else: + return eval_cond_clojure(clauses, env) + +# eval-cond-scheme +def eval_cond_scheme(clauses, env): + if sx_truthy(empty_p(clauses)): + return NIL + else: + clause = first(clauses) + test = first(clause) + body = nth(clause, 1) + if sx_truthy((((type_of(test) == 'symbol') if not sx_truthy((type_of(test) == 'symbol')) else ((symbol_name(test) == 'else') if sx_truthy((symbol_name(test) == 'else')) else (symbol_name(test) == ':else'))) if sx_truthy(((type_of(test) == 'symbol') if not sx_truthy((type_of(test) == 'symbol')) else ((symbol_name(test) == 'else') if sx_truthy((symbol_name(test) == 'else')) else (symbol_name(test) == ':else')))) else ((type_of(test) == 'keyword') if not sx_truthy((type_of(test) == 'keyword')) else (keyword_name(test) == 'else')))): + return body + else: + if sx_truthy(trampoline(eval_expr(test, env))): + return body + else: + return eval_cond_scheme(rest(clauses), env) + +# eval-cond-clojure +def eval_cond_clojure(clauses, env): + if sx_truthy((len(clauses) < 2)): + return NIL + else: + test = first(clauses) + body = nth(clauses, 1) + if sx_truthy((((type_of(test) == 'keyword') if not sx_truthy((type_of(test) == 'keyword')) else (keyword_name(test) == 'else')) if sx_truthy(((type_of(test) == 'keyword') if not sx_truthy((type_of(test) == 'keyword')) else (keyword_name(test) == 'else'))) else ((type_of(test) == 'symbol') if not sx_truthy((type_of(test) == 'symbol')) else ((symbol_name(test) == 'else') if sx_truthy((symbol_name(test) == 'else')) else (symbol_name(test) == ':else'))))): + return body + else: + if sx_truthy(trampoline(eval_expr(test, env))): + return body + else: + return eval_cond_clojure(slice(clauses, 2), env) + +# process-bindings +def process_bindings(bindings, env): + local = env_extend(env) + for pair in bindings: + if sx_truthy(((type_of(pair) == 'list') if not sx_truthy((type_of(pair) == 'list')) else (len(pair) >= 2))): + name = (symbol_name(first(pair)) if sx_truthy((type_of(first(pair)) == 'symbol')) else sx_str(first(pair))) + local[name] = trampoline(eval_expr(nth(pair, 1), local)) + return local + +# is-render-expr? +def is_render_expr(expr): + if sx_truthy(((not sx_truthy((type_of(expr) == 'list'))) if sx_truthy((not sx_truthy((type_of(expr) == 'list')))) else empty_p(expr))): + return False + else: + h = first(expr) + if sx_truthy((not sx_truthy((type_of(h) == 'symbol')))): + return False + else: + n = symbol_name(h) + return ((n == '<>') if sx_truthy((n == '<>')) else ((n == 'raw!') if sx_truthy((n == 'raw!')) else (starts_with_p(n, '~') if sx_truthy(starts_with_p(n, '~')) else (starts_with_p(n, 'html:') if sx_truthy(starts_with_p(n, 'html:')) else (contains_p(HTML_TAGS, n) if sx_truthy(contains_p(HTML_TAGS, n)) else ((index_of(n, '-') > 0) if not sx_truthy((index_of(n, '-') > 0)) else ((len(expr) > 1) if not sx_truthy((len(expr) > 1)) else (type_of(nth(expr, 1)) == 'keyword')))))))) + +# merge-spread-attrs +def merge_spread_attrs(target, spread_dict): + for key in keys(spread_dict): + val = dict_get(spread_dict, key) + if sx_truthy((key == 'class')): + existing = dict_get(target, 'class') + target['class'] = (sx_str(existing, ' ', val) if sx_truthy((existing if not sx_truthy(existing) else (not sx_truthy((existing == ''))))) else val) + else: + if sx_truthy((key == 'style')): + existing = dict_get(target, 'style') + target['style'] = (sx_str(existing, ';', val) if sx_truthy((existing if not sx_truthy(existing) else (not sx_truthy((existing == ''))))) else val) + else: + target[key] = val + return NIL + + +# === Transpiled from parser === + +# sx-parse +def sx_parse(source): + _cells = {} + _cells['pos'] = 0 + len_src = len(source) + def skip_comment(): + while True: + if sx_truthy(((_cells['pos'] < len_src) if not sx_truthy((_cells['pos'] < len_src)) else (not sx_truthy((nth(source, _cells['pos']) == '\n'))))): + _cells['pos'] = (_cells['pos'] + 1) + continue + break + def skip_ws(): + while True: + if sx_truthy((_cells['pos'] < len_src)): + ch = nth(source, _cells['pos']) + if sx_truthy(((ch == ' ') if sx_truthy((ch == ' ')) else ((ch == '\t') if sx_truthy((ch == '\t')) else ((ch == '\n') if sx_truthy((ch == '\n')) else (ch == '\r'))))): + _cells['pos'] = (_cells['pos'] + 1) + continue + elif sx_truthy((ch == ';')): + _cells['pos'] = (_cells['pos'] + 1) + skip_comment() + continue + else: + break + break + def hex_digit_value(ch): + return index_of('0123456789abcdef', lower(ch)) + def read_string(): + _cells['pos'] = (_cells['pos'] + 1) + _cells['buf'] = '' + while True: + if sx_truthy((_cells['pos'] >= len_src)): + error('Unterminated string') + break + else: + ch = nth(source, _cells['pos']) + if sx_truthy((ch == '"')): + _cells['pos'] = (_cells['pos'] + 1) + break + elif sx_truthy((ch == '\\')): + _cells['pos'] = (_cells['pos'] + 1) + esc = nth(source, _cells['pos']) + if sx_truthy((esc == 'u')): + _cells['pos'] = (_cells['pos'] + 1) + d0 = hex_digit_value(nth(source, _cells['pos'])) + _ = _sx_cell_set(_cells, 'pos', (_cells['pos'] + 1)) + d1 = hex_digit_value(nth(source, _cells['pos'])) + _ = _sx_cell_set(_cells, 'pos', (_cells['pos'] + 1)) + d2 = hex_digit_value(nth(source, _cells['pos'])) + _ = _sx_cell_set(_cells, 'pos', (_cells['pos'] + 1)) + d3 = hex_digit_value(nth(source, _cells['pos'])) + _ = _sx_cell_set(_cells, 'pos', (_cells['pos'] + 1)) + _cells['buf'] = sx_str(_cells['buf'], char_from_code(((d0 * 4096) + (d1 * 256)))) + continue + else: + _cells['buf'] = sx_str(_cells['buf'], ('\n' if sx_truthy((esc == 'n')) else ('\t' if sx_truthy((esc == 't')) else ('\r' if sx_truthy((esc == 'r')) else esc)))) + _cells['pos'] = (_cells['pos'] + 1) + continue + else: + _cells['buf'] = sx_str(_cells['buf'], ch) + _cells['pos'] = (_cells['pos'] + 1) + continue + return _cells['buf'] + def read_ident(): + start = _cells['pos'] + while True: + if sx_truthy(((_cells['pos'] < len_src) if not sx_truthy((_cells['pos'] < len_src)) else ident_char_p(nth(source, _cells['pos'])))): + _cells['pos'] = (_cells['pos'] + 1) + continue + break + return slice(source, start, _cells['pos']) + def read_keyword(): + _cells['pos'] = (_cells['pos'] + 1) + return make_keyword(read_ident()) + def read_number(): + start = _cells['pos'] + if sx_truthy(((_cells['pos'] < len_src) if not sx_truthy((_cells['pos'] < len_src)) else (nth(source, _cells['pos']) == '-'))): + _cells['pos'] = (_cells['pos'] + 1) + def read_digits(): + while True: + if sx_truthy(((_cells['pos'] < len_src) if not sx_truthy((_cells['pos'] < len_src)) else (lambda c: ((c >= '0') if not sx_truthy((c >= '0')) else (c <= '9')))(nth(source, _cells['pos'])))): + _cells['pos'] = (_cells['pos'] + 1) + continue + break + read_digits() + if sx_truthy(((_cells['pos'] < len_src) if not sx_truthy((_cells['pos'] < len_src)) else (nth(source, _cells['pos']) == '.'))): + _cells['pos'] = (_cells['pos'] + 1) + read_digits() + if sx_truthy(((_cells['pos'] < len_src) if not sx_truthy((_cells['pos'] < len_src)) else ((nth(source, _cells['pos']) == 'e') if sx_truthy((nth(source, _cells['pos']) == 'e')) else (nth(source, _cells['pos']) == 'E')))): + _cells['pos'] = (_cells['pos'] + 1) + if sx_truthy(((_cells['pos'] < len_src) if not sx_truthy((_cells['pos'] < len_src)) else ((nth(source, _cells['pos']) == '+') if sx_truthy((nth(source, _cells['pos']) == '+')) else (nth(source, _cells['pos']) == '-')))): + _cells['pos'] = (_cells['pos'] + 1) + read_digits() + return parse_number(slice(source, start, _cells['pos'])) + def read_symbol(): + name = read_ident() + if sx_truthy((name == 'true')): + return True + elif sx_truthy((name == 'false')): + return False + elif sx_truthy((name == 'nil')): + return NIL + else: + return make_symbol(name) + def read_list(close_ch): + items = [] + while True: + skip_ws() + if sx_truthy((_cells['pos'] >= len_src)): + error('Unterminated list') + break + else: + if sx_truthy((nth(source, _cells['pos']) == close_ch)): + _cells['pos'] = (_cells['pos'] + 1) + break + else: + items.append(read_expr()) + continue + return items + def read_map(): + result = {} + while True: + skip_ws() + if sx_truthy((_cells['pos'] >= len_src)): + error('Unterminated map') + break + else: + if sx_truthy((nth(source, _cells['pos']) == '}')): + _cells['pos'] = (_cells['pos'] + 1) + break + else: + key_expr = read_expr() + key_str = (keyword_name(key_expr) if sx_truthy((type_of(key_expr) == 'keyword')) else sx_str(key_expr)) + val_expr = read_expr() + result[key_str] = val_expr + continue + return result + def read_raw_string(): + _cells['buf'] = '' + while True: + if sx_truthy((_cells['pos'] >= len_src)): + error('Unterminated raw string') + break + else: + ch = nth(source, _cells['pos']) + if sx_truthy((ch == '|')): + _cells['pos'] = (_cells['pos'] + 1) + break + else: + _cells['buf'] = sx_str(_cells['buf'], ch) + _cells['pos'] = (_cells['pos'] + 1) + continue + return _cells['buf'] + def read_expr(): + skip_ws() + if sx_truthy((_cells['pos'] >= len_src)): + return error('Unexpected end of input') + else: + ch = nth(source, _cells['pos']) + if sx_truthy((ch == '(')): + _cells['pos'] = (_cells['pos'] + 1) + return read_list(')') + elif sx_truthy((ch == '[')): + _cells['pos'] = (_cells['pos'] + 1) + return read_list(']') + elif sx_truthy((ch == '{')): + _cells['pos'] = (_cells['pos'] + 1) + return read_map() + elif sx_truthy((ch == '"')): + return read_string() + elif sx_truthy((ch == ':')): + return read_keyword() + elif sx_truthy((ch == "'")): + _cells['pos'] = (_cells['pos'] + 1) + return [make_symbol('quote'), read_expr()] + elif sx_truthy((ch == '`')): + _cells['pos'] = (_cells['pos'] + 1) + return [make_symbol('quasiquote'), read_expr()] + elif sx_truthy((ch == ',')): + _cells['pos'] = (_cells['pos'] + 1) + if sx_truthy(((_cells['pos'] < len_src) if not sx_truthy((_cells['pos'] < len_src)) else (nth(source, _cells['pos']) == '@'))): + _cells['pos'] = (_cells['pos'] + 1) + return [make_symbol('splice-unquote'), read_expr()] + else: + return [make_symbol('unquote'), read_expr()] + elif sx_truthy((ch == '#')): + _cells['pos'] = (_cells['pos'] + 1) + if sx_truthy((_cells['pos'] >= len_src)): + return error('Unexpected end of input after #') + else: + dispatch_ch = nth(source, _cells['pos']) + if sx_truthy((dispatch_ch == ';')): + _cells['pos'] = (_cells['pos'] + 1) + read_expr() + return read_expr() + elif sx_truthy((dispatch_ch == '|')): + _cells['pos'] = (_cells['pos'] + 1) + return read_raw_string() + elif sx_truthy((dispatch_ch == "'")): + _cells['pos'] = (_cells['pos'] + 1) + return [make_symbol('quote'), read_expr()] + elif sx_truthy(ident_start_p(dispatch_ch)): + macro_name = read_ident() + handler = reader_macro_get(macro_name) + if sx_truthy(handler): + return handler(read_expr()) + else: + return error(sx_str('Unknown reader macro: #', macro_name)) + else: + return error(sx_str('Unknown reader macro: #', dispatch_ch)) + elif sx_truthy((((ch >= '0') if not sx_truthy((ch >= '0')) else (ch <= '9')) if sx_truthy(((ch >= '0') if not sx_truthy((ch >= '0')) else (ch <= '9'))) else ((ch == '-') if not sx_truthy((ch == '-')) else (((_cells['pos'] + 1) < len_src) if not sx_truthy(((_cells['pos'] + 1) < len_src)) else (lambda next_ch: ((next_ch >= '0') if not sx_truthy((next_ch >= '0')) else (next_ch <= '9')))(nth(source, (_cells['pos'] + 1))))))): + return read_number() + elif sx_truthy(((ch == '.') if not sx_truthy((ch == '.')) else (((_cells['pos'] + 2) < len_src) if not sx_truthy(((_cells['pos'] + 2) < len_src)) else ((nth(source, (_cells['pos'] + 1)) == '.') if not sx_truthy((nth(source, (_cells['pos'] + 1)) == '.')) else (nth(source, (_cells['pos'] + 2)) == '.'))))): + _cells['pos'] = (_cells['pos'] + 3) + return make_symbol('...') + elif sx_truthy(ident_start_p(ch)): + return read_symbol() + else: + return error(sx_str('Unexpected character: ', ch)) + exprs = [] + while True: + skip_ws() + if sx_truthy((_cells['pos'] < len_src)): + exprs.append(read_expr()) + continue + break + return exprs + +# sx-serialize +def sx_serialize(val): + _match = type_of(val) + if _match == 'nil': + return 'nil' + elif _match == 'boolean': + if sx_truthy(val): + return 'true' + else: + return 'false' + elif _match == 'number': + return sx_str(val) + elif _match == 'string': + return sx_str('"', escape_string(val), '"') + elif _match == 'symbol': + return symbol_name(val) + elif _match == 'keyword': + return sx_str(':', keyword_name(val)) + elif _match == 'list': + return sx_str('(', join(' ', map(sx_serialize, val)), ')') + elif _match == 'dict': + return sx_serialize_dict(val) + elif _match == 'sx-expr': + return sx_expr_source(val) + elif _match == 'spread': + return sx_str('(make-spread ', sx_serialize_dict(spread_attrs(val)), ')') + else: + return sx_str(val) + +# sx-serialize-dict +def sx_serialize_dict(d): + return sx_str('{', join(' ', reduce(lambda acc, key: concat(acc, [sx_str(':', key), sx_serialize(dict_get(d, key))]), [], keys(d))), '}') + +# serialize +serialize = sx_serialize + + # === Transpiled from adapter-html === # render-to-html @@ -2116,6 +3189,201 @@ def env_components(env): return filter(lambda k: (lambda v: (is_component(v) if sx_truthy(is_component(v)) else is_macro(v)))(env_get(env, k)), keys(env)) +# === Transpiled from frames (CEK continuation frames) === + +# make-cek-state +def make_cek_state(control, env, kont): + return {'control': control, 'env': env, 'kont': kont, 'phase': 'eval', 'value': NIL} + +# make-cek-value +def make_cek_value(value, env, kont): + return {'control': NIL, 'env': env, 'kont': kont, 'phase': 'continue', 'value': value} + +# cek-terminal? +def cek_terminal_p(state): + return ((get(state, 'phase') == 'continue') if not sx_truthy((get(state, 'phase') == 'continue')) else empty_p(get(state, 'kont'))) + +# cek-control +def cek_control(s): + return get(s, 'control') + +# cek-env +def cek_env(s): + return get(s, 'env') + +# cek-kont +def cek_kont(s): + return get(s, 'kont') + +# cek-phase +def cek_phase(s): + return get(s, 'phase') + +# cek-value +def cek_value(s): + return get(s, 'value') + +# make-if-frame +def make_if_frame(then_expr, else_expr, env): + return {'type': 'if', 'then': then_expr, 'else': else_expr, 'env': env} + +# make-when-frame +def make_when_frame(body_exprs, env): + return {'type': 'when', 'body': body_exprs, 'env': env} + +# make-begin-frame +def make_begin_frame(remaining, env): + return {'type': 'begin', 'remaining': remaining, 'env': env} + +# make-let-frame +def make_let_frame(name, remaining, body, local): + return {'type': 'let', 'name': name, 'remaining': remaining, 'body': body, 'env': local} + +# make-define-frame +def make_define_frame(name, env, has_effects, effect_list): + return {'type': 'define', 'name': name, 'env': env, 'has-effects': has_effects, 'effect-list': effect_list} + +# make-set-frame +def make_set_frame(name, env): + return {'type': 'set', 'name': name, 'env': env} + +# make-arg-frame +def make_arg_frame(f, evaled, remaining, env, raw_args): + return {'type': 'arg', 'f': f, 'evaled': evaled, 'remaining': remaining, 'env': env, 'raw-args': raw_args} + +# make-call-frame +def make_call_frame(f, args, env): + return {'type': 'call', 'f': f, 'args': args, 'env': env} + +# make-cond-frame +def make_cond_frame(remaining, env, scheme_p): + return {'type': 'cond', 'remaining': remaining, 'env': env, 'scheme': scheme_p} + +# make-case-frame +def make_case_frame(match_val, remaining, env): + return {'type': 'case', 'match-val': match_val, 'remaining': remaining, 'env': env} + +# make-thread-frame +def make_thread_frame(remaining, env): + return {'type': 'thread', 'remaining': remaining, 'env': env} + +# make-map-frame +def make_map_frame(f, remaining, results, env): + return {'type': 'map', 'f': f, 'remaining': remaining, 'results': results, 'env': env, 'indexed': False} + +# make-map-indexed-frame +def make_map_indexed_frame(f, remaining, results, env): + return {'type': 'map', 'f': f, 'remaining': remaining, 'results': results, 'env': env, 'indexed': True} + +# make-filter-frame +def make_filter_frame(f, remaining, results, current_item, env): + return {'type': 'filter', 'f': f, 'remaining': remaining, 'results': results, 'current-item': current_item, 'env': env} + +# make-reduce-frame +def make_reduce_frame(f, remaining, env): + return {'type': 'reduce', 'f': f, 'remaining': remaining, 'env': env} + +# make-for-each-frame +def make_for_each_frame(f, remaining, env): + return {'type': 'for-each', 'f': f, 'remaining': remaining, 'env': env} + +# make-some-frame +def make_some_frame(f, remaining, env): + return {'type': 'some', 'f': f, 'remaining': remaining, 'env': env} + +# make-every-frame +def make_every_frame(f, remaining, env): + return {'type': 'every', 'f': f, 'remaining': remaining, 'env': env} + +# make-scope-frame +def make_scope_frame(name, remaining, env): + return {'type': 'scope', 'name': name, 'remaining': remaining, 'env': env} + +# make-reset-frame +def make_reset_frame(env): + return {'type': 'reset', 'env': env} + +# make-dict-frame +def make_dict_frame(remaining, results, env): + return {'type': 'dict', 'remaining': remaining, 'results': results, 'env': env} + +# make-and-frame +def make_and_frame(remaining, env): + return {'type': 'and', 'remaining': remaining, 'env': env} + +# make-or-frame +def make_or_frame(remaining, env): + return {'type': 'or', 'remaining': remaining, 'env': env} + +# make-dynamic-wind-frame +def make_dynamic_wind_frame(phase, body_thunk, after_thunk, env): + return {'type': 'dynamic-wind', 'phase': phase, 'body-thunk': body_thunk, 'after-thunk': after_thunk, 'env': env} + +# make-reactive-reset-frame +def make_reactive_reset_frame(env, update_fn, first_render_p): + return {'type': 'reactive-reset', 'env': env, 'update-fn': update_fn, 'first-render': first_render_p} + +# make-deref-frame +def make_deref_frame(env): + return {'type': 'deref', 'env': env} + +# frame-type +def frame_type(f): + return get(f, 'type') + +# kont-push +def kont_push(frame, kont): + return cons(frame, kont) + +# kont-top +def kont_top(kont): + return first(kont) + +# kont-pop +def kont_pop(kont): + return rest(kont) + +# kont-empty? +def kont_empty_p(kont): + return empty_p(kont) + +# kont-capture-to-reset +def kont_capture_to_reset(kont): + def scan(k, captured): + if sx_truthy(empty_p(k)): + return error('shift without enclosing reset') + else: + frame = first(k) + if sx_truthy(((frame_type(frame) == 'reset') if sx_truthy((frame_type(frame) == 'reset')) else (frame_type(frame) == 'reactive-reset'))): + return [captured, rest(k)] + else: + return scan(rest(k), append(captured, [frame])) + return scan(kont, []) + +# has-reactive-reset-frame? +def has_reactive_reset_frame_p(kont): + if sx_truthy(empty_p(kont)): + return False + else: + if sx_truthy((frame_type(first(kont)) == 'reactive-reset')): + return True + else: + return has_reactive_reset_frame_p(rest(kont)) + +# kont-capture-to-reactive-reset +def kont_capture_to_reactive_reset(kont): + def scan(k, captured): + if sx_truthy(empty_p(k)): + return error('reactive deref without enclosing reactive-reset') + else: + frame = first(k) + if sx_truthy((frame_type(frame) == 'reactive-reset')): + return [captured, frame, rest(k)] + else: + return scan(rest(k), append(captured, [frame])) + return scan(kont, []) + + # === Transpiled from page-helpers (pure data transformation helpers) === # special-form-category-map @@ -2614,6 +3882,822 @@ def prepare_url_expr(url_path, env): return auto_quote_unknowns(expr, env) +# === Transpiled from cek (explicit CEK machine evaluator) === + +# cek-run +def cek_run(state): + if sx_truthy(cek_terminal_p(state)): + return cek_value(state) + else: + return cek_run(cek_step(state)) + +# cek-step +def cek_step(state): + if sx_truthy((cek_phase(state) == 'eval')): + return step_eval(state) + else: + return step_continue(state) + +# step-eval +def step_eval(state): + expr = cek_control(state) + env = cek_env(state) + kont = cek_kont(state) + _match = type_of(expr) + if _match == 'number': + return make_cek_value(expr, env, kont) + elif _match == 'string': + return make_cek_value(expr, env, kont) + elif _match == 'boolean': + return make_cek_value(expr, env, kont) + elif _match == 'nil': + return make_cek_value(NIL, env, kont) + elif _match == 'symbol': + name = symbol_name(expr) + val = (env_get(env, name) if sx_truthy(env_has(env, name)) else (get_primitive(name) if sx_truthy(is_primitive(name)) else (True if sx_truthy((name == 'true')) else (False if sx_truthy((name == 'false')) else (NIL if sx_truthy((name == 'nil')) else error(sx_str('Undefined symbol: ', name))))))) + return make_cek_value(val, env, kont) + elif _match == 'keyword': + return make_cek_value(keyword_name(expr), env, kont) + elif _match == 'dict': + ks = keys(expr) + if sx_truthy(empty_p(ks)): + return make_cek_value({}, env, kont) + else: + first_key = first(ks) + remaining_entries = [] + for k in rest(ks): + remaining_entries.append([k, get(expr, k)]) + return make_cek_state(get(expr, first_key), env, kont_push(make_dict_frame(remaining_entries, [[first_key]], env), kont)) + elif _match == 'list': + if sx_truthy(empty_p(expr)): + return make_cek_value([], env, kont) + else: + return step_eval_list(expr, env, kont) + else: + return make_cek_value(expr, env, kont) + +# step-eval-list +def step_eval_list(expr, env, kont): + head = first(expr) + args = rest(expr) + if sx_truthy((not sx_truthy(((type_of(head) == 'symbol') if sx_truthy((type_of(head) == 'symbol')) else ((type_of(head) == 'lambda') if sx_truthy((type_of(head) == 'lambda')) else (type_of(head) == 'list')))))): + if sx_truthy(empty_p(expr)): + return make_cek_value([], env, kont) + else: + return make_cek_state(first(expr), env, kont_push(make_map_frame(NIL, rest(expr), [], env), kont)) + else: + if sx_truthy((type_of(head) == 'symbol')): + name = symbol_name(head) + if sx_truthy((name == 'if')): + return step_sf_if(args, env, kont) + elif sx_truthy((name == 'when')): + return step_sf_when(args, env, kont) + elif sx_truthy((name == 'cond')): + return step_sf_cond(args, env, kont) + elif sx_truthy((name == 'case')): + return step_sf_case(args, env, kont) + elif sx_truthy((name == 'and')): + return step_sf_and(args, env, kont) + elif sx_truthy((name == 'or')): + return step_sf_or(args, env, kont) + elif sx_truthy((name == 'let')): + return step_sf_let(args, env, kont) + elif sx_truthy((name == 'let*')): + return step_sf_let(args, env, kont) + elif sx_truthy((name == 'lambda')): + return step_sf_lambda(args, env, kont) + elif sx_truthy((name == 'fn')): + return step_sf_lambda(args, env, kont) + elif sx_truthy((name == 'define')): + return step_sf_define(args, env, kont) + elif sx_truthy((name == 'defcomp')): + return make_cek_value(sf_defcomp(args, env), env, kont) + elif sx_truthy((name == 'defisland')): + return make_cek_value(sf_defisland(args, env), env, kont) + elif sx_truthy((name == 'defmacro')): + return make_cek_value(sf_defmacro(args, env), env, kont) + elif sx_truthy((name == 'defstyle')): + return make_cek_value(sf_defstyle(args, env), env, kont) + elif sx_truthy((name == 'defhandler')): + return make_cek_value(sf_defhandler(args, env), env, kont) + elif sx_truthy((name == 'defpage')): + return make_cek_value(sf_defpage(args, env), env, kont) + elif sx_truthy((name == 'defquery')): + return make_cek_value(sf_defquery(args, env), env, kont) + elif sx_truthy((name == 'defaction')): + return make_cek_value(sf_defaction(args, env), env, kont) + elif sx_truthy((name == 'deftype')): + return make_cek_value(sf_deftype(args, env), env, kont) + elif sx_truthy((name == 'defeffect')): + return make_cek_value(sf_defeffect(args, env), env, kont) + elif sx_truthy((name == 'begin')): + return step_sf_begin(args, env, kont) + elif sx_truthy((name == 'do')): + return step_sf_begin(args, env, kont) + elif sx_truthy((name == 'quote')): + return make_cek_value((NIL if sx_truthy(empty_p(args)) else first(args)), env, kont) + elif sx_truthy((name == 'quasiquote')): + return make_cek_value(qq_expand(first(args), env), env, kont) + elif sx_truthy((name == '->')): + return step_sf_thread_first(args, env, kont) + elif sx_truthy((name == 'set!')): + return step_sf_set_b(args, env, kont) + elif sx_truthy((name == 'letrec')): + return make_cek_value(sf_letrec(args, env), env, kont) + elif sx_truthy((name == 'reset')): + return step_sf_reset(args, env, kont) + elif sx_truthy((name == 'shift')): + return step_sf_shift(args, env, kont) + elif sx_truthy((name == 'deref')): + return step_sf_deref(args, env, kont) + elif sx_truthy((name == 'scope')): + return step_sf_scope(args, env, kont) + elif sx_truthy((name == 'provide')): + return step_sf_provide(args, env, kont) + elif sx_truthy((name == 'dynamic-wind')): + return make_cek_value(sf_dynamic_wind(args, env), env, kont) + elif sx_truthy((name == 'map')): + return step_ho_map(args, env, kont) + elif sx_truthy((name == 'map-indexed')): + return step_ho_map_indexed(args, env, kont) + elif sx_truthy((name == 'filter')): + return step_ho_filter(args, env, kont) + elif sx_truthy((name == 'reduce')): + return step_ho_reduce(args, env, kont) + elif sx_truthy((name == 'some')): + return step_ho_some(args, env, kont) + elif sx_truthy((name == 'every?')): + return step_ho_every(args, env, kont) + elif sx_truthy((name == 'for-each')): + return step_ho_for_each(args, env, kont) + elif sx_truthy((env_has(env, name) if not sx_truthy(env_has(env, name)) else is_macro(env_get(env, name)))): + mac = env_get(env, name) + return make_cek_state(expand_macro(mac, args, env), env, kont) + elif sx_truthy((render_active_p() if not sx_truthy(render_active_p()) else is_render_expr(expr))): + return make_cek_value(render_expr(expr, env), env, kont) + else: + return step_eval_call(head, args, env, kont) + else: + return step_eval_call(head, args, env, kont) + +# step-sf-if +def step_sf_if(args, env, kont): + return make_cek_state(first(args), env, kont_push(make_if_frame(nth(args, 1), (nth(args, 2) if sx_truthy((len(args) > 2)) else NIL), env), kont)) + +# step-sf-when +def step_sf_when(args, env, kont): + return make_cek_state(first(args), env, kont_push(make_when_frame(rest(args), env), kont)) + +# step-sf-begin +def step_sf_begin(args, env, kont): + if sx_truthy(empty_p(args)): + return make_cek_value(NIL, env, kont) + else: + if sx_truthy((len(args) == 1)): + return make_cek_state(first(args), env, kont) + else: + return make_cek_state(first(args), env, kont_push(make_begin_frame(rest(args), env), kont)) + +# step-sf-let +def step_sf_let(args, env, kont): + if sx_truthy((type_of(first(args)) == 'symbol')): + return make_cek_value(sf_named_let(args, env), env, kont) + else: + bindings = first(args) + body = rest(args) + local = env_extend(env) + if sx_truthy(empty_p(bindings)): + return step_sf_begin(body, local, kont) + else: + first_binding = (first(bindings) if sx_truthy(((type_of(first(bindings)) == 'list') if not sx_truthy((type_of(first(bindings)) == 'list')) else (len(first(bindings)) == 2))) else [first(bindings), nth(bindings, 1)]) + rest_bindings = (rest(bindings) if sx_truthy(((type_of(first(bindings)) == 'list') if not sx_truthy((type_of(first(bindings)) == 'list')) else (len(first(bindings)) == 2))) else (lambda pairs: _sx_begin(reduce(lambda acc, i: _sx_append(pairs, [nth(bindings, (i * 2)), nth(bindings, ((i * 2) + 1))]), NIL, range(1, (len(bindings) / 2))), pairs))([])) + vname = (symbol_name(first(first_binding)) if sx_truthy((type_of(first(first_binding)) == 'symbol')) else first(first_binding)) + return make_cek_state(nth(first_binding, 1), local, kont_push(make_let_frame(vname, rest_bindings, body, local), kont)) + +# step-sf-define +def step_sf_define(args, env, kont): + name_sym = first(args) + has_effects = ((len(args) >= 4) if not sx_truthy((len(args) >= 4)) else ((type_of(nth(args, 1)) == 'keyword') if not sx_truthy((type_of(nth(args, 1)) == 'keyword')) else (keyword_name(nth(args, 1)) == 'effects'))) + val_idx = (3 if sx_truthy(((len(args) >= 4) if not sx_truthy((len(args) >= 4)) else ((type_of(nth(args, 1)) == 'keyword') if not sx_truthy((type_of(nth(args, 1)) == 'keyword')) else (keyword_name(nth(args, 1)) == 'effects')))) else 1) + effect_list = (nth(args, 2) if sx_truthy(((len(args) >= 4) if not sx_truthy((len(args) >= 4)) else ((type_of(nth(args, 1)) == 'keyword') if not sx_truthy((type_of(nth(args, 1)) == 'keyword')) else (keyword_name(nth(args, 1)) == 'effects')))) else NIL) + return make_cek_state(nth(args, val_idx), env, kont_push(make_define_frame(symbol_name(name_sym), env, has_effects, effect_list), kont)) + +# step-sf-set! +def step_sf_set_b(args, env, kont): + return make_cek_state(nth(args, 1), env, kont_push(make_set_frame(symbol_name(first(args)), env), kont)) + +# step-sf-and +def step_sf_and(args, env, kont): + if sx_truthy(empty_p(args)): + return make_cek_value(True, env, kont) + else: + return make_cek_state(first(args), env, kont_push(make_and_frame(rest(args), env), kont)) + +# step-sf-or +def step_sf_or(args, env, kont): + if sx_truthy(empty_p(args)): + return make_cek_value(False, env, kont) + else: + return make_cek_state(first(args), env, kont_push(make_or_frame(rest(args), env), kont)) + +# step-sf-cond +def step_sf_cond(args, env, kont): + scheme_p = cond_scheme_p(args) + if sx_truthy(scheme_p): + if sx_truthy(empty_p(args)): + return make_cek_value(NIL, env, kont) + else: + clause = first(args) + test = first(clause) + if sx_truthy((((type_of(test) == 'symbol') if not sx_truthy((type_of(test) == 'symbol')) else ((symbol_name(test) == 'else') if sx_truthy((symbol_name(test) == 'else')) else (symbol_name(test) == ':else'))) if sx_truthy(((type_of(test) == 'symbol') if not sx_truthy((type_of(test) == 'symbol')) else ((symbol_name(test) == 'else') if sx_truthy((symbol_name(test) == 'else')) else (symbol_name(test) == ':else')))) else ((type_of(test) == 'keyword') if not sx_truthy((type_of(test) == 'keyword')) else (keyword_name(test) == 'else')))): + return make_cek_state(nth(clause, 1), env, kont) + else: + return make_cek_state(test, env, kont_push(make_cond_frame(args, env, True), kont)) + else: + if sx_truthy((len(args) < 2)): + return make_cek_value(NIL, env, kont) + else: + test = first(args) + if sx_truthy((((type_of(test) == 'keyword') if not sx_truthy((type_of(test) == 'keyword')) else (keyword_name(test) == 'else')) if sx_truthy(((type_of(test) == 'keyword') if not sx_truthy((type_of(test) == 'keyword')) else (keyword_name(test) == 'else'))) else ((type_of(test) == 'symbol') if not sx_truthy((type_of(test) == 'symbol')) else ((symbol_name(test) == 'else') if sx_truthy((symbol_name(test) == 'else')) else (symbol_name(test) == ':else'))))): + return make_cek_state(nth(args, 1), env, kont) + else: + return make_cek_state(test, env, kont_push(make_cond_frame(args, env, False), kont)) + +# step-sf-case +def step_sf_case(args, env, kont): + return make_cek_state(first(args), env, kont_push(make_case_frame(NIL, rest(args), env), kont)) + +# step-sf-thread-first +def step_sf_thread_first(args, env, kont): + return make_cek_state(first(args), env, kont_push(make_thread_frame(rest(args), env), kont)) + +# step-sf-lambda +def step_sf_lambda(args, env, kont): + return make_cek_value(sf_lambda(args, env), env, kont) + +# step-sf-scope +def step_sf_scope(args, env, kont): + return make_cek_value(sf_scope(args, env), env, kont) + +# step-sf-provide +def step_sf_provide(args, env, kont): + return make_cek_value(sf_provide(args, env), env, kont) + +# step-sf-reset +def step_sf_reset(args, env, kont): + return make_cek_state(first(args), env, kont_push(make_reset_frame(env), kont)) + +# step-sf-shift +def step_sf_shift(args, env, kont): + k_name = symbol_name(first(args)) + body = nth(args, 1) + captured_result = kont_capture_to_reset(kont) + captured = first(captured_result) + rest_kont = nth(captured_result, 1) + k = make_cek_continuation(captured, rest_kont) + shift_env = env_extend(env) + shift_env[k_name] = k + return make_cek_state(body, shift_env, rest_kont) + +# step-sf-deref +def step_sf_deref(args, env, kont): + return make_cek_state(first(args), env, kont_push(make_deref_frame(env), kont)) + +# cek-call +def cek_call(f, args): + a = ([] if sx_truthy(is_nil(args)) else args) + if sx_truthy(is_nil(f)): + return NIL + elif sx_truthy(is_lambda(f)): + return cek_run(continue_with_call(f, a, {}, a, [])) + elif sx_truthy(is_callable(f)): + return apply(f, a) + else: + return NIL + +# reactive-shift-deref +def reactive_shift_deref(sig, env, kont): + _cells = {} + scan_result = kont_capture_to_reactive_reset(kont) + captured_frames = first(scan_result) + reset_frame = nth(scan_result, 1) + remaining_kont = nth(scan_result, 2) + update_fn = get(reset_frame, 'update-fn') + _cells['sub_disposers'] = [] + subscriber = _sx_fn(lambda : ( + for_each(lambda d: cek_call(d, NIL), _cells['sub_disposers']), + _sx_cell_set(_cells, 'sub_disposers', []), + (lambda new_reset: (lambda new_kont: with_island_scope(lambda d: _sx_append(_cells['sub_disposers'], d), lambda : cek_run(make_cek_value(signal_value(sig), env, new_kont))))(concat(captured_frames, [new_reset], remaining_kont)))(make_reactive_reset_frame(env, update_fn, False)) +)[-1]) + signal_add_sub(sig, subscriber) + register_in_scope(_sx_fn(lambda : ( + signal_remove_sub(sig, subscriber), + for_each(lambda d: cek_call(d, NIL), _cells['sub_disposers']) +)[-1])) + initial_kont = concat(captured_frames, [reset_frame], remaining_kont) + return make_cek_value(signal_value(sig), env, initial_kont) + +# step-eval-call +def step_eval_call(head, args, env, kont): + return make_cek_state(head, env, kont_push(make_arg_frame(NIL, [], args, env, args), kont)) + +# step-ho-map +def step_ho_map(args, env, kont): + f = trampoline(eval_expr(first(args), env)) + coll = trampoline(eval_expr(nth(args, 1), env)) + if sx_truthy(empty_p(coll)): + return make_cek_value([], env, kont) + else: + return continue_with_call(f, [first(coll)], env, [], kont_push(make_map_frame(f, rest(coll), [], env), kont)) + +# step-ho-map-indexed +def step_ho_map_indexed(args, env, kont): + f = trampoline(eval_expr(first(args), env)) + coll = trampoline(eval_expr(nth(args, 1), env)) + if sx_truthy(empty_p(coll)): + return make_cek_value([], env, kont) + else: + return continue_with_call(f, [0, first(coll)], env, [], kont_push(make_map_indexed_frame(f, rest(coll), [], env), kont)) + +# step-ho-filter +def step_ho_filter(args, env, kont): + f = trampoline(eval_expr(first(args), env)) + coll = trampoline(eval_expr(nth(args, 1), env)) + if sx_truthy(empty_p(coll)): + return make_cek_value([], env, kont) + else: + return continue_with_call(f, [first(coll)], env, [], kont_push(make_filter_frame(f, rest(coll), [], first(coll), env), kont)) + +# step-ho-reduce +def step_ho_reduce(args, env, kont): + f = trampoline(eval_expr(first(args), env)) + init = trampoline(eval_expr(nth(args, 1), env)) + coll = trampoline(eval_expr(nth(args, 2), env)) + if sx_truthy(empty_p(coll)): + return make_cek_value(init, env, kont) + else: + return continue_with_call(f, [init, first(coll)], env, [], kont_push(make_reduce_frame(f, rest(coll), env), kont)) + +# step-ho-some +def step_ho_some(args, env, kont): + f = trampoline(eval_expr(first(args), env)) + coll = trampoline(eval_expr(nth(args, 1), env)) + if sx_truthy(empty_p(coll)): + return make_cek_value(False, env, kont) + else: + return continue_with_call(f, [first(coll)], env, [], kont_push(make_some_frame(f, rest(coll), env), kont)) + +# step-ho-every +def step_ho_every(args, env, kont): + f = trampoline(eval_expr(first(args), env)) + coll = trampoline(eval_expr(nth(args, 1), env)) + if sx_truthy(empty_p(coll)): + return make_cek_value(True, env, kont) + else: + return continue_with_call(f, [first(coll)], env, [], kont_push(make_every_frame(f, rest(coll), env), kont)) + +# step-ho-for-each +def step_ho_for_each(args, env, kont): + f = trampoline(eval_expr(first(args), env)) + coll = trampoline(eval_expr(nth(args, 1), env)) + if sx_truthy(empty_p(coll)): + return make_cek_value(NIL, env, kont) + else: + return continue_with_call(f, [first(coll)], env, [], kont_push(make_for_each_frame(f, rest(coll), env), kont)) + +# step-continue +def step_continue(state): + value = cek_value(state) + env = cek_env(state) + kont = cek_kont(state) + if sx_truthy(kont_empty_p(kont)): + return state + else: + frame = kont_top(kont) + rest_k = kont_pop(kont) + ft = frame_type(frame) + if sx_truthy((ft == 'if')): + if sx_truthy((value if not sx_truthy(value) else (not sx_truthy(is_nil(value))))): + return make_cek_state(get(frame, 'then'), get(frame, 'env'), rest_k) + else: + if sx_truthy(is_nil(get(frame, 'else'))): + return make_cek_value(NIL, env, rest_k) + else: + return make_cek_state(get(frame, 'else'), get(frame, 'env'), rest_k) + elif sx_truthy((ft == 'when')): + if sx_truthy((value if not sx_truthy(value) else (not sx_truthy(is_nil(value))))): + body = get(frame, 'body') + fenv = get(frame, 'env') + if sx_truthy(empty_p(body)): + return make_cek_value(NIL, fenv, rest_k) + else: + if sx_truthy((len(body) == 1)): + return make_cek_state(first(body), fenv, rest_k) + else: + return make_cek_state(first(body), fenv, kont_push(make_begin_frame(rest(body), fenv), rest_k)) + else: + return make_cek_value(NIL, env, rest_k) + elif sx_truthy((ft == 'begin')): + remaining = get(frame, 'remaining') + fenv = get(frame, 'env') + if sx_truthy(empty_p(remaining)): + return make_cek_value(value, fenv, rest_k) + else: + if sx_truthy((len(remaining) == 1)): + return make_cek_state(first(remaining), fenv, rest_k) + else: + return make_cek_state(first(remaining), fenv, kont_push(make_begin_frame(rest(remaining), fenv), rest_k)) + elif sx_truthy((ft == 'let')): + name = get(frame, 'name') + remaining = get(frame, 'remaining') + body = get(frame, 'body') + local = get(frame, 'env') + local[name] = value + if sx_truthy(empty_p(remaining)): + return step_sf_begin(body, local, rest_k) + else: + next_binding = first(remaining) + vname = (symbol_name(first(next_binding)) if sx_truthy((type_of(first(next_binding)) == 'symbol')) else first(next_binding)) + return make_cek_state(nth(next_binding, 1), local, kont_push(make_let_frame(vname, rest(remaining), body, local), rest_k)) + elif sx_truthy((ft == 'define')): + name = get(frame, 'name') + fenv = get(frame, 'env') + has_effects = get(frame, 'has-effects') + effect_list = get(frame, 'effect-list') + if sx_truthy((is_lambda(value) if not sx_truthy(is_lambda(value)) else is_nil(lambda_name(value)))): + value.name = name + fenv[name] = value + if sx_truthy(has_effects): + effect_names = (map(lambda e: (symbol_name(e) if sx_truthy((type_of(e) == 'symbol')) else sx_str(e)), effect_list) if sx_truthy((type_of(effect_list) == 'list')) else [sx_str(effect_list)]) + effect_anns = (env_get(fenv, '*effect-annotations*') if sx_truthy(env_has(fenv, '*effect-annotations*')) else {}) + effect_anns[name] = effect_names + fenv['*effect-annotations*'] = effect_anns + return make_cek_value(value, fenv, rest_k) + elif sx_truthy((ft == 'set')): + name = get(frame, 'name') + fenv = get(frame, 'env') + fenv[name] = value + return make_cek_value(value, env, rest_k) + elif sx_truthy((ft == 'and')): + if sx_truthy((not sx_truthy(value))): + return make_cek_value(value, env, rest_k) + else: + remaining = get(frame, 'remaining') + if sx_truthy(empty_p(remaining)): + return make_cek_value(value, env, rest_k) + else: + return make_cek_state(first(remaining), get(frame, 'env'), (rest_k if sx_truthy((len(remaining) == 1)) else kont_push(make_and_frame(rest(remaining), get(frame, 'env')), rest_k))) + elif sx_truthy((ft == 'or')): + if sx_truthy(value): + return make_cek_value(value, env, rest_k) + else: + remaining = get(frame, 'remaining') + if sx_truthy(empty_p(remaining)): + return make_cek_value(False, env, rest_k) + else: + return make_cek_state(first(remaining), get(frame, 'env'), (rest_k if sx_truthy((len(remaining) == 1)) else kont_push(make_or_frame(rest(remaining), get(frame, 'env')), rest_k))) + elif sx_truthy((ft == 'cond')): + remaining = get(frame, 'remaining') + fenv = get(frame, 'env') + scheme_p = get(frame, 'scheme') + if sx_truthy(scheme_p): + if sx_truthy(value): + return make_cek_state(nth(first(remaining), 1), fenv, rest_k) + else: + next_clauses = rest(remaining) + if sx_truthy(empty_p(next_clauses)): + return make_cek_value(NIL, fenv, rest_k) + else: + next_clause = first(next_clauses) + next_test = first(next_clause) + if sx_truthy((((type_of(next_test) == 'symbol') if not sx_truthy((type_of(next_test) == 'symbol')) else ((symbol_name(next_test) == 'else') if sx_truthy((symbol_name(next_test) == 'else')) else (symbol_name(next_test) == ':else'))) if sx_truthy(((type_of(next_test) == 'symbol') if not sx_truthy((type_of(next_test) == 'symbol')) else ((symbol_name(next_test) == 'else') if sx_truthy((symbol_name(next_test) == 'else')) else (symbol_name(next_test) == ':else')))) else ((type_of(next_test) == 'keyword') if not sx_truthy((type_of(next_test) == 'keyword')) else (keyword_name(next_test) == 'else')))): + return make_cek_state(nth(next_clause, 1), fenv, rest_k) + else: + return make_cek_state(next_test, fenv, kont_push(make_cond_frame(next_clauses, fenv, True), rest_k)) + else: + if sx_truthy(value): + return make_cek_state(nth(remaining, 1), fenv, rest_k) + else: + next = slice(remaining, 2) + if sx_truthy((len(next) < 2)): + return make_cek_value(NIL, fenv, rest_k) + else: + next_test = first(next) + if sx_truthy((((type_of(next_test) == 'keyword') if not sx_truthy((type_of(next_test) == 'keyword')) else (keyword_name(next_test) == 'else')) if sx_truthy(((type_of(next_test) == 'keyword') if not sx_truthy((type_of(next_test) == 'keyword')) else (keyword_name(next_test) == 'else'))) else ((type_of(next_test) == 'symbol') if not sx_truthy((type_of(next_test) == 'symbol')) else ((symbol_name(next_test) == 'else') if sx_truthy((symbol_name(next_test) == 'else')) else (symbol_name(next_test) == ':else'))))): + return make_cek_state(nth(next, 1), fenv, rest_k) + else: + return make_cek_state(next_test, fenv, kont_push(make_cond_frame(next, fenv, False), rest_k)) + elif sx_truthy((ft == 'case')): + match_val = get(frame, 'match-val') + remaining = get(frame, 'remaining') + fenv = get(frame, 'env') + if sx_truthy(is_nil(match_val)): + return sf_case_step_loop(value, remaining, fenv, rest_k) + else: + return sf_case_step_loop(match_val, remaining, fenv, rest_k) + elif sx_truthy((ft == 'thread')): + remaining = get(frame, 'remaining') + fenv = get(frame, 'env') + if sx_truthy(empty_p(remaining)): + return make_cek_value(value, fenv, rest_k) + else: + form = first(remaining) + rest_forms = rest(remaining) + result = ((lambda f: (lambda rargs: (lambda all_args: (apply(f, all_args) if sx_truthy((is_callable(f) if not sx_truthy(is_callable(f)) else (not sx_truthy(is_lambda(f))))) else (trampoline(call_lambda(f, all_args, fenv)) if sx_truthy(is_lambda(f)) else error(sx_str('-> form not callable: ', inspect(f))))))(cons(value, rargs)))(map(lambda a: trampoline(eval_expr(a, fenv)), rest(form))))(trampoline(eval_expr(first(form), fenv))) if sx_truthy((type_of(form) == 'list')) else (lambda f: (f(value) if sx_truthy((is_callable(f) if not sx_truthy(is_callable(f)) else (not sx_truthy(is_lambda(f))))) else (trampoline(call_lambda(f, [value], fenv)) if sx_truthy(is_lambda(f)) else error(sx_str('-> form not callable: ', inspect(f))))))(trampoline(eval_expr(form, fenv)))) + if sx_truthy(empty_p(rest_forms)): + return make_cek_value(result, fenv, rest_k) + else: + return make_cek_value(result, fenv, kont_push(make_thread_frame(rest_forms, fenv), rest_k)) + elif sx_truthy((ft == 'arg')): + f = get(frame, 'f') + evaled = get(frame, 'evaled') + remaining = get(frame, 'remaining') + fenv = get(frame, 'env') + raw_args = get(frame, 'raw-args') + if sx_truthy(is_nil(f)): + if sx_truthy(empty_p(remaining)): + return continue_with_call(value, [], fenv, raw_args, rest_k) + else: + return make_cek_state(first(remaining), fenv, kont_push(make_arg_frame(value, [], rest(remaining), fenv, raw_args), rest_k)) + else: + new_evaled = append(evaled, [value]) + if sx_truthy(empty_p(remaining)): + return continue_with_call(f, new_evaled, fenv, raw_args, rest_k) + else: + return make_cek_state(first(remaining), fenv, kont_push(make_arg_frame(f, new_evaled, rest(remaining), fenv, raw_args), rest_k)) + elif sx_truthy((ft == 'dict')): + remaining = get(frame, 'remaining') + results = get(frame, 'results') + fenv = get(frame, 'env') + last_result = last(results) + completed = append(slice(results, 0, (len(results) - 1)), [[first(last_result), value]]) + if sx_truthy(empty_p(remaining)): + d = {} + for pair in completed: + d[first(pair)] = nth(pair, 1) + return make_cek_value(d, fenv, rest_k) + else: + next_entry = first(remaining) + return make_cek_state(nth(next_entry, 1), fenv, kont_push(make_dict_frame(rest(remaining), append(completed, [[first(next_entry)]]), fenv), rest_k)) + elif sx_truthy((ft == 'reset')): + return make_cek_value(value, env, rest_k) + elif sx_truthy((ft == 'deref')): + val = value + fenv = get(frame, 'env') + if sx_truthy((not sx_truthy(is_signal(val)))): + return make_cek_value(val, fenv, rest_k) + else: + if sx_truthy(has_reactive_reset_frame_p(rest_k)): + return reactive_shift_deref(val, fenv, rest_k) + else: + ctx = sx_context('sx-reactive', NIL) + if sx_truthy(ctx): + dep_list = get(ctx, 'deps') + notify_fn = get(ctx, 'notify') + if sx_truthy((not sx_truthy(contains_p(dep_list, val)))): + dep_list.append(val) + signal_add_sub(val, notify_fn) + return make_cek_value(signal_value(val), fenv, rest_k) + elif sx_truthy((ft == 'reactive-reset')): + update_fn = get(frame, 'update-fn') + first_p = get(frame, 'first-render') + if sx_truthy((update_fn if not sx_truthy(update_fn) else (not sx_truthy(first_p)))): + cek_call(update_fn, [value]) + return make_cek_value(value, env, rest_k) + elif sx_truthy((ft == 'scope')): + name = get(frame, 'name') + remaining = get(frame, 'remaining') + fenv = get(frame, 'env') + if sx_truthy(empty_p(remaining)): + scope_pop(name) + return make_cek_value(value, fenv, rest_k) + else: + return make_cek_state(first(remaining), fenv, kont_push(make_scope_frame(name, rest(remaining), fenv), rest_k)) + elif sx_truthy((ft == 'map')): + f = get(frame, 'f') + remaining = get(frame, 'remaining') + results = get(frame, 'results') + indexed = get(frame, 'indexed') + fenv = get(frame, 'env') + new_results = append(results, [value]) + if sx_truthy(empty_p(remaining)): + return make_cek_value(new_results, fenv, rest_k) + else: + call_args = ([len(new_results), first(remaining)] if sx_truthy(indexed) else [first(remaining)]) + next_frame = (make_map_indexed_frame(f, rest(remaining), new_results, fenv) if sx_truthy(indexed) else make_map_frame(f, rest(remaining), new_results, fenv)) + return continue_with_call(f, call_args, fenv, [], kont_push(next_frame, rest_k)) + elif sx_truthy((ft == 'filter')): + f = get(frame, 'f') + remaining = get(frame, 'remaining') + results = get(frame, 'results') + current_item = get(frame, 'current-item') + fenv = get(frame, 'env') + new_results = (append(results, [current_item]) if sx_truthy(value) else results) + if sx_truthy(empty_p(remaining)): + return make_cek_value(new_results, fenv, rest_k) + else: + return continue_with_call(f, [first(remaining)], fenv, [], kont_push(make_filter_frame(f, rest(remaining), new_results, first(remaining), fenv), rest_k)) + elif sx_truthy((ft == 'reduce')): + f = get(frame, 'f') + remaining = get(frame, 'remaining') + fenv = get(frame, 'env') + if sx_truthy(empty_p(remaining)): + return make_cek_value(value, fenv, rest_k) + else: + return continue_with_call(f, [value, first(remaining)], fenv, [], kont_push(make_reduce_frame(f, rest(remaining), fenv), rest_k)) + elif sx_truthy((ft == 'for-each')): + f = get(frame, 'f') + remaining = get(frame, 'remaining') + fenv = get(frame, 'env') + if sx_truthy(empty_p(remaining)): + return make_cek_value(NIL, fenv, rest_k) + else: + return continue_with_call(f, [first(remaining)], fenv, [], kont_push(make_for_each_frame(f, rest(remaining), fenv), rest_k)) + elif sx_truthy((ft == 'some')): + f = get(frame, 'f') + remaining = get(frame, 'remaining') + fenv = get(frame, 'env') + if sx_truthy(value): + return make_cek_value(value, fenv, rest_k) + else: + if sx_truthy(empty_p(remaining)): + return make_cek_value(False, fenv, rest_k) + else: + return continue_with_call(f, [first(remaining)], fenv, [], kont_push(make_some_frame(f, rest(remaining), fenv), rest_k)) + elif sx_truthy((ft == 'every')): + f = get(frame, 'f') + remaining = get(frame, 'remaining') + fenv = get(frame, 'env') + if sx_truthy((not sx_truthy(value))): + return make_cek_value(False, fenv, rest_k) + else: + if sx_truthy(empty_p(remaining)): + return make_cek_value(True, fenv, rest_k) + else: + return continue_with_call(f, [first(remaining)], fenv, [], kont_push(make_every_frame(f, rest(remaining), fenv), rest_k)) + else: + return error(sx_str('Unknown frame type: ', ft)) + +# continue-with-call +def continue_with_call(f, args, env, raw_args, kont): + if sx_truthy(continuation_p(f)): + arg = (NIL if sx_truthy(empty_p(args)) else first(args)) + cont_data = continuation_data(f) + captured = get(cont_data, 'captured') + rest_k = get(cont_data, 'rest-kont') + return make_cek_value(arg, env, concat(captured, rest_k)) + elif sx_truthy((is_callable(f) if not sx_truthy(is_callable(f)) else ((not sx_truthy(is_lambda(f))) if not sx_truthy((not sx_truthy(is_lambda(f)))) else ((not sx_truthy(is_component(f))) if not sx_truthy((not sx_truthy(is_component(f)))) else (not sx_truthy(is_island(f))))))): + return make_cek_value(apply(f, args), env, kont) + elif sx_truthy(is_lambda(f)): + params = lambda_params(f) + local = env_merge(lambda_closure(f), env) + if sx_truthy((len(args) > len(params))): + return error(sx_str((lambda_name(f) if sx_truthy(lambda_name(f)) else 'lambda'), ' expects ', len(params), ' args, got ', len(args))) + else: + for pair in zip(params, args): + local[first(pair)] = nth(pair, 1) + for p in slice(params, len(args)): + local[p] = NIL + return make_cek_state(lambda_body(f), local, kont) + elif sx_truthy((is_component(f) if sx_truthy(is_component(f)) else is_island(f))): + parsed = parse_keyword_args(raw_args, env) + kwargs = first(parsed) + children = nth(parsed, 1) + local = env_merge(component_closure(f), env) + for p in component_params(f): + local[p] = (dict_get(kwargs, p) if sx_truthy(dict_get(kwargs, p)) else NIL) + if sx_truthy(component_has_children(f)): + local['children'] = children + return make_cek_state(component_body(f), local, kont) + else: + return error(sx_str('Not callable: ', inspect(f))) + +# sf-case-step-loop +def sf_case_step_loop(match_val, clauses, env, kont): + if sx_truthy((len(clauses) < 2)): + return make_cek_value(NIL, env, kont) + else: + test = first(clauses) + body = nth(clauses, 1) + if sx_truthy((((type_of(test) == 'keyword') if not sx_truthy((type_of(test) == 'keyword')) else (keyword_name(test) == 'else')) if sx_truthy(((type_of(test) == 'keyword') if not sx_truthy((type_of(test) == 'keyword')) else (keyword_name(test) == 'else'))) else ((type_of(test) == 'symbol') if not sx_truthy((type_of(test) == 'symbol')) else ((symbol_name(test) == 'else') if sx_truthy((symbol_name(test) == 'else')) else (symbol_name(test) == ':else'))))): + return make_cek_state(body, env, kont) + else: + test_val = trampoline(eval_expr(test, env)) + if sx_truthy((match_val == test_val)): + return make_cek_state(body, env, kont) + else: + return sf_case_step_loop(match_val, slice(clauses, 2), env, kont) + +# eval-expr-cek +def eval_expr_cek(expr, env): + return cek_run(make_cek_state(expr, env, [])) + +# trampoline-cek +def trampoline_cek(val): + if sx_truthy(is_thunk(val)): + return eval_expr_cek(thunk_expr(val), thunk_env(val)) + else: + return val + +# freeze-registry +freeze_registry = {} + +# freeze-signal +def freeze_signal(name, sig): + scope_name = sx_context('sx-freeze-scope', NIL) + if sx_truthy(scope_name): + entries = (get(freeze_registry, scope_name) if sx_truthy(get(freeze_registry, scope_name)) else []) + entries.append({'name': name, 'signal': sig}) + return _sx_dict_set(freeze_registry, scope_name, entries) + return NIL + +# freeze-scope +def freeze_scope(name, body_fn): + scope_push('sx-freeze-scope', name) + freeze_registry[name] = [] + cek_call(body_fn, NIL) + scope_pop('sx-freeze-scope') + return NIL + +# cek-freeze-scope +def cek_freeze_scope(name): + entries = (get(freeze_registry, name) if sx_truthy(get(freeze_registry, name)) else []) + signals_dict = {} + for entry in entries: + signals_dict[get(entry, 'name')] = signal_value(get(entry, 'signal')) + return {'name': name, 'signals': signals_dict} + +# cek-freeze-all +def cek_freeze_all(): + return map(lambda name: cek_freeze_scope(name), keys(freeze_registry)) + +# cek-thaw-scope +def cek_thaw_scope(name, frozen): + entries = (get(freeze_registry, name) if sx_truthy(get(freeze_registry, name)) else []) + values = get(frozen, 'signals') + if sx_truthy(values): + for entry in entries: + sig_name = get(entry, 'name') + sig = get(entry, 'signal') + val = get(values, sig_name) + if sx_truthy((not sx_truthy(is_nil(val)))): + reset_b(sig, val) + return NIL + return NIL + +# cek-thaw-all +def cek_thaw_all(frozen_list): + for frozen in frozen_list: + cek_thaw_scope(get(frozen, 'name'), frozen) + return NIL + +# freeze-to-sx +def freeze_to_sx(name): + return sx_serialize(cek_freeze_scope(name)) + +# thaw-from-sx +def thaw_from_sx(sx_text): + parsed = sx_parse(sx_text) + if sx_truthy((not sx_truthy(empty_p(parsed)))): + frozen = first(parsed) + return cek_thaw_scope(get(frozen, 'name'), frozen) + return NIL + +# content-store +content_store = {} + +# content-hash +def content_hash(sx_text): + _cells = {} + _cells['hash'] = 5381 + for i in range(0, len(sx_text)): + _cells['hash'] = (((_cells['hash'] * 33) + char_code_at(sx_text, i)) % 4294967296) + return to_hex(_cells['hash']) + +# content-put +def content_put(sx_text): + cid = content_hash(sx_text) + content_store[cid] = sx_text + return cid + +# content-get +def content_get(cid): + return get(content_store, cid) + +# freeze-to-cid +def freeze_to_cid(scope_name): + sx_text = freeze_to_sx(scope_name) + return content_put(sx_text) + +# thaw-from-cid +def thaw_from_cid(cid): + sx_text = content_get(cid) + if sx_truthy(sx_text): + thaw_from_sx(sx_text) + return True + return NIL + + # === Transpiled from signals (reactive signal runtime) === # make-signal diff --git a/web/test-aser.sx b/web/tests/test-aser.sx similarity index 100% rename from web/test-aser.sx rename to web/tests/test-aser.sx diff --git a/web/test-cek-reactive.sx b/web/tests/test-cek-reactive.sx similarity index 100% rename from web/test-cek-reactive.sx rename to web/tests/test-cek-reactive.sx diff --git a/web/test-deps.sx b/web/tests/test-deps.sx similarity index 100% rename from web/test-deps.sx rename to web/tests/test-deps.sx diff --git a/web/test-engine.sx b/web/tests/test-engine.sx similarity index 100% rename from web/test-engine.sx rename to web/tests/test-engine.sx diff --git a/web/test-orchestration.sx b/web/tests/test-orchestration.sx similarity index 100% rename from web/test-orchestration.sx rename to web/tests/test-orchestration.sx diff --git a/web/test-router.sx b/web/tests/test-router.sx similarity index 100% rename from web/test-router.sx rename to web/tests/test-router.sx diff --git a/web/test-signals.sx b/web/tests/test-signals.sx similarity index 100% rename from web/test-signals.sx rename to web/tests/test-signals.sx