From 223f84b1beaa9a3ec93a9481e6839a2ea3f65eb4 Mon Sep 17 00:00:00 2001 From: Daniel Morris Date: Fri, 27 Feb 2026 19:16:04 +0000 Subject: [PATCH 1/3] feat: add --help/-h flags and CLI list argument parsing - `ilo --help` and `ilo -h` now show help text (previously treated as inline code) - CLI can now pass list arguments: `[1,2,3]` (bracketed) or `1,2,3` (bare comma) - Add 6 integration tests covering both features - Update README.md, SPEC.md, and help text with list arg examples --- Cargo.lock | 2 +- README.md | 7 +++++ SPEC.md | 6 +++++ src/main.rs | 19 +++++++++++-- tests/eval_inline.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f303e880..1c8b1a1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -253,7 +253,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "ilo" -version = "0.1.0" +version = "0.1.1" dependencies = [ "cranelift-codegen", "cranelift-frontend", diff --git a/README.md b/README.md index da5ddbe8..228cd7ea 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,12 @@ No flags needed. The first arg is code (or a file path — auto-detected). Remai ilo 'dbl x:n>n;s=*x 2;+s 0 tot p:n q:n r:n>n;s=*p q;t=*s r;+s t' tot 10 20 30 ``` +**Pass list arguments** with brackets: +```bash +ilo 'f xs:L n>n;len xs' '[1,2,3]' # → 3 +ilo 'f xs:L n>n;xs.0' '[10,20,30]' # → 10 +``` + **Run from a file:** ```bash ilo program.ilo 10 20 30 @@ -105,6 +111,7 @@ ilo program.ilo 10 20 30 **Help & language spec:** ```bash ilo help # usage and examples +ilo -h # same as ilo help ilo help lang # print the full language specification ``` diff --git a/SPEC.md b/SPEC.md index d9a82632..59bf12e7 100644 --- a/SPEC.md +++ b/SPEC.md @@ -142,6 +142,12 @@ xs.0 # first element xs.2 # third element ``` +**CLI list arguments:** Pass lists from the command line with brackets or bare commas: +``` +ilo 'f xs:L n>n;len xs' '[1,2,3]' → 3 +ilo 'f xs:L n>n;xs.0' '10,20,30' → 10 +``` + --- ## Statements diff --git a/src/main.rs b/src/main.rs index 819b05fd..4bcee576 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ fn main() { if args.len() < 2 { eprintln!("Usage: ilo [args... | --run func args... | --bench func args... | --emit python]"); - eprintln!(" ilo help Show usage and examples"); + eprintln!(" ilo help | -h Show usage and examples"); eprintln!(" ilo help lang Show language specification"); std::process::exit(1); } @@ -23,7 +23,7 @@ fn main() { std::process::exit(0); } - if args[1] == "help" { + if args[1] == "help" || args[1] == "--help" || args[1] == "-h" { if args.len() > 2 && args[2] == "lang" { print!("{}", include_str!("../SPEC.md")); } else { @@ -45,6 +45,7 @@ fn main() { println!(" --run-llvm LLVM JIT (requires --features llvm build)\n"); println!("Examples:"); println!(" ilo 'f x:n>n;*x 2' 5 Define and call f(5) → 10"); + println!(" ilo 'f xs:L n>n;len xs' '[1,2,3]' Pass a list argument → 3"); println!(" ilo program.ilo 10 20 Run file with arguments"); println!(" ilo 'f x:n>n;*x 2' --emit python Transpile to Python"); } @@ -630,6 +631,20 @@ print(f"__NS__={{_per}}") } fn parse_cli_arg(s: &str) -> interpreter::Value { + // Bracketed list: [1,2,3] or [] + 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(',').map(|part| parse_cli_arg(part.trim())).collect(); + return interpreter::Value::List(items); + } + // Bare comma list: 1,2,3 + if s.contains(',') { + let items = s.split(',').map(|part| parse_cli_arg(part.trim())).collect(); + return interpreter::Value::List(items); + } if let Ok(n) = s.parse::() && n.is_finite() { return interpreter::Value::Number(n); diff --git a/tests/eval_inline.rs b/tests/eval_inline.rs index 203859fe..9a741fa0 100644 --- a/tests/eval_inline.rs +++ b/tests/eval_inline.rs @@ -221,6 +221,70 @@ fn inline_bench_mode() { // --- Help --- +#[test] +fn help_flag_shows_usage() { + let out = ilo() + .args(["--help"]) + .output() + .expect("failed to run ilo"); + assert!(out.status.success()); + let stdout = String::from_utf8_lossy(&out.stdout); + assert!(stdout.contains("Backends:"), "expected backends section, got: {}", stdout); +} + +#[test] +fn help_short_flag_shows_usage() { + let out = ilo() + .args(["-h"]) + .output() + .expect("failed to run ilo"); + assert!(out.status.success()); + let stdout = String::from_utf8_lossy(&out.stdout); + assert!(stdout.contains("Backends:"), "expected backends section, got: {}", stdout); +} + +// --- List arguments --- + +#[test] +fn inline_list_arg_bracketed() { + let out = ilo() + .args(["f xs:L n>n;len xs", "[1,2,3]"]) + .output() + .expect("failed to run ilo"); + assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr)); + assert_eq!(String::from_utf8_lossy(&out.stdout).trim(), "3"); +} + +#[test] +fn inline_list_arg_bracketed_index() { + let out = ilo() + .args(["f xs:L n>n;xs.0", "[10,20,30]"]) + .output() + .expect("failed to run ilo"); + assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr)); + assert_eq!(String::from_utf8_lossy(&out.stdout).trim(), "10"); +} + +#[test] +fn inline_list_arg_bare_comma() { + let out = ilo() + .args(["f xs:L n>n;len xs", "1,2,3"]) + .output() + .expect("failed to run ilo"); + assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr)); + assert_eq!(String::from_utf8_lossy(&out.stdout).trim(), "3"); +} + +#[test] +fn inline_list_arg_bare_comma_index() { + let out = ilo() + .args(["f xs:L n>n;xs.0", "10,20,30"]) + .output() + .expect("failed to run ilo"); + assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr)); + assert_eq!(String::from_utf8_lossy(&out.stdout).trim(), "10"); +} + #[test] fn help_shows_usage() { let out = ilo() From 64da7d7184160340936f5c16ec3ad1583947eeaf Mon Sep 17 00:00:00 2001 From: Daniel Morris Date: Fri, 27 Feb 2026 19:17:40 +0000 Subject: [PATCH 2/3] docs: prefer bare comma form for CLI list examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bracket syntax requires shell quoting — show 1,2,3 as primary form. --- README.md | 6 +++--- SPEC.md | 6 +++--- src/main.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 228cd7ea..80aa1aa7 100644 --- a/README.md +++ b/README.md @@ -97,10 +97,10 @@ No flags needed. The first arg is code (or a file path — auto-detected). Remai ilo 'dbl x:n>n;s=*x 2;+s 0 tot p:n q:n r:n>n;s=*p q;t=*s r;+s t' tot 10 20 30 ``` -**Pass list arguments** with brackets: +**Pass list arguments** with commas: ```bash -ilo 'f xs:L n>n;len xs' '[1,2,3]' # → 3 -ilo 'f xs:L n>n;xs.0' '[10,20,30]' # → 10 +ilo 'f xs:L n>n;len xs' 1,2,3 # → 3 +ilo 'f xs:L n>n;xs.0' 10,20,30 # → 10 ``` **Run from a file:** diff --git a/SPEC.md b/SPEC.md index 59bf12e7..79b00c40 100644 --- a/SPEC.md +++ b/SPEC.md @@ -142,10 +142,10 @@ xs.0 # first element xs.2 # third element ``` -**CLI list arguments:** Pass lists from the command line with brackets or bare commas: +**CLI list arguments:** Pass lists from the command line with commas (brackets also accepted): ``` -ilo 'f xs:L n>n;len xs' '[1,2,3]' → 3 -ilo 'f xs:L n>n;xs.0' '10,20,30' → 10 +ilo 'f xs:L n>n;len xs' 1,2,3 → 3 +ilo 'f xs:L n>n;xs.0' 10,20,30 → 10 ``` --- diff --git a/src/main.rs b/src/main.rs index 4bcee576..5ff71ace 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,7 +45,7 @@ fn main() { println!(" --run-llvm LLVM JIT (requires --features llvm build)\n"); println!("Examples:"); println!(" ilo 'f x:n>n;*x 2' 5 Define and call f(5) → 10"); - println!(" ilo 'f xs:L n>n;len xs' '[1,2,3]' Pass a list argument → 3"); + println!(" ilo 'f xs:L n>n;len xs' 1,2,3 Pass a list argument → 3"); println!(" ilo program.ilo 10 20 Run file with arguments"); println!(" ilo 'f x:n>n;*x 2' --emit python Transpile to Python"); } From 996850cc98704551f7a88830316528e9d3a859a0 Mon Sep 17 00:00:00 2001 From: Daniel Morris Date: Fri, 27 Feb 2026 19:18:29 +0000 Subject: [PATCH 3/3] docs: show both number and text list examples --- README.md | 2 +- SPEC.md | 2 +- src/main.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 80aa1aa7..b207e442 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ ilo 'dbl x:n>n;s=*x 2;+s 0 tot p:n q:n r:n>n;s=*p q;t=*s r;+s t' tot 10 20 30 **Pass list arguments** with commas: ```bash ilo 'f xs:L n>n;len xs' 1,2,3 # → 3 -ilo 'f xs:L n>n;xs.0' 10,20,30 # → 10 +ilo 'f xs:L t>t;xs.0' 'a,b,c' # → a ``` **Run from a file:** diff --git a/SPEC.md b/SPEC.md index 79b00c40..e85f952e 100644 --- a/SPEC.md +++ b/SPEC.md @@ -145,7 +145,7 @@ xs.2 # third element **CLI list arguments:** Pass lists from the command line with commas (brackets also accepted): ``` ilo 'f xs:L n>n;len xs' 1,2,3 → 3 -ilo 'f xs:L n>n;xs.0' 10,20,30 → 10 +ilo 'f xs:L t>t;xs.0' 'a,b,c' → a ``` --- diff --git a/src/main.rs b/src/main.rs index 5ff71ace..410be572 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,7 +45,7 @@ fn main() { println!(" --run-llvm LLVM JIT (requires --features llvm build)\n"); println!("Examples:"); println!(" ilo 'f x:n>n;*x 2' 5 Define and call f(5) → 10"); - println!(" ilo 'f xs:L n>n;len xs' 1,2,3 Pass a list argument → 3"); + println!(" ilo 'f xs:L n>n;len xs' 1,2,3 Pass a list → 3"); println!(" ilo program.ilo 10 20 Run file with arguments"); println!(" ilo 'f x:n>n;*x 2' --emit python Transpile to Python"); }