From 8772d59d84092f1244988b35c8151aab26b7500c Mon Sep 17 00:00:00 2001 From: giles Date: Wed, 4 Mar 2026 17:12:17 +0000 Subject: [PATCH] Fix _aser_call list serialization causing EvalError on re-parse Plain Python lists (e.g. from map) were serialized as ((item1) (item2)) which re-parses as a function application, causing "Not callable: _RawHTML" when the head gets fully evaluated. Keyword list values now wrap as (<> item1 item2) fragments; positional list children are flattened. Co-Authored-By: Claude Opus 4.6 --- shared/sx/async_eval.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/shared/sx/async_eval.py b/shared/sx/async_eval.py index cba8e65..86856f6 100644 --- a/shared/sx/async_eval.py +++ b/shared/sx/async_eval.py @@ -1249,12 +1249,29 @@ async def _aser_call( extra_class = val.class_name else: parts.append(f":{arg.name}") - parts.append(serialize(val)) + # Plain list (e.g. from map) → wrap as fragment to + # avoid ambiguity with function application on re-parse + if isinstance(val, list): + items = [serialize(v) for v in val + if v is not NIL and v is not None] + parts.append( + "(<> " + " ".join(items) + ")" if items + else "nil" + ) + else: + parts.append(serialize(val)) i += 2 else: result = await _aser(arg, env, ctx) if result is not NIL and result is not None: - parts.append(serialize(result)) + # Flatten list results (e.g. from map) into individual + # children, matching _aser_fragment behaviour + if isinstance(result, list): + for item in result: + if item is not NIL and item is not None: + parts.append(serialize(item)) + else: + parts.append(serialize(result)) i += 1 # If we converted a :style to a class, merge into existing :class or add it if extra_class: