Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/multiline-fn.ilo
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ nums>L n
[1,2,3]

-- run: greet "world"
-- out: ~hello "world"
-- out: ~hello world
-- run: nums
-- out: [1, 2, 3]
2 changes: 1 addition & 1 deletion examples/rsrt.ilo
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ top-words ws:L t>L t;rsrt ws
-- run: top-nums [3,1,4,1,5,9,2,6]
-- out: [9, 6, 5, 4, 3, 2, 1, 1]
-- run: top-words ["banana","apple","cherry"]
-- out: ["cherry", "banana", "apple"]
-- out: [cherry, banana, apple]
4 changes: 2 additions & 2 deletions examples/sort-by-key.ilo
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ by-len-desc ws:L t>L t;rev (srt wlen ws)
-- run: by-dist [-3,1,-5,2]
-- out: [1, 2, -3, -5]
-- run: by-len ["banana","fig","apple","kiwi"]
-- out: ["fig", "kiwi", "apple", "banana"]
-- out: [fig, kiwi, apple, banana]
-- run: by-len-desc ["banana","fig","apple","kiwi"]
-- out: ["banana", "apple", "kiwi", "fig"]
-- out: [banana, apple, kiwi, fig]
60 changes: 55 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3269,22 +3269,29 @@ print(f"__NS__={{_per}}")
}

fn parse_cli_arg(s: &str) -> interpreter::Value {
// Bracketed list: [1,2,3] or []
// Bracketed list: [1,2,3], ["apple","ant"], [] — split top-level commas,
// honoring quoted strings so commas inside strings don't split.
if s.starts_with('[') && s.ends_with(']') {
let inner = s[1..s.len() - 1].trim();
if inner.is_empty() {
return interpreter::Value::List(vec![]);
}
let items = inner
.split(',')
let items = split_top_level_commas(inner)
.into_iter()
.map(|part| parse_cli_arg(part.trim()))
.collect();
return interpreter::Value::List(items);
}
// Quoted string: strip surrounding double quotes and treat as text.
// This preserves the raw contents (no escape decoding) which mirrors how
// the rest of the CLI passes bare text.
if s.len() >= 2 && s.starts_with('"') && s.ends_with('"') {
return interpreter::Value::Text(s[1..s.len() - 1].to_string());
}
// Bare comma list: 1,2,3
if s.contains(',') {
let items = s
.split(',')
let items = split_top_level_commas(s)
.into_iter()
.map(|part| parse_cli_arg(part.trim()))
.collect();
return interpreter::Value::List(items);
Expand All @@ -3306,6 +3313,49 @@ fn parse_cli_arg(s: &str) -> interpreter::Value {
}
}

/// Split on commas, but ignore commas inside double-quoted strings or nested
/// brackets so list args like `["a,b","c"]` and `[[1,2],[3,4]]` parse correctly.
fn split_top_level_commas(s: &str) -> Vec<String> {
let mut out = Vec::new();
let mut cur = String::new();
let mut depth = 0i32;
let mut in_str = false;
let mut prev_escape = false;
for ch in s.chars() {
if in_str {
cur.push(ch);
if prev_escape {
prev_escape = false;
} else if ch == '\\' {
prev_escape = true;
} else if ch == '"' {
in_str = false;
}
continue;
}
match ch {
'"' => {
in_str = true;
cur.push(ch);
}
'[' => {
depth += 1;
cur.push(ch);
}
']' => {
depth -= 1;
cur.push(ch);
}
',' if depth == 0 => {
out.push(std::mem::take(&mut cur));
}
_ => cur.push(ch),
}
}
out.push(cur);
out
}

/// Coerce CLI args to match a function's parameter types.
/// - Wraps a non-list value in `[value]` when the param type is `L _`
fn coerce_cli_args(
Expand Down
3 changes: 1 addition & 2 deletions tests/regression_uniqby.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ fn uniqby_all_same_key_keeps_first_tree() {

// ── Order preservation: first-seen wins, original order preserved ──────────

const PARITY_SRC: &str =
"par n:n>t\n==(mod n 2) 0{ret \"even\"}\n\"odd\"\nf xs:L n>L n;uniqby par xs";
const PARITY_SRC: &str = "par n:n>t;?=(mod n 2) 0 \"even\" \"odd\"\nf xs:L n>L n;uniqby par xs";

#[test]
fn uniqby_preserves_order_tree() {
Expand Down
Loading