Refactor spread to use provide/emit! internally

Spreads now emit their attrs into the nearest element's provide scope
instead of requiring per-child spread? checks at every intermediate
layer. emit! is tolerant (no-op when no provider), so spreads in
non-element contexts silently vanish.

- adapter-html: element/lake/marsh wrap children in provide, collect
  emitted; removed 14 spread filters from fragment, forms, components
- adapter-sx: aser wraps result to catch spread values from fn calls;
  aser-call uses provide with attr-parts/child-parts ordering
- adapter-async: same pattern for both render and aser paths
- adapter-dom: added emit! in spread dispatch + provide in element
  rendering; kept spread? checks for reactive/island and DOM safety
- platform: emit! returns NIL when no provider instead of erroring
- 3 new aser tests: stored spread, nested element, silent drop

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 15:41:32 +00:00
parent 859aad4333
commit 2de4ba8c57
9 changed files with 444 additions and 526 deletions

View File

@@ -1,5 +1,3 @@
# WARNING: special-forms.sx declares forms not in eval.sx: reset, shift
# WARNING: eval.sx dispatches forms not in special-forms.sx: form?, provide
"""
sx_ref.py -- Generated from reference SX evaluator specification.
@@ -87,11 +85,9 @@ def sx_context(name, *default):
def sx_emit(name, value):
"""Append value to nearest enclosing provider's accumulator. Error if no provider."""
"""Append value to nearest enclosing provider's accumulator. No-op if no provider."""
if name in _provide_stacks and _provide_stacks[name]:
_provide_stacks[name][-1]["emitted"].append(value)
else:
raise RuntimeError(f"No provider for emit!: {name}")
return NIL
@@ -2225,7 +2221,8 @@ def render_to_html(expr, env):
elif _match == 'raw-html':
return raw_html_content(expr)
elif _match == 'spread':
return expr
sx_emit('element-attrs', spread_attrs(expr))
return ''
else:
return render_value_to_html(trampoline(eval_expr(expr, env)), env)
@@ -2248,7 +2245,8 @@ def render_value_to_html(val, env):
elif _match == 'raw-html':
return raw_html_content(val)
elif _match == 'spread':
return val
sx_emit('element-attrs', spread_attrs(val))
return ''
else:
return escape_html(sx_str(val))
@@ -2266,12 +2264,12 @@ def render_list_to_html(expr, env):
else:
head = first(expr)
if sx_truthy((not sx_truthy((type_of(head) == 'symbol')))):
return join('', filter(lambda x: (not sx_truthy(is_spread(x))), map(lambda x: render_value_to_html(x, env), expr)))
return join('', map(lambda x: render_value_to_html(x, env), expr))
else:
name = symbol_name(head)
args = rest(expr)
if sx_truthy((name == '<>')):
return join('', filter(lambda x: (not sx_truthy(is_spread(x))), map(lambda x: render_to_html(x, env), args)))
return join('', map(lambda x: render_to_html(x, env), args))
elif sx_truthy((name == 'raw!')):
return join('', map(lambda x: sx_str(trampoline(eval_expr(x, env))), args))
elif sx_truthy((name == 'lake')):
@@ -2315,8 +2313,7 @@ def dispatch_html_form(name, expr, env):
if sx_truthy((len(expr) == 3)):
return render_to_html(nth(expr, 2), env)
else:
results = map(lambda i: render_to_html(nth(expr, i), env), range(2, len(expr)))
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
return join('', map(lambda i: render_to_html(nth(expr, i), env), range(2, len(expr))))
elif sx_truthy((name == 'cond')):
branch = eval_cond(rest(expr), env)
if sx_truthy(branch):
@@ -2330,38 +2327,36 @@ def dispatch_html_form(name, expr, env):
if sx_truthy((len(expr) == 3)):
return render_to_html(nth(expr, 2), local)
else:
results = map(lambda i: render_to_html(nth(expr, i), local), range(2, len(expr)))
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
return join('', map(lambda i: render_to_html(nth(expr, i), local), range(2, len(expr))))
elif sx_truthy(((name == 'begin') if sx_truthy((name == 'begin')) else (name == 'do'))):
if sx_truthy((len(expr) == 2)):
return render_to_html(nth(expr, 1), env)
else:
results = map(lambda i: render_to_html(nth(expr, i), env), range(1, len(expr)))
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
return join('', map(lambda i: render_to_html(nth(expr, i), env), range(1, len(expr))))
elif sx_truthy(is_definition_form(name)):
trampoline(eval_expr(expr, env))
return ''
elif sx_truthy((name == 'map')):
f = trampoline(eval_expr(nth(expr, 1), env))
coll = trampoline(eval_expr(nth(expr, 2), env))
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), map(lambda item: (render_lambda_html(f, [item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [item]), env)), coll)))
return join('', map(lambda item: (render_lambda_html(f, [item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [item]), env)), coll))
elif sx_truthy((name == 'map-indexed')):
f = trampoline(eval_expr(nth(expr, 1), env))
coll = trampoline(eval_expr(nth(expr, 2), env))
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), map_indexed(lambda i, item: (render_lambda_html(f, [i, item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [i, item]), env)), coll)))
return join('', map_indexed(lambda i, item: (render_lambda_html(f, [i, item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [i, item]), env)), coll))
elif sx_truthy((name == 'filter')):
return render_to_html(trampoline(eval_expr(expr, env)), env)
elif sx_truthy((name == 'for-each')):
f = trampoline(eval_expr(nth(expr, 1), env))
coll = trampoline(eval_expr(nth(expr, 2), env))
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), map(lambda item: (render_lambda_html(f, [item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [item]), env)), coll)))
return join('', map(lambda item: (render_lambda_html(f, [item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [item]), env)), coll))
elif sx_truthy((name == 'provide')):
prov_name = trampoline(eval_expr(nth(expr, 1), env))
prov_val = trampoline(eval_expr(nth(expr, 2), env))
body_start = 3
body_count = (len(expr) - 3)
provide_push(prov_name, prov_val)
result = (render_to_html(nth(expr, body_start), env) if sx_truthy((body_count == 1)) else join('', filter(lambda r: (not sx_truthy(is_spread(r))), map(lambda i: render_to_html(nth(expr, i), env), range(body_start, (body_start + body_count))))))
result = (render_to_html(nth(expr, body_start), env) if sx_truthy((body_count == 1)) else join('', map(lambda i: render_to_html(nth(expr, i), env), range(body_start, (body_start + body_count)))))
provide_pop(prov_name)
return result
else:
@@ -2382,12 +2377,7 @@ def render_html_component(comp, args, env):
for p in component_params(comp):
local[p] = (dict_get(kwargs, p) if sx_truthy(dict_has(kwargs, p)) else NIL)
if sx_truthy(component_has_children(comp)):
parts = []
for c in children:
r = render_to_html(c, env)
if sx_truthy((not sx_truthy(is_spread(r)))):
parts.append(r)
local['children'] = make_raw_html(join('', parts))
local['children'] = make_raw_html(join('', map(lambda c: render_to_html(c, env), children)))
return render_to_html(component_body(comp), local)
# render-html-element
@@ -2399,14 +2389,12 @@ def render_html_element(tag, args, env):
if sx_truthy(is_void):
return sx_str('<', tag, render_attrs(attrs), ' />')
else:
content_parts = []
for c in children:
result = render_to_html(c, env)
if sx_truthy(is_spread(result)):
merge_spread_attrs(attrs, spread_attrs(result))
else:
content_parts.append(result)
return sx_str('<', tag, render_attrs(attrs), '>', join('', content_parts), '</', tag, '>')
provide_push('element-attrs', NIL)
content = join('', map(lambda c: render_to_html(c, env), children))
for spread_dict in sx_emitted('element-attrs'):
merge_spread_attrs(attrs, spread_dict)
provide_pop('element-attrs')
return sx_str('<', tag, render_attrs(attrs), '>', content, '</', tag, '>')
# render-html-lake
def render_html_lake(args, env):
@@ -2416,14 +2404,12 @@ def render_html_lake(args, env):
children = []
reduce(lambda state, arg: (lambda skip: (assoc(state, 'skip', False, 'i', (get(state, 'i') + 1)) if sx_truthy(skip) else ((lambda kname: (lambda kval: _sx_begin((_sx_cell_set(_cells, 'lake_id', kval) if sx_truthy((kname == 'id')) else (_sx_cell_set(_cells, 'lake_tag', kval) if sx_truthy((kname == 'tag')) else NIL)), assoc(state, 'skip', True, 'i', (get(state, 'i') + 1))))(trampoline(eval_expr(nth(args, (get(state, 'i') + 1)), env))))(keyword_name(arg)) 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)
lake_attrs = {'data-sx-lake': (_cells['lake_id'] if sx_truthy(_cells['lake_id']) else '')}
content_parts = []
for c in children:
result = render_to_html(c, env)
if sx_truthy(is_spread(result)):
merge_spread_attrs(lake_attrs, spread_attrs(result))
else:
content_parts.append(result)
return sx_str('<', _cells['lake_tag'], render_attrs(lake_attrs), '>', join('', content_parts), '</', _cells['lake_tag'], '>')
provide_push('element-attrs', NIL)
content = join('', map(lambda c: render_to_html(c, env), children))
for spread_dict in sx_emitted('element-attrs'):
merge_spread_attrs(lake_attrs, spread_dict)
provide_pop('element-attrs')
return sx_str('<', _cells['lake_tag'], render_attrs(lake_attrs), '>', content, '</', _cells['lake_tag'], '>')
# render-html-marsh
def render_html_marsh(args, env):
@@ -2433,14 +2419,12 @@ def render_html_marsh(args, env):
children = []
reduce(lambda state, arg: (lambda skip: (assoc(state, 'skip', False, 'i', (get(state, 'i') + 1)) if sx_truthy(skip) else ((lambda kname: (lambda kval: _sx_begin((_sx_cell_set(_cells, 'marsh_id', kval) if sx_truthy((kname == 'id')) else (_sx_cell_set(_cells, 'marsh_tag', kval) if sx_truthy((kname == 'tag')) else (NIL if sx_truthy((kname == 'transform')) else NIL))), assoc(state, 'skip', True, 'i', (get(state, 'i') + 1))))(trampoline(eval_expr(nth(args, (get(state, 'i') + 1)), env))))(keyword_name(arg)) 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)
marsh_attrs = {'data-sx-marsh': (_cells['marsh_id'] if sx_truthy(_cells['marsh_id']) else '')}
content_parts = []
for c in children:
result = render_to_html(c, env)
if sx_truthy(is_spread(result)):
merge_spread_attrs(marsh_attrs, spread_attrs(result))
else:
content_parts.append(result)
return sx_str('<', _cells['marsh_tag'], render_attrs(marsh_attrs), '>', join('', content_parts), '</', _cells['marsh_tag'], '>')
provide_push('element-attrs', NIL)
content = join('', map(lambda c: render_to_html(c, env), children))
for spread_dict in sx_emitted('element-attrs'):
merge_spread_attrs(marsh_attrs, spread_dict)
provide_pop('element-attrs')
return sx_str('<', _cells['marsh_tag'], render_attrs(marsh_attrs), '>', content, '</', _cells['marsh_tag'], '>')
# render-html-island
def render_html_island(island, args, env):
@@ -2452,12 +2436,7 @@ def render_html_island(island, args, env):
for p in component_params(island):
local[p] = (dict_get(kwargs, p) if sx_truthy(dict_has(kwargs, p)) else NIL)
if sx_truthy(component_has_children(island)):
parts = []
for c in children:
r = render_to_html(c, env)
if sx_truthy((not sx_truthy(is_spread(r)))):
parts.append(r)
local['children'] = make_raw_html(join('', parts))
local['children'] = make_raw_html(join('', map(lambda c: render_to_html(c, env), children)))
body_html = render_to_html(component_body(island), local)
state_sx = serialize_island_state(kwargs)
return sx_str('<span data-sx-island="', escape_attr(island_name), '"', (sx_str(' data-sx-state="', escape_attr(state_sx), '"') if sx_truthy(state_sx) else ''), '>', body_html, '</span>')
@@ -2483,40 +2462,12 @@ def render_to_sx(expr, env):
# aser
def aser(expr, env):
set_render_active_b(True)
_match = type_of(expr)
if _match == 'number':
return expr
elif _match == 'string':
return expr
elif _match == 'boolean':
return expr
elif _match == 'nil':
result = _sx_case(type_of(expr), [('number', lambda: expr), ('string', lambda: expr), ('boolean', lambda: expr), ('nil', lambda: NIL), ('symbol', lambda: (lambda name: (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))))))))(symbol_name(expr))), ('keyword', lambda: keyword_name(expr)), ('list', lambda: ([] if sx_truthy(empty_p(expr)) else aser_list(expr, env))), ('spread', lambda: _sx_begin(sx_emit('element-attrs', spread_attrs(expr)), NIL)), (None, lambda: expr)])
if sx_truthy(is_spread(result)):
sx_emit('element-attrs', spread_attrs(result))
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:
return error(sx_str('Undefined symbol: ', name))
elif _match == 'keyword':
return keyword_name(expr)
elif _match == 'list':
if sx_truthy(empty_p(expr)):
return []
else:
return aser_list(expr, env)
elif _match == 'spread':
return expr
else:
return expr
return result
# aser-list
def aser_list(expr, env):
@@ -2561,10 +2512,10 @@ def aser_fragment(children, env):
result = aser(c, env)
if sx_truthy((type_of(result) == 'list')):
for item in result:
if sx_truthy(((not sx_truthy(is_nil(item))) if not sx_truthy((not sx_truthy(is_nil(item)))) else (not sx_truthy(is_spread(item))))):
if sx_truthy((not sx_truthy(is_nil(item)))):
parts.append(serialize(item))
else:
if sx_truthy(((not sx_truthy(is_nil(result))) if not sx_truthy((not sx_truthy(is_nil(result)))) else (not sx_truthy(is_spread(result))))):
if sx_truthy((not sx_truthy(is_nil(result)))):
parts.append(serialize(result))
if sx_truthy(empty_p(parts)):
return ''
@@ -2574,9 +2525,11 @@ def aser_fragment(children, env):
# aser-call
def aser_call(name, args, env):
_cells = {}
parts = [name]
attr_parts = []
child_parts = []
_cells['skip'] = False
_cells['i'] = 0
provide_push('element-attrs', NIL)
for arg in args:
if sx_truthy(_cells['skip']):
_cells['skip'] = False
@@ -2585,26 +2538,27 @@ def aser_call(name, args, env):
if sx_truthy(((type_of(arg) == 'keyword') if not sx_truthy((type_of(arg) == 'keyword')) else ((_cells['i'] + 1) < len(args)))):
val = aser(nth(args, (_cells['i'] + 1)), env)
if sx_truthy((not sx_truthy(is_nil(val)))):
parts.append(sx_str(':', keyword_name(arg)))
parts.append(serialize(val))
attr_parts.append(sx_str(':', keyword_name(arg)))
attr_parts.append(serialize(val))
_cells['skip'] = True
_cells['i'] = (_cells['i'] + 1)
else:
val = aser(arg, env)
if sx_truthy((not sx_truthy(is_nil(val)))):
if sx_truthy(is_spread(val)):
for k in keys(spread_attrs(val)):
v = dict_get(spread_attrs(val), k)
parts.append(sx_str(':', k))
parts.append(serialize(v))
if sx_truthy((type_of(val) == 'list')):
for item in val:
if sx_truthy((not sx_truthy(is_nil(item)))):
child_parts.append(serialize(item))
else:
if sx_truthy((type_of(val) == 'list')):
for item in val:
if sx_truthy((not sx_truthy(is_nil(item)))):
parts.append(serialize(item))
else:
parts.append(serialize(val))
child_parts.append(serialize(val))
_cells['i'] = (_cells['i'] + 1)
for spread_dict in sx_emitted('element-attrs'):
for k in keys(spread_dict):
v = dict_get(spread_dict, k)
attr_parts.append(sx_str(':', k))
attr_parts.append(serialize(v))
provide_pop('element-attrs')
parts = concat([name], attr_parts, child_parts)
return sx_str('(', join(' ', parts), ')')
# SPECIAL_FORM_NAMES
@@ -3659,7 +3613,8 @@ async def async_render(expr, env, ctx):
elif _match == 'raw-html':
return raw_html_content(expr)
elif _match == 'spread':
return expr
sx_emit('element-attrs', spread_attrs(expr))
return ''
elif _match == 'symbol':
val = (await async_eval(expr, env, ctx))
return (await async_render(val, env, ctx))
@@ -3691,7 +3646,7 @@ async def async_render_list(expr, env, ctx):
elif sx_truthy((name == 'raw!')):
return (await async_render_raw(args, env, ctx))
elif sx_truthy((name == '<>')):
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), (await async_map_render(args, env, ctx))))
return join('', (await async_map_render(args, env, ctx)))
elif sx_truthy(starts_with_p(name, 'html:')):
return (await async_render_element(slice(name, 5), args, env, ctx))
elif sx_truthy(async_render_form_p(name)):
@@ -3746,12 +3701,12 @@ async def async_render_element(tag, args, env, ctx):
else:
token = (svg_context_set(True) if sx_truthy(((tag == 'svg') if sx_truthy((tag == 'svg')) else (tag == 'math'))) else NIL)
content_parts = []
provide_push('element-attrs', NIL)
for c in children:
result = (await async_render(c, env, ctx))
if sx_truthy(is_spread(result)):
merge_spread_attrs(attrs, spread_attrs(result))
else:
content_parts.append(result)
content_parts.append((await async_render(c, env, ctx)))
for spread_dict in sx_emitted('element-attrs'):
merge_spread_attrs(attrs, spread_dict)
provide_pop('element-attrs')
if sx_truthy(token):
svg_context_reset(token)
return sx_str('<', tag, render_attrs(attrs), '>', join('', content_parts), '</', tag, '>')
@@ -3787,9 +3742,7 @@ async def async_render_component(comp, args, env, ctx):
if sx_truthy(component_has_children(comp)):
parts = []
for c in children:
r = (await async_render(c, env, ctx))
if sx_truthy((not sx_truthy(is_spread(r)))):
parts.append(r)
parts.append((await async_render(c, env, ctx)))
local['children'] = make_raw_html(join('', parts))
return (await async_render(component_body(comp), local, ctx))
@@ -3805,9 +3758,7 @@ async def async_render_island(island, args, env, ctx):
if sx_truthy(component_has_children(island)):
parts = []
for c in children:
r = (await async_render(c, env, ctx))
if sx_truthy((not sx_truthy(is_spread(r)))):
parts.append(r)
parts.append((await async_render(c, env, ctx)))
local['children'] = make_raw_html(join('', parts))
body_html = (await async_render(component_body(island), local, ctx))
state_json = serialize_island_state(kwargs)
@@ -3871,8 +3822,7 @@ async def dispatch_async_render_form(name, expr, env, ctx):
if sx_truthy((len(expr) == 3)):
return (await async_render(nth(expr, 2), env, ctx))
else:
results = (await async_map_render(slice(expr, 2), env, ctx))
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
return join('', (await async_map_render(slice(expr, 2), env, ctx)))
elif sx_truthy((name == 'cond')):
clauses = rest(expr)
if sx_truthy(cond_scheme_p(clauses)):
@@ -3886,38 +3836,36 @@ async def dispatch_async_render_form(name, expr, env, ctx):
if sx_truthy((len(expr) == 3)):
return (await async_render(nth(expr, 2), local, ctx))
else:
results = (await async_map_render(slice(expr, 2), local, ctx))
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
return join('', (await async_map_render(slice(expr, 2), local, ctx)))
elif sx_truthy(((name == 'begin') if sx_truthy((name == 'begin')) else (name == 'do'))):
if sx_truthy((len(expr) == 2)):
return (await async_render(nth(expr, 1), env, ctx))
else:
results = (await async_map_render(rest(expr), env, ctx))
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
return join('', (await async_map_render(rest(expr), env, ctx)))
elif sx_truthy(is_definition_form(name)):
(await async_eval(expr, env, ctx))
return ''
elif sx_truthy((name == 'map')):
f = (await async_eval(nth(expr, 1), env, ctx))
coll = (await async_eval(nth(expr, 2), env, ctx))
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), (await async_map_fn_render(f, coll, env, ctx))))
return join('', (await async_map_fn_render(f, coll, env, ctx)))
elif sx_truthy((name == 'map-indexed')):
f = (await async_eval(nth(expr, 1), env, ctx))
coll = (await async_eval(nth(expr, 2), env, ctx))
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), (await async_map_indexed_fn_render(f, coll, env, ctx))))
return join('', (await async_map_indexed_fn_render(f, coll, env, ctx)))
elif sx_truthy((name == 'filter')):
return (await async_render((await async_eval(expr, env, ctx)), env, ctx))
elif sx_truthy((name == 'for-each')):
f = (await async_eval(nth(expr, 1), env, ctx))
coll = (await async_eval(nth(expr, 2), env, ctx))
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), (await async_map_fn_render(f, coll, env, ctx))))
return join('', (await async_map_fn_render(f, coll, env, ctx)))
elif sx_truthy((name == 'provide')):
prov_name = (await async_eval(nth(expr, 1), env, ctx))
prov_val = (await async_eval(nth(expr, 2), env, ctx))
body_start = 3
body_count = (len(expr) - 3)
provide_push(prov_name, prov_val)
result = ((await async_render(nth(expr, body_start), env, ctx)) if sx_truthy((body_count == 1)) else (lambda results: join('', filter(lambda r: (not sx_truthy(is_spread(r))), results)))((await async_map_render(slice(expr, body_start), env, ctx))))
result = ((await async_render(nth(expr, body_start), env, ctx)) if sx_truthy((body_count == 1)) else join('', (await async_map_render(slice(expr, body_start), env, ctx))))
provide_pop(prov_name)
return result
else:
@@ -4019,42 +3967,35 @@ async def async_invoke(f, *args):
# async-aser
async def async_aser(expr, env, ctx):
_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':
t = type_of(expr)
result = NIL
if sx_truthy((t == 'number')):
result = expr
elif sx_truthy((t == 'string')):
result = expr
elif sx_truthy((t == 'boolean')):
result = expr
elif sx_truthy((t == 'nil')):
result = NIL
elif sx_truthy((t == '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:
return error(sx_str('Undefined symbol: ', name))
elif _match == 'keyword':
return keyword_name(expr)
elif _match == 'dict':
return (await async_aser_dict(expr, env, ctx))
elif _match == 'spread':
return expr
elif _match == 'list':
if sx_truthy(empty_p(expr)):
return []
else:
return (await async_aser_list(expr, env, ctx))
result = (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)))))))
elif sx_truthy((t == 'keyword')):
result = keyword_name(expr)
elif sx_truthy((t == 'dict')):
result = (await async_aser_dict(expr, env, ctx))
elif sx_truthy((t == 'spread')):
sx_emit('element-attrs', spread_attrs(expr))
result = NIL
elif sx_truthy((t == 'list')):
result = ([] if sx_truthy(empty_p(expr)) else (await async_aser_list(expr, env, ctx)))
else:
return expr
result = expr
if sx_truthy(is_spread(result)):
sx_emit('element-attrs', spread_attrs(result))
return NIL
else:
return result
# async-aser-dict
async def async_aser_dict(expr, env, ctx):
@@ -4148,10 +4089,10 @@ async def async_aser_fragment(children, env, ctx):
result = (await async_aser(c, env, ctx))
if sx_truthy((type_of(result) == 'list')):
for item in result:
if sx_truthy(((not sx_truthy(is_nil(item))) if not sx_truthy((not sx_truthy(is_nil(item)))) else (not sx_truthy(is_spread(item))))):
if sx_truthy((not sx_truthy(is_nil(item)))):
parts.append(serialize(item))
else:
if sx_truthy(((not sx_truthy(is_nil(result))) if not sx_truthy((not sx_truthy(is_nil(result)))) else (not sx_truthy(is_spread(result))))):
if sx_truthy((not sx_truthy(is_nil(result)))):
parts.append(serialize(result))
if sx_truthy(empty_p(parts)):
return make_sx_expr('')
@@ -4204,9 +4145,11 @@ async def async_parse_aser_kw_args(args, kwargs, children, env, ctx):
async def async_aser_call(name, args, env, ctx):
_cells = {}
token = (svg_context_set(True) if sx_truthy(((name == 'svg') if sx_truthy((name == 'svg')) else (name == 'math'))) else NIL)
parts = [name]
attr_parts = []
child_parts = []
_cells['skip'] = False
_cells['i'] = 0
provide_push('element-attrs', NIL)
for arg in args:
if sx_truthy(_cells['skip']):
_cells['skip'] = False
@@ -4215,39 +4158,40 @@ async def async_aser_call(name, args, env, ctx):
if sx_truthy(((type_of(arg) == 'keyword') if not sx_truthy((type_of(arg) == 'keyword')) else ((_cells['i'] + 1) < len(args)))):
val = (await async_aser(nth(args, (_cells['i'] + 1)), env, ctx))
if sx_truthy((not sx_truthy(is_nil(val)))):
parts.append(sx_str(':', keyword_name(arg)))
attr_parts.append(sx_str(':', keyword_name(arg)))
if sx_truthy((type_of(val) == 'list')):
live = filter(lambda v: (not sx_truthy(is_nil(v))), val)
if sx_truthy(empty_p(live)):
parts.append('nil')
attr_parts.append('nil')
else:
items = map(serialize, live)
if sx_truthy(some(lambda v: is_sx_expr(v), live)):
parts.append(sx_str('(<> ', join(' ', items), ')'))
attr_parts.append(sx_str('(<> ', join(' ', items), ')'))
else:
parts.append(sx_str('(list ', join(' ', items), ')'))
attr_parts.append(sx_str('(list ', join(' ', items), ')'))
else:
parts.append(serialize(val))
attr_parts.append(serialize(val))
_cells['skip'] = True
_cells['i'] = (_cells['i'] + 1)
else:
result = (await async_aser(arg, env, ctx))
if sx_truthy((not sx_truthy(is_nil(result)))):
if sx_truthy(is_spread(result)):
for k in keys(spread_attrs(result)):
v = dict_get(spread_attrs(result), k)
parts.append(sx_str(':', k))
parts.append(serialize(v))
if sx_truthy((type_of(result) == 'list')):
for item in result:
if sx_truthy((not sx_truthy(is_nil(item)))):
child_parts.append(serialize(item))
else:
if sx_truthy((type_of(result) == 'list')):
for item in result:
if sx_truthy((not sx_truthy(is_nil(item)))):
parts.append(serialize(item))
else:
parts.append(serialize(result))
child_parts.append(serialize(result))
_cells['i'] = (_cells['i'] + 1)
for spread_dict in sx_emitted('element-attrs'):
for k in keys(spread_dict):
v = dict_get(spread_dict, k)
attr_parts.append(sx_str(':', k))
attr_parts.append(serialize(v))
provide_pop('element-attrs')
if sx_truthy(token):
svg_context_reset(token)
parts = concat([name], attr_parts, child_parts)
return make_sx_expr(sx_str('(', join(' ', parts), ')'))
# ASYNC_ASER_FORM_NAMES