Skip to content

Commit da396c2

Browse files
committed
fix: any() in results picks the first alternative; multi-char sets stay alternations
A to-position any() lists alternative spellings; the Ruby runtime picks the first in non-iterating mode — _repl_of now resolves the first element (nested anys and none included). _render_item collapsed all-string sets into a single-char class (any("helloHelloHELLO") matches every character); sets now keep the list form unless every string is a single character. title_case keeps its separator: the after-separator upcasing used a consuming match, deleting every separator occurrence.
1 parent 999585a commit da396c2

3 files changed

Lines changed: 29 additions & 2 deletions

File tree

‎src/interscript/engine.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ def _run_op(self, op: dict, text: str) -> str:
176176
)
177177
if sep != "":
178178
out = re.sub(
179-
re.escape(sep) + "(.)",
179+
f"(?<={re.escape(sep)})(.)",
180180
lambda m: m.group(1).upper(),
181181
out,
182182
)

‎src/interscript/isc.py‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,9 @@ def _render_item(item: dict, aliases: dict[str, str]) -> str:
655655
return " + ".join(_render_item(part, aliases) for part in item["parts"])
656656
if kind == "set":
657657
items = item["items"]
658-
if all(sub["type"] == "string" for sub in items):
658+
if all(sub["type"] == "string" for sub in items) and all(
659+
len(sub["value"]) == 1 for sub in items
660+
):
659661
return f'any("{_escape("".join(sub["value"] for sub in items))}")'
660662
return "any([" + ", ".join(_render_item(sub, aliases) for sub in items) + "])"
661663
if kind == "range":
@@ -751,6 +753,12 @@ def _repl_of(item: dict, aliases: dict[str, str]) -> str:
751753
return "".join(_repl_of(part, aliases) for part in item["parts"])
752754
if kind == "capture":
753755
return f"${item['index']}"
756+
if kind == "set":
757+
# A to-position any() lists alternative spellings; the Ruby
758+
# runtime picks the first in non-iterating mode.
759+
if not item["items"]:
760+
return ""
761+
return _repl_of(item["items"][0], aliases)
754762
if kind == "alias_ref":
755763
name = item["name"]
756764
if name not in aliases:

‎tests/test_isc.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,22 @@ def test_title_case_word_separator():
192192
"kind": "title_case",
193193
"word_separator": "",
194194
}
195+
196+
197+
def test_any_in_result_picks_first_alternative():
198+
src = 'system "x" { stage main { sub any("ab") any(["XA", "YB"]) } }'
199+
tree = isc_to_tree(src)
200+
subst = tree["stages"][0]["children"][0]
201+
assert subst["result"] == "XA"
202+
203+
204+
def test_any_in_result_nested_first():
205+
src = 'system "x" { stage main { sub "a" any([any("XY"), "Z"]) } }'
206+
tree = isc_to_tree(src)
207+
assert tree["stages"][0]["children"][0]["result"] == "X"
208+
209+
210+
def test_any_in_result_none_first():
211+
src = 'system "x" { stage main { sub "a" any([none, " "]) } }'
212+
tree = isc_to_tree(src)
213+
assert tree["stages"][0]["children"][0]["result"] == ""

0 commit comments

Comments
 (0)