diff --git a/CHANGELOG.md b/CHANGELOG.md index bd9eabb..6b1f470 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.17.0] - 2026-07-04 + +Harden no-libc `--pie` linux binaries with static-PIE self-relocation and fatal +`PT_GNU_RELRO` re-protection, add process-parallelism primitives, and grow a +unified JSON stack — streaming NDJSON emit, float parsing, and RFC 8259 +escaping. Makes `[target.linux-arm64]` permanent behind a qemu CI lane, and +fixes the critical arm64 `--pie` startup crash and windows mixed-DLL link +correctness. Built with mach 2.14.1. ### Added @@ -51,6 +58,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 verbatim) for `emit`, and `ESCAPE_ENSURE_ASCII` (RFC 3629 decode to `\uXXXX`, astral surrogate pairs, U+FFFD on invalid input) for the stream. Both surfaces are byte-identical to their pre-unification output (#338). +- data/json: float number parsing — numbers now accept the full RFC 8259 grammar + (`int frac? exp?`); a number carrying a fraction or exponent parses as a float + (correctly rounded through `std.text.parse`'s bignum decimal→f64 machinery over + the zero-copy source span), while integer-looking numbers still yield an `i64` + on the byte-identical path. `Value` gains `value_is_float` and `value_float` + (an integer widens to `f64`); `value_number` is unchanged, and `emit` writes + floats in shortest round-trippable form (#349). +- data/json: `value_string_decode(v, buf, len) -> Result[usize, str]` — resolves a + string value's raw on-wire escapes into logical bytes in a caller buffer, the + inverse of the emit escaper. Handles `\" \\ \/ \b \f \n \r \t` and `\uXXXX` (a + high+low surrogate pair combines into one astral code point via the validated + `std.text.utf8` encoder), and errors on malformed escapes. The parser keeps its + zero-copy raw-bytes representation; decoding is paid only at the consumption + point, resolving the parse-vs-emit representation asymmetry (#340). +- build/ci: a permanent `[target.linux-arm64]` (aarch64/linux/aapcs64) makes std + cross-buildable to aarch64 out of the box, and a `cross-arm64` CI lane + cross-builds the unit suite and runs it under `qemu-aarch64` for an automatic + aarch64 regression signal over the full suite (#280). ### Fixed @@ -64,6 +89,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 panics naming the violated invariant in each case — the glibc stance, matching `os.page_size`'s `AT_PAGESZ` precedent (#336) — so a `--pie` binary either runs fully hardened or dies loudly; no silent-unhardened path remains (#347). +- runtime/linux: `_rt_relocate` now re-protects the RELRO segment's actual mapped + extent — taken from its backing `PT_LOAD` and rounded up to `AT_PAGESZ` — rather + than the ELF writer's page-padded `p_memsz`. On a 4 KiB-page aarch64 kernel the + padded `PT_GNU_RELRO` `p_memsz` (64 KiB, mach#1845) spanned an unmapped gap, so + the `mprotect` failed with `ENOMEM` and, being fatal (#347), crashed every + `--pie` binary at startup. Std half of the arm64 startup fix (mach#1885). - system: `os.page_size` on linux now returns the runtime `AT_PAGESZ` the entrypoint captures from the auxiliary vector at startup, instead of a hardcoded 4096 — correct on aarch64 kernels configured for 16 KiB or 64 KiB @@ -72,6 +103,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 source of truth; `std.runtime.linux.reloc` keeps its own pre-relocation read for the RELRO mprotect. `AT_PAGESZ` is mandatory on linux, so page_size() panics when it is unavailable rather than fabricating a default (#336). +- data/json: `emit` now escapes string values and object keys per RFC 8259 — + `"` → `\"`, `\` → `\\`, control bytes (0x00–0x1F) via the short escapes + `\b \t \n \f \r` or else `\u00xx`, all other bytes (including valid UTF-8) + verbatim. Values or keys holding a quote, backslash, or control byte previously + emitted invalid JSON (#337). +- system/os/windows: every `ext fun` (61 kernel32 imports plus the windows + runtime entrypoint) now carries an explicit `#[library]` decorator naming its + providing DLL. The unattributed imports previously relied on the COFF fallback + binding them to dependency 0 — correct only while `kernel32.dll` sorted first — + so the first mixed-DLL link (e.g. also linking `glfw3.dll`) mis-bound whole DLL + sets and hit `STATUS_ENTRYPOINT_NOT_FOUND` at load. Purely additive (#334). ## [0.16.2] - 2026-06-28 diff --git a/mach.toml b/mach.toml index 7292457..ef9a8e1 100644 --- a/mach.toml +++ b/mach.toml @@ -1,7 +1,7 @@ [project] id = "std" name = "Mach Standard Library" -version = "0.16.2" +version = "0.17.0" src = "src" dep = "dep" target = "native" diff --git a/src/allocator.mach b/src/allocator.mach index b2bd3fe..9a60816 100644 --- a/src/allocator.mach +++ b/src/allocator.mach @@ -1,4 +1,4 @@ -# std.allocator: generic allocator interface and utilities +# generic allocator interface and utilities # # this is intended to be the glue between platform memory primitives and higher # level containers/types @@ -19,7 +19,7 @@ use std.types.string.str; use mem: std.memory; -# Allocator: backend-agnostic allocator interface +# backend-agnostic allocator interface # --- # ctx: opaque context passed to callbacks. # fn_allocate: allocate (ctx, size, align) -> ptr (nil on OOM). @@ -32,7 +32,7 @@ pub rec Allocator { fn_deallocate: fun(ptr, ptr, usize, usize) i64; } -# allocate_raw: allocate raw bytes using this allocator +# allocate raw bytes using this allocator # --- # a: allocator to use for this allocation. # size: number of bytes (0 returns nil). @@ -51,7 +51,7 @@ pub fun allocate_raw(a: *Allocator, size: usize, align: usize) Result[ptr, str] ret ok[ptr, str](unwrap[ptr](opt_fn_allocate)); } -# reallocate_raw: reallocate an allocation in-place if possible, otherwise may return a new pointer +# reallocate an allocation in-place if possible, otherwise may return a new pointer # --- # a: allocator to use for this operation # p: existing pointer (or nil to allocate new) @@ -77,7 +77,7 @@ pub fun reallocate_raw(a: *Allocator, p: ptr, old_size: usize, new_size: usize, ret ok[ptr, str](unwrap[ptr](opt_fn_reallocate)); } -# deallocate_raw: deallocate an allocation previously returned by allocate_raw or reallocate_raw +# deallocate an allocation previously returned by allocate_raw or reallocate_raw # --- # a: Allocator to use for this operation # p: pointer previously returned by allocate_raw or reallocate_raw @@ -88,7 +88,7 @@ pub fun deallocate_raw(a: *Allocator, p: ptr, size: usize, align: usize) i64 { ret a.fn_deallocate(a.ctx, p, size, align); } -# allocate: allocate count elements of type T +# allocate count elements of type T # --- # a: Allocator to use for this allocation # count: number of elements to allocate @@ -113,7 +113,7 @@ pub fun allocate[T](a: *Allocator, count: usize) Result[*T, str] { ret ok[*T, str](unwrap_ok[ptr, str](res_allocate_raw)::*T); } -# zallocate: allocate and zero-initialize count elements of T +# allocate and zero-initialize count elements of T # --- # a: Allocator to use for this allocation # count: number of elements to allocate @@ -132,7 +132,7 @@ pub fun zallocate[T](a: *Allocator, count: usize) Result[*T, str] { ret ok[*T, str](p); } -# reallocate: reallocate an allocation of T elements +# reallocate an allocation of T elements # --- # a: Allocator to use for this operation # p: existing pointer @@ -156,7 +156,7 @@ pub fun reallocate[T](a: *Allocator, p: *T, old_count: usize, new_count: usize) ret ok[*T, str](unwrap_ok[ptr, str](res_reallocate_raw)::*T); } -# deallocate: deallocate memory previously returned by alloc/zalloc for count +# deallocate memory previously returned by alloc/zalloc for count # elements. # --- # a: Allocator to use for this operation diff --git a/src/allocator/arena.mach b/src/allocator/arena.mach index 9e9d159..1740f27 100644 --- a/src/allocator/arena.mach +++ b/src/allocator/arena.mach @@ -1,4 +1,4 @@ -# std.allocator.arena: arena allocator implementation +# arena allocator implementation # # bump allocator with chunked growth. allocation is O(1) amortized. # deallocate is a no-op except for the most recent allocation which @@ -25,7 +25,7 @@ use allo: std.allocator; use page: std.allocator.page; use mem: std.memory; -# Chunk: header for each backing allocation. +# header for each backing allocation # --- # prev: previous chunk in the linked list # cap: data capacity in bytes (data follows the header) @@ -36,7 +36,7 @@ pub rec Chunk { val CHUNK_HDR: usize = 16; -# Arena: bump allocator state with chunked growth. +# bump allocator state with chunked growth # --- # backing: allocator used for chunk allocations # buf: current chunk data pointer (cached for fast-path) @@ -77,12 +77,12 @@ fun max_usize(x: usize, y: usize) usize { ret y; } -# chunk_data: get data pointer for a chunk (data follows header). +# get data pointer for a chunk (data follows header) fun chunk_data(c: *Chunk) ptr { ret (c::usize + CHUNK_HDR)::ptr; } -# alloc_chunk: allocate a new chunk with at least min_cap data bytes. +# allocate a new chunk with at least min_cap data bytes fun alloc_chunk(ar: *Arena, min_cap: usize) *Chunk { val total: usize = CHUNK_HDR + min_cap; val res: Result[ptr, str] = allo.allocate_raw(?ar.backing, total, CHUNK_HDR); @@ -94,13 +94,13 @@ fun alloc_chunk(ar: *Arena, min_cap: usize) *Chunk { ret c; } -# free_chunk: deallocate a chunk through the backing allocator. +# deallocate a chunk through the backing allocator fun free_chunk(ar: *Arena, c: *Chunk) i64 { val total: usize = CHUNK_HDR + c.cap; ret allo.deallocate_raw(?ar.backing, c::ptr, total, CHUNK_HDR); } -# grow: allocate a new chunk and make it current. +# allocate a new chunk and make it current fun grow(ar: *Arena, min_size: usize) bool { var new_cap: usize = max_usize(ar.cap * 2, min_size); new_cap = max_usize(new_cap, ar.default_cap); @@ -121,7 +121,7 @@ fun grow(ar: *Arena, min_size: usize) bool { ret true; } -# init: initialize an Arena with a backing allocator and optional initial capacity. +# initialize an Arena with a backing allocator and optional initial capacity # --- # ar: Arena to initialize # backing: allocator used to provide backing storage @@ -158,7 +158,7 @@ pub fun init(ar: *Arena, backing: *allo.Allocator, cap: usize) Option[str] { ret none[str](); } -# dnit: free all chunks and zero the Arena state. +# free all chunks and zero the Arena state # --- # ar: Arena to destroy # ret: 0 if all backing frees succeeded, or first negative errno @@ -189,7 +189,7 @@ pub fun dnit(ar: *Arena) i64 { ret first_err; } -# make: wire up an Allocator backed by this Arena. +# wire up an Allocator backed by this Arena # --- # a: Allocator to initialize # ar: initialized Arena (must outlive the Allocator) @@ -205,7 +205,7 @@ pub fun make(a: *allo.Allocator, ar: *Arena) Option[str] { ret none[str](); } -# reset: reset the Arena to empty, freeing all chunks except the first. +# reset the Arena to empty, freeing all chunks except the first # # existing allocations become invalid after reset. # --- @@ -231,7 +231,7 @@ pub fun reset(ar: *Arena) { ar.last_size = 0; } -# allocate: arena bump allocation callback. +# arena bump allocation callback fun allocate(ctx: ptr, size: usize, align: usize) Option[ptr] { if (ctx == nil) { ret none[ptr](); } @@ -269,7 +269,7 @@ fun allocate(ctx: ptr, size: usize, align: usize) Option[ptr] { ret some[ptr]((ar.buf::usize + start)::ptr); } -# reallocate: arena resize callback. in-place for the most recent allocation if space permits. +# arena resize callback. in-place for the most recent allocation if space permits fun reallocate(ctx: ptr, p: ptr, old_size: usize, new_size: usize, align: usize) Option[ptr] { if (ctx == nil) { ret none[ptr](); } @@ -307,7 +307,7 @@ fun reallocate(ctx: ptr, p: ptr, old_size: usize, new_size: usize, align: usize) ret some[ptr](q); } -# deallocate: arena free callback. rolls back the most recent allocation if matched. +# arena free callback. rolls back the most recent allocation if matched fun deallocate(ctx: ptr, p: ptr, size: usize, align: usize) i64 { if (ctx == nil) { ret -1; } diff --git a/src/allocator/bump.mach b/src/allocator/bump.mach index 13a340f..ace87c7 100644 --- a/src/allocator/bump.mach +++ b/src/allocator/bump.mach @@ -1,8 +1,8 @@ -# std.allocator.bump: brk-based bump allocator +# brk-based bump allocator # # monotonically advances a brk pointer for small allocations (< 128KB), # falls back to mmap for large allocations. deallocate is a no-op for -# brk-backed memory — individual small allocations cannot be freed, only +# brk-backed memory, individual small allocations cannot be freed, only # reclaimed on program exit. use an arena allocator for bulk-freeable # allocation patterns, or a real heap allocator for general-purpose use. @@ -21,7 +21,7 @@ use pmem: std.system.os; val MMAP_THRESHOLD: usize = 131072; val MIN_BRK_EXTEND: usize = 65536; -# BumpState: brk bump allocator tracking state. +# brk bump allocator tracking state # --- # current: current bump pointer position # end: current end of the brk region @@ -30,7 +30,7 @@ pub rec BumpState { end: usize; } -# make: initialize a bump-backed Allocator and its BumpState. +# initialize a bump-backed Allocator and its BumpState # --- # a: Allocator to initialize # state: BumpState to initialize (must outlive the Allocator) @@ -50,13 +50,13 @@ pub fun make(a: *allo.Allocator, state: *BumpState) Option[str] { ret none[str](); } -# align_up: align a value up to the given alignment (must be a power of two). +# align a value up to the given alignment (must be a power of two) fun align_up(value: usize, align: usize) usize { val mask: usize = align - 1; ret (value + mask) & ~mask; } -# allocate: allocate size bytes from the brk heap, or fall back to mmap for large allocations. +# allocate size bytes from the brk heap, or fall back to mmap for large allocations # --- # ctx: BumpState pointer # size: number of bytes to allocate @@ -99,7 +99,7 @@ fun allocate(ctx: ptr, size: usize, align: usize) Option[ptr] { ret some[ptr](aligned::ptr); } -# reallocate: reallocate a heap allocation, copying data to a new location if needed. +# reallocate a heap allocation, copying data to a new location if needed # --- # ctx: BumpState pointer # p: pointer to existing allocation @@ -141,7 +141,7 @@ fun reallocate(ctx: ptr, p: ptr, old_size: usize, new_size: usize, align: usize) ret some[ptr](new_p); } -# deallocate: deallocate a heap allocation. no-op for brk-backed memory. +# deallocate a heap allocation. no-op for brk-backed memory # --- # ctx: BumpState pointer # p: pointer to deallocate diff --git a/src/allocator/page.mach b/src/allocator/page.mach index bbd8f2e..b646ade 100644 --- a/src/allocator/page.mach +++ b/src/allocator/page.mach @@ -1,4 +1,4 @@ -# std.allocator.page: page allocator adapter +# page allocator adapter # # wraps platform page allocation functions for the Allocator interface. # alignment is ignored since page allocations are always page-aligned. @@ -12,7 +12,7 @@ use std.types.string.str; use allo: std.allocator; use pmem: std.system.os; -# make: initialize a page-backed Allocator. +# initialize a page-backed Allocator # --- # a: Allocator to initialize pub fun make(a: *allo.Allocator) Option[str] { @@ -26,7 +26,7 @@ pub fun make(a: *allo.Allocator) Option[str] { ret none[str](); } -# allocate: allocate size bytes via platform page allocator. +# allocate size bytes via platform page allocator # --- # ctx: unused context pointer # size: number of bytes to allocate @@ -40,7 +40,7 @@ fun allocate(ctx: ptr, size: usize, align: usize) Option[ptr] { ret some[ptr](p); } -# reallocate: reallocate a page-backed allocation. +# reallocate a page-backed allocation # --- # ctx: unused context pointer # p: pointer to existing allocation @@ -56,7 +56,7 @@ fun reallocate(ctx: ptr, p: ptr, old_size: usize, new_size: usize, align: usize) ret some[ptr](result); } -# deallocate: deallocate a page-backed allocation. +# deallocate a page-backed allocation # --- # ctx: unused context pointer # p: pointer to deallocate diff --git a/src/chrono/date.mach b/src/chrono/date.mach index 23287c3..1d44e04 100644 --- a/src/chrono/date.mach +++ b/src/chrono/date.mach @@ -1,4 +1,4 @@ -# calendar date and datetime types with civil date math. +# calendar date and datetime types with civil date math # # Date represents a calendar date (year, month, day). # Datetime extends Date with time-of-day and UTC offset. @@ -11,7 +11,7 @@ val SECONDS_PER_DAY: i64 = 86400; val SECONDS_PER_HOUR: i64 = 3600; val SECONDS_PER_MINUTE: i64 = 60; -# Date: a calendar date without time-of-day or timezone. +# a calendar date without time-of-day or timezone # --- # year: year (e.g. 2025) # month: month [1, 12] @@ -22,7 +22,7 @@ pub rec Date { day: i64; } -# Datetime: a calendar date with time-of-day and UTC offset. +# a calendar date with time-of-day and UTC offset # --- # year: year (e.g. 2025) # month: month [1, 12] @@ -43,7 +43,7 @@ pub rec Datetime { offset: i64; } -# is_leap_year: report whether year is a leap year. +# report whether year is a leap year # --- # year: year to test # ret: true if year is a leap year @@ -51,7 +51,7 @@ pub fun is_leap_year(year: i64) bool { ret year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); } -# days_in_month: return the number of days in a given month. +# return the number of days in a given month # --- # year: year (needed for February) # month: month [1, 12] @@ -67,7 +67,7 @@ pub fun days_in_month(year: i64, month: i64) i64 { ret 31; } -# date_from_time: extract the UTC date from a Time. +# extract the UTC date from a Time # --- # t: time instant # ret: UTC calendar date @@ -80,7 +80,7 @@ pub fun date_from_time(t: Time) Date { ret Date{year: y, month: m, day: d}; } -# datetime_from_time: extract a UTC Datetime from a Time. +# extract a UTC Datetime from a Time # --- # t: time instant # ret: UTC datetime @@ -88,7 +88,7 @@ pub fun datetime_from_time(t: Time) Datetime { ret datetime_with_offset(t, 0); } -# datetime_with_offset: extract a Datetime from a Time with a UTC offset. +# extract a Datetime from a Time with a UTC offset # --- # t: time instant # offset: UTC offset in seconds @@ -115,7 +115,7 @@ pub fun datetime_with_offset(t: Time, offset: i64) Datetime { }; } -# datetime_to_time: convert a Datetime back to a Time instant. +# convert a Datetime back to a Time instant # --- # dt: datetime to convert # ret: time instant (UTC) @@ -128,7 +128,7 @@ pub fun datetime_to_time(dt: Datetime) Time { ret unix(sec, dt.nsec); } -# date_to_time: convert a Date to a Time at midnight UTC. +# convert a Date to a Time at midnight UTC # --- # d: date to convert # ret: time instant at 00:00:00 UTC on the given date diff --git a/src/chrono/duration.mach b/src/chrono/duration.mach index 3c5dd84..ccbe4dd 100644 --- a/src/chrono/duration.mach +++ b/src/chrono/duration.mach @@ -1,4 +1,4 @@ -# elapsed time representation and conversion. +# elapsed time representation and conversion # # Duration represents elapsed time as nanoseconds (i64). @@ -6,7 +6,7 @@ use std.types.size.usize; use std.types.string.str; use std.types.string.str_equals; -# Duration: elapsed time in nanoseconds. +# elapsed time in nanoseconds pub def Duration: i64; pub val NANOSECOND: Duration = 1; @@ -16,7 +16,7 @@ pub val SECOND: Duration = 1000000000; pub val MINUTE: Duration = 60 * SECOND; pub val HOUR: Duration = 60 * MINUTE; -# duration_nsec: return the duration as nanoseconds. +# return the duration as nanoseconds # --- # d: duration to convert # ret: duration in nanoseconds @@ -24,7 +24,7 @@ pub fun duration_nsec(d: Duration) i64 { ret d; } -# duration_usec: return the duration as microseconds. +# return the duration as microseconds # --- # d: duration to convert # ret: duration in microseconds @@ -32,7 +32,7 @@ pub fun duration_usec(d: Duration) i64 { ret d / MICROSECOND; } -# duration_msec: return the duration as milliseconds. +# return the duration as milliseconds # --- # d: duration to convert # ret: duration in milliseconds @@ -40,7 +40,7 @@ pub fun duration_msec(d: Duration) i64 { ret d / MILLISECOND; } -# duration_sec: return the duration as whole seconds. +# return the duration as whole seconds # --- # d: duration to convert # ret: duration in seconds @@ -48,7 +48,7 @@ pub fun duration_sec(d: Duration) i64 { ret d / SECOND; } -# duration_min: return the duration as whole minutes. +# return the duration as whole minutes # --- # d: duration to convert # ret: duration in minutes @@ -56,7 +56,7 @@ pub fun duration_min(d: Duration) i64 { ret d / MINUTE; } -# duration_hour: return the duration as whole hours. +# return the duration as whole hours # --- # d: duration to convert # ret: duration in hours @@ -64,7 +64,7 @@ pub fun duration_hour(d: Duration) i64 { ret d / HOUR; } -# duration_abs: return the absolute value of d. +# return the absolute value of d # --- # d: duration to take absolute value of # ret: |d| @@ -77,7 +77,7 @@ pub fun duration_abs(d: Duration) Duration { ret d; } -# du_put: append byte b into buf at off if it fits; ret new offset, or cap + 1 +# append byte b into buf at off if it fits; ret new offset, or cap + 1 # when the buffer is full (a poison value that later appends propagate). fun du_put(buf: *u8, off: usize, cap: usize, b: u8) usize { if (off >= cap) { ret cap + 1; } @@ -85,7 +85,7 @@ fun du_put(buf: *u8, off: usize, cap: usize, b: u8) usize { ret off + 1; } -# du_put_str: append a null-terminated string into buf at off; ret new offset +# append a null-terminated string into buf at off; ret new offset # (poison-propagating like du_put). fun du_put_str(buf: *u8, off: usize, cap: usize, s: str) usize { var o: usize = off; @@ -97,7 +97,7 @@ fun du_put_str(buf: *u8, off: usize, cap: usize, s: str) usize { ret o; } -# du_put_u64: append n's decimal digits into buf at off; ret new offset (poison +# append n's decimal digits into buf at off; ret new offset (poison # value > cap when the digits would not fit). fun du_put_u64(buf: *u8, off: usize, cap: usize, n: u64) usize { if (n == 0) { ret du_put(buf, off, cap, '0'); } @@ -118,7 +118,7 @@ fun du_put_u64(buf: *u8, off: usize, cap: usize, n: u64) usize { ret off + len; } -# format_duration: render d as a compact ASCII human-readable string into buf. +# render d as a compact ASCII human-readable string into buf # --- # writes a null-terminated string and returns it (aliasing buf), or nil if cap # is too small to hold the rendering plus its terminator. negative durations diff --git a/src/chrono/format.mach b/src/chrono/format.mach index 8d6886e..24be9fd 100644 --- a/src/chrono/format.mach +++ b/src/chrono/format.mach @@ -1,4 +1,4 @@ -# date and time formatting. +# date and time formatting # # provides formatters for standard time representations. # intended usage: `use fmt: std.chrono.format;` then `fmt.rfc3339(dt, buf, len)`. @@ -17,7 +17,7 @@ use std.chrono.date.civil_to_days; val SECONDS_PER_HOUR: i64 = 3600; val SECONDS_PER_MINUTE: i64 = 60; -# rfc3339: write a Datetime as RFC 3339 into a buffer. +# write a Datetime as RFC 3339 into a buffer # # output: YYYY-MM-DDTHH:MM:SSZ, YYYY-MM-DDTHH:MM:SS+HH:MM, # or with fractional seconds when nsec != 0. @@ -75,7 +75,7 @@ pub fun rfc3339(dt: Datetime, buf: *u8, len: usize) usize { ret pos; } -# rfc3339_date: write a Date as RFC 3339 full-date into a buffer. +# write a Date as RFC 3339 full-date into a buffer # # output: YYYY-MM-DD # --- @@ -96,7 +96,7 @@ pub fun rfc3339_date(d: Date, buf: *u8, len: usize) usize { ret 10; } -# rfc2822: write a Datetime as RFC 2822 into a buffer. +# write a Datetime as RFC 2822 into a buffer # # output: Fri, 13 Feb 2009 23:31:30 +0000 # --- @@ -142,7 +142,7 @@ pub fun rfc2822(dt: Datetime, buf: *u8, len: usize) usize { ret 31; } -# unix_sec: write seconds as decimal Unix timestamp into a buffer. +# write seconds as decimal Unix timestamp into a buffer # --- # sec: seconds since epoch # buf: output buffer (at least 21 bytes) diff --git a/src/chrono/time.mach b/src/chrono/time.mach index 2210e50..8cda353 100644 --- a/src/chrono/time.mach +++ b/src/chrono/time.mach @@ -1,4 +1,4 @@ -# instant in time with nanosecond precision. +# instant in time with nanosecond precision # # Time represents an absolute point in time as seconds + nanoseconds # since the Unix epoch (1970-01-01 00:00:00 UTC). @@ -13,7 +13,7 @@ use std.chrono.duration.SECOND; use os: std.system.os; -# Time: an instant in time with nanosecond precision. +# an instant in time with nanosecond precision # --- # sec: seconds since Unix epoch (1970-01-01 00:00:00 UTC) # nsec: nanoseconds within second [0, 999999999] @@ -22,7 +22,7 @@ pub rec Time { nsec: i64; } -# now: return the current wall-clock time. +# return the current wall-clock time # --- # ret: current Time from system clock, zero on error pub fun now() Time { @@ -31,7 +31,7 @@ pub fun now() Time { ret Time{sec: ts.sec, nsec: ts.nsec}; } -# monotonic: return the current monotonic clock time. +# return the current monotonic clock time # --- # ret: current Time from monotonic clock (for measuring elapsed time), zero on error pub fun monotonic() Time { @@ -40,7 +40,7 @@ pub fun monotonic() Time { ret Time{sec: ts.sec, nsec: ts.nsec}; } -# unix: create a Time from a Unix timestamp. +# create a Time from a Unix timestamp # --- # sec: seconds since Unix epoch # nsec: nanoseconds within second @@ -62,7 +62,7 @@ pub fun unix(sec: i64, nsec: i64) Time { ret Time{sec: s, nsec: n}; } -# since: return the time elapsed since t. +# return the time elapsed since t # --- # t: start time # ret: duration since t @@ -70,7 +70,7 @@ pub fun since(t: Time) Duration { ret time_sub(now(), t); } -# until: return the duration until t. +# return the duration until t # --- # t: target time # ret: duration until t @@ -78,7 +78,7 @@ pub fun until(t: Time) Duration { ret time_sub(t, now()); } -# time_unix_sec: return seconds since Unix epoch. +# return seconds since Unix epoch # --- # t: time to query # ret: seconds component @@ -86,7 +86,7 @@ pub fun time_unix_sec(t: Time) i64 { ret t.sec; } -# time_unix_nsec: return nanoseconds since Unix epoch. +# return nanoseconds since Unix epoch # --- # t: time to query # ret: total nanoseconds since epoch @@ -94,7 +94,7 @@ pub fun time_unix_nsec(t: Time) i64 { ret t.sec * SECOND + t.nsec; } -# time_unix_usec: return microseconds since Unix epoch. +# return microseconds since Unix epoch # --- # t: time to query # ret: total microseconds since epoch @@ -102,7 +102,7 @@ pub fun time_unix_usec(t: Time) i64 { ret t.sec * (SECOND / MICROSECOND) + t.nsec / MICROSECOND; } -# time_unix_msec: return milliseconds since Unix epoch. +# return milliseconds since Unix epoch # --- # t: time to query # ret: total milliseconds since epoch @@ -110,7 +110,7 @@ pub fun time_unix_msec(t: Time) i64 { ret t.sec * (SECOND / MILLISECOND) + t.nsec / MILLISECOND; } -# time_add: return t + d. +# return t + d # --- # t: base time # d: duration to add @@ -131,7 +131,7 @@ pub fun time_add(t: Time, d: Duration) Time { ret Time{sec: sec, nsec: nsec}; } -# time_sub: return the duration t - u. +# return the duration t - u # --- # t: minuend time # u: subtrahend time @@ -140,7 +140,7 @@ pub fun time_sub(t: Time, u: Time) Duration { ret (t.sec - u.sec) * SECOND + (t.nsec - u.nsec); } -# time_before: report whether t is before u. +# report whether t is before u # --- # t: time to test # u: time to compare against @@ -151,7 +151,7 @@ pub fun time_before(t: Time, u: Time) bool { ret t.nsec < u.nsec; } -# time_after: report whether t is after u. +# report whether t is after u # --- # t: time to test # u: time to compare against @@ -162,7 +162,7 @@ pub fun time_after(t: Time, u: Time) bool { ret t.nsec > u.nsec; } -# time_equal: report whether t and u represent the same instant. +# report whether t and u represent the same instant # --- # t: first time # u: second time @@ -171,7 +171,7 @@ pub fun time_equal(t: Time, u: Time) bool { ret t.sec == u.sec && t.nsec == u.nsec; } -# time_is_zero: report whether t represents the zero time instant. +# report whether t represents the zero time instant # --- # t: time to test # ret: true if t is the zero time (Unix epoch) diff --git a/src/collections/bitset.mach b/src/collections/bitset.mach index 9e98940..26c52d5 100644 --- a/src/collections/bitset.mach +++ b/src/collections/bitset.mach @@ -1,4 +1,4 @@ -# dynamic bitset backed by allocator. +# dynamic bitset backed by allocator use std.types.bool.bool; use std.types.bool.true; @@ -17,7 +17,7 @@ use bits: std.math.bits; use allocator: std.allocator; use page: std.allocator.page; -# Bitset: dynamic bitset storing nbits bits in an array of u64 words. +# dynamic bitset storing nbits bits in an array of u64 words # --- # alloc: allocator for backing storage # words: pointer to the u64 word array @@ -30,7 +30,7 @@ pub rec Bitset { nwords: usize; } -# init: create a bitset with all bits cleared. +# create a bitset with all bits cleared # --- # alloc: allocator for backing storage # nbits: number of bits @@ -54,7 +54,7 @@ pub fun init(alloc: *allocator.Allocator, nbits: usize) Result[Bitset, str] { ret ok[Bitset, str](bs); } -# dnit: free the backing word array. +# free the backing word array # --- # ret: true if memory was freed successfully pub fun dnit(bs: *Bitset) bool { @@ -71,7 +71,7 @@ pub fun dnit(bs: *Bitset) bool { ret freed; } -# set: set the bit at the given index. +# set the bit at the given index # --- # idx: bit index pub fun set(bs: *Bitset, idx: usize) { @@ -81,7 +81,7 @@ pub fun set(bs: *Bitset, idx: usize) { bs.words[word] = bs.words[word] | (1::u64 << bit); } -# clear: clear the bit at the given index. +# clear the bit at the given index # --- # idx: bit index pub fun clear(bs: *Bitset, idx: usize) { @@ -91,7 +91,7 @@ pub fun clear(bs: *Bitset, idx: usize) { bs.words[word] = bs.words[word] & ~(1::u64 << bit); } -# get: test the bit at the given index. +# test the bit at the given index # --- # idx: bit index # ret: true if the bit is set, false if cleared or out of range @@ -102,7 +102,7 @@ pub fun get(bs: *Bitset, idx: usize) bool { ret (bs.words[word] & (1::u64 << bit)) != 0; } -# toggle: flip the bit at the given index. +# flip the bit at the given index # --- # idx: bit index pub fun toggle(bs: *Bitset, idx: usize) { @@ -112,7 +112,7 @@ pub fun toggle(bs: *Bitset, idx: usize) { bs.words[word] = bs.words[word] ^ (1::u64 << bit); } -# count: count the number of set bits. +# count the number of set bits # --- # ret: population count pub fun count(bs: *Bitset) usize { @@ -125,13 +125,13 @@ pub fun count(bs: *Bitset) usize { ret total; } -# clear_all: clear all bits to zero. +# clear all bits to zero pub fun clear_all(bs: *Bitset) { if (bs.nwords == 0) { ret; } mem.zero[u64](bs.words, bs.nwords); } -# set_all: set all bits to one, masking the trailing word. +# set all bits to one, masking the trailing word pub fun set_all(bs: *Bitset) { if (bs.nwords == 0) { ret; } mem.fill[u64](bs.words, 0xffffffffffffffff, bs.nwords); diff --git a/src/collections/deque.mach b/src/collections/deque.mach index 7f6600b..c1ad891 100644 --- a/src/collections/deque.mach +++ b/src/collections/deque.mach @@ -1,4 +1,4 @@ -# double-ended queue (ring buffer). +# double-ended queue (ring buffer) use std.types.bool.bool; use std.types.bool.true; @@ -23,7 +23,7 @@ pub rec Deque[T] { cap: usize; } -# create an empty deque. +# create an empty deque # --- # alloc: allocator to use for allocations # ret: a new empty Deque[T] @@ -37,7 +37,7 @@ pub fun init[T](alloc: *allo.Allocator) Deque[T] { ret dq; } -# free the backing buffer. +# free the backing buffer # --- # ret: true if memory was freed successfully pub fun dnit[T](dq: *Deque[T]) bool { @@ -60,21 +60,21 @@ pub fun dnit[T](dq: *Deque[T]) bool { ret freed; } -# check if the deque is empty. +# check if the deque is empty # --- # ret: true if the deque has no elements pub fun is_empty[T](dq: Deque[T]) bool { ret dq.len == 0; } -# return the number of elements in the deque. +# return the number of elements in the deque # --- # ret: number of elements pub fun length[T](dq: Deque[T]) usize { ret dq.len; } -# grow the ring buffer to at least double its current capacity. +# grow the ring buffer to at least double its current capacity # --- # ret: ok with new capacity, or error fun grow[T](dq: *Deque[T]) Result[usize, str] { @@ -113,7 +113,7 @@ fun grow[T](dq: *Deque[T]) Result[usize, str] { ret ok[usize, str](new_cap); } -# append a value to the back of the deque. +# append a value to the back of the deque # --- # value: value to append # ret: the new length, or an error @@ -132,7 +132,7 @@ pub fun push_back[T](dq: *Deque[T], value: T) Result[usize, str] { ret ok[usize, str](dq.len); } -# prepend a value to the front of the deque. +# prepend a value to the front of the deque # --- # value: value to prepend # ret: the new length, or an error @@ -151,7 +151,7 @@ pub fun push_front[T](dq: *Deque[T], value: T) Result[usize, str] { ret ok[usize, str](dq.len); } -# remove and return the element at the back. +# remove and return the element at the back # --- # ret: the value, or an error if empty pub fun pop_back[T](dq: *Deque[T]) Result[T, str] { @@ -165,7 +165,7 @@ pub fun pop_back[T](dq: *Deque[T]) Result[T, str] { ret ok[T, str](dq.data[idx]); } -# remove and return the element at the front. +# remove and return the element at the front # --- # ret: the value, or an error if empty pub fun pop_front[T](dq: *Deque[T]) Result[T, str] { @@ -180,7 +180,7 @@ pub fun pop_front[T](dq: *Deque[T]) Result[T, str] { ret ok[T, str](value); } -# get a pointer to the element at the given logical index. +# get a pointer to the element at the given logical index # --- # index: logical index (0 = front) # ret: pointer to element, or an error @@ -194,7 +194,7 @@ pub fun get[T](dq: *Deque[T], index: usize) Result[*T, str] { ret ok[*T, str](?dq.data[phys]); } -# reset the deque to empty without freeing memory. +# reset the deque to empty without freeing memory pub fun clear[T](dq: *Deque[T]) { if (dq == nil) { ret; } dq.len = 0; diff --git a/src/collections/heap.mach b/src/collections/heap.mach index c941ac0..7502033 100644 --- a/src/collections/heap.mach +++ b/src/collections/heap.mach @@ -1,4 +1,4 @@ -# binary min-heap (priority queue). +# binary min-heap (priority queue) use std.types.bool.bool; use std.types.bool.true; @@ -23,7 +23,7 @@ pub rec Heap[T] { cmp: fun(*T, *T) i64; } -# create an empty min-heap. +# create an empty min-heap # --- # alloc: allocator to use for allocations # cmp: comparison function (negative if a < b, 0 if equal, positive if a > b) @@ -38,7 +38,7 @@ pub fun init[T](alloc: *allo.Allocator, cmp: fun(*T, *T) i64) Heap[T] { ret h; } -# free the backing buffer. +# free the backing buffer # --- # ret: true if memory was freed successfully pub fun dnit[T](h: *Heap[T]) bool { @@ -59,21 +59,21 @@ pub fun dnit[T](h: *Heap[T]) bool { ret freed; } -# check if the heap is empty. +# check if the heap is empty # --- # ret: true if the heap has no elements pub fun is_empty[T](h: Heap[T]) bool { ret h.len == 0; } -# return the number of elements in the heap. +# return the number of elements in the heap # --- # ret: number of elements pub fun length[T](h: Heap[T]) usize { ret h.len; } -# grow the backing buffer to at least double capacity. +# grow the backing buffer to at least double capacity # --- # ret: ok with new capacity, or error fun grow[T](h: *Heap[T]) Result[usize, str] { @@ -98,7 +98,7 @@ fun grow[T](h: *Heap[T]) Result[usize, str] { ret ok[usize, str](new_cap); } -# restore heap property upward from the given index. +# restore heap property upward from the given index fun sift_up[T](h: *Heap[T], start: usize) { var i: usize = start; for (i > 0) { @@ -114,7 +114,7 @@ fun sift_up[T](h: *Heap[T], start: usize) { } } -# restore heap property downward from the given index. +# restore heap property downward from the given index fun sift_down[T](h: *Heap[T], start: usize) { var i: usize = start; for (i < h.len) { @@ -145,7 +145,7 @@ fun sift_down[T](h: *Heap[T], start: usize) { } } -# add an element to the heap. +# add an element to the heap # --- # value: value to insert # ret: the new length, or an error @@ -163,7 +163,7 @@ pub fun push[T](h: *Heap[T], value: T) Result[usize, str] { ret ok[usize, str](h.len); } -# remove and return the minimum element. +# remove and return the minimum element # --- # ret: the minimum value, or an error if empty pub fun pop[T](h: *Heap[T]) Result[T, str] { @@ -182,7 +182,7 @@ pub fun pop[T](h: *Heap[T]) Result[T, str] { ret ok[T, str](min_val); } -# return a pointer to the minimum element without removing it. +# return a pointer to the minimum element without removing it # --- # ret: pointer to the minimum element, or an error if empty pub fun peek[T](h: *Heap[T]) Result[*T, str] { diff --git a/src/collections/map.mach b/src/collections/map.mach index 4ff8115..c28f536 100644 --- a/src/collections/map.mach +++ b/src/collections/map.mach @@ -1,4 +1,4 @@ -# std.collections.map: generic hash map using open addressing with linear probing +# generic hash map using open addressing with linear probing # # keys and values are stored in parallel arrays. a separate "state" array tracks # which slots are empty, occupied, or tombstones (deleted). @@ -28,7 +28,7 @@ val SLOT_TOMBSTONE: u8 = 2; val DEFAULT_CAPACITY: usize = 16; val LOAD_FACTOR_PERCENT: usize = 70; -# Map[K, V]: generic hash map with user-provided hash and equality functions. +# generic hash map with user-provided hash and equality functions # --- # alloc: allocator for backing storage # keys: key buffer @@ -51,7 +51,7 @@ pub rec Map[K, V] { eq_fn: fun(ptr, ptr) bool; } -# init: create an empty map. +# create an empty map # --- # alloc: allocator to use for backing storage # hash_fn: hash function for keys @@ -71,7 +71,7 @@ pub fun init[K, V](alloc: *allocator.Allocator, hash_fn: fun(ptr) u64, eq_fn: fu ret m; } -# dnit: free all backing storage and reset the map. +# free all backing storage and reset the map # --- # ret: true if memory was freed successfully pub fun dnit[K, V](m: *Map[K, V]) bool { @@ -100,28 +100,28 @@ pub fun dnit[K, V](m: *Map[K, V]) bool { ret ok; } -# is_empty: check if the map has no entries. +# check if the map has no entries # --- # ret: true if the map has no entries pub fun is_empty[K, V](m: Map[K, V]) bool { ret m.len == 0; } -# length: return the number of entries in the map. +# return the number of entries in the map # --- # ret: number of entries pub fun length[K, V](m: Map[K, V]) usize { ret m.len; } -# capacity: return the current capacity in slots. +# return the current capacity in slots # --- # ret: capacity in slots pub fun capacity[K, V](m: Map[K, V]) usize { ret m.cap; } -# clear: remove all entries but keep allocated capacity. +# remove all entries but keep allocated capacity pub fun clear[K, V](m: *Map[K, V]) { if (m == nil || m.cap == 0) { ret; } mem.raw_fill(m.states::ptr, SLOT_EMPTY, m.cap); @@ -129,7 +129,7 @@ pub fun clear[K, V](m: *Map[K, V]) { m.tombstones = 0; } -# find_slot: locate the slot for a key, or the first available slot. +# locate the slot for a key, or the first available slot # --- # key: pointer to the key to find # ret: (idx, found) where found indicates an exact match @@ -185,7 +185,7 @@ fun find_slot[K, V](m: *Map[K, V], key: *K) rec { idx: usize; found: bool; } { ret result; } -# grow: resize the map and rehash all entries. +# resize the map and rehash all entries # --- # new_cap: target capacity # ret: the new capacity, or an error message @@ -254,7 +254,7 @@ fun grow[K, V](m: *Map[K, V], new_cap: usize) Result[usize, str] { ret ok[usize, str](new_cap); } -# ensure_capacity: ensure room for at least one more entry. +# ensure room for at least one more entry # --- # ret: the current capacity, or an error message fun ensure_capacity[K, V](m: *Map[K, V]) Result[usize, str] { @@ -278,7 +278,7 @@ fun ensure_capacity[K, V](m: *Map[K, V]) Result[usize, str] { ret ok[usize, str](m.cap); } -# insert: insert or update a key-value pair. +# insert or update a key-value pair # --- # key: key to insert # value: value to associate @@ -308,7 +308,7 @@ pub fun insert[K, V](m: *Map[K, V], key: K, value: V) Result[bool, str] { ret ok[bool, str](true); } -# get: get a pointer to the value associated with a key. +# get a pointer to the value associated with a key # --- # key: pointer to the key to look up # ret: pointer to the value, or an error message @@ -326,7 +326,7 @@ pub fun get[K, V](m: *Map[K, V], key: *K) Result[*V, str] { ret ok[*V, str](?m.values[slot.idx]); } -# contains: check if the map contains a key. +# check if the map contains a key # --- # key: pointer to the key to check # ret: true if the key exists @@ -337,7 +337,7 @@ pub fun contains[K, V](m: *Map[K, V], key: *K) bool { ret slot.found; } -# remove: remove a key-value pair from the map. +# remove a key-value pair from the map # --- # key: pointer to the key to remove # ret: true if removed, false if the key was not found @@ -359,7 +359,7 @@ pub fun remove[K, V](m: *Map[K, V], key: *K) Result[bool, str] { ret ok[bool, str](true); } -# hash_str: FNV-1a hash for strings. +# FNV-1a hash for strings pub fun hash_str(p: ptr) u64 { val s: *str = p::*str; val FNV_OFFSET: u64 = 14695981039346656037; @@ -381,14 +381,14 @@ pub fun hash_str(p: ptr) u64 { ret hash; } -# eq_str: equality function for strings. +# equality function for strings pub fun eq_str(pa: ptr, pb: ptr) bool { val a: *str = pa::*str; val b: *str = pb::*str; ret str_equals(@a, @b); } -# hash_i64: splitmix64 hash for i64. +# splitmix64 hash for i64 pub fun hash_i64(p: ptr) u64 { val n: *i64 = p::*i64; var x: u64 = (@n)::u64; @@ -400,14 +400,14 @@ pub fun hash_i64(p: ptr) u64 { ret x; } -# eq_i64: equality function for i64. +# equality function for i64 pub fun eq_i64(pa: ptr, pb: ptr) bool { val a: *i64 = pa::*i64; val b: *i64 = pb::*i64; ret @a == @b; } -# hash_u64: splitmix64 hash for u64. +# splitmix64 hash for u64 pub fun hash_u64(p: ptr) u64 { val n: *u64 = p::*u64; var x: u64 = @n; @@ -419,14 +419,14 @@ pub fun hash_u64(p: ptr) u64 { ret x; } -# eq_u64: equality function for u64. +# equality function for u64 pub fun eq_u64(pa: ptr, pb: ptr) bool { val a: *u64 = pa::*u64; val b: *u64 = pb::*u64; ret @a == @b; } -# hash_u32: splitmix64 hash for u32. +# splitmix64 hash for u32 pub fun hash_u32(p: ptr) u64 { val n: *u32 = p::*u32; var x: u64 = (@n)::u64; @@ -438,7 +438,7 @@ pub fun hash_u32(p: ptr) u64 { ret x; } -# eq_u32: equality function for u32. +# equality function for u32 pub fun eq_u32(pa: ptr, pb: ptr) bool { val a: *u32 = pa::*u32; val b: *u32 = pb::*u32; diff --git a/src/collections/set.mach b/src/collections/set.mach index 9083960..63b1715 100644 --- a/src/collections/set.mach +++ b/src/collections/set.mach @@ -1,4 +1,4 @@ -# hash set backed by Map. +# hash set backed by Map use std.types.bool.bool; use std.types.bool.true; @@ -15,14 +15,14 @@ use allocator: std.allocator; use page: std.allocator.page; use map: std.collections.map; -# Set[K]: hash set storing unique keys. +# hash set storing unique keys # --- # inner: backing hash map with u8 dummy values pub rec Set[K] { inner: map.Map[K, u8]; } -# init: create an empty set. +# create an empty set # --- # alloc: allocator for backing storage # hash_fn: hash function for keys @@ -34,28 +34,28 @@ pub fun init[K](alloc: *allocator.Allocator, hash_fn: fun(ptr) u64, eq_fn: fun(p ret s; } -# dnit: free all backing storage and reset the set. +# free all backing storage and reset the set # --- # ret: true if memory was freed successfully pub fun dnit[K](s: *Set[K]) bool { ret map.dnit[K, u8](?s.inner); } -# is_empty: check if the set has no entries. +# check if the set has no entries # --- # ret: true if the set is empty pub fun is_empty[K](s: Set[K]) bool { ret map.is_empty[K, u8](s.inner); } -# length: return the number of entries in the set. +# return the number of entries in the set # --- # ret: number of entries pub fun length[K](s: Set[K]) usize { ret map.length[K, u8](s.inner); } -# insert: add a key to the set. +# add a key to the set # --- # key: key to insert # ret: ok(true) if the key was new, ok(false) if it already existed @@ -63,7 +63,7 @@ pub fun insert[K](s: *Set[K], key: K) Result[bool, str] { ret map.insert[K, u8](?s.inner, key, 0); } -# contains: check if the set contains a key. +# check if the set contains a key # --- # key: pointer to the key to check # ret: true if the key exists @@ -71,7 +71,7 @@ pub fun contains[K](s: *Set[K], key: *K) bool { ret map.contains[K, u8](?s.inner, key); } -# remove: remove a key from the set. +# remove a key from the set # --- # key: pointer to the key to remove # ret: ok(true) if removed, ok(false) if the key was not found @@ -79,7 +79,7 @@ pub fun remove[K](s: *Set[K], key: *K) Result[bool, str] { ret map.remove[K, u8](?s.inner, key); } -# clear: remove all entries but keep allocated capacity. +# remove all entries but keep allocated capacity pub fun clear[K](s: *Set[K]) { map.clear[K, u8](?s.inner); } diff --git a/src/collections/slice.mach b/src/collections/slice.mach index 24c46b2..83c60d9 100644 --- a/src/collections/slice.mach +++ b/src/collections/slice.mach @@ -9,7 +9,7 @@ use std.types.result.Result; use std.types.result.ok; use std.types.result.err; -# Slice[T]: pointer + length view over a contiguous sequence of T. +# pointer + length view over a contiguous sequence of T # --- # data: pointer to the first element # size: number of elements in the slice @@ -18,7 +18,7 @@ pub rec Slice[T] { size: usize; } -# make: create a Slice[T] from a pointer and element count. +# create a Slice[T] from a pointer and element count # --- # data: pointer to the data # size: number of elements @@ -30,12 +30,12 @@ pub fun make[T](data: *T, size: usize) Slice[T] { ret s; } -# is_empty: check if the slice has no elements. +# check if the slice has no elements pub fun is_empty[T](s: Slice[T]) bool { ret s.size == 0; } -# get: retrieve a reference to the element at the given index. +# retrieve a reference to the element at the given index # --- # s: slice to access # index: element index @@ -45,7 +45,7 @@ pub fun get[T](s: Slice[T], index: usize) Result[*T, str] { ret ok[*T, str](?s.data[index]); } -# set: update the element at the given index. +# update the element at the given index # --- # s: slice to modify # index: element index diff --git a/src/collections/sort.mach b/src/collections/sort.mach index e00690b..271b8d0 100644 --- a/src/collections/sort.mach +++ b/src/collections/sort.mach @@ -1,4 +1,4 @@ -# in-place sorting, searching, and array utilities. +# in-place sorting, searching, and array utilities use std.types.bool.bool; use std.types.bool.true; @@ -12,7 +12,7 @@ use std.types.result.is_err; use std.types.result.unwrap_ok; use std.types.result.unwrap_err; -# swap: exchange the values at two pointers. +# exchange the values at two pointers # --- # a: pointer to the first element # b: pointer to the second element @@ -22,7 +22,7 @@ pub fun swap[T](a: *T, b: *T) { @b = tmp; } -# reverse: reverse an array in place. +# reverse an array in place # --- # data: pointer to the array # len: number of elements @@ -37,7 +37,7 @@ pub fun reverse[T](data: *T, len: usize) { } } -# sort: in-place shell sort with Ciura gap sequence. +# in-place shell sort with Ciura gap sequence # --- # data: pointer to the array # len: number of elements @@ -68,7 +68,7 @@ pub fun sort[T](data: *T, len: usize, cmp: fun(*T, *T) i64) { } } -# gap_at: return the shell sort gap at the given index. +# return the shell sort gap at the given index fun gap_at(idx: usize) usize { if (idx == 0) { ret 701; } if (idx == 1) { ret 301; } @@ -80,7 +80,7 @@ fun gap_at(idx: usize) usize { ret 1; } -# is_sorted: check if an array is sorted according to the comparator. +# check if an array is sorted according to the comparator # --- # data: pointer to the array # len: number of elements @@ -98,7 +98,7 @@ pub fun is_sorted[T](data: *T, len: usize, cmp: fun(*T, *T) i64) bool { ret true; } -# binary_search: search for a target in a sorted array. +# search for a target in a sorted array # --- # data: pointer to the sorted array # len: number of elements diff --git a/src/collections/vector.mach b/src/collections/vector.mach index 700076e..7366179 100644 --- a/src/collections/vector.mach +++ b/src/collections/vector.mach @@ -15,7 +15,7 @@ use std.types.result.unwrap_err; use allo: std.allocator; use page: std.allocator.page; -# Vector: resizable vector backed by an allo. +# resizable vector backed by an allo pub rec Vector[T] { alloc: *allo.Allocator; data: *T; @@ -23,7 +23,7 @@ pub rec Vector[T] { cap: usize; } -# init: create an empty vector using the provided allocator +# create an empty vector using the provided allocator # --- # alloc: allocator to use for allocations # ret: a new empty Vector[T] @@ -36,7 +36,7 @@ pub fun init[T](alloc: *allo.Allocator) Vector[T] { ret v; } -# dnit: free the backing buffer and reset the vector fields. +# free the backing buffer and reset the vector fields # --- # ret: true if memory was freed successfully pub fun dnit[T](vec: *Vector[T]) bool { @@ -57,14 +57,14 @@ pub fun dnit[T](vec: *Vector[T]) bool { ret freed; } -# is_empty: check if the vector is empty. +# check if the vector is empty # --- # ret: true if the vector has no elements pub fun is_empty[T](vec: Vector[T]) bool { ret vec.len == 0; } -# length: return the number of elements in the vector. +# return the number of elements in the vector # --- # vec: vector to query # ret: number of elements @@ -72,7 +72,7 @@ pub fun length[T](vec: Vector[T]) usize { ret vec.len; } -# capacity: return the current capacity of the vector. +# return the current capacity of the vector # --- # vec: vector to query # ret: number of elements the vector can hold before reallocating @@ -80,13 +80,13 @@ pub fun capacity[T](vec: Vector[T]) usize { ret vec.cap; } -# clear: clear the vector contents but keep allocated capacity. +# clear the vector contents but keep allocated capacity pub fun clear[T](vec: *Vector[T]) { if (vec == nil) { ret; } vec.len = 0; } -# reserve: ensure there is room for additional elements. +# ensure there is room for additional elements # --- # additional: number of extra elements to reserve space for # ret: the new capacity, or an error message @@ -129,7 +129,7 @@ pub fun reserve[T](vec: *Vector[T], additional: usize) Result[usize, str] { ret ok[usize, str](vec.cap); } -# push: append a value to the vector. +# append a value to the vector # --- # value: value to append # ret: the new length, or an error message @@ -144,7 +144,7 @@ pub fun push[T](vec: *Vector[T], value: T) Result[usize, str] { ret ok[usize, str](vec.len); } -# pop: remove and return the last element. +# remove and return the last element # --- # ret: the value, or an error message if empty pub fun pop[T](vec: *Vector[T]) Result[T, str] { @@ -157,7 +157,7 @@ pub fun pop[T](vec: *Vector[T]) Result[T, str] { ret ok[T, str](vec.data[vec.len]); } -# get: get a pointer to the element at the given index. +# get a pointer to the element at the given index # --- # index: element index # ret: pointer to the element, or an error message diff --git a/src/crypto/hash/fnv1a.mach b/src/crypto/hash/fnv1a.mach index cdedc84..381f3b1 100644 --- a/src/crypto/hash/fnv1a.mach +++ b/src/crypto/hash/fnv1a.mach @@ -1,17 +1,17 @@ -# std.crypto.hash.fnv1a: incremental FNV-1a hashing. +# incremental FNV-1a hashing # # the type interners hash composite records field-by-field rather than over a # contiguous byte buffer, so they need an incremental folding API. this mirrors # the byte-wise FNV-1a used by the stdlib map's `hash_str`, exposed as the # `FNV_INIT` seed constant plus per-value `step_*` folds. -# FNV-1a 64-bit prime. +# FNV-1a 64-bit prime pub val FNV_PRIME: u64 = 1099511628211; -# FNV-1a 64-bit offset basis. +# FNV-1a 64-bit offset basis pub val FNV_OFFSET: u64 = 14695981039346656037; pub val FNV_INIT: u64 = FNV_OFFSET; -# step_u8: fold one byte into the running hash. +# fold one byte into the running hash # --- # h: running hash # v: byte to fold in @@ -22,7 +22,7 @@ pub fun step_u8(h: u64, v: u8) u64 { ret x; } -# step_u32: fold a 32-bit value into the running hash, byte by byte (little-endian). +# fold a 32-bit value into the running hash, byte by byte (little-endian) # --- # h: running hash # v: value to fold in diff --git a/src/crypto/hash/sha256.mach b/src/crypto/hash/sha256.mach index bf87dcf..4fc6e2f 100644 --- a/src/crypto/hash/sha256.mach +++ b/src/crypto/hash/sha256.mach @@ -1,4 +1,4 @@ -# SHA-256 cryptographic hash. +# SHA-256 cryptographic hash use std.types.bool.bool; use std.types.size.usize; @@ -8,17 +8,17 @@ pub val DIGEST_SIZE: usize = 32; pub val BLOCK_SIZE: usize = 64; pub rec State { - h0: u32; - h1: u32; - h2: u32; - h3: u32; - h4: u32; - h5: u32; - h6: u32; - h7: u32; - buf: [64]u8; + h0: u32; + h1: u32; + h2: u32; + h3: u32; + h4: u32; + h5: u32; + h6: u32; + h7: u32; + buf: [64]u8; buf_len: usize; - total: u64; + total: u64; } val K: [64]u32 = [64]u32{ @@ -127,7 +127,7 @@ fun process_block(s: *State, block: *u8) { s.h7 = s.h7 + h; } -# initialize a new SHA-256 state with standard IV. +# initialize a new SHA-256 state with standard IV # --- # ret: initialized state pub fun init() State { @@ -145,7 +145,7 @@ pub fun init() State { ret s; } -# feed data into the hash state. +# feed data into the hash state # --- # s: pointer to hash state # data: pointer to input bytes @@ -178,7 +178,7 @@ pub fun update(s: *State, data: *u8, len: usize) { } } -# finalize the hash and write the 32-byte digest. +# finalize the hash and write the 32-byte digest # --- # s: pointer to hash state # digest: pointer to 32-byte output buffer @@ -223,7 +223,7 @@ pub fun final(s: *State, digest: *u8) { write_u32_be(digest, 28, s.h7); } -# compute SHA-256 digest of a byte buffer in one call. +# compute SHA-256 digest of a byte buffer in one call # --- # data: pointer to input bytes # len: number of bytes to hash diff --git a/src/crypto/hash/sha512.mach b/src/crypto/hash/sha512.mach index 4df1c6e..38f689d 100644 --- a/src/crypto/hash/sha512.mach +++ b/src/crypto/hash/sha512.mach @@ -1,4 +1,4 @@ -# SHA-512 cryptographic hash. +# SHA-512 cryptographic hash use std.types.bool.bool; use std.types.size.usize; @@ -8,17 +8,17 @@ pub val DIGEST_SIZE: usize = 64; pub val BLOCK_SIZE: usize = 128; pub rec State { - h0: u64; - h1: u64; - h2: u64; - h3: u64; - h4: u64; - h5: u64; - h6: u64; - h7: u64; - buf: [128]u8; + h0: u64; + h1: u64; + h2: u64; + h3: u64; + h4: u64; + h5: u64; + h6: u64; + h7: u64; + buf: [128]u8; buf_len: usize; - total: u64; + total: u64; } val K: [80]u64 = [80]u64{ @@ -137,7 +137,7 @@ fun process_block(s: *State, block: *u8) { s.h7 = s.h7 + h; } -# initialize a new SHA-512 state with standard IV. +# initialize a new SHA-512 state with standard IV # --- # ret: initialized state pub fun init() State { @@ -155,7 +155,7 @@ pub fun init() State { ret s; } -# feed data into the hash state. +# feed data into the hash state # --- # s: pointer to hash state # data: pointer to input bytes @@ -188,7 +188,7 @@ pub fun update(s: *State, data: *u8, len: usize) { } } -# finalize the hash and write the 64-byte digest. +# finalize the hash and write the 64-byte digest # --- # s: pointer to hash state # digest: pointer to 64-byte output buffer @@ -242,7 +242,7 @@ pub fun final(s: *State, digest: *u8) { write_u64_be(digest, 56, s.h7); } -# compute SHA-512 digest of a byte buffer in one call. +# compute SHA-512 digest of a byte buffer in one call # --- # data: pointer to input bytes # len: number of bytes to hash diff --git a/src/crypto/rand.mach b/src/crypto/rand.mach index db7ec33..f7cb984 100644 --- a/src/crypto/rand.mach +++ b/src/crypto/rand.mach @@ -1,4 +1,4 @@ -# cryptographic random number generation. +# cryptographic random number generation # # fills buffers with random bytes from the OS entropy source. @@ -6,7 +6,7 @@ use std.types.bool.bool; use std.types.size.usize; use sys: std.system.os; -# fill: fill a buffer with cryptographic random bytes. +# fill a buffer with cryptographic random bytes # --- # buf: destination buffer # len: number of bytes to fill @@ -15,7 +15,7 @@ pub fun fill(buf: *u8, len: usize) i64 { ret sys.random_fill(buf, len); } -# u64: return a random 64-bit unsigned integer. +# return a random 64-bit unsigned integer # # aborts if the OS entropy source fails. # --- @@ -26,7 +26,7 @@ pub fun u64() u64 { ret v; } -# u32: return a random 32-bit unsigned integer. +# return a random 32-bit unsigned integer # # aborts if the OS entropy source fails. # --- diff --git a/src/data/json.mach b/src/data/json.mach index 1da8379..7ca4cd4 100644 --- a/src/data/json.mach +++ b/src/data/json.mach @@ -1,4 +1,4 @@ -# JSON parser and emitter. +# JSON parser and emitter # # this module hosts two emission surfaces over one escape core: # @@ -69,7 +69,7 @@ val VALUE_SIZE: usize = $size_of(Value); val STR_SIZE: usize = $size_of(str); val USIZE_SIZE: usize = $size_of(usize); -# a parsed JSON value. +# a parsed JSON value # --- # kind: type discriminator (NULL, BOOL, NUMBER, STRING, ARRAY, OBJECT) # bool_val: boolean value (1 = true, 0 = false) when kind == BOOL @@ -108,7 +108,7 @@ rec Parser { alloc: *allo.Allocator; } -# parse: parse JSON text into a Value tree. +# parse JSON text into a Value tree # --- # src: pointer to JSON source bytes # src_len: length of source in bytes @@ -142,44 +142,44 @@ pub fun parse(src: *u8, src_len: usize, alloc: *allo.Allocator) Result[Value, st ret r; } -# value_is_null: check if a value is null. +# check if a value is null pub fun value_is_null(v: *Value) bool { ret v.kind == NULL; } -# value_is_bool: check if a value is a boolean. +# check if a value is a boolean pub fun value_is_bool(v: *Value) bool { ret v.kind == BOOL; } -# value_is_number: check if a value is a number. +# check if a value is a number pub fun value_is_number(v: *Value) bool { ret v.kind == NUMBER; } -# value_is_string: check if a value is a string. +# check if a value is a string pub fun value_is_string(v: *Value) bool { ret v.kind == STRING; } -# value_is_array: check if a value is an array. +# check if a value is an array pub fun value_is_array(v: *Value) bool { ret v.kind == ARRAY; } -# value_is_object: check if a value is an object. +# check if a value is an object pub fun value_is_object(v: *Value) bool { ret v.kind == OBJECT; } -# value_bool: get the boolean value. +# get the boolean value # --- # ret: true if bool_val is nonzero pub fun value_bool(v: *Value) bool { ret v.bool_val != 0; } -# value_is_float: whether a NUMBER value was parsed as a float. +# whether a NUMBER value was parsed as a float # # true for a number with a fraction or exponent, false for an integer-looking # number; selects whether to read it with value_float or value_number. @@ -187,7 +187,7 @@ pub fun value_is_float(v: *Value) bool { ret v.kind == NUMBER && v.is_float != 0; } -# value_number: get the integer value of an integer NUMBER. +# get the integer value of an integer NUMBER # # meaningful when the number was parsed as an integer (value_is_float is false); # read a float number with value_float. @@ -195,7 +195,7 @@ pub fun value_number(v: *Value) i64 { ret v.num_val; } -# value_float: get the value of a NUMBER as a 64-bit float. +# get the value of a NUMBER as a 64-bit float # # returns the float value for a number parsed as a float, or the integer value # widened to f64 for an integer number, so it is defined for any NUMBER. @@ -204,7 +204,7 @@ pub fun value_float(v: *Value) f64 { ret v.num_val::f64; } -# value_string: get the raw string pointer and length. +# get the raw string pointer and length # # for a parsed value these are the RAW on-wire bytes between the quotes, escapes # intact and zero-copy into the input (parse "a\nb" yields the 4 bytes a \ n b); @@ -217,7 +217,7 @@ pub fun value_string(v: *Value, len: *usize) *u8 { ret v.str_val::*u8; } -# value_string_decode: decode the raw wire bytes of a string value into logical +# decode the raw wire bytes of a string value into logical # bytes, resolving JSON escapes into a caller buffer. # # the inverse of the emit escaper: '\"' '\\' '\/' become '"' '\' '/', '\b' '\f' @@ -249,12 +249,12 @@ pub fun value_string_decode(v: *Value, buf: *u8, len: usize) Result[usize, str] ret ok[usize, str](b.pos); } -# value_count: get the number of children (array elements or object entries). +# get the number of children (array elements or object entries) pub fun value_count(v: *Value) usize { ret v.count; } -# value_get: get an array element or object value by index. +# get an array element or object value by index # --- # index: zero-based index # ret: pointer to the child Value, or nil if out of bounds @@ -263,7 +263,7 @@ pub fun value_get(v: *Value, index: usize) *Value { ret ?v.children[index]; } -# value_key: get an object key by index. +# get an object key by index # # the key points into the original input and is NOT null-terminated; # its byte length comes from value_key_len. @@ -275,7 +275,7 @@ pub fun value_key(v: *Value, index: usize) str { ret v.keys[index]; } -# value_key_len: get the byte length of an object key by index. +# get the byte length of an object key by index # --- # index: zero-based index # ret: key length in bytes, or 0 if out of bounds @@ -284,7 +284,7 @@ pub fun value_key_len(v: *Value, index: usize) usize { ret v.keys_len[index]; } -# key_equals: length-bounded comparison of a stored key slice against a +# length-bounded comparison of a stored key slice against a # null-terminated needle. fun key_equals(k: str, klen: usize, key: str) bool { var i: usize = 0; @@ -295,7 +295,7 @@ fun key_equals(k: str, klen: usize, key: str) bool { ret key[klen] == 0; } -# value_find: find an object value by key name (linear search). +# find an object value by key name (linear search) # --- # key: null-terminated key to search for # ret: pointer to the Value, or nil if not found @@ -311,7 +311,7 @@ pub fun value_find(v: *Value, key: str) *Value { ret nil; } -# emit: emit a Value as JSON text into a buffer. +# emit a Value as JSON text into a buffer # # strings and object keys are escaped under ESCAPE_VERBATIM: '"', '\', and # control bytes 0x00-0x1F are escaped (short escapes \b \t \n \f \r, else @@ -738,7 +738,7 @@ fun bufw_write(ctx: ptr, buf: *u8, len: usize) Result[usize, str] { ret ok[usize, str](len); } -# the escape policy for a JSON string body: how bytes >= 0x80 are rendered. +# the escape policy for a JSON string body: how bytes >= 0x80 are rendered def EscapePolicy: u8; # structural-utf8-verbatim: escape '"', '\', and the C0 controls only; every @@ -780,7 +780,7 @@ fun escape_unit(w: *writer.Writer, policy: EscapePolicy, s: *u8, i: usize) usize ret write_utf8_escape(w, s, i); } -# escape s[0..slen) as a JSON string body (no surrounding quotes) under policy. +# escape s[0..slen) as a JSON string body (no surrounding quotes) under policy fun escape_bytes(w: *writer.Writer, policy: EscapePolicy, s: *u8, slen: usize) { var i: usize = 0; for (i < slen) { i = escape_unit(w, policy, s, i); } @@ -865,7 +865,7 @@ fun write_codepoint(w: *writer.Writer, cp: u32) { write_u_hex(w, lo); } -# emit a \u escape for a 16-bit value. +# emit a \u escape for a 16-bit value # --- # w: the writer to emit through # code: the 16-bit value (only the low 16 bits are used) @@ -877,7 +877,7 @@ fun write_u_hex(w: *writer.Writer, code: u32) { fmt.write_byte(w, hex_digit(code & 0xF)); } -# map a nibble (0-15) to its lowercase hexadecimal ASCII digit. +# map a nibble (0-15) to its lowercase hexadecimal ASCII digit # --- # n: the nibble value # ret: the ASCII digit byte @@ -995,7 +995,7 @@ fun read_hex4(s: *u8, i: usize, slen: usize) Result[u32, str] { ret ok[u32, str](v); } -# map a hex ASCII digit to its 0-15 value, or 0x100 if the byte is not hex. +# map a hex ASCII digit to its 0-15 value, or 0x100 if the byte is not hex # --- # c: the candidate hex digit byte # ret: the nibble value, or 0x100 for a non-hex byte @@ -1097,7 +1097,7 @@ pub rec Array { first: bool; } -# object_begin: begin a JSON object, writing `{` and arming the first-member +# begin a JSON object, writing `{` and arming the first-member # state. # --- # w: the writer to emit through (must outlive the object) @@ -1108,7 +1108,7 @@ pub fun object_begin(w: *writer.Writer, o: *Object) { fmt.write_byte(w, '{'); } -# object_end: end a JSON object, writing `}` and the newline that terminates the +# end a JSON object, writing `}` and the newline that terminates the # NDJSON line. # --- # o: the object to close @@ -1117,7 +1117,7 @@ pub fun object_end(o: *Object) { fmt.write_newline(o.w); } -# object_end_value: close a nested object, writing `}` without the NDJSON line +# close a nested object, writing `}` without the NDJSON line # terminator. # # Used for an object that is a member value or an array element, where the @@ -1128,7 +1128,7 @@ pub fun object_end_value(o: *Object) { fmt.write_byte(o.w, '}'); } -# field_object_begin: open an object-valued member: the key lead-in, then `{`, +# open an object-valued member: the key lead-in, then `{`, # arming `child` over the parent's writer. # # Fill `child` with the field_* helpers and close it with object_end_value; the @@ -1142,7 +1142,7 @@ pub fun field_object_begin(o: *Object, key: *u8, child: *Object) { object_begin(o.w, child); } -# field_array_begin: open an array-valued member: the key lead-in, then `[`, +# open an array-valued member: the key lead-in, then `[`, # arming `arr` over the parent's writer. Close it with array_end. # --- # o: the open parent object @@ -1155,14 +1155,14 @@ pub fun field_array_begin(o: *Object, key: *u8, arr: *Array) { fmt.write_byte(o.w, '['); } -# array_end: close an array, writing `]`. +# close an array, writing `]` # --- # arr: the array to close pub fun array_end(arr: *Array) { fmt.write_byte(arr.w, ']'); } -# array_object_begin: open an object element of `arr`: the element separator, +# open an object element of `arr`: the element separator, # then `{`, arming `child` over the array's writer. # # Fill `child` with the field_* helpers and close it with object_end_value. @@ -1175,7 +1175,7 @@ pub fun array_object_begin(arr: *Array, child: *Object) { object_begin(arr.w, child); } -# field_str: emit a string-valued member (the value quoted and ASCII-escaped). +# emit a string-valued member (the value quoted and ASCII-escaped) # --- # o: the open object # key: the member key (ASCII, emitted verbatim between quotes) @@ -1185,7 +1185,7 @@ pub fun field_str(o: *Object, key: *u8, v: *u8) { write_json_string(o.w, v); } -# field_str_or_null: emit a string-or-null member: the escaped value, or JSON +# emit a string-or-null member: the escaped value, or JSON # `null` when `v` is nil. # --- # o: the open object @@ -1200,7 +1200,7 @@ pub fun field_str_or_null(o: *Object, key: *u8, v: *u8) { write_json_string(o.w, v); } -# field_null: emit a JSON `null`-valued member. +# emit a JSON `null`-valued member # --- # o: the open object # key: the member key @@ -1209,7 +1209,7 @@ pub fun field_null(o: *Object, key: *u8) { fmt.write_str(o.w, "null"); } -# field_i64: emit an integer-valued member. +# emit an integer-valued member # --- # o: the open object # key: the member key @@ -1219,7 +1219,7 @@ pub fun field_i64(o: *Object, key: *u8, v: i64) { fmt.write_i64(o.w, v); } -# field_bool: emit a boolean-valued member. +# emit a boolean-valued member # --- # o: the open object # key: the member key @@ -1230,7 +1230,7 @@ pub fun field_bool(o: *Object, key: *u8, v: bool) { or { fmt.write_str(o.w, "false"); } } -# write_json_string: write a JSON string literal under ESCAPE_ENSURE_ASCII: the +# write a JSON string literal under ESCAPE_ENSURE_ASCII: the # value quoted, every byte escaped to printable ASCII. # --- # w: the writer to emit through @@ -1244,7 +1244,7 @@ pub fun write_json_string(w: *writer.Writer, s: *u8) { fmt.write_byte(w, '"'); } -# write the key/colon lead-in of a member, prefixing a comma after the first. +# write the key/colon lead-in of a member, prefixing a comma after the first # --- # o: the open object # key: the member key (ASCII, emitted verbatim) @@ -1627,7 +1627,7 @@ test "json: emit escapes object keys" { ret 0; } -# a fixed-capacity byte sink used to capture streaming emitter output in tests. +# a fixed-capacity byte sink used to capture streaming emitter output in tests # --- # buf: destination buffer # cap: buffer capacity @@ -1638,7 +1638,7 @@ rec TestSink { len: usize; } -# writer callback appending to a TestSink, dropping bytes past its capacity. +# writer callback appending to a TestSink, dropping bytes past its capacity fun test_sink_write(ctx: ptr, buf: *u8, len: usize) Result[usize, str] { val s: *TestSink = ctx::*TestSink; var i: usize = 0; @@ -1650,7 +1650,7 @@ fun test_sink_write(ctx: ptr, buf: *u8, len: usize) Result[usize, str] { ret ok[usize, str](len); } -# whether the sink's captured bytes equal the first `wlen` bytes of `want`. +# whether the sink's captured bytes equal the first `wlen` bytes of `want` fun sink_is(s: *TestSink, want: *u8, wlen: usize) bool { if (s.len != wlen) { ret false; } var i: usize = 0; @@ -1661,7 +1661,7 @@ fun sink_is(s: *TestSink, want: *u8, wlen: usize) bool { ret true; } -# wire a Writer over a TestSink backed by `buf`. +# wire a Writer over a TestSink backed by `buf` fun test_writer(w: *writer.Writer, s: *TestSink, buf: *u8, cap: usize) { s.buf = buf; s.cap = cap; @@ -1772,7 +1772,7 @@ test "json: write_json_string utf8_astral" { ret 0; } -# whether the sink holds exactly `count` U+FFFD replacement escapes, quoted. +# whether the sink holds exactly `count` U+FFFD replacement escapes, quoted # # A pure run of the replacement escape proves the decoder rejected the input # entirely: any accepted (overlong, surrogate, or out-of-range) decode would @@ -1968,7 +1968,7 @@ fun decode_check(raw: *u8, rawlen: usize, want: *u8, wantlen: usize) bool { ret true; } -# whether value_string_decode rejects the given raw string body. +# whether value_string_decode rejects the given raw string body fun decode_rejects(raw: *u8, rawlen: usize) bool { val v: Value = make_string((raw::usize)::str, rawlen); var buf: [64]u8; diff --git a/src/data/toml.mach b/src/data/toml.mach index 376bbe9..9eb2a97 100644 --- a/src/data/toml.mach +++ b/src/data/toml.mach @@ -1,4 +1,4 @@ -# TOML 1.0 parser and accessor API. +# TOML 1.0 parser and accessor API # # parses TOML documents into a tree of tables, arrays, and values. # all memory is owned by the provided allocator (typically an arena). @@ -25,7 +25,7 @@ use std.types.string.str_len; use std.allocator.Allocator; use std.allocator.allocate; -use mem: std.memory; +use mem: std.memory; use page: std.allocator.page; pub val TYPE_STRING: u8 = 0; @@ -37,7 +37,7 @@ pub val TYPE_TABLE: u8 = 5; val VALUE_SIZE: usize = $size_of(Value); -# Value: tagged TOML value. +# tagged TOML value # --- # tag: type discriminator (TYPE_*) pub rec Value { @@ -52,7 +52,7 @@ pub rec Value { }; } -# Array: ordered list of TOML values. +# ordered list of TOML values # --- # items: pointer to Value array (ptr to break recursion) # len: number of elements @@ -63,7 +63,7 @@ pub rec Array { cap: usize; } -# Table: ordered map of string keys to TOML values. +# ordered map of string keys to TOML values # --- # keys: pointer to str array (parallel with values) # values: pointer to Value array @@ -83,7 +83,7 @@ rec KeySegs { cap: usize; } -# table_make: create an empty table with nil backing storage. +# create an empty table with nil backing storage fun table_make() Table { var t: Table; t.keys = nil; @@ -93,7 +93,7 @@ fun table_make() Table { ret t; } -# table_set: insert or overwrite a key-value pair in a table. +# insert or overwrite a key-value pair in a table # --- # a: allocator for growth # t: target table @@ -154,7 +154,7 @@ fun table_set(a: *Allocator, t: *Table, key: str, val_: Value) Result[bool, str] ret ok[bool, str](true); } -# table_find: find a value by key in a table. +# find a value by key in a table # --- # t: table to search # key: key string to match @@ -173,7 +173,7 @@ fun table_find(t: *Table, key: str) *Value { ret nil; } -# table_ensure_subtable: find or create a sub-table under a key. +# find or create a sub-table under a key # --- # a: allocator for new table storage # t: parent table @@ -197,7 +197,7 @@ fun table_ensure_subtable(a: *Allocator, t: *Table, key: str) Result[*Table, str ret ok[*Table, str](?v.data.table); } -# array_make: create an empty array with nil backing storage. +# create an empty array with nil backing storage fun array_make() Array { var a: Array; a.items = nil; @@ -206,7 +206,7 @@ fun array_make() Array { ret a; } -# array_push: append a value to an array. +# append a value to an array # --- # a: allocator for growth # arr: target array @@ -245,7 +245,7 @@ fun array_push(a: *Allocator, arr: *Array, val_: Value) Result[bool, str] { ret ok[bool, str](true); } -# keysegs_make: create an empty key segment list. +# create an empty key segment list fun keysegs_make() KeySegs { var ks: KeySegs; ks.segs = nil; @@ -254,7 +254,7 @@ fun keysegs_make() KeySegs { ret ks; } -# keysegs_push: append a segment to a key path. +# append a segment to a key path # --- # a: allocator for growth # ks: target key segments @@ -327,7 +327,7 @@ fun value_array(a: Array) Value { ret v; } -# get: look up a value by dotted path in a table. +# look up a value by dotted path in a table # # walks nested tables for each dot-separated segment. for keys that # contain literal dots, use get_table() then iterate with table_key(). @@ -355,7 +355,7 @@ pub fun get(t: *Table, path: str) *Value { ret find_by_seg(current, (path::usize + start)::str, i - start); } -# find_by_seg: find a value by key prefix and length. +# find a value by key prefix and length # --- # t: table to search # seg: start of the key segment (not null-terminated) @@ -376,7 +376,7 @@ fun find_by_seg(t: *Table, seg: str, seg_len: usize) *Value { } -# get_str: look up a string value by dotted path. +# look up a string value by dotted path # --- # t: root table # path: dotted key path @@ -387,7 +387,7 @@ pub fun get_str(t: *Table, path: str) str { ret v.data.string; } -# get_int: look up an integer value by dotted path. +# look up an integer value by dotted path # --- # t: root table # path: dotted key path @@ -398,7 +398,7 @@ pub fun get_int(t: *Table, path: str) Option[i64] { ret some[i64](v.data.integer); } -# get_float: look up a float value by dotted path. +# look up a float value by dotted path # --- # t: root table # path: dotted key path @@ -409,7 +409,7 @@ pub fun get_float(t: *Table, path: str) Option[f64] { ret some[f64](v.data.float); } -# get_bool: look up a boolean value by dotted path. +# look up a boolean value by dotted path # --- # t: root table # path: dotted key path @@ -420,7 +420,7 @@ pub fun get_bool(t: *Table, path: str) Option[bool] { ret some[bool](v.data.boolean); } -# get_table: look up a sub-table by dotted path. +# look up a sub-table by dotted path # --- # t: root table # path: dotted key path @@ -431,7 +431,7 @@ pub fun get_table(t: *Table, path: str) *Table { ret ?v.data.table; } -# get_array: look up an array by dotted path. +# look up an array by dotted path # --- # t: root table # path: dotted key path @@ -442,7 +442,7 @@ pub fun get_array(t: *Table, path: str) *Array { ret ?v.data.array; } -# array_get: get a value from an array by index. +# get a value from an array by index # --- # arr: array to index # index: element index @@ -453,7 +453,7 @@ pub fun array_get(arr: *Array, index: usize) *Value { ret ?items[index]; } -# table_len: get the number of entries in a table. +# get the number of entries in a table # --- # t: table to query # ret: number of key-value pairs @@ -462,7 +462,7 @@ pub fun table_len(t: *Table) usize { ret t.len; } -# table_key: get a key by positional index. +# get a key by positional index # --- # t: table to query # index: position (0-based) @@ -473,7 +473,7 @@ pub fun table_key(t: *Table, index: usize) str { ret keys[index]; } -# table_value: get a value by positional index. +# get a value by positional index # --- # t: table to query # index: position (0-based) @@ -484,7 +484,7 @@ pub fun table_value(t: *Table, index: usize) *Value { ret ?vals[index]; } -# array_len: get the number of elements in an array. +# get the number of elements in an array # --- # arr: array to query # ret: number of elements @@ -546,7 +546,7 @@ fun skip_to_newline(src: str, i: *usize) { if (src[@i] == '\n') { @i = @i + 1; } } -# alloc_str: allocate a copy of a substring. +# allocate a copy of a substring # --- # a: allocator # src: source string @@ -564,7 +564,7 @@ fun alloc_str(a: *Allocator, src: str, start: usize, len: usize) Result[str, str ret ok[str, str](buf::*u8); } -# hex_digit: return the numeric value of a hex character, or -1. +# return the numeric value of a hex character, or -1 fun hex_digit(c: u8) i32 { if (c >= '0' && c <= '9') { ret (c - '0')::u32::i32; } if (c >= 'a' && c <= 'f') { ret (c - 'a')::u32::i32 + 10; } @@ -572,7 +572,7 @@ fun hex_digit(c: u8) i32 { ret -1; } -# decode_escape: write an escape sequence into buf starting at di. +# write an escape sequence into buf starting at di # advances si past the escape. returns 0 on invalid escape, otherwise # the number of bytes written (1 for simple escapes, 1-4 for unicode). fun decode_escape(src: str, si: *usize, buf: *u8, di: usize) usize { @@ -608,7 +608,7 @@ fun decode_escape(src: str, si: *usize, buf: *u8, di: usize) usize { ret 0; } -# count_escape_len: count output bytes for an escape at src[@i]. +# count output bytes for an escape at src[@i] # advances i past the escape sequence. fun count_escape_len(src: str, i: *usize) usize { val e: u8 = src[@i]; @@ -629,7 +629,7 @@ fun count_escape_len(src: str, i: *usize) usize { ret 1; } -# utf8_len: return the number of bytes needed to encode a codepoint as UTF-8. +# return the number of bytes needed to encode a codepoint as UTF-8 fun utf8_len(code: u32) usize { if (code <= 0x7F) { ret 1; } if (code <= 0x7FF) { ret 2; } @@ -637,7 +637,7 @@ fun utf8_len(code: u32) usize { ret 4; } -# encode_utf8: write a unicode codepoint as UTF-8 into buf at offset di. +# write a unicode codepoint as UTF-8 into buf at offset di # returns the number of bytes written (1-4). fun encode_utf8(buf: *u8, di: usize, code: u32) usize { if (code <= 0x7F) { @@ -662,7 +662,7 @@ fun encode_utf8(buf: *u8, di: usize, code: u32) usize { ret 4; } -# parse_basic_string: parse a double-quoted string with escape processing. +# parse a double-quoted string with escape processing # expects the cursor on the opening '"'. # --- # a: allocator for the output buffer @@ -723,7 +723,7 @@ fun parse_basic_string(a: *Allocator, src: str, i: *usize) Result[str, str] { ret ok[str, str](buf::*u8); } -# parse_ml_basic_string: parse a triple-quoted basic string. +# parse a triple-quoted basic string # expects the cursor immediately after the opening """. # --- # a: allocator @@ -784,7 +784,7 @@ fun parse_ml_basic_string(a: *Allocator, src: str, i: *usize) Result[str, str] { ret ok[str, str](buf::*u8); } -# parse_literal_string: parse a single-quoted string (no escapes). +# parse a single-quoted string (no escapes) # expects the cursor on the opening "'". # --- # a: allocator @@ -810,7 +810,7 @@ fun parse_literal_string(a: *Allocator, src: str, i: *usize) Result[str, str] { ret alloc_str(a, src, start, len); } -# parse_ml_literal_string: parse a triple-quoted literal string. +# parse a triple-quoted literal string # expects the cursor immediately after the opening '''. # --- # a: allocator @@ -833,7 +833,7 @@ fun parse_ml_literal_string(a: *Allocator, src: str, i: *usize) Result[str, str] ret alloc_str(a, src, start, len); } -# parse_number: parse an integer or float value. +# parse an integer or float value # handles decimal, hex, octal, binary integers, decimal floats with # optional exponent, and special values inf/nan. # --- @@ -914,7 +914,7 @@ fun parse_number(src: str, i: *usize) Result[Value, str] { ret ok[Value, str](value_int(x::i64 * sign)); } -# parse_float_frac: parse the fractional part of a float after the '.'. +# parse the fractional part of a float after the '.' # --- # src: source text # i: cursor position (on the '.') @@ -944,7 +944,7 @@ fun parse_float_frac(src: str, i: *usize, int_part: i64, sign: i64) Result[Value ret ok[Value, str](value_float(result)); } -# parse_float_exp: parse the exponent part of a float after 'e'/'E'. +# parse the exponent part of a float after 'e'/'E' # --- # src: source text # i: cursor position (on the 'e' or 'E') @@ -974,7 +974,7 @@ fun parse_float_exp(src: str, i: *usize, mantissa: f64) Result[Value, str] { ret ok[Value, str](value_float(result)); } -# apply_pow10: multiply or divide value by 10^exp using a lookup table. +# multiply or divide value by 10^exp using a lookup table fun apply_pow10(value: f64, exp: i64, exp_sign: i64) f64 { var pow10: [20]f64; pow10[0] = 1.0; @@ -1014,7 +1014,7 @@ fun apply_pow10(value: f64, exp: i64, exp_sign: i64) f64 { ret result; } -# parse_hex_int: parse hexadecimal digits into an integer value. +# parse hexadecimal digits into an integer value fun parse_hex_int(src: str, i: *usize, sign: i64) Result[Value, str] { var x: u64 = 0; var any: bool = false; @@ -1032,7 +1032,7 @@ fun parse_hex_int(src: str, i: *usize, sign: i64) Result[Value, str] { ret ok[Value, str](value_int(x::i64 * sign)); } -# parse_oct_int: parse octal digits into an integer value. +# parse octal digits into an integer value fun parse_oct_int(src: str, i: *usize, sign: i64) Result[Value, str] { var x: u64 = 0; var any: bool = false; @@ -1049,7 +1049,7 @@ fun parse_oct_int(src: str, i: *usize, sign: i64) Result[Value, str] { ret ok[Value, str](value_int(x::i64 * sign)); } -# parse_bin_int: parse binary digits into an integer value. +# parse binary digits into an integer value fun parse_bin_int(src: str, i: *usize, sign: i64) Result[Value, str] { var x: u64 = 0; var any: bool = false; @@ -1066,13 +1066,13 @@ fun parse_bin_int(src: str, i: *usize, sign: i64) Result[Value, str] { ret ok[Value, str](value_int(x::i64 * sign)); } -# is_value_term: check if a byte terminates a bare value. +# check if a byte terminates a bare value fun is_value_term(b: u8) bool { ret b == 0 || b == ' ' || b == '\t' || b == '\n' || b == '\r' || b == ',' || b == ']' || b == '}' || b == '#'; } -# parse_bool_val: parse "true" or "false". +# parse "true" or "false" fun parse_bool_val(src: str, i: *usize) Result[Value, str] { if (src[@i] == 't' && src[@i + 1] == 'r' && src[@i + 2] == 'u' && src[@i + 3] == 'e') { if (!is_value_term(src[@i + 4])) { ret err[Value, str]("expected boolean"); } @@ -1087,7 +1087,7 @@ fun parse_bool_val(src: str, i: *usize) Result[Value, str] { ret err[Value, str]("expected boolean"); } -# parse_key_segment: parse a single key segment (bare, quoted, or literal). +# parse a single key segment (bare, quoted, or literal) # --- # a: allocator # src: source text @@ -1109,7 +1109,7 @@ fun parse_key_segment(a: *Allocator, src: str, i: *usize) Result[str, str] { ret alloc_str(a, src, start, @i - start); } -# parse_key_path: parse a possibly-dotted key into segments. +# parse a possibly-dotted key into segments # # handles bare keys, quoted keys, and mixed dotted keys like a."b".c. # each segment is stored independently, preserving literal dots in @@ -1140,7 +1140,7 @@ fun parse_key_path(a: *Allocator, src: str, i: *usize) Result[KeySegs, str] { ret ok[KeySegs, str](ks); } -# navigate_segs: walk key segments, creating intermediate tables. +# walk key segments, creating intermediate tables # returns the table that should receive the final segment's value. # --- # a: allocator for new tables @@ -1159,7 +1159,7 @@ fun navigate_segs(a: *Allocator, t: *Table, ks: *KeySegs) Result[*Table, str] { ret ok[*Table, str](current); } -# parse_value: parse a TOML value at the current position. +# parse a TOML value at the current position # --- # a: allocator # src: source text @@ -1201,7 +1201,7 @@ fun parse_value(a: *Allocator, src: str, i: *usize) Result[Value, str] { ret err[Value, str]("unexpected character in value"); } -# parse_array_value: parse a TOML array [...]. +# parse a TOML array [...] # --- # a: allocator # src: source text @@ -1234,7 +1234,7 @@ fun parse_array_value(a: *Allocator, src: str, i: *usize) Result[Value, str] { ret ok[Value, str](value_array(arr)); } -# parse_inline_table: parse a TOML inline table {...}. +# parse a TOML inline table {...} # --- # a: allocator # src: source text @@ -1286,7 +1286,7 @@ fun parse_inline_table(a: *Allocator, src: str, i: *usize) Result[Value, str] { ret ok[Value, str](value_table(t)); } -# navigate_for_array_table: resolve a [[key]] header. +# resolve a [[key]] header # # navigates parent segments (creating tables or following existing # array-of-tables entries), then appends a new table to the array @@ -1361,7 +1361,7 @@ fun navigate_for_array_table(a: *Allocator, root: *Table, ks: *KeySegs) Result[* ret ok[*Table, str](?items[0].data.table); } -# parse: parse a TOML document into a table tree. +# parse a TOML document into a table tree # # supports TOML 1.0: basic and literal strings (single and multi-line), # integers (decimal, hex, octal, binary), floats, booleans, arrays, @@ -1465,7 +1465,7 @@ pub fun parse(a: *Allocator, src: str) Result[Table, str] { } # float regression tests (#278). these exercise the f64 paths that transit -# memory — apply_pow10's [20]f64 array-element load feeding an FP multiply +# memory, apply_pow10's [20]f64 array-element load feeding an FP multiply # (exponents) and the Value f64 union field store/load (value_float/get_float). # they catch an aarch64 f64 memory-load/store miscompile that produced wrong # values with zero test signal; before that compiler fix they fail on aarch64, diff --git a/src/encoding/base64.mach b/src/encoding/base64.mach index 22e2022..7ddcce2 100644 --- a/src/encoding/base64.mach +++ b/src/encoding/base64.mach @@ -1,4 +1,4 @@ -# base64 encoding and decoding. +# base64 encoding and decoding use std.types.bool.bool; use std.types.bool.true; @@ -7,21 +7,21 @@ use std.types.size.usize; use std.types.string.str; use std.types.string.str_equals; -val std_table: [64]u8 = [64]u8{ +val STD_TABLE: [64]u8 = [64]u8{ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47 }; -val url_table: [64]u8 = [64]u8{ +val URL_TABLE: [64]u8 = [64]u8{ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 95 }; -val decode_table: [256]u8 = [256]u8{ +val DECODE_TABLE: [256]u8 = [256]u8{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 62, 255, 63, @@ -40,7 +40,7 @@ val decode_table: [256]u8 = [256]u8{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }; -# return the buffer size required to encode src_len bytes (including null terminator). +# return the buffer size required to encode src_len bytes (including null terminator) # --- # src_len: number of source bytes # ret: required destination buffer size @@ -48,7 +48,7 @@ pub fun encoded_len(src_len: usize) usize { ret (src_len + 2) / 3 * 4 + 1; } -# return the maximum number of decoded bytes for a base64 string of src_len chars. +# return the maximum number of decoded bytes for a base64 string of src_len chars # --- # src_len: length of the base64 string # ret: maximum decoded byte count @@ -113,7 +113,7 @@ fun encode_with_table(src: *u8, src_len: usize, dst: *u8, dst_len: usize, table: ret j; } -# encode bytes as standard base64 with padding. +# encode bytes as standard base64 with padding # --- # src: pointer to source bytes # src_len: number of source bytes @@ -121,10 +121,10 @@ fun encode_with_table(src: *u8, src_len: usize, dst: *u8, dst_len: usize, table: # dst_len: size of destination buffer (must be >= encoded_len(src_len)) # ret: number of bytes written (not counting null terminator), 0 if dst too small pub fun encode(src: *u8, src_len: usize, dst: *u8, dst_len: usize) usize { - ret encode_with_table(src, src_len, dst, dst_len, ?std_table[0], true); + ret encode_with_table(src, src_len, dst, dst_len, ?STD_TABLE[0], true); } -# encode bytes as url-safe base64 without padding. +# encode bytes as url-safe base64 without padding # --- # src: pointer to source bytes # src_len: number of source bytes @@ -132,10 +132,10 @@ pub fun encode(src: *u8, src_len: usize, dst: *u8, dst_len: usize) usize { # dst_len: size of destination buffer (must be >= encoded_len(src_len)) # ret: number of bytes written (not counting null terminator), 0 if dst too small pub fun encode_url(src: *u8, src_len: usize, dst: *u8, dst_len: usize) usize { - ret encode_with_table(src, src_len, dst, dst_len, ?url_table[0], false); + ret encode_with_table(src, src_len, dst, dst_len, ?URL_TABLE[0], false); } -# decode a base64 string to bytes. +# decode a base64 string to bytes # # handles both standard and url-safe alphabets, and padding characters. # --- @@ -165,10 +165,10 @@ pub fun decode(src: *u8, src_len: usize, dst: *u8, dst_len: usize) usize { var j: usize = 0; for (i + 3 < data_len) { - val a: u8 = decode_table[src[i]::usize]; - val b: u8 = decode_table[src[i + 1]::usize]; - val c: u8 = decode_table[src[i + 2]::usize]; - val d: u8 = decode_table[src[i + 3]::usize]; + val a: u8 = DECODE_TABLE[src[i]::usize]; + val b: u8 = DECODE_TABLE[src[i + 1]::usize]; + val c: u8 = DECODE_TABLE[src[i + 2]::usize]; + val d: u8 = DECODE_TABLE[src[i + 3]::usize]; if (a == 255 || b == 255 || c == 255 || d == 255) { ret 0; } dst[j] = (a << 2) | (b >> 4); dst[j + 1] = (b << 4) | (c >> 2); @@ -179,16 +179,16 @@ pub fun decode(src: *u8, src_len: usize, dst: *u8, dst_len: usize) usize { val tail: usize = data_len - i; if (tail == 2) { - val a: u8 = decode_table[src[i]::usize]; - val b: u8 = decode_table[src[i + 1]::usize]; + val a: u8 = DECODE_TABLE[src[i]::usize]; + val b: u8 = DECODE_TABLE[src[i + 1]::usize]; if (a == 255 || b == 255) { ret 0; } dst[j] = (a << 2) | (b >> 4); j = j + 1; } or (tail == 3) { - val a: u8 = decode_table[src[i]::usize]; - val b: u8 = decode_table[src[i + 1]::usize]; - val c: u8 = decode_table[src[i + 2]::usize]; + val a: u8 = DECODE_TABLE[src[i]::usize]; + val b: u8 = DECODE_TABLE[src[i + 1]::usize]; + val c: u8 = DECODE_TABLE[src[i + 2]::usize]; if (a == 255 || b == 255 || c == 255) { ret 0; } dst[j] = (a << 2) | (b >> 4); dst[j + 1] = (b << 4) | (c >> 2); diff --git a/src/encoding/hex.mach b/src/encoding/hex.mach index 1b42b5b..8faa66f 100644 --- a/src/encoding/hex.mach +++ b/src/encoding/hex.mach @@ -1,4 +1,4 @@ -# hexadecimal encoding and decoding. +# hexadecimal encoding and decoding use std.types.bool.bool; use std.types.bool.true; @@ -7,7 +7,7 @@ use std.types.size.usize; use std.types.string.str; use std.types.string.str_equals; -# return the buffer size required to encode src_len bytes (including null terminator). +# return the buffer size required to encode src_len bytes (including null terminator) # --- # src_len: number of source bytes # ret: required destination buffer size @@ -15,7 +15,7 @@ pub fun encoded_len(src_len: usize) usize { ret src_len * 2 + 1; } -# return the maximum number of decoded bytes for a hex string of src_len chars. +# return the maximum number of decoded bytes for a hex string of src_len chars # --- # src_len: length of the hex string # ret: maximum decoded byte count @@ -69,7 +69,7 @@ fun encode_with(src: *u8, src_len: usize, dst: *u8, dst_len: usize, upper: bool) ret src_len * 2; } -# encode bytes as lowercase hexadecimal. +# encode bytes as lowercase hexadecimal # --- # src: pointer to source bytes # src_len: number of source bytes @@ -80,7 +80,7 @@ pub fun encode(src: *u8, src_len: usize, dst: *u8, dst_len: usize) usize { ret encode_with(src, src_len, dst, dst_len, false); } -# encode bytes as uppercase hexadecimal. +# encode bytes as uppercase hexadecimal # --- # src: pointer to source bytes # src_len: number of source bytes @@ -91,7 +91,7 @@ pub fun encode_upper(src: *u8, src_len: usize, dst: *u8, dst_len: usize) usize { ret encode_with(src, src_len, dst, dst_len, true); } -# decode a hexadecimal string to bytes. +# decode a hexadecimal string to bytes # # accepts both uppercase and lowercase hex characters. # returns 0 if the input has odd length or contains invalid characters. diff --git a/src/filesystem.mach b/src/filesystem.mach index 4917c2f..1260af2 100644 --- a/src/filesystem.mach +++ b/src/filesystem.mach @@ -1,7 +1,7 @@ # file and directory operations # # provides File handles, FileInfo metadata, temp files, and path-based -# queries. all syscall interaction goes through std.system.os — this +# queries. all syscall interaction goes through std.system.os, this # module contains no platform-specific logic. use std.types.bool.bool; @@ -28,14 +28,14 @@ use writer: std.io.writer; use reader: std.io.reader; use rand: std.crypto.rand; -# File: wrapper around a file descriptor. +# wrapper around a file descriptor # --- # fd: underlying file descriptor pub rec File { fd: i32; } -# FileInfo: portable file metadata. +# portable file metadata # --- # size: file size in bytes # mode: raw permission/type bits @@ -50,7 +50,7 @@ pub rec FileInfo { created: i64; } -# TempFile: temporary file with an allocated path for cleanup. +# temporary file with an allocated path for cleanup # --- # file: underlying File handle # path: allocated path string (caller must free) @@ -59,7 +59,7 @@ pub rec TempFile { path: path.Path; } -# Buffer: a length-counted byte buffer returned by length-aware file reads. +# a length-counted byte buffer returned by length-aware file reads # unlike a `str`, a Buffer carries its true byte length, so it correctly # describes binary content that may embed NUL bytes. the buffer is # over-allocated by one NUL terminator (so it may also be read as a `str`), @@ -79,7 +79,7 @@ pub val stderr: File = File{fd: 2}; val TEMP_MAX_ATTEMPTS: usize = 100; val HEX_CHARS: str = "0123456789abcdef"; -# open: open a file for reading. +# open a file for reading # --- # p: file path # ret: the opened File, or an error message @@ -89,7 +89,7 @@ pub fun open(p: str) Result[File, str] { ret ok[File, str](File{fd: raw::i32}); } -# open_with: open a file with explicit flags and mode. +# open a file with explicit flags and mode # --- # p: file path # flags: open flags (O_RDONLY, O_WRONLY, O_CREAT, etc.) @@ -101,7 +101,7 @@ pub fun open_with(p: str, flags: i32, mode: i32) Result[File, str] { ret ok[File, str](File{fd: raw::i32}); } -# create: create or truncate a file for writing. +# create or truncate a file for writing # --- # p: file path # mode: permission bits @@ -113,7 +113,7 @@ pub fun create(p: str, mode: i32) Result[File, str] { ret ok[File, str](File{fd: raw::i32}); } -# close: close a file descriptor. +# close a file descriptor # --- # f: file to close # ret: true on success, or an error message @@ -124,7 +124,7 @@ pub fun close(f: *File) Result[bool, str] { ret ok[bool, str](true); } -# read: read up to len bytes into buf. +# read up to len bytes into buf # --- # f: file to read from # buf: destination buffer @@ -137,7 +137,7 @@ pub fun read(f: *File, buf: *u8, len: usize) Result[usize, str] { ret ok[usize, str](raw::usize); } -# write: write up to len bytes from buf. +# write up to len bytes from buf # --- # f: file to write to # buf: source buffer @@ -150,7 +150,7 @@ pub fun write(f: *File, buf: *u8, len: usize) Result[usize, str] { ret ok[usize, str](raw::usize); } -# seek: reposition file offset. +# reposition file offset # --- # f: file to seek # offset: byte offset @@ -163,7 +163,7 @@ pub fun seek(f: *File, offset: i64, whence: i32) Result[i64, str] { ret ok[i64, str](raw); } -# info: get metadata for an open file. +# get metadata for an open file # --- # f: file to query # ret: file metadata, or an error message @@ -175,7 +175,7 @@ pub fun info(f: *File) Result[FileInfo, str] { ret ok[FileInfo, str](info_from_stat(?st)); } -# get_writer: initialize a Writer backed by a file. +# initialize a Writer backed by a file # --- # f: file to write to (must outlive the Writer) # w: Writer to initialize @@ -184,7 +184,7 @@ pub fun get_writer(f: *File, w: *writer.Writer) { w.fn_write = file_write_cb; } -# get_reader: initialize a Reader backed by a file. +# initialize a Reader backed by a file # --- # f: file to read from (must outlive the Reader) # r: Reader to initialize @@ -193,7 +193,7 @@ pub fun get_reader(f: *File, r: *reader.Reader) { r.fn_read = file_read_cb; } -# read_all_sized: read an entire file into a length-counted Buffer. +# read an entire file into a length-counted Buffer # # the result carries the file's true byte length, so binary content with # embedded NUL bytes is described correctly (a plain `str` would lose its @@ -241,10 +241,10 @@ pub fun read_all_sized(a: *allocator.Allocator, p: str) Result[Buffer, str] { ret ok[Buffer, str](Buffer{data: buf, len: total}); } -# read_all: read an entire file into an allocated, NUL-terminated string. +# read an entire file into an allocated, NUL-terminated string # # for text files only; binary content with embedded NUL bytes loses its -# length to the first NUL when accessed through `str_len` — use +# length to the first NUL when accessed through `str_len`, use # `read_all_sized` for binary data. # --- # a: allocator for the result buffer @@ -258,7 +258,7 @@ pub fun read_all(a: *allocator.Allocator, p: str) Result[str, str] { ret ok[str, str](unwrap_ok[Buffer, str](rb).data::str); } -# write_file: write data to a file at path, creating or truncating it. +# write data to a file at path, creating or truncating it # --- # p: file path # data: bytes to write @@ -285,22 +285,22 @@ pub fun write_file(p: str, data: *u8, len: usize, mode: i32) Result[bool, str] { ret ok[bool, str](true); } -# info_is_dir: check whether FileInfo describes a directory. +# check whether FileInfo describes a directory pub fun info_is_dir(fi: *FileInfo) bool { ret (fi.mode & os.S_IFMT) == os.S_IFDIR; } -# info_is_file: check whether FileInfo describes a regular file. +# check whether FileInfo describes a regular file pub fun info_is_file(fi: *FileInfo) bool { ret (fi.mode & os.S_IFMT) == os.S_IFREG; } -# info_is_symlink: check whether FileInfo describes a symbolic link. +# check whether FileInfo describes a symbolic link pub fun info_is_symlink(fi: *FileInfo) bool { ret (fi.mode & os.S_IFMT) == os.S_IFLNK; } -# info_path: get metadata for a path. +# get metadata for a path # --- # p: path to query # ret: file metadata, or an error message @@ -312,7 +312,7 @@ pub fun info_path(p: str) Result[FileInfo, str] { ret ok[FileInfo, str](info_from_stat(?st)); } -# info_link: get metadata for a path without following a final symbolic link. +# get metadata for a path without following a final symbolic link # # the lstat counterpart to info_path: a symbolic link reports its own metadata # (info_is_symlink is true) rather than the target's. use it to detect links @@ -328,7 +328,7 @@ pub fun info_link(p: str) Result[FileInfo, str] { ret ok[FileInfo, str](info_from_stat(?st)); } -# is_dir: check whether a path is an existing directory. +# check whether a path is an existing directory pub fun is_dir(p: str) bool { val r: Result[FileInfo, str] = info_path(p); if (is_err[FileInfo, str](r)) { ret false; } @@ -336,7 +336,7 @@ pub fun is_dir(p: str) bool { ret info_is_dir(?fi); } -# is_file: check whether a path is an existing regular file. +# check whether a path is an existing regular file pub fun is_file(p: str) bool { val r: Result[FileInfo, str] = info_path(p); if (is_err[FileInfo, str](r)) { ret false; } @@ -344,12 +344,12 @@ pub fun is_file(p: str) bool { ret info_is_file(?fi); } -# exists: check whether a path exists. +# check whether a path exists pub fun exists(p: str) bool { ret is_ok[FileInfo, str](info_path(p)); } -# unlink: remove a file. +# remove a file # --- # p: path to remove # ret: true on success, or an error message @@ -359,7 +359,7 @@ pub fun unlink(p: str) Result[bool, str] { ret ok[bool, str](true); } -# rename: rename a file or directory. +# rename a file or directory # --- # from: source path # to: destination path @@ -370,7 +370,7 @@ pub fun rename(from: str, to: str) Result[bool, str] { ret ok[bool, str](true); } -# symlink: create a symbolic link at linkpath pointing to target. +# create a symbolic link at linkpath pointing to target # # the target is stored verbatim: a relative target is preserved as given, with # no resolution or normalization, so the link keeps resolving correctly after @@ -389,7 +389,7 @@ pub fun symlink(target: str, linkpath: str) Result[bool, str] { ret ok[bool, str](true); } -# create_dir: create a directory. +# create a directory # --- # p: directory path # mode: permission bits @@ -401,7 +401,7 @@ pub fun create_dir(p: str, mode: i32) Result[bool, str] { ret ok[bool, str](true); } -# create_dir_all: create a directory and all missing parents. +# create a directory and all missing parents # --- # a: allocator for intermediate path operations # p: directory path @@ -444,9 +444,9 @@ val REMOVE_MAX_DEPTH: usize = 1024; # entries; large enough to hold several entries per read_dir call. val DIRENT_BUF_SIZE: usize = 8192; -# remove_all: recursively remove a file, directory, or symbolic link. +# recursively remove a file, directory, or symbolic link # -# directories are removed depth-first — their contents first, then the +# directories are removed depth-first, their contents first, then the # directory itself. symbolic links are removed as links and never followed: # a link inside the tree that points outside it leaves the target untouched. # this is the safety property a recursive delete must hold, and it relies on @@ -469,7 +469,7 @@ fun remove_all_at(a: *allocator.Allocator, p: str, depth: usize) Result[bool, st } # lstat (AT_SYMLINK_NOFOLLOW) so a symlink reports as a link, not its - # target — the walk must remove the link itself, never descend through it. + # target, the walk must remove the link itself, never descend through it. var st: os.stat_t; val sr: i64 = os.stat_path(os.AT_FDCWD, p, ?st, os.AT_SYMLINK_NOFOLLOW); if (sr < 0) { @@ -599,7 +599,7 @@ fun is_dot_name(name: *u8) bool { ret false; } -# temp_create: create a temporary file with a unique name. +# create a temporary file with a unique name # # the file is created under the OS temp directory resolved at call time # (see os.temp_dir): $TMPDIR or "/tmp" on posix, GetTempPathA on windows. @@ -639,22 +639,22 @@ pub fun temp_create(a: *allocator.Allocator, prefix: str) Result[TempFile, str] ret err[TempFile, str]("temp file: max attempts exceeded"); } -# temp_path: get the path of a temp file. +# get the path of a temp file pub fun temp_path(tf: *TempFile) str { ret tf.path; } -# temp_close: close the temp file (does not remove it). +# close the temp file (does not remove it) pub fun temp_close(tf: *TempFile) Result[bool, str] { ret close(?tf.file); } -# temp_remove: remove the temp file from disk. +# remove the temp file from disk pub fun temp_remove(tf: *TempFile) Result[bool, str] { ret unlink(tf.path); } -# temp_close_and_remove: close and remove. +# close and remove pub fun temp_close_and_remove(tf: *TempFile) Result[bool, str] { val cr: Result[bool, str] = close(?tf.file); val rr: Result[bool, str] = unlink(tf.path); diff --git a/src/format.mach b/src/format.mach index 1c4e8e7..f1fba85 100644 --- a/src/format.mach +++ b/src/format.mach @@ -1,4 +1,4 @@ -# formatting primitives. +# formatting primitives # # writes formatted data to any io.Writer without allocation. # @@ -6,12 +6,12 @@ # its type: signed/unsigned integers (any width) in decimal, str as text, ptr as # 0x-hex, f64 as the shortest round-trippable decimal. f32 widens to f64 (an # exact widening) and prints as that value, so it has no f32-specific shortest -# round-trip — an inexact f32 shows the full f64 expansion of its widened value. +# round-trip, an inexact f32 shows the full f64 expansion of its widened value. # bool and char share u8's -# representation, so they render as their numeric value — a bool prints 1 or 0; +# representation, so they render as their numeric value, a bool prints 1 or 0; # reach for the `{:c}` spec to render an integer's low byte as a character. # -# a hole may carry a spec after `:` — a leading `<` to left-align (pad on the +# a hole may carry a spec after `:`, a leading `<` to left-align (pad on the # right), `x`/`X` for lower/upper hex, `c` for a low-byte char, a decimal minimum # width, and a leading `0` to zero-pad rather than space-pad (e.g. `{:x}`, `{:c}`, # `{:5}`, `{:<5}`, `{:08x}`). width pads on the left (right-align) by default. @@ -32,10 +32,10 @@ use std.types.string.str; use std.types.string.str_len; use std.types.string.str_equals; use writer: std.io.writer; -use mem: std.memory; -use bn: std.math.bignum; +use mem: std.memory; +use bn: std.math.bignum; -# write_bytes: write raw bytes to a writer. +# write raw bytes to a writer # --- # w: target writer # buf: source buffer @@ -45,7 +45,7 @@ pub fun write_bytes(w: *writer.Writer, buf: *u8, len: usize) Result[usize, str] ret writer.write_all(w, buf, len); } -# write_str: write a null-terminated string to a writer. +# write a null-terminated string to a writer # --- # w: target writer # s: string to write (nil treated as empty) @@ -55,7 +55,7 @@ pub fun write_str(w: *writer.Writer, s: str) Result[usize, str] { ret writer.write_all(w, s, str_len(s)); } -# write_byte: write a single byte to a writer. +# write a single byte to a writer # --- # w: target writer # b: byte to write @@ -65,7 +65,7 @@ pub fun write_byte(w: *writer.Writer, b: u8) Result[usize, str] { ret writer.write_all(w, ?x, 1); } -# write_newline: write a linefeed to a writer. +# write a linefeed to a writer # --- # w: target writer # ret: 1 on success, or an error message @@ -73,7 +73,7 @@ pub fun write_newline(w: *writer.Writer) Result[usize, str] { ret write_byte(w, '\n'); } -# write_u64: write an unsigned integer in decimal. +# write an unsigned integer in decimal # --- # w: target writer # n: value to format @@ -101,7 +101,7 @@ pub fun write_u64(w: *writer.Writer, n: u64) Result[usize, str] { ret writer.write_all(w, ?buf[idx], len); } -# write_i64: write a signed integer in decimal. +# write a signed integer in decimal # --- # w: target writer # n: value to format @@ -123,7 +123,7 @@ pub fun write_i64(w: *writer.Writer, n: i64) Result[usize, str] { ret ok[usize, str](unwrap_ok[usize, str](r1) + unwrap_ok[usize, str](r2)); } -# write_hex_u64: write a 64-bit value in hexadecimal. +# write a 64-bit value in hexadecimal # --- # w: target writer # n: value to format @@ -161,7 +161,7 @@ pub fun write_hex_u64(w: *writer.Writer, n: u64, upper: bool) Result[usize, str] ret writer.write_all(w, ?buf[idx], len); } -# write_ptr: write a pointer as 0x followed by hex digits. +# write a pointer as 0x followed by hex digits # --- # w: target writer # p: pointer to format @@ -176,7 +176,7 @@ pub fun write_ptr(w: *writer.Writer, p: ptr) Result[usize, str] { ret ok[usize, str](unwrap_ok[usize, str](r1) + unwrap_ok[usize, str](r2)); } -# bitlen_u64: number of significant bits in v (0 when v == 0). +# number of significant bits in v (0 when v == 0) fun bitlen_u64(v: u64) usize { var n: usize = 0; var x: u64 = v; @@ -187,10 +187,10 @@ fun bitlen_u64(v: u64) usize { ret n; } -# dragon4: shortest round-trippable decimal digits of v = f * 2^e (f != 0). +# shortest round-trippable decimal digits of v = f * 2^e (f != 0) # writes digit values 0..9 into buf, the count into out_n, and the decimal # exponent into out_decExp such that v = 0. * 10^out_decExp. exact -# bignum arithmetic, round-to-nearest-even — no magic tables. +# bignum arithmetic, round-to-nearest-even, no magic tables. fun dragon4(f: u64, e: i64, buf: *u8, out_n: *usize, out_decExp: *i64) { var R: bn.Big; var S: bn.Big; @@ -335,7 +335,7 @@ fun dragon4(f: u64, e: i64, buf: *u8, out_n: *usize, out_decExp: *i64) { @out_decExp = k; } -# write_f64: write a 64-bit float in shortest round-trippable decimal. +# write a 64-bit float in shortest round-trippable decimal # --- # w: target writer # n: value to format @@ -475,7 +475,7 @@ pub val ERR_BAD_FORMAT: str = "bad format"; pub val ERR_FEW_HOLES: str = "more arguments than format holes"; pub val ERR_MANY_HOLES: str = "more format holes than arguments"; -# Spec: a parsed `{...}` hole spec. +# a parsed `{...}` hole spec # --- # left: left-align (pad on the right) instead of the default right-align # hex: render an integer in hexadecimal @@ -492,14 +492,14 @@ rec Spec { width: usize; } -# Span: a fixed-capacity buffer writer used to size a field before padding. +# a fixed-capacity buffer writer used to size a field before padding rec Span { buf: *u8; len: usize; cap: usize; } -# span_write: Writer callback appending bytes into a Span up to its capacity. +# writer callback appending bytes into a Span up to its capacity fun span_write(ctx: ptr, p: *u8, len: usize) Result[usize, str] { val s: *Span = ctx::*Span; var i: usize = 0; @@ -512,7 +512,7 @@ fun span_write(ctx: ptr, p: *u8, len: usize) Result[usize, str] { ret ok[usize, str](len); } -# parse_spec: parse a `{...}` hole, advancing *ip past the closing brace. +# parse a `{...}` hole, advancing *ip past the closing brace # --- # precondition: fmt[*ip] == '{' opening a real hole (callers handle `{{`). # grammar: '{' [ ':' [ '<' ] [ '0' ] [ width ] [ 'x' | 'X' | 'c' ] ] '}' @@ -566,7 +566,7 @@ fun parse_spec(fmt: str, ip: *usize) Result[Spec, str] { ret ok[Spec, str](sp); } -# emit_pad: write n copies of byte b to w. +# write n copies of byte b to w fun emit_pad(w: *writer.Writer, b: u8, n: usize) Result[usize, str] { var i: usize = 0; for (i < n) { @@ -577,11 +577,11 @@ fun emit_pad(w: *writer.Writer, b: u8, n: usize) Result[usize, str] { ret ok[usize, str](n); } -# emit_field: write a rendered field with width padding per spec. +# write a rendered field with width padding per spec # --- # right-aligned by default; a leading '-' stays ahead of '0' padding. when # sp.left is set, the value is written first and space-padded on the right -# (the zero flag is ignored — trailing zeros would corrupt the value). +# (the zero flag is ignored, trailing zeros would corrupt the value). # ret: total bytes written (>= len), or an error fun emit_field(w: *writer.Writer, buf: *u8, len: usize, sp: *Spec) Result[usize, str] { if (sp.width <= len) { @@ -616,7 +616,7 @@ fun emit_field(w: *writer.Writer, buf: *u8, len: usize, sp: *Spec) Result[usize, ret ok[usize, str](sp.width); } -# emit_literal: write literal text up to the next hole, honoring `{{`/`}}`. +# write literal text up to the next hole, honoring `{{`/`}}` # --- # advances *ip and adds written bytes to *tp. # ret: ok(true) stopped at a hole-open `{`; ok(false) reached end of string; @@ -655,7 +655,7 @@ fun emit_literal(w: *writer.Writer, fmt: str, ip: *usize, tp: *usize) Result[boo ret ok[bool, str](false); } -# fmt_i64: format a signed integer per spec (decimal, hex of the two's-complement +# format a signed integer per spec (decimal, hex of the two's-complement # bits, or low-byte char) with width padding. fun fmt_i64(w: *writer.Writer, v: i64, sp: *Spec) Result[usize, str] { var scratch: [64]u8; @@ -678,7 +678,7 @@ fun fmt_i64(w: *writer.Writer, v: i64, sp: *Spec) Result[usize, str] { ret emit_field(w, ?scratch[0], s.len, sp); } -# fmt_u64: format an unsigned integer per spec (decimal, hex, or low-byte char) +# format an unsigned integer per spec (decimal, hex, or low-byte char) # with width padding. fun fmt_u64(w: *writer.Writer, v: u64, sp: *Spec) Result[usize, str] { var scratch: [64]u8; @@ -701,7 +701,7 @@ fun fmt_u64(w: *writer.Writer, v: u64, sp: *Spec) Result[usize, str] { ret emit_field(w, ?scratch[0], s.len, sp); } -# fmt_f64_field: format a float in shortest round-trip decimal with width padding. +# format a float in shortest round-trip decimal with width padding fun fmt_f64_field(w: *writer.Writer, v: f64, sp: *Spec) Result[usize, str] { var scratch: [64]u8; var s: Span = Span{ buf: ?scratch[0], len: 0, cap: 64 }; @@ -714,7 +714,7 @@ fun fmt_f64_field(w: *writer.Writer, v: f64, sp: *Spec) Result[usize, str] { ret emit_field(w, ?scratch[0], s.len, sp); } -# fmt_ptr_field: format a pointer as 0x-prefixed hex with width padding. +# format a pointer as 0x-prefixed hex with width padding fun fmt_ptr_field(w: *writer.Writer, p: ptr, sp: *Spec) Result[usize, str] { var scratch: [64]u8; var s: Span = Span{ buf: ?scratch[0], len: 0, cap: 64 }; @@ -727,7 +727,7 @@ fun fmt_ptr_field(w: *writer.Writer, p: ptr, sp: *Spec) Result[usize, str] { ret emit_field(w, ?scratch[0], s.len, sp); } -# fmt_str_field: write a string with width padding (space-padded; right-aligned +# write a string with width padding (space-padded; right-aligned # by default, left-aligned when sp.left is set). fun fmt_str_field(w: *writer.Writer, sv: str, sp: *Spec) Result[usize, str] { var n: usize = 0; @@ -752,7 +752,7 @@ fun fmt_str_field(w: *writer.Writer, sv: str, sp: *Spec) Result[usize, str] { ret ok[usize, str](sp.width); } -# vformat: format a comptime-variadic pack into a writer (v1.7 packs). +# format a comptime-variadic pack into a writer (v1.7 packs) # # holes are type-directed `{}` matched to args in order: signed/unsigned int -> # decimal, str -> text, ptr -> 0xHEX, f64 -> shortest round-trip decimal. specs: @@ -782,14 +782,14 @@ pub fun vformat(w: *writer.Writer, fmt: str, va: ...) Result[usize, str] { # type-directed dispatch: a `$type_of` gate folds at lowering (#1472), so # every arm is type-checked under each concrete arg type and only the - # selected arm executes. each arm casts arg to its own type — an identity + # selected arm executes. each arm casts arg to its own type, an identity # cast in the taken arm; the rest are pruned before they run. unsupported # types fall through to a runtime ERR_BAD_FORMAT. var fr: Result[usize, str]; $if ($type_of(arg) == str) { fr = fmt_str_field(w, (arg::usize)::str, ?sp); } $or ($type_of(arg) == ptr) { fr = fmt_ptr_field(w, (arg::usize)::ptr, ?sp); } $or ($type_of(arg) == f64) { fr = fmt_f64_field(w, arg::f64, ?sp); } - # f32 widens to f64 (exact) and prints as that value — no f32 shortest round-trip. + # f32 widens to f64 (exact) and prints as that value, no f32 shortest round-trip. $or ($type_of(arg) == f32) { fr = fmt_f64_field(w, arg::f64, ?sp); } $or ($type_of(arg) == i64) { fr = fmt_i64(w, arg::i64, ?sp); } $or ($type_of(arg) == i32) { fr = fmt_i64(w, arg::i64, ?sp); } @@ -811,7 +811,7 @@ pub fun vformat(w: *writer.Writer, fmt: str, va: ...) Result[usize, str] { ret ok[usize, str](total); } -# format: format a comptime-variadic pack into a writer. +# format a comptime-variadic pack into a writer # # thin wrapper that forwards the whole pack to vformat. # --- @@ -823,7 +823,7 @@ pub fun format(w: *writer.Writer, fmt: str, va: ...) Result[usize, str] { ret vformat(w, fmt, va...); } -# test-only buffer-backed writer used to capture write_f64 output. +# test-only buffer-backed writer used to capture write_f64 output rec TestBuf { data: *u8; len: usize; @@ -842,7 +842,7 @@ fun testbuf_write(ctx: ptr, p: *u8, len: usize) Result[usize, str] { ret ok[usize, str](len); } -# f64_into: format n into storage (null-terminated); returns the byte length. +# format n into storage (null-terminated); returns the byte length fun f64_into(n: f64, storage: *u8, cap: usize) usize { var tb: TestBuf; tb.data = storage; @@ -857,14 +857,14 @@ fun f64_into(n: f64, storage: *u8, cap: usize) usize { ret tb.len; } -# golden_eq: format n and compare to the expected shortest decimal. +# format n and compare to the expected shortest decimal fun golden_eq(n: f64, want: str) bool { var s: [64]u8; f64_into(n, ?s[0], 64); ret str_equals(?s[0], want); } -# golden_bits_eq: format the f64 with the given bit pattern and compare. +# format the f64 with the given bit pattern and compare fun golden_bits_eq(bits: u64, want: str) bool { var n: f64; mem.raw_copy(?n, ?bits, 8); @@ -926,7 +926,7 @@ test "write_f64: golden notation" { # extremes use exact bit patterns so they don't depend on the precision of the # compiler's float-literal lexer (which is not correctly-rounded for large -# exponents — tracked separately from this formatter). +# exponents, tracked separately from this formatter). test "write_f64: golden extremes (exact bits)" { if (!golden_bits_eq(0x7FEFFFFFFFFFFFFF, "1.7976931348623157e308")) { ret 1; } if (!golden_bits_eq(0x0010000000000000, "2.2250738585072014e-308")) { ret 1; } @@ -936,7 +936,7 @@ test "write_f64: golden extremes (exact bits)" { ret 0; } -# fmt_capture: vformat a pack into storage (null-terminated); returns the Result. +# vformat a pack into storage (null-terminated); returns the Result # behavioral tests assert the captured bytes and the returned true byte count. fun fmt_capture(storage: *u8, cap: usize, fmt: str, va: ...) Result[usize, str] { var tb: TestBuf; diff --git a/src/io/buffer.mach b/src/io/buffer.mach index a8db857..0bb2b71 100644 --- a/src/io/buffer.mach +++ b/src/io/buffer.mach @@ -1,4 +1,4 @@ -# growable byte buffer for binary serialization. +# growable byte buffer for binary serialization # # WriteBuf builds byte sequences with typed writes, alignment, and patching. # ReadBuf provides a cursor over an existing byte slice for deserialization. @@ -21,7 +21,7 @@ use allocator: std.allocator; use page: std.allocator.page; use mem: std.memory; -# WriteBuf: growable output buffer. +# growable output buffer # --- # alloc: allocator for buffer memory # data: backing byte array @@ -34,7 +34,7 @@ pub rec WriteBuf { cap: usize; } -# wbuf_make: create an empty write buffer. +# create an empty write buffer # --- # a: allocator for buffer memory # ret: a new empty WriteBuf @@ -47,7 +47,7 @@ pub fun wbuf_make(a: *allocator.Allocator) WriteBuf { ret buf; } -# wbuf_dnit: free buffer memory and reset fields. +# free buffer memory and reset fields # --- # buf: buffer to deinitialize # ret: true if memory was freed successfully @@ -68,7 +68,7 @@ pub fun wbuf_dnit(buf: *WriteBuf) bool { ret freed; } -# wbuf_reserve: ensure capacity for additional bytes. +# ensure capacity for additional bytes # --- # buf: buffer to reserve in # additional: number of additional bytes needed @@ -100,7 +100,7 @@ pub fun wbuf_reserve(buf: *WriteBuf, additional: usize) Result[usize, str] { ret ok[usize, str](buf.cap); } -# wbuf_write: write a value of type T into the buffer. +# write a value of type T into the buffer # --- # buf: buffer to write into # value: value to serialize @@ -116,7 +116,7 @@ pub fun wbuf_write[T](buf: *WriteBuf, value: T) Result[usize, str] { ret ok[usize, str](buf.len); } -# wbuf_write_bytes: write raw bytes into the buffer. +# write raw bytes into the buffer # --- # buf: buffer to write into # p: pointer to source bytes @@ -133,7 +133,7 @@ pub fun wbuf_write_bytes(buf: *WriteBuf, p: *u8, len: usize) Result[usize, str] ret ok[usize, str](buf.len); } -# wbuf_write_str: write a string including its null terminator. +# write a string including its null terminator # --- # buf: buffer to write into # s: string to write @@ -151,7 +151,7 @@ pub fun wbuf_write_str(buf: *WriteBuf, s: str) Result[usize, str] { ret ok[usize, str](buf.len); } -# wbuf_align: pad with zero bytes to an alignment boundary. +# pad with zero bytes to an alignment boundary # --- # buf: buffer to align # boundary: alignment boundary (must be power of two) @@ -169,7 +169,7 @@ pub fun wbuf_align(buf: *WriteBuf, boundary: usize) Result[usize, str] { ret ok[usize, str](buf.len); } -# wbuf_patch: overwrite bytes at a given offset without changing length. +# overwrite bytes at a given offset without changing length # --- # buf: buffer to patch # offset: byte offset to write at @@ -184,7 +184,7 @@ pub fun wbuf_patch[T](buf: *WriteBuf, offset: usize, value: T) Result[usize, str ret ok[usize, str](sz); } -# ReadBuf: cursor over an existing byte slice. +# cursor over an existing byte slice # --- # data: pointer to byte data # len: total length in bytes @@ -195,7 +195,7 @@ pub rec ReadBuf { pos: usize; } -# rbuf_make: wrap existing data as a read buffer. +# wrap existing data as a read buffer # --- # data: pointer to byte data # len: length in bytes @@ -208,7 +208,7 @@ pub fun rbuf_make(data: *u8, len: usize) ReadBuf { ret buf; } -# rbuf_read: read a value of type T and advance position. +# read a value of type T and advance position # --- # buf: buffer to read from # ret: the value, or an error @@ -222,7 +222,7 @@ pub fun rbuf_read[T](buf: *ReadBuf) Result[T, str] { ret ok[T, str](v); } -# rbuf_read_bytes: return a pointer into the buffer and advance. +# return a pointer into the buffer and advance # --- # buf: buffer to read from # len: number of bytes to consume @@ -235,7 +235,7 @@ pub fun rbuf_read_bytes(buf: *ReadBuf, len: usize) Result[*u8, str] { ret ok[*u8, str](p); } -# rbuf_read_str: read a null-terminated string and advance past the NUL. +# read a null-terminated string and advance past the NUL # --- # buf: buffer to read from # ret: the string, or an error @@ -252,7 +252,7 @@ pub fun rbuf_read_str(buf: *ReadBuf) Result[str, str] { ret err[str, str]("no null terminator found"); } -# rbuf_skip: advance position by n bytes. +# advance position by n bytes # --- # buf: buffer to advance # n: number of bytes to skip @@ -263,7 +263,7 @@ pub fun rbuf_skip(buf: *ReadBuf, n: usize) Result[usize, str] { ret ok[usize, str](buf.pos); } -# rbuf_align: skip to an alignment boundary. +# skip to an alignment boundary # --- # buf: buffer to align # boundary: alignment boundary (must be power of two) @@ -275,7 +275,7 @@ pub fun rbuf_align(buf: *ReadBuf, boundary: usize) Result[usize, str] { ret rbuf_skip(buf, skip); } -# rbuf_remaining: return the number of unread bytes. +# return the number of unread bytes # --- # buf: buffer to query # ret: bytes between pos and len diff --git a/src/io/reader.mach b/src/io/reader.mach index 8f32b08..9e7db3d 100644 --- a/src/io/reader.mach +++ b/src/io/reader.mach @@ -1,4 +1,4 @@ -# generic reader interface. +# generic reader interface # # backend-agnostic read interface using ctx + fn_ptr dispatch. # concrete implementations (fd, buffer, etc.) wire themselves via make(). @@ -11,7 +11,7 @@ use std.types.result.unwrap_ok; use std.types.size.usize; use std.types.string.str; -# Reader: generic read interface +# generic read interface # --- # ctx: opaque context passed to the read callback # fn_read: read callback (ctx, buf, len) -> Result[usize, str] @@ -22,7 +22,7 @@ pub rec Reader { pub val ERR_EOF: str = "eof"; -# read: read up to len bytes into buf. +# read up to len bytes into buf # --- # r: reader to read from # buf: buffer to read into @@ -32,7 +32,7 @@ pub fun read(r: *Reader, buf: *u8, len: usize) Result[usize, str] { ret r.fn_read(r.ctx, buf, len); } -# read_exact: read exactly len bytes into buf. +# read exactly len bytes into buf # --- # r: reader to read from # buf: buffer to fill diff --git a/src/io/writer.mach b/src/io/writer.mach index cd6e912..a746b4f 100644 --- a/src/io/writer.mach +++ b/src/io/writer.mach @@ -1,4 +1,4 @@ -# generic writer interface. +# generic writer interface # # backend-agnostic write interface using ctx + fn_ptr dispatch. # concrete implementations (fd, buffer, etc.) wire themselves via make(). @@ -11,7 +11,7 @@ use std.types.result.unwrap_ok; use std.types.size.usize; use std.types.string.str; -# Writer: generic write interface +# generic write interface # --- # ctx: opaque context passed to the write callback # fn_write: write callback (ctx, buf, len) -> Result[usize, str] @@ -22,7 +22,7 @@ pub rec Writer { pub val ERR_SHORT_WRITE: str = "short write"; -# write: write up to len bytes from buf. +# write up to len bytes from buf # --- # w: writer to write to # buf: buffer to write from @@ -32,7 +32,7 @@ pub fun write(w: *Writer, buf: *u8, len: usize) Result[usize, str] { ret w.fn_write(w.ctx, buf, len); } -# write_all: write exactly len bytes from buf. +# write exactly len bytes from buf # --- # w: writer to write to # buf: buffer to write from diff --git a/src/lib.mach b/src/lib.mach index 2c4dc9b..0f23351 100644 --- a/src/lib.mach +++ b/src/lib.mach @@ -1,3 +1,5 @@ +# aggregate surface re-exporting every standard library module + fwd std.types.bool; fwd std.types.char; fwd std.types.option; diff --git a/src/log.mach b/src/log.mach index c1af644..99b0293 100644 --- a/src/log.mach +++ b/src/log.mach @@ -1,4 +1,4 @@ -# structured logging with configurable level and output. +# structured logging with configurable level and output # # writes leveled log messages to stderr by default, or to a configured # writer. each message is prefixed with the level tag in brackets. @@ -24,7 +24,7 @@ var out_ctx: ptr = nil; var out_fn: usize = 0; var writer_set: i64 = 0; -# set the minimum log level. +# set the minimum log level # # messages below this level are silently discarded. safe to call from # any thread; takes effect immediately for subsequent log calls. @@ -34,7 +34,7 @@ pub fun set_level(level: Level) { atomic.store(?level_val, level::i64); } -# set the output writer for log messages. +# set the output writer for log messages # # when set, all output goes through this writer instead of stderr. # must be called before spawning threads that log. @@ -71,28 +71,28 @@ fun log_msg(level: Level, prefix: str, msg: str) { write_piece("\n", 1); } -# log a message at DEBUG level. +# log a message at DEBUG level # --- # msg: message to log pub fun debug(msg: str) { log_msg(DEBUG, "DEBUG", msg); } -# log a message at INFO level. +# log a message at INFO level # --- # msg: message to log pub fun info(msg: str) { log_msg(INFO, "INFO", msg); } -# log a message at WARN level. +# log a message at WARN level # --- # msg: message to log pub fun warn(msg: str) { log_msg(WARN, "WARN", msg); } -# log a message at ERROR level. +# log a message at ERROR level # --- # msg: message to log pub fun error(msg: str) { @@ -119,7 +119,7 @@ test "set_level: DEBUG enables all" { ret 0; } -test "log functions: nil message does not crash" { +test "log: nil message does not crash" { set_level(DEBUG); debug(nil); info(nil); diff --git a/src/math.mach b/src/math.mach index 72b253d..9e1fee0 100644 --- a/src/math.mach +++ b/src/math.mach @@ -1,4 +1,4 @@ -# integer math utilities. +# integer math utilities use std.types.bool.bool; use std.types.bool.true; @@ -7,7 +7,7 @@ use std.types.bool.false; val I64_MIN: i64 = -9223372036854775808; val I64_MAX: i64 = 9223372036854775807; -# return the smaller of two signed integers. +# return the smaller of two signed integers # --- # a: first value # b: second value @@ -17,7 +17,7 @@ pub fun min(a: i64, b: i64) i64 { ret b; } -# return the larger of two signed integers. +# return the larger of two signed integers # --- # a: first value # b: second value @@ -27,7 +27,7 @@ pub fun max(a: i64, b: i64) i64 { ret b; } -# clamp a signed integer to the range [lo, hi]. +# clamp a signed integer to the range [lo, hi] # --- # v: value to clamp # lo: lower bound @@ -39,7 +39,7 @@ pub fun clamp(v: i64, lo: i64, hi: i64) i64 { ret v; } -# return the absolute value of a signed integer. +# return the absolute value of a signed integer # # saturates at I64_MAX for I64_MIN input. # --- @@ -51,7 +51,7 @@ pub fun abs(v: i64) i64 { ret v; } -# return the smaller of two unsigned integers. +# return the smaller of two unsigned integers # --- # a: first value # b: second value @@ -61,7 +61,7 @@ pub fun umin(a: u64, b: u64) u64 { ret b; } -# return the larger of two unsigned integers. +# return the larger of two unsigned integers # --- # a: first value # b: second value @@ -71,7 +71,7 @@ pub fun umax(a: u64, b: u64) u64 { ret b; } -# clamp an unsigned integer to the range [lo, hi]. +# clamp an unsigned integer to the range [lo, hi] # --- # v: value to clamp # lo: lower bound @@ -83,7 +83,7 @@ pub fun uclamp(v: u64, lo: u64, hi: u64) u64 { ret v; } -# check whether a value is a power of two. +# check whether a value is a power of two # --- # v: value to check # ret: true if v is a non-zero power of two @@ -92,7 +92,7 @@ pub fun is_pow2(v: u64) bool { ret (v & (v - 1)) == 0; } -# round up to the next power of two. +# round up to the next power of two # # returns v if already a power of two, 1 if v is 0. # --- @@ -110,7 +110,7 @@ pub fun next_pow2(v: u64) u64 { ret n + 1; } -# compute the floor of log base 2. +# compute the floor of log base 2 # # returns 0 for v == 0 (undefined). # --- @@ -129,7 +129,7 @@ pub fun log2(v: u64) u64 { ret n; } -# ceiling division of two unsigned integers. +# ceiling division of two unsigned integers # --- # a: dividend # b: divisor (must not be 0) @@ -138,7 +138,7 @@ pub fun ceil_div(a: u64, b: u64) u64 { ret (a + b - 1) / b; } -# saturating signed addition. +# saturating signed addition # # clamps the result to [I64_MIN, I64_MAX] on overflow. # --- @@ -152,7 +152,7 @@ pub fun sat_add(a: i64, b: i64) i64 { ret result; } -# saturating signed subtraction. +# saturating signed subtraction # # clamps the result to [I64_MIN, I64_MAX] on overflow. # --- @@ -166,7 +166,7 @@ pub fun sat_sub(a: i64, b: i64) i64 { ret result; } -# saturating signed multiplication. +# saturating signed multiplication # # clamps the result to [I64_MIN, I64_MAX] on overflow. # --- diff --git a/src/math/bignum.mach b/src/math/bignum.mach index 8cefc5c..8624c9e 100644 --- a/src/math/bignum.mach +++ b/src/math/bignum.mach @@ -1,4 +1,4 @@ -# fixed-capacity big integer for exact decimal<->binary float conversion. +# fixed-capacity big integer for exact decimal<->binary float conversion # # limbs are little-endian 32-bit; n counts active limbs (n == 0 is zero, no # leading-zero limbs). 128 limbs (4096 bits) covers every f64 conversion @@ -9,25 +9,25 @@ use std.types.bool.bool; use std.types.size.usize; -# Big: a fixed-capacity unsigned big integer. +# a fixed-capacity unsigned big integer pub rec Big { n: usize; d: [128]u32; } -# zero: set b to zero. +# set b to zero pub fun zero(b: *Big) { b.n = 0; } -# norm: drop leading-zero limbs so n is exact. +# drop leading-zero limbs so n is exact pub fun norm(b: *Big) { for (b.n > 0 && b.d[b.n - 1] == 0) { b.n = b.n - 1; } } -# from_u64: set b to v. +# set b to v pub fun from_u64(b: *Big, v: u64) { b.d[0] = (v & 0xFFFFFFFF)::u32; b.d[1] = (v >> 32)::u32; @@ -35,19 +35,19 @@ pub fun from_u64(b: *Big, v: u64) { norm(b); } -# is_zero: true iff b == 0. +# true iff b == 0 pub fun is_zero(b: *Big) bool { ret b.n == 0; } -# to_u64: low 64 bits of b (exact when b < 2^64). +# low 64 bits of b (exact when b < 2^64) pub fun to_u64(b: *Big) u64 { if (b.n == 0) { ret 0; } if (b.n == 1) { ret b.d[0]::u64; } ret b.d[0]::u64 | (b.d[1]::u64 << 32); } -# copy: dst = src. +# dst = src pub fun copy(dst: *Big, src: *Big) { dst.n = src.n; var i: usize = 0; @@ -57,7 +57,7 @@ pub fun copy(dst: *Big, src: *Big) { } } -# cmp: -1 if a < b, 0 if equal, 1 if a > b. +# -1 if a < b, 0 if equal, 1 if a > b pub fun cmp(a: *Big, b: *Big) i64 { if (a.n != b.n) { if (a.n < b.n) { ret -1; } @@ -74,7 +74,7 @@ pub fun cmp(a: *Big, b: *Big) i64 { ret 0; } -# mul_small: b = b * m. +# b = b * m pub fun mul_small(b: *Big, m: u32) { if (b.n == 0 || m == 0) { zero(b); ret; } var carry: u64 = 0; @@ -91,7 +91,7 @@ pub fun mul_small(b: *Big, m: u32) { } } -# shl: b = b << bits (multiply by 2^bits). +# b = b << bits (multiply by 2^bits) pub fun shl(b: *Big, bits: usize) { if (b.n == 0 || bits == 0) { ret; } val limb_shift: usize = bits / 32; @@ -125,7 +125,7 @@ pub fun shl(b: *Big, bits: usize) { } } -# add: a = a + b. +# a = a + b pub fun add(a: *Big, b: *Big) { var maxn: usize = a.n; if (b.n > maxn) { maxn = b.n; } @@ -149,7 +149,7 @@ pub fun add(a: *Big, b: *Big) { norm(a); } -# sub: a = a - b, requires a >= b. +# a = a - b, requires a >= b pub fun sub(a: *Big, b: *Big) { var borrow: i64 = 0; var i: usize = 0; @@ -170,7 +170,7 @@ pub fun sub(a: *Big, b: *Big) { norm(a); } -# add_small: b = b + x. +# b = b + x pub fun add_small(b: *Big, x: u32) { if (b.n == 0) { from_u64(b, x::u64); ret; } var carry: u64 = x::u64; @@ -187,7 +187,7 @@ pub fun add_small(b: *Big, x: u32) { } } -# mul_pow10: b = b * 10^k. +# b = b * 10^k pub fun mul_pow10(b: *Big, k: usize) { var rem: usize = k; for (rem >= 9) { @@ -205,7 +205,7 @@ pub fun mul_pow10(b: *Big, k: usize) { } } -# bitlen: number of significant bits (0 when b == 0). +# number of significant bits (0 when b == 0) pub fun bitlen(b: *Big) usize { if (b.n == 0) { ret 0; } var top: u32 = b.d[b.n - 1]; diff --git a/src/math/bits.mach b/src/math/bits.mach index 3bc22bf..e30aad9 100644 --- a/src/math/bits.mach +++ b/src/math/bits.mach @@ -1,6 +1,6 @@ -# bit manipulation utilities. +# bit manipulation utilities -# count the number of set bits (Hamming weight). +# count the number of set bits (Hamming weight) # --- # v: value to count # ret: number of 1-bits in v @@ -12,7 +12,7 @@ pub fun popcount(v: u64) u64 { ret (x * 0x0101010101010101) >> 56; } -# count leading zeros. +# count leading zeros # # returns 64 if v is 0. # --- @@ -31,7 +31,7 @@ pub fun clz(v: u64) u64 { ret n; } -# count trailing zeros. +# count trailing zeros # # returns 64 if v is 0. # --- @@ -42,7 +42,7 @@ pub fun ctz(v: u64) u64 { ret popcount((v & (0 - v)) - 1); } -# rotate bits left by n positions. +# rotate bits left by n positions # --- # v: value to rotate # n: number of bit positions (masked to 0..63) @@ -53,7 +53,7 @@ pub fun rotate_left(v: u64, n: u64) u64 { ret (v << s) | (v >> (64 - s)); } -# rotate bits right by n positions. +# rotate bits right by n positions # --- # v: value to rotate # n: number of bit positions (masked to 0..63) @@ -64,7 +64,7 @@ pub fun rotate_right(v: u64, n: u64) u64 { ret (v >> s) | (v << (64 - s)); } -# reverse byte order (big-endian to little-endian or vice versa). +# reverse byte order (big-endian to little-endian or vice versa) # --- # v: value to byte-swap # ret: v with bytes in reversed order @@ -81,7 +81,7 @@ pub fun byte_swap(v: u64) u64 { ret x; } -# reverse all 64 bits. +# reverse all 64 bits # --- # v: value to reverse # ret: v with all bits in reversed order diff --git a/src/memory.mach b/src/memory.mach index 217e3b6..f02b2c7 100644 --- a/src/memory.mach +++ b/src/memory.mach @@ -1,11 +1,11 @@ +# low-level memory operations for raw and typed buffers + use std.types.bool.bool; use std.types.bool.true; use std.types.bool.false; use std.types.size.usize; -# low-level memory operations for raw and typed buffers. - -# raw_fill: fill a block of raw memory with a byte value. +# fill a block of raw memory with a byte value # --- # p: pointer to the start of the memory block # value: byte value to fill with @@ -24,7 +24,7 @@ pub fun raw_fill(p: ptr, value: u8, size: usize) { } } -# raw_copy: copy a block of raw memory from source to destination. +# copy a block of raw memory from source to destination # --- # dst: pointer to the destination memory block # src: pointer to the source memory block @@ -44,7 +44,7 @@ pub fun raw_copy(dst: ptr, src: ptr, size: usize) { } } -# copy a block of raw memory, correctly handling overlapping regions. +# copy a block of raw memory, correctly handling overlapping regions # # copies backward when dst > src to avoid corruption from overlap. # for non-overlapping regions, raw_copy is preferred. @@ -71,7 +71,7 @@ pub fun raw_move(dst: ptr, src: ptr, size: usize) { } } -# raw_zero: zero out a block of raw memory. +# zero out a block of raw memory # --- # p: pointer to the start of the memory block # size: number of bytes to zero out @@ -79,7 +79,7 @@ pub fun raw_zero(p: ptr, size: usize) { raw_fill(p, 0, size); } -# fill: fill a block of memory with a value for type T. +# fill a block of memory with a value for type T # --- # p: pointer to the start of the memory block # value: value to fill with @@ -96,7 +96,7 @@ pub fun fill[T](p: *T, value: T, count: usize) { } } -# copy: copy a block of memory from a source to a destination. +# copy a block of memory from a source to a destination # --- # dst: pointer to the destination memory block # src: pointer to the source memory block @@ -113,7 +113,7 @@ pub fun copy[T](dst: *T, src: *T, count: usize) { } } -# copy a typed block of memory, correctly handling overlapping regions. +# copy a typed block of memory, correctly handling overlapping regions # # delegates to raw_move for the actual byte-level overlapping copy. # for non-overlapping regions, copy[T] is preferred. @@ -130,7 +130,7 @@ pub fun move[T](dst: *T, src: *T, count: usize) { raw_move(dst::ptr, src::ptr, $size_of(T) * count); } -# zero: zero out a block of memory for a number of elements of type T. +# zero out a block of memory for a number of elements of type T # --- # p: pointer to the start of the memory block # count: number of elements to zero out @@ -140,7 +140,7 @@ pub fun zero[T](p: *T, count: usize) { raw_zero(p::ptr, $size_of(T) * count); } -# raw_equal: compare two blocks of raw memory byte-wise. +# compare two blocks of raw memory byte-wise # # nil contract: n==0 is vacuously true regardless of pointer values. # equal pointers (including nil==nil) are trivially true without dereference. @@ -164,7 +164,7 @@ pub fun raw_equal(a: ptr, b: ptr, n: usize) bool { ret true; } -# equal: compare n typed elements at a and b for byte-wise equality. +# compare n typed elements at a and b for byte-wise equality # # delegates to raw_equal; see raw_equal for nil handling. # returns false if the byte count would overflow usize. diff --git a/src/net/dns.mach b/src/net/dns.mach index 326daf6..a19ff9b 100644 --- a/src/net/dns.mach +++ b/src/net/dns.mach @@ -1,4 +1,4 @@ -# DNS hostname resolution. +# DNS hostname resolution use std.types.bool.bool; use std.types.bool.true; @@ -10,10 +10,10 @@ use std.types.result.unwrap_ok; use std.types.string.str; use std.types.string.str_len; use memory: std.memory; -use os: std.system.os; -use ip: std.net.ip; -use udp: std.net.udp; -use rand: std.crypto.rand; +use os: std.system.os; +use ip: std.net.ip; +use udp: std.net.udp; +use rand: std.crypto.rand; val DNS_PORT: u16 = 53; val DNS_HEADER_LEN: usize = 12; @@ -21,7 +21,7 @@ val DNS_MAX_PACKET: usize = 512; val DNS_TYPE_A: u16 = 1; val DNS_CLASS_IN: u16 = 1; -# lookup_hosts: resolve a hostname via the system hosts file. +# resolve a hostname via the system hosts file # # searches the platform hosts file for a matching hostname and writes # the first IPv4 address found into addr. @@ -92,7 +92,7 @@ pub fun lookup_hosts(hostname: str, addr: *ip.IPv4) bool { ret false; } -# query: resolve a hostname via DNS A record query. +# resolve a hostname via DNS A record query # # queries the platform nameserver with a DNS A record request over UDP. # writes the first address from the response into addr. @@ -128,11 +128,11 @@ pub fun query(hostname: str, addr: *ip.IPv4) bool { ret parse_response(?resp[0], recvd::usize, addr, qid); } -# resolve: resolve a hostname to an IPv4 address. +# resolve a hostname to an IPv4 address # # per RFC 6761 the name `localhost` and any name ending in `.localhost` # resolve to the loopback address (127.0.0.1) without consulting the hosts -# file or a nameserver — this is resolver behavior, not hosts-file content, +# file or a nameserver, this is resolver behavior, not hosts-file content, # and so is portable across platforms whose hosts file omits localhost. # other names fall back to the hosts file, then a DNS query. # --- @@ -151,7 +151,7 @@ pub fun resolve(hostname: str, addr: *ip.IPv4) bool { ret query(hostname, addr); } -# is_localhost: report whether hostname is an RFC 6761 localhost name. +# report whether hostname is an RFC 6761 localhost name # # matches `localhost` or any name ending in `.localhost`, case-insensitively. fun is_localhost(hostname: str) bool { diff --git a/src/net/ip.mach b/src/net/ip.mach index 0cee035..6b92a1d 100644 --- a/src/net/ip.mach +++ b/src/net/ip.mach @@ -1,4 +1,4 @@ -# IP address types and utilities. +# IP address types and utilities use std.types.bool.bool; use std.types.size.usize; @@ -7,21 +7,21 @@ use std.types.string.str_starts_with; use mem: std.memory; use os: std.system.os; -# IPv4: an IPv4 address stored as four octets. +# an IPv4 address stored as four octets # --- # octets: the four octets in network order pub rec IPv4 { octets: [4]u8; } -# IPv6: an IPv6 address stored as sixteen octets. +# an IPv6 address stored as sixteen octets # --- # octets: the sixteen octets in network order pub rec IPv6 { octets: [16]u8; } -# Addr: a tagged union of IPv4 and IPv6 addresses. +# a tagged union of IPv4 and IPv6 addresses # --- # is_v6: nonzero if the address is IPv6 # v4: the IPv4 address (valid when is_v6 == 0) @@ -32,7 +32,7 @@ pub rec Addr { v6: IPv6; } -# Endpoint: an IP address and port pair. +# an IP address and port pair # --- # addr: IPv4 address # port: port number in host byte order @@ -41,7 +41,7 @@ pub rec Endpoint { port: u16; } -# ipv4: create an IPv4 address from four octets. +# create an IPv4 address from four octets # --- # a: first octet # b: second octet @@ -57,17 +57,17 @@ pub fun ipv4(a: u8, b: u8, c: u8, d: u8) IPv4 { ret ip; } -# ipv4_any: return the unspecified IPv4 address (0.0.0.0). +# return the unspecified IPv4 address (0.0.0.0) pub fun ipv4_any() IPv4 { ret ipv4(0, 0, 0, 0); } -# ipv4_loopback: return the IPv4 loopback address (127.0.0.1). +# return the IPv4 loopback address (127.0.0.1) pub fun ipv4_loopback() IPv4 { ret ipv4(127, 0, 0, 1); } -# ipv4_to_u32: convert an IPv4 address to a network byte order u32. +# convert an IPv4 address to a network byte order u32 # --- # ip: the IPv4 address # ret: 32-bit integer in network byte order @@ -78,7 +78,7 @@ pub fun ipv4_to_u32(ip: IPv4) u32 { | ip.octets[3]::u32; } -# ipv4_from_u32: convert a network byte order u32 to an IPv4 address. +# convert a network byte order u32 to an IPv4 address # --- # n: 32-bit integer in network byte order # ret: the constructed IPv4 address @@ -91,7 +91,7 @@ pub fun ipv4_from_u32(n: u32) IPv4 { ret ip; } -# ipv4_format: format an IPv4 address as "a.b.c.d" into a buffer. +# format an IPv4 address as "a.b.c.d" into a buffer # --- # ip: the IPv4 address # buf: destination buffer @@ -115,14 +115,14 @@ pub fun ipv4_format(ip: IPv4, buf: *u8, len: usize) usize { ret off; } -# ipv6_any: return the unspecified IPv6 address (::). +# return the unspecified IPv6 address (::) pub fun ipv6_any() IPv6 { var ip: IPv6; mem.raw_zero(?ip.octets[0], 16); ret ip; } -# ipv6_loopback: return the IPv6 loopback address (::1). +# return the IPv6 loopback address (::1) pub fun ipv6_loopback() IPv6 { var ip: IPv6; mem.raw_zero(?ip.octets[0], 16); @@ -130,7 +130,7 @@ pub fun ipv6_loopback() IPv6 { ret ip; } -# addr_v4: wrap an IPv4 address in an Addr. +# wrap an IPv4 address in an Addr # --- # ip: the IPv4 address # ret: an Addr containing the IPv4 address @@ -141,7 +141,7 @@ pub fun addr_v4(ip: IPv4) Addr { ret a; } -# addr_v6: wrap an IPv6 address in an Addr. +# wrap an IPv6 address in an Addr # --- # ip: the IPv6 address # ret: an Addr containing the IPv6 address @@ -152,7 +152,7 @@ pub fun addr_v6(ip: IPv6) Addr { ret a; } -# endpoint: create an Endpoint from octets and a port. +# create an Endpoint from octets and a port # --- # a: first octet # b: second octet @@ -164,7 +164,7 @@ pub fun endpoint(a: u8, b: u8, c: u8, d: u8, port: u16) Endpoint { ret Endpoint{addr: ipv4(a, b, c, d), port: port}; } -# to_sockaddr: serialize an Endpoint into a sockaddr_in byte buffer. +# serialize an Endpoint into a sockaddr_in byte buffer # --- # ep: the endpoint to serialize # sa: pointer to a buffer of at least os.SOCKADDR_IN_SIZE bytes @@ -172,7 +172,7 @@ pub fun to_sockaddr(ep: Endpoint, sa: *u8) { os.sock_addr_init(sa, ep.port, ?ep.addr.octets[0]); } -# from_sockaddr: deserialize a sockaddr_in byte buffer into an Endpoint. +# deserialize a sockaddr_in byte buffer into an Endpoint # --- # sa: pointer to the sockaddr_in buffer # ep: pointer to the Endpoint to fill diff --git a/src/net/tcp.mach b/src/net/tcp.mach index 55b409d..20ed151 100644 --- a/src/net/tcp.mach +++ b/src/net/tcp.mach @@ -1,4 +1,4 @@ -# TCP socket operations. +# TCP socket operations use std.types.bool.bool; use std.types.size.usize; @@ -11,21 +11,21 @@ use std.types.string.str; use os: std.system.os; use ip: std.net.ip; -# Listener: a bound TCP socket listening for connections. +# a bound TCP socket listening for connections # --- # fd: the underlying socket file descriptor pub rec Listener { fd: i32; } -# Stream: a connected TCP socket for reading and writing. +# a connected TCP socket for reading and writing # --- # fd: the underlying socket file descriptor pub rec Stream { fd: i32; } -# listen: create a TCP listener bound to an endpoint. +# create a TCP listener bound to an endpoint # # creates a socket, sets SO_REUSEADDR, binds to the address and port, # and begins listening with the given backlog. @@ -58,7 +58,7 @@ pub fun listen(ep: ip.Endpoint, backlog: i32) Result[Listener, str] { ret ok[Listener, str](Listener{fd: fd::i32}); } -# accept: accept a new connection on a listener. +# accept a new connection on a listener # --- # ln: the listener to accept on # ret: a connected Stream, or an error message @@ -70,7 +70,7 @@ pub fun accept(ln: *Listener) Result[Stream, str] { ret ok[Stream, str](Stream{fd: fd::i32}); } -# accept_ep: accept a new connection and populate the remote endpoint. +# accept a new connection and populate the remote endpoint # --- # ln: the listener to accept on # ep: pointer to an Endpoint to fill with the remote address @@ -84,7 +84,7 @@ pub fun accept_ep(ln: *Listener, ep: *ip.Endpoint) Result[Stream, str] { ret ok[Stream, str](Stream{fd: fd::i32}); } -# connect: establish a TCP connection to a remote endpoint. +# establish a TCP connection to a remote endpoint # --- # ep: endpoint to connect to # ret: a connected Stream, or an error message @@ -104,7 +104,7 @@ pub fun connect(ep: ip.Endpoint) Result[Stream, str] { ret ok[Stream, str](Stream{fd: fd::i32}); } -# stream_read: read bytes from a TCP stream. +# read bytes from a TCP stream # --- # s: the stream to read from # buf: destination buffer @@ -114,7 +114,7 @@ pub fun stream_read(s: *Stream, buf: *u8, len: usize) i64 { ret os.sock_recv(s.fd, buf, len); } -# stream_write: write bytes to a TCP stream. +# write bytes to a TCP stream # --- # s: the stream to write to # buf: source buffer @@ -124,7 +124,7 @@ pub fun stream_write(s: *Stream, buf: *u8, len: usize) i64 { ret os.sock_send(s.fd, buf, len); } -# stream_shutdown: shut down part or all of a TCP stream. +# shut down part or all of a TCP stream # --- # s: the stream to shut down # how: SHUT_RD (0), SHUT_WR (1), or SHUT_RDWR (2) @@ -132,14 +132,14 @@ pub fun stream_shutdown(s: *Stream, how: i32) i64 { ret os.sock_shutdown(s.fd, how); } -# stream_close: close a TCP stream. +# close a TCP stream # --- # s: the stream to close pub fun stream_close(s: *Stream) { os.sock_close(s.fd); } -# listener_close: close a TCP listener. +# close a TCP listener # --- # ln: the listener to close pub fun listener_close(ln: *Listener) { diff --git a/src/net/udp.mach b/src/net/udp.mach index e2fa8ed..98034fe 100644 --- a/src/net/udp.mach +++ b/src/net/udp.mach @@ -1,4 +1,4 @@ -# UDP socket operations. +# UDP socket operations use std.types.bool.bool; use std.types.size.usize; @@ -11,14 +11,14 @@ use std.types.string.str; use os: std.system.os; use ip: std.net.ip; -# Socket: a bound or unbound UDP socket. +# a bound or unbound UDP socket # --- # fd: the underlying socket file descriptor pub rec Socket { fd: i32; } -# create: create an unbound UDP socket. +# create an unbound UDP socket # --- # ret: the Socket, or an error message pub fun create() Result[Socket, str] { @@ -27,7 +27,7 @@ pub fun create() Result[Socket, str] { ret ok[Socket, str](Socket{fd: fd::i32}); } -# bind: create a UDP socket bound to an endpoint. +# create a UDP socket bound to an endpoint # --- # ep: endpoint to bind to # ret: the bound Socket, or an error message @@ -50,7 +50,7 @@ pub fun bind(ep: ip.Endpoint) Result[Socket, str] { ret ok[Socket, str](Socket{fd: fd::i32}); } -# send_to: send a datagram to a remote endpoint. +# send a datagram to a remote endpoint # --- # s: the socket to send from # buf: source buffer @@ -63,7 +63,7 @@ pub fun send_to(s: *Socket, buf: *u8, len: usize, ep: ip.Endpoint) i64 { ret os.sock_sendto(s.fd, buf, len, 0, ?sa[0], os.SOCKADDR_IN_SIZE); } -# recv_from: receive a datagram and populate the source endpoint. +# receive a datagram and populate the source endpoint # --- # s: the socket to receive on # buf: destination buffer @@ -80,7 +80,7 @@ pub fun recv_from(s: *Socket, buf: *u8, len: usize, ep: *ip.Endpoint) i64 { ret n; } -# socket_close: close a UDP socket. +# close a UDP socket # --- # s: the socket to close pub fun socket_close(s: *Socket) { diff --git a/src/print.mach b/src/print.mach index d7eea2e..e8327a1 100644 --- a/src/print.mach +++ b/src/print.mach @@ -1,4 +1,4 @@ -# formatted output to stdout/stderr. +# formatted output to stdout/stderr # # convenience wrappers around std.format backed by filesystem stdout/stderr. @@ -21,7 +21,7 @@ fun stderr_writer(w: *writer.Writer) { fs.get_writer(?fs.stderr, w); } -# write s to stdout. +# write s to stdout # --- # s: string to write # ret: bytes written, or an error @@ -31,7 +31,7 @@ pub fun print(s: str) Result[usize, str] { ret f.write_str(?w, s); } -# write s followed by a newline to stdout. +# write s followed by a newline to stdout # --- # s: string to write # ret: bytes written, or an error @@ -48,7 +48,7 @@ pub fun println(s: str) Result[usize, str] { ret ok[usize, str](unwrap_ok[usize, str](r1) + unwrap_ok[usize, str](r2)); } -# write s to stderr. +# write s to stderr # --- # s: string to write # ret: bytes written, or an error @@ -58,7 +58,7 @@ pub fun eprint(s: str) Result[usize, str] { ret f.write_str(?w, s); } -# write s followed by a newline to stderr. +# write s followed by a newline to stderr # --- # s: string to write # ret: bytes written, or an error @@ -75,7 +75,7 @@ pub fun eprintln(s: str) Result[usize, str] { ret ok[usize, str](unwrap_ok[usize, str](r1) + unwrap_ok[usize, str](r2)); } -# write unsigned 64-bit integer to stdout. +# write unsigned 64-bit integer to stdout # --- # n: value to write # ret: bytes written, or an error @@ -85,7 +85,7 @@ pub fun u64(n: u64) Result[usize, str] { ret f.write_u64(?w, n); } -# write unsigned 64-bit integer to stderr. +# write unsigned 64-bit integer to stderr # --- # n: value to write # ret: bytes written, or an error @@ -95,7 +95,7 @@ pub fun eu64(n: u64) Result[usize, str] { ret f.write_u64(?w, n); } -# formatted output to stdout. +# formatted output to stdout # --- # fmt: format string (see std.format.vformat for hole syntax) # va: comptime variadic argument pack @@ -106,7 +106,7 @@ pub fun printf(fmt: str, va: ...) Result[usize, str] { ret f.vformat(?w, fmt, va...); } -# formatted output to stderr. +# formatted output to stderr # --- # fmt: format string (see std.format.vformat for hole syntax) # va: comptime variadic argument pack @@ -117,7 +117,7 @@ pub fun eprintf(fmt: str, va: ...) Result[usize, str] { ret f.vformat(?w, fmt, va...); } -# formatted output to stdout followed by a newline. +# formatted output to stdout followed by a newline # --- # fmt: format string (see std.format.vformat for hole syntax) # va: comptime variadic argument pack @@ -135,7 +135,7 @@ pub fun printlnf(fmt: str, va: ...) Result[usize, str] { ret ok[usize, str](unwrap_ok[usize, str](r1) + unwrap_ok[usize, str](r2)); } -# formatted output to stderr followed by a newline. +# formatted output to stderr followed by a newline # --- # fmt: format string (see std.format.vformat for hole syntax) # va: comptime variadic argument pack diff --git a/src/process/env.mach b/src/process/env.mach index 46602d2..4bd85b3 100644 --- a/src/process/env.mach +++ b/src/process/env.mach @@ -1,4 +1,4 @@ -# environment variable access. +# environment variable access use std.types.bool.bool; use std.types.bool.true; @@ -8,7 +8,7 @@ use std.types.string.str; use os: std.system.os; -# get: read an environment variable into a buffer. +# read an environment variable into a buffer # # when the value fits (ret < cap) it is copied and null-terminated. # always returns the full value length, so ret >= cap signals truncation @@ -22,7 +22,7 @@ pub fun get(name: str, buf: *u8, cap: usize) i64 { ret os.getenv(name, buf, cap); } -# cwd: read the current working directory into a buffer. +# read the current working directory into a buffer # --- # buf: destination buffer # cap: buffer capacity in bytes @@ -31,7 +31,7 @@ pub fun cwd(buf: *u8, cap: usize) i64 { ret os.getcwd(buf, cap); } -# environ: the inherited environment as captured by the runtime at +# the inherited environment as captured by the runtime at # program start. # --- # ret: null-terminated array of "NAME=value" strings, or nil if the diff --git a/src/process/exec.mach b/src/process/exec.mach index a0be609..1d87d94 100644 --- a/src/process/exec.mach +++ b/src/process/exec.mach @@ -1,4 +1,4 @@ -# process spawning and management. +# process spawning and management use std.types.bool.bool; use std.types.bool.true; @@ -12,21 +12,21 @@ use std.types.string.str; use os: std.system.os; -# ExitStatus: raw wait status from a terminated process. +# raw wait status from a terminated process # --- # raw: wait status as returned by wait_pid pub rec ExitStatus { raw: i32; } -# Child: handle to a spawned child process. +# handle to a spawned child process # --- # pid: process id of the child pub rec Child { pid: i64; } -# Capture: result of running a child process and collecting its stdout. +# result of running a child process and collecting its stdout # --- # status: exit status of the child process # len: total bytes the child wrote to stdout; a len greater than the @@ -36,7 +36,7 @@ pub rec Capture { len: usize; } -# run: spawn a process and wait for it to exit. +# spawn a process and wait for it to exit # --- # pathname: path to executable # argv: null-terminated argument array @@ -53,7 +53,7 @@ pub fun run(pathname: str, argv: **u8, envp: **u8) Result[ExitStatus, str] { ret ok[ExitStatus, str](ExitStatus{raw: wstatus}); } -# capture: run a process and collect its standard output into a buffer. +# run a process and collect its standard output into a buffer # # spawns the child with its stdout connected to a pipe, drains the pipe # to end-of-file (so a child producing more than buf holds never blocks), @@ -112,7 +112,7 @@ pub fun capture(pathname: str, argv: **u8, envp: **u8, buf: *u8, cap: usize) Res ret ok[Capture, str](Capture{status: ExitStatus{raw: wstatus}, len: total}); } -# spawn: start a process without waiting. +# start a process without waiting # --- # pathname: path to executable # argv: null-terminated argument array @@ -124,7 +124,7 @@ pub fun spawn(pathname: str, argv: **u8, envp: **u8) Result[Child, str] { ret ok[Child, str](Child{pid: pid}); } -# spawn_redirected: start a process without waiting, with its stdout and/or +# start a process without waiting, with its stdout and/or # stderr bound to caller-supplied descriptors. # # the parent keeps ownership of the passed descriptors (close them after the @@ -143,7 +143,7 @@ pub fun spawn_redirected(pathname: str, argv: **u8, envp: **u8, stdout_fd: i32, ret ok[Child, str](Child{pid: pid}); } -# wait: wait for a child process to exit. +# wait for a child process to exit # --- # child: child handle from spawn # ret: exit status, or an error message @@ -154,7 +154,7 @@ pub fun wait(child: Child) Result[ExitStatus, str] { ret ok[ExitStatus, str](ExitStatus{raw: wstatus}); } -# wait_any: block until any child of this process exits. +# block until any child of this process exits # # POSIX wait(-1) semantics on every platform (the windows layer emulates the # -1 pid by waiting across its tracked child handles). the returned handle @@ -171,7 +171,7 @@ pub fun wait_any(out_status: *ExitStatus) Result[Child, str] { ret ok[Child, str](Child{pid: pid}); } -# exited: check if the process exited normally. +# check if the process exited normally # --- # status: exit status to inspect # ret: true if the process called exit @@ -179,7 +179,7 @@ pub fun exited(status: ExitStatus) bool { ret os.has_exited(status.raw); } -# code: get the exit code of a normally exited process. +# get the exit code of a normally exited process # --- # status: exit status to inspect # ret: exit code (0-255), only valid if exited() is true @@ -187,7 +187,7 @@ pub fun code(status: ExitStatus) i32 { ret os.exit_code(status.raw); } -# signaled: check if the process was killed by a signal. +# check if the process was killed by a signal # --- # status: exit status to inspect # ret: true if terminated by signal @@ -195,7 +195,7 @@ pub fun signaled(status: ExitStatus) bool { ret os.was_signaled(status.raw); } -# signal: get the signal number that killed the process. +# get the signal number that killed the process # --- # status: exit status to inspect # ret: signal number @@ -203,7 +203,7 @@ pub fun signal(status: ExitStatus) i32 { ret os.term_signal(status.raw); } -# exit: terminate the current process. +# terminate the current process # --- # code: exit code pub fun exit(code: i64) { @@ -405,7 +405,7 @@ test "exec: repeated spawns stay correct" { var redir_buf: [64]u8; -test "std.process.exec.spawn_redirected:pipes_child_stdout" { +test "exec: spawn_redirected pipes child stdout" { var fds: [2]i32; if (os.pipe(?fds[0]) < 0) { ret 1; } @@ -437,7 +437,7 @@ test "std.process.exec.spawn_redirected:pipes_child_stdout" { ret 0; } -test "std.process.exec.wait_any:reaps_each_child_once" { +test "exec: wait_any reaps each child once" { var argv_a: [4]usize = argv_ok(); val ra: Result[Child, str] = spawn(prog_ok(), (?argv_a[0])::**u8, nil); if (is_err[Child, str](ra)) { ret 1; } @@ -466,7 +466,7 @@ test "std.process.exec.wait_any:reaps_each_child_once" { ret 0; } -test "std.process.exec.wait_any:errs_with_no_children" { +test "exec: wait_any errs with no children" { var st: ExitStatus; st.raw = 0; val w: Result[Child, str] = wait_any(?st); diff --git a/src/rand.mach b/src/rand.mach index 0fc1dd2..c06fbf8 100644 --- a/src/rand.mach +++ b/src/rand.mach @@ -1,11 +1,11 @@ -# pseudorandom number generation (xoshiro256**). +# pseudorandom number generation (xoshiro256**) # # fast, high-quality PRNG suitable for simulations, games, and general # non-cryptographic use. seed from std.crypto.rand for unpredictable output. use std.types.bool.true; use std.types.size.usize; -use cr: std.crypto.rand; +use cr: std.crypto.rand; use bits: std.math.bits; pub rec Rng { @@ -15,7 +15,7 @@ pub rec Rng { s3: u64; } -# create an Rng seeded from the kernel entropy pool. +# create an Rng seeded from the kernel entropy pool # --- # ret: initialized Rng with cryptographic seed pub fun init() Rng { @@ -30,7 +30,7 @@ pub fun init() Rng { ret r; } -# create an Rng with explicit seed values. +# create an Rng with explicit seed values # # at least one value must be non-zero. # --- @@ -51,7 +51,7 @@ pub fun seed(s0: u64, s1: u64, s2: u64, s3: u64) Rng { ret r; } -# generate the next random u64 and advance state. +# generate the next random u64 and advance state # --- # r: pointer to the Rng state # ret: pseudorandom 64-bit value @@ -69,7 +69,7 @@ pub fun next(r: *Rng) u64 { ret result; } -# generate the next random u32 and advance state. +# generate the next random u32 and advance state # --- # r: pointer to the Rng state # ret: pseudorandom 32-bit value @@ -77,7 +77,7 @@ pub fun next_u32(r: *Rng) u32 { ret next(r)::u32; } -# generate a random value in the range [lo, hi). +# generate a random value in the range [lo, hi) # # hi must be greater than lo; otherwise returns lo. # --- @@ -98,7 +98,7 @@ pub fun range(r: *Rng, lo: i64, hi: i64) i64 { ret lo; } -# generate a random value in the unsigned range [lo, hi). +# generate a random value in the unsigned range [lo, hi) # # hi must be greater than lo; otherwise returns lo. # --- @@ -119,7 +119,7 @@ pub fun range_u64(r: *Rng, lo: u64, hi: u64) u64 { ret lo; } -# shuffle an array in place using Fisher-Yates. +# shuffle an array in place using Fisher-Yates # --- # r: pointer to the Rng state # data: pointer to the array diff --git a/src/runtime.mach b/src/runtime.mach index 6a5551a..c4cf211 100644 --- a/src/runtime.mach +++ b/src/runtime.mach @@ -1,4 +1,4 @@ -# std.runtime: program entrypoint contract +# program entrypoint contract # --- # provides the platform/arch-specific `_start` symbol that the linker uses as # the program entrypoint. user code must define a `main` function as follows: diff --git a/src/runtime/darwin.mach b/src/runtime/darwin.mach index 0d996ff..e4c5f48 100644 --- a/src/runtime/darwin.mach +++ b/src/runtime/darwin.mach @@ -1,3 +1,5 @@ +# darwin program entrypoint, dispatched by architecture + $if ($mach.build.os != $mach.os.darwin) { $error("std.runtime.darwin: requires darwin target"); } diff --git a/src/runtime/darwin/aarch64.mach b/src/runtime/darwin/aarch64.mach index 2919c3f..8095465 100644 --- a/src/runtime/darwin/aarch64.mach +++ b/src/runtime/darwin/aarch64.mach @@ -1,4 +1,4 @@ -# std.runtime.darwin.aarch64: aarch64 darwin entrypoint +# aarch64 darwin entrypoint # # provides `_start` (via `start`), the Mach-O entry point for aarch64 darwin executables. # diff --git a/src/runtime/darwin/x86_64.mach b/src/runtime/darwin/x86_64.mach index bc807ee..7c5b2d6 100644 --- a/src/runtime/darwin/x86_64.mach +++ b/src/runtime/darwin/x86_64.mach @@ -1,4 +1,4 @@ -# std.runtime.darwin.x86_64: x86_64 SysV ABI darwin entrypoint +# x86_64 SysV ABI darwin entrypoint # # provides `_start` (via `start`), the Mach-O entry point for x86_64 darwin executables. # diff --git a/src/runtime/linux.mach b/src/runtime/linux.mach index b7882a2..5e41ac0 100644 --- a/src/runtime/linux.mach +++ b/src/runtime/linux.mach @@ -1,3 +1,5 @@ +# linux program entrypoint, dispatched by architecture + $if ($mach.build.arch == $mach.arch.x86_64) { use std.runtime.linux.x86_64; } diff --git a/src/runtime/linux/aarch64.mach b/src/runtime/linux/aarch64.mach index bbc009e..b52ad44 100644 --- a/src/runtime/linux/aarch64.mach +++ b/src/runtime/linux/aarch64.mach @@ -1,9 +1,9 @@ -# std.runtime.linux.aarch64: aarch64 (AAPCS64) linux entrypoint +# aarch64 (AAPCS64) linux entrypoint # --- # provides `_start`, the ELF entry point for aarch64 linux executables. # # on entry, the kernel places the following on the stack (same layout as -# every LP64 linux triple — 8-byte slots): +# every LP64 linux triple, 8-byte slots): # [sp] = argc # [sp+8] = argv[0] # [sp+16] = argv[1] @@ -22,13 +22,13 @@ # #[symbol("main")] # fun main(argc: i64, argv: **u8) i64 { ... } # -# VERIFICATION STATUS — written ahead of the mach aarch64 backend; two +# VERIFICATION STATUS, written ahead of the mach aarch64 backend; two # assumptions cannot be checked until the backend + qemu are available and # MUST be confirmed there (tracked with #270 / briar-systems/mach#1431): # (a) Entry frame: like x86_64 `_start`, the first asm instruction reads the # raw kernel-supplied sp (argc at [sp]). This relies on mach not emitting # a frame-setup prologue that moves sp before the asm block for the entry -# function — the same guarantee the x86_64 entry depends on. +# function, the same guarantee the x86_64 entry depends on. # (b) Symbol references in inline asm: the `adrp ; str/ldr [reg, :lo12:sym]` # data-symbol idiom and `bl ` calls require the arm64 inline-asm # path to lower symbol operands to the page/lo12 + call relocations diff --git a/src/runtime/linux/reloc.mach b/src/runtime/linux/reloc.mach index 75a5823..3d07e84 100644 --- a/src/runtime/linux/reloc.mach +++ b/src/runtime/linux/reloc.mach @@ -1,4 +1,4 @@ -# std.runtime.linux.reloc: static-PIE self-relocation +# static-PIE self-relocation # --- # A no-libc static-PIE (linux ASLR, `mach build --pie`) has no `ld.so`, so it applies # its own ELF RELATIVE relocations before `main`. `_rt_relocate` is called from @@ -39,7 +39,7 @@ use sys: std.system.os.linux.shared; # hardened; panic is reached only post-relocation, so its message pointer is already slid. use std.system.panic.panic; -# read a u64 at a raw runtime address. PIC: pure pointer arithmetic, no global. +# read a u64 at a raw runtime address. PIC: pure pointer arithmetic, no global # --- # addr: the runtime address to read # ret: the 8 bytes at `addr`, little-endian native @@ -48,7 +48,7 @@ fun load64(addr: usize) u64 { ret p[0]; } -# read a u32 at a raw runtime address. PIC: pure pointer arithmetic, no global. +# read a u32 at a raw runtime address. PIC: pure pointer arithmetic, no global # --- # addr: the runtime address to read # ret: the 4 bytes at `addr`, little-endian native @@ -57,7 +57,7 @@ fun load32(addr: usize) u32 { ret p[0]; } -# store a u64 at a raw runtime address. PIC: pure pointer arithmetic, no global. +# store a u64 at a raw runtime address. PIC: pure pointer arithmetic, no global # --- # addr: the runtime address to write # value: the 8 bytes to store diff --git a/src/runtime/linux/riscv64.mach b/src/runtime/linux/riscv64.mach index fd06aa4..9b0e212 100644 --- a/src/runtime/linux/riscv64.mach +++ b/src/runtime/linux/riscv64.mach @@ -1,9 +1,9 @@ -# std.runtime.linux.riscv64: riscv64 (lp64) linux entrypoint +# riscv64 (lp64) linux entrypoint # --- # provides `_start`, the ELF entry point for riscv64 linux executables. # # on entry, the kernel places the following on the stack (same layout as -# every LP64 linux triple — 8-byte slots): +# every LP64 linux triple, 8-byte slots): # [sp] = argc # [sp+8] = argv[0] # [sp+16] = argv[1] diff --git a/src/runtime/linux/x86_64.mach b/src/runtime/linux/x86_64.mach index 0258172..bb62399 100644 --- a/src/runtime/linux/x86_64.mach +++ b/src/runtime/linux/x86_64.mach @@ -1,4 +1,4 @@ -# std.runtime.linux.x86_64: x86_64 SysV ABI linux entrypoint +# x86_64 SysV ABI linux entrypoint # --- # provides `_start`, the ELF entry point for x86_64 linux executables. # diff --git a/src/runtime/windows.mach b/src/runtime/windows.mach index 42395b0..e880374 100644 --- a/src/runtime/windows.mach +++ b/src/runtime/windows.mach @@ -1,3 +1,5 @@ +# windows program entrypoint, dispatched by architecture + $if ($mach.build.os != $mach.os.windows) { $error("std.runtime.windows: requires windows target"); } diff --git a/src/runtime/windows/x86_64.mach b/src/runtime/windows/x86_64.mach index 300a808..60d8c79 100644 --- a/src/runtime/windows/x86_64.mach +++ b/src/runtime/windows/x86_64.mach @@ -1,4 +1,4 @@ -# std.runtime.windows.x86_64: x86_64 Windows entrypoint +# x86_64 Windows entrypoint # # provides `_start` (via `mainCRTStartup`), the PE entry point for x86_64 # Windows executables. @@ -35,7 +35,7 @@ val MAX_CMDLINE: usize = 32768; # the entrypoint references these by literal name from inline asm (`[argc]`, # `[argv_ptrs]`, `call parse_cmdline`), so each carries a `#[symbol]` decorator to -# keep its link name verbatim rather than mangled — mirroring the linux runtime's +# keep its link name verbatim rather than mangled, mirroring the linux runtime's # `_rt_*` symbols. var cmdline_buf: [32768]u8; #[symbol("argv_ptrs")] @@ -63,7 +63,7 @@ pub fun _start() { } } -# split a raw command line string into argc/argv. +# split a raw command line string into argc/argv # # copies the command line into cmdline_buf, splits on whitespace, # handles double-quote grouping (quotes are stripped from the result). diff --git a/src/sync/atomic.mach b/src/sync/atomic.mach index 380b07b..7d93973 100644 --- a/src/sync/atomic.mach +++ b/src/sync/atomic.mach @@ -1,4 +1,4 @@ -# atomic operations for lock-free programming. +# atomic operations for lock-free programming # # all operations have sequential-consistency ordering, implemented with # real per-arch instruction sequences selected at comptime on @@ -19,7 +19,7 @@ use std.types.bool.bool; use std.types.bool.true; use std.types.bool.false; -# atomic 64-bit load with sequential consistency. +# atomic 64-bit load with sequential consistency # --- # ptr: address to load from # ret: loaded value @@ -60,7 +60,7 @@ pub fun load(ptr: *i64) i64 { ret result; } -# atomic 64-bit store with sequential consistency. +# atomic 64-bit store with sequential consistency # --- # ptr: address to store to # v: value to store @@ -97,7 +97,7 @@ pub fun store(ptr: *i64, v: i64) { } } -# atomic compare-and-swap. +# atomic compare-and-swap # if *ptr == *expected, stores desired and returns true. # otherwise, writes actual value to *expected and returns false. # --- @@ -161,7 +161,7 @@ pub fun cas(ptr: *i64, expected: *i64, desired: i64) bool { ret false; } -# atomic fetch-and-add. returns the old value. +# atomic fetch-and-add. returns the old value # --- # ptr: address of the atomic variable # v: value to add @@ -209,7 +209,7 @@ pub fun fetch_add(ptr: *i64, v: i64) i64 { ret old; } -# atomic fetch-and-subtract. returns the old value. +# atomic fetch-and-subtract. returns the old value # --- # ptr: address of the atomic variable # v: value to subtract @@ -259,7 +259,7 @@ pub fun fetch_sub(ptr: *i64, v: i64) i64 { ret old; } -# atomic exchange. returns the old value. +# atomic exchange. returns the old value # --- # ptr: address of the atomic variable # v: new value @@ -306,7 +306,7 @@ pub fun exchange(ptr: *i64, v: i64) i64 { ret old; } -# full memory barrier. +# full memory barrier pub fun fence() { $if ($mach.build.arch == $mach.arch.x86_64) { asm x86_64 { @@ -328,7 +328,7 @@ pub fun fence() { } } -# cpu yield hint for spin loops. +# cpu yield hint for spin loops pub fun spin_hint() { $if ($mach.build.arch == $mach.arch.x86_64) { asm x86_64 { diff --git a/src/sync/mutex.mach b/src/sync/mutex.mach index d6a0954..82170f6 100644 --- a/src/sync/mutex.mach +++ b/src/sync/mutex.mach @@ -1,9 +1,9 @@ -# mutual exclusion lock. +# mutual exclusion lock # # test-and-test-and-set spinlock with exponential backoff using atomic # operations. on contention, spins with CPU pause hints for an # exponentially increasing number of iterations (32 up to 4096) before -# retrying the lock. fully target-agnostic — uses only compiler builtin +# retrying the lock. fully target-agnostic, uses only compiler builtin # atomics. # # values: 0 = unlocked, 1 = locked @@ -14,14 +14,14 @@ use atomic: std.sync.atomic; pub def Mutex: i64; -# create a new unlocked mutex. +# create a new unlocked mutex # --- # ret: an unlocked mutex pub fun make() Mutex { ret 0; } -# acquire the mutex, blocking until it is available. +# acquire the mutex, blocking until it is available # # uses test-and-test-and-set with exponential backoff: reads the state # without a bus lock first, then attempts CAS only when the lock appears @@ -56,14 +56,14 @@ pub fun lock(m: *Mutex) { } } -# release the mutex. +# release the mutex # --- # m: pointer to the mutex pub fun unlock(m: *Mutex) { atomic.store(m, 0); } -# try to acquire the mutex without blocking. +# try to acquire the mutex without blocking # --- # m: pointer to the mutex # ret: true if the lock was acquired, false if already held @@ -72,7 +72,7 @@ pub fun try_lock(m: *Mutex) bool { ret atomic.cas(m, ?expected, 1); } -# check whether the mutex is currently held. +# check whether the mutex is currently held # # the result is immediately stale in a concurrent context; use only # for diagnostics or assertions, never for synchronization decisions. diff --git a/src/sync/thread.mach b/src/sync/thread.mach index 9f5f064..a2510de 100644 --- a/src/sync/thread.mach +++ b/src/sync/thread.mach @@ -1,4 +1,4 @@ -# thread creation and management. +# thread creation and management # # spawns OS-level threads via the OS layer primitives. each thread gets # a dedicated stack allocated via the OS allocator. the thread's @@ -11,11 +11,11 @@ use std.types.bool.bool; use std.types.size.usize; use atomic: std.sync.atomic; -use sys: std.system.os; +use sys: std.system.os; val STACK_SIZE: usize = 2097152; -# handle to a spawned thread. +# handle to a spawned thread # --- # tid: kernel thread id # stack: pointer to the base of the allocated stack region @@ -26,7 +26,7 @@ pub rec Thread { done: i64; } -# spawn a new thread that executes the given function. +# spawn a new thread that executes the given function # # allocates a 2MB stack, then calls the OS thread_spawn primitive which # handles clone and trampoline setup. the child sets the done flag and @@ -35,7 +35,7 @@ pub rec Thread { # the handle is caller-owned and initialized in place: the child writes # the completion flag through ?t.done, so the record must stay at a # stable address for the thread's lifetime (a by-value return would -# hand the child the address of a dead frame — see issue #195). +# hand the child the address of a dead frame, see issue #195). # --- # f: function to execute in the new thread # t: caller-owned handle, initialized by this call; t.tid < 0 on failure @@ -64,7 +64,7 @@ pub fun spawn(f: fun(), t: *Thread) { t.tid = tid; } -# wait for a thread to finish. +# wait for a thread to finish # # blocks on the done flag using OS wait primitives. the thread's stack # is freed by the trampoline before the thread exits. @@ -77,7 +77,7 @@ pub fun join(t: *Thread) { t.stack = 0; } -# check whether a thread has finished executing. +# check whether a thread has finished executing # --- # t: pointer to the thread handle # ret: true if the thread has completed @@ -110,7 +110,7 @@ test "thread: Thread record initializes" { test "thread: spawn and join" { $if ($mach.build.os == $mach.os.windows) { # WaitOnAddress/WakeByAddressSingle are correctly pinned to the synch - # apiset (#253), and wine resolves it (apiset -> kernelbase/ntdll) — but + # apiset (#253), and wine resolves it (apiset -> kernelbase/ntdll), but # mach v1.5.0 omits the import call-thunk for the last PE import # descriptor (mach#1388, the same codegen gap behind the #241 RtlGenRandom # failures), so the wait path dispatches through a null pointer and @@ -128,7 +128,7 @@ test "thread: spawn and join" { test "thread: is_done after join" { $if ($mach.build.os == $mach.os.windows) { - # see "thread: spawn and join" above — the synch-apiset wait path faults + # see "thread: spawn and join" above, the synch-apiset wait path faults # under wine on mach#1388's missing last-descriptor thunk. skip under wine. if (win.running_under_wine()) { ret 0; } } diff --git a/src/system/os.mach b/src/system/os.mach index 524c0ab..a9ba4eb 100644 --- a/src/system/os.mach +++ b/src/system/os.mach @@ -1,4 +1,4 @@ -# std.system.os: cross-platform OS interface. +# cross-platform OS interface # # forwards the portable intersection of all supported targets. # for platform-specific functionality, import the target module @@ -196,12 +196,12 @@ fwd impl.thread_wake; # temp directory -# temp_dir: resolve the directory designated for temporary files. +# resolve the directory designated for temporary files # # follows the env.get truncation contract: ret < cap means the path was # copied and null-terminated; ret >= cap signals truncation and ret is the # full path length. lookup order is per-OS: -# windows: GetTempPathA — TMP, then TEMP, then USERPROFILE, then the +# windows: GetTempPathA, TMP, then TEMP, then USERPROFILE, then the # windows directory; the result ends with a path separator # posix: the $TMPDIR environment variable, falling back to "/tmp" # --- @@ -239,7 +239,7 @@ $if ($mach.build.os != $mach.os.windows) { # time -# realtime: read the wall-clock time. +# read the wall-clock time # --- # out: pointer to Timespec to populate # ret: 0 on success, negative errno on failure @@ -259,7 +259,7 @@ pub fun realtime(out: *Timespec) i64 { # sentinels fwd NOT_FOUND: shared.NOT_FOUND; -# monotonic: read the monotonic clock. +# read the monotonic clock # --- # out: pointer to Timespec to populate # ret: 0 on success, negative errno on failure @@ -284,7 +284,7 @@ pub fun message(code: i64) str { ret impl.error_message(code); } -test "std.system.os.cpu_count:at_least_one" { +test "os: cpu_count at least one" { if (impl.cpu_count() < 1) { ret 1; } ret 0; } diff --git a/src/system/os/darwin.mach b/src/system/os/darwin.mach index d96ab73..424494e 100644 --- a/src/system/os/darwin.mach +++ b/src/system/os/darwin.mach @@ -1,4 +1,4 @@ -# std.system.os.darwin: darwin OS interface with ISA dispatch. +# darwin OS interface with ISA dispatch # # forwards the complete surface from the selected ISA backend. # consumers who need darwin-specific functionality import this module diff --git a/src/system/os/darwin/aarch64.mach b/src/system/os/darwin/aarch64.mach index 3359408..38d038b 100644 --- a/src/system/os/darwin/aarch64.mach +++ b/src/system/os/darwin/aarch64.mach @@ -1,4 +1,4 @@ -# std.system.os.darwin.aarch64: aarch64-specific darwin OS primitives. +# aarch64-specific darwin OS primitives # # provides page_size and pipe which require arch-specific assembly. # everything else is in shared.mach. @@ -19,7 +19,7 @@ pub fun page_size() usize { ret 16384; } -# pipe: create a unidirectional pipe. +# create a unidirectional pipe # # darwin pipe() returns two fds in x0/x1 and signals failure via the # carry flag, neither of which the syscall DSL captures, so this uses raw diff --git a/src/system/os/darwin/shared.mach b/src/system/os/darwin/shared.mach index 4651dc3..9bbfcb7 100644 --- a/src/system/os/darwin/shared.mach +++ b/src/system/os/darwin/shared.mach @@ -1,4 +1,4 @@ -# std.system.os.darwin.shared: code shared across all darwin ISA implementations. +# code shared across all darwin ISA implementations # # contains types, constants, syscall wrappers, and all OS primitives that # are identical across darwin architectures. arch-specific modules provide @@ -104,54 +104,54 @@ val UL_COMPARE_AND_WAIT64: usize = 5; # kernel ABI types -# stat_t: darwin stat64 structure for file metadata. +# darwin stat64 structure for file metadata pub rec stat_t { - st_dev: i32; - st_mode: u16; - st_nlink: u16; - st_ino: u64; - st_uid: u32; - st_gid: u32; - st_rdev: i32; - st_atime: i64; - st_atime_nsec: i64; - st_mtime: i64; - st_mtime_nsec: i64; - st_ctime: i64; - st_ctime_nsec: i64; + st_dev: i32; + st_mode: u16; + st_nlink: u16; + st_ino: u64; + st_uid: u32; + st_gid: u32; + st_rdev: i32; + st_atime: i64; + st_atime_nsec: i64; + st_mtime: i64; + st_mtime_nsec: i64; + st_ctime: i64; + st_ctime_nsec: i64; st_birthtime: i64; st_birthtime_nsec: i64; - st_size: i64; - st_blocks: i64; - st_blksize: i32; - st_flags: u32; - st_gen: u32; - _reserved0: i32; - _reserved1: i64; - _reserved2: i64; + st_size: i64; + st_blocks: i64; + st_blksize: i32; + st_flags: u32; + st_gen: u32; + _reserved0: i32; + _reserved1: i64; + _reserved2: i64; } -# timeval: gettimeofday result. +# gettimeofday result rec timeval { tv_sec: i64; tv_usec: i32; _pad: i32; } -# timespec: time specification with seconds and nanoseconds. +# time specification with seconds and nanoseconds pub rec timespec { tv_sec: i64; tv_nsec: i64; } -# dirent64: directory entry (darwin getdirentries64 layout). +# directory entry (darwin getdirentries64 layout) pub rec dirent64 { - d_ino: u64; + d_ino: u64; d_seekoff: u64; - d_reclen: u16; - d_namlen: u16; - d_type: u8; - d_name: [1024]u8; + d_reclen: u16; + d_namlen: u16; + d_type: u8; + d_name: [1024]u8; } # path @@ -463,7 +463,7 @@ pub fun syscall6(n: usize, a0: usize, a1: usize, a2: usize, a3: usize, a4: usize # process -# terminate: exit the process with the given code. +# exit the process with the given code # --- # code: exit code pub fun terminate(code: i64) { @@ -476,7 +476,7 @@ pub fun terminate(code: i64) { } } -# abort: abort the process immediately with exit code 255. +# abort the process immediately with exit code 255 pub fun abort() { val pid: i64 = syscall0(SYS_GETPID); syscall2(SYS_KILL, pid::usize, SIGABRT::usize); @@ -508,7 +508,7 @@ pub fun deallocate(p: ptr, size: usize) i64 { ret syscall2(SYS_MUNMAP, p::usize, size); } -# darwin has no mremap — allocate new, copy, free old. +# darwin has no mremap, allocate new, copy, free old pub fun reallocate(p: ptr, old_size: usize, new_size: usize) ptr { if (p == nil) { ret allocate(new_size); @@ -534,7 +534,7 @@ pub fun reallocate(p: ptr, old_size: usize, new_size: usize) ptr { ret new_p; } -# darwin has no brk — simulate with mmap reserve + mprotect commit. +# darwin has no brk, simulate with mmap reserve + mprotect commit var _brk_base: usize = 0; var _brk_end: usize = 0; @@ -622,7 +622,7 @@ pub fun sync_file(p: ptr, size: usize) i64 { # environment (set by runtime at program start) pub var _envp: usize = 0; -# environ: pointer to the environment captured by the runtime at program +# pointer to the environment captured by the runtime at program # start (null-terminated array of "NAME=value" strings). nil before # runtime init. pub fun environ() **u8 { @@ -681,7 +681,7 @@ pub fun rename(olddir: i32, oldpath: *u8, newdir: i32, newpath: *u8) i64 { ret syscall4(SYS_RENAMEAT, olddir::isize::usize, oldpath::usize, newdir::isize::usize, newpath::usize); } -# symlink: create a symbolic link at linkpath pointing to target. +# create a symbolic link at linkpath pointing to target # # target is stored verbatim: a relative target stays relative, so the link # keeps resolving correctly after the containing tree is moved. @@ -697,7 +697,7 @@ pub fun make_dir(dirfd: i32, path: *u8, mode: i32) i64 { ret syscall3(SYS_MKDIRAT, dirfd::isize::usize, path::usize, mode::u32::usize); } -# darwin uses getdirentries64 instead of getdents64. +# darwin uses getdirentries64 instead of getdents64 pub fun read_dir(fd: i32, dirp: *dirent64, count: usize) i64 { var basep: i64 = 0; ret syscall4(SYS_GETDIRENTRIES64, fd::isize::usize, dirp::usize, count, (?basep)::usize); @@ -713,7 +713,7 @@ pub fun seek(fd: i32, offset: i64, whence: i32) i64 { # process -# fork: create a child process by duplicating the caller. +# create a child process by duplicating the caller # # the XNU fork trap returns the child PID in the primary register # (rax/x0) for BOTH processes and flags the child via the second return @@ -756,7 +756,7 @@ pub fun fork() i64 { ret out; } -# vfork: create a child process sharing the parent's address space, +# create a child process sharing the parent's address space, # suspending the parent until the child execs or exits. # # the XNU vfork trap uses the same two-register return convention as @@ -829,7 +829,7 @@ fwd os_shared.was_stopped; fwd os_shared.stop_signal; fwd os_shared.was_continued; -# close_inherited_fds: close every file descriptor >= 3 in the caller. +# close every file descriptor >= 3 in the caller # # used by the child between fork and exec to avoid leaking parent FDs # (pipes, sockets, etc.); darwin has no close_range, so it walks up to @@ -853,7 +853,7 @@ fun close_inherited_fds() { } } -# spawn: create a child process running the given program. +# create a child process running the given program # # closes inherited file descriptors >= 3 in the child before exec to # prevent leaking parent FDs (pipes, sockets, etc.) to the child. @@ -866,7 +866,7 @@ pub fun spawn(pathname: *u8, argv: **u8, envp: **u8) i64 { ret spawn_redirected(pathname, argv, envp, -1, -1, -1); } -# spawn_redirected: spawn a child with its standard streams bound to +# spawn a child with its standard streams bound to # caller-supplied descriptors. # # forks, duplicates each non-negative descriptor onto the matching @@ -905,14 +905,14 @@ pub fun spawn_redirected(pathname: *u8, argv: **u8, envp: **u8, stdin_fd: i32, s ret pid; } -# getpid: return the current process ID. +# return the current process ID # --- # ret: process ID pub fun getpid() i64 { ret syscall0(SYS_GETPID); } -# sleep: suspend execution for the given number of nanoseconds. +# suspend execution for the given number of nanoseconds # # darwin has no nanosleep syscall; uses select with a timeval timeout. # --- @@ -931,7 +931,7 @@ pub fun sleep(nsec: i64) { syscall5(SYS_SELECT, 0, 0, 0, 0, (?tv)::usize); } -# cpu_count: the number of CPUs available to this process. +# the number of CPUs available to this process # # reads `hw.ncpu` through the __sysctl syscall (mib [CTL_HW, HW_NCPU]). # never returns less than 1. @@ -949,7 +949,7 @@ pub fun cpu_count() i64 { ret ncpu::i64; } -# getcwd: get the current working directory. +# get the current working directory # --- # buf: destination buffer # size: buffer capacity in bytes @@ -958,7 +958,7 @@ pub fun getcwd(buf: *u8, size: usize) i64 { ret syscall2(SYS___GETCWD, buf::usize, size); } -# getenv: look up an environment variable by name. +# look up an environment variable by name # # when the value fits (ret < cap) it is copied and null-terminated. # always returns the full value length, so ret >= cap signals truncation @@ -995,7 +995,7 @@ pub fun getenv(name: *u8, buf: *u8, cap: usize) i64 { var thread_registered: i64 = 0; -# called by the kernel for each new thread created via bsdthread_create. +# called by the kernel for each new thread created via bsdthread_create fun thread_start(self: usize, kport: usize, func: usize, arg: usize, stacksize: usize, pflags: usize) { val ctx: *usize = arg::*usize; val done_addr: usize = ctx[0]; @@ -1009,7 +1009,7 @@ fun thread_start(self: usize, kport: usize, func: usize, arg: usize, stacksize: syscall4(SYS_BSDTHREAD_TERMINATE, stack_base, stack_size, kport, 0); } -# workqueue thread callback (unused, required by bsdthread_register). +# workqueue thread callback (unused, required by bsdthread_register) fun thread_wq_start(self: usize, kport: usize, saddr: usize, arg: usize, cnt: usize, flags: usize) { syscall4(SYS_BSDTHREAD_TERMINATE, 0, 0, 0, 0); } @@ -1023,7 +1023,7 @@ fun ensure_thread_registered() { syscall6(SYS_BSDTHREAD_REGISTER, start::usize, wq::usize, 64, 0, 0, 0); } -# thread_spawn: create a new thread via bsdthread_create. +# create a new thread via bsdthread_create # # registers the thread start callback on first call, then creates a # thread that calls f. the kernel passes f and done_ptr through to @@ -1045,7 +1045,7 @@ pub fun thread_spawn(f: fun(), done_ptr: *i64, stack_base: usize, stack_size: us ret syscall5(SYS_BSDTHREAD_CREATE, f::usize, ctx::usize, stack_top, 0, 0); } -# thread_wait: block until the value at addr changes from expected. +# block until the value at addr changes from expected # # wraps __ulock_wait with UL_COMPARE_AND_WAIT64. returns immediately # if *addr does not equal expected. spurious wakeups are possible. @@ -1057,7 +1057,7 @@ pub fun thread_wait(addr: *i64, expected: i64) i64 { ret syscall4(SYS_ULOCK_WAIT, UL_COMPARE_AND_WAIT64, addr::usize, expected::usize, 0); } -# thread_wake: wake one thread blocked on a ulock wait at addr. +# wake one thread blocked on a ulock wait at addr # --- # addr: pointer to the futex word # ret: number of threads woken, or negative errno @@ -1151,7 +1151,7 @@ pub fun sock_setopt(fd: i32, level: i32, opt: i32, value: *u8, vallen: usize) i6 pub val DNS_HOSTS_PATH: str = "/etc/hosts"; -# dns_nameserver: read the first nameserver from /etc/resolv.conf. +# read the first nameserver from /etc/resolv.conf # --- # ns: pointer to 4 bytes to fill with the IPv4 address # ret: 0 on success, or NOT_FOUND / negative errno @@ -1223,7 +1223,7 @@ fun dns_parse_ns_addr(buf: *u8, len: usize, addr: *u8) bool { # random -# random_fill: fill a buffer with cryptographic random bytes via getentropy. +# fill a buffer with cryptographic random bytes via getentropy # --- # buf: destination buffer # len: number of bytes to fill @@ -1244,7 +1244,7 @@ pub fun random_fill(buf: *u8, len: usize) i64 { # time -# clock_gettime: read a clock into a timespe# +# read a clock into a timespec # uses the kernel clock_gettime syscall (available since macOS 10.12). # CLOCK_MONOTONIC returns true monotonic time via the kernel's nanouptime. # --- diff --git a/src/system/os/darwin/x86_64.mach b/src/system/os/darwin/x86_64.mach index a12e314..c9c6ca8 100644 --- a/src/system/os/darwin/x86_64.mach +++ b/src/system/os/darwin/x86_64.mach @@ -1,4 +1,4 @@ -# std.system.os.darwin.x86_64: x86_64-specific darwin OS primitives. +# x86_64-specific darwin OS primitives # # provides page_size and pipe which require arch-specific assembly. # everything else is in shared.mach. @@ -19,7 +19,7 @@ pub fun page_size() usize { ret 4096; } -# pipe: create a unidirectional pipe. +# create a unidirectional pipe # # darwin pipe() returns two fds in rax/rdx and signals failure via the # carry flag, neither of which the syscall DSL captures, so this uses raw diff --git a/src/system/os/linux.mach b/src/system/os/linux.mach index cd72746..dba3003 100644 --- a/src/system/os/linux.mach +++ b/src/system/os/linux.mach @@ -1,4 +1,4 @@ -# std.system.os.linux: linux OS interface with ISA dispatch. +# linux OS interface with ISA dispatch # # forwards the complete surface from the selected ISA backend. # consumers who need linux-specific functionality import this module diff --git a/src/system/os/linux/aarch64.mach b/src/system/os/linux/aarch64.mach index d9bcd4d..36649c6 100644 --- a/src/system/os/linux/aarch64.mach +++ b/src/system/os/linux/aarch64.mach @@ -1,4 +1,4 @@ -# std.system.os.linux.aarch64: aarch64-specific linux OS primitives. +# aarch64-specific linux OS primitives # # provides page_size and thread_spawn which require arch-specific assembly. # everything else is in shared.mach. @@ -27,7 +27,7 @@ $if ($mach.build.arch != $mach.arch.aarch64) { $error("std.system.os.linux.aarch64: requires aarch64 target"); } -# page_size: return the system page size. +# return the system page size # # aarch64 linux supports 4 KiB, 16 KiB, and 64 KiB pages depending on kernel # configuration, so it reads the runtime AT_PAGESZ the entrypoint captured @@ -86,7 +86,7 @@ fun thread_trampoline() { asm aarch64 { brk 0 } } -# thread_spawn: create a new thread sharing the current address space. +# create a new thread sharing the current address space # # uses clone with shared VM, FS, files, and signals. the child's stack # carries the function pointer and done_ptr, so no globals are needed. @@ -114,7 +114,7 @@ pub fun thread_spawn(f: fun(), done_ptr: *i64, stack_base: usize, stack_size: us # parent/child discrimination must stay in registers: under CLONE_VM the # child's frame pointer still addresses the parent frame, so a shared stack - # local would race (both sides writing the same slot — see issue #195). a + # local would race (both sides writing the same slot, see issue #195). a # conditional branch can target only a numeric local label on aarch64, not a # symbol (there is no imm19 symbol reloc), so the parent (x0 != 0) skips via # cbnz to local label 1, and the child (x0 == 0) falls through to an diff --git a/src/system/os/linux/riscv64.mach b/src/system/os/linux/riscv64.mach index ee7f730..0fd838b 100644 --- a/src/system/os/linux/riscv64.mach +++ b/src/system/os/linux/riscv64.mach @@ -1,4 +1,4 @@ -# std.system.os.linux.riscv64: riscv64-specific linux OS primitives. +# riscv64-specific linux OS primitives # # provides page_size and thread_spawn which require arch-specific assembly. # everything else is in shared.mach. @@ -27,7 +27,7 @@ $if ($mach.build.arch != $mach.arch.riscv64) { $error("std.system.os.linux.riscv64: requires riscv64 target"); } -# page_size: return the system page size. +# return the system page size # # riscv64 linux uses 4 KiB base pages (Sv39/Sv48/Sv57 all share the 4 KiB leaf), # but it reads the runtime AT_PAGESZ the entrypoint captured @@ -83,7 +83,7 @@ fun thread_trampoline() { asm riscv64 { ebreak } } -# thread_spawn: create a new thread sharing the current address space. +# create a new thread sharing the current address space # # uses clone with shared VM, FS, files, and signals. the child's stack # carries the function pointer and done_ptr, so no globals are needed. @@ -111,7 +111,7 @@ pub fun thread_spawn(f: fun(), done_ptr: *i64, stack_base: usize, stack_size: us # parent/child discrimination must stay in registers: under CLONE_VM the # child's frame pointer still addresses the parent frame, so a shared stack - # local would race (both sides writing the same slot — see issue #195). a + # local would race (both sides writing the same slot, see issue #195). a # conditional branch reaches only a numeric local label on riscv64, not a # symbol, so the parent (a0 != 0) skips via bnez to local label 1, and the # child (a0 == 0) falls through to a `tail` to the trampoline symbol (no diff --git a/src/system/os/linux/shared.mach b/src/system/os/linux/shared.mach index b8fb76c..ad7888b 100644 --- a/src/system/os/linux/shared.mach +++ b/src/system/os/linux/shared.mach @@ -1,4 +1,4 @@ -# std.system.os.linux.shared: code shared across all linux ISA implementations. +# code shared across all linux ISA implementations # # contains types, constants, syscall wrappers, and all OS primitives that # are identical across linux architectures. arch-specific modules provide @@ -19,7 +19,7 @@ $if ($mach.build.os != $mach.os.linux) { # syscall numbers are architecture-specific: x86_64 has its own table, while # aarch64 and riscv64 both use the generic asm-generic/unistd table. those tables -# lack fork/vfork/symlink/dup2 entirely — clone, symlinkat, and dup3 stand in +# lack fork/vfork/symlink/dup2 entirely, clone, symlinkat, and dup3 stand in # (see the fork, vfork, symlink, and spawn_redirected wrappers below). riscv64 also # lacks the legacy renameat, so its table carries renameat2 instead. $if ($mach.build.arch == $mach.arch.x86_64) { @@ -321,13 +321,13 @@ $or ($mach.build.arch == $mach.arch.riscv64) { } } -# timespec: time specification with seconds and nanoseconds. +# time specification with seconds and nanoseconds pub rec timespec { tv_sec: i64; tv_nsec: i64; } -# dirent64: directory entry from getdents64. +# directory entry from getdents64 pub rec dirent64 { d_ino: u64; d_off: i64; @@ -413,7 +413,7 @@ pub val EINTR_MAX_RETRIES: usize = 8; # syscall wrappers -# syscall0: execute a syscall with no arguments. +# execute a syscall with no arguments # --- # n: syscall number # ret: syscall result (negative on error) @@ -443,7 +443,7 @@ pub fun syscall0(n: usize) i64 { ret out; } -# syscall1: execute a syscall with 1 argument. +# execute a syscall with 1 argument # --- # n: syscall number # a0: first argument @@ -477,7 +477,7 @@ pub fun syscall1(n: usize, a0: usize) i64 { ret out; } -# syscall2: execute a syscall with 2 arguments. +# execute a syscall with 2 arguments # --- # n: syscall number # a0: first argument @@ -515,7 +515,7 @@ pub fun syscall2(n: usize, a0: usize, a1: usize) i64 { ret out; } -# syscall3: execute a syscall with 3 arguments. +# execute a syscall with 3 arguments # --- # n: syscall number # a0: first argument @@ -557,7 +557,7 @@ pub fun syscall3(n: usize, a0: usize, a1: usize, a2: usize) i64 { ret out; } -# syscall4: execute a syscall with 4 arguments. +# execute a syscall with 4 arguments # --- # n: syscall number # a0: first argument @@ -603,7 +603,7 @@ pub fun syscall4(n: usize, a0: usize, a1: usize, a2: usize, a3: usize) i64 { ret out; } -# syscall5: execute a syscall with 5 arguments. +# execute a syscall with 5 arguments # --- # n: syscall number # a0: first argument @@ -653,7 +653,7 @@ pub fun syscall5(n: usize, a0: usize, a1: usize, a2: usize, a3: usize, a4: usize ret out; } -# syscall6: execute a syscall with 6 arguments. +# execute a syscall with 6 arguments # --- # n: syscall number # a0: first argument @@ -709,7 +709,7 @@ pub fun syscall6(n: usize, a0: usize, a1: usize, a2: usize, a3: usize, a4: usize # memory -# allocate: allocate anonymous read-write memory via mmap. +# allocate anonymous read-write memory via mmap # --- # size: number of bytes to allocate; if 0, returns nil # ret: pointer to allocated memory, or nil on failure @@ -729,7 +729,7 @@ pub fun allocate(size: usize) ptr { ret res::usize::ptr; } -# deallocate: free memory via munmap. +# free memory via munmap # --- # p: pointer to memory; if nil, returns 0 # size: allocation size in bytes; if 0, returns 0 @@ -741,7 +741,7 @@ pub fun deallocate(p: ptr, size: usize) i64 { ret syscall2(SYS_MUNMAP, p::usize, size); } -# reallocate: resize a memory region via mremap. +# resize a memory region via mremap # --- # p: pointer to memory; if nil, behaves like allocate # old_size: current allocation size in bytes @@ -762,14 +762,14 @@ pub fun reallocate(p: ptr, old_size: usize, new_size: usize) ptr { ret res::usize::ptr; } -# heap_region_base: query the current program break via brk(0). +# query the current program break via brk(0) # --- # ret: current break address pub fun heap_region_base() usize { ret syscall1(SYS_BRK, 0)::usize; } -# heap_region_extend: set the program break to addr via brk. +# set the program break to addr via brk # --- # addr: desired new break address # ret: actual break address after the call @@ -777,7 +777,7 @@ pub fun heap_region_extend(addr: usize) usize { ret syscall1(SYS_BRK, addr)::usize; } -# protect: change protection on a memory region via mprotect. +# change protection on a memory region via mprotect # --- # p: page-aligned pointer to the region # size: size of the region in bytes @@ -787,7 +787,7 @@ pub fun protect(p: ptr, size: usize, prot: u32) i64 { ret syscall3(SYS_MPROTECT, p::usize, size, prot::usize); } -# lock: lock a memory region into physical RAM via mlock. +# lock a memory region into physical RAM via mlock # --- # p: pointer to the region # size: size of the region in bytes @@ -796,7 +796,7 @@ pub fun lock(p: ptr, size: usize) i64 { ret syscall2(SYS_MLOCK, p::usize, size); } -# unlock: unlock a previously locked memory region via munlock. +# unlock a previously locked memory region via munlock # --- # p: pointer to the region # size: size of the region in bytes @@ -805,7 +805,7 @@ pub fun unlock(p: ptr, size: usize) i64 { ret syscall2(SYS_MUNLOCK, p::usize, size); } -# advise: advise the kernel on expected access patterns via madvise. +# advise the kernel on expected access patterns via madvise # --- # p: pointer to the region # size: size of the region in bytes @@ -825,7 +825,7 @@ fun log2_usize(v: usize) usize { ret n; } -# allocate_huge: allocate memory backed by huge pages via mmap. +# allocate memory backed by huge pages via mmap # --- # size: number of bytes; if 0, returns nil # page_size: huge page size in bytes (must be power of two) @@ -848,7 +848,7 @@ pub fun allocate_huge(size: usize, page_size: usize) ptr { ret res::usize::ptr; } -# numa_node_count: return the number of NUMA nodes via get_mempolicy. +# return the number of NUMA nodes via get_mempolicy # --- # ret: number of NUMA nodes (at least 1) pub fun numa_node_count() usize { @@ -866,7 +866,7 @@ pub fun numa_node_count() usize { ret count; } -# numa_current_node: return the NUMA node of the current CPU via getcpu. +# return the NUMA node of the current CPU via getcpu # --- # ret: NUMA node id (0 on failure) pub fun numa_current_node() usize { @@ -878,7 +878,7 @@ pub fun numa_current_node() usize { ret node::usize; } -# numa_allocate: allocate memory pinned to a specific NUMA node. +# allocate memory pinned to a specific NUMA node # --- # size: number of bytes; if 0, returns nil # node: target NUMA node id @@ -900,7 +900,7 @@ pub fun numa_allocate(size: usize, node: usize) ptr { ret p; } -# numa_move: move a memory region to a different NUMA node via mbind. +# move a memory region to a different NUMA node via mbind # --- # p: pointer to the region # size: size of the region in bytes @@ -917,7 +917,7 @@ pub fun numa_move(p: ptr, size: usize, node: usize) i64 { ret syscall6(SYS_MBIND, p::usize, size, MPOL_BIND, (?mask)::usize, 64, MPOL_MF_MOVE); } -# map_file: map a file descriptor into memory via mmap. +# map a file descriptor into memory via mmap # --- # fd: file descriptor to map # offset: offset into the file (must be page-aligned) @@ -939,7 +939,7 @@ pub fun map_file(fd: i32, offset: usize, size: usize, prot: u32) ptr { ret res::usize::ptr; } -# sync_file: flush a memory-mapped region to its backing file via msync. +# flush a memory-mapped region to its backing file via msync # --- # p: pointer to the mapped region # size: size of the region in bytes @@ -953,7 +953,7 @@ pub fun sync_file(p: ptr, size: usize) i64 { # feature detection -# has_numa: check if the kernel supports NUMA memory policy. +# check if the kernel supports NUMA memory policy # --- # ret: true if get_mempolicy syscall is available pub fun has_numa() bool { @@ -962,7 +962,7 @@ pub fun has_numa() bool { ret res != ENOSYS; } -# has_huge_pages: check if the kernel supports huge page allocation. +# check if the kernel supports huge page allocation # --- # ret: true if MAP_HUGETLB mmap succeeds pub fun has_huge_pages() bool { @@ -981,7 +981,7 @@ pub fun has_huge_pages() bool { # filesystem -# read: read bytes from a file descriptor. +# read bytes from a file descriptor # # retries automatically on EINTR. # --- @@ -999,7 +999,7 @@ pub fun read(fd: i32, buf: *u8, count: usize) i64 { ret EINTR; } -# write: write bytes to a file descriptor. +# write bytes to a file descriptor # # retries automatically on EINTR. # --- @@ -1017,7 +1017,7 @@ pub fun write(fd: i32, buf: *u8, count: usize) i64 { ret EINTR; } -# openat: open a file relative to a directory file descriptor. +# openat: open a file relative to a directory file descriptor # # retries automatically on EINTR. # --- @@ -1036,7 +1036,7 @@ pub fun open(dirfd: i32, path: *u8, flags: i32, mode: i32) i64 { ret EINTR; } -# close: close a file descriptor. +# close a file descriptor # --- # fd: file descriptor # ret: 0 on success, or negative errno @@ -1044,7 +1044,7 @@ pub fun close(fd: i32) i64 { ret syscall1(SYS_CLOSE, fd::isize::usize); } -# fstat: get file status by file descriptor. +# fstat: get file status by file descriptor # --- # fd: file descriptor # st: pointer to stat_t to fill @@ -1053,7 +1053,7 @@ pub fun stat(fd: i32, st: *stat_t) i64 { ret syscall2(SYS_FSTAT, fd::isize::usize, st::usize); } -# newfstatat: get file status relative to a directory fd. +# newfstatat: get file status relative to a directory fd # --- # dirfd: directory fd (or AT_FDCWD) # path: null-terminated path @@ -1064,7 +1064,7 @@ pub fun stat_path(dirfd: i32, path: *u8, st: *stat_t, flags: i32) i64 { ret syscall4(SYS_NEWFSTATAT, dirfd::isize::usize, path::usize, st::usize, flags::u32::usize); } -# unlinkat: remove a file or directory relative to a directory fd. +# unlinkat: remove a file or directory relative to a directory fd # --- # dirfd: directory fd (or AT_FDCWD) # path: null-terminated path @@ -1074,7 +1074,7 @@ pub fun unlink(dirfd: i32, path: *u8, flags: i32) i64 { ret syscall3(SYS_UNLINKAT, dirfd::isize::usize, path::usize, flags::u32::usize); } -# renameat: rename a file relative to directory fds. +# renameat: rename a file relative to directory fds # --- # olddir: source directory fd # oldpath: source path @@ -1091,7 +1091,7 @@ pub fun rename(olddir: i32, oldpath: *u8, newdir: i32, newpath: *u8) i64 { } } -# symlink: create a symbolic link at linkpath pointing to target. +# create a symbolic link at linkpath pointing to target # # target is stored verbatim: a relative target stays relative, so the link # keeps resolving correctly after the containing tree is moved. @@ -1113,7 +1113,7 @@ pub fun symlink(target: *u8, linkpath: *u8) i64 { } } -# mkdirat: create a directory relative to a directory fd. +# mkdirat: create a directory relative to a directory fd # --- # dirfd: directory fd (or AT_FDCWD) # path: null-terminated path @@ -1123,7 +1123,7 @@ pub fun make_dir(dirfd: i32, path: *u8, mode: i32) i64 { ret syscall3(SYS_MKDIRAT, dirfd::isize::usize, path::usize, mode::u32::usize); } -# getdents64: read directory entries. +# getdents64: read directory entries # --- # fd: directory fd # dirp: pointer to dirent64 buffer @@ -1133,7 +1133,7 @@ pub fun read_dir(fd: i32, dirp: *dirent64, count: usize) i64 { ret syscall3(SYS_GETDENTS64, fd::isize::usize, dirp::usize, count); } -# faccessat: check file accessibility relative to a directory fd. +# faccessat: check file accessibility relative to a directory fd # --- # dirfd: directory fd (or AT_FDCWD) # path: null-terminated path @@ -1144,7 +1144,7 @@ pub fun access(dirfd: i32, path: *u8, mode: i32, flags: i32) i64 { ret syscall4(SYS_FACCESSAT, dirfd::isize::usize, path::usize, mode::u32::usize, flags::u32::usize); } -# lseek: reposition read/write offset of a file descriptor. +# lseek: reposition read/write offset of a file descriptor # --- # fd: file descriptor # offset: byte offset @@ -1157,25 +1157,25 @@ pub fun seek(fd: i32, offset: i64, whence: i32) i64 { # environment (set by runtime at program start) pub var _envp: usize = 0; -# environ: pointer to the environment captured by the runtime at program +# pointer to the environment captured by the runtime at program # start (null-terminated array of "NAME=value" strings). nil before # runtime init. pub fun environ() **u8 { ret _envp::**u8; } -# _pagesz: the runtime page size in bytes, read from the auxiliary vector +# the runtime page size in bytes, read from the auxiliary vector # (AT_PAGESZ) at program start. 0 until the runtime publishes it; AT_PAGESZ is # mandatory on linux, so a 0 still seen at a page_size() call means the auxv # lacked it (broken/nonstandard environment) or a caller ran before _rt_init -# published — page_size() panics on either rather than fabricating a value. this +# published, page_size() panics on either rather than fabricating a value. this # is the single consumer-facing page-size source (briar-systems/mach-std#336): # std.runtime.linux.reloc keeps its own private pre-relocation read of AT_PAGESZ # for the RELRO mprotect (it runs before any global is safe to touch), but every # page_size() caller reads this global. pub var _pagesz: usize = 0; -# pagesz_from_auxv: read AT_PAGESZ from the auxiliary vector reachable from envp. +# read AT_PAGESZ from the auxiliary vector reachable from envp # # the auxv (type/value u64 pairs, AT_NULL-terminated) sits immediately past the # NULL terminator of the null-terminated pointer array `envp` addresses. walks @@ -1196,7 +1196,7 @@ fun pagesz_from_auxv(envp: *u64) usize { ret 0; } -# capture_pagesz: publish the auxv page size into `_pagesz`. +# publish the auxv page size into `_pagesz` # # called once by the entrypoint at startup, after `_envp` is set and (in a --pie # build) after `_rt_relocate` has applied the relocations, so it runs as ordinary @@ -1210,7 +1210,7 @@ pub fun capture_pagesz() { # process -# terminate: exit the process with the given code. +# exit the process with the given code # # uses exit_group so all threads in the process are terminated; plain # exit would only end the calling thread, leaving the process alive. @@ -1230,12 +1230,12 @@ pub fun terminate(code: i64) { } } -# abort: abort the process immediately with exit code 255. +# abort the process immediately with exit code 255 pub fun abort() { terminate(255); } -# fork: create a new child process. +# create a new child process # --- # ret: in parent: child PID (>0), in child: 0, on error: negative errno pub fun fork() i64 { @@ -1254,7 +1254,7 @@ pub fun fork() i64 { } } -# vfork: create child process sharing memory with parent. +# create child process sharing memory with parent # --- # ret: in parent: child PID (>0), in child: 0, on error: negative errno pub fun vfork() i64 { @@ -1277,7 +1277,7 @@ pub fun vfork() i64 { } } -# execve: replace the current process image with a new program. +# execve: replace the current process image with a new program # --- # pathname: path to executable # argv: null-terminated argument array @@ -1287,7 +1287,7 @@ pub fun exec(pathname: *u8, argv: **u8, envp: **u8) i64 { ret syscall3(SYS_EXECVE, pathname::usize, argv::usize, envp::usize); } -# wait4: wait for a child process to change state. +# wait4: wait for a child process to change state # # retries automatically on EINTR. # --- @@ -1306,7 +1306,7 @@ pub fun wait(pid: i64, wstatus: *i32, options: i32, rusage: *u8) i64 { ret EINTR; } -# waitpid: wait for a specific child process. +# waitpid: wait for a specific child process # --- # pid: process ID (-1 = any child) # wstatus: pointer to status (can be nil) @@ -1325,7 +1325,7 @@ fwd os_shared.was_stopped; fwd os_shared.stop_signal; fwd os_shared.was_continued; -# close_inherited_fds: close every file descriptor >= 3 in the caller. +# close every file descriptor >= 3 in the caller # # used by the child between fork and exec to avoid leaking parent FDs # (pipes, sockets, etc.); falls back to a bounded loop when close_range @@ -1348,7 +1348,7 @@ val SPAWN_STACK_SIZE: usize = 16384; # clone flags for the spawn fast path: CLONE_VM shares the address space (no # COW, so the kernel never runs fork's overcommit commit-accounting and spawn -# cannot ENOMEM on a swapless vm.overcommit_memory=0 host — issue mach#1487), +# cannot ENOMEM on a swapless vm.overcommit_memory=0 host, issue mach#1487), # CLONE_VFORK suspends the parent until the child execs or exits, and SIGCHLD # makes the child a normal waitable process. val SPAWN_CLONE_FLAGS: usize = CLONE_VM | CLONE_VFORK | SIGCHLD; @@ -1367,10 +1367,10 @@ $or ($mach.build.arch == $mach.arch.riscv64) { val SPAWN_SP_BIAS: usize = 16; } -# spawn_ctx: arguments carried across the clone boundary to the trampoline. +# arguments carried across the clone boundary to the trampoline # lives in the parent's frame; CLONE_VFORK keeps the parent suspended (and this # struct alive and stable) until the child execs or exits. -rec spawn_ctx { +rec SpawnCtx { pathname: *u8; argv: **u8; envp: **u8; @@ -1379,12 +1379,12 @@ rec spawn_ctx { stderr_fd: i32; } -# spawn_trampoline: child-side entry, reached by a direct jump/branch from the +# child-side entry, reached by a direct jump/branch from the # child half of clone (see spawn_redirected) so it runs on the private child # stack and never touches the parent's frame. at entry sp points at the # ctx-pointer slot; after the standard prologue it sits at [rbp+8] (x86_64) / # [x29+16] (aarch64), matching thread_trampoline. the child only redirects fds, -# closes inherited fds, and execs — all stack-safe under CLONE_VM — and never +# closes inherited fds, and execs, all stack-safe under CLONE_VM, and never # returns: a successful exec replaces the image, any failure exits the child # (126 on a failed redirect, 127 on a failed exec). #[symbol("_std_spawn_trampoline")] @@ -1409,7 +1409,7 @@ fun spawn_trampoline() { sd a0, {ctx_addr} } } - val ctx: *spawn_ctx = ctx_addr::*spawn_ctx; + val ctx: *SpawnCtx = ctx_addr::*SpawnCtx; # aarch64 has no dup2 syscall; dup3 with flags 0 is equivalent (it differs # only in rejecting oldfd == newfd, which redirect fds never are). @@ -1464,7 +1464,7 @@ fun spawn_trampoline() { } } -# spawn: create a child process running the given program. +# create a child process running the given program # # closes inherited file descriptors >= 3 in the child before exec to # prevent leaking parent FDs (pipes, sockets, etc.) to the child. @@ -1477,7 +1477,7 @@ pub fun spawn(pathname: *u8, argv: **u8, envp: **u8) i64 { ret spawn_redirected(pathname, argv, envp, -1, -1, -1); } -# spawn_redirected: spawn a child with its standard streams bound to +# spawn a child with its standard streams bound to # caller-supplied descriptors. # # forks, duplicates each non-negative descriptor onto the matching @@ -1495,7 +1495,7 @@ pub fun spawn(pathname: *u8, argv: **u8, envp: **u8) i64 { # stderr_fd: descriptor to install as the child's stderr, or -1 to inherit # ret: child PID on success, or negative errno pub fun spawn_redirected(pathname: *u8, argv: **u8, envp: **u8, stdin_fd: i32, stdout_fd: i32, stderr_fd: i32) i64 { - var ctx: spawn_ctx; + var ctx: SpawnCtx; ctx.pathname = pathname; ctx.argv = argv; ctx.envp = envp; @@ -1576,14 +1576,14 @@ pub fun spawn_redirected(pathname: *u8, argv: **u8, envp: **u8, stdin_fd: i32, s ret result; } -# getpid: return the current process ID. +# return the current process ID # --- # ret: process ID pub fun getpid() i64 { ret syscall0(SYS_GETPID); } -# pipe: create a unidirectional pipe. +# create a unidirectional pipe # --- # fds: pointer to two i32s; fds[0] = read end, fds[1] = write end # ret: 0 on success, or negative errno @@ -1591,7 +1591,7 @@ pub fun pipe(fds: *i32) i64 { ret syscall2(SYS_PIPE2, fds::usize, 0); } -# sleep: suspend execution for the given number of nanoseconds. +# suspend execution for the given number of nanoseconds # --- # nsec: nanoseconds to sleep pub fun sleep(nsec: i64) { @@ -1602,7 +1602,7 @@ pub fun sleep(nsec: i64) { syscall2(SYS_NANOSLEEP, (?req)::usize, 0); } -# cpu_count: the number of CPUs available to this process. +# the number of CPUs available to this process # # popcounts the sched_getaffinity mask, so taskset/cgroup cpuset restrictions # are honoured; the kernel reports the mask size it wrote in the return value. @@ -1632,7 +1632,7 @@ pub fun cpu_count() i64 { ret n; } -# getcwd: get the current working directory. +# get the current working directory # --- # buf: destination buffer # size: buffer capacity in bytes @@ -1641,7 +1641,7 @@ pub fun getcwd(buf: *u8, size: usize) i64 { ret syscall2(SYS_GETCWD, buf::usize, size); } -# getenv: look up an environment variable by name. +# look up an environment variable by name # # when the value fits (ret < cap) it is copied and null-terminated. # always returns the full value length, so ret >= cap signals truncation @@ -1676,7 +1676,7 @@ pub fun getenv(name: *u8, buf: *u8, cap: usize) i64 { # threads -# thread_wait: block until the value at addr changes from expected. +# block until the value at addr changes from expected # # wraps the futex FUTEX_WAIT operation. returns immediately if *addr # does not equal expected. spurious wakeups are possible. @@ -1688,7 +1688,7 @@ pub fun thread_wait(addr: *i64, expected: i64) i64 { ret syscall6(SYS_FUTEX, addr::usize, FUTEX_WAIT, expected::usize, 0, 0, 0); } -# thread_wake: wake one thread blocked on a futex wait at addr. +# wake one thread blocked on a futex wait at addr # --- # addr: pointer to the futex word # ret: number of threads woken, or negative errno @@ -1709,7 +1709,7 @@ pub val SHUT_RDWR: i32 = 2; pub val SOCKADDR_IN_SIZE: usize = 16; -# sock_addr_init: fill a sockaddr_in buffer with the given port and IPv4 address. +# fill a sockaddr_in buffer with the given port and IPv4 address # --- # sa: pointer to a buffer of at least SOCKADDR_IN_SIZE bytes # port: port in host byte order @@ -1727,7 +1727,7 @@ pub fun sock_addr_init(sa: *u8, port: u16, addr: *u8) { sa[7] = addr[3]; } -# sock_addr_read: read port and IPv4 address from a sockaddr_in buffer. +# read port and IPv4 address from a sockaddr_in buffer # --- # sa: pointer to the sockaddr_in buffer # port: pointer to store port in host byte order @@ -1740,7 +1740,7 @@ pub fun sock_addr_read(sa: *u8, port: *u16, addr: *u8) { addr[3] = sa[7]; } -# sock_send: send data on a connected socket. +# send data on a connected socket # --- # fd: socket fd # buf: source buffer @@ -1750,7 +1750,7 @@ pub fun sock_send(fd: i32, buf: *u8, len: usize) i64 { ret write(fd, buf, len); } -# sock_recv: receive data from a connected socket. +# receive data from a connected socket # --- # fd: socket fd # buf: destination buffer @@ -1760,7 +1760,7 @@ pub fun sock_recv(fd: i32, buf: *u8, len: usize) i64 { ret read(fd, buf, len); } -# sock_close: close a socket file descriptor. +# close a socket file descriptor # --- # fd: socket fd # ret: 0 on success, or negative errno @@ -1768,7 +1768,7 @@ pub fun sock_close(fd: i32) i64 { ret close(fd); } -# sock_create: create a socket file descriptor. +# create a socket file descriptor # --- # domain: address family (AF_INET) # typ: socket type (SOCK_STREAM, SOCK_DGRAM) @@ -1778,7 +1778,7 @@ pub fun sock_create(domain: i32, typ: i32, protocol: i32) i64 { ret syscall3(SYS_SOCKET, domain::u32::usize, typ::u32::usize, protocol::u32::usize); } -# sock_bind: bind a socket to an address. +# bind a socket to an address # --- # fd: socket fd # addr: pointer to sockaddr structure @@ -1788,7 +1788,7 @@ pub fun sock_bind(fd: i32, addr: *u8, addrlen: usize) i64 { ret syscall3(SYS_BIND, fd::isize::usize, addr::usize, addrlen); } -# sock_listen: mark a socket as a passive listener. +# mark a socket as a passive listener # --- # fd: socket fd # backlog: maximum pending connection queue length @@ -1797,7 +1797,7 @@ pub fun sock_listen(fd: i32, backlog: i32) i64 { ret syscall2(SYS_LISTEN, fd::isize::usize, backlog::u32::usize); } -# sock_accept: accept a connection on a listening socket. +# accept a connection on a listening socket # --- # fd: socket fd # addr: pointer to sockaddr to fill with peer address @@ -1807,7 +1807,7 @@ pub fun sock_accept(fd: i32, addr: *u8, addrlen: *u32) i64 { ret syscall3(SYS_ACCEPT, fd::isize::usize, addr::usize, addrlen::usize); } -# sock_connect: connect a socket to a remote address. +# connect a socket to a remote address # --- # fd: socket fd # addr: pointer to sockaddr structure @@ -1817,7 +1817,7 @@ pub fun sock_connect(fd: i32, addr: *u8, addrlen: usize) i64 { ret syscall3(SYS_CONNECT, fd::isize::usize, addr::usize, addrlen); } -# sock_sendto: send data to a specific address. +# send data to a specific address # --- # fd: socket fd # buf: source buffer @@ -1830,7 +1830,7 @@ pub fun sock_sendto(fd: i32, buf: *u8, len: usize, flags: i32, addr: *u8, addrle ret syscall6(SYS_SENDTO, fd::isize::usize, buf::usize, len, flags::u32::usize, addr::usize, addrlen); } -# sock_recvfrom: receive data and source address. +# receive data and source address # --- # fd: socket fd # buf: destination buffer @@ -1843,7 +1843,7 @@ pub fun sock_recvfrom(fd: i32, buf: *u8, len: usize, flags: i32, addr: *u8, addr ret syscall6(SYS_RECVFROM, fd::isize::usize, buf::usize, len, flags::u32::usize, addr::usize, addrlen::usize); } -# sock_shutdown: shut down part or all of a socket connection. +# shut down part or all of a socket connection # --- # fd: socket fd # how: SHUT_RD (0), SHUT_WR (1), or SHUT_RDWR (2) @@ -1852,7 +1852,7 @@ pub fun sock_shutdown(fd: i32, how: i32) i64 { ret syscall2(SYS_SHUTDOWN, fd::isize::usize, how::u32::usize); } -# sock_setopt: set a socket option. +# set a socket option # --- # fd: socket fd # level: option level (SOL_SOCKET, etc.) @@ -1868,7 +1868,7 @@ pub fun sock_setopt(fd: i32, level: i32, opt: i32, value: *u8, vallen: usize) i6 pub val DNS_HOSTS_PATH: str = "/etc/hosts"; -# dns_nameserver: read the first nameserver from /etc/resolv.conf. +# read the first nameserver from /etc/resolv.conf # --- # ns: pointer to 4 bytes to fill with the IPv4 address # ret: 0 on success, or NOT_FOUND / negative errno @@ -1940,7 +1940,7 @@ fun dns_parse_ns_addr(buf: *u8, len: usize, addr: *u8) bool { # random -# random_fill: fill a buffer with cryptographic random bytes via getrandom. +# fill a buffer with cryptographic random bytes via getrandom # --- # buf: destination buffer # len: number of bytes to fill @@ -1960,7 +1960,7 @@ pub fun random_fill(buf: *u8, len: usize) i64 { # time -# clock_gettime: get time from a clock source. +# get time from a clock source # --- # clock_id: clock to query (CLOCK_REALTIME, CLOCK_MONOTONIC) # ts: pointer to timespec to fill @@ -1971,7 +1971,7 @@ pub fun clock_gettime(clock_id: i32, ts: *timespec) i64 { # errno -# error_message: return a human-readable message for a negated errno code. +# return a human-readable message for a negated errno code # --- # code: negated errno value (e.g., -2 for ENOENT) # ret: descriptive error message string diff --git a/src/system/os/linux/x86_64.mach b/src/system/os/linux/x86_64.mach index 1c003ae..d1df4bd 100644 --- a/src/system/os/linux/x86_64.mach +++ b/src/system/os/linux/x86_64.mach @@ -1,4 +1,4 @@ -# std.system.os.linux.x86_64: x86_64-specific linux OS primitives. +# x86_64-specific linux OS primitives # # provides page_size and thread_spawn which require arch-specific assembly. # everything else is in shared.mach. @@ -27,7 +27,7 @@ $if ($mach.build.arch != $mach.arch.x86_64) { $error("std.system.os.linux.x86_64: requires x86_64 target"); } -# page_size: return the system page size. +# return the system page size # # x86_64 linux always presents a 4 KiB base page, but it reads the runtime # AT_PAGESZ the entrypoint captured (shared.capture_pagesz) for one page-size @@ -83,7 +83,7 @@ fun thread_trampoline() { asm x86_64 { hlt } } -# thread_spawn: create a new thread sharing the current address space. +# create a new thread sharing the current address space # # uses clone with shared VM, FS, files, and signals. the child's stack # carries the function pointer and done_ptr, so no globals are needed. @@ -109,7 +109,7 @@ pub fun thread_spawn(f: fun(), done_ptr: *i64, stack_base: usize, stack_size: us # parent/child discrimination must stay in registers: under CLONE_VM the # child's rbp still addresses the parent frame, so a shared stack local - # would race (both sides writing the same slot — see issue #195). the + # would race (both sides writing the same slot, see issue #195). the # child jumps straight to the trampoline off its own stack; the parent # falls through and stores the tid. asm x86_64 { mfence } diff --git a/src/system/os/shared.mach b/src/system/os/shared.mach index b10fa73..d1238ef 100644 --- a/src/system/os/shared.mach +++ b/src/system/os/shared.mach @@ -1,11 +1,11 @@ -# std.system.os.shared: abstract types and constants for the OS interface. +# abstract types and constants for the OS interface # # types here are target-independent. every OS implementation populates them. use std.types.size.usize; use std.types.bool.bool; -# Timespec: seconds and nanoseconds from a clock source. +# seconds and nanoseconds from a clock source # --- # sec: whole seconds # nsec: nanoseconds within second [0, 999999999] diff --git a/src/system/os/windows.mach b/src/system/os/windows.mach index 1f9941e..1eef019 100644 --- a/src/system/os/windows.mach +++ b/src/system/os/windows.mach @@ -1,4 +1,4 @@ -# std.system.os.windows: windows OS interface with ISA dispatch. +# windows OS interface with ISA dispatch # # forwards the complete surface from the selected ISA backend. # consumers who need windows-specific functionality import this module diff --git a/src/system/os/windows/shared.mach b/src/system/os/windows/shared.mach index d607267..8d66511 100644 --- a/src/system/os/windows/shared.mach +++ b/src/system/os/windows/shared.mach @@ -1,4 +1,4 @@ -# std.system.os.windows.shared: code shared across all windows ISA implementations. +# code shared across all windows ISA implementations # # windows has no stable syscall interface. all OS interaction goes through # kernel32.dll and ntdll.dll via ext fun declarations, plus ws2_32.dll for @@ -248,7 +248,7 @@ ext fun FindNextFileA(p0: isize, p1: *u8) i32; ext fun FindClose(p0: isize) i32; #[library("kernel32.dll")] ext fun GetFinalPathNameByHandleA(p0: isize, p1: *u8, p2: u32, p3: u32) u32; -# CreateSymbolicLinkA returns a BOOLEAN — a single byte. +# CreateSymbolicLinkA returns a BOOLEAN, a single byte #[library("kernel32.dll")] ext fun CreateSymbolicLinkA(p0: *u8, p1: *u8, p2: u32) u8; @@ -262,7 +262,7 @@ ext fun QueryPerformanceFrequency(p0: *i64) i32; #[library("kernel32.dll")] ext fun CreateThread(p0: ptr, p1: usize, p2: usize, p3: ptr, p4: u32, p5: *u32) isize; -# WaitOnAddress / WakeByAddressSingle live in the synch apiset DLL, not kernel32. +# WaitOnAddress / WakeByAddressSingle live in the synch apiset DLL, not kernel32 # real windows' kernel32 does not export them (only wine's does), so without # the `#[library]` decorator the import binds to kernel32 and the native loader # rejects the exe with STATUS_ENTRYPOINT_NOT_FOUND. pin them to the canonical @@ -367,15 +367,15 @@ rec BY_HANDLE_FILE_INFORMATION { } rec WIN32_FIND_DATAA { - dwFileAttributes: u32; - ftCreationTime: FILETIME; - ftLastAccessTime: FILETIME; - ftLastWriteTime: FILETIME; - nFileSizeHigh: u32; - nFileSizeLow: u32; - dwReserved0: u32; - dwReserved1: u32; - cFileName: [260]u8; + dwFileAttributes: u32; + ftCreationTime: FILETIME; + ftLastAccessTime: FILETIME; + ftLastWriteTime: FILETIME; + nFileSizeHigh: u32; + nFileSizeLow: u32; + dwReserved0: u32; + dwReserved1: u32; + cFileName: [260]u8; cAlternateFileName: [14]u8; } @@ -591,7 +591,7 @@ fun free_fd(fd: i32) { fd_spin_unlock(); } -# child process tracking table. +# child process tracking table # # fixed-size, like the fd table above. the bound is pinned by # WaitForMultipleObjects' MAXIMUM_WAIT_OBJECTS (64): the wait-any path @@ -610,7 +610,7 @@ var _proc_lock: i64 = 0; # lookup/scan ignores it until it holds a real handle. val PROC_RESERVED: isize = -2; -# whether a slot holds a real child handle (neither free nor reserved). +# whether a slot holds a real child handle (neither free nor reserved) fun proc_slot_live(h: isize) bool { ret h != INVALID_HANDLE_VALUE && h != PROC_RESERVED; } @@ -659,7 +659,7 @@ fun reserve_proc() i32 { ret -1; } -# bind a reserved slot to a spawned child's pid and process handle. +# bind a reserved slot to a spawned child's pid and process handle # the pid is published before the handle so a torn observation can never # pair a live handle with a stale pid. fun commit_proc(slot: i32, pid: u32, handle: isize) { @@ -760,7 +760,7 @@ fun filetime_to_unix(ft: FILETIME, sec: *i64, nsec: *i64) { @nsec = (unix_ticks % 10000000) * 100; } -# append one byte to the command line, reserving the terminator slot. +# append one byte to the command line, reserving the terminator slot # --- # ret: false when the byte does not fit fun cmd_put(buf: *u8, cap: usize, off: *usize, b: u8) bool { @@ -772,7 +772,7 @@ fun cmd_put(buf: *u8, cap: usize, off: *usize, b: u8) bool { ret true; } -# build a command line string from a null-terminated argv array. +# build a command line string from a null-terminated argv array # escapes per the CommandLineToArgvW convention. # --- # argv: null-terminated array of null-terminated strings @@ -967,7 +967,7 @@ pub fun page_size() usize { ret 4096; } -# map a file descriptor into memory via CreateFileMapping + MapViewOfFile. +# map a file descriptor into memory via CreateFileMapping + MapViewOfFile # --- # fd: file descriptor to map # offset: offset into the file (must be page-aligned) @@ -1006,7 +1006,7 @@ pub fun map_file(fd: i32, offset: usize, size: usize, prot: u32) ptr { ret p; } -# flush a memory-mapped region to its backing file via FlushViewOfFile. +# flush a memory-mapped region to its backing file via FlushViewOfFile # --- # p: pointer to the mapped region # size: size of the region in bytes @@ -1155,7 +1155,7 @@ pub fun stat(fd: i32, st: *stat_t) i64 { ret 0; } -# stub: dirfd is ignored — path must be absolute or relative to cwd +# stub: dirfd is ignored, path must be absolute or relative to cwd pub fun stat_path(dirfd: i32, path: *u8, st: *stat_t, flags: i32) i64 { val attr: u32 = GetFileAttributesA(path); if (attr == 0xFFFFFFFF) { @@ -1187,7 +1187,7 @@ pub fun stat_path(dirfd: i32, path: *u8, st: *stat_t, flags: i32) i64 { ret r; } -# stub: dirfd is ignored — path must be absolute or relative to cwd +# stub: dirfd is ignored, path must be absolute or relative to cwd pub fun unlink(dirfd: i32, path: *u8, flags: i32) i64 { if ((flags & AT_REMOVEDIR) != 0) { if (RemoveDirectoryA(path) == 0) { @@ -1214,7 +1214,7 @@ pub fun unlink(dirfd: i32, path: *u8, flags: i32) i64 { ret 0; } -# stub: olddir/newdir are ignored — paths must be absolute or relative to cwd +# stub: olddir/newdir are ignored, paths must be absolute or relative to cwd pub fun rename(olddir: i32, oldpath: *u8, newdir: i32, newpath: *u8) i64 { if (MoveFileA(oldpath, newpath) == 0) { ret last_error(); @@ -1222,12 +1222,12 @@ pub fun rename(olddir: i32, oldpath: *u8, newdir: i32, newpath: *u8) i64 { ret 0; } -# symlink: create a symbolic link at linkpath pointing to target. +# create a symbolic link at linkpath pointing to target # # uses CreateSymbolicLinkA (the -A/ANSI entry point, consistent with the rest # of this layer; the file is uniformly ANSI and no UTF-8→UTF-16 helper exists). # target is passed verbatim so relative targets stay relative. the directory -# flag is set when the target resolves to a directory — relative targets are +# flag is set when the target resolves to a directory, relative targets are # resolved against linkpath's parent, matching how the link itself resolves at # use time. ALLOW_UNPRIVILEGED_CREATE is always requested (it is honored under # developer mode and ignored otherwise); when the OS refuses for lack of @@ -1270,7 +1270,7 @@ fun symlink_target_is_dir(target: *u8, linkpath: *u8) bool { ret (attr & FILE_ATTRIBUTE_DIRECTORY) != 0; } -# build "" into buf for the directory probe. +# build "" into buf for the directory probe # when linkpath has no directory component the target is left relative to the # cwd (copied as-is). returns false when the joined path would overflow buf. fun symlink_resolve_target(target: *u8, linkpath: *u8, buf: *u8, cap: usize) bool { @@ -1437,7 +1437,7 @@ fun zero_bytes(p: *u8, n: usize) { } } -# build a CreateProcess environment block from a null-terminated envp array. +# build a CreateProcess environment block from a null-terminated envp array # # the block is a sequence of null-terminated "NAME=VALUE" strings followed # by a final null. ownership transfers to the caller, which frees it with @@ -1506,7 +1506,7 @@ fun register_child(pi: PROCESS_INFORMATION, slot: i32) i64 { ret pi.dwProcessId::i64; } -# restore the inherit flag of the first n handles to its saved state. +# restore the inherit flag of the first n handles to its saved state fun restore_inherit(list: *isize, prev: *u32, n: usize) { var i: usize = 0; for (i < n) { @@ -1515,10 +1515,10 @@ fun restore_inherit(list: *isize, prev: *u32, n: usize) { } } -# create a child with its standard streams redirected. +# create a child with its standard streams redirected # # inheritance is scoped with PROC_THREAD_ATTRIBUTE_HANDLE_LIST so the child -# receives exactly the listed std handles — concurrent spawns cannot leak +# receives exactly the listed std handles, concurrent spawns cannot leak # unrelated inheritable handles (e.g. another thread's pipe ends) into it. # each listed handle is temporarily marked inheritable and restored to its # prior state on every path. a parent stream that does not exist (NULL or @@ -1676,7 +1676,7 @@ fun create_inherit(pathname: *u8, cmdline: *u8, env_block: ptr, slot: i32) i64 { ret register_child(pi, slot); } -# spawn: create a child process running the given program. +# create a child process running the given program # # collapses onto spawn_redirected with all three streams inherited. # --- @@ -1688,7 +1688,7 @@ pub fun spawn(pathname: *u8, argv: **u8, envp: **u8) i64 { ret spawn_redirected(pathname, argv, envp, -1, -1, -1); } -# spawn_redirected: spawn a child with its standard streams bound to +# spawn a child with its standard streams bound to # caller-supplied descriptors (-1 inherits the parent's stream). # # with no redirection the child inherits the parent's streams natively; @@ -1749,14 +1749,14 @@ pub fun spawn_redirected(pathname: *u8, argv: **u8, envp: **u8, stdin_fd: i32, s ret r; } -# getpid: return the current process ID. +# return the current process ID # --- # ret: process ID pub fun getpid() i64 { ret GetCurrentProcessId()::i64; } -# pipe: create a unidirectional pipe. +# create a unidirectional pipe # --- # fds: pointer to two i32s; fds[0] = read end, fds[1] = write end # ret: 0 on success, or negative errno @@ -1784,7 +1784,7 @@ pub fun pipe(fds: *i32) i64 { ret 0; } -# sleep: suspend execution for the given number of nanoseconds. +# suspend execution for the given number of nanoseconds # --- # nsec: nanoseconds to sleep pub fun sleep(nsec: i64) { @@ -1793,7 +1793,7 @@ pub fun sleep(nsec: i64) { Sleep(ms); } -# cpu_count: the number of CPUs available to this process. +# the number of CPUs available to this process # # GetActiveProcessorCount over all processor groups, so machines with more # than 64 logical processors report fully. never returns less than 1. @@ -1806,7 +1806,7 @@ pub fun cpu_count() i64 { ret n::i64; } -# getcwd: get the current working directory. +# get the current working directory # --- # buf: destination buffer # size: buffer capacity in bytes @@ -1819,7 +1819,7 @@ pub fun getcwd(buf: *u8, size: usize) i64 { ret len::i64; } -# getenv: look up an environment variable by name. +# look up an environment variable by name # # when the value fits (ret < cap) it is copied and null-terminated. # always returns the full value length, so ret >= cap signals truncation @@ -1854,7 +1854,7 @@ pub fun getenv(name: *u8, buf: *u8, cap: usize) i64 { ret len::i64; } -# temp_dir: resolve the directory designated for temporary files. +# resolve the directory designated for temporary files # # GetTempPathA consults TMP, then TEMP, then USERPROFILE, then the windows # directory, returning the first as a path that ends with a separator. it @@ -1878,7 +1878,7 @@ pub fun temp_dir(buf: *u8, cap: usize) i64 { ret len::i64; } -# captured environment vector, built once from the win32 environment block. +# captured environment vector, built once from the win32 environment block var _environ_vec: **u8 = nil; var _environ_init: u8 = 0; var _environ_lock: i64 = 0; @@ -1894,13 +1894,13 @@ fun environ_spin_unlock() { atomic.store(?_environ_lock, 0); } -# environ: the process environment as a unix-style "NAME=VALUE" vector. +# the process environment as a unix-style "NAME=VALUE" vector # # parses the win32 environment block (GetEnvironmentStrings) into a # null-terminated array of pointers on first call and caches it for the # process lifetime; the block backs the entries, so it is retained rather # than freed. the hidden drive-cwd entries the block prepends (names -# starting with '=', e.g. "=C:=C:\...") are skipped — they violate the +# starting with '=', e.g. "=C:=C:\...") are skipped, they violate the # NAME=value contract. returns nil if the block is unavailable or # allocation fails; failure is not cached, so a later call may succeed. pub fun environ() **u8 { @@ -1950,13 +1950,13 @@ pub fun environ() **u8 { ret vec; } -# wait: wait for a child process to change state. +# wait for a child process to change state # # uses the process handle table to look up children by pid. # pid == -1 waits for any child. WNOHANG uses a zero timeout. # -# WAIT_FAILED is treated as a dead handle — on windows it is in practice -# ERROR_INVALID_HANDLE, a permanent condition no retry can clear — so the +# WAIT_FAILED is treated as a dead handle, on windows it is in practice +# ERROR_INVALID_HANDLE, a permanent condition no retry can clear, so the # affected child is purged (best-effort CloseHandle + slot freed) rather # than left pinning the table forever. a single-pid wait purges and # returns the error; the wait-any path probes each snapshot handle @@ -2119,7 +2119,7 @@ fun thread_trampoline(arg: ptr) { WakeByAddressSingle(done::ptr); } -# thread_spawn: create a new thread via CreateThread. +# create a new thread via CreateThread # # stores fn and done_ptr at the base of the pre-allocated stack region, # then passes that address as CreateThread's lpParameter. the trampoline @@ -2144,7 +2144,7 @@ pub fun thread_spawn(f: fun(), done_ptr: *i64, stack_base: usize, stack_size: us ret tid::i64; } -# thread_wait: block until the value at addr changes from expected. +# block until the value at addr changes from expected # # wraps WaitOnAddress for 64-bit compare-and-wait. returns immediately # if *addr does not equal expected. spurious wakeups are possible. @@ -2161,7 +2161,7 @@ pub fun thread_wait(addr: *i64, expected: i64) i64 { ret 0; } -# thread_wake: wake one thread blocked on WaitOnAddress at addr. +# wake one thread blocked on WaitOnAddress at addr # --- # addr: pointer to the futex word # ret: 0 (always succeeds) @@ -2172,7 +2172,7 @@ pub fun thread_wake(addr: *i64) i64 { # runtime environment -# running_under_wine: detect whether the process is running under the wine +# detect whether the process is running under the wine # windows compatibility layer rather than on genuine windows. # # probes ntdll for the wine-only `wine_get_version` export, the canonical @@ -2329,7 +2329,7 @@ pub fun sock_setopt(fd: i32, level: i32, opt: i32, value: *u8, vallen: usize) i6 pub val DNS_HOSTS_PATH: str = "C:/Windows/System32/drivers/etc/hosts"; -# dns_nameserver: get the primary DNS nameserver address. +# get the primary DNS nameserver address # # windows does not use /etc/resolv.conf. a real implementation would # call GetAdaptersAddresses or read the registry. returns NOT_FOUND @@ -2343,7 +2343,7 @@ pub fun dns_nameserver(ns: *u8) i64 { # random -# random_fill: fill a buffer with cryptographic random bytes via RtlGenRandom. +# fill a buffer with cryptographic random bytes via RtlGenRandom # --- # buf: destination buffer # len: number of bytes to fill diff --git a/src/system/os/windows/x86_64.mach b/src/system/os/windows/x86_64.mach index d3b12f2..550b7e6 100644 --- a/src/system/os/windows/x86_64.mach +++ b/src/system/os/windows/x86_64.mach @@ -1,6 +1,6 @@ -# std.system.os.windows.x86_64: x86_64-specific windows OS primitives. +# x86_64-specific windows OS primitives # -# windows has no architecture-specific OS code — all Win32 API calls are +# windows has no architecture-specific OS code, all Win32 API calls are # arch-independent. this module exists only for ISA dispatch and forwards # everything from shared.mach. diff --git a/src/system/panic.mach b/src/system/panic.mach index 43782b3..384048a 100644 --- a/src/system/panic.mach +++ b/src/system/panic.mach @@ -1,4 +1,4 @@ -# low-level panic: write message to stderr and terminate. +# low-level panic: write message to stderr and terminate # # self-contained module with no dependency on std.system.os, # allowing std.types.result and std.types.option to panic @@ -6,7 +6,7 @@ use std.types.size.usize; -# panic: write a null-terminated message to stderr and abort. +# write a null-terminated message to stderr and abort # --- # msg: pointer to null-terminated error message pub fun panic(msg: *u8) { diff --git a/src/text/parse.mach b/src/text/parse.mach index 51f49c3..b74c362 100644 --- a/src/text/parse.mach +++ b/src/text/parse.mach @@ -1,3 +1,7 @@ +# number parsing utilities +# --- +# parse integers from strings with various bases and options + use std.types.bool.bool; use std.types.bool.true; use std.types.bool.false; @@ -16,13 +20,9 @@ use std.types.char.char_is_space; use std.types.char.char_digit_val; use mem: std.memory; -use bn: std.math.bignum; +use bn: std.math.bignum; -# std.text.parse: number parsing utilities -# --- -# parse integers from strings with various bases and options - -# parse an unsigned 64-bit integer prefix from a string. +# parse an unsigned 64-bit integer prefix from a string # # stops at the first character that is not a valid digit for the given base, # returning the value parsed so far. use parse_u64_exact to require full @@ -134,7 +134,7 @@ pub fun parse_u64(s: str, base: u8) Result[u64, str] { ret ok[u64, str](result); } -# parse an unsigned 64-bit integer from a string, requiring full consumption. +# parse an unsigned 64-bit integer from a string, requiring full consumption # # returns an error if there are any characters remaining after the number. # leading whitespace is also rejected. @@ -226,7 +226,7 @@ pub fun parse_u64_exact(s: str, base: u8) Result[u64, str] { ret ok[u64, str](result); } -# parse a signed 64-bit integer prefix from a string. +# parse a signed 64-bit integer prefix from a string # # delegates to parse_u64 for the unsigned portion, so it inherits the same # prefix-parsing behavior. use parse_i64_exact to require full input @@ -297,7 +297,7 @@ pub fun parse_i64(s: str, base: u8) Result[i64, str] { ret ok[i64, str](u_val::i64); } -# parse a signed 64-bit integer from a string, requiring full consumption. +# parse a signed 64-bit integer from a string, requiring full consumption # # returns an error if there are any characters remaining after the number. # leading whitespace is also rejected. @@ -352,11 +352,7 @@ pub fun parse_i64_exact(s: str, base: u8) Result[i64, str] { ret ok[i64, str](u_val::i64); } -# parse a 64-bit floating point number prefix from a string. -# -# handles optional sign, integer part, fractional part, and exponent. -# also handles special values inf, -inf, nan, +inf, +nan. -# cmp_ratio_pow2: sign of (num/den - 2^p) — compares the rational num/den to 2^p. +# sign of (num/den - 2^p), comparing the rational num/den to 2^p fun cmp_ratio_pow2(num: *bn.Big, den: *bn.Big, p: i64) i64 { var a: bn.Big; var b: bn.Big; @@ -367,7 +363,7 @@ fun cmp_ratio_pow2(num: *bn.Big, den: *bn.Big, p: i64) i64 { ret bn.cmp(?a, ?b); } -# decimal_to_f64: nearest f64 bit pattern (sign excluded) to M * 10^D, round-to- +# nearest f64 bit pattern (sign excluded) to M * 10^D, round-to- # nearest-even, via exact bignum arithmetic. M is non-negative; the caller ORs in # the sign bit. handles subnormals, overflow (-> inf), and underflow (-> 0). fun decimal_to_f64(M: *bn.Big, D: i64, trunc: bool) u64 { @@ -395,7 +391,7 @@ fun decimal_to_f64(M: *bn.Big, D: i64, trunc: bool) u64 { done = true; } - # clamp the mantissa LSB to the subnormal floor (2^-1074) — a single rounding. + # clamp the mantissa LSB to the subnormal floor (2^-1074), a single rounding. var lsb: i64 = e2; if (lsb < -1074) { lsb = -1074; } @@ -449,8 +445,8 @@ fun decimal_to_f64(M: *bn.Big, D: i64, trunc: bool) u64 { ret (biased::u64 << 52) | (q & 0xFFFFFFFFFFFFF); } -# collect_significand: scan integer + fractional digits from s at @i into M -# (capped at 768 significant digits — well past what f64 rounding can use, so +# scan integer + fractional digits from s at @i into M +# (capped at 768 significant digits, well past what f64 rounding can use, so # excess digits are dropped without affecting the result). advances @i and writes # the decimal-exponent contribution to @out_dexp (value-so-far = M * 10^out_dexp). # returns true iff at least one digit was seen. @@ -511,7 +507,7 @@ pub fun parse_f64(s: str) Result[f64, str] { ret parse_f64_len(s, str_len(s)); } -# parse a 64-bit floating point number prefix from the first `len` bytes of `s`. +# parse a 64-bit floating point number prefix from the first `len` bytes of `s` # # like parse_f64 but bounded by an explicit length instead of a null terminator, # so it is safe on a byte span embedded in a larger buffer (e.g. a zero-copy @@ -590,7 +586,7 @@ pub fun parse_f64_len(s: str, len: usize) Result[f64, str] { ret ok[f64, str](result); } -# parse a 64-bit floating point number from a string, requiring full consumption. +# parse a 64-bit floating point number from a string, requiring full consumption # # handles optional sign, integer part, fractional part, and exponent. # also handles special values inf, -inf, nan, +inf, +nan. @@ -1032,7 +1028,7 @@ test "parse: f64_exact inf trailing" { ret 0; } -# pbits: parse s and return its f64 bit pattern (0xDEADBEEF sentinel on error). +# parse s and return its f64 bit pattern (0xDEADBEEF sentinel on error) fun pbits(s: str) u64 { val r: Result[f64, str] = parse_f64(s); if (is_err[f64, str](r)) { ret 0xDEADBEEF; } diff --git a/src/text/string.mach b/src/text/string.mach index fd205ce..b8c7d24 100644 --- a/src/text/string.mach +++ b/src/text/string.mach @@ -1,4 +1,4 @@ -# std.text.string: owned null-terminated string helpers over the allocator. +# owned null-terminated string helpers over the allocator # # these helpers allocate, copy, and free null-terminated `str` buffers using a # caller-supplied allocator. they live above `std.types.string` (which operates @@ -20,7 +20,7 @@ use std.allocator.Allocator; use std.allocator.allocate; use std.allocator.deallocate; -# str_dup: allocate an owned, null-terminated copy of `s`. +# allocate an owned, null-terminated copy of `s` # --- # a: allocator backing the copy # s: borrowed null-terminated string to copy @@ -30,7 +30,7 @@ pub fun str_dup(a: *Allocator, s: str) Result[str, str] { ret dup_bytes(a, s, 0, n); } -# str_dup_range: allocate an owned, null-terminated copy of `len` bytes of +# allocate an owned, null-terminated copy of `len` bytes of # `source` starting at `offset`. # --- # a: allocator backing the copy @@ -42,7 +42,7 @@ pub fun str_dup_range(a: *Allocator, source: str, offset: usize, len: usize) Res ret dup_bytes(a, source, offset, len); } -# str_free: release a string previously returned by str_dup / str_dup_range. +# release a string previously returned by str_dup / str_dup_range # --- # a: allocator the string was allocated from # s: owned string to free (nil is a no-op) @@ -52,7 +52,7 @@ pub fun str_free(a: *Allocator, s: str) { deallocate[char](a, s, n + 1); } -# dup_bytes: allocate `len + 1` chars, copy `len` bytes from `src + offset`, +# allocate `len + 1` chars, copy `len` bytes from `src + offset`, # and null-terminate. fun dup_bytes(a: *Allocator, src: str, offset: usize, len: usize) Result[str, str] { val r: Result[*char, str] = allocate[char](a, len + 1); diff --git a/src/text/utf8.mach b/src/text/utf8.mach index 8db4bcf..ffc30fa 100644 --- a/src/text/utf8.mach +++ b/src/text/utf8.mach @@ -1,4 +1,4 @@ -# UTF-8 encoding, decoding, and validation. +# UTF-8 encoding, decoding, and validation use std.types.bool.bool; use std.types.bool.true; @@ -10,7 +10,7 @@ pub def Codepoint: u32; pub val REPLACEMENT: Codepoint = 0xFFFD; pub val MAX_CODEPOINT: Codepoint = 0x10FFFF; -# return the sequence length from a UTF-8 leading byte. +# return the sequence length from a UTF-8 leading byte # --- # first_byte: the first byte of a UTF-8 sequence # ret: 1-4 for valid leading bytes, 0 for invalid @@ -23,7 +23,7 @@ pub fun byte_len(first_byte: u8) usize { ret 0; } -# return how many bytes are needed to encode a codepoint. +# return how many bytes are needed to encode a codepoint # --- # cp: the codepoint to measure # ret: 1-4 for valid codepoints, 0 if > U+10FFFF @@ -35,7 +35,7 @@ pub fun codepoint_len(cp: Codepoint) usize { ret 0; } -# true if the byte is a UTF-8 continuation byte (0x80-0xBF). +# true if the byte is a UTF-8 continuation byte (0x80-0xBF) # --- # b: byte to test # ret: true if continuation byte @@ -43,7 +43,7 @@ pub fun is_continuation(b: u8) bool { ret b >= 0x80 && b < 0xC0; } -# encode a codepoint into a byte buffer. +# encode a codepoint into a byte buffer # --- # cp: codepoint to encode # buf: destination buffer @@ -86,7 +86,7 @@ pub fun encode(cp: Codepoint, buf: *u8, len: usize) usize { ret 4; } -# decode one codepoint from a byte buffer. +# decode one codepoint from a byte buffer # --- # buf: source buffer # len: number of bytes available @@ -172,7 +172,7 @@ pub fun decode(buf: *u8, len: usize, cp: *Codepoint) usize { ret 4; } -# check if a byte buffer contains valid UTF-8. +# check if a byte buffer contains valid UTF-8 # --- # buf: source buffer # len: number of bytes @@ -230,7 +230,7 @@ pub fun validate(buf: *u8, len: usize) bool { ret true; } -# count the number of codepoints in a UTF-8 byte buffer. +# count the number of codepoints in a UTF-8 byte buffer # --- # buf: source buffer # len: number of bytes diff --git a/src/types/char.mach b/src/types/char.mach index 8486eb2..4a7b278 100644 --- a/src/types/char.mach +++ b/src/types/char.mach @@ -1,11 +1,11 @@ -# character type and ASCII classification. +# character type and ASCII classification use std.types.bool.bool; -# a single byte representing a character in a null-terminated string. +# a single byte representing a character in a null-terminated string pub def char: u8; -# char_is_space: check if a character is ASCII whitespace. +# check if a character is ASCII whitespace # --- # c: character to test # ret: true if whitespace (space, tab, newline, vertical tab, form feed, carriage return) @@ -13,7 +13,7 @@ pub fun char_is_space(c: char) bool { ret c == ' ' || c == '\t' || c == '\n' || c == 11 || c == 12 || c == '\r'; } -# char_is_digit: check if a character is an ASCII digit. +# check if a character is an ASCII digit # --- # c: character to test # ret: true if 0-9 @@ -21,7 +21,7 @@ pub fun char_is_digit(c: char) bool { ret c >= '0' && c <= '9'; } -# char_is_alpha: check if a character is an ASCII letter. +# check if a character is an ASCII letter # --- # c: character to test # ret: true if a-z or A-Z @@ -29,7 +29,7 @@ pub fun char_is_alpha(c: char) bool { ret (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } -# char_is_alnum: check if a character is alphanumeric. +# check if a character is alphanumeric # --- # c: character to test # ret: true if letter or digit @@ -37,7 +37,7 @@ pub fun char_is_alnum(c: char) bool { ret char_is_alpha(c) || char_is_digit(c); } -# char_is_lower: check if a character is a lowercase ASCII letter. +# check if a character is a lowercase ASCII letter # --- # c: character to test # ret: true if a-z @@ -45,7 +45,7 @@ pub fun char_is_lower(c: char) bool { ret c >= 'a' && c <= 'z'; } -# char_is_upper: check if a character is an uppercase ASCII letter. +# check if a character is an uppercase ASCII letter # --- # c: character to test # ret: true if A-Z @@ -53,7 +53,7 @@ pub fun char_is_upper(c: char) bool { ret c >= 'A' && c <= 'Z'; } -# char_to_lower: convert an ASCII letter to lowercase. +# convert an ASCII letter to lowercase # --- # c: character to convert # ret: lowercase equivalent, or c unchanged if not uppercase @@ -62,7 +62,7 @@ pub fun char_to_lower(c: char) char { ret c; } -# char_to_upper: convert an ASCII letter to uppercase. +# convert an ASCII letter to uppercase # --- # c: character to convert # ret: uppercase equivalent, or c unchanged if not lowercase @@ -71,7 +71,7 @@ pub fun char_to_upper(c: char) char { ret c; } -# char_is_hex_digit: check if a character is a hexadecimal digit. +# check if a character is a hexadecimal digit # --- # c: character to test # ret: true if 0-9, a-f, or A-F @@ -79,7 +79,7 @@ pub fun char_is_hex_digit(c: char) bool { ret (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } -# char_is_punct: check if a character is ASCII punctuation. +# check if a character is ASCII punctuation # --- # c: character to test # ret: true if punctuation @@ -87,7 +87,7 @@ pub fun char_is_punct(c: char) bool { ret (c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~'); } -# char_is_print: check if a character is printable ASCII. +# check if a character is printable ASCII # --- # c: character to test # ret: true if printable (space through tilde) @@ -95,7 +95,7 @@ pub fun char_is_print(c: char) bool { ret c >= ' ' && c <= '~'; } -# char_is_ctrl: check if a character is an ASCII control character. +# check if a character is an ASCII control character # --- # c: character to test # ret: true if control character @@ -103,7 +103,7 @@ pub fun char_is_ctrl(c: char) bool { ret c < ' ' || c == 127; } -# char_digit_val: get the numeric value of a digit or letter character. +# get the numeric value of a digit or letter character # --- # c: character to evaluate # ret: 0-9 for digits, 10-35 for letters, or -1 if invalid diff --git a/src/types/option.mach b/src/types/option.mach index 9d14e40..33df258 100644 --- a/src/types/option.mach +++ b/src/types/option.mach @@ -5,7 +5,7 @@ use std.types.bool.true; use std.types.bool.false; use std.system.panic.panic; -# Option[T]: represents an optional value that may or may not be present. +# represents an optional value that may or may not be present # --- # has_value: true if a value is present # value: the contained value (undefined when has_value is false) @@ -14,7 +14,7 @@ pub rec Option[T] { value: T; } -# some: create an Option[T] containing a value. +# create an Option[T] containing a value # --- # value: the value to contain # ret: an Option[T] with the value present @@ -25,7 +25,7 @@ pub fun some[T](value: T) Option[T] { ret opt; } -# none: create an Option[T] with no value. +# create an Option[T] with no value # --- # ret: an Option[T] with no value present pub fun none[T]() Option[T] { @@ -34,17 +34,17 @@ pub fun none[T]() Option[T] { ret opt; } -# is_some: check if the Option[T] contains a value. +# check if the Option[T] contains a value pub fun is_some[T](opt: Option[T]) bool { ret opt.has_value == true; } -# is_none: check if the Option[T] is empty. +# check if the Option[T] is empty pub fun is_none[T](opt: Option[T]) bool { ret opt.has_value == false; } -# unwrap: return the contained value. +# return the contained value # # aborts the process if no value is present. # --- @@ -56,7 +56,7 @@ pub fun unwrap[T](opt: Option[T]) T { ret opt.value; } -# unwrap_or: return the contained value, or a default if empty. +# return the contained value, or a default if empty # --- # default: value to return if the option is empty # ret: the contained value, or default diff --git a/src/types/path.mach b/src/types/path.mach index 303c9e3..45109cb 100644 --- a/src/types/path.mach +++ b/src/types/path.mach @@ -43,12 +43,12 @@ use page: std.allocator.page; pub def Path: str; -# separator: platform path separator character, emitted by construction. +# platform path separator character, emitted by construction pub fun separator() u8 { ret os.separator; } -# is_separator: whether c separates path components on the target. +# whether c separates path components on the target # # windows accepts both '/' and '\'; posix treats only '/' as a separator. pub fun is_separator(c: u8) bool { @@ -60,7 +60,7 @@ pub fun is_separator(c: u8) bool { } } -# root_len: byte length of the absolute root prefix at the head of p. +# byte length of the absolute root prefix at the head of p # # recognizes windows drive roots ('C:' or 'C:\') and UNC roots # ('\\server\share'); returns 0 for relative paths, single-separator roots, @@ -93,12 +93,12 @@ fun root_len(p: Path) usize { } } -# is_empty: check whether a path is empty or nil. +# check whether a path is empty or nil pub fun is_empty(p: Path) bool { ret p == nil || p[0] == 0; } -# is_abs: check whether a path is absolute. +# check whether a path is absolute # # a path is absolute when it begins with a separator (a posix or UNC root) # or, on windows, with a drive-letter root 'X:\' / 'X:/'. a bare drive @@ -114,7 +114,7 @@ pub fun is_abs(p: Path) bool { ret false; } -# is_root: check whether a path is a root unit. +# check whether a path is a root unit # # true when p is only separators, or (on windows) exactly a drive or UNC # root followed by any trailing separators. @@ -133,7 +133,7 @@ pub fun is_root(p: Path) bool { ret true; } -# filename: return the final component of a path. +# return the final component of a path # # returns a pointer into p (no allocation). returns nil for empty paths # and empty string for paths ending in a separator. @@ -159,7 +159,7 @@ pub fun filename(p: Path) str { ret p; } -# extension: return the file extension without the leading dot. +# return the file extension without the leading dot # # returns a pointer into p (no allocation). returns nil if there is no # extension (no dot, or dot is first char of filename). @@ -185,7 +185,7 @@ pub fun extension(p: Path) str { ret nil; } -# stem: return the filename without its extension. +# return the filename without its extension # # "foo/bar.txt" → "bar", "foo/.hidden" → ".hidden", "foo/bar" → "bar" # --- @@ -219,7 +219,7 @@ pub fun stem(a: *allocator.Allocator, p: Path) Result[Path, str] { ret ok[Path, str](buf::*u8); } -# clone: duplicate a path using the provided allocator. +# duplicate a path using the provided allocator # --- # a: allocator for the new path # p: path to clone (nil returns nil) @@ -241,7 +241,7 @@ pub fun clone(a: *allocator.Allocator, p: Path) Result[Path, str] { ret ok[Path, str](buf::*u8); } -# join: join two path segments with the platform separator. +# join two path segments with the platform separator # --- # a: allocator for the resulting path # left: left path segment @@ -281,7 +281,7 @@ pub fun join(a: *allocator.Allocator, left: Path, right: Path) Result[Path, str] ret ok[Path, str](buf::*u8); } -# parent: return the parent directory of a path. +# return the parent directory of a path # --- # a: allocator for the resulting path # p: path to get parent of @@ -342,7 +342,7 @@ fun clone_sep(a: *allocator.Allocator, sep: u8) Result[Path, str] { ret ok[Path, str](buf::*u8); } -# clone_prefix: clone the first n bytes of p as a null-terminated path. +# clone the first n bytes of p as a null-terminated path fun clone_prefix(a: *allocator.Allocator, p: Path, n: usize) Result[Path, str] { val r: Result[*u8, str] = allocator.allocate[u8](a, n + 1); if (is_err[*u8, str](r)) { @@ -356,7 +356,7 @@ fun clone_prefix(a: *allocator.Allocator, p: Path, n: usize) Result[Path, str] { ret ok[Path, str](buf::*u8); } -# parent_rooted: parent of a path whose head is an absolute root of length +# parent of a path whose head is an absolute root of length # rl (> 0). a path at the root returns the root itself, so the volume or # UNC root is never split or crossed. fun parent_rooted(a: *allocator.Allocator, p: Path, rl: usize) Result[Path, str] { diff --git a/src/types/result.mach b/src/types/result.mach index b7ee5a2..fa69973 100644 --- a/src/types/result.mach +++ b/src/types/result.mach @@ -1,11 +1,11 @@ -# std.types.result: success-or-error value type +# success-or-error value type use std.types.bool.bool; use std.types.bool.true; use std.types.bool.false; use std.system.panic.panic; -# Result[T, E]: represents either success (ok) containing T, or error (err) containing E. +# represents either success (ok) containing T, or error (err) containing E # --- # tag: true for ok, false for err # value: the contained ok or err value @@ -17,7 +17,7 @@ pub rec Result[T, E] { }; } -# ok: create a Result[T, E] representing success. +# create a Result[T, E] representing success # --- # value: the success value # ret: a Result[T, E] with the ok value present @@ -28,7 +28,7 @@ pub fun ok[T, E](value: T) Result[T, E] { ret res; } -# err: create a Result[T, E] representing an error. +# create a Result[T, E] representing an error # --- # value: the error value # ret: a Result[T, E] with the err value present @@ -39,17 +39,17 @@ pub fun err[T, E](value: E) Result[T, E] { ret res; } -# is_ok: check if the result is ok (success). +# check if the result is ok (success) pub fun is_ok[T, E](res: Result[T, E]) bool { ret res.tag; } -# is_err: check if the result is err (error). +# check if the result is err (error) pub fun is_err[T, E](res: Result[T, E]) bool { ret !res.tag; } -# unwrap_ok: return the contained ok value. +# return the contained ok value # # aborts the process if the result is err. # --- @@ -61,7 +61,7 @@ pub fun unwrap_ok[T, E](res: Result[T, E]) T { ret res.value.ok; } -# unwrap_err: return the contained err value. +# return the contained err value # # aborts the process if the result is ok. # --- diff --git a/src/types/size.mach b/src/types/size.mach index b20b3a5..2d28bdb 100644 --- a/src/types/size.mach +++ b/src/types/size.mach @@ -1,21 +1,21 @@ -# pointer-width-sized integer types. +# pointer-width-sized integer types # --- # Defines usize and isize for the target pointer width. Defaults to 64-bit when unknown. $if ($mach.build.pointer_width == 2) { - pub def usize: u16; - pub def isize: i16; + pub def usize: u16; + pub def isize: i16; } $or ($mach.build.pointer_width == 4) { - pub def usize: u32; - pub def isize: i32; + pub def usize: u32; + pub def isize: i32; } $or ($mach.build.pointer_width == 8) { - pub def usize: u64; - pub def isize: i64; + pub def usize: u64; + pub def isize: i64; } $or { - # default to 64-bit size - pub def usize: u64; - pub def isize: i64; + # default to 64-bit size + pub def usize: u64; + pub def isize: i64; } diff --git a/src/types/string.mach b/src/types/string.mach index d08b01f..1045a4d 100644 --- a/src/types/string.mach +++ b/src/types/string.mach @@ -14,10 +14,10 @@ use std.types.result.is_err; use std.types.result.unwrap_ok; -# str: a pointer to a null-terminated sequence of char. +# a pointer to a null-terminated sequence of char pub def str: *char; -# str_len: calculate the length of a null-terminated string. +# calculate the length of a null-terminated string # --- # ret: length of the string (not including null terminator) pub fun str_len(s: str) usize { @@ -28,7 +28,7 @@ pub fun str_len(s: str) usize { ret len; } -# str_empty: check if the string is empty or nil. +# check if the string is empty or nil # --- # ret: true if the string has zero length or is nil pub fun str_empty(s: str) bool { @@ -36,7 +36,7 @@ pub fun str_empty(s: str) bool { ret s[0] == 0; } -# str_equals: compare two null-terminated strings for equality. +# compare two null-terminated strings for equality # --- # other: the other string to compare against # ret: true if the strings are equal @@ -54,7 +54,7 @@ pub fun str_equals(s: str, other: str) bool { ret s[i] == other[i]; } -# str_compare: compare two null-terminated strings lexically. +# compare two null-terminated strings lexically # --- # other: the other string to compare against # ret: <0 if s < other, 0 if equal, >0 if s > other @@ -79,7 +79,7 @@ pub fun str_compare(s: str, other: str) i64 { ret 0; } -# str_starts_with: check if the string starts with the given prefix. +# check if the string starts with the given prefix # --- # prefix: the prefix to check # ret: true if the string starts with prefix @@ -95,7 +95,7 @@ pub fun str_starts_with(s: str, prefix: str) bool { ret true; } -# str_ends_with: check if the string ends with the given suffix. +# check if the string ends with the given suffix # --- # suffix: the suffix to check # ret: true if the string ends with suffix @@ -116,7 +116,7 @@ pub fun str_ends_with(s: str, suffix: str) bool { ret true; } -# str_index_of: find the first index of a substring. +# find the first index of a substring # --- # sub: the substring to find # ret: the index of the first occurrence, or an error message @@ -151,7 +151,7 @@ pub fun str_index_of(s: str, sub: str) Result[usize, str] { ret err[usize, str]("substring not found"); } -# str_last_index_of: find the last index of a substring. +# find the last index of a substring # --- # sub: the substring to find # ret: the index of the last occurrence, or an error message @@ -185,7 +185,7 @@ pub fun str_last_index_of(s: str, sub: str) Result[usize, str] { ret err[usize, str]("substring not found"); } -# str_contains: check if the string contains the given substring. +# check if the string contains the given substring # --- # sub: the substring to check # ret: true if the string contains sub @@ -194,7 +194,7 @@ pub fun str_contains(s: str, sub: str) bool { ret is_ok[usize, str](r); } -# str_region_equals: compare a region of a string against a pattern. +# compare a region of a string against a pattern # --- # start: byte offset into s # len: number of bytes to compare @@ -216,7 +216,7 @@ pub fun str_region_equals(s: str, start: usize, len: usize, other: str) bool { ret true; } -# str_trim_left: return a pointer past leading whitespace. +# return a pointer past leading whitespace # --- # ret: pointer to first non-whitespace character pub fun str_trim_left(s: str) str { @@ -228,7 +228,7 @@ pub fun str_trim_left(s: str) str { ret (s::usize + i)::str; } -# str_index_char: find the first occurrence of a character in a string. +# find the first occurrence of a character in a string # --- # c: character to find # ret: the index of the first occurrence, or an error message @@ -242,7 +242,7 @@ pub fun str_index_char(s: str, c: char) Result[usize, str] { ret err[usize, str]("character not found"); } -# str_last_index_char: find the last occurrence of a character in a string. +# find the last occurrence of a character in a string # --- # c: character to find # ret: the index of the last occurrence, or an error message @@ -258,7 +258,7 @@ pub fun str_last_index_char(s: str, c: char) Result[usize, str] { ret err[usize, str]("character not found"); } -# str_contains_char: check if a string contains a character. +# check if a string contains a character # --- # c: character to find # ret: true if c appears in s @@ -527,7 +527,7 @@ test "string: contains_char" { ret 0; } -# StrView: a borrowed, length-counted slice of characters. unlike `str` +# a borrowed, length-counted slice of characters. unlike `str` # (a null-terminated `*char`), a view need not be null-terminated, so it can # name a sub-range of a larger buffer without copying or mutating it. # --- @@ -538,7 +538,7 @@ pub rec StrView { len: usize; } -# view: construct a StrView over `len` chars starting at `data`. +# construct a StrView over `len` chars starting at `data` # --- # data: pointer to the first character # len: number of characters @@ -550,7 +550,7 @@ pub fun view(data: *char, len: usize) StrView { ret v; } -# view_eq_str: compare a view against a null-terminated string for byte equality. +# compare a view against a null-terminated string for byte equality # --- # v: the view # s: null-terminated string to compare against @@ -565,7 +565,7 @@ pub fun view_eq_str(v: StrView, s: str) bool { ret s[v.len] == 0; } -# view_index_char: find the first occurrence of a character within the view. +# find the first occurrence of a character within the view # --- # v: the view to search # c: character to find @@ -579,7 +579,7 @@ pub fun view_index_char(v: StrView, c: char) Result[usize, str] { ret err[usize, str]("character not found"); } -# view_contains_char: check if the view contains a character. +# check if the view contains a character # --- # v: the view to search # c: character to find