refactor: obtain arguments through process initialization
This commit is contained in:
@@ -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.
|
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.
|
||||||
|
|
||||||
|
|||||||
+7
-6
@@ -21,6 +21,7 @@ test import "@std/hashmap"
|
|||||||
test import "@std/strmap"
|
test import "@std/strmap"
|
||||||
test import "@std/meta"
|
test import "@std/meta"
|
||||||
test import "@std/io"
|
test import "@std/io"
|
||||||
|
test import "@std/process"
|
||||||
test import "@source/diagnostics"
|
test import "@source/diagnostics"
|
||||||
test import "@source/strpool"
|
test import "@source/strpool"
|
||||||
test import "@source/lexer"
|
test import "@source/lexer"
|
||||||
@@ -44,8 +45,8 @@ DriverError :: alias (
|
|||||||
)
|
)
|
||||||
|
|
||||||
main proc(init process.Init) i32 {
|
main proc(init process.Init) i32 {
|
||||||
return command(mem.c_allocator, init.io) catch |err| {
|
return command(mem.c_allocator, init.io, init.args) catch |err| {
|
||||||
if (process.argument(2)) |path| {
|
if (process.argument(init.args, 2)) |path| {
|
||||||
io.print("{s}: infrastructure error: {s}\n", io.stderr(init.io), {
|
io.print("{s}: infrastructure error: {s}\n", io.stderr(init.io), {
|
||||||
path, infrastructure_message(err),
|
path, infrastructure_message(err),
|
||||||
}) catch |_| {}
|
}) catch |_| {}
|
||||||
@@ -76,12 +77,12 @@ infrastructure_message proc(error DriverError) []u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@hide:file
|
@hide:file
|
||||||
command proc(allocator mem.Allocator, runtime io.Io) i32 ! DriverError {
|
command proc(allocator mem.Allocator, runtime io.Io, args process.Args) i32 ! DriverError {
|
||||||
if (process.argument_count() != 3) {
|
if (process.argument_count(args) != 3) {
|
||||||
try io.print("usage: honey run <file>\n", io.stderr(runtime), {})
|
try io.print("usage: honey run <file>\n", io.stderr(runtime), {})
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
if (process.argument(1)) |operation| {
|
if (process.argument(args, 1)) |operation| {
|
||||||
if (!mem.eql(operation, "run")) {
|
if (!mem.eql(operation, "run")) {
|
||||||
try io.print("usage: honey run <file>\n", io.stderr(runtime), {})
|
try io.print("usage: honey run <file>\n", io.stderr(runtime), {})
|
||||||
return 2
|
return 2
|
||||||
@@ -89,7 +90,7 @@ command proc(allocator mem.Allocator, runtime io.Io) i32 ! DriverError {
|
|||||||
} else {
|
} else {
|
||||||
return 2
|
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
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,11 @@
|
|||||||
# the bootstrap Init currently exposes only io; macOS provides process-lifetime argv storage.
|
argument_count proc(args Args) usize {
|
||||||
@hide:file
|
return args.values.len
|
||||||
_NSGetArgc c_func() @c_int
|
|
||||||
|
|
||||||
@hide:file
|
|
||||||
_NSGetArgv c_func() @*[*;0]u8
|
|
||||||
|
|
||||||
argument_count proc() usize {
|
|
||||||
return usize(_NSGetArgc()^)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#! returns a borrowed, zero-terminated slice; storage lasts for the process lifetime.
|
#! returns a borrowed, zero-terminated slice, valid while the supplied argument storage lives.
|
||||||
argument proc(index usize) ?[;0]u8 {
|
argument proc(args Args, index usize) ?[;0]u8 {
|
||||||
if (index >= argument_count()) return null
|
if (index >= argument_count(args)) return null
|
||||||
pointer :: _NSGetArgv()^[index]
|
pointer :: args.values[index]
|
||||||
length := usize(0)
|
length := usize(0)
|
||||||
while (pointer[length] != 0) length += 1
|
while (pointer[length] != 0) length += 1
|
||||||
return pointer[..length;0]
|
return pointer[..length;0]
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -2,4 +2,10 @@ import "@std/io"
|
|||||||
|
|
||||||
Init :: struct {
|
Init :: struct {
|
||||||
io io.Io
|
io io.Io
|
||||||
|
args Args
|
||||||
|
}
|
||||||
|
|
||||||
|
#! borrows the argument pointer array and its zero-terminated strings; owns no storage.
|
||||||
|
Args :: struct {
|
||||||
|
values [][*;0]u8
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user