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 Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 commas:
```bash
ilo 'f xs:L n>n;len xs' 1,2,3 # → 3
ilo 'f xs:L t>t;xs.0' 'a,b,c' # → a
```

**Run from a file:**
```bash
ilo program.ilo 10 20 30
Expand All @@ -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
```

Expand Down
6 changes: 6 additions & 0 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ xs.0 # first element
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 t>t;xs.0' 'a,b,c' → a
```

---

## Statements
Expand Down
19 changes: 17 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn main() {

if args.len() < 2 {
eprintln!("Usage: ilo <file-or-code> [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);
}
Expand All @@ -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 {
Expand All @@ -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 → 3");
println!(" ilo program.ilo 10 20 Run file with arguments");
println!(" ilo 'f x:n>n;*x 2' --emit python Transpile to Python");
}
Expand Down Expand Up @@ -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::<f64>()
&& n.is_finite() {
return interpreter::Value::Number(n);
Expand Down
64 changes: 64 additions & 0 deletions tests/eval_inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down