From c1e03632ed04e4f4a99a18c8d8bea804c4ec9de4 Mon Sep 17 00:00:00 2001 From: hl-valdemar Date: Fri, 23 Oct 2026 11:37:29 +0200 Subject: [PATCH] refactor: obtain arguments through process initialization --- README.md | 4 +++- source/main.hon | 13 +++++++------ std/process/arguments.hon | 19 ++++++------------- std/process/arguments.test.hon | 27 +++++++++++++++++++++++++++ std/process/process.hon | 6 ++++++ 5 files changed, 49 insertions(+), 20 deletions(-) create mode 100644 std/process/arguments.test.hon diff --git a/README.md b/README.md index 90e8f9e..ab608d7 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,9 @@ main proc() int { } ``` -this prints `42`. `main` must be a top-level function with no parameters; nonvoid results are printed, not used as process exit statuses. the current macOS bootstrap obtains arguments from the native startup environment. +this prints `42`. interpreted `main` must be a top-level function with no parameters; nonvoid results are printed, not used as process exit statuses. + +the native bootstrap accepts either a no-argument `main` or `main proc(init process.Init)`. it supplies `init.io` and `init.args` directly from native startup `argc`/`argv`. `process.Args` borrows the argument pointer array and zero-terminated strings without allocation or copying; native startup storage lasts for the process lifetime. `process.argument_count(init.args)` includes the executable name, and `process.argument(init.args, index)` returns a borrowed `[;0]u8` or `null` when out of range. callers can supply their own `process.Args { values = pointers[..] }` for testing. source loading uses the supplied `io.Io` for opening, reading, and closing files. `io.open` accepts a borrowed zero-terminated slice (`[;0]u8`), including arguments returned by `process.argument` without copying their storage. the bootstrap supports checked sentinel-slice construction with `pointer[..length;0]`. `io.read_all(allocator, reader, maximum)` reads to EOF into a caller-owned `ArrayList(u8)`; release it with `arraylist.deinit`. it frees partial storage on error and consumes one extra byte to distinguish an exact-size input from a limit violation. the driver maps `limit_exceeded` to `source_too_large` at its `u32` source-size limit. diff --git a/source/main.hon b/source/main.hon index 086b910..0b71bce 100644 --- a/source/main.hon +++ b/source/main.hon @@ -21,6 +21,7 @@ test import "@std/hashmap" test import "@std/strmap" test import "@std/meta" test import "@std/io" +test import "@std/process" test import "@source/diagnostics" test import "@source/strpool" test import "@source/lexer" @@ -44,8 +45,8 @@ DriverError :: alias ( ) main proc(init process.Init) i32 { - return command(mem.c_allocator, init.io) catch |err| { - if (process.argument(2)) |path| { + return command(mem.c_allocator, init.io, init.args) catch |err| { + if (process.argument(init.args, 2)) |path| { io.print("{s}: infrastructure error: {s}\n", io.stderr(init.io), { path, infrastructure_message(err), }) catch |_| {} @@ -76,12 +77,12 @@ infrastructure_message proc(error DriverError) []u8 { } @hide:file -command proc(allocator mem.Allocator, runtime io.Io) i32 ! DriverError { - if (process.argument_count() != 3) { +command proc(allocator mem.Allocator, runtime io.Io, args process.Args) i32 ! DriverError { + if (process.argument_count(args) != 3) { try io.print("usage: honey run \n", io.stderr(runtime), {}) return 2 } - if (process.argument(1)) |operation| { + if (process.argument(args, 1)) |operation| { if (!mem.eql(operation, "run")) { try io.print("usage: honey run \n", io.stderr(runtime), {}) return 2 @@ -89,7 +90,7 @@ command proc(allocator mem.Allocator, runtime io.Io) i32 ! DriverError { } else { return 2 } - if (process.argument(2)) |path| return try run_file(allocator, runtime, path) + if (process.argument(args, 2)) |path| return try run_file(allocator, runtime, path) return 2 } diff --git a/std/process/arguments.hon b/std/process/arguments.hon index b4870ce..2a281f3 100644 --- a/std/process/arguments.hon +++ b/std/process/arguments.hon @@ -1,18 +1,11 @@ -# the bootstrap Init currently exposes only io; macOS provides process-lifetime argv storage. -@hide:file -_NSGetArgc c_func() @c_int - -@hide:file -_NSGetArgv c_func() @*[*;0]u8 - -argument_count proc() usize { - return usize(_NSGetArgc()^) +argument_count proc(args Args) usize { + return args.values.len } -#! returns a borrowed, zero-terminated slice; storage lasts for the process lifetime. -argument proc(index usize) ?[;0]u8 { - if (index >= argument_count()) return null - pointer :: _NSGetArgv()^[index] +#! returns a borrowed, zero-terminated slice, valid while the supplied argument storage lives. +argument proc(args Args, index usize) ?[;0]u8 { + if (index >= argument_count(args)) return null + pointer :: args.values[index] length := usize(0) while (pointer[length] != 0) length += 1 return pointer[..length;0] diff --git a/std/process/arguments.test.hon b/std/process/arguments.test.hon new file mode 100644 index 0000000..057bba0 --- /dev/null +++ b/std/process/arguments.test.hon @@ -0,0 +1,27 @@ +import "@std/testing" +import "@std/mem" + +borrows_supplied_arguments test { + first [3;0]mut u8 := ['r', 'u', 'n'] + empty [0;0]u8 := [] + spaced [9;0]u8 := ['t', 'w', 'o', ' ', 'w', 'o', 'r', 'd', 's'] + pointers [3][*;0]u8 :: [(&first).ptr, (&empty).ptr, (&spaced).ptr] + args :: Args{ values = pointers[..] } + try testing.expect_equal(usize(3), argument_count(args)) + if (argument(args, 0)) |value| { + first[0] = 'f' + try testing.expect(mem.eql(value, "fun")) + } else { try testing.expect(false) } + if (argument(args, 1)) |value| { + try testing.expect_equal(usize(0), value.len) + } else { try testing.expect(false) } + if (argument(args, 2)) |value| { + try testing.expect(mem.eql(value, "two words")) + } else { try testing.expect(false) } + try testing.expect(argument(args, 3) == null) + try testing.expect(argument(args, maxval!(usize)) == null) + + none :: Args{ values = pointers[0..0] } + try testing.expect_equal(usize(0), argument_count(none)) + try testing.expect(argument(none, 0) == null) +} diff --git a/std/process/process.hon b/std/process/process.hon index 583e5fb..bee8187 100644 --- a/std/process/process.hon +++ b/std/process/process.hon @@ -2,4 +2,10 @@ import "@std/io" Init :: struct { io io.Io + args Args +} + +#! borrows the argument pointer array and its zero-terminated strings; owns no storage. +Args :: struct { + values [][*;0]u8 }