diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f42e4fa3e..f9cff56dc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -63,6 +63,12 @@ jobs: call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 ..\..\build\${{ matrix.build_type }}\c3c.exe --debug-log build hello_world_win32_lib + - name: Compile and run dynlib-test + run: | + cd resources/examples/dynlib-test + ../../../build/c3c dynamic-lib add.c3 + ../../../build/c3c compile-run test.c3 -l ./add.lib + - name: Vendor-fetch run: | build\${{ matrix.build_type }}\c3c.exe vendor-fetch raylib5 @@ -311,6 +317,12 @@ jobs: ../build/c3c compile-run linux_stack.c3 ../build/c3c compile-run examples/args.c3 -- foo -bar "baz baz" + - name: Compile and run dynlib-test + run: | + cd resources/examples/dynlib-test + ../../../build/c3c dynamic-lib add.c3 + ../../../build/c3c compile-run test.c3 -l ./add.so + - name: Compile run unit tests run: | cd test @@ -621,6 +633,12 @@ jobs: ../build/c3c compile-run -O5 examples/load_world.c3 ../build/c3c compile-run examples/args.c3 -- foo -bar "baz baz" + - name: Compile and run dynlib-test + run: | + cd resources/examples/dynlib-test + ../../../build/c3c dynamic-lib add.c3 + ../../../build/c3c compile-run test.c3 -l ./add.dylib + - name: Compile run unit tests run: | cd test diff --git a/lib/std/ascii.c3 b/lib/std/ascii.c3 index ad5fe9036..412e09b95 100644 --- a/lib/std/ascii.c3 +++ b/lib/std/ascii.c3 @@ -53,9 +53,9 @@ fn bool char.is_blank(char c) => is_blank_m(c); fn bool char.is_cntrl(char c) => is_cntrl_m(c); fn char char.to_lower(char c) => (char)to_lower_m(c); fn char char.to_upper(char c) => (char)to_upper_m(c); -/** - * @require c.is_xdigit() - **/ +<* + @require c.is_xdigit() +*> fn char char.from_hex(char c) => c.is_digit() ? c - '0' : 10 + (c | 0x20) - 'a'; fn bool uint.in_range(uint c, uint start, uint len) => in_range_m(c, start, len); diff --git a/lib/std/atomic.c3 b/lib/std/atomic.c3 index eff1d59c4..754a34620 100644 --- a/lib/std/atomic.c3 +++ b/lib/std/atomic.c3 @@ -8,12 +8,12 @@ struct Atomic Type data; } -/** - * Loads data atomically, by default this uses SEQ_CONSISTENT ordering. - * - * @param ordering "The ordering, cannot be release or acquire-release." - * @require ordering != RELEASE && ordering != ACQUIRE_RELEASE : "Release and acquire-release are not valid for load" - **/ +<* + Loads data atomically, by default this uses SEQ_CONSISTENT ordering. + + @param ordering "The ordering, cannot be release or acquire-release." + @require ordering != RELEASE && ordering != ACQUIRE_RELEASE : "Release and acquire-release are not valid for load" +*> macro Type Atomic.load(&self, AtomicOrdering ordering = SEQ_CONSISTENT) { Type* data = &self.data; @@ -28,12 +28,12 @@ macro Type Atomic.load(&self, AtomicOrdering ordering = SEQ_CONSISTENT) case RELEASE: unreachable("Invalid ordering."); } } -/** - * Stores data atomically, by default this uses SEQ_CONSISTENT ordering. - * - * @param ordering "The ordering, cannot be acquire or acquire-release." - * @require ordering != ACQUIRE && ordering != ACQUIRE_RELEASE : "Acquire and acquire-release are not valid for store" - **/ +<* + Stores data atomically, by default this uses SEQ_CONSISTENT ordering. + + @param ordering "The ordering, cannot be acquire or acquire-release." + @require ordering != ACQUIRE && ordering != ACQUIRE_RELEASE : "Acquire and acquire-release are not valid for store" +*> macro void Atomic.store(&self, Type value, AtomicOrdering ordering = SEQ_CONSISTENT) { Type* data = &self.data; @@ -131,16 +131,16 @@ macro @atomic_exec(#func, data, value, ordering) @local module std::atomic; import std::math; -/** - * @param [&in] ptr "the variable or dereferenced pointer to the data." - * @param [in] y "the value to be added to ptr." - * @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" - * @return "returns the old value of ptr" - * - * @require !$alignment || math::is_power_of_2($alignment) "Alignment must be a power of two." - * @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used." - * @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - **/ +<* + @param [&in] ptr "the variable or dereferenced pointer to the data." + @param [in] y "the value to be added to ptr." + @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" + @return "returns the old value of ptr" + + @require !$alignment || math::is_power_of_2($alignment) "Alignment must be a power of two." + @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used." + @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." +*> macro fetch_add(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile = false, usz $alignment = 0) { $if $alignment == 0: @@ -149,16 +149,16 @@ macro fetch_add(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatil return $$atomic_fetch_add(ptr, y, $volatile, $ordering.ordinal, $alignment); } -/** - * @param [&in] ptr "the variable or dereferenced pointer to the data." - * @param [in] y "the value to be added to ptr." - * @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" - * @return "returns the old value of ptr" - * - * @require !$alignment || math::is_power_of_2($alignment) "Alignment must be a power of two." - * @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used." - * @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - **/ +<* + @param [&in] ptr "the variable or dereferenced pointer to the data." + @param [in] y "the value to be added to ptr." + @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" + @return "returns the old value of ptr" + + @require !$alignment || math::is_power_of_2($alignment) "Alignment must be a power of two." + @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used." + @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." +*> macro fetch_sub(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile = false, usz $alignment = 0) { $if $alignment == 0: @@ -167,15 +167,15 @@ macro fetch_sub(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatil return $$atomic_fetch_sub(ptr, y, $volatile, $ordering.ordinal, $alignment); } -/** - * @param [&in] ptr "the variable or dereferenced pointer to the data." - * @param [in] y "the value to be added to ptr." - * @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" - * @return "returns the old value of ptr" - * - * @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used." - * @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - **/ +<* + @param [&in] ptr "the variable or dereferenced pointer to the data." + @param [in] y "the value to be added to ptr." + @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" + @return "returns the old value of ptr" + + @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used." + @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." +*> macro fetch_mul(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT) { var $load_ordering = $ordering; @@ -204,15 +204,15 @@ macro fetch_mul(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT) return old_value; } -/** - * @param [&in] ptr "the variable or dereferenced pointer to the data." - * @param [in] y "the value to be added to ptr." - * @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" - * @return "returns the old value of ptr" - * -* @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used." -* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - **/ +<* + @param [&in] ptr "the variable or dereferenced pointer to the data." + @param [in] y "the value to be added to ptr." + @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" + @return "returns the old value of ptr" + + @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used." + @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." +*> macro fetch_div(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT) { var $load_ordering = $ordering; @@ -240,17 +240,17 @@ macro fetch_div(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT) return old_value; } -/** - * @param [&in] ptr "the variable or dereferenced pointer to the data." - * @param [in] y "the value to be added to ptr." - * @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" - * @return "returns the old value of ptr" - * - * @require !$alignment || math::is_power_of_2($alignment) "Alignment must be a power of two." - * @require types::is_int($typeof(*ptr)) "Only integer pointers may be used." - * @require types::is_int($typeof(y)) "The value for or must be an int" - * @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - **/ +<* + @param [&in] ptr "the variable or dereferenced pointer to the data." + @param [in] y "the value to be added to ptr." + @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" + @return "returns the old value of ptr" + + @require !$alignment || math::is_power_of_2($alignment) "Alignment must be a power of two." + @require types::is_int($typeof(*ptr)) "Only integer pointers may be used." + @require types::is_int($typeof(y)) "The value for or must be an int" + @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." +*> macro fetch_or(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile = false, usz $alignment = 0) { $if types::is_int($typeof(*ptr)): @@ -283,17 +283,17 @@ macro fetch_or(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile return old_value; } -/** - * @param [&in] ptr "the variable or dereferenced pointer to the data." - * @param [in] y "the value to be added to ptr." - * @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" - * @return "returns the old value of ptr" - * - * @require !$alignment || math::is_power_of_2($alignment) "Alignment must be a power of two." - * @require types::is_int($typeof(*ptr)) "Only integer pointers may be used." - * @require types::is_int($typeof(y)) "The value for or must be an int" - * @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - **/ +<* + @param [&in] ptr "the variable or dereferenced pointer to the data." + @param [in] y "the value to be added to ptr." + @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" + @return "returns the old value of ptr" + + @require !$alignment || math::is_power_of_2($alignment) "Alignment must be a power of two." + @require types::is_int($typeof(*ptr)) "Only integer pointers may be used." + @require types::is_int($typeof(y)) "The value for or must be an int" + @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." +*> macro fetch_xor(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile = false, usz $alignment = 0) { $if types::is_int($typeof(*ptr)): @@ -326,17 +326,17 @@ macro fetch_xor(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatil return old_value; } -/** - * @param [&in] ptr "the variable or dereferenced pointer to the data." - * @param [in] y "the value to be added to ptr." - * @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" - * @return "returns the old value of ptr" - * - * @require !$alignment || math::is_power_of_2($alignment) "Alignment must be a power of two." - * @require types::is_int($typeof(*ptr)) "Only integer pointers may be used." - * @require types::is_int($typeof(y)) "The value for or must be an int" - * @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - **/ +<* + @param [&in] ptr "the variable or dereferenced pointer to the data." + @param [in] y "the value to be added to ptr." + @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" + @return "returns the old value of ptr" + + @require !$alignment || math::is_power_of_2($alignment) "Alignment must be a power of two." + @require types::is_int($typeof(*ptr)) "Only integer pointers may be used." + @require types::is_int($typeof(y)) "The value for or must be an int" + @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." +*> macro fetch_and(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile = false, usz $alignment = 0) { $if types::is_int($typeof(*ptr)): @@ -369,16 +369,16 @@ macro fetch_and(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatil return old_value; } -/** - * @param [&in] ptr "the variable or dereferenced pointer to the data." - * @param [in] y "the value to be added to ptr." - * @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" - * @return "returns the old value of ptr" - * - * @require types::is_int($typeof(*ptr)) "Only integer pointers may be used." - * @require types::is_int($typeof(y)) "The value for or must be an int" - * @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - **/ +<* + @param [&in] ptr "the variable or dereferenced pointer to the data." + @param [in] y "the value to be added to ptr." + @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" + @return "returns the old value of ptr" + + @require types::is_int($typeof(*ptr)) "Only integer pointers may be used." + @require types::is_int($typeof(y)) "The value for or must be an int" + @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." +*> macro fetch_shift_right(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT) { var $load_ordering = $ordering; @@ -407,16 +407,16 @@ macro fetch_shift_right(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT) return old_value; } -/** - * @param [&in] ptr "the variable or dereferenced pointer to the data." - * @param [in] y "the value to be added to ptr." - * @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" - * @return "returns the old value of ptr" - * - * @require types::is_int($typeof(*ptr)) "Only integer pointers may be used." - * @require types::is_int($typeof(y)) "The value for or must be an int" - * @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - **/ +<* + @param [&in] ptr "the variable or dereferenced pointer to the data." + @param [in] y "the value to be added to ptr." + @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" + @return "returns the old value of ptr" + + @require types::is_int($typeof(*ptr)) "Only integer pointers may be used." + @require types::is_int($typeof(y)) "The value for or must be an int" + @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." +*> macro fetch_shift_left(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT) { var $load_ordering = $ordering; @@ -445,14 +445,14 @@ macro fetch_shift_left(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT) return old_value; } -/** - * @param [&in] ptr "the variable or dereferenced pointer to the data." - * @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" - * @return "returns the old value of ptr" - * - * @require types::is_int($typeof(*ptr)) "Only integer pointers may be used." - * @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - **/ +<* + @param [&in] ptr "the variable or dereferenced pointer to the data." + @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" + @return "returns the old value of ptr" + + @require types::is_int($typeof(*ptr)) "Only integer pointers may be used." + @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." +*> macro flag_set(ptr, AtomicOrdering $ordering = SEQ_CONSISTENT) { $typeof(*ptr) old_value; @@ -465,14 +465,14 @@ macro flag_set(ptr, AtomicOrdering $ordering = SEQ_CONSISTENT) return old_value; } -/** - * @param [&in] ptr "the variable or dereferenced pointer to the data." - * @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" - * @return "returns the old value of ptr" - * - * @require types::is_int($typeof(*ptr)) "Only integer pointers may be used." - * @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - **/ +<* + @param [&in] ptr "the variable or dereferenced pointer to the data." + @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" + @return "returns the old value of ptr" + + @require types::is_int($typeof(*ptr)) "Only integer pointers may be used." + @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." +*> macro flag_clear(ptr, AtomicOrdering $ordering = SEQ_CONSISTENT) { $typeof(*ptr) old_value; @@ -485,15 +485,15 @@ macro flag_clear(ptr, AtomicOrdering $ordering = SEQ_CONSISTENT) return old_value; } -/** - * @param [&in] ptr "the variable or dereferenced pointer to the data." - * @param [in] y "the value to be added to ptr." - * @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" - * @return "returns the old value of ptr" - * - * @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used." - * @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - **/ +<* + @param [&in] ptr "the variable or dereferenced pointer to the data." + @param [in] y "the value to be added to ptr." + @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" + @return "returns the old value of ptr" + + @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used." + @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." +*> macro fetch_max(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile = false, usz $alignment = 0) { $if $alignment == 0: @@ -502,15 +502,15 @@ macro fetch_max(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatil return $$atomic_fetch_max(ptr, y, $volatile, $ordering.ordinal, $alignment); } -/** - * @param [&in] ptr "the variable or dereferenced pointer to the data." - * @param [in] y "the value to be added to ptr." - * @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" - * @return "returns the old value of ptr" - * - * @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used." - * @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - **/ +<* + @param [&in] ptr "the variable or dereferenced pointer to the data." + @param [in] y "the value to be added to ptr." + @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" + @return "returns the old value of ptr" + + @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used." + @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid." +*> macro fetch_min(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile = false, usz $alignment = 0) { $if $alignment == 0: diff --git a/lib/std/bits.c3 b/lib/std/bits.c3 index 1be9b18ae..3a1a59eab 100644 --- a/lib/std/bits.c3 +++ b/lib/std/bits.c3 @@ -1,13 +1,13 @@ module std::bits; -/** - * @require types::is_intlike($typeof(i)) `The input must be an integer or integer vector` - **/ +<* + @require types::is_intlike($typeof(i)) `The input must be an integer or integer vector` +*> macro reverse(i) => $$bitreverse(i); -/** - * @require types::is_intlike($typeof(i)) `The input must be an integer or integer vector` - **/ +<* + @require types::is_intlike($typeof(i)) `The input must be an integer or integer vector` +*> macro bswap(i) @builtin => $$bswap(i); macro uint[<*>].popcount(self) => $$popcount(self); diff --git a/lib/std/collections/anylist.c3 b/lib/std/collections/anylist.c3 index 95a6653de..18ba0554c 100644 --- a/lib/std/collections/anylist.c3 +++ b/lib/std/collections/anylist.c3 @@ -16,19 +16,20 @@ struct AnyList (Printable) } -/** - * @param initial_capacity "The initial capacity to reserve" - * Use `init` for to use a custom allocator. - **/ +<* + Use `init` for to use a custom allocator. + + @param initial_capacity "The initial capacity to reserve" +*> fn AnyList* AnyList.new_init(&self, usz initial_capacity = 16, Allocator allocator = null) { return self.init(allocator ?: allocator::heap(), initial_capacity) @inline; } -/** - * @param [&inout] allocator "The allocator to use" - * @param initial_capacity "The initial capacity to reserve" - **/ +<* + @param [&inout] allocator "The allocator to use" + @param initial_capacity "The initial capacity to reserve" +*> fn AnyList* AnyList.init(&self, Allocator allocator, usz initial_capacity = 16) { self.allocator = allocator; @@ -46,11 +47,11 @@ fn AnyList* AnyList.init(&self, Allocator allocator, usz initial_capacity = 16) return self; } -/** - * Initialize the list using the temp allocator. - * - * @param initial_capacity "The initial capacity to reserve" - **/ +<* + Initialize the list using the temp allocator. + + @param initial_capacity "The initial capacity to reserve" +*> fn AnyList* AnyList.temp_init(&self, usz initial_capacity = 16) { return self.init(allocator::temp(), initial_capacity) @inline; @@ -89,9 +90,9 @@ fn String AnyList.to_string(&self, Allocator allocator) @dynamic fn String AnyList.to_tstring(&self) => string::tformat("%s", *self); -/** - * Push an element on the list by cloning it. - **/ +<* + Push an element on the list by cloning it. +*> macro void AnyList.push(&self, element) { if (!self.allocator) self.allocator = allocator::heap(); @@ -104,20 +105,20 @@ fn void AnyList.append_internal(&self, any element) @local self.entries[self.size++] = element; } -/** - * Free a retained element removed using *_retained. - **/ +<* + Free a retained element removed using *_retained. +*> fn void AnyList.free_element(&self, any element) @inline { allocator::free(self.allocator, element.ptr); } -/** - * Pop a value who's type is known. If the type is incorrect, this - * will still pop the element. - * - * @return! CastResult.TYPE_MISMATCH, IteratorResult.NO_MORE_ELEMENT - **/ +<* + Pop a value who's type is known. If the type is incorrect, this + will still pop the element. + + @return! CastResult.TYPE_MISMATCH, IteratorResult.NO_MORE_ELEMENT +*> macro AnyList.pop(&self, $Type) { if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; @@ -125,10 +126,10 @@ macro AnyList.pop(&self, $Type) return *anycast(self.entries[--self.size], $Type); } -/** - * Pop the last value and allocate the copy using the given allocator. - * @return! IteratorResult.NO_MORE_ELEMENT - **/ +<* + Pop the last value and allocate the copy using the given allocator. + @return! IteratorResult.NO_MORE_ELEMENT +*> fn any! AnyList.copy_pop(&self, Allocator allocator = allocator::heap()) { if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; @@ -136,33 +137,33 @@ fn any! AnyList.copy_pop(&self, Allocator allocator = allocator::heap()) return allocator::clone_any(allocator, self.entries[--self.size]); } -/** - * Pop the last value and allocate the copy using the given allocator. - * @return! IteratorResult.NO_MORE_ELEMENT - * @deprecated `use copy_pop` - **/ +<* + Pop the last value and allocate the copy using the given allocator. + @return! IteratorResult.NO_MORE_ELEMENT + @deprecated `use copy_pop` +*> fn any! AnyList.new_pop(&self, Allocator allocator = allocator::heap()) { return self.copy_pop(allocator); } -/** - * Pop the last value and allocate the copy using the temp allocator - * @return! IteratorResult.NO_MORE_ELEMENT - * @deprecated `use tcopy_pop` - **/ +<* + Pop the last value and allocate the copy using the temp allocator + @return! IteratorResult.NO_MORE_ELEMENT + @deprecated `use tcopy_pop` +*> fn any! AnyList.temp_pop(&self) => self.copy_pop(allocator::temp()); -/** - * Pop the last value and allocate the copy using the temp allocator - * @return! IteratorResult.NO_MORE_ELEMENT - **/ +<* + Pop the last value and allocate the copy using the temp allocator + @return! IteratorResult.NO_MORE_ELEMENT +*> fn any! AnyList.tcopy_pop(&self) => self.copy_pop(allocator::temp()); -/** - * Pop the last value. It must later be released using list.free_element() - * @return! IteratorResult.NO_MORE_ELEMENT - **/ +<* + Pop the last value. It must later be released using list.free_element() + @return! IteratorResult.NO_MORE_ELEMENT +*> fn any! AnyList.pop_retained(&self) { if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; @@ -178,9 +179,9 @@ fn void AnyList.clear(&self) self.size = 0; } -/** - * Same as pop() but pops the first value instead. - **/ +<* + Same as pop() but pops the first value instead. +*> macro AnyList.pop_first(&self, $Type) { if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; @@ -188,9 +189,9 @@ macro AnyList.pop_first(&self, $Type) return *anycast(self.entries[0], $Type); } -/** - * Same as pop_retained() but pops the first value instead. - **/ +<* + Same as pop_retained() but pops the first value instead. +*> fn any! AnyList.pop_first_retained(&self) { if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; @@ -198,18 +199,18 @@ fn any! AnyList.pop_first_retained(&self) return self.entries[0]; } -/** - * Same as new_pop() but pops the first value instead. - * @deprecated `use copy_pop_first` - **/ +<* + Same as new_pop() but pops the first value instead. + @deprecated `use copy_pop_first` +*> fn any! AnyList.new_pop_first(&self, Allocator allocator = allocator::heap()) { return self.copy_pop_first(allocator) @inline; } -/** - * Same as new_pop() but pops the first value instead. - **/ +<* + Same as new_pop() but pops the first value instead. +*> fn any! AnyList.copy_pop_first(&self, Allocator allocator = allocator::heap()) { if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; @@ -218,20 +219,20 @@ fn any! AnyList.copy_pop_first(&self, Allocator allocator = allocator::heap()) return allocator::clone_any(allocator, self.entries[0]); } -/** - * Same as temp_pop() but pops the first value instead. - **/ +<* + Same as temp_pop() but pops the first value instead. +*> fn any! AnyList.tcopy_pop_first(&self) => self.copy_pop_first(allocator::temp()); -/** - * Same as temp_pop() but pops the first value instead. - * @deprecated `use tcopy_pop_first` - **/ +<* + Same as temp_pop() but pops the first value instead. + @deprecated `use tcopy_pop_first` +*> fn any! AnyList.temp_pop_first(&self) => self.new_pop_first(allocator::temp()); -/** - * @require index < self.size - **/ +<* + @require index < self.size +*> fn void AnyList.remove_at(&self, usz index) { if (!--self.size || index == self.size) return; @@ -249,9 +250,9 @@ fn void AnyList.add_all(&self, AnyList* other_list) } } -/** - * Reverse the elements in a list. - **/ +<* + Reverse the elements in a list. +*> fn void AnyList.reverse(&self) { if (self.size < 2) return; @@ -268,26 +269,26 @@ fn any[] AnyList.array_view(&self) return self.entries[:self.size]; } -/** - * Push an element to the front of the list. - **/ +<* + Push an element to the front of the list. +*> macro void AnyList.push_front(&self, type) { self.insert_at(0, type); } -/** - * @require index < self.size - **/ +<* + @require index < self.size +*> macro void AnyList.insert_at(&self, usz index, type) @local { any value = allocator::copy(self.allocator, type); self.insert_at_internal(self, index, value); } -/** - * @require index < self.size - **/ +<* + @require index < self.size +*> fn void AnyList.insert_at_internal(&self, usz index, any value) @local { self.ensure_capacity(); @@ -300,17 +301,17 @@ fn void AnyList.insert_at_internal(&self, usz index, any value) @local } -/** - * @require self.size > 0 - **/ +<* + @require self.size > 0 +*> fn void AnyList.remove_last(&self) { self.free_element(self.entries[--self.size]); } -/** - * @require self.size > 0 - **/ +<* + @require self.size > 0 +*> fn void AnyList.remove_first(&self) { self.remove_at(0); @@ -346,17 +347,17 @@ fn usz AnyList.len(&self) @operator(len) @inline return self.size; } -/** - * @require index < self.size "Index out of range" - **/ +<* + @require index < self.size "Index out of range" +*> macro AnyList.get(&self, usz index, $Type) { return *anycast(self.entries[index], $Type); } -/** - * @require index < self.size "Index out of range" - **/ +<* + @require index < self.size "Index out of range" +*> fn any AnyList.get_any(&self, usz index) @inline { return self.entries[index]; @@ -378,19 +379,19 @@ fn void AnyList.swap(&self, usz i, usz j) self.entries[j] = temp; } -/** - * @param filter "The function to determine if it should be removed or not" - * @return "the number of deleted elements" - **/ +<* + @param filter "The function to determine if it should be removed or not" + @return "the number of deleted elements" +*> fn usz AnyList.remove_if(&self, AnyPredicate filter) { return self._remove_if(filter, false); } -/** - * @param selection "The function to determine if it should be kept or not" - * @return "the number of deleted elements" - **/ +<* + @param selection "The function to determine if it should be kept or not" + @return "the number of deleted elements" +*> fn usz AnyList.retain_if(&self, AnyPredicate selection) { return self._remove_if(selection, true); @@ -458,9 +459,9 @@ macro usz AnyList._remove_using_test(&self, AnyTest filter, bool $invert, ctx) @ return size - self.size; } -/** - * Reserve at least min_capacity - **/ +<* + Reserve at least min_capacity +*> fn void AnyList.reserve(&self, usz min_capacity) { if (!min_capacity) return; @@ -476,9 +477,9 @@ macro any AnyList.@item_at(&self, usz index) @operator([]) return self.entries[index]; } -/** - * @require index <= self.size "Index out of range" - **/ +<* + @require index <= self.size "Index out of range" +*> macro void AnyList.set(&self, usz index, value) { if (index == self.size) diff --git a/lib/std/collections/bitset.c3 b/lib/std/collections/bitset.c3 index 6ea47cf47..99a58d875 100644 --- a/lib/std/collections/bitset.c3 +++ b/lib/std/collections/bitset.c3 @@ -1,6 +1,6 @@ -/** - * @require SIZE > 0 - **/ +<* + @require SIZE > 0 +*> module std::collections::bitset(); def Type = uint; @@ -23,9 +23,9 @@ fn usz BitSet.cardinality(&self) return n; } -/** - * @require i < SIZE - **/ +<* + @require i < SIZE +*> fn void BitSet.set(&self, usz i) { usz q = i / BITS; @@ -33,9 +33,9 @@ fn void BitSet.set(&self, usz i) self.data[q] |= 1 << r; } -/** - * @require i < SIZE - **/ +<* + @require i < SIZE +*> fn void BitSet.unset(&self, usz i) { usz q = i / BITS; @@ -43,9 +43,9 @@ fn void BitSet.unset(&self, usz i) self.data[q] &= ~(1 << r); } -/** - * @require i < SIZE - **/ +<* + @require i < SIZE +*> fn bool BitSet.get(&self, usz i) @operator([]) @inline { usz q = i / BITS; @@ -58,18 +58,18 @@ fn usz BitSet.len(&self) @operator(len) @inline return SZ * BITS; } -/** - * @require i < SIZE - **/ +<* + @require i < SIZE +*> fn void BitSet.set_bool(&self, usz i, bool value) @operator([]=) @inline { if (value) return self.set(i); self.unset(i); } -/** - * @require Type.kindof == UNSIGNED_INT - **/ +<* + @require Type.kindof == UNSIGNED_INT +*> module std::collections::growablebitset(); import std::collections::list; @@ -82,10 +82,10 @@ struct GrowableBitSet GrowableBitSetList data; } -/** - * @param initial_capacity - * @param [&inout] allocator "The allocator to use, defaults to the heap allocator" - **/ +<* + @param initial_capacity + @param [&inout] allocator "The allocator to use, defaults to the heap allocator" +*> fn GrowableBitSet* GrowableBitSet.new_init(&self, usz initial_capacity = 1, Allocator allocator = allocator::heap()) { self.data.new_init(initial_capacity, allocator); diff --git a/lib/std/collections/elastic_array.c3 b/lib/std/collections/elastic_array.c3 index 7a38da86a..db4e45aeb 100644 --- a/lib/std/collections/elastic_array.c3 +++ b/lib/std/collections/elastic_array.c3 @@ -1,9 +1,9 @@ // Copyright (c) 2021-2024 Christoffer Lerno. All rights reserved. // Use of self source code is governed by the MIT license // a copy of which can be found in the LICENSE_STDLIB file. -/** - * @require MAX_SIZE >= 1 `The size must be at least 1 element big.` - **/ +<* + @require MAX_SIZE >= 1 `The size must be at least 1 element big.` +*> module std::collections::elastic_array(); import std::io, std::math, std::collections::list_common; @@ -60,9 +60,9 @@ fn void! ElasticArray.push_try(&self, Type element) @inline self.entries[self.size++] = element; } -/** - * @require self.size < MAX_SIZE `Tried to exceed the max size` - **/ +<* + @require self.size < MAX_SIZE `Tried to exceed the max size` +*> fn void ElasticArray.push(&self, Type element) @inline { self.entries[self.size++] = element; @@ -79,9 +79,9 @@ fn void ElasticArray.clear(&self) self.size = 0; } -/** - * @require self.size > 0 - **/ +<* + @require self.size > 0 +*> fn Type! ElasticArray.pop_first(&self) { if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; @@ -89,18 +89,18 @@ fn Type! ElasticArray.pop_first(&self) return self.entries[0]; } -/** - * @require index < self.size - **/ +<* + @require index < self.size +*> fn void ElasticArray.remove_at(&self, usz index) { if (!--self.size || index == self.size) return; self.entries[index .. self.size - 1] = self.entries[index + 1 .. self.size]; } -/** - * @require other_list.size + self.size <= MAX_SIZE - **/ +<* + @require other_list.size + self.size <= MAX_SIZE +*> fn void ElasticArray.add_all(&self, ElasticArray* other_list) { if (!other_list.size) return; @@ -110,10 +110,10 @@ fn void ElasticArray.add_all(&self, ElasticArray* other_list) } } -/** - * Add as many elements as possible to the new array, - * returning the number of elements that didn't fit. - **/ +<* + Add as many elements as possible to the new array, + returning the number of elements that didn't fit. +*> fn usz ElasticArray.add_all_to_limit(&self, ElasticArray* other_list) { if (!other_list.size) return 0; @@ -125,12 +125,12 @@ fn usz ElasticArray.add_all_to_limit(&self, ElasticArray* other_list) return 0; } -/** - * Add as many values from this array as possible, returning the - * number of elements that didn't fit. - * - * @param [in] array - **/ +<* + Add as many values from this array as possible, returning the + number of elements that didn't fit. + + @param [in] array +*> fn usz ElasticArray.add_array_to_limit(&self, Type[] array) { if (!array.len) return 0; @@ -142,13 +142,13 @@ fn usz ElasticArray.add_array_to_limit(&self, Type[] array) return 0; } -/** - * Add the values of an array to this list. - * - * @param [in] array - * @require array.len + self.size <= MAX_SIZE `Size would exceed max.` - * @ensure self.size >= array.len - **/ +<* + Add the values of an array to this list. + + @param [in] array + @require array.len + self.size <= MAX_SIZE `Size would exceed max.` + @ensure self.size >= array.len +*> fn void ElasticArray.add_array(&self, Type[] array) { if (!array.len) return; @@ -160,33 +160,33 @@ fn void ElasticArray.add_array(&self, Type[] array) -/** - * IMPORTANT The returned array must be freed using free_aligned. - **/ +<* + IMPORTANT The returned array must be freed using free_aligned. +*> fn Type[] ElasticArray.to_new_aligned_array(&self) { return list_common::list_to_new_aligned_array(Type, self, allocator::heap()); } -/** - * IMPORTANT The returned array must be freed using free_aligned. - **/ +<* + IMPORTANT The returned array must be freed using free_aligned. +*> fn Type[] ElasticArray.to_aligned_array(&self, Allocator allocator) { return list_common::list_to_new_aligned_array(Type, self, allocator); } -/** - * @require !type_is_overaligned() : "This function is not available on overaligned types" - **/ +<* + @require !type_is_overaligned() : "This function is not available on overaligned types" +*> macro Type[] ElasticArray.to_new_array(&self) { return list_common::list_to_array(Type, self, allocator::heap()); } -/** - * @require !type_is_overaligned() : "This function is not available on overaligned types" - **/ +<* + @require !type_is_overaligned() : "This function is not available on overaligned types" +*> macro Type[] ElasticArray.to_array(&self, Allocator allocator) { return list_common::list_to_new_array(Type, self, allocator); @@ -201,9 +201,9 @@ fn Type[] ElasticArray.to_tarray(&self) $endif; } -/** - * Reverse the elements in a list. - **/ +<* + Reverse the elements in a list. +*> fn void ElasticArray.reverse(&self) { list_common::list_reverse(self); @@ -214,35 +214,35 @@ fn Type[] ElasticArray.array_view(&self) return self.entries[:self.size]; } -/** - * @require self.size < MAX_SIZE `List would exceed max size` - **/ +<* + @require self.size < MAX_SIZE `List would exceed max size` +*> fn void ElasticArray.push_front(&self, Type type) @inline { self.insert_at(0, type); } -/** - * @require self.size < MAX_SIZE `List would exceed max size` - **/ +<* + @require self.size < MAX_SIZE `List would exceed max size` +*> fn void! ElasticArray.push_front_try(&self, Type type) @inline { return self.insert_at_try(0, type); } -/** - * @require index <= self.size - **/ +<* + @require index <= self.size +*> fn void! ElasticArray.insert_at_try(&self, usz index, Type value) { if (self.size == MAX_SIZE) return AllocationFailure.OUT_OF_MEMORY?; self.insert_at(index, value); } -/** - * @require self.size < MAX_SIZE `List would exceed max size` - * @require index <= self.size - **/ +<* + @require self.size < MAX_SIZE `List would exceed max size` + @require index <= self.size +*> fn void ElasticArray.insert_at(&self, usz index, Type type) { for (usz i = self.size; i > index; i--) @@ -253,9 +253,9 @@ fn void ElasticArray.insert_at(&self, usz index, Type type) self.entries[index] = type; } -/** - * @require index < self.size - **/ +<* + @require index < self.size +*> fn void ElasticArray.set_at(&self, usz index, Type type) { self.entries[index] = type; @@ -310,19 +310,19 @@ fn void ElasticArray.swap(&self, usz i, usz j) @swap(self.entries[i], self.entries[j]); } -/** - * @param filter "The function to determine if it should be removed or not" - * @return "the number of deleted elements" - **/ +<* + @param filter "The function to determine if it should be removed or not" + @return "the number of deleted elements" +*> fn usz ElasticArray.remove_if(&self, ElementPredicate filter) { return list_common::list_remove_if(self, filter, false); } -/** - * @param selection "The function to determine if it should be kept or not" - * @return "the number of deleted elements" - **/ +<* + @param selection "The function to determine if it should be kept or not" + @return "the number of deleted elements" +*> fn usz ElasticArray.retain_if(&self, ElementPredicate selection) { return list_common::list_remove_if(self, selection, true); @@ -384,13 +384,13 @@ fn bool ElasticArray.equals(&self, ElasticArray other_list) @if(ELEMENT_IS_EQUAT return true; } -/** - * Check for presence of a value in a list. - * - * @param [&in] self "the list to find elements in" - * @param value "The value to search for" - * @return "True if the value is found, false otherwise" - **/ +<* + Check for presence of a value in a list. + + @param [&in] self "the list to find elements in" + @param value "The value to search for" + @return "True if the value is found, false otherwise" +*> fn bool ElasticArray.contains(&self, Type value) @if(ELEMENT_IS_EQUATABLE) { foreach (i, v : self) @@ -400,31 +400,31 @@ fn bool ElasticArray.contains(&self, Type value) @if(ELEMENT_IS_EQUATABLE) return false; } -/** - * @param [&inout] self "The list to remove elements from" - * @param value "The value to remove" - * @return "true if the value was found" - **/ +<* + @param [&inout] self "The list to remove elements from" + @param value "The value to remove" + @return "true if the value was found" +*> fn bool ElasticArray.remove_last_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE) { return @ok(self.remove_at(self.rindex_of(value))); } -/** - * @param [&inout] self "The list to remove elements from" - * @param value "The value to remove" - * @return "true if the value was found" - **/ +<* + @param [&inout] self "The list to remove elements from" + @param value "The value to remove" + @return "true if the value was found" +*> fn bool ElasticArray.remove_first_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE) { return @ok(self.remove_at(self.index_of(value))); } -/** - * @param [&inout] self "The list to remove elements from" - * @param value "The value to remove" - * @return "the number of deleted elements." - **/ +<* + @param [&inout] self "The list to remove elements from" + @param value "The value to remove" + @return "the number of deleted elements." +*> fn usz ElasticArray.remove_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE) { return list_common::list_remove_item(self, value); @@ -438,10 +438,10 @@ fn void ElasticArray.remove_all_from(&self, ElasticArray* other_list) @if(ELEMEN foreach (v : other_list) self.remove_item(v); } -/** - * @param [&in] self - * @return "The number non-null values in the list" - **/ +<* + @param [&in] self + @return "The number non-null values in the list" +*> fn usz ElasticArray.compact_count(&self) @if(ELEMENT_IS_POINTER) { usz vals = 0; diff --git a/lib/std/collections/enummap.c3 b/lib/std/collections/enummap.c3 index 9338b0d9d..a41d4cd24 100644 --- a/lib/std/collections/enummap.c3 +++ b/lib/std/collections/enummap.c3 @@ -1,6 +1,6 @@ -/** - * @require Enum.kindof == TypeKind.ENUM : "Only enums may be used with an enummap" - **/ +<* + @require Enum.kindof == TypeKind.ENUM : "Only enums may be used with an enummap" +*> module std::collections::enummap(); import std::io; struct EnumMap (Printable) @@ -43,18 +43,18 @@ fn String EnumMap.to_tstring(&self) @dynamic return string::tformat("%s", *self); } -/** - * @return "The total size of this map, which is the same as the number of enum values" - * @pure - **/ +<* + @return "The total size of this map, which is the same as the number of enum values" + @pure +*> fn usz EnumMap.len(&self) @operator(len) @inline { return self.values.len; } -/** - * @return "Retrieve a value given the underlying enum, if there is no entry, then the zero value for the value is returned." - **/ +<* + @return "Retrieve a value given the underlying enum, if there is no entry, then the zero value for the value is returned." +*> fn ValueType EnumMap.get(&self, Enum key) @operator([]) @inline { return self.values[key.ordinal]; diff --git a/lib/std/collections/enumset.c3 b/lib/std/collections/enumset.c3 index e99435e1b..fcd656629 100644 --- a/lib/std/collections/enumset.c3 +++ b/lib/std/collections/enumset.c3 @@ -2,9 +2,9 @@ // Use of self source code is governed by the MIT license // a copy of which can be found in the LICENSE_STDLIB file. -/** - * @require Enum.kindof == TypeKind.ENUM : "Only enums may be used with an enumset" - **/ +<* + @require Enum.kindof == TypeKind.ENUM : "Only enums may be used with an enumset" +*> module std::collections::enumset(); import std::io; diff --git a/lib/std/collections/hashmap.c3 b/lib/std/collections/hashmap.c3 index c085a6f8a..8f0c446fd 100644 --- a/lib/std/collections/hashmap.c3 +++ b/lib/std/collections/hashmap.c3 @@ -13,25 +13,25 @@ struct HashMap float load_factor; } -/** - * @param [&inout] allocator "The allocator to use" - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require !self.allocator "Map was already initialized" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ +<* + @param [&inout] allocator "The allocator to use" + @require capacity > 0 "The capacity must be 1 or higher" + @require load_factor > 0.0 "The load factor must be higher than 0" + @require !self.allocator "Map was already initialized" + @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" +*> fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = null) { return self.init(allocator ?: allocator::heap(), capacity, load_factor); } -/** - * @param [&inout] allocator "The allocator to use" - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require !self.allocator "Map was already initialized" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ +<* + @param [&inout] allocator "The allocator to use" + @require capacity > 0 "The capacity must be 1 or higher" + @require load_factor > 0.0 "The load factor must be higher than 0" + @require !self.allocator "Map was already initialized" + @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" +*> fn HashMap* HashMap.init(&self, Allocator allocator, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR) { capacity = math::next_power_of_2(capacity); @@ -42,25 +42,25 @@ fn HashMap* HashMap.init(&self, Allocator allocator, uint capacity = DEFAULT_INI return self; } -/** - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require !self.allocator "Map was already initialized" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ +<* + @require capacity > 0 "The capacity must be 1 or higher" + @require load_factor > 0.0 "The load factor must be higher than 0" + @require !self.allocator "Map was already initialized" + @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" +*> fn HashMap* HashMap.temp_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR) { return self.init(allocator::temp(), capacity, load_factor) @inline; } -/** - * @param [&inout] allocator "The allocator to use" - * @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values" - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require !self.allocator "Map was already initialized" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ +<* + @param [&inout] allocator "The allocator to use" + @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values" + @require capacity > 0 "The capacity must be 1 or higher" + @require load_factor > 0.0 "The load factor must be higher than 0" + @require !self.allocator "Map was already initialized" + @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" +*> macro HashMap* HashMap.new_init_with_key_values(&self, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap()) { self.new_init(capacity, load_factor, allocator); @@ -70,16 +70,16 @@ macro HashMap* HashMap.new_init_with_key_values(&self, ..., uint capacity = DEFA return self; } -/** - * @param [in] keys "The keys for the HashMap entries" - * @param [in] values "The values for the HashMap entries" - * @param [&inout] allocator "The allocator to use" - * @require keys.len == values.len "Both keys and values arrays must be the same length" - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require !self.allocator "Map was already initialized" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ +<* + @param [in] keys "The keys for the HashMap entries" + @param [in] values "The values for the HashMap entries" + @param [&inout] allocator "The allocator to use" + @require keys.len == values.len "Both keys and values arrays must be the same length" + @require capacity > 0 "The capacity must be 1 or higher" + @require load_factor > 0.0 "The load factor must be higher than 0" + @require !self.allocator "Map was already initialized" + @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" +*> fn HashMap* HashMap.new_init_from_keys_and_values(&self, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap()) { assert(keys.len == values.len); @@ -91,13 +91,13 @@ fn HashMap* HashMap.new_init_from_keys_and_values(&self, Key[] keys, Value[] val return self; } -/** - * @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values" - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require !self.allocator "Map was already initialized" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ +<* + @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values" + @require capacity > 0 "The capacity must be 1 or higher" + @require load_factor > 0.0 "The load factor must be higher than 0" + @require !self.allocator "Map was already initialized" + @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" +*> macro HashMap* HashMap.temp_init_with_key_values(&self, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR) { self.temp_init(capacity, load_factor); @@ -107,16 +107,16 @@ macro HashMap* HashMap.temp_init_with_key_values(&self, ..., uint capacity = DEF return self; } -/** - * @param [in] keys "The keys for the HashMap entries" - * @param [in] values "The values for the HashMap entries" - * @param [&inout] allocator "The allocator to use" - * @require keys.len == values.len "Both keys and values arrays must be the same length" - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require !self.allocator "Map was already initialized" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ +<* + @param [in] keys "The keys for the HashMap entries" + @param [in] values "The values for the HashMap entries" + @param [&inout] allocator "The allocator to use" + @require keys.len == values.len "Both keys and values arrays must be the same length" + @require capacity > 0 "The capacity must be 1 or higher" + @require load_factor > 0.0 "The load factor must be higher than 0" + @require !self.allocator "Map was already initialized" + @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" +*> fn HashMap* HashMap.temp_init_from_keys_and_values(&self, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap()) { assert(keys.len == values.len); @@ -128,29 +128,29 @@ fn HashMap* HashMap.temp_init_from_keys_and_values(&self, Key[] keys, Value[] va return self; } -/** - * Has this hash map been initialized yet? - * - * @param [&in] map "The hash map we are testing" - * @return "Returns true if it has been initialized, false otherwise" - **/ +<* + Has this hash map been initialized yet? + + @param [&in] map "The hash map we are testing" + @return "Returns true if it has been initialized, false otherwise" +*> fn bool HashMap.is_initialized(&map) { return (bool)map.allocator; } -/** - * @param [&in] other_map "The map to copy from." - **/ +<* + @param [&in] other_map "The map to copy from." +*> fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map) { return self.init_from_map(other_map, allocator::heap()) @inline; } -/** - * @param [&inout] allocator "The allocator to use" - * @param [&in] other_map "The map to copy from." - **/ +<* + @param [&inout] allocator "The allocator to use" + @param [&in] other_map "The map to copy from." +*> fn HashMap* HashMap.init_from_map(&self, HashMap* other_map, Allocator allocator) { self.new_init(other_map.table.len, other_map.load_factor, allocator); @@ -158,9 +158,9 @@ fn HashMap* HashMap.init_from_map(&self, HashMap* other_map, Allocator allocator return self; } -/** - * @param [&in] other_map "The map to copy from." - **/ +<* + @param [&in] other_map "The map to copy from." +*> fn HashMap* HashMap.temp_init_from_map(&map, HashMap* other_map) { return map.init_from_map(other_map, allocator::temp()) @inline; @@ -198,10 +198,10 @@ fn Entry*! HashMap.get_entry(&map, Key key) return SearchResult.MISSING?; } -/** - * Get the value or update and - * @require $assignable(#expr, Value) - **/ +<* + Get the value or update and + @require $assignable(#expr, Value) +*> macro Value HashMap.@get_or_set(&map, Key key, Value #expr) { if (!map.count) @@ -295,9 +295,9 @@ fn Key[] HashMap.key_tlist(&map) @deprecated("Use 'tcopy_keys'") return map.copy_keys(allocator::temp()) @inline; } -/** - * @deprecated "use copy_keys" - **/ +<* + @deprecated "use copy_keys" +*> fn Key[] HashMap.key_new_list(&map, Allocator allocator = allocator::heap()) { return map.copy_keys(allocator) @inline; @@ -342,9 +342,9 @@ macro HashMap.@each_entry(map; @body(entry)) } } -/** - * @deprecated `use tcopy_values` - **/ +<* + @deprecated `use tcopy_values` +*> fn Value[] HashMap.value_tlist(&map) { return map.copy_values(allocator::temp()) @inline; @@ -355,9 +355,9 @@ fn Value[] HashMap.tcopy_values(&map) return map.copy_values(allocator::temp()) @inline; } -/** - * @deprecated `use copy_values` - **/ +<* + @deprecated `use copy_values` +*> fn Value[] HashMap.value_new_list(&map, Allocator allocator = allocator::heap()) { return map.copy_values(allocator); diff --git a/lib/std/collections/linkedlist.c3 b/lib/std/collections/linkedlist.c3 index ec20551bd..e6d5e20f3 100644 --- a/lib/std/collections/linkedlist.c3 +++ b/lib/std/collections/linkedlist.c3 @@ -20,19 +20,19 @@ struct LinkedList Node *_last; } -/** - * @param [&inout] allocator "The allocator to use, defaults to the heap allocator" - * @return "the initialized list" - **/ +<* + @param [&inout] allocator "The allocator to use, defaults to the heap allocator" + @return "the initialized list" +*> fn LinkedList* LinkedList.init(&self, Allocator allocator) { *self = { .allocator = allocator }; return self; } -/** - * @return "the initialized list" - **/ +<* + @return "the initialized list" +*> fn LinkedList* LinkedList.new_init(&self) { return self.init(allocator::heap()) @inline; @@ -44,9 +44,9 @@ fn LinkedList* LinkedList.temp_init(&self) return self.init(allocator::temp()) @inline; } -/** - * @require self.allocator - **/ +<* + @require self.allocator +*> macro void LinkedList.free_node(&self, Node* node) @private { allocator::free(self.allocator, node); @@ -124,9 +124,9 @@ fn void LinkedList.clear(&self) fn usz LinkedList.len(&self) @inline => self.size; -/** - * @require index < self.size - **/ +<* + @require index < self.size +*> macro Node* LinkedList.node_at_index(&self, usz index) { if (index * 2 >= self.size) @@ -140,33 +140,33 @@ macro Node* LinkedList.node_at_index(&self, usz index) while (index--) node = node.next; return node; } -/** - * @require index < self.size - **/ +<* + @require index < self.size +*> fn Type LinkedList.get(&self, usz index) { return self.node_at_index(index).value; } -/** - * @require index < self.size - **/ +<* + @require index < self.size +*> fn void LinkedList.set(&self, usz index, Type element) { self.node_at_index(index).value = element; } -/** - * @require index < self.size - **/ +<* + @require index < self.size +*> fn void LinkedList.remove_at(&self, usz index) { self.unlink(self.node_at_index(index)); } -/** - * @require index <= self.size - **/ +<* + @require index <= self.size +*> fn void LinkedList.insert_at(&self, usz index, Type element) { switch (index) @@ -179,9 +179,9 @@ fn void LinkedList.insert_at(&self, usz index, Type element) self.link_before(self.node_at_index(index), element); } } -/** - * @require succ != null - **/ +<* + @require succ != null +*> fn void LinkedList.link_before(&self, Node *succ, Type value) @private { Node* pred = succ.prev; @@ -199,9 +199,9 @@ fn void LinkedList.link_before(&self, Node *succ, Type value) @private self.size++; } -/** - * @require self._first - **/ +<* + @require self._first +*> fn void LinkedList.unlink_first(&self) @private { Node* f = self._first; @@ -290,9 +290,9 @@ fn bool LinkedList.remove_last_match(&self, Type t) @if(ELEMENT_IS_EQUATABLE) } return false; } -/** - * @require self._last - **/ +<* + @require self._last +*> fn void LinkedList.unlink_last(&self) @inline @private { Node* l = self._last; @@ -310,9 +310,9 @@ fn void LinkedList.unlink_last(&self) @inline @private self.size--; } -/** - * @require x != null - **/ +<* + @require x != null +*> fn void LinkedList.unlink(&self, Node* x) @private { Node* next = x.next; diff --git a/lib/std/collections/list.c3 b/lib/std/collections/list.c3 index 8809974a7..1451f517e 100644 --- a/lib/std/collections/list.c3 +++ b/lib/std/collections/list.c3 @@ -19,10 +19,10 @@ struct List (Printable) Type *entries; } -/** - * @param initial_capacity "The initial capacity to reserve" - * @param [&inout] allocator "The allocator to use, defaults to the heap allocator" - **/ +<* + @param initial_capacity "The initial capacity to reserve" + @param [&inout] allocator "The allocator to use, defaults to the heap allocator" +*> fn List* List.new_init(&self, usz initial_capacity = 16, Allocator allocator = allocator::heap()) { self.allocator = allocator; @@ -33,22 +33,22 @@ fn List* List.new_init(&self, usz initial_capacity = 16, Allocator allocator = a return self; } -/** - * Initialize the list using the temp allocator. - * - * @param initial_capacity "The initial capacity to reserve" - **/ +<* + Initialize the list using the temp allocator. + + @param initial_capacity "The initial capacity to reserve" +*> fn List* List.temp_init(&self, usz initial_capacity = 16) { return self.new_init(initial_capacity, allocator::temp()) @inline; } -/** - * Initialize a new list with an array. - * - * @param [in] values `The values to initialize the list with.` - * @require self.size == 0 "The List must be empty" - **/ +<* + Initialize a new list with an array. + + @param [in] values `The values to initialize the list with.` + @require self.size == 0 "The List must be empty" +*> fn List* List.new_init_with_array(&self, Type[] values, Allocator allocator = allocator::heap()) { self.new_init(values.len, allocator) @inline; @@ -56,12 +56,12 @@ fn List* List.new_init_with_array(&self, Type[] values, Allocator allocator = al return self; } -/** - * Initialize a temporary list with an array. - * - * @param [in] values `The values to initialize the list with.` - * @require self.size == 0 "The List must be empty" - **/ +<* + Initialize a temporary list with an array. + + @param [in] values `The values to initialize the list with.` + @require self.size == 0 "The List must be empty" +*> fn List* List.temp_init_with_array(&self, Type[] values) { self.temp_init(values.len) @inline; @@ -69,9 +69,9 @@ fn List* List.temp_init_with_array(&self, Type[] values) return self; } -/** - * @require self.capacity == 0 "The List must not be allocated" - **/ +<* + @require self.capacity == 0 "The List must not be allocated" +*> fn void List.init_wrapping_array(&self, Type[] types, Allocator allocator = allocator::heap()) { self.allocator = allocator; @@ -128,9 +128,9 @@ fn void List.clear(&self) self.set_size(0); } -/** - * @require self.size > 0 - **/ +<* + @require self.size > 0 +*> fn Type! List.pop_first(&self) { if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; @@ -138,9 +138,9 @@ fn Type! List.pop_first(&self) return self.entries[0]; } -/** - * @require index < self.size - **/ +<* + @require index < self.size +*> fn void List.remove_at(&self, usz index) { self.set_size(self.size - 1); @@ -160,17 +160,17 @@ fn void List.add_all(&self, List* other_list) } -/** - * IMPORTANT The returned array must be freed using free_aligned. - **/ +<* + IMPORTANT The returned array must be freed using free_aligned. +*> fn Type[] List.to_new_aligned_array(&self, Allocator allocator = allocator::heap()) { return list_common::list_to_new_aligned_array(Type, self, allocator); } -/** - * @require !type_is_overaligned() : "This function is not available on overaligned types" - **/ +<* + @require !type_is_overaligned() : "This function is not available on overaligned types" +*> macro Type[] List.to_new_array(&self, Allocator allocator = allocator::heap()) { return list_common::list_to_new_array(Type, self, allocator); @@ -185,9 +185,9 @@ fn Type[] List.to_tarray(&self) $endif; } -/** - * Reverse the elements in a list. - **/ +<* + Reverse the elements in a list. +*> fn void List.reverse(&self) { list_common::list_reverse(self); @@ -198,12 +198,12 @@ fn Type[] List.array_view(&self) return self.entries[:self.size]; } -/** - * Add the values of an array to this list. - * - * @param [in] array - * @ensure self.size >= array.len - **/ +<* + Add the values of an array to this list. + + @param [in] array + @ensure self.size >= array.len +*> fn void List.add_array(&self, Type[] array) { if (!array.len) return; @@ -217,9 +217,9 @@ fn void List.push_front(&self, Type type) @inline self.insert_at(0, type); } -/** - * @require index <= self.size - **/ +<* + @require index <= self.size +*> fn void List.insert_at(&self, usz index, Type type) { self.reserve(1); @@ -231,9 +231,9 @@ fn void List.insert_at(&self, usz index, Type type) self.entries[index] = type; } -/** - * @require index < self.size - **/ +<* + @require index < self.size +*> fn void List.set_at(&self, usz index, Type type) { self.entries[index] = type; @@ -304,19 +304,19 @@ fn void List.swap(&self, usz i, usz j) @swap(self.entries[i], self.entries[j]); } -/** - * @param filter "The function to determine if it should be removed or not" - * @return "the number of deleted elements" - **/ +<* + @param filter "The function to determine if it should be removed or not" + @return "the number of deleted elements" +*> fn usz List.remove_if(&self, ElementPredicate filter) { return list_common::list_remove_if(self, filter, false); } -/** - * @param selection "The function to determine if it should be kept or not" - * @return "the number of deleted elements" - **/ +<* + @param selection "The function to determine if it should be kept or not" + @return "the number of deleted elements" +*> fn usz List.retain_if(&self, ElementPredicate selection) { return list_common::list_remove_if(self, selection, true); @@ -395,9 +395,9 @@ fn void List._update_size_change(&self,usz old_size, usz new_size) &self.entries[old_size], &self.entries[new_size]); } -/** - * @require new_size == 0 || self.capacity != 0 - **/ +<* + @require new_size == 0 || self.capacity != 0 +*> fn usz List.set_size(&self, usz new_size) @inline @private { usz old_size = self.size; @@ -412,9 +412,9 @@ macro void List.pre_free(&self) @private self._update_size_change(self.size, self.capacity); } -/** - * @require self.capacity - **/ +<* + @require self.capacity +*> macro void List.post_alloc(&self) @private { self._update_size_change(self.capacity, self.size); @@ -451,13 +451,13 @@ fn bool List.equals(&self, List other_list) @if(ELEMENT_IS_EQUATABLE) return true; } -/** - * Check for presence of a value in a list. - * - * @param [&in] self "the list to find elements in" - * @param value "The value to search for" - * @return "True if the value is found, false otherwise" - **/ +<* + Check for presence of a value in a list. + + @param [&in] self "the list to find elements in" + @param value "The value to search for" + @return "True if the value is found, false otherwise" +*> fn bool List.contains(&self, Type value) @if(ELEMENT_IS_EQUATABLE) { foreach (i, v : self) @@ -467,30 +467,30 @@ fn bool List.contains(&self, Type value) @if(ELEMENT_IS_EQUATABLE) return false; } -/** - * @param [&inout] self "The list to remove elements from" - * @param value "The value to remove" - * @return "true if the value was found" - **/ +<* + @param [&inout] self "The list to remove elements from" + @param value "The value to remove" + @return "true if the value was found" +*> fn bool List.remove_last_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE) { return @ok(self.remove_at(self.rindex_of(value))); } -/** - * @param [&inout] self "The list to remove elements from" - * @param value "The value to remove" - * @return "true if the value was found" - **/ +<* + @param [&inout] self "The list to remove elements from" + @param value "The value to remove" + @return "true if the value was found" +*> fn bool List.remove_first_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE) { return @ok(self.remove_at(self.index_of(value))); } -/** - * @param [&inout] self "The list to remove elements from" - * @param value "The value to remove" - * @return "the number of deleted elements." - **/ +<* + @param [&inout] self "The list to remove elements from" + @param value "The value to remove" + @return "the number of deleted elements." +*> fn usz List.remove_item(&self, Type value) @if(ELEMENT_IS_EQUATABLE) { usz old_size = self.size; @@ -512,10 +512,10 @@ fn void List.remove_all_from(&self, List* other_list) @if(ELEMENT_IS_EQUATABLE) foreach (v : other_list) self.remove_item(v); } -/** - * @param [&in] self - * @return "The number non-null values in the list" - **/ +<* + @param [&in] self + @return "The number non-null values in the list" +*> fn usz List.compact_count(&self) @if(ELEMENT_IS_POINTER) { usz vals = 0; @@ -534,32 +534,32 @@ fn usz List.compact(&self) @if(ELEMENT_IS_POINTER) // --> Deprecated -/** - * @param [&inout] self "The list to remove elements from" - * @param value "The value to remove" - * @return "true if the value was found" - **/ +<* + @param [&inout] self "The list to remove elements from" + @param value "The value to remove" + @return "true if the value was found" +*> fn bool List.remove_last_match(&self, Type value) @if(ELEMENT_IS_EQUATABLE) @deprecated { return self.remove_last_item(value) @inline; } -/** - * @param [&inout] self "The list to remove elements from" - * @param value "The value to remove" - * @return "true if the value was found" - **/ +<* + @param [&inout] self "The list to remove elements from" + @param value "The value to remove" + @return "true if the value was found" +*> fn bool List.remove_first_match(&self, Type value) @if(ELEMENT_IS_EQUATABLE) @deprecated { return self.remove_first_item(value) @inline; } -/** - * @param [&inout] self "The list to remove elements from" - * @param value "The value to remove" - * @return "the number of deleted elements." - **/ +<* + @param [&inout] self "The list to remove elements from" + @param value "The value to remove" + @return "the number of deleted elements." +*> fn usz List.remove_all_matches(&self, Type value) @if(ELEMENT_IS_EQUATABLE) @deprecated { return self.remove_item(value) @inline; diff --git a/lib/std/collections/list_common.c3 b/lib/std/collections/list_common.c3 index 416e0cad3..eee4ef397 100644 --- a/lib/std/collections/list_common.c3 +++ b/lib/std/collections/list_common.c3 @@ -1,8 +1,8 @@ module std::collections::list_common; -/** - * IMPORTANT The returned array must be freed using free_aligned. - **/ +<* + IMPORTANT The returned array must be freed using free_aligned. +*> macro list_to_new_aligned_array($Type, self, Allocator allocator) { if (!self.size) return $Type[] {}; diff --git a/lib/std/collections/map.c3 b/lib/std/collections/map.c3 index 5929e0c16..885cadb5f 100644 --- a/lib/std/collections/map.c3 +++ b/lib/std/collections/map.c3 @@ -21,11 +21,11 @@ struct MapImpl float load_factor; } -/** - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ +<* + @require capacity > 0 "The capacity must be 1 or higher" + @require load_factor > 0.0 "The load factor must be higher than 0" + @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" +*> fn Map new(uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap()) { MapImpl* map = allocator::alloc(allocator, MapImpl); @@ -33,11 +33,11 @@ fn Map new(uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT return (Map)map; } -/** - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ +<* + @require capacity > 0 "The capacity must be 1 or higher" + @require load_factor > 0.0 "The load factor must be higher than 0" + @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" +*> fn Map temp(uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR) { MapImpl* map = mem::temp_alloc(MapImpl); @@ -45,13 +45,13 @@ fn Map temp(uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAUL return (Map)map; } -/** - * @param [&inout] allocator "The allocator to use" - * @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values" - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ +<* + @param [&inout] allocator "The allocator to use" + @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values" + @require capacity > 0 "The capacity must be 1 or higher" + @require load_factor > 0.0 "The load factor must be higher than 0" + @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" +*> macro Map new_init_with_key_values(..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap()) { Map map = new(capacity, load_factor, allocator); @@ -61,15 +61,15 @@ macro Map new_init_with_key_values(..., uint capacity = DEFAULT_INITIAL_CAPACITY return map; } -/** - * @param [in] keys "Array of keys for the Map entries" - * @param [in] values "Array of values for the Map entries" - * @param [&inout] allocator "The allocator to use" - * @require keys.len == values.len "Both keys and values arrays must be the same length" - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ +<* + @param [in] keys "Array of keys for the Map entries" + @param [in] values "Array of values for the Map entries" + @param [&inout] allocator "The allocator to use" + @require keys.len == values.len "Both keys and values arrays must be the same length" + @require capacity > 0 "The capacity must be 1 or higher" + @require load_factor > 0.0 "The load factor must be higher than 0" + @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" +*> fn Map new_init_from_keys_and_values(Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap()) { assert(keys.len == values.len); @@ -81,12 +81,12 @@ fn Map new_init_from_keys_and_values(Key[] keys, Value[] values, uint capacity = return map; } -/** - * @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values" - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ +<* + @require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values" + @require capacity > 0 "The capacity must be 1 or higher" + @require load_factor > 0.0 "The load factor must be higher than 0" + @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" +*> macro Map temp_new_with_key_values(..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR) { Map map = temp(capacity, load_factor); @@ -96,15 +96,15 @@ macro Map temp_new_with_key_values(..., uint capacity = DEFAULT_INITIAL_CAPACITY return map; } -/** - * @param [in] keys "The keys for the HashMap entries" - * @param [in] values "The values for the HashMap entries" - * @param [&inout] allocator "The allocator to use" - * @require keys.len == values.len "Both keys and values arrays must be the same length" - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ +<* + @param [in] keys "The keys for the HashMap entries" + @param [in] values "The values for the HashMap entries" + @param [&inout] allocator "The allocator to use" + @require keys.len == values.len "Both keys and values arrays must be the same length" + @require capacity > 0 "The capacity must be 1 or higher" + @require load_factor > 0.0 "The load factor must be higher than 0" + @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" +*> fn Map temp_init_from_keys_and_values(Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap()) { assert(keys.len == values.len); @@ -116,9 +116,9 @@ fn Map temp_init_from_keys_and_values(Key[] keys, Value[] values, uint capacity return map; } -/** - * @param [&in] other_map "The map to copy from." - **/ +<* + @param [&in] other_map "The map to copy from." +*> fn Map new_from_map(Map other_map, Allocator allocator = null) { MapImpl* other_map_impl = (MapImpl*)other_map; @@ -137,9 +137,9 @@ fn Map new_from_map(Map other_map, Allocator allocator = null) return (Map)map; } -/** - * @param [&in] other_map "The map to copy from." - **/ +<* + @param [&in] other_map "The map to copy from." +*> fn Map temp_from_map(Map other_map) { return new_from_map(other_map, allocator::temp()); @@ -179,10 +179,10 @@ fn Entry*! Map.get_entry(map, Key key) return SearchResult.MISSING?; } -/** - * Get the value or update and - * @require $assignable(#expr, Value) - **/ +<* + Get the value or update and + @require $assignable(#expr, Value) +*> macro Value Map.@get_or_set(&self, Key key, Value #expr) { MapImpl *map = (MapImpl*)*self; diff --git a/lib/std/collections/object.c3 b/lib/std/collections/object.c3 index 89662cddc..7253cd022 100644 --- a/lib/std/collections/object.c3 +++ b/lib/std/collections/object.c3 @@ -148,9 +148,9 @@ fn bool Object.is_int(&self) @inline => self.type == int128.typeid; fn bool Object.is_keyable(&self) => self.is_empty() || self.is_map(); fn bool Object.is_indexable(&self) => self.is_empty() || self.is_array(); -/** - * @require self.is_keyable() - **/ +<* + @require self.is_keyable() +*> fn void Object.init_map_if_needed(&self) @private { if (self.is_empty()) @@ -160,9 +160,9 @@ fn void Object.init_map_if_needed(&self) @private } } -/** - * @require self.is_indexable() - **/ +<* + @require self.is_indexable() +*> fn void Object.init_array_if_needed(&self) @private { if (self.is_empty()) @@ -172,9 +172,9 @@ fn void Object.init_array_if_needed(&self) @private } } -/** - * @require self.is_keyable() - **/ +<* + @require self.is_keyable() +*> fn void Object.set_object(&self, String key, Object* new_object) @private { self.init_map_if_needed(); @@ -218,9 +218,9 @@ macro Object* Object.set(&self, String key, value) return val; } -/** - * @require self.is_indexable() - **/ +<* + @require self.is_indexable() +*> macro Object* Object.set_at(&self, usz index, String key, value) { Object* val = self.object_from_value(value); @@ -228,10 +228,10 @@ macro Object* Object.set_at(&self, usz index, String key, value) return val; } -/** - * @require self.is_indexable() - * @ensure return != null - **/ +<* + @require self.is_indexable() + @ensure return != null +*> macro Object* Object.push(&self, value) { Object* val = self.object_from_value(value); @@ -239,42 +239,42 @@ macro Object* Object.push(&self, value) return val; } -/** - * @require self.is_keyable() - **/ +<* + @require self.is_keyable() +*> fn Object*! Object.get(&self, String key) => self.is_empty() ? SearchResult.MISSING? : self.map.get(key); fn bool Object.has_key(&self, String key) => self.is_map() && self.map.has_key(key); -/** - * @require self.is_indexable() - **/ +<* + @require self.is_indexable() +*> fn Object* Object.get_at(&self, usz index) { return self.array.get(index); } -/** - * @require self.is_indexable() - **/ +<* + @require self.is_indexable() +*> fn usz Object.get_len(&self) { return self.array.len(); } -/** - * @require self.is_indexable() - **/ +<* + @require self.is_indexable() +*> fn void Object.push_object(&self, Object* to_append) { self.init_array_if_needed(); self.array.push(to_append); } -/** - * @require self.is_indexable() - **/ +<* + @require self.is_indexable() +*> fn void Object.set_object_at(&self, usz index, Object* to_set) { self.init_array_if_needed(); @@ -291,9 +291,9 @@ fn void Object.set_object_at(&self, usz index, Object* to_set) self.array.set_at(index, to_set); } -/** - * @require $Type.kindof.is_int() "Expected an integer type." - **/ +<* + @require $Type.kindof.is_int() "Expected an integer type." +*> macro get_integer_value(Object* value, $Type) { if (value.is_float()) @@ -313,19 +313,19 @@ macro get_integer_value(Object* value, $Type) } -/** - * @require self.is_indexable() - * @require $Type.kindof.is_int() : "Expected an integer type" - **/ +<* + @require self.is_indexable() + @require $Type.kindof.is_int() : "Expected an integer type" +*> macro Object.get_integer_at(&self, $Type, usz index) @private { return get_integer_value(self.get_at(index), $Type); } -/** - * @require self.is_keyable() - * @require $Type.kindof.is_int() : "Expected an integer type" - **/ +<* + @require self.is_keyable() + @require $Type.kindof.is_int() : "Expected an integer type" +*> macro Object.get_integer(&self, $Type, String key) @private { return get_integer_value(self.get(key), $Type); @@ -355,9 +355,9 @@ fn uint! Object.get_uint_at(&self, usz index) => self.get_integer_at(uint, index fn ulong! Object.get_ulong_at(&self, usz index) => self.get_integer_at(ulong, index); fn uint128! Object.get_uint128_at(&self, usz index) => self.get_integer_at(uint128, index); -/** - * @require self.is_keyable() - **/ +<* + @require self.is_keyable() +*> fn String! Object.get_string(&self, String key) { Object* value = self.get(key)!; @@ -365,9 +365,9 @@ fn String! Object.get_string(&self, String key) return value.s; } -/** - * @require self.is_indexable() - **/ +<* + @require self.is_indexable() +*> fn String! Object.get_string_at(&self, usz index) { Object* value = self.get_at(index); @@ -375,9 +375,9 @@ fn String! Object.get_string_at(&self, usz index) return value.s; } -/** - * @require self.is_keyable() - **/ +<* + @require self.is_keyable() +*> macro String! Object.get_enum(&self, $EnumType, String key) { Object value = self.get(key)!; @@ -385,9 +385,9 @@ macro String! Object.get_enum(&self, $EnumType, String key) return ($EnumType)value.i; } -/** - * @require self.is_indexable() - **/ +<* + @require self.is_indexable() +*> macro String! Object.get_enum_at(&self, $EnumType, usz index) { Object value = self.get_at(index); @@ -395,9 +395,9 @@ macro String! Object.get_enum_at(&self, $EnumType, usz index) return ($EnumType)value.i; } -/** - * @require self.is_keyable() - **/ +<* + @require self.is_keyable() +*> fn bool! Object.get_bool(&self, String key) { Object* value = self.get(key)!; @@ -406,9 +406,9 @@ fn bool! Object.get_bool(&self, String key) } -/** - * @require self.is_indexable() - **/ +<* + @require self.is_indexable() +*> fn bool! Object.get_bool_at(&self, usz index) { Object* value = self.get_at(index); @@ -416,9 +416,9 @@ fn bool! Object.get_bool_at(&self, usz index) return value.b; } -/** - * @require self.is_keyable() - **/ +<* + @require self.is_keyable() +*> fn double! Object.get_float(&self, String key) { Object* value = self.get(key)!; @@ -435,9 +435,9 @@ fn double! Object.get_float(&self, String key) } } -/** - * @require self.is_indexable() - **/ +<* + @require self.is_indexable() +*> fn double! Object.get_float_at(&self, usz index) { Object* value = self.get_at(index); diff --git a/lib/std/collections/priorityqueue.c3 b/lib/std/collections/priorityqueue.c3 index a66f616d5..4f99b18ae 100644 --- a/lib/std/collections/priorityqueue.c3 +++ b/lib/std/collections/priorityqueue.c3 @@ -66,9 +66,9 @@ fn void PrivatePriorityQueue.push(&self, Type element) } } -/** -* @require self != null -*/ +<* + @require self != null +*> fn Type! PrivatePriorityQueue.pop(&self) { usz i = 0; @@ -128,9 +128,9 @@ fn bool PrivatePriorityQueue.is_empty(&self) return self.heap.is_empty(); } -/** - * @require index < self.len() - */ +<* + @require index < self.len() +*> fn Type PrivatePriorityQueue.get(&self, usz index) @operator([]) { return self.heap[index]; diff --git a/lib/std/collections/range.c3 b/lib/std/collections/range.c3 index 7f8c26aba..98917a167 100644 --- a/lib/std/collections/range.c3 +++ b/lib/std/collections/range.c3 @@ -1,6 +1,6 @@ -/** - * @require Type.is_ordered : "The type must be ordered" - **/ +<* + @require Type.is_ordered : "The type must be ordered" +*> module std::collections::range(); import std::io; @@ -21,9 +21,9 @@ fn bool Range.contains(&self, Type value) @inline return value >= self.start && value <= self.end; } -/** - * @require index < self.len() : "Can't index into an empty range" - **/ +<* + @require index < self.len() : "Can't index into an empty range" +*> fn Type Range.get(&self, usz index) @operator([]) { return (Type)(self.start + (usz)index); @@ -86,9 +86,9 @@ fn String ExclusiveRange.to_tstring(&self) return self.to_new_string(allocator::temp()); } -/** - * @require index < self.len() : "Can't index into an empty range" - **/ +<* + @require index < self.len() : "Can't index into an empty range" +*> fn Type ExclusiveRange.get(&self, usz index) @operator([]) { return (Type)(self.start + index); diff --git a/lib/std/compression/qoi.c3 b/lib/std/compression/qoi.c3 index eb9e2198d..6db6f4ea5 100644 --- a/lib/std/compression/qoi.c3 +++ b/lib/std/compression/qoi.c3 @@ -2,23 +2,23 @@ module std::compression::qoi; const uint PIXELS_MAX = 400000000; -/** - * Colorspace. - * Purely informative. It will be saved to the file header, - * but does not affect how chunks are en-/decoded. - */ +<* + Colorspace. + Purely informative. It will be saved to the file header, + but does not affect how chunks are en-/decoded. +*> enum QOIColorspace : char (char id) { SRGB = 0, // sRGB with linear alpha LINEAR = 1 // all channels linear } -/** - * Channels. - * The channels used in an image. - * AUTO can be used when decoding to automatically determine - * the channels from the file's header. - */ +<* + Channels. + The channels used in an image. + AUTO can be used when decoding to automatically determine + the channels from the file's header. +*> enum QOIChannels : char (char id) { AUTO = 0, @@ -26,10 +26,10 @@ enum QOIChannels : char (char id) RGBA = 4 } -/** - * Descriptor. - * Contains information about an image. - */ +<* + Descriptor. + Contains information about an image. +*> struct QOIDesc { uint width; @@ -38,10 +38,10 @@ struct QOIDesc QOIColorspace colorspace; } -/** - * QOI Errors. - * These are all the possible bad outcomes. - */ +<* + QOI Errors. + These are all the possible bad outcomes. +*> fault QOIError { INVALID_PARAMETERS, @@ -56,21 +56,21 @@ fault QOIError module std::compression::qoi @if(!$feature(QOI_NO_STDIO)); import std::io; -/** - * Encode raw RGB or RGBA pixels into a QOI image and write it to the - * file system. - * - * The desc struct must be filled with the image width, height, the - * used channels (QOIChannels.RGB or RGBA) and the colorspace - * (QOIColorspace.SRGB or LINEAR). - * - * The function returns an optional, which can either be a QOIError - * or the number of bytes written on success. - * - * @param [in] filename `The file's name to write the image to` - * @param [in] input `The raw RGB or RGBA pixels to encode` - * @param [&in] desc `The descriptor of the image` - */ +<* + Encode raw RGB or RGBA pixels into a QOI image and write it to the + file system. + + The desc struct must be filled with the image width, height, the + used channels (QOIChannels.RGB or RGBA) and the colorspace + (QOIColorspace.SRGB or LINEAR). + + The function returns an optional, which can either be a QOIError + or the number of bytes written on success. + + @param [in] filename `The file's name to write the image to` + @param [in] input `The raw RGB or RGBA pixels to encode` + @param [&in] desc `The descriptor of the image` +*> fn usz! write(String filename, char[] input, QOIDesc* desc) { @pool() { @@ -91,27 +91,27 @@ fn usz! write(String filename, char[] input, QOIDesc* desc) } -/** - * Read and decode a QOI image from the file system. - * - * If channels is set to QOIChannels.AUTO, the function will - * automatically determine the channels from the file's header. - * However, if channels is RGB or RGBA, the output format will be - * forced into this number of channels. - * - * The desc struct will be filled with the width, height, - * channels and colorspace of the image. - * - * The function returns an optional, which can either be a QOIError - * or a char[] pointing to the decoded pixels on success. - * - * The returned pixel data should be free()d after use, or the decoding - * and use of the data should be wrapped in a @pool() { ... }; block. - * - * @param [in] filename `The file's name to read the image from` - * @param [&out] desc `The descriptor to fill with the image's info` - * @param channels `The channels to be used` - */ +<* + Read and decode a QOI image from the file system. + + If channels is set to QOIChannels.AUTO, the function will + automatically determine the channels from the file's header. + However, if channels is RGB or RGBA, the output format will be + forced into this number of channels. + + The desc struct will be filled with the width, height, + channels and colorspace of the image. + + The function returns an optional, which can either be a QOIError + or a char[] pointing to the decoded pixels on success. + + The returned pixel data should be free()d after use, or the decoding + and use of the data should be wrapped in a @pool() { ... }; block. + + @param [in] filename `The file's name to read the image from` + @param [&out] desc `The descriptor to fill with the image's info` + @param channels `The channels to be used` +*> fn char[]! read(String filename, QOIDesc* desc, QOIChannels channels = AUTO, Allocator allocator = allocator::heap()) { // read file @@ -128,19 +128,19 @@ fn char[]! read(String filename, QOIDesc* desc, QOIChannels channels = AUTO, All module std::compression::qoi; import std::bits; -/** - * Encode raw RGB or RGBA pixels into a QOI image in memory. - * - * The function returns an optional, which can either be a QOIError - * or a char[] pointing to the encoded data on success. - * - * The returned qoi data should be free()d after use, or the encoding - * and use of the data should be wrapped in a @pool() { ... }; block. - * See the write() function for an example. - * - * @param [in] input `The raw RGB or RGBA pixels to encode` - * @param [&in] desc `The descriptor of the image` - */ +<* + Encode raw RGB or RGBA pixels into a QOI image in memory. + + The function returns an optional, which can either be a QOIError + or a char[] pointing to the encoded data on success. + + The returned qoi data should be free()d after use, or the encoding + and use of the data should be wrapped in a @pool() { ... }; block. + See the write() function for an example. + + @param [in] input `The raw RGB or RGBA pixels to encode` + @param [&in] desc `The descriptor of the image` +*> fn char[]! encode(char[] input, QOIDesc* desc, Allocator allocator = allocator::heap()) { // check info in desc @@ -266,27 +266,27 @@ fn char[]! encode(char[] input, QOIDesc* desc, Allocator allocator = allocator:: } -/** - * Decode a QOI image from memory. - * - * If channels is set to QOIChannels.AUTO, the function will - * automatically determine the channels from the file's header. - * However, if channels is RGB or RGBA, the output format will be - * forced into this number of channels. - * - * The desc struct will be filled with the width, height, - * channels and colorspace of the image. - * - * The function returns an optional, which can either be a QOIError - * or a char[] pointing to the decoded pixels on success. - * - * The returned pixel data should be free()d after use, or the decoding - * and use of the data should be wrapped in a @pool() { ... }; block. - * - * @param [in] data `The QOI image data to decode` - * @param [&out] desc `The descriptor to fill with the image's info` - * @param channels `The channels to be used` - */ +<* + Decode a QOI image from memory. + + If channels is set to QOIChannels.AUTO, the function will + automatically determine the channels from the file's header. + However, if channels is RGB or RGBA, the output format will be + forced into this number of channels. + + The desc struct will be filled with the width, height, + channels and colorspace of the image. + + The function returns an optional, which can either be a QOIError + or a char[] pointing to the decoded pixels on success. + + The returned pixel data should be free()d after use, or the decoding + and use of the data should be wrapped in a @pool() { ... }; block. + + @param [in] data `The QOI image data to decode` + @param [&out] desc `The descriptor to fill with the image's info` + @param channels `The channels to be used` +*> fn char[]! decode(char[] data, QOIDesc* desc, QOIChannels channels = AUTO, Allocator allocator = allocator::heap()) { // check input data diff --git a/lib/std/core/allocators/arena_allocator.c3 b/lib/std/core/allocators/arena_allocator.c3 index 70dcd68b7..5c4629e07 100644 --- a/lib/std/core/allocators/arena_allocator.c3 +++ b/lib/std/core/allocators/arena_allocator.c3 @@ -10,9 +10,9 @@ struct ArenaAllocator (Allocator) usz used; } -/** - * Initialize a memory arena for use using the provided bytes. - **/ +<* + Initialize a memory arena for use using the provided bytes. +*> fn ArenaAllocator* ArenaAllocator.init(&self, char[] data) { self.data = data; @@ -31,9 +31,9 @@ struct ArenaAllocatorHeader @local char[*] data; } -/* - * @require ptr != null - **/ +<* + @require ptr != null +*> fn void ArenaAllocator.release(&self, void* ptr, bool) @dynamic { assert((uptr)ptr >= (uptr)self.data.ptr, "Pointer originates from a different allocator."); @@ -48,11 +48,11 @@ fn void ArenaAllocator.release(&self, void* ptr, bool) @dynamic fn usz ArenaAllocator.mark(&self) @dynamic => self.used; fn void ArenaAllocator.reset(&self, usz mark) @dynamic => self.used = mark; -/** - * @require !alignment || math::is_power_of_2(alignment) - * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` - * @require size > 0 - **/ +<* + @require !alignment || math::is_power_of_2(alignment) + @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` + @require size > 0 +*> fn void*! ArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic { alignment = alignment_for_allocation(alignment); @@ -70,12 +70,12 @@ fn void*! ArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz a return mem; } -/** - * @require !alignment || math::is_power_of_2(alignment) - * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` - * @require old_pointer != null - * @require size > 0 - **/ +<* + @require !alignment || math::is_power_of_2(alignment) + @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` + @require old_pointer != null + @require size > 0 +*> fn void*! ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignment) @dynamic { alignment = alignment_for_allocation(alignment); diff --git a/lib/std/core/allocators/dynamic_arena.c3 b/lib/std/core/allocators/dynamic_arena.c3 index 1069d595f..9637baa1e 100644 --- a/lib/std/core/allocators/dynamic_arena.c3 +++ b/lib/std/core/allocators/dynamic_arena.c3 @@ -12,10 +12,10 @@ struct DynamicArenaAllocator (Allocator) usz page_size; } -/** - * @param [&inout] allocator - * @require page_size >= 128 - **/ +<* + @param [&inout] allocator + @require page_size >= 128 +*> fn void DynamicArenaAllocator.init(&self, usz page_size, Allocator allocator) { self.page = null; @@ -60,10 +60,10 @@ struct DynamicArenaChunk @local usz size; } -/** - * @require ptr - * @require self.page `tried to free pointer on invalid allocator` - */ +<* + @require ptr + @require self.page `tried to free pointer on invalid allocator` +*> fn void DynamicArenaAllocator.release(&self, void* ptr, bool) @dynamic { DynamicArenaPage* current_page = self.page; @@ -74,11 +74,11 @@ fn void DynamicArenaAllocator.release(&self, void* ptr, bool) @dynamic current_page.current_stack_ptr = null; } -/** - * @require size > 0 `Resize doesn't support zeroing` - * @require old_pointer != null `Resize doesn't handle null pointers` - * @require self.page `tried to realloc pointer on invalid allocator` - */ +<* + @require size > 0 `Resize doesn't support zeroing` + @require old_pointer != null `Resize doesn't handle null pointers` + @require self.page `tried to realloc pointer on invalid allocator` +*> fn void*! DynamicArenaAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic { DynamicArenaPage* current_page = self.page; @@ -126,10 +126,10 @@ fn void DynamicArenaAllocator.reset(&self, usz mark = 0) @dynamic self.page = page; } -/** - * @require math::is_power_of_2(alignment) - * @require size > 0 - */ +<* + @require math::is_power_of_2(alignment) + @require size > 0 +*> fn void*! DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment) @local { // First, make sure that we can align it, extending the page size if needed. @@ -156,10 +156,10 @@ fn void*! DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment) @loca return mem_start; } -/** - * @require size > 0 `acquire expects size > 0` - * @require !alignment || math::is_power_of_2(alignment) - */ +<* + @require size > 0 `acquire expects size > 0` + @require !alignment || math::is_power_of_2(alignment) +*> fn void*! DynamicArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic { alignment = alignment_for_allocation(alignment); diff --git a/lib/std/core/allocators/heap_allocator.c3 b/lib/std/core/allocators/heap_allocator.c3 index 45e26bb3c..3aef5c57e 100644 --- a/lib/std/core/allocators/heap_allocator.c3 +++ b/lib/std/core/allocators/heap_allocator.c3 @@ -11,10 +11,10 @@ struct SimpleHeapAllocator (Allocator) Header* free_list; } -/** - * @require allocator "An underlying memory provider must be given" - * @require !self.free_list "The allocator may not be already initialized" - **/ +<* + @require allocator "An underlying memory provider must be given" + @require !self.free_list "The allocator may not be already initialized" +*> fn void SimpleHeapAllocator.init(&self, MemoryAllocFn allocator) { self.alloc_fn = allocator; @@ -49,9 +49,9 @@ fn void SimpleHeapAllocator.release(&self, void* old_pointer, bool aligned) @dyn } } -/** - * @require old_pointer && bytes > 0 - **/ +<* + @require old_pointer && bytes > 0 +*> fn void*! SimpleHeapAllocator._realloc(&self, void* old_pointer, usz bytes) @local { // Find the block header. diff --git a/lib/std/core/allocators/on_stack_allocator.c3 b/lib/std/core/allocators/on_stack_allocator.c3 index ce9cc96a4..65a70fd9b 100644 --- a/lib/std/core/allocators/on_stack_allocator.c3 +++ b/lib/std/core/allocators/on_stack_allocator.c3 @@ -16,10 +16,11 @@ struct OnStackAllocatorExtraChunk @local void* data; } -/** - * @param [&inout] allocator - * Initialize a memory arena for use using the provided bytes. - **/ +<* + Initialize a memory arena for use using the provided bytes. + + @param [&inout] allocator +*> fn void OnStackAllocator.init(&self, char[] data, Allocator allocator) { self.data = data; @@ -54,9 +55,9 @@ struct OnStackAllocatorHeader char[*] data; } -/** - * @require old_pointer - **/ +<* + @require old_pointer +*> fn void OnStackAllocator.release(&self, void* old_pointer, bool aligned) @dynamic { if (allocation_in_stack_mem(self, old_pointer)) return; @@ -98,11 +99,11 @@ fn OnStackAllocatorExtraChunk* on_stack_allocator_find_chunk(OnStackAllocator* a return null; } -/** - * @require size > 0 - * @require old_pointer != null - * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` - **/ +<* + @require size > 0 + @require old_pointer != null + @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` +*> fn void*! OnStackAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic { if (!allocation_in_stack_mem(self, old_pointer)) @@ -119,10 +120,10 @@ fn void*! OnStackAllocator.resize(&self, void* old_pointer, usz size, usz alignm return mem; } -/** - * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` - * @require size > 0 - **/ +<* + @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` + @require size > 0 +*> fn void*! OnStackAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic { bool aligned = alignment > 0; diff --git a/lib/std/core/allocators/temp_allocator.c3 b/lib/std/core/allocators/temp_allocator.c3 index 72ac77b46..7b7e4b69d 100644 --- a/lib/std/core/allocators/temp_allocator.c3 +++ b/lib/std/core/allocators/temp_allocator.c3 @@ -32,9 +32,9 @@ struct TempAllocatorPage macro usz TempAllocatorPage.pagesize(&self) => self.size & ~PAGE_IS_ALIGNED; macro bool TempAllocatorPage.is_aligned(&self) => self.size & PAGE_IS_ALIGNED == PAGE_IS_ALIGNED; -/** - * @require size >= 16 - **/ +<* + @require size >= 16 +*> fn TempAllocator*! new_temp_allocator(usz size, Allocator allocator) { TempAllocator* temp = allocator::alloc_with_padding(allocator, TempAllocator, size)!; @@ -134,11 +134,11 @@ fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment) @d return data; } -/** - * @require size > 0 - * @require !alignment || math::is_power_of_2(alignment) - * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` - **/ +<* + @require size > 0 + @require !alignment || math::is_power_of_2(alignment) + @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` +*> fn void*! TempAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic { alignment = alignment_for_allocation(alignment); diff --git a/lib/std/core/allocators/tracking_allocator.c3 b/lib/std/core/allocators/tracking_allocator.c3 index 6fb86f256..ef831be82 100644 --- a/lib/std/core/allocators/tracking_allocator.c3 +++ b/lib/std/core/allocators/tracking_allocator.c3 @@ -26,29 +26,29 @@ struct TrackingAllocator (Allocator) usz allocs_total; } -/** - * Initialize a tracking allocator to wrap (and track) another allocator. - * - * @param [&inout] allocator "The allocator to track" - **/ +<* + Initialize a tracking allocator to wrap (and track) another allocator. + + @param [&inout] allocator "The allocator to track" +*> fn void TrackingAllocator.init(&self, Allocator allocator) { *self = { .inner_allocator = allocator }; self.map.new_init(allocator: allocator); } -/** - * Free this tracking allocator. - **/ +<* + Free this tracking allocator. +*> fn void TrackingAllocator.free(&self) { self.map.free(); *self = {}; } -/** - * @return "the total allocated memory not yet freed." - **/ +<* + @return "the total allocated memory not yet freed." +*> fn usz TrackingAllocator.allocated(&self) { usz allocated = 0; @@ -59,14 +59,14 @@ fn usz TrackingAllocator.allocated(&self) return allocated; } -/** - * @return "the total memory allocated (freed or not)." - **/ +<* + @return "the total memory allocated (freed or not)." +*> fn usz TrackingAllocator.total_allocated(&self) => self.mem_total; -/** - * @return "the total number of allocations (freed or not)." - **/ +<* + @return "the total number of allocations (freed or not)." +*> fn usz TrackingAllocator.total_allocation_count(&self) => self.allocs_total; fn Allocation[] TrackingAllocator.allocations_tlist(&self, Allocator allocator) @@ -74,9 +74,9 @@ fn Allocation[] TrackingAllocator.allocations_tlist(&self, Allocator allocator) return self.map.value_tlist(); } -/** - * @return "the number of non-freed allocations." - **/ +<* + @return "the number of non-freed allocations." +*> fn usz TrackingAllocator.allocation_count(&self) => self.map.count; fn void*! TrackingAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic diff --git a/lib/std/core/array.c3 b/lib/std/core/array.c3 index ab00fe671..baa8c9ca7 100644 --- a/lib/std/core/array.c3 +++ b/lib/std/core/array.c3 @@ -1,12 +1,12 @@ module std::core::array; import std::core::array::slice; -/** - * @param [in] array - * @param [in] element - * @return "the first index of the element" - * @return! SearchResult.MISSING - **/ +<* + @param [in] array + @param [in] element + @return "the first index of the element" + @return! SearchResult.MISSING +*> macro index_of(array, element) { foreach (i, &e : array) @@ -16,10 +16,10 @@ macro index_of(array, element) return SearchResult.MISSING?; } -/** - * @require @typekind(array) == VECTOR || @typekind(array) == ARRAY - * @require @typekind(array[0]) == VECTOR || @typekind(array[0]) == ARRAY - **/ +<* + @require @typekind(array) == VECTOR || @typekind(array) == ARRAY + @require @typekind(array[0]) == VECTOR || @typekind(array[0]) == ARRAY +*> macro slice2d(array, x = 0, xlen = 0, y = 0, ylen = 0) { if (xlen < 1) xlen = $typeof(array[0]).len + xlen; @@ -29,12 +29,12 @@ macro slice2d(array, x = 0, xlen = 0, y = 0, ylen = 0) } -/** - * @param [in] array - * @param [in] element - * @return "the last index of the element" - * @return! SearchResult.MISSING - **/ +<* + @param [in] array + @param [in] element + @return "the last index of the element" + @return! SearchResult.MISSING +*> macro rindex_of(array, element) { foreach_r (i, &e : array) @@ -44,17 +44,17 @@ macro rindex_of(array, element) return SearchResult.MISSING?; } -/** - * Concatenate two arrays or slices, returning a slice containing the concatenation of them. - * - * @param [in] arr1 - * @param [in] arr2 - * @param [&inout] allocator "The allocator to use, default is the heap allocator" - * @require @typekind(arr1) == SLICE || @typekind(arr1) == ARRAY - * @require @typekind(arr2) == SLICE || @typekind(arr2) == ARRAY - * @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type" - * @ensure result.len == arr1.len + arr2.len - **/ +<* + Concatenate two arrays or slices, returning a slice containing the concatenation of them. + + @param [in] arr1 + @param [in] arr2 + @param [&inout] allocator "The allocator to use, default is the heap allocator" + @require @typekind(arr1) == SLICE || @typekind(arr1) == ARRAY + @require @typekind(arr2) == SLICE || @typekind(arr2) == ARRAY + @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type" + @ensure result.len == arr1.len + arr2.len +*> macro concat(arr1, arr2, Allocator allocator) @nodiscard { var $Type = $typeof(arr1[0]); @@ -69,33 +69,33 @@ macro concat(arr1, arr2, Allocator allocator) @nodiscard } return result; } -/** - * Concatenate two arrays or slices, returning a slice containing the concatenation of them. - * - * @param [in] arr1 - * @param [in] arr2 - * @param [&inout] allocator "The allocator to use, default is the heap allocator" - * @require @typekind(arr1) == SLICE || @typekind(arr1) == ARRAY - * @require @typekind(arr2) == SLICE || @typekind(arr2) == ARRAY - * @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type" - * @ensure result.len == arr1.len + arr2.len - **/ +<* + Concatenate two arrays or slices, returning a slice containing the concatenation of them. + + @param [in] arr1 + @param [in] arr2 + @param [&inout] allocator "The allocator to use, default is the heap allocator" + @require @typekind(arr1) == SLICE || @typekind(arr1) == ARRAY + @require @typekind(arr2) == SLICE || @typekind(arr2) == ARRAY + @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type" + @ensure result.len == arr1.len + arr2.len +*> macro concat_new(arr1, arr2, Allocator allocator = allocator::heap()) @nodiscard { return concat(arr1, arr2, allocator); } -/** - * Concatenate two arrays or slices, returning a slice containing the concatenation of them, - * allocated using the temp allocator. - * - * @param [in] arr1 - * @param [in] arr2 - * @require @typekind(arr1) == SLICE || @typekind(arr1) == ARRAY - * @require @typekind(arr2) == SLICE || @typekind(arr2) == ARRAY - * @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type" - * @ensure result.len == arr1.len + arr2.len - **/ +<* + Concatenate two arrays or slices, returning a slice containing the concatenation of them, + allocated using the temp allocator. + + @param [in] arr1 + @param [in] arr2 + @require @typekind(arr1) == SLICE || @typekind(arr1) == ARRAY + @require @typekind(arr2) == SLICE || @typekind(arr2) == ARRAY + @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type" + @ensure result.len == arr1.len + arr2.len +*> macro tconcat(arr1, arr2) @nodiscard => concat(arr1, arr2, allocator::temp()); module std::core::array::slice(); @@ -142,18 +142,18 @@ macro void Slice2d.@each_ref(&self; @body(usz[<2>], Type*)) } } -/** - * @require idy >= 0 && idy < self.ylen - **/ +<* + @require idy >= 0 && idy < self.ylen +*> macro Type[] Slice2d.get(self, usz idy) @operator([]) { return (self.ptr + self.inner_len * (idy + self.ystart))[self.xstart:self.xlen]; } -/** - * @require y >= 0 && y < self.ylen - * @require x >= 0 && x < self.xlen - **/ +<* + @require y >= 0 && y < self.ylen + @require x >= 0 && x < self.xlen +*> fn Slice2d Slice2d.slice(&self, isz x = 0, isz xlen = 0, isz y = 0, isz ylen = 0) { if (xlen < 1) xlen = self.xlen + xlen; diff --git a/lib/std/core/bitorder.c3 b/lib/std/core/bitorder.c3 index 431aa6116..0b49cee2d 100644 --- a/lib/std/core/bitorder.c3 +++ b/lib/std/core/bitorder.c3 @@ -87,10 +87,10 @@ bitstruct UInt128LE : uint128 @littleendian uint128 val : 0..127; } -/** - * @require is_array_or_slice_of_char(bytes) "argument must be an array, a pointer to an array or a slice of char" - * @require is_bitorder($Type) "type must be a bitorder integer" - **/ +<* + @require is_array_or_slice_of_char(bytes) "argument must be an array, a pointer to an array or a slice of char" + @require is_bitorder($Type) "type must be a bitorder integer" +*> macro read(bytes, $Type) { char[] s; @@ -103,10 +103,10 @@ macro read(bytes, $Type) return bitcast(*(char[$Type.sizeof]*)s.ptr, $Type).val; } -/** - * @require is_arrayptr_or_slice_of_char(bytes) "argument must be a pointer to an array or a slice of char" - * @require is_bitorder($Type) "type must be a bitorder integer" - **/ +<* + @require is_arrayptr_or_slice_of_char(bytes) "argument must be a pointer to an array or a slice of char" + @require is_bitorder($Type) "type must be a bitorder integer" +*> macro write(x, bytes, $Type) { char[] s; diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index 066f2fa0c..d534e47fd 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -4,29 +4,29 @@ module std::core::builtin; import libc, std::hash, std::io, std::os::backtrace; -/** - * Use `IteratorResult` when reading the end of an iterator, or accessing a result out of bounds. - **/ +<* + Use `IteratorResult` when reading the end of an iterator, or accessing a result out of bounds. +*> fault IteratorResult { NO_MORE_ELEMENT } -/** - * Use `SearchResult` when trying to return a value from some collection but the element is missing. - **/ +<* + Use `SearchResult` when trying to return a value from some collection but the element is missing. +*> fault SearchResult { MISSING } -/** - * Use `CastResult` when an attempt at conversion fails. - **/ +<* + Use `CastResult` when an attempt at conversion fails. +*> fault CastResult { TYPE_MISMATCH } def VoidFn = fn void(); -/** - * Stores a variable on the stack, then restores it at the end of the - * macro scope. - * - * @param variable `the variable to store and restore` - **/ +<* + Stores a variable on the stack, then restores it at the end of the + macro scope. + + @param variable `the variable to store and restore` +*> macro void @scope(&variable; @body) @builtin { var temp = *variable; @@ -34,10 +34,10 @@ macro void @scope(&variable; @body) @builtin @body(); } -/** - * Swap two variables - * @require $assignable(*b, $typeof(*a)) && $assignable(*a, $typeof(*b)) - **/ +<* + Swap two variables + @require $assignable(*b, $typeof(*a)) && $assignable(*a, $typeof(*b)) +*> macro void @swap(&a, &b) @builtin { var temp = *a; @@ -45,15 +45,15 @@ macro void @swap(&a, &b) @builtin *b = temp; } -/** - * Convert an `any` type to a type, returning an failure if there is a type mismatch. - * - * @param v `the any to convert to the given type.` - * @param $Type `the type to convert to` - * @return `The any.ptr converted to its type.` - * @ensure @typeis(return, $Type*) - * @return! CastResult.TYPE_MISMATCH - **/ +<* + Convert an `any` type to a type, returning an failure if there is a type mismatch. + + @param v `the any to convert to the given type.` + @param $Type `the type to convert to` + @return `The any.ptr converted to its type.` + @ensure @typeis(return, $Type*) + @return! CastResult.TYPE_MISMATCH +*> macro anycast(any v, $Type) @builtin { if (v.type != $Type.typeid) return CastResult.TYPE_MISMATCH?; @@ -153,11 +153,11 @@ fn void panicf(String fmt, String file, String function, uint line, args...) }; } -/** - * Marks the path as unreachable. This will panic in safe mode, and in fast will simply be assumed - * never happens. - * @param [in] string "The panic message or format string" - **/ +<* + Marks the path as unreachable. This will panic in safe mode, and in fast will simply be assumed + never happens. + @param [in] string "The panic message or format string" +*> macro void unreachable(String string = "Unreachable statement reached.", ...) @builtin @noreturn { $if env::COMPILER_SAFE_MODE: @@ -166,19 +166,19 @@ macro void unreachable(String string = "Unreachable statement reached.", ...) @b $$unreachable(); } -/** - * Marks the path as unsupported, this is similar to unreachable. - * @param [in] string "The error message" - **/ +<* + Marks the path as unsupported, this is similar to unreachable. + @param [in] string "The error message" +*> macro void unsupported(String string = "Unsupported function invoked") @builtin @noreturn { panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat); $$unreachable(); } -/** - * Unconditionally break into an attached debugger when reached. - **/ +<* + Unconditionally break into an attached debugger when reached. +*> macro void breakpoint() @builtin { $$breakpoint(); @@ -199,13 +199,13 @@ macro any.as_inner(&self) return $$any_make(self.ptr, self.type.inner); } -/** - * @param expr "the expression to cast" - * @param $Type "the type to cast to" - * - * @require $sizeof(expr) == $Type.sizeof "Cannot bitcast between types of different size." - * @ensure @typeis(return, $Type) - **/ +<* + @param expr "the expression to cast" + @param $Type "the type to cast to" + + @require $sizeof(expr) == $Type.sizeof "Cannot bitcast between types of different size." + @ensure @typeis(return, $Type) +*> macro bitcast(expr, $Type) @builtin { $if $Type.alignof <= $alignof(expr): @@ -217,13 +217,13 @@ macro bitcast(expr, $Type) @builtin $endif } -/** - * @param $Type `The type of the enum` - * @param [in] enum_name `The name of the enum to search for` - * @require $Type.kindof == ENUM `Only enums may be used` - * @ensure @typeis(return, $Type) - * @return! SearchResult.MISSING - **/ +<* + @param $Type `The type of the enum` + @param [in] enum_name `The name of the enum to search for` + @require $Type.kindof == ENUM `Only enums may be used` + @ensure @typeis(return, $Type) + @return! SearchResult.MISSING +*> macro enum_by_name($Type, String enum_name) @builtin { typeid x = $Type.typeid; @@ -234,13 +234,13 @@ macro enum_by_name($Type, String enum_name) @builtin return SearchResult.MISSING?; } -/** - * Mark an expression as likely to be true - * - * @param #value "expression to be marked likely" - * @param $probability "in the range 0 - 1" - * @require $probability >= 0 && $probability <= 1.0 - **/ +<* + Mark an expression as likely to be true + + @param #value "expression to be marked likely" + @param $probability "in the range 0 - 1" + @require $probability >= 0 && $probability <= 1.0 +*> macro bool @likely(bool #value, $probability = 1.0) @builtin { $switch @@ -253,13 +253,13 @@ macro bool @likely(bool #value, $probability = 1.0) @builtin $endswitch } -/** - * Mark an expression as unlikely to be true - * - * @param #value "expression to be marked unlikely" - * @param $probability "in the range 0 - 1" - * @require $probability >= 0 && $probability <= 1.0 - **/ +<* + Mark an expression as unlikely to be true + + @param #value "expression to be marked unlikely" + @param $probability "in the range 0 - 1" + @require $probability >= 0 && $probability <= 1.0 +*> macro bool @unlikely(bool #value, $probability = 1.0) @builtin { $switch @@ -272,11 +272,11 @@ macro bool @unlikely(bool #value, $probability = 1.0) @builtin $endswitch } -/** - * @require values::@is_int(#value) || values::@is_bool(#value) - * @require $assignable(expected, $typeof(#value)) - * @require $probability >= 0 && $probability <= 1.0 - **/ +<* + @require values::@is_int(#value) || values::@is_bool(#value) + @require $assignable(expected, $typeof(#value)) + @require $probability >= 0 && $probability <= 1.0 +*> macro @expect(#value, expected, $probability = 1.0) @builtin { $switch @@ -289,10 +289,10 @@ macro @expect(#value, expected, $probability = 1.0) @builtin $endswitch } -/** - * Locality for prefetch, levels 0 - 3, corresponding - * to "extremely local" to "no locality" - **/ +<* + Locality for prefetch, levels 0 - 3, corresponding + to "extremely local" to "no locality" +*> enum PrefetchLocality { NO_LOCALITY, @@ -301,13 +301,13 @@ enum PrefetchLocality VERY_NEAR, } -/** - * Prefetch a pointer. +<* + Prefetch a pointer. - * @param [in] ptr `Pointer to prefetch` - * @param $locality `Locality ranging from none to extremely local` - * @param $write `Prefetch for write, otherwise prefetch for read.` - **/ + @param [in] ptr `Pointer to prefetch` + @param $locality `Locality ranging from none to extremely local` + @param $write `Prefetch for write, otherwise prefetch for read.` +*> macro @prefetch(void* ptr, PrefetchLocality $locality = VERY_NEAR, bool $write = false) @builtin { $if !env::BUILTIN_PREFETCH_IS_DISABLED: @@ -369,9 +369,9 @@ macro @is_empty_macro_slot(#arg) @builtin => @typeis(#arg, EmptySlot); macro @is_valid_macro_slot(#arg) @builtin => !@typeis(#arg, EmptySlot); const MAX_FRAMEADDRESS = 128; -/** - * @require n >= 0 - **/ +<* + @require n >= 0 +*> macro void* get_frameaddress(int n) { if (n > MAX_FRAMEADDRESS) return null; @@ -510,9 +510,9 @@ macro void* get_frameaddress(int n) } } -/** - * @require n >= 0 - **/ +<* + @require n >= 0 +*> macro void* get_returnaddress(int n) { if (n > MAX_FRAMEADDRESS) return null; diff --git a/lib/std/core/builtin_comparison.c3 b/lib/std/core/builtin_comparison.c3 index 16437556a..b511fb70e 100644 --- a/lib/std/core/builtin_comparison.c3 +++ b/lib/std/core/builtin_comparison.c3 @@ -3,9 +3,9 @@ // a copy of which can be found in the LICENSE_STDLIB file. module std::core::builtin; -/** - * @require types::@comparable_value(a) && types::@comparable_value(b) - **/ +<* + @require types::@comparable_value(a) && types::@comparable_value(b) +*> macro less(a, b) @builtin { $switch @@ -18,9 +18,9 @@ macro less(a, b) @builtin $endswitch } -/** - * @require types::@comparable_value(a) && types::@comparable_value(b) - **/ +<* + @require types::@comparable_value(a) && types::@comparable_value(b) +*> macro less_eq(a, b) @builtin { $switch @@ -33,9 +33,9 @@ macro less_eq(a, b) @builtin $endswitch } -/** - * @require types::@comparable_value(a) && types::@comparable_value(b) - **/ +<* + @require types::@comparable_value(a) && types::@comparable_value(b) +*> macro greater(a, b) @builtin { $switch @@ -48,9 +48,9 @@ macro greater(a, b) @builtin $endswitch } -/** - * @require types::@comparable_value(a) && types::@comparable_value(b) - **/ +<* + @require types::@comparable_value(a) && types::@comparable_value(b) +*> macro int compare_to(a, b) @builtin { $switch @@ -62,9 +62,9 @@ macro int compare_to(a, b) @builtin return (int)(a > b) - (int)(a < b); $endswitch } -/** - * @require types::@comparable_value(a) && types::@comparable_value(b) - **/ +<* + @require types::@comparable_value(a) && types::@comparable_value(b) +*> macro greater_eq(a, b) @builtin { $switch @@ -77,9 +77,9 @@ macro greater_eq(a, b) @builtin $endswitch } -/** - * @require types::@equatable_value(a) && types::@equatable_value(b) `values must be equatable` - **/ +<* + @require types::@equatable_value(a) && types::@equatable_value(b) `values must be equatable` +*> macro bool equals(a, b) @builtin { $switch diff --git a/lib/std/core/conv.c3 b/lib/std/core/conv.c3 index ca7085c6d..b2b593775 100644 --- a/lib/std/core/conv.c3 +++ b/lib/std/core/conv.c3 @@ -9,10 +9,10 @@ const uint UTF16_SURROGATE_BITS @private = 10; const uint UTF16_SURROGATE_LOW_VALUE @private = 0xDC00; const uint UTF16_SURROGATE_HIGH_VALUE @private = 0xD800; -/** - * @param c `The utf32 codepoint to convert` - * @param [out] output `the resulting buffer` - **/ +<* + @param c `The utf32 codepoint to convert` + @param [out] output `the resulting buffer` +*> fn usz! char32_to_utf8(Char32 c, char[] output) { if (!output.len) return UnicodeResult.CONVERSION_FAILED?; @@ -45,12 +45,12 @@ fn usz! char32_to_utf8(Char32 c, char[] output) } } -/** - * Convert a code pointer into 1-2 UTF16 characters. - * - * @param c `The character to convert.` - * @param [inout] output `the resulting UTF16 buffer to write to.` - **/ +<* + Convert a code pointer into 1-2 UTF16 characters. + + @param c `The character to convert.` + @param [inout] output `the resulting UTF16 buffer to write to.` +*> fn void char32_to_utf16_unsafe(Char32 c, Char16** output) { if (c < UTF16_SURROGATE_OFFSET) @@ -66,13 +66,13 @@ fn void char32_to_utf16_unsafe(Char32 c, Char16** output) (*output)++[0] = (Char16)low; } -/** - * Convert 1-2 UTF16 data points into UTF8. - * - * @param [in] ptr `The UTF16 data to convert.` - * @param [inout] available `amount of UTF16 data available.` - * @param [inout] output `the resulting utf8 buffer to write to.` - **/ +<* + Convert 1-2 UTF16 data points into UTF8. + + @param [in] ptr `The UTF16 data to convert.` + @param [inout] available `amount of UTF16 data available.` + @param [inout] output `the resulting utf8 buffer to write to.` +*> fn void! char16_to_utf8_unsafe(Char16 *ptr, usz *available, char** output) { Char16 high = *ptr; @@ -100,10 +100,10 @@ fn void! char16_to_utf8_unsafe(Char16 *ptr, usz *available, char** output) char32_to_utf8_unsafe(uc, output); *available = 2; } -/** - * @param c `The utf32 codepoint to convert` - * @param [inout] output `the resulting buffer` - **/ +<* + @param c `The utf32 codepoint to convert` + @param [inout] output `the resulting buffer` +*> fn usz char32_to_utf8_unsafe(Char32 c, char** output) { switch @@ -129,11 +129,11 @@ fn usz char32_to_utf8_unsafe(Char32 c, char** output) } } -/** - * @param [in] ptr `pointer to the first character to parse` - * @param [inout] size `Set to max characters to read, set to characters read` - * @return `the parsed 32 bit codepoint` - **/ +<* + @param [in] ptr `pointer to the first character to parse` + @param [inout] size `Set to max characters to read, set to characters read` + @return `the parsed 32 bit codepoint` +*> fn Char32! utf8_to_char32(char* ptr, usz* size) { usz max_size = *size; @@ -184,10 +184,10 @@ fn Char32! utf8_to_char32(char* ptr, usz* size) return uc + c & 0x3F; } -/** - * @param utf8 `An UTF-8 encoded slice of bytes` - * @return `the number of encoded code points` - **/ +<* + @param utf8 `An UTF-8 encoded slice of bytes` + @return `the number of encoded code points` +*> fn usz utf8_codepoints(String utf8) { usz len = 0; @@ -198,11 +198,11 @@ fn usz utf8_codepoints(String utf8) return len; } -/** - * Calculate the UTF8 length required to encode an UTF32 array. - * @param [in] utf32 `the utf32 data to calculate from` - * @return `the length of the resulting UTF8 array` - **/ +<* + Calculate the UTF8 length required to encode an UTF32 array. + @param [in] utf32 `the utf32 data to calculate from` + @return `the length of the resulting UTF8 array` +*> fn usz utf8len_for_utf32(Char32[] utf32) { usz len = 0; @@ -223,11 +223,11 @@ fn usz utf8len_for_utf32(Char32[] utf32) return len; } -/** - * Calculate the UTF8 length required to encode an UTF16 array. - * @param [in] utf16 `the utf16 data to calculate from` - * @return `the length of the resulting UTF8 array` - **/ +<* + Calculate the UTF8 length required to encode an UTF16 array. + @param [in] utf16 `the utf16 data to calculate from` + @return `the length of the resulting UTF8 array` +*> fn usz utf8len_for_utf16(Char16[] utf16) { usz len = 0; @@ -255,11 +255,11 @@ fn usz utf8len_for_utf16(Char16[] utf16) return len; } -/** - * Calculate the UTF16 length required to encode a UTF8 array. - * @param utf8 `the utf8 data to calculate from` - * @return `the length of the resulting UTF16 array` - **/ +<* + Calculate the UTF16 length required to encode a UTF8 array. + @param utf8 `the utf8 data to calculate from` + @return `the length of the resulting UTF16 array` +*> fn usz utf16len_for_utf8(String utf8) { usz len = utf8.len; @@ -279,10 +279,10 @@ fn usz utf16len_for_utf8(String utf8) return len16; } -/** - * @param [in] utf32 `the UTF32 array to check the length for` - * @return `the required length of an UTF16 array to hold the UTF32 data.` - **/ +<* + @param [in] utf32 `the UTF32 array to check the length for` + @return `the required length of an UTF16 array to hold the UTF32 data.` +*> fn usz utf16len_for_utf32(Char32[] utf32) { usz len = utf32.len; @@ -293,13 +293,13 @@ fn usz utf16len_for_utf32(Char32[] utf32) return len; } -/** - * Convert an UTF32 array to an UTF8 array. - * - * @param [in] utf32 - * @param [out] utf8_buffer - * @return `the number of bytes written.` - **/ +<* + Convert an UTF32 array to an UTF8 array. + + @param [in] utf32 + @param [out] utf8_buffer + @return `the number of bytes written.` +*> fn usz! utf32to8(Char32[] utf32, char[] utf8_buffer) { char[] buffer = utf8_buffer; @@ -313,13 +313,13 @@ fn usz! utf32to8(Char32[] utf32, char[] utf8_buffer) return utf8_buffer.len - buffer.len; } -/** - * Convert an UTF8 array to an UTF32 array. - * - * @param [in] utf8 - * @param [out] utf32_buffer - * @return `the number of Char32s written.` - **/ +<* + Convert an UTF8 array to an UTF32 array. + + @param [in] utf8 + @param [out] utf32_buffer + @return `the number of Char32s written.` +*> fn usz! utf8to32(String utf8, Char32[] utf32_buffer) { usz len = utf8.len; @@ -339,14 +339,14 @@ fn usz! utf8to32(String utf8, Char32[] utf32_buffer) return len32; } -/** - * Copy an array of UTF16 data into an UTF8 buffer without bounds - * checking. This will assume the buffer is sufficiently large to hold - * the converted data. - * - * @param [in] utf16 `The UTF16 array containing the data to convert.` - * @param [out] utf8_buffer `the (sufficiently large) buffer to hold the UTF16 data.` - **/ +<* + Copy an array of UTF16 data into an UTF8 buffer without bounds + checking. This will assume the buffer is sufficiently large to hold + the converted data. + + @param [in] utf16 `The UTF16 array containing the data to convert.` + @param [out] utf8_buffer `the (sufficiently large) buffer to hold the UTF16 data.` +*> fn void! utf16to8_unsafe(Char16[] utf16, char* utf8_buffer) { usz len16 = utf16.len; @@ -358,14 +358,14 @@ fn void! utf16to8_unsafe(Char16[] utf16, char* utf8_buffer) } } -/** - * Copy an array of UTF8 data into an UTF32 buffer without bounds - * checking. This will assume the buffer is sufficiently large to hold - * the converted data. - * - * @param [in] utf8 `The UTF8 buffer containing the data to convert.` - * @param [out] utf32_buffer `the (sufficiently large) buffer to hold the UTF8 data.` - **/ +<* + Copy an array of UTF8 data into an UTF32 buffer without bounds + checking. This will assume the buffer is sufficiently large to hold + the converted data. + + @param [in] utf8 `The UTF8 buffer containing the data to convert.` + @param [out] utf32_buffer `the (sufficiently large) buffer to hold the UTF8 data.` +*> fn void! utf8to32_unsafe(String utf8, Char32* utf32_buffer) { usz len = utf8.len; @@ -378,14 +378,14 @@ fn void! utf8to32_unsafe(String utf8, Char32* utf32_buffer) } } -/** - * Copy an array of UTF8 data into an UTF16 buffer without bounds - * checking. This will assume the buffer is sufficiently large to hold - * the converted data. - * - * @param [in] utf8 `The UTF8 buffer containing the data to convert.` - * @param [out] utf16_buffer `the (sufficiently large) buffer to hold the UTF8 data.` - **/ +<* + Copy an array of UTF8 data into an UTF16 buffer without bounds + checking. This will assume the buffer is sufficiently large to hold + the converted data. + + @param [in] utf8 `The UTF8 buffer containing the data to convert.` + @param [out] utf16_buffer `the (sufficiently large) buffer to hold the UTF8 data.` +*> fn void! utf8to16_unsafe(String utf8, Char16* utf16_buffer) { usz len = utf8.len; @@ -398,14 +398,14 @@ fn void! utf8to16_unsafe(String utf8, Char16* utf16_buffer) } } -/** - * Copy an array of UTF32 code points into an UTF8 buffer without bounds - * checking. This will assume the buffer is sufficiently large to hold - * the converted data. - * - * @param [in] utf32 `The UTF32 buffer containing the data to convert.` - * @param [out] utf8_buffer `the (sufficiently large) buffer to hold the UTF8 data.` - **/ +<* + Copy an array of UTF32 code points into an UTF8 buffer without bounds + checking. This will assume the buffer is sufficiently large to hold + the converted data. + + @param [in] utf32 `The UTF32 buffer containing the data to convert.` + @param [out] utf8_buffer `the (sufficiently large) buffer to hold the UTF8 data.` +*> fn void utf32to8_unsafe(Char32[] utf32, char* utf8_buffer) { char* start = utf8_buffer; diff --git a/lib/std/core/dstring.c3 b/lib/std/core/dstring.c3 index 72b7a3dc1..1dcc482ab 100644 --- a/lib/std/core/dstring.c3 +++ b/lib/std/core/dstring.c3 @@ -5,9 +5,9 @@ distinct DString (OutStream) = void*; const usz MIN_CAPACITY @private = 16; -/** - * @require !self.data() "String already initialized" - **/ +<* + @require !self.data() "String already initialized" +*> fn DString DString.new_init(&self, usz capacity = MIN_CAPACITY, Allocator allocator = allocator::heap()) { if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY; @@ -18,9 +18,9 @@ fn DString DString.new_init(&self, usz capacity = MIN_CAPACITY, Allocator alloca return *self = (DString)data; } -/** - * @require !self.data() "String already initialized" - **/ +<* + @require !self.data() "String already initialized" +*> fn DString DString.temp_init(&self, usz capacity = MIN_CAPACITY) { self.new_init(capacity, allocator::temp()) @inline; @@ -138,9 +138,9 @@ fn usz DString.len(&self) @dynamic return self.data().len; } -/** - * @require new_size <= self.len() - */ +<* + @require new_size <= self.len() +*> fn void DString.chop(self, usz new_size) { if (!self) return; @@ -165,9 +165,9 @@ fn usz DString.append_utf32(&self, Char32[] chars) return self.data().len - end; } -/** - * @require index < self.len() - **/ +<* + @require index < self.len() +*> fn void DString.set(self, usz index, char c) { self.data().chars[index] = c; @@ -184,9 +184,9 @@ fn void DString.append_repeat(&self, char c, usz times) } } -/** - * @require c <= 0x10ffff - */ +<* + @require c <= 0x10ffff +*> fn usz DString.append_char32(&self, Char32 c) { char[4] buffer @noinit; @@ -333,20 +333,20 @@ fn void DString.append_char(&self, char c) data.chars[data.len++] = c; } -/** - * @require start < self.len() - * @require end < self.len() - * @require end >= start "End must be same or equal to the start" - **/ +<* + @require start < self.len() + @require end < self.len() + @require end >= start "End must be same or equal to the start" +*> fn void DString.delete_range(&self, usz start, usz end) { self.delete(start, end - start + 1); } -/** - * @require start < self.len() - * @require start + len <= self.len() - **/ +<* + @require start < self.len() + @require start + len <= self.len() +*> fn void DString.delete(&self, usz start, usz len = 1) { if (!len) return; @@ -390,9 +390,9 @@ macro void DString.append(&self, value) $endswitch } -/** - * @require index <= self.len() - **/ +<* + @require index <= self.len() +*> fn void DString.insert_chars_at(&self, usz index, String s) { if (s.len == 0) return; @@ -425,9 +425,9 @@ fn void DString.insert_chars_at(&self, usz index, String s) } } -/** - * @require index <= self.len() - **/ +<* + @require index <= self.len() +*> fn void DString.insert_string_at(&self, usz index, DString str) { StringData* other = str.data(); @@ -435,9 +435,9 @@ fn void DString.insert_string_at(&self, usz index, DString str) self.insert_at(index, str.str_view()); } -/** - * @require index <= self.len() - **/ +<* + @require index <= self.len() +*> fn void DString.insert_char_at(&self, usz index, char c) { self.reserve(1); @@ -449,9 +449,9 @@ fn void DString.insert_char_at(&self, usz index, char c) data.len++; } -/** - * @require index <= self.len() - **/ +<* + @require index <= self.len() +*> fn usz DString.insert_char32_at(&self, usz index, Char32 c) { char[4] buffer @noinit; @@ -469,9 +469,9 @@ fn usz DString.insert_char32_at(&self, usz index, Char32 c) return n; } -/** - * @require index <= self.len() - **/ +<* + @require index <= self.len() +*> fn usz DString.insert_utf32_at(&self, usz index, Char32[] chars) { usz n = conv::utf8len_for_utf32(chars); diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index 5e167bcdd..d34ae0918 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -13,175 +13,175 @@ macro bool @constant_is_power_of_2($x) @const @private return $x != 0 && ($x & ($x - 1)) == 0; } -/** - * Load a vector from memory according to a mask assuming default alignment. - * - * @param ptr "The pointer address to load from." - * @param mask "The mask for the load" - * @param passthru "The value to use for non masked values" - * @require $assignable(&&passthru, $typeof(ptr)) : "Pointer and passthru must match" - * @require @typekind(passthru) == VECTOR : "Expected passthru to be a vector" - * @require passthru.len == mask.len : "Mask and passthru must have the same length" - * - * @return "A vector with the loaded values where the mask is true, passthru where the mask is false" - **/ +<* + Load a vector from memory according to a mask assuming default alignment. + + @param ptr "The pointer address to load from." + @param mask "The mask for the load" + @param passthru "The value to use for non masked values" + @require $assignable(&&passthru, $typeof(ptr)) : "Pointer and passthru must match" + @require @typekind(passthru) == VECTOR : "Expected passthru to be a vector" + @require passthru.len == mask.len : "Mask and passthru must have the same length" + + @return "A vector with the loaded values where the mask is true, passthru where the mask is false" +*> macro masked_load(ptr, bool[<*>] mask, passthru) { return $$masked_load(ptr, mask, passthru, 0); } -/** - * Load a vector from memory according to a mask. - * - * @param ptr "The pointer address to load from." - * @param mask "The mask for the load" - * @param passthru "The value to use for non masked values" - * @param $alignment "The alignment to assume for the pointer" - * - * @require $assignable(&&passthru, $typeof(ptr)) : "Pointer and passthru must match" - * @require @typekind(passthru) == VECTOR : "Expected passthru to be a vector" - * @require passthru.len == mask.len : "Mask and passthru must have the same length" - * @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two" - * - * @return "A vector with the loaded values where the mask is true, passthru where the mask is false" - **/ +<* + Load a vector from memory according to a mask. + + @param ptr "The pointer address to load from." + @param mask "The mask for the load" + @param passthru "The value to use for non masked values" + @param $alignment "The alignment to assume for the pointer" + + @require $assignable(&&passthru, $typeof(ptr)) : "Pointer and passthru must match" + @require @typekind(passthru) == VECTOR : "Expected passthru to be a vector" + @require passthru.len == mask.len : "Mask and passthru must have the same length" + @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two" + + @return "A vector with the loaded values where the mask is true, passthru where the mask is false" +*> macro @masked_load_aligned(ptr, bool[<*>] mask, passthru, usz $alignment) { return $$masked_load(ptr, mask, passthru, $alignment); } -/** - * Load values from a pointer vector, assuming default alignment. - * - * @param ptrvec "The vector of pointers to load from." - * @param mask "The mask for the load" - * @param passthru "The value to use for non masked values" - * - * @require @typekind(ptrvec) == VECTOR : "Expected ptrvec to be a vector" - * @require @typekind(passthru) == VECTOR : "Expected passthru to be a vector" - * @require $assignable(&&passthru[0], $typeof(ptrvec[0])) : "Pointer and passthru must match" - * @require passthru.len == mask.len : "Mask and passthru must have the same length" - * @require mask.len == ptrvec.len : "Mask and ptrvec must have the same length" - * - * @return "A vector with the loaded values where the mask is true, passthru where the mask is false" - **/ +<* + Load values from a pointer vector, assuming default alignment. + + @param ptrvec "The vector of pointers to load from." + @param mask "The mask for the load" + @param passthru "The value to use for non masked values" + + @require @typekind(ptrvec) == VECTOR : "Expected ptrvec to be a vector" + @require @typekind(passthru) == VECTOR : "Expected passthru to be a vector" + @require $assignable(&&passthru[0], $typeof(ptrvec[0])) : "Pointer and passthru must match" + @require passthru.len == mask.len : "Mask and passthru must have the same length" + @require mask.len == ptrvec.len : "Mask and ptrvec must have the same length" + + @return "A vector with the loaded values where the mask is true, passthru where the mask is false" +*> macro gather(ptrvec, bool[<*>] mask, passthru) { return $$gather(ptrvec, mask, passthru, 0); } -/** - * Load values from a pointer vector. - * - * @param ptrvec "The vector of pointers to load from." - * @param mask "The mask for the load" - * @param passthru "The value to use for non masked values" - * @param $alignment "The alignment to assume for the pointers" - * - * @require @typekind(ptrvec) == VECTOR : "Expected ptrvec to be a vector" - * @require @typekind(passthru) == VECTOR : "Expected passthru to be a vector" - * @require $assignable(&&passthru[0], $typeof(ptrvec[0])) : "Pointer and passthru must match" - * @require passthru.len == mask.len : "Mask and passthru must have the same length" - * @require mask.len == ptrvec.len : "Mask and ptrvec must have the same length" - * @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two" - * - * @return "A vector with the loaded values where the mask is true, passthru where the mask is false" - **/ +<* + Load values from a pointer vector. + + @param ptrvec "The vector of pointers to load from." + @param mask "The mask for the load" + @param passthru "The value to use for non masked values" + @param $alignment "The alignment to assume for the pointers" + + @require @typekind(ptrvec) == VECTOR : "Expected ptrvec to be a vector" + @require @typekind(passthru) == VECTOR : "Expected passthru to be a vector" + @require $assignable(&&passthru[0], $typeof(ptrvec[0])) : "Pointer and passthru must match" + @require passthru.len == mask.len : "Mask and passthru must have the same length" + @require mask.len == ptrvec.len : "Mask and ptrvec must have the same length" + @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two" + + @return "A vector with the loaded values where the mask is true, passthru where the mask is false" +*> macro @gather_aligned(ptrvec, bool[<*>] mask, passthru, usz $alignment) { return $$gather(ptrvec, mask, passthru, $alignment); } -/** - * Store parts of a vector according to the mask, assuming default alignment. - * - * @param ptr "The pointer address to store to." - * @param value "The value to store masked" - * @param mask "The mask for the store" - * - * @require $assignable(&&value, $typeof(ptr)) : "Pointer and value must match" - * @require @typekind(value) == VECTOR : "Expected value to be a vector" - * @require value.len == mask.len : "Mask and value must have the same length" - **/ +<* + Store parts of a vector according to the mask, assuming default alignment. + + @param ptr "The pointer address to store to." + @param value "The value to store masked" + @param mask "The mask for the store" + + @require $assignable(&&value, $typeof(ptr)) : "Pointer and value must match" + @require @typekind(value) == VECTOR : "Expected value to be a vector" + @require value.len == mask.len : "Mask and value must have the same length" +*> macro masked_store(ptr, value, bool[<*>] mask) { return $$masked_store(ptr, value, mask, 0); } -/** - * @param ptr "The pointer address to store to." - * @param value "The value to store masked" - * @param mask "The mask for the store" - * @param $alignment "The alignment of the pointer" - * - * @require $assignable(&&value, $typeof(ptr)) : "Pointer and value must match" - * @require @typekind(value) == VECTOR : "Expected value to be a vector" - * @require value.len == mask.len : "Mask and value must have the same length" - * @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two" - * - **/ +<* + @param ptr "The pointer address to store to." + @param value "The value to store masked" + @param mask "The mask for the store" + @param $alignment "The alignment of the pointer" + + @require $assignable(&&value, $typeof(ptr)) : "Pointer and value must match" + @require @typekind(value) == VECTOR : "Expected value to be a vector" + @require value.len == mask.len : "Mask and value must have the same length" + @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two" + +*> macro @masked_store_aligned(ptr, value, bool[<*>] mask, usz $alignment) { return $$masked_store(ptr, value, mask, $alignment); } -/** - * @param ptrvec "The vector pointer containing the addresses to store to." - * @param value "The value to store masked" - * @param mask "The mask for the store" - * @require @typekind(ptrvec) == VECTOR : "Expected ptrvec to be a vector" - * @require @typekind(value) == VECTOR : "Expected value to be a vector" - * @require $assignable(&&value[0], $typeof(ptrvec[0])) : "Pointer and value must match" - * @require value.len == mask.len : "Mask and value must have the same length" - * @require mask.len == ptrvec.len : "Mask and ptrvec must have the same length" - * - **/ +<* + @param ptrvec "The vector pointer containing the addresses to store to." + @param value "The value to store masked" + @param mask "The mask for the store" + @require @typekind(ptrvec) == VECTOR : "Expected ptrvec to be a vector" + @require @typekind(value) == VECTOR : "Expected value to be a vector" + @require $assignable(&&value[0], $typeof(ptrvec[0])) : "Pointer and value must match" + @require value.len == mask.len : "Mask and value must have the same length" + @require mask.len == ptrvec.len : "Mask and ptrvec must have the same length" + +*> macro scatter(ptrvec, value, bool[<*>] mask) { return $$scatter(ptrvec, value, mask, 0); } -/** - * @param ptrvec "The vector pointer containing the addresses to store to." - * @param value "The value to store masked" - * @param mask "The mask for the store" - * @param $alignment "The alignment of the load" - * - * @require @typekind(ptrvec) == VECTOR : "Expected ptrvec to be a vector" - * @require @typekind(value) == VECTOR : "Expected value to be a vector" - * @require $assignable(&&value[0], $typeof(ptrvec[0])) : "Pointer and value must match" - * @require value.len == mask.len : "Mask and value must have the same length" - * @require mask.len == ptrvec.len : "Mask and ptrvec must have the same length" - * @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two" - **/ +<* + @param ptrvec "The vector pointer containing the addresses to store to." + @param value "The value to store masked" + @param mask "The mask for the store" + @param $alignment "The alignment of the load" + + @require @typekind(ptrvec) == VECTOR : "Expected ptrvec to be a vector" + @require @typekind(value) == VECTOR : "Expected value to be a vector" + @require $assignable(&&value[0], $typeof(ptrvec[0])) : "Pointer and value must match" + @require value.len == mask.len : "Mask and value must have the same length" + @require mask.len == ptrvec.len : "Mask and ptrvec must have the same length" + @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two" +*> macro @scatter_aligned(ptrvec, value, bool[<*>] mask, usz $alignment) { return $$scatter(ptrvec, value, mask, $alignment); } -/** - * @param [in] x "The variable or dereferenced pointer to load." - * @param $alignment "The alignment to assume for the load" - * @return "The value of x" - * - * @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two" - **/ +<* + @param [in] x "The variable or dereferenced pointer to load." + @param $alignment "The alignment to assume for the load" + @return "The value of x" + + @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two" +*> macro @unaligned_load(&x, usz $alignment) @builtin { return $$unaligned_load(x, $alignment); } -/** - * @param [out] x "The variable or dereferenced pointer to store to." - * @param value "The value to store." - * @param $alignment "The alignment to assume for the store" - * @return "The value of x" - * - * @require $assignable(value, $typeof(*x)) : "The value doesn't match the variable" - * @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two" - **/ +<* + @param [out] x "The variable or dereferenced pointer to store to." + @param value "The value to store." + @param $alignment "The alignment to assume for the store" + @return "The value of x" + + @require $assignable(value, $typeof(*x)) : "The value doesn't match the variable" + @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two" +*> macro @unaligned_store(&x, value, usz $alignment) @builtin { return $$unaligned_store(x, ($typeof(*x))value, $alignment); @@ -192,9 +192,9 @@ macro @volatile_load(&x) @builtin return $$volatile_load(x); } -/** - * @require $assignable(y, $typeof(*x)) : "The value doesn't match the variable" - **/ +<* + @require $assignable(y, $typeof(*x)) : "The value doesn't match the variable" +*> macro @volatile_store(&x, y) @builtin { return $$volatile_store(x, ($typeof(*x))y); @@ -211,58 +211,58 @@ enum AtomicOrdering : int SEQ_CONSISTENT, // Acquire semantics, ordered with other seq_consistent } -/** - * @param [in] x "the variable or dereferenced pointer to load." - * @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" - * @param $volatile "whether the load should be volatile, defaults to 'false'" - * @return "returns the value of x" - * - * @require $ordering != AtomicOrdering.RELEASE "Release ordering is not valid for load." - * @require $ordering != AtomicOrdering.ACQUIRE_RELEASE "Acquire release is not valid for load." - * @require types::may_load_atomic($typeof(x)) "Only integer, float and pointers may be used." - * @require @typekind(x) == POINTER "You can only load from a pointer" - **/ +<* + @param [in] x "the variable or dereferenced pointer to load." + @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" + @param $volatile "whether the load should be volatile, defaults to 'false'" + @return "returns the value of x" + + @require $ordering != AtomicOrdering.RELEASE "Release ordering is not valid for load." + @require $ordering != AtomicOrdering.ACQUIRE_RELEASE "Acquire release is not valid for load." + @require types::may_load_atomic($typeof(x)) "Only integer, float and pointers may be used." + @require @typekind(x) == POINTER "You can only load from a pointer" +*> macro @atomic_load(&x, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = false) @builtin { return $$atomic_load(x, $volatile, (int)$ordering); } -/** - * @param [out] x "the variable or dereferenced pointer to store to." - * @param value "the value to store." - * @param $ordering "the atomic ordering of the store, defaults to SEQ_CONSISTENT" - * @param $volatile "whether the store should be volatile, defaults to 'false'" - * - * @require $ordering != AtomicOrdering.ACQUIRE "Acquire ordering is not valid for store." - * @require $ordering != AtomicOrdering.ACQUIRE_RELEASE "Acquire release is not valid for store." - * @require types::may_load_atomic($typeof(x)) "Only integer, float and pointers may be used." - **/ +<* + @param [out] x "the variable or dereferenced pointer to store to." + @param value "the value to store." + @param $ordering "the atomic ordering of the store, defaults to SEQ_CONSISTENT" + @param $volatile "whether the store should be volatile, defaults to 'false'" + + @require $ordering != AtomicOrdering.ACQUIRE "Acquire ordering is not valid for store." + @require $ordering != AtomicOrdering.ACQUIRE_RELEASE "Acquire release is not valid for store." + @require types::may_load_atomic($typeof(x)) "Only integer, float and pointers may be used." +*> macro void @atomic_store(&x, value, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = false) @builtin { $$atomic_store(x, value, $volatile, (int)$ordering); } -/** - * @require $success != AtomicOrdering.NOT_ATOMIC && $success != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - * @require $failure != AtomicOrdering.RELEASE && $failure != AtomicOrdering.ACQUIRE_RELEASE "Acquire release is not valid." - **/ +<* + @require $success != AtomicOrdering.NOT_ATOMIC && $success != AtomicOrdering.UNORDERED "Acquire ordering is not valid." + @require $failure != AtomicOrdering.RELEASE && $failure != AtomicOrdering.ACQUIRE_RELEASE "Acquire release is not valid." +*> macro compare_exchange(ptr, compare, value, AtomicOrdering $success = SEQ_CONSISTENT, AtomicOrdering $failure = SEQ_CONSISTENT, bool $volatile = true, bool $weak = false, usz $alignment = 0) { return $$compare_exchange(ptr, compare, value, $volatile, $weak, $success.ordinal, $failure.ordinal, $alignment); } -/** - * @require $success != AtomicOrdering.NOT_ATOMIC && $success != AtomicOrdering.UNORDERED "Acquire ordering is not valid." - * @require $failure != AtomicOrdering.RELEASE && $failure != AtomicOrdering.ACQUIRE_RELEASE "Acquire release is not valid." - **/ +<* + @require $success != AtomicOrdering.NOT_ATOMIC && $success != AtomicOrdering.UNORDERED "Acquire ordering is not valid." + @require $failure != AtomicOrdering.RELEASE && $failure != AtomicOrdering.ACQUIRE_RELEASE "Acquire release is not valid." +*> macro compare_exchange_volatile(ptr, compare, value, AtomicOrdering $success = SEQ_CONSISTENT, AtomicOrdering $failure = SEQ_CONSISTENT) { return compare_exchange(ptr, compare, value, $success, $failure, true); } -/** - * @require math::is_power_of_2(alignment) - **/ +<* + @require math::is_power_of_2(alignment) +*> fn usz aligned_offset(usz offset, usz alignment) { return alignment * ((offset + alignment - 1) / alignment); @@ -273,9 +273,9 @@ macro void* aligned_pointer(void* ptr, usz alignment) return (void*)(uptr)aligned_offset((uptr)ptr, alignment); } -/** - * @require math::is_power_of_2(alignment) - **/ +<* + @require math::is_power_of_2(alignment) +*> fn bool ptr_is_aligned(void* ptr, usz alignment) @inline { return (uptr)ptr & ((uptr)alignment - 1) == 0; @@ -296,94 +296,96 @@ macro void clear_inline(void* dst, usz $len, usz $dst_align = 0, bool $is_volati $$memset_inline(dst, (char)0, $len, $is_volatile, $dst_align); } -/** - * Copy memory from src to dst efficiently, assuming the memory ranges do not overlap. - * - * @param [&out] dst "The destination to copy to" - * @param [&in] src "The source to copy from" - * @param len "The number of bytes to copy" - * @param $dst_align "the alignment of the destination if different from the default, 0 assumes the default" - * @param $src_align "the alignment of the destination if different from the default, 0 assumes the default" - * @param $is_volatile "True if this copy should be treated as volatile, i.e. it can't be optimized away." - * - * @require len == 0 || dst + len <= src || src + len <= dst : "Ranges may not overlap" - **/ +<* + Copy memory from src to dst efficiently, assuming the memory ranges do not overlap. + + @param [&out] dst "The destination to copy to" + @param [&in] src "The source to copy from" + @param len "The number of bytes to copy" + @param $dst_align "the alignment of the destination if different from the default, 0 assumes the default" + @param $src_align "the alignment of the destination if different from the default, 0 assumes the default" + @param $is_volatile "True if this copy should be treated as volatile, i.e. it can't be optimized away." + + @require len == 0 || dst + len <= src || src + len <= dst : "Ranges may not overlap" +*> macro void copy(void* dst, void* src, usz len, usz $dst_align = 0, usz $src_align = 0, bool $is_volatile = false, bool $inlined = false) { $$memcpy(dst, src, len, $is_volatile, $dst_align, $src_align); } -/** - * Copy memory from src to dst efficiently, assuming the memory ranges do not overlap, it - * will always be inlined and never call memcopy - * - * @param [&out] dst "The destination to copy to" - * @param [&in] src "The source to copy from" - * @param $len "The number of bytes to copy" - * @param $dst_align "the alignment of the destination if different from the default, 0 assumes the default" - * @param $src_align "the alignment of the destination if different from the default, 0 assumes the default" - * @param $is_volatile "True if this copy should be treated as volatile, i.e. it can't be optimized away." - * - * @require $len == 0 || dst + $len <= src || src + $len <= dst : "Ranges may not overlap" - **/ +<* + Copy memory from src to dst efficiently, assuming the memory ranges do not overlap, it + will always be inlined and never call memcopy + + @param [&out] dst "The destination to copy to" + @param [&in] src "The source to copy from" + @param $len "The number of bytes to copy" + @param $dst_align "the alignment of the destination if different from the default, 0 assumes the default" + @param $src_align "the alignment of the destination if different from the default, 0 assumes the default" + @param $is_volatile "True if this copy should be treated as volatile, i.e. it can't be optimized away." + + @require $len == 0 || dst + $len <= src || src + $len <= dst : "Ranges may not overlap" +*> macro void copy_inline(void* dst, void* src, usz $len, usz $dst_align = 0, usz $src_align = 0, bool $is_volatile = false) { $$memcpy_inline(dst, src, $len, $is_volatile, $dst_align, $src_align); } -/** - * Copy memory from src to dst but correctly handle the possibility of overlapping ranges. - * - * @param [&out] dst "The destination to copy to" - * @param [&in] src "The source to copy from" - * @param len "The number of bytes to copy" - * @param $dst_align "the alignment of the destination if different from the default, 0 assumes the default" - * @param $src_align "the alignment of the destination if different from the default, 0 assumes the default" - * @param $is_volatile "True if this copy should be treated as volatile, i.e. it can't be optimized away." - **/ +<* + Copy memory from src to dst but correctly handle the possibility of overlapping ranges. + + @param [&out] dst "The destination to copy to" + @param [&in] src "The source to copy from" + @param len "The number of bytes to copy" + @param $dst_align "the alignment of the destination if different from the default, 0 assumes the default" + @param $src_align "the alignment of the destination if different from the default, 0 assumes the default" + @param $is_volatile "True if this copy should be treated as volatile, i.e. it can't be optimized away." +*> macro void move(void* dst, void* src, usz len, usz $dst_align = 0, usz $src_align = 0, bool $is_volatile = false) { $$memmove(dst, src, len, $is_volatile, $dst_align, $src_align); } -/** - * Sets all memory in a region to that of the provided byte. - * - * @param [&out] dst "The destination to copy to" - * @param val "The value to copy into memory" - * @param len "The number of bytes to copy" - * @param $dst_align "the alignment of the destination if different from the default, 0 assumes the default" - * @param $is_volatile "True if this copy should be treated as volatile, i.e. it can't be optimized away." - * - * @ensure !len || (dst[0] == val && dst[len - 1] == val) - **/ +<* + Sets all memory in a region to that of the provided byte. + + @param [&out] dst "The destination to copy to" + @param val "The value to copy into memory" + @param len "The number of bytes to copy" + @param $dst_align "the alignment of the destination if different from the default, 0 assumes the default" + @param $is_volatile "True if this copy should be treated as volatile, i.e. it can't be optimized away." + + @ensure !len || (dst[0] == val && dst[len - 1] == val) +*> macro void set(void* dst, char val, usz len, usz $dst_align = 0, bool $is_volatile = false) { $$memset(dst, val, len, $is_volatile, $dst_align); } -/** - * Sets all memory in a region to that of the provided byte. Never calls OS memset. - * - * @param [&out] dst "The destination to copy to" - * @param val "The value to copy into memory" - * @param $len "The number of bytes to copy" - * @param $dst_align "the alignment of the destination if different from the default, 0 assumes the default" - * @param $is_volatile "True if this copy should be treated as volatile, i.e. it can't be optimized away." - * - * @ensure !$len || (dst[0] == val && dst[$len - 1] == val) - **/ +<* + Sets all memory in a region to that of the provided byte. Never calls OS memset. + + @param [&out] dst "The destination to copy to" + @param val "The value to copy into memory" + @param $len "The number of bytes to copy" + @param $dst_align "the alignment of the destination if different from the default, 0 assumes the default" + @param $is_volatile "True if this copy should be treated as volatile, i.e. it can't be optimized away." + + @ensure !$len || (dst[0] == val && dst[$len - 1] == val) +*> macro void set_inline(void* dst, char val, usz $len, usz $dst_align = 0, bool $is_volatile = false) { $$memset_inline(dst, val, $len, $is_volatile, $dst_align); } -/** - * @require values::@inner_kind(a) == TypeKind.SLICE || values::@inner_kind(a) == TypeKind.POINTER - * @require values::@inner_kind(b) == TypeKind.SLICE || values::@inner_kind(b) == TypeKind.POINTER - * @require values::@inner_kind(a) != TypeKind.SLICE || len == -1 - * @require values::@inner_kind(a) != TypeKind.POINTER || len > -1 - * @require values::@assign_to(a, b) && values::@assign_to(b, a) - **/ +<* + Test if n elements are equal in a slice, pointed to by a pointer etc. + + @require values::@inner_kind(a) == TypeKind.SLICE || values::@inner_kind(a) == TypeKind.POINTER + @require values::@inner_kind(b) == TypeKind.SLICE || values::@inner_kind(b) == TypeKind.POINTER + @require values::@inner_kind(a) != TypeKind.SLICE || len == -1 + @require values::@inner_kind(a) != TypeKind.POINTER || len > -1 + @require values::@assign_to(a, b) && values::@assign_to(b, a) +*> macro bool equals(a, b, isz len = -1, usz $align = 0) { $if !$align: @@ -429,15 +431,19 @@ macro bool equals(a, b, isz len = -1, usz $align = 0) return true; } +<* + Check if an allocation must be aligned given the type. -macro type_alloc_must_be_aligned($Type) + @return `true if the alignment of the type exceeds DEFAULT_MEM_ALIGNMENT.` +*> +macro bool type_alloc_must_be_aligned($Type) { return $Type.alignof > DEFAULT_MEM_ALIGNMENT; } -/** - * Run with a specific allocator inside of the macro body. - **/ +<* + Run with a specific allocator inside of the macro body. +*> macro void @scoped(Allocator allocator; @body()) { Allocator old_allocator = allocator::thread_allocator; @@ -446,6 +452,10 @@ macro void @scoped(Allocator allocator; @body()) @body(); } +<* + Run the tracking allocator in the scope, then + print out stats. +*> macro void @report_heap_allocs_in_scope(;@body()) { TrackingAllocator tracker; @@ -461,6 +471,14 @@ macro void @report_heap_allocs_in_scope(;@body()) @body(); } +<* + Allocate [size] bytes on the stack to use for allocation, + with the heap allocator as the backing allocator. + + Release everything on scope exit. + + @param $size `the size of the buffer` +*> macro void @stack_mem(usz $size; @body(Allocator mem)) @builtin { char[$size] buffer; @@ -487,11 +505,10 @@ struct TempState TempAllocator* old; TempAllocator* current; usz mark; -} - -/** - * Push the current temp allocator. A push must always be balanced with a pop using the current state. - **/ +}/* +/+++ + Push the current temp allocator. A push must always be balanced with a pop using the current state. ++++/ */ fn TempState temp_push(TempAllocator* other = null) { TempAllocator* current = allocator::temp(); @@ -503,9 +520,9 @@ fn TempState temp_push(TempAllocator* other = null) return { old, current, current.used }; } -/** - * Pop the current temp allocator. A pop must always be balanced with a push. - **/ +<* + Pop the current temp allocator. A pop must always be balanced with a push. +*> fn void temp_pop(TempState old_state) { assert(allocator::thread_temp_allocator == old_state.current, "Tried to pop temp allocators out of order."); @@ -580,10 +597,10 @@ fn void* malloc(usz size) @builtin @inline @nodiscard return allocator::malloc(allocator::heap(), size); } -/** - * Allocate using an aligned allocation. This is necessary for types with a default memory alignment - * exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. - **/ +<* + Allocate using an aligned allocation. This is necessary for types with a default memory alignment + exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. +*> fn void* malloc_aligned(usz size, usz alignment) @builtin @inline @nodiscard { return allocator::malloc_aligned(allocator::heap(), size, alignment)!!; @@ -595,11 +612,11 @@ fn void* tmalloc(usz size, usz alignment = 0) @builtin @inline @nodiscard return allocator::temp().acquire(size, NO_ZERO, alignment)!!; } -/** - * @require $vacount < 2 : "Too many arguments." - * @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type" - * @require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead" - **/ +<* + @require $vacount < 2 : "Too many arguments." + @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type" + @require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead" +*> macro new($Type, ...) @nodiscard { $if $vacount == 0: @@ -611,12 +628,12 @@ macro new($Type, ...) @nodiscard $endif } -/** - * Allocate using an aligned allocation. This is necessary for types with a default memory alignment - * exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. - * @require $vacount < 2 : "Too many arguments." - * @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type" - **/ +<* + Allocate using an aligned allocation. This is necessary for types with a default memory alignment + exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. + @require $vacount < 2 : "Too many arguments." + @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type" +*> macro new_aligned($Type, ...) @nodiscard { $if $vacount == 0: @@ -628,27 +645,27 @@ macro new_aligned($Type, ...) @nodiscard $endif } -/** - * @require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead" - **/ +<* + @require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead" +*> macro alloc($Type) @nodiscard { return ($Type*)malloc($Type.sizeof); } -/** - * Allocate using an aligned allocation. This is necessary for types with a default memory alignment - * exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. - **/ +<* + Allocate using an aligned allocation. This is necessary for types with a default memory alignment + exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. +*> macro alloc_aligned($Type) @nodiscard { return ($Type*)malloc_aligned($Type.sizeof, $Type.alignof); } -/** - * @require $vacount < 2 : "Too many arguments." - * @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type" - **/ +<* + @require $vacount < 2 : "Too many arguments." + @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type" +*> macro temp_new($Type, ...) @nodiscard { $if $vacount == 0: @@ -666,35 +683,35 @@ macro temp_alloc($Type) @nodiscard } -/** - * @require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_array_aligned' instead" - **/ +<* + @require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_array_aligned' instead" +*> macro new_array($Type, usz elements) @nodiscard { return allocator::new_array(allocator::heap(), $Type, elements); } -/** - * Allocate using an aligned allocation. This is necessary for types with a default memory alignment - * exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. - **/ +<* + Allocate using an aligned allocation. This is necessary for types with a default memory alignment + exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. +*> macro new_array_aligned($Type, usz elements) @nodiscard { return allocator::new_array_aligned(allocator::heap(), $Type, elements); } -/** - * @require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_array_aligned' instead" - **/ +<* + @require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_array_aligned' instead" +*> macro alloc_array($Type, usz elements) @nodiscard { return allocator::alloc_array(allocator::heap(), $Type, elements); } -/** - * Allocate using an aligned allocation. This is necessary for types with a default memory alignment - * exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. - **/ +<* + Allocate using an aligned allocation. This is necessary for types with a default memory alignment + exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. +*> macro alloc_array_aligned($Type, usz elements) @nodiscard { return allocator::alloc_array_aligned(allocator::heap(), $Type, elements); @@ -715,10 +732,10 @@ fn void* calloc(usz size) @builtin @inline @nodiscard return allocator::calloc(allocator::heap(), size); } -/** - * Allocate using an aligned allocation. This is necessary for types with a default memory alignment - * exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. - **/ +<* + Allocate using an aligned allocation. This is necessary for types with a default memory alignment + exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. +*> fn void* calloc_aligned(usz size, usz alignment) @builtin @inline @nodiscard { return allocator::calloc_aligned(allocator::heap(), size, alignment)!!; diff --git a/lib/std/core/mem_allocator.c3 b/lib/std/core/mem_allocator.c3 index 00458fb97..f930dc22e 100644 --- a/lib/std/core/mem_allocator.c3 +++ b/lib/std/core/mem_allocator.c3 @@ -20,22 +20,22 @@ interface Allocator { fn void reset(usz mark) @optional; fn usz mark() @optional; - /** + <* * @require !alignment || math::is_power_of_2(alignment) * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` * @require size > 0 - **/ + *> fn void*! acquire(usz size, AllocInitType init_type, usz alignment = 0); - /** + <* * @require !alignment || math::is_power_of_2(alignment) * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` * @require ptr != null * @require new_size > 0 - **/ + *> fn void*! resize(void* ptr, usz new_size, usz alignment = 0); - /** + <* * @require ptr != null - **/ + *> fn void release(void* ptr, bool aligned); } @@ -146,11 +146,11 @@ macro void free_aligned(Allocator allocator, void* ptr) allocator.release(ptr, aligned: true); } -/** - * @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_aligned' instead" - * @require $vacount < 2 : "Too many arguments." - * @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type" - **/ +<* + @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_aligned' instead" + @require $vacount < 2 : "Too many arguments." + @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type" +*> macro new(Allocator allocator, $Type, ...) @nodiscard { $if $vacount == 0: @@ -162,11 +162,11 @@ macro new(Allocator allocator, $Type, ...) @nodiscard $endif } -/** - * @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_aligned' instead" - * @require $vacount < 2 : "Too many arguments." - * @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type" - **/ +<* + @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_aligned' instead" + @require $vacount < 2 : "Too many arguments." + @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type" +*> macro new_try(Allocator allocator, $Type, ...) @nodiscard { $if $vacount == 0: @@ -178,12 +178,12 @@ macro new_try(Allocator allocator, $Type, ...) @nodiscard $endif } -/** - * Allocate using an aligned allocation. This is necessary for types with a default memory alignment - * exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. - * @require $vacount < 2 : "Too many arguments." - * @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type" - **/ +<* + Allocate using an aligned allocation. This is necessary for types with a default memory alignment + exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. + @require $vacount < 2 : "Too many arguments." + @require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type" +*> macro new_aligned($Type, ...) @nodiscard { $if $vacount == 0: @@ -195,92 +195,92 @@ macro new_aligned($Type, ...) @nodiscard $endif } -/** - * @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT - **/ +<* + @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT +*> macro new_with_padding(Allocator allocator, $Type, usz padding) @nodiscard { return ($Type*)calloc_try(allocator, $Type.sizeof + padding); } -/** - * @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead" - **/ +<* + @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead" +*> macro alloc(Allocator allocator, $Type) @nodiscard { return ($Type*)malloc(allocator, $Type.sizeof); } -/** - * @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead" - **/ +<* + @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead" +*> macro alloc_try(Allocator allocator, $Type) @nodiscard { return ($Type*)malloc_try(allocator, $Type.sizeof); } -/** - * Allocate using an aligned allocation. This is necessary for types with a default memory alignment - * exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. - **/ +<* + Allocate using an aligned allocation. This is necessary for types with a default memory alignment + exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. +*> macro alloc_aligned(Allocator allocator, $Type) @nodiscard { return ($Type*)malloc_aligned(allocator, $Type.sizeof, $Type.alignof); } -/** - * @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT - **/ +<* + @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT +*> macro alloc_with_padding(Allocator allocator, $Type, usz padding) @nodiscard { return ($Type*)malloc_try(allocator, $Type.sizeof + padding); } -/** - * @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_array_aligned' instead" - **/ +<* + @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_array_aligned' instead" +*> macro new_array(Allocator allocator, $Type, usz elements) @nodiscard { return new_array_try(allocator, $Type, elements)!!; } -/** - * @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_array_aligned' instead" - **/ +<* + @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_array_aligned' instead" +*> macro new_array_try(Allocator allocator, $Type, usz elements) @nodiscard { return (($Type*)calloc_try(allocator, $Type.sizeof * elements))[:elements]; } -/** - * Allocate using an aligned allocation. This is necessary for types with a default memory alignment - * exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. - **/ +<* + Allocate using an aligned allocation. This is necessary for types with a default memory alignment + exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. +*> macro new_array_aligned(Allocator allocator, $Type, usz elements) @nodiscard { return (($Type*)calloc_aligned(allocator, $Type.sizeof * elements, $Type.alignof))[:elements]!!; } -/** - * @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_array_aligned' instead" - **/ +<* + @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_array_aligned' instead" +*> macro alloc_array(Allocator allocator, $Type, usz elements) @nodiscard { return alloc_array_try(allocator, $Type, elements)!!; } -/** - * Allocate using an aligned allocation. This is necessary for types with a default memory alignment - * exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. - **/ +<* + Allocate using an aligned allocation. This is necessary for types with a default memory alignment + exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned. +*> macro alloc_array_aligned(Allocator allocator, $Type, usz elements) @nodiscard { return (($Type*)malloc_aligned(allocator, $Type.sizeof * elements, $Type.alignof))[:elements]!!; } -/** - * @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_array_aligned' instead" - **/ +<* + @require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_array_aligned' instead" +*> macro alloc_array_try(Allocator allocator, $Type, usz elements) @nodiscard { return (($Type*)malloc_try(allocator, $Type.sizeof * elements))[:elements]; @@ -300,11 +300,11 @@ fn any clone_any(Allocator allocator, any value) @nodiscard } -/** - * @require bytes > 0 - * @require alignment > 0 - * @require bytes <= isz.max - **/ +<* + @require bytes > 0 + @require alignment > 0 + @require bytes <= isz.max +*> macro void*! @aligned_alloc(#alloc_fn, usz bytes, usz alignment) { if (alignment < void*.alignof) alignment = void*.alignof; @@ -338,10 +338,10 @@ macro void! @aligned_free(#free_fn, void* old_pointer) $endif } -/** - * @require bytes > 0 - * @require alignment > 0 - **/ +<* + @require bytes > 0 + @require alignment > 0 +*> macro void*! @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes, usz alignment) { AlignedBlock* desc = (AlignedBlock*)old_pointer - 1; @@ -412,9 +412,9 @@ fn void destroy_temp_allocators_after_exit() @finalizer(65535) @local @if(env::L destroy_temp_allocators(); } -/** - * Call this to destroy any memory used by the temp allocators. This will invalidate all temp memory. - **/ +<* + Call this to destroy any memory used by the temp allocators. This will invalidate all temp memory. +*> fn void destroy_temp_allocators() { if (!thread_temp_allocator) return; diff --git a/lib/std/core/sanitizer/asan.c3 b/lib/std/core/sanitizer/asan.c3 index 118235d38..890e9857a 100644 --- a/lib/std/core/sanitizer/asan.c3 +++ b/lib/std/core/sanitizer/asan.c3 @@ -14,21 +14,21 @@ module std::core::sanitizer::asan; def ErrorCallback = fn void (ZString); -/** - * Marks a memory region ([addr, addr+size)) as unaddressable. - * - * This memory must be previously allocated by your program. Instrumented - * code is forbidden from accessing addresses in this region until it is - * unpoisoned. This function is not guaranteed to poison the entire region - - * it could poison only a subregion of [addr, addr+size) due to ASan - * alignment restrictions. - * - * NOTE This function is not thread-safe because no two threads can poison or - * unpoison memory in the same memory region simultaneously. - * - * @param addr "Start of memory region." - * @param size "Size of memory region." - **/ +<* + Marks a memory region ([addr, addr+size)) as unaddressable. + + This memory must be previously allocated by your program. Instrumented + code is forbidden from accessing addresses in this region until it is + unpoisoned. This function is not guaranteed to poison the entire region - + it could poison only a subregion of [addr, addr+size) due to ASan + alignment restrictions. + + NOTE This function is not thread-safe because no two threads can poison or + unpoison memory in the same memory region simultaneously. + + @param addr "Start of memory region." + @param size "Size of memory region." +*> macro poison_memory_region(void* addr, usz size) { $if env::ADDRESS_SANITIZER: @@ -36,20 +36,20 @@ macro poison_memory_region(void* addr, usz size) $endif } -/** - * Marks a memory region ([addr, addr+size)) as addressable. - * - * This memory must be previously allocated by your program. Accessing - * addresses in this region is allowed until this region is poisoned again. - * This function could unpoison a super-region of [addr, addr+size) due - * to ASan alignment restrictions. - * - * NOTE This function is not thread-safe because no two threads can - * poison or unpoison memory in the same memory region simultaneously. - * - * @param addr "Start of memory region." - * @param size "Size of memory region." - **/ +<* + Marks a memory region ([addr, addr+size)) as addressable. + + This memory must be previously allocated by your program. Accessing + addresses in this region is allowed until this region is poisoned again. + This function could unpoison a super-region of [addr, addr+size) due + to ASan alignment restrictions. + + NOTE This function is not thread-safe because no two threads can + poison or unpoison memory in the same memory region simultaneously. + + @param addr "Start of memory region." + @param size "Size of memory region." +*> macro unpoison_memory_region(void* addr, usz size) { $if env::ADDRESS_SANITIZER: @@ -57,11 +57,11 @@ macro unpoison_memory_region(void* addr, usz size) $endif } -/** - * Checks if an address is poisoned. - * @return "True if 'addr' is poisoned (that is, 1-byte read/write access to this address would result in an error report from ASan). Otherwise returns false." - * @param addr "Address to check." - **/ +<* + Checks if an address is poisoned. + @return "True if 'addr' is poisoned (that is, 1-byte read/write access to this address would result in an error report from ASan). Otherwise returns false." + @param addr "Address to check." +*> macro bool address_is_poisoned(void* addr) { $if env::ADDRESS_SANITIZER: @@ -71,16 +71,16 @@ macro bool address_is_poisoned(void* addr) $endif } -/** - * Checks if a region is poisoned. - * - * If at least one byte in [beg, beg+size) is poisoned, returns the - * address of the first such byte. Otherwise returns 0. - * - * @param beg "Start of memory region." - * @param size "Start of memory region." - * @return "Address of first poisoned byte." - **/ +<* + Checks if a region is poisoned. + + If at least one byte in [beg, beg+size) is poisoned, returns the + address of the first such byte. Otherwise returns 0. + + @param beg "Start of memory region." + @param size "Start of memory region." + @return "Address of first poisoned byte." +*> macro void* region_is_poisoned(void* beg, usz size) { $if env::ADDRESS_SANITIZER: @@ -90,9 +90,9 @@ macro void* region_is_poisoned(void* beg, usz size) $endif } -/** - * Sets the callback function to be called during ASan error reporting. - **/ +<* + Sets the callback function to be called during ASan error reporting. +*> fn void set_error_report_callback(ErrorCallback callback) { $if env::ADDRESS_SANITIZER: diff --git a/lib/std/core/string.c3 b/lib/std/core/string.c3 index d6db44754..0f8234c4a 100644 --- a/lib/std/core/string.c3 +++ b/lib/std/core/string.c3 @@ -33,11 +33,11 @@ fault NumberConversion } -/** - * Return a temporary ZString created using the formatting function. - * - * @param [in] fmt `The formatting string` - **/ +<* + Return a temporary ZString created using the formatting function. + + @param [in] fmt `The formatting string` +*> fn ZString tformat_zstr(String fmt, args...) { DString str = dstring::temp_with_capacity(fmt.len + args.len * 8); @@ -45,12 +45,12 @@ fn ZString tformat_zstr(String fmt, args...) return str.zstr_view(); } -/** - * Return a new String created using the formatting function. - * - * @param [inout] allocator `The allocator to use` - * @param [in] fmt `The formatting string` - **/ +<* + Return a new String created using the formatting function. + + @param [inout] allocator `The allocator to use` + @param [in] fmt `The formatting string` +*> fn String format(String fmt, args..., Allocator allocator) { @pool(allocator) @@ -61,18 +61,18 @@ fn String format(String fmt, args..., Allocator allocator) }; } -/** - * Return a heap allocated String created using the formatting function. - * - * @param [in] fmt `The formatting string` - **/ +<* + Return a heap allocated String created using the formatting function. + + @param [in] fmt `The formatting string` +*> fn String new_format(String fmt, args..., Allocator allocator = null) => format(fmt, ...args, allocator: allocator ?: allocator::heap()); -/** - * Return a temporary String created using the formatting function. - * - * @param [in] fmt `The formatting string` - **/ +<* + Return a temporary String created using the formatting function. + + @param [in] fmt `The formatting string` +*> fn String tformat(String fmt, args...) { DString str = dstring::temp_with_capacity(fmt.len + args.len * 8); @@ -80,12 +80,12 @@ fn String tformat(String fmt, args...) return str.str_view(); } -/** - * Return a new ZString created using the formatting function. - * - * @param [in] fmt `The formatting string` - * @param [inout] allocator `The allocator to use` - **/ +<* + Return a new ZString created using the formatting function. + + @param [in] fmt `The formatting string` + @param [inout] allocator `The allocator to use` +*> fn ZString new_format_zstr(String fmt, args..., Allocator allocator = allocator::heap()) { @pool(allocator) @@ -96,14 +96,14 @@ fn ZString new_format_zstr(String fmt, args..., Allocator allocator = allocator: }; } -/** - * Check if a character is in a set. - * - * @param c `the character to check` - * @param [in] set `The formatting string` - * @pure - * @return `True if a character is in the set` - **/ +<* + Check if a character is in a set. + + @param c `the character to check` + @param [in] set `The formatting string` + @pure + @return `True if a character is in the set` +*> macro bool char_in_set(char c, String set) { foreach (ch : set) if (ch == c) return true; @@ -135,14 +135,14 @@ fn String join_new(String[] s, String joiner, Allocator allocator = allocator::h }; } -/** - * Remove characters from the front and end of a string. - * - * @param [in] string `The string to trim` - * @param [in] to_trim `The set of characters to trim, defaults to whitespace` - * @pure - * @return `a substring of the string passed in` - **/ +<* + Remove characters from the front and end of a string. + + @param [in] string `The string to trim` + @param [in] to_trim `The set of characters to trim, defaults to whitespace` + @pure + @return `a substring of the string passed in` +*> fn String String.trim(string, String to_trim = "\t\n\r ") { usz start = 0; @@ -154,14 +154,14 @@ fn String String.trim(string, String to_trim = "\t\n\r ") return string[start..end]; } -/** - * Check if the String starts with the needle. - * - * @param [in] string - * @param [in] needle - * @pure - * @return `'true' if the string starts with the needle` - **/ +<* + Check if the String starts with the needle. + + @param [in] string + @param [in] needle + @pure + @return `'true' if the string starts with the needle` +*> fn bool String.starts_with(string, String needle) { if (needle.len > string.len) return false; @@ -169,14 +169,14 @@ fn bool String.starts_with(string, String needle) return string[:needle.len] == needle; } -/** - * Check if the String ends with the needle. - * - * @param [in] string - * @param [in] needle - * @pure - * @return `'true' if the string ends with the needle` - **/ +<* + Check if the String ends with the needle. + + @param [in] string + @param [in] needle + @pure + @return `'true' if the string ends with the needle` +*> fn bool String.ends_with(string, String needle) { if (needle.len > string.len) return false; @@ -184,28 +184,28 @@ fn bool String.ends_with(string, String needle) return string[^needle.len..] == needle; } -/** - * Strip the front of the string if the prefix exists. - * - * @param [in] string - * @param [in] needle - * @pure - * @return `the substring with the prefix removed` - **/ +<* + Strip the front of the string if the prefix exists. + + @param [in] string + @param [in] needle + @pure + @return `the substring with the prefix removed` +*> fn String String.strip(string, String needle) { if (!needle.len || !string.starts_with(needle)) return string; return string[needle.len..]; } -/** - * Strip the end of the string if the suffix exists. - * - * @param [in] string - * @param [in] needle - * @pure - * @return `the substring with the suffix removed` - **/ +<* + Strip the end of the string if the suffix exists. + + @param [in] string + @param [in] needle + @pure + @return `the substring with the suffix removed` +*> fn String String.strip_end(string, String needle) { if (!needle.len || !string.ends_with(needle)) return string; @@ -213,16 +213,16 @@ fn String String.strip_end(string, String needle) return string[:(string.len - needle.len)]; } -/** - * Split a string into parts, e.g "a|b|c" split with "|" yields { "a", "b", "c" } - * - * @param [in] s - * @param [in] needle - * @param [&inout] allocator "The allocator to use for the String[]" - * @param max "Max number of elements, 0 means no limit, defaults to 0" - * @require needle.len > 0 "The needle must be at least 1 character long" - * @ensure return.len > 0 - **/ +<* + Split a string into parts, e.g "a|b|c" split with "|" yields { "a", "b", "c" } + + @param [in] s + @param [in] needle + @param [&inout] allocator "The allocator to use for the String[]" + @param max "Max number of elements, 0 means no limit, defaults to 0" + @require needle.len > 0 "The needle must be at least 1 character long" + @ensure return.len > 0 +*> fn String[] String.split(s, String needle, usz max = 0, Allocator allocator = allocator::heap()) { usz capacity = 16; @@ -253,51 +253,51 @@ fn String[] String.split(s, String needle, usz max = 0, Allocator allocator = al return holder[:i]; } -/** - * Split a string into parts, e.g "a|b|c" split with "|" yields { "a", "b", "c" }, using the heap allocator - * to store the parts. - * - * @param [in] s - * @param [in] needle - * @param max "Max number of elements, 0 means no limit, defaults to 0" - * @require needle.len > 0 "The needle must be at least 1 character long" - * @ensure return.len > 0 - **/ +<* + Split a string into parts, e.g "a|b|c" split with "|" yields { "a", "b", "c" }, using the heap allocator + to store the parts. + + @param [in] s + @param [in] needle + @param max "Max number of elements, 0 means no limit, defaults to 0" + @require needle.len > 0 "The needle must be at least 1 character long" + @ensure return.len > 0 +*> fn String[] String.new_split(s, String needle, usz max = 0) => s.split(needle, max, allocator::heap()) @inline; -/** - * This function is identical to String.split, but implicitly uses the - * temporary allocator. - * - * @param [in] s - * @param [in] needle - * @param max "Max number of elements, 0 means no limit, defaults to 0" - **/ +<* + This function is identical to String.split, but implicitly uses the + temporary allocator. + + @param [in] s + @param [in] needle + @param max "Max number of elements, 0 means no limit, defaults to 0" +*> fn String[] String.tsplit(s, String needle, usz max = 0) => s.split(needle, max, allocator::temp()) @inline; -/** - * Check if a substring is found in the string. +<* + Check if a substring is found in the string. - * @param [in] s - * @param [in] needle "The string to look for." - * @pure - * @return "true if the string contains the substring, false otherwise" - **/ + @param [in] s + @param [in] needle "The string to look for." + @pure + @return "true if the string contains the substring, false otherwise" +*> fn bool String.contains(s, String needle) { return @ok(s.index_of(needle)); } -/** - * Find the index of the first incidence of a string. - * - * @param [in] s - * @param needle "The character to look for" - * @pure - * @ensure return < s.len - * @return "the index of the needle" - * @return! SearchResult.MISSING "if the needle cannot be found" - **/ +<* + Find the index of the first incidence of a string. + + @param [in] s + @param needle "The character to look for" + @pure + @ensure return < s.len + @return "the index of the needle" + @return! SearchResult.MISSING "if the needle cannot be found" +*> fn usz! String.index_of_char(s, char needle) { foreach (i, c : s) @@ -307,17 +307,17 @@ fn usz! String.index_of_char(s, char needle) return SearchResult.MISSING?; } -/** - * Find the index of the first incidence of a character. - * - * @param [in] s - * @param needle "The character to look for" - * @param start_index "The index to start with, may exceed max index." - * @pure - * @ensure return < s.len - * @return "the index of the needle" - * @return! SearchResult.MISSING "if the needle cannot be found starting from the start_index" - **/ +<* + Find the index of the first incidence of a character. + + @param [in] s + @param needle "The character to look for" + @param start_index "The index to start with, may exceed max index." + @pure + @ensure return < s.len + @return "the index of the needle" + @return! SearchResult.MISSING "if the needle cannot be found starting from the start_index" +*> fn usz! String.index_of_char_from(s, char needle, usz start_index) { usz len = s.len; @@ -329,16 +329,16 @@ fn usz! String.index_of_char_from(s, char needle, usz start_index) return SearchResult.MISSING?; } -/** - * Find the index of the first incidence of a character starting from the end. - * - * @param [in] s - * @param needle "the character to find" - * @pure - * @ensure return < s.len - * @return "the index of the needle" - * @return! SearchResult.MISSING "if the needle cannot be found" - **/ +<* + Find the index of the first incidence of a character starting from the end. + + @param [in] s + @param needle "the character to find" + @pure + @ensure return < s.len + @return "the index of the needle" + @return! SearchResult.MISSING "if the needle cannot be found" +*> fn usz! String.rindex_of_char(s, char needle) { foreach_r (i, c : s) @@ -348,17 +348,17 @@ fn usz! String.rindex_of_char(s, char needle) return SearchResult.MISSING?; } -/** - * Find the index of the first incidence of a string. - * - * @param [in] s - * @param [in] needle - * @pure - * @ensure return < s.len - * @require needle.len > 0 : "The needle must be len 1 or more" - * @return "the index of the needle" - * @return! SearchResult.MISSING "if the needle cannot be found" - **/ +<* + Find the index of the first incidence of a string. + + @param [in] s + @param [in] needle + @pure + @ensure return < s.len + @require needle.len > 0 : "The needle must be len 1 or more" + @return "the index of the needle" + @return! SearchResult.MISSING "if the needle cannot be found" +*> fn usz! String.index_of(s, String needle) { usz needed = needle.len; @@ -373,17 +373,17 @@ fn usz! String.index_of(s, String needle) return SearchResult.MISSING?; } -/** - * Find the index of the last incidence of a string. - * - * @param [in] s - * @param [in] needle - * @pure - * @ensure return < s.len - * @require needle.len > 0 "The needle must be len 1 or more" - * @return "the index of the needle" - * @return! SearchResult.MISSING "if the needle cannot be found" - **/ +<* + Find the index of the last incidence of a string. + + @param [in] s + @param [in] needle + @pure + @ensure return < s.len + @require needle.len > 0 "The needle must be len 1 or more" + @return "the index of the needle" + @return! SearchResult.MISSING "if the needle cannot be found" +*> fn usz! String.rindex_of(s, String needle) { usz needed = needle.len; @@ -476,12 +476,12 @@ fn String ZString.tcopy(z) return z.str_view().copy(allocator::temp()) @inline; } -/** - * Convert an UTF-8 string to UTF-16 - * @return "The UTF-16 string as a slice, allocated using the given allocator" - * @return! UnicodeResult.INVALID_UTF8 "If the string contained an invalid UTF-8 sequence" - * @return! AllocationFailure "If allocation of the string fails" - **/ +<* + Convert an UTF-8 string to UTF-16 + @return "The UTF-16 string as a slice, allocated using the given allocator" + @return! UnicodeResult.INVALID_UTF8 "If the string contained an invalid UTF-8 sequence" + @return! AllocationFailure "If allocation of the string fails" +*> fn Char16[]! String.to_new_utf16(s, Allocator allocator = allocator::heap()) { usz len16 = conv::utf16len_for_utf8(s); @@ -491,12 +491,12 @@ fn Char16[]! String.to_new_utf16(s, Allocator allocator = allocator::heap()) return data[:len16]; } -/** - * Convert an UTF-8 string to UTF-16 - * @return "The UTF-16 string as a slice, allocated using the given allocator" - * @return! UnicodeResult.INVALID_UTF8 "If the string contained an invalid UTF-8 sequence" - * @return! AllocationFailure "If allocation of the string fails" - **/ +<* + Convert an UTF-8 string to UTF-16 + @return "The UTF-16 string as a slice, allocated using the given allocator" + @return! UnicodeResult.INVALID_UTF8 "If the string contained an invalid UTF-8 sequence" + @return! AllocationFailure "If allocation of the string fails" +*> fn Char16[]! String.to_temp_utf16(s) { return s.to_new_utf16(allocator::temp()); @@ -522,12 +522,12 @@ fn Char32[]! String.to_utf32(s, Allocator allocator) fn Char32[]! String.to_new_utf32(s) => s.to_utf32(allocator::heap()) @inline; fn Char32[]! String.to_temp_utf32(s) => s.to_utf32(allocator::temp()) @inline; -/** - * Convert a string to ASCII lower case. - * - * @param [inout] s - * @pure - **/ +<* + Convert a string to ASCII lower case. + + @param [inout] s + @pure +*> fn void String.convert_ascii_to_lower(s) { foreach (&c : s) if (c.is_upper() @pure) *c += 'a' - 'A'; @@ -545,25 +545,25 @@ fn String String.temp_ascii_to_lower(s) return s.new_ascii_to_lower(allocator::temp()); } -/** - * Convert a string to ASCII upper case. - * - * @param [inout] s - * @pure - **/ +<* + Convert a string to ASCII upper case. + + @param [inout] s + @pure +*> fn void String.convert_ascii_to_upper(s) { foreach (&c : s) if (c.is_lower() @pure) *c -= 'a' - 'A'; } -/** - * Returns a string converted to ASCII upper case. - * - * @param [in] s - * @param [inout] allocator - * - * @return `a new String converted to ASCII upper case.` - **/ +<* + Returns a string converted to ASCII upper case. + + @param [in] s + @param [inout] allocator + + @return `a new String converted to ASCII upper case.` +*> fn String String.new_ascii_to_upper(s, Allocator allocator = allocator::heap()) { String copy = s.copy(allocator); @@ -576,10 +576,10 @@ fn StringIterator String.iterator(s) return { s, 0 }; } -/** - * @param [in] s - * @return `a temporary String converted to ASCII upper case.` - **/ +<* + @param [in] s + @return `a temporary String converted to ASCII upper case.` +*> fn String String.temp_ascii_to_upper(s) { return s.new_ascii_to_upper(allocator::temp()); @@ -627,9 +627,9 @@ fn usz String.utf8_codepoints(s) } -/** - * @require (base <= 10 && base > 1) || base == 16 : "Unsupported base" - **/ +<* + @require (base <= 10 && base > 1) || base == 16 : "Unsupported base" +*> macro String.to_integer(string, $Type, int base = 10) { usz len = string.len; diff --git a/lib/std/core/string_to_real.c3 b/lib/std/core/string_to_real.c3 index d970b591a..cd89b86d6 100644 --- a/lib/std/core/string_to_real.c3 +++ b/lib/std/core/string_to_real.c3 @@ -31,9 +31,9 @@ const MASK = KMAX - 1; const B1B_DIG = 2; const uint[2] B1B_MAX = { 9007199, 254740991 }; -/** - * @require chars.len > 0 - **/ +<* + @require chars.len > 0 +*> macro double! decfloat(char[] chars, int $bits, int $emin, int sign) { uint[KMAX] x; @@ -266,7 +266,7 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign) y *= sign; bool denormal; - /* Limit precision for denormal results */ + // Limit precision for denormal results uint bits = $bits; if (bits > math::DOUBLE_MANT_DIG + e2 - $emin) { diff --git a/lib/std/core/types.c3 b/lib/std/core/types.c3 index ccb147782..6b40b1145 100644 --- a/lib/std/core/types.c3 +++ b/lib/std/core/types.c3 @@ -8,9 +8,9 @@ fault ConversionResult VALUE_OUT_OF_RANGE, VALUE_OUT_OF_UNSIGNED_RANGE, } -/** - * @require $Type.kindof.is_int() || $Type.kindof == TypeKind.ENUM "Argument was not an integer" - **/ +<* + @require $Type.kindof.is_int() || $Type.kindof == TypeKind.ENUM "Argument was not an integer" +*> macro any_to_int(any v, $Type) { typeid any_type = v.type; @@ -123,9 +123,9 @@ macro bool is_slice_convertable($Type) macro bool is_bool($Type) @const => $Type.kindof == TypeKind.BOOL; macro bool is_int($Type) @const => $Type.kindof == TypeKind.SIGNED_INT || $Type.kindof == TypeKind.UNSIGNED_INT; -/** - * @require is_numerical($Type) "Expected a numerical type" - **/ +<* + @require is_numerical($Type) "Expected a numerical type" +*> macro bool is_signed($Type) @const { $switch (inner_kind($Type)) @@ -139,9 +139,9 @@ macro bool is_signed($Type) @const $endswitch } -/** - * @require is_numerical($Type) "Expected a numerical type" - **/ +<* + @require is_numerical($Type) "Expected a numerical type" +*> macro bool is_unsigned($Type) @const { $switch (inner_kind($Type)) @@ -304,9 +304,9 @@ macro bool is_equatable_type($Type) @const $endif } -/** - * Checks if a type implements the copy protocol. - **/ +<* + Checks if a type implements the copy protocol. +*> macro bool implements_copy($Type) @const { return $defined($Type.copy) && $defined($Type.free); diff --git a/lib/std/core/values.c3 b/lib/std/core/values.c3 index 52e1bb145..4439d52b1 100644 --- a/lib/std/core/values.c3 +++ b/lib/std/core/values.c3 @@ -3,9 +3,9 @@ module std::core::values; macro typeid @typeid(#value) @const @builtin => $typeof(#value).typeid; macro TypeKind @typekind(#value) @const @builtin => $typeof(#value).kindof; macro bool @typeis(#value, $Type) @const @builtin => $typeof(#value).typeid == $Type.typeid; -/** - * Return true if two values have the same type before any conversions. - **/ +<* + Return true if two values have the same type before any conversions. +*> macro bool @is_same_type(#value1, #value2) @const => $typeof(#value1).typeid == $typeof(#value2).typeid; macro bool @is_bool(#value) @const => types::is_bool($typeof(#value)); macro bool @is_int(#value) @const => types::is_int($typeof(#value)); diff --git a/lib/std/crypto/rc4.c3 b/lib/std/crypto/rc4.c3 index de3212fba..62787d3ea 100644 --- a/lib/std/crypto/rc4.c3 +++ b/lib/std/crypto/rc4.c3 @@ -9,12 +9,12 @@ struct Rc4 char[256] state; } -/** - * Initialize the RC4 state. - * - * @param [in] key "The key to use" - * @require key.len > 0 "The key must be at least 1 byte long" - **/ +<* + Initialize the RC4 state. + + @param [in] key "The key to use" + @require key.len > 0 "The key must be at least 1 byte long" +*> fn void Rc4.init(&self, char[] key) { // Init the state matrix @@ -28,11 +28,11 @@ fn void Rc4.init(&self, char[] key) self.j = 0; } -/** - * Run a single pass of en/decryption using a particular key. - * @param [in] key - * @param [inout] data - **/ +<* + Run a single pass of en/decryption using a particular key. + @param [in] key + @param [inout] data +*> fn void crypt(char[] key, char[] data) { Rc4 rc4; @@ -40,13 +40,13 @@ fn void crypt(char[] key, char[] data) rc4.crypt(data, data); } -/** - * Encrypt or decrypt a sequence of bytes. - * - * @param [in] in "The input" - * @param [out] out "The output" - * @require in.len <= out.len "Output would overflow" - **/ +<* + Encrypt or decrypt a sequence of bytes. + + @param [in] in "The input" + @param [out] out "The output" + @require in.len <= out.len "Output would overflow" +*> fn void Rc4.crypt(&self, char[] in, char[] out) { uint i = self.i; @@ -64,11 +64,11 @@ fn void Rc4.crypt(&self, char[] in, char[] out) self.j = j; } -/** - * Clear the rc4 state. - * - * @param [&out] self "The RC4 State" - **/ +<* + Clear the rc4 state. + + @param [&out] self "The RC4 State" +*> fn void Rc4.destroy(&self) { *self = {}; diff --git a/lib/std/encoding/base64.c3 b/lib/std/encoding/base64.c3 index 4c9cf4ee0..e4ee8389b 100644 --- a/lib/std/encoding/base64.c3 +++ b/lib/std/encoding/base64.c3 @@ -25,24 +25,24 @@ fault Base64Error INVALID_CHARACTER, } -/** - * @param alphabet "The alphabet used for encoding." - * @param padding "Set to a negative value to disable padding." - * @require alphabet.len == 64 - * @require padding < 256 - * @return! Base64Error.DUPLICATE_IN_ALPHABET, Base64Error.PADDING_IN_ALPHABET - **/ +<* + @param alphabet "The alphabet used for encoding." + @param padding "Set to a negative value to disable padding." + @require alphabet.len == 64 + @require padding < 256 + @return! Base64Error.DUPLICATE_IN_ALPHABET, Base64Error.PADDING_IN_ALPHABET +*> fn void! Base64Encoder.init(&self, String alphabet, int padding = '=') { check_alphabet(alphabet, padding)!; *self = { .padding = padding, .alphabet = alphabet }; } -/** - * Calculate the size of the encoded data. - * @param n "Size of the input to be encoded." - * @return "The size of the input once encoded." - **/ +<* + Calculate the size of the encoded data. + @param n "Size of the input to be encoded." + @return "The size of the input once encoded." +*> fn usz Base64Encoder.encode_len(&self, usz n) { if (self.padding >= 0) return (n + 2) / 3 * 4; @@ -50,13 +50,13 @@ fn usz Base64Encoder.encode_len(&self, usz n) return n / 3 * 4 + (trailing * 4 + 2) / 3; } -/** - * Encode the content of src into dst, which must be properly sized. - * @param src "The input to be encoded." - * @param dst "The encoded input." - * @return "The encoded size." - * @return! Base64Error.DESTINATION_TOO_SMALL - **/ +<* + Encode the content of src into dst, which must be properly sized. + @param src "The input to be encoded." + @param dst "The encoded input." + @return "The encoded size." + @return! Base64Error.DESTINATION_TOO_SMALL +*> fn usz! Base64Encoder.encode(&self, char[] src, char[] dst) { if (src.len == 0) return 0; @@ -112,13 +112,13 @@ struct Base64Decoder char invalid; } -/** - * @param alphabet "The alphabet used for encoding." - * @param padding "Set to a negative value to disable padding." - * @require alphabet.len == 64 - * @require padding < 256 - * @return! Base64Error.DUPLICATE_IN_ALPHABET, Base64Error.PADDING_IN_ALPHABET - **/ +<* + @param alphabet "The alphabet used for encoding." + @param padding "Set to a negative value to disable padding." + @require alphabet.len == 64 + @require padding < 256 + @return! Base64Error.DUPLICATE_IN_ALPHABET, Base64Error.PADDING_IN_ALPHABET +*> fn void! Base64Decoder.init(&self, String alphabet, int padding = '=') { check_alphabet(alphabet, padding)!; @@ -147,12 +147,12 @@ fn void! Base64Decoder.init(&self, String alphabet, int padding = '=') } } -/** - * Calculate the size of the decoded data. - * @param n "Size of the input to be decoded." - * @return "The size of the input once decoded." - * @return! Base64Error.INVALID_PADDING - **/ +<* + Calculate the size of the decoded data. + @param n "Size of the input to be decoded." + @return "The size of the input once decoded." + @return! Base64Error.INVALID_PADDING +*> fn usz! Base64Decoder.decode_len(&self, usz n) { usz dn = n / 4 * 3; @@ -170,13 +170,13 @@ fn usz! Base64Decoder.decode_len(&self, usz n) return dn; } -/** - * Decode the content of src into dst, which must be properly sized. - * @param src "The input to be decoded." - * @param dst "The decoded input." - * @return "The decoded size." - * @return! Base64Error.DESTINATION_TOO_SMALL, Base64Error.INVALID_PADDING, Base64Error.INVALID_CHARACTER - **/ +<* + Decode the content of src into dst, which must be properly sized. + @param src "The input to be decoded." + @param dst "The decoded input." + @return "The decoded size." + @return! Base64Error.DESTINATION_TOO_SMALL, Base64Error.INVALID_PADDING, Base64Error.INVALID_CHARACTER +*> fn usz! Base64Decoder.decode(&self, char[] src, char[] dst) { if (src.len == 0) return 0; diff --git a/lib/std/encoding/csv.c3 b/lib/std/encoding/csv.c3 index 07f12e031..407695ca5 100644 --- a/lib/std/encoding/csv.c3 +++ b/lib/std/encoding/csv.c3 @@ -25,9 +25,9 @@ fn usz CsvRow.len(&self) @operator(len) return self.list.len; } -/** - * @require col < self.list.len - **/ +<* + @require col < self.list.len +*> fn String CsvRow.get_col(&self, usz col) @operator([]) { return self.list[col]; @@ -44,9 +44,9 @@ fn CsvRow! CsvReader.read_new_row(self) return self.read_row(allocator::heap()) @inline; } -/** - * @param [&inout] allocator - **/ +<* + @param [&inout] allocator +*> fn CsvRow! CsvReader.read_row(self, Allocator allocator) { String row = io::readline(self.stream, allocator: allocator)!; @@ -60,9 +60,9 @@ fn CsvRow! CsvReader.read_temp_row(self) return self.read_row(allocator::temp()) @inline; } -/** - * @require self.allocator `Row already freed` - **/ +<* + @require self.allocator `Row already freed` +*> fn void CsvRow.free(&self) { allocator::free(self.allocator, self.list); diff --git a/lib/std/hash/hmac.c3 b/lib/std/hash/hmac.c3 index 540e2368c..a9be8dbe8 100644 --- a/lib/std/hash/hmac.c3 +++ b/lib/std/hash/hmac.c3 @@ -14,10 +14,10 @@ fn char[HASH_BYTES] hash(char[] key, char[] message) return hmac.final(); } -/** - * @require output.len > 0 "Output must be greater than zero" - * @require output.len < int.max / HASH_BYTES "Output is too large" - **/ +<* + @require output.len > 0 "Output must be greater than zero" + @require output.len < int.max / HASH_BYTES "Output is too large" +*> fn void pbkdf2(char[] pw, char[] salt, uint iterations, char[] output) { usz l = output.len / HASH_BYTES; diff --git a/lib/std/hash/sha1.c3 b/lib/std/hash/sha1.c3 index 57dd1917d..1bba448e0 100644 --- a/lib/std/hash/sha1.c3 +++ b/lib/std/hash/sha1.c3 @@ -44,10 +44,10 @@ fn void Sha1.init(&self) }; } -/** - * @param [in] data - * @require data.len <= uint.max - **/ +<* + @param [in] data + @require data.len <= uint.max +*> fn void Sha1.update(&self, char[] data) { uint j = self.count[0]; @@ -154,10 +154,10 @@ macro @r4(&block, v, &wref, x, y, &z, i) @local *wref = w.rotl(30); } -/** - * @param [&inout] state - * @param [&in] buffer - **/ +<* + @param [&inout] state + @param [&in] buffer +*> fn void sha1_transform(uint* state, char* buffer) @local { Long16 block; diff --git a/lib/std/hash/sha256.c3 b/lib/std/hash/sha256.c3 index 81e385caa..b18200c96 100644 --- a/lib/std/hash/sha256.c3 +++ b/lib/std/hash/sha256.c3 @@ -63,10 +63,10 @@ fn void Sha256.init(&self) }; } -/** - * @param [in] data - * @require data.len <= uint.max - **/ +<* + @param [in] data + @require data.len <= uint.max +*> fn void Sha256.update(&self, char[] data) { uint i = 0; uint len = data.len; @@ -120,10 +120,10 @@ fn char[HASH_SIZE] Sha256.final(&self) { return hash; } -/** - * @param [&inout] state - * @param [&in] buffer - **/ +<* + @param [&inout] state + @param [&in] buffer +*> fn void sha256_transform(uint* state, char* buffer) @local { uint a, b, c, d, e, f, g, h, t1, t2; uint[64] m; diff --git a/lib/std/io/bits.c3 b/lib/std/io/bits.c3 index 9be309e4d..1ecac6eee 100644 --- a/lib/std/io/bits.c3 +++ b/lib/std/io/bits.c3 @@ -17,10 +17,10 @@ fn void BitReader.clear(&self) @inline self.len = 0; } -/** - * @require nbits <= 8 - * @require self.len + nbits <= uint.sizeof * 8 - **/ +<* + @require nbits <= 8 + @require self.len + nbits <= uint.sizeof * 8 +*> fn char! BitReader.read_bits(&self, uint nbits) { uint bits = self.bits; @@ -61,9 +61,9 @@ fn void! BitWriter.flush(&self) self.len = 0; } -/** - * @require nbits <= 8 - **/ +<* + @require nbits <= 8 +*> fn void! BitWriter.write_bits(&self, uint bits, uint nbits) { if (nbits == 0) return; diff --git a/lib/std/io/file.c3 b/lib/std/io/file.c3 index a74fc82c1..113502825 100644 --- a/lib/std/io/file.c3 +++ b/lib/std/io/file.c3 @@ -37,17 +37,17 @@ fn usz! get_size(String path) fn void! delete(String filename) => os::native_remove(filename) @inline; -/** - * @require self.file != null - **/ +<* + @require self.file != null +*> fn void! File.reopen(&self, String filename, String mode) { self.file = os::native_freopen(self.file, filename, mode)!; } -/** - * @require self.file != null - **/ +<* + @require self.file != null +*> fn usz! File.seek(&self, isz offset, Seek seek_mode = Seek.SET) @dynamic { os::native_fseek(self.file, offset, seek_mode)!; @@ -57,9 +57,9 @@ fn usz! File.seek(&self, isz offset, Seek seek_mode = Seek.SET) @dynamic /* Implement later -/** - * @require self.file == null - **/ +<* + @require self.file == null +*> fn void! File.memopen(File* file, char[] data, String mode) { @pool() @@ -71,17 +71,17 @@ fn void! File.memopen(File* file, char[] data, String mode) */ -/** - * @require self.file != null - */ +<* + @require self.file != null +*> fn void! File.write_byte(&self, char c) @dynamic { return os::native_fputc(c, self.file); } -/** - * @param [&inout] self - */ +<* + @param [&inout] self +*> fn void! File.close(&self) @inline @dynamic { if (self.file && libc::fclose(self.file)) @@ -105,26 +105,26 @@ fn void! File.close(&self) @inline @dynamic self.file = null; } -/** - * @require self.file - */ +<* + @require self.file +*> fn bool File.eof(&self) @inline { return libc::feof(self.file) != 0; } -/** - * @param [in] buffer - */ +<* + @param [in] buffer +*> fn usz! File.read(&self, char[] buffer) @dynamic { return os::native_fread(self.file, buffer); } -/** - * @param [out] buffer - * @require self.file `File must be initialized` - */ +<* + @param [out] buffer + @require self.file `File must be initialized` +*> fn usz! File.write(&self, char[] buffer) @dynamic { return os::native_fwrite(self.file, buffer); @@ -138,13 +138,13 @@ fn char! File.read_byte(&self) @dynamic return (char)c; } -/** - * Load up to buffer.len characters. Returns IoError.OVERFLOW if the file is longer - * than the buffer. - * - * @param filename "The path to the file to read" - * @param [in] buffer "The buffer to read to" - **/ +<* + Load up to buffer.len characters. Returns IoError.OVERFLOW if the file is longer + than the buffer. + + @param filename "The path to the file to read" + @param [in] buffer "The buffer to read to" +*> fn char[]! load_buffer(String filename, char[] buffer) { File file = open(filename, "rb")!; @@ -182,9 +182,9 @@ fn char[]! load_temp(String filename) return load_new(filename, allocator::temp()); } -/** - * @require self.file `File must be initialized` - */ +<* + @require self.file `File must be initialized` +*> fn void! File.flush(&self) @dynamic { libc::fflush(self.file); diff --git a/lib/std/io/formatter_private.c3 b/lib/std/io/formatter_private.c3 index 2904834d6..fbdcb34d3 100644 --- a/lib/std/io/formatter_private.c3 +++ b/lib/std/io/formatter_private.c3 @@ -119,14 +119,14 @@ fn FloatType! float_from_any(any arg) @private } -/** - * Read a simple integer value, typically for formatting. - * - * @param [inout] len_ptr "the length remaining." - * @param [in] buf "the buf to read from." - * @param maxlen "the maximum len that can be read." - * @return "The result of the atoi." - **/ +<* + Read a simple integer value, typically for formatting. + + @param [inout] len_ptr "the length remaining." + @param [in] buf "the buf to read from." + @param maxlen "the maximum len that can be read." + @return "The result of the atoi." +*> fn uint simple_atoi(char* buf, usz maxlen, usz* len_ptr) @inline @private { uint i = 0; diff --git a/lib/std/io/io.c3 b/lib/std/io/io.c3 index 9de526516..7a7253c51 100644 --- a/lib/std/io/io.c3 +++ b/lib/std/io/io.c3 @@ -45,16 +45,16 @@ fault IoError } -/** - * Read from a stream (default is stdin) to the next "\n" - * or to the end of the stream, whatever comes first. - * "\r" will be filtered from the String. - * - * @param stream `The stream to read from.` - * @require @is_instream(stream) `The stream must implement InStream.` - * @param [inout] allocator `the allocator to use.` - * @return `The string containing the data read.` - **/ +<* + Read from a stream (default is stdin) to the next "\n" + or to the end of the stream, whatever comes first. + "\r" will be filtered from the String. + + @param stream `The stream to read from.` + @require @is_instream(stream) `The stream must implement InStream.` + @param [inout] allocator `the allocator to use.` + @return `The string containing the data read.` +*> macro String! readline(stream = io::stdin(), Allocator allocator = allocator::heap()) { bool $is_stream = @typeis(stream, InStream); @@ -90,27 +90,27 @@ macro String! readline(stream = io::stdin(), Allocator allocator = allocator::he }; } -/** - * Reads a string, see `readline`, except the it is allocated - * on the temporary allocator and does not need to be freed. - * - * @param stream `The stream to read from.` - * @require @is_instream(stream) `The stream must implement InStream.` - * @return `The temporary string containing the data read.` - **/ +<* + Reads a string, see `readline`, except the it is allocated + on the temporary allocator and does not need to be freed. + + @param stream `The stream to read from.` + @require @is_instream(stream) `The stream must implement InStream.` + @return `The temporary string containing the data read.` +*> macro String! treadline(stream = io::stdin()) { return readline(stream, allocator::temp()) @inline; } -/** - * Print a value to a stream. - * - * @param out `the stream to print to` - * @param x `the value to print` - * @require @is_outstream(out) `The output must implement OutStream.` - * @return `the number of bytes printed.` - */ +<* + Print a value to a stream. + + @param out `the stream to print to` + @param x `the value to print` + @require @is_outstream(out) `The output must implement OutStream.` + @return `the number of bytes printed.` +*> macro usz! fprint(out, x) { var $Type = $typeof(x); @@ -127,14 +127,14 @@ macro usz! fprint(out, x) $endswitch } -/** - * Prints using a 'printf'-style formatting string. - * See `printf` for details on formatting. - * - * @param [inout] out `The OutStream to print to` - * @param [in] format `The printf-style format string` - * @return `the number of characters printed` - **/ +<* + Prints using a 'printf'-style formatting string. + See `printf` for details on formatting. + + @param [inout] out `The OutStream to print to` + @param [in] format `The printf-style format string` + @return `the number of characters printed` +*> fn usz! fprintf(OutStream out, String format, args...) { Formatter formatter; @@ -142,14 +142,14 @@ fn usz! fprintf(OutStream out, String format, args...) return formatter.vprintf(format, args); } -/** - * Prints using a 'printf'-style formatting string, - * appending '\n' at the end. See `printf`. - * - * @param [inout] out `The OutStream to print to` - * @param [in] format `The printf-style format string` - * @return `the number of characters printed` - **/ +<* + Prints using a 'printf'-style formatting string, + appending '\n' at the end. See `printf`. + + @param [inout] out `The OutStream to print to` + @param [in] format `The printf-style format string` + @return `the number of characters printed` +*> fn usz! fprintfn(OutStream out, String format, args...) @maydiscard { Formatter formatter; @@ -160,9 +160,9 @@ fn usz! fprintfn(OutStream out, String format, args...) @maydiscard return len + 1; } -/** - * @require @is_outstream(out) "The output must implement OutStream" - */ +<* + @require @is_outstream(out) "The output must implement OutStream" +*> macro usz! fprintn(out, x = "") { usz len = fprint(out, x)!; @@ -176,37 +176,37 @@ macro usz! fprintn(out, x = "") return len + 1; } -/** - * Print any value to stdout. - **/ +<* + Print any value to stdout. +*> macro void print(x) { (void)fprint(io::stdout(), x); } -/** - * Print any value to stdout, appending an '\n’ after. - * - * @param x "The value to print" - **/ +<* + Print any value to stdout, appending an '\n’ after. + + @param x "The value to print" +*> macro void printn(x = "") { (void)fprintn(io::stdout(), x); } -/** - * Print any value to stderr. - **/ +<* + Print any value to stderr. +*> macro void eprint(x) { (void)fprint(io::stderr(), x); } -/** - * Print any value to stderr, appending an '\n’ after. - * - * @param x "The value to print" - **/ +<* + Print any value to stderr, appending an '\n’ after. + + @param x "The value to print" +*> macro void eprintn(x) { (void)fprintn(io::stderr(), x); @@ -224,20 +224,20 @@ fn void! out_putchar_fn(void* data @unused, char c) @private libc::putchar(c); } -/** - * Prints using a 'printf'-style formatting string. - * To print integer numbers, use "%d" or "%x"/"%X, - * the latter gives the hexadecimal representation. - * - * All types can be printed using "%s" which gives - * the default representation of the value. - * - * To create a custom output for a type, implement - * the Printable interface. - * - * @param [in] format `The printf-style format string` - * @return `the number of characters printed` - **/ +<* + Prints using a 'printf'-style formatting string. + To print integer numbers, use "%d" or "%x"/"%X, + the latter gives the hexadecimal representation. + + All types can be printed using "%s" which gives + the default representation of the value. + + To create a custom output for a type, implement + the Printable interface. + + @param [in] format `The printf-style format string` + @return `the number of characters printed` +*> fn usz! printf(String format, args...) @maydiscard { Formatter formatter; @@ -245,13 +245,13 @@ fn usz! printf(String format, args...) @maydiscard return formatter.vprintf(format, args); } -/** - * Prints using a 'printf'-style formatting string, - * appending '\n' at the end. See `printf`. - * - * @param [in] format `The printf-style format string` - * @return `the number of characters printed` - **/ +<* + Prints using a 'printf'-style formatting string, + appending '\n' at the end. See `printf`. + + @param [in] format `The printf-style format string` + @return `the number of characters printed` +*> fn usz! printfn(String format, args...) @maydiscard { Formatter formatter; @@ -262,13 +262,13 @@ fn usz! printfn(String format, args...) @maydiscard return len + 1; } -/** - * Prints using a 'printf'-style formatting string - * to stderr. - * - * @param [in] format `The printf-style format string` - * @return `the number of characters printed` - **/ +<* + Prints using a 'printf'-style formatting string + to stderr. + + @param [in] format `The printf-style format string` + @return `the number of characters printed` +*> fn usz! eprintf(String format, args...) @maydiscard { Formatter formatter; @@ -278,13 +278,13 @@ fn usz! eprintf(String format, args...) @maydiscard } -/** - * Prints using a 'printf'-style formatting string, - * to stderr appending '\n' at the end. See `printf`. - * - * @param [in] format `The printf-style format string` - * @return `the number of characters printed` - **/ +<* + Prints using a 'printf'-style formatting string, + to stderr appending '\n' at the end. See `printf`. + + @param [in] format `The printf-style format string` + @return `the number of characters printed` +*> fn usz! eprintfn(String format, args...) @maydiscard { Formatter formatter; @@ -296,14 +296,14 @@ fn usz! eprintfn(String format, args...) @maydiscard return len + 1; } -/** - * Prints using a 'printf'-style formatting string, - * to a string buffer. See `printf`. - * - * @param [inout] buffer `The buffer to print to` - * @param [in] format `The printf-style format string` - * @return `a slice formed from the "buffer" with the resulting length.` - **/ +<* + Prints using a 'printf'-style formatting string, + to a string buffer. See `printf`. + + @param [inout] buffer `The buffer to print to` + @param [in] format `The printf-style format string` + @return `a slice formed from the "buffer" with the resulting length.` +*> fn char[]! bprintf(char[] buffer, String format, args...) @maydiscard { Formatter formatter; @@ -332,19 +332,19 @@ struct BufferData @private module std::io @if (env::LIBC); import libc; -/** - * Libc `putchar`, prints a single character to stdout. - **/ +<* + Libc `putchar`, prints a single character to stdout. +*> fn void putchar(char c) @inline { libc::putchar(c); } -/** - * Get standard out. - * - * @return `stdout as a File` - **/ +<* + Get standard out. + + @return `stdout as a File` +*> fn File* stdout() { static File file; @@ -352,11 +352,11 @@ fn File* stdout() return &file; } -/** - * Get standard err. - * - * @return `stderr as a File` - **/ +<* + Get standard err. + + @return `stderr as a File` +*> fn File* stderr() { static File file; @@ -364,11 +364,11 @@ fn File* stderr() return &file; } -/** - * Get standard in. - * - * @return `stdin as a File` - **/ +<* + Get standard in. + + @return `stdin as a File` +*> fn File* stdin() { static File file; diff --git a/lib/std/io/os/file_libc.c3 b/lib/std/io/os/file_libc.c3 index f156e0054..58cdcd769 100644 --- a/lib/std/io/os/file_libc.c3 +++ b/lib/std/io/os/file_libc.c3 @@ -1,10 +1,10 @@ module std::io::os @if(env::LIBC); import libc; -/** - * @require mode.len > 0 - * @require filename.len > 0 - **/ +<* + @require mode.len > 0 + @require filename.len > 0 +*> fn void*! native_fopen(String filename, String mode) @inline { @pool() @@ -41,10 +41,10 @@ fn void! native_remove(String filename) }; } -/** - * @require mode.len > 0 - * @require filename.len > 0 - **/ +<* + @require mode.len > 0 + @require filename.len > 0 +*> fn void*! native_freopen(void* file, String filename, String mode) @inline { @pool() diff --git a/lib/std/io/os/file_nolibc.c3 b/lib/std/io/os/file_nolibc.c3 index b52d80f10..7c23afa03 100644 --- a/lib/std/io/os/file_nolibc.c3 +++ b/lib/std/io/os/file_nolibc.c3 @@ -21,31 +21,31 @@ FreadFn native_fread_fn @weak @if(!$defined(native_fread_fn)); RemoveFn native_remove_fn @weak @if(!$defined(native_remove_fn)); FputcFn native_fputc_fn @weak @if(!$defined(native_fputc_fn)); -/** - * @require mode.len > 0 - * @require filename.len > 0 - **/ +<* + @require mode.len > 0 + @require filename.len > 0 +*> fn void*! native_fopen(String filename, String mode) @inline { if (native_fopen_fn) return native_fopen_fn(filename, mode); return IoError.UNSUPPORTED_OPERATION?; } -/** - * Delete a file. - * - * @require filename.len > 0 - **/ +<* + Delete a file. + + @require filename.len > 0 +*> fn void! native_remove(String filename) @inline { if (native_remove_fn) return native_remove_fn(filename); return IoError.UNSUPPORTED_OPERATION?; } -/** - * @require mode.len > 0 - * @require filename.len > 0 - **/ +<* + @require mode.len > 0 + @require filename.len > 0 +*> fn void*! native_freopen(void* file, String filename, String mode) @inline { if (native_freopen_fn) return native_freopen_fn(file, filename, mode); diff --git a/lib/std/io/os/rmtree.c3 b/lib/std/io/os/rmtree.c3 index 995b8cf22..71ee5ac00 100644 --- a/lib/std/io/os/rmtree.c3 +++ b/lib/std/io/os/rmtree.c3 @@ -1,9 +1,9 @@ module std::io::os @if(env::POSIX); import std::io, std::os, libc; -/** - * @require dir.str_view() - **/ +<* + @require dir.str_view() +*> fn void! native_rmtree(Path dir) { DIRPtr directory = posix::opendir(dir.as_zstr()); diff --git a/lib/std/io/path.c3 b/lib/std/io/path.c3 index 9e9c6e82c..40b1c2623 100644 --- a/lib/std/io/path.c3 +++ b/lib/std/io/path.c3 @@ -165,11 +165,11 @@ fn Path! Path.append(self, String filename, Allocator allocator = allocator::hea return self.new_append(filename, allocator) @inline; } -/** - * Append the string to the current path. - * - * @param [in] filename - **/ +<* + Append the string to the current path. + + @param [in] filename +*> fn Path! Path.new_append(self, String filename, Allocator allocator = allocator::heap()) { if (!self.path_string.len) return new(filename, allocator, self.env)!; @@ -226,9 +226,9 @@ fn Path! Path.absolute(self, Allocator allocator = allocator::heap()) @deprecate return self.new_absolute(allocator) @inline; } -/** - * @require self.env == DEFAULT_PATH_ENV : "This method is only available on native paths" - **/ +<* + @require self.env == DEFAULT_PATH_ENV : "This method is only available on native paths" +*> fn Path! Path.new_absolute(self, Allocator allocator = allocator::heap()) { String path_str = self.str_view(); @@ -283,14 +283,14 @@ fn String Path.dirname(self) return path_str[:basename_start - 1]; } -/** - * Test if the path has the given extension, so given the path /foo/bar.c3 - * this would be true matching the extension "c3" - * - * @param [in] extension `The extension name (not including the leading '.')` - * @require extension.len > 0 : `The extension cannot be empty` - * @return `true if the extension matches` - **/ +<* + Test if the path has the given extension, so given the path /foo/bar.c3 + this would be true matching the extension "c3" + + @param [in] extension `The extension name (not including the leading '.')` + @require extension.len > 0 : `The extension cannot be empty` + @return `true if the extension matches` +*> fn bool Path.has_extension(self, String extension) { String basename = self.basename(); @@ -509,11 +509,11 @@ fn String Path.root_directory(self) def PathWalker = fn bool! (Path, bool is_dir, void*); -/* - * Walk the path recursively. PathWalker is run on every file and - * directory found. Return true to abort the walk. - * @require self.env == DEFAULT_PATH_ENV : "This method is only available on native paths" - */ +<* + Walk the path recursively. PathWalker is run on every file and + directory found. Return true to abort the walk. + @require self.env == DEFAULT_PATH_ENV : "This method is only available on native paths" +*> fn bool! Path.walk(self, PathWalker w, void* data) { const PATH_MAX = 512; diff --git a/lib/std/io/stream.c3 b/lib/std/io/stream.c3 index 50f346e22..6e7fe49e0 100644 --- a/lib/std/io/stream.c3 +++ b/lib/std/io/stream.c3 @@ -47,28 +47,28 @@ macro bool @is_outstream(#expr) return $assignable(#expr, OutStream); } -/** - * @param [&out] ref - * @require @is_instream(stream) - **/ +<* + @param [&out] ref + @require @is_instream(stream) +*> macro usz! read_any(stream, any ref) { return read_all(stream, ((char*)ref)[:ref.type.sizeof]); } -/** - * @param [&in] ref "the object to write." - * @require @is_outstream(stream) - * @ensure return == ref.type.sizeof - */ +<* + @param [&in] ref "the object to write." + @require @is_outstream(stream) + @ensure return == ref.type.sizeof +*> macro usz! write_any(stream, any ref) { return write_all(stream, ((char*)ref)[:ref.type.sizeof]); } -/** - * @require @is_instream(stream) - */ +<* + @require @is_instream(stream) +*> macro usz! read_all(stream, char[] buffer) { if (buffer.len == 0) return 0; @@ -77,9 +77,9 @@ macro usz! read_all(stream, char[] buffer) return n; } -/** - * @require @is_instream(stream) - */ +<* + @require @is_instream(stream) +*> macro char[]! read_new_fully(stream, Allocator allocator = allocator::heap()) { usz len = available(stream)!; @@ -93,9 +93,9 @@ macro char[]! read_new_fully(stream, Allocator allocator = allocator::heap()) return data[:len]; } -/** - * @require @is_outstream(stream) - */ +<* + @require @is_outstream(stream) +*> macro usz! write_all(stream, char[] buffer) { if (buffer.len == 0) return 0; @@ -186,10 +186,10 @@ macro usz! copy_through_buffer(InStream in, OutStream dst, char[] buffer) @local const char[*] MAX_VARS @private = { [2] = 3, [4] = 5, [8] = 10 }; -/** - * @require @is_instream(stream) - * @require @typekind(x_ptr) == POINTER && $typeof(x_ptr).inner.kindof.is_int() - **/ +<* + @require @is_instream(stream) + @require @typekind(x_ptr) == POINTER && $typeof(x_ptr).inner.kindof.is_int() +*> macro usz! read_varint(stream, x_ptr) { var $Type = $typefrom($typeof(x_ptr).inner); @@ -223,10 +223,10 @@ macro usz! read_varint(stream, x_ptr) } return MathError.OVERFLOW?; } -/** - * @require @is_outstream(stream) - * @require @typekind(x).is_int() - **/ +<* + @require @is_outstream(stream) + @require @typekind(x).is_int() +*> macro usz! write_varint(stream, x) { var $Type = $typeof(x); @@ -243,9 +243,9 @@ macro usz! write_varint(stream, x) return write_all(stream, buffer[:i + 1]); } -/** - * @require @is_instream(stream) - **/ +<* + @require @is_instream(stream) +*> macro ushort! read_be_ushort(stream) { char hi_byte = stream.read_byte()!; @@ -253,26 +253,26 @@ macro ushort! read_be_ushort(stream) return (ushort)(hi_byte << 8 | lo_byte); } -/** - * @require @is_instream(stream) - **/ +<* + @require @is_instream(stream) +*> macro short! read_be_short(stream) { return read_be_ushort(stream); } -/** - * @require @is_outstream(stream) - **/ +<* + @require @is_outstream(stream) +*> macro void! write_be_short(stream, ushort s) { stream.write_byte((char)(s >> 8))!; stream.write_byte((char)s)!; } -/** - * @require @is_instream(stream) - **/ +<* + @require @is_instream(stream) +*> macro uint! read_be_uint(stream) { uint val = stream.read_byte()! << 24; @@ -281,17 +281,17 @@ macro uint! read_be_uint(stream) return val + stream.read_byte()!; } -/** - * @require @is_instream(stream) - **/ +<* + @require @is_instream(stream) +*> macro int! read_be_int(stream) { return read_be_uint(stream); } -/** - * @require @is_outstream(stream) - **/ +<* + @require @is_outstream(stream) +*> macro void! write_be_int(stream, uint s) { stream.write_byte((char)(s >> 24))!; @@ -300,9 +300,9 @@ macro void! write_be_int(stream, uint s) stream.write_byte((char)s)!; } -/** - * @require @is_instream(stream) - **/ +<* + @require @is_instream(stream) +*> macro ulong! read_be_ulong(stream) { ulong val = (ulong)stream.read_byte()! << 56; @@ -315,17 +315,17 @@ macro ulong! read_be_ulong(stream) return val + stream.read_byte()!; } -/** - * @require @is_instream(stream) - **/ +<* + @require @is_instream(stream) +*> macro long! read_be_long(stream) { return read_be_ulong(stream); } -/** - * @require @is_outstream(stream) - **/ +<* + @require @is_outstream(stream) +*> macro void! write_be_long(stream, ulong s) { stream.write_byte((char)(s >> 56))!; @@ -338,9 +338,9 @@ macro void! write_be_long(stream, ulong s) stream.write_byte((char)s)!; } -/** - * @require @is_instream(stream) - **/ +<* + @require @is_instream(stream) +*> macro uint128! read_be_uint128(stream) { uint128 val = (uint128)stream.read_byte()! << 120; @@ -361,17 +361,17 @@ macro uint128! read_be_uint128(stream) return val + stream.read_byte()!; } -/** - * @require @is_instream(stream) - **/ +<* + @require @is_instream(stream) +*> macro int128! read_be_int128(stream) { return read_be_uint128(stream); } -/** - * @require @is_outstream(stream) - **/ +<* + @require @is_outstream(stream) +*> macro void! write_be_int128(stream, uint128 s) { stream.write_byte((char)(s >> 120))!; @@ -392,19 +392,19 @@ macro void! write_be_int128(stream, uint128 s) stream.write_byte((char)s)!; } -/** - * @require @is_outstream(stream) - * @require data.len < 256 "Data exceeded 255" - **/ +<* + @require @is_outstream(stream) + @require data.len < 256 "Data exceeded 255" +*> macro usz! write_tiny_bytearray(stream, char[] data) { stream.write_byte((char)data.len)!; return stream.write(data) + 1; } -/** - * @require @is_instream(stream) - **/ +<* + @require @is_instream(stream) +*> macro char[]! read_tiny_bytearray(stream, Allocator allocator) { int len = stream.read_byte()!; @@ -414,19 +414,19 @@ macro char[]! read_tiny_bytearray(stream, Allocator allocator) return data; } -/** - * @require @is_outstream(stream) - * @require data.len < 0x1000 "Data exceeded 65535" - **/ +<* + @require @is_outstream(stream) + @require data.len < 0x1000 "Data exceeded 65535" +*> macro usz! write_short_bytearray(stream, char[] data) { io::write_be_short(stream, (ushort)data.len)!; return stream.write(data) + 2; } -/** - * @require @is_instream(stream) - **/ +<* + @require @is_instream(stream) +*> macro char[]! read_short_bytearray(stream, Allocator allocator) { int len = io::read_be_ushort(stream)!; @@ -436,9 +436,9 @@ macro char[]! read_short_bytearray(stream, Allocator allocator) return data; } -/** - * Wrap bytes for reading using io functions. - **/ +<* + Wrap bytes for reading using io functions. +*> fn ByteReader wrap_bytes(char[] bytes) { return { bytes, 0 }; diff --git a/lib/std/io/stream/buffer.c3 b/lib/std/io/stream/buffer.c3 index 301167f45..1c106bf46 100644 --- a/lib/std/io/stream/buffer.c3 +++ b/lib/std/io/stream/buffer.c3 @@ -8,12 +8,12 @@ struct ReadBuffer (InStream) usz write_idx; } -/** - * Buffer reads from a stream. - * @param [inout] self - * @require bytes.len > 0 - * @require self.bytes.len == 0 "Init may not run on already initialized data" - **/ +<* + Buffer reads from a stream. + @param [inout] self + @require bytes.len > 0 + @require self.bytes.len == 0 "Init may not run on already initialized data" +*> fn ReadBuffer* ReadBuffer.init(&self, InStream wrapped_stream, char[] bytes) { *self = { .wrapped_stream = wrapped_stream, .bytes = bytes }; @@ -68,12 +68,12 @@ struct WriteBuffer (OutStream) usz index; } -/** - * Buffer writes to a stream. Call `flush` when done writing to the buffer. - * @param [inout] self - * @require bytes.len > 0 "Non-empty buffer required" - * @require self.bytes.len == 0 "Init may not run on already initialized data" - **/ +<* + Buffer writes to a stream. Call `flush` when done writing to the buffer. + @param [inout] self + @require bytes.len > 0 "Non-empty buffer required" + @require self.bytes.len == 0 "Init may not run on already initialized data" +*> fn WriteBuffer* WriteBuffer.init(&self, OutStream wrapped_stream, char[] bytes) { *self = { .wrapped_stream = wrapped_stream, .bytes = bytes }; diff --git a/lib/std/io/stream/bytebuffer.c3 b/lib/std/io/stream/bytebuffer.c3 index 764640883..a5f64b19c 100644 --- a/lib/std/io/stream/bytebuffer.c3 +++ b/lib/std/io/stream/bytebuffer.c3 @@ -11,11 +11,11 @@ struct ByteBuffer (InStream, OutStream) bool has_last; } -/** - * ByteBuffer provides a streamable read/write buffer. - * max_read defines how many bytes might be kept before its internal buffer is shrinked. - * @require self.bytes.len == 0 "Buffer already initialized." - **/ +<* + ByteBuffer provides a streamable read/write buffer. + max_read defines how many bytes might be kept before its internal buffer is shrinked. + @require self.bytes.len == 0 "Buffer already initialized." +*> fn ByteBuffer*! ByteBuffer.new_init(&self, usz max_read, usz initial_capacity = 16, Allocator allocator = allocator::heap()) { *self = { .allocator = allocator, .max_read = max_read }; @@ -29,10 +29,10 @@ fn ByteBuffer*! ByteBuffer.temp_init(&self, usz max_read, usz initial_capacity = return self.new_init(max_read, initial_capacity, allocator::temp()); } -/** - * @require buf.len > 0 - * @require self.bytes.len == 0 "Buffer already initialized." - **/ +<* + @require buf.len > 0 + @require self.bytes.len == 0 "Buffer already initialized." +*> fn ByteBuffer*! ByteBuffer.init_with_buffer(&self, char[] buf) { *self = { .max_read = buf.len, .bytes = buf }; @@ -93,9 +93,9 @@ fn char! ByteBuffer.read_byte(&self) @dynamic return c; } -/* - * Only the last byte of a successful read can be pushed back. - */ +<* + Only the last byte of a successful read can be pushed back. +*> fn void! ByteBuffer.pushback_byte(&self) @dynamic { if (!self.has_last) return IoError.EOF?; diff --git a/lib/std/io/stream/bytewriter.c3 b/lib/std/io/stream/bytewriter.c3 index 0133bddf2..538b491a0 100644 --- a/lib/std/io/stream/bytewriter.c3 +++ b/lib/std/io/stream/bytewriter.c3 @@ -8,23 +8,23 @@ struct ByteWriter (OutStream) Allocator allocator; } -/** - * @param [&inout] self - * @param [&inout] allocator - * @require self.bytes.len == 0 "Init may not run on already initialized data" - * @ensure (bool)allocator, self.index == 0 - **/ +<* + @param [&inout] self + @param [&inout] allocator + @require self.bytes.len == 0 "Init may not run on already initialized data" + @ensure (bool)allocator, self.index == 0 +*> fn ByteWriter* ByteWriter.new_init(&self, Allocator allocator = allocator::heap()) { *self = { .bytes = {}, .allocator = allocator }; return self; } -/** - * @param [&inout] self - * @require self.bytes.len == 0 "Init may not run on already initialized data" - * @ensure self.index == 0 - **/ +<* + @param [&inout] self + @require self.bytes.len == 0 "Init may not run on already initialized data" + @ensure self.index == 0 +*> fn ByteWriter* ByteWriter.temp_init(&self) { return self.new_init(allocator::temp()) @inline; @@ -72,10 +72,10 @@ fn void! ByteWriter.write_byte(&self, char c) @dynamic self.bytes[self.index++] = c; } -/** - * @param [&inout] self - * @param reader - **/ +<* + @param [&inout] self + @param reader +*> fn usz! ByteWriter.read_from(&self, InStream reader) @dynamic { usz start_index = self.index; diff --git a/lib/std/io/stream/limitreader.c3 b/lib/std/io/stream/limitreader.c3 index 06ee68768..e512e92b7 100644 --- a/lib/std/io/stream/limitreader.c3 +++ b/lib/std/io/stream/limitreader.c3 @@ -6,10 +6,10 @@ struct LimitReader (InStream) usz limit; } -/** - * @param [&inout] wrapped_stream "The stream to read from" - * @param limit "The max limit to read" - **/ +<* + @param [&inout] wrapped_stream "The stream to read from" + @param limit "The max limit to read" +*> fn LimitReader* LimitReader.init(&self, InStream wrapped_stream, usz limit) { *self = { .wrapped_stream = wrapped_stream, .limit = limit }; diff --git a/lib/std/io/stream/scanner.c3 b/lib/std/io/stream/scanner.c3 index 51c168003..062970ec3 100644 --- a/lib/std/io/stream/scanner.c3 +++ b/lib/std/io/stream/scanner.c3 @@ -8,23 +8,23 @@ struct Scanner (InStream) usz read_idx; } -/** - * Scanner provides a way to read delimited data (with newlines as the default). - * The supplied buffer must be at least as large as the expected data length - * including its pattern. - * - * @param [&in] stream "The stream to read data from." - * @require buffer.len > 0 "Non-empty buffer required." - **/ +<* + Scanner provides a way to read delimited data (with newlines as the default). + The supplied buffer must be at least as large as the expected data length + including its pattern. + + @param [&in] stream "The stream to read data from." + @require buffer.len > 0 "Non-empty buffer required." +*> fn void Scanner.init(&self, InStream stream, char[] buffer) { *self = { .wrapped_stream = stream, .buf = buffer }; } -/** - * Return and clear any remaining unscanned data. - **/ +<* + Return and clear any remaining unscanned data. +*> fn char[] Scanner.flush(&self) @dynamic { assert(self.read_idx >= self.pattern_idx); @@ -40,11 +40,11 @@ fn void! Scanner.close(&self) @dynamic if (&self.wrapped_stream.close) return self.wrapped_stream.close(); } -/** - * Scan the stream for the next split character and return data up to the match. - * @require pattern.len > 0 "Non-empty pattern required." - * @require self.buf.len > pattern.len "Pattern too large." - **/ +<* + Scan the stream for the next split character and return data up to the match. + @require pattern.len > 0 "Non-empty pattern required." + @require self.buf.len > pattern.len "Pattern too large." +*> fn char[]! Scanner.scan(&self, String pattern = "\n") { if (self.read_idx == 0) diff --git a/lib/std/libc/libc_extra.c3 b/lib/std/libc/libc_extra.c3 index f56dac51e..4c4142513 100644 --- a/lib/std/libc/libc_extra.c3 +++ b/lib/std/libc/libc_extra.c3 @@ -1,9 +1,11 @@ module libc; import std::time; -/** - * @require self >= 0 - **/ +<* + Return a "timespec" from a duration. + + @require self >= 0 +*> fn TimeSpec NanoDuration.to_timespec(self) @inline { CLong ns = (CLong)(self % 1000_000_000); @@ -11,9 +13,11 @@ fn TimeSpec NanoDuration.to_timespec(self) @inline return { .s = sec, .ns = ns }; } -/** - * @require self >= 0 - **/ +<* + Convert a duration to a timespec. + + @require self >= 0 +*> fn TimeSpec Duration.to_timespec(self) @inline { CLong ns = (CLong)(1000 * (self % time::SEC)); diff --git a/lib/std/math/bigint.c3 b/lib/std/math/bigint.c3 index 6399bbbf5..c5a181f77 100644 --- a/lib/std/math/bigint.c3 +++ b/lib/std/math/bigint.c3 @@ -1,6 +1,6 @@ -/** - * Untested new big int implementation, missing unit tests. Etc - */ +<* +Untested new big int implementation, missing unit tests. Etc +*> module std::math::bigint; import std::math::random; import std::io; @@ -58,9 +58,9 @@ fn BigInt* BigInt.init_with_u128(&self, uint128 value) return self; } -/** - * @require values.len <= MAX_LEN - **/ +<* + @require values.len <= MAX_LEN +*> fn BigInt* BigInt.init_with_array(&self, uint[] values) { self.data[..] = 0; @@ -513,9 +513,9 @@ fn String BigInt.to_string(&self, Allocator allocator) @dynamic return self.to_string_with_radix(10, allocator); } -/** - * @require radix > 1 && radix <= 36 "Radix must be 2-36" - **/ +<* + @require radix > 1 && radix <= 36 "Radix must be 2-36" +*> fn String BigInt.to_string_with_radix(&self, int radix, Allocator allocator) { if (self.is_zero()) return "0".copy(allocator); @@ -555,9 +555,9 @@ fn String BigInt.to_string_with_radix(&self, int radix, Allocator allocator) }; } -/** - * @require !exp.is_negative() "Positive exponents only" - **/ +<* + @require !exp.is_negative() "Positive exponents only" +*> fn BigInt BigInt.mod_pow(&self, BigInt exp, BigInt mod) { BigInt result_num = ONE; @@ -624,11 +624,11 @@ fn BigInt BigInt.mod_pow(&self, BigInt exp, BigInt mod) return result_num; } -/* - * Fast calculation of modular reduction using Barrett's reduction. - * Requires x < b^(2k), where b is the base. In this case, base is - * 2^32 (uint). - */ +<* + Fast calculation of modular reduction using Barrett's reduction. + Requires x < b^(2k), where b is the base. In this case, base is + 2^32 (uint). +*> fn BigInt barrett_reduction(BigInt x, BigInt n, BigInt constant) { int k = n.len; @@ -831,9 +831,9 @@ fn BigInt BigInt.gcd(&self, BigInt other) return g; } -/** - * @require bits >> 5 < MAX_LEN "Required bits > maxlength" - **/ +<* + @require bits >> 5 < MAX_LEN "Required bits > maxlength" +*> fn void BigInt.randomize_bits(&self, Random random, int bits) { int dwords = bits >> 5; @@ -878,11 +878,11 @@ fn void BigInt.randomize_bits(&self, Random random, int bits) module std::math::bigint @private; -/** - * @param [&out] quotient - * @param [&in] bi2 - * @param [&out] remainder - **/ +<* + @param [&out] quotient + @param [&in] bi2 + @param [&out] remainder +*> fn void BigInt.single_byte_divide(&self, BigInt* bi2, BigInt* quotient, BigInt* remainder) { uint[MAX_LEN] result; @@ -930,11 +930,11 @@ fn void BigInt.single_byte_divide(&self, BigInt* bi2, BigInt* quotient, BigInt* remainder.reduce_len(); } -/** - * @param [&out] quotient - * @param [&in] other - * @param [&out] remainder - **/ +<* + @param [&out] quotient + @param [&in] other + @param [&out] remainder +*> fn void BigInt.multi_byte_divide(&self, BigInt* other, BigInt* quotient, BigInt* remainder) { uint[MAX_LEN] result; @@ -1105,9 +1105,3 @@ fn int shift_right(uint* data, int len, int shift_val) @inline } return find_length(data, buf_len); } - - - - - - diff --git a/lib/std/math/math.c3 b/lib/std/math/math.c3 index 406fab07d..d8a24644e 100644 --- a/lib/std/math/math.c3 +++ b/lib/std/math/math.c3 @@ -119,21 +119,21 @@ def MATRIX4_IDENTITY = matrix::IDENTITY4(); def MATRIX4F_IDENTITY = matrix::IDENTITY4(); -/** - * @require types::is_numerical($typeof(x)) `The input must be a numerical value or numerical vector` - **/ +<* + @require types::is_numerical($typeof(x)) `The input must be a numerical value or numerical vector` +*> macro deg_to_rad(x) { return x * PI / 180; } -/** - * @require types::is_numerical($typeof(x)) `The input must be a numerical value or numerical vector` - **/ +<* + @require types::is_numerical($typeof(x)) `The input must be a numerical value or numerical vector` +*> macro abs(x) => $$abs(x); -/** - * @require values::@is_int(x) `The input must be an integer` - **/ +<* + @require values::@is_int(x) `The input must be an integer` +*> macro sign(x) { var $Type = $typeof(x); @@ -144,10 +144,10 @@ macro sign(x) $endif } -/** - * @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" - * @require values::@is_int(y) || values::@is_float(y) "Expected an integer or floating point value" - **/ +<* + @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" + @require values::@is_int(y) || values::@is_float(y) "Expected an integer or floating point value" +*> macro atan2(x, y) { $if @typeis(x, float) && @typeis(y, float): @@ -157,12 +157,12 @@ macro atan2(x, y) $endif } -/** - * @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" - * @require @typekind(sinp) == POINTER "Expected sinp to be a pointer" - * @require values::@is_same_type(sinp, cosp) "Expected sinp and cosp to have the same type" - * @require $assignable(x, $typeof(*sinp)) "Expected x and sinp/cosp to have the same type" - **/ +<* + @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" + @require @typekind(sinp) == POINTER "Expected sinp to be a pointer" + @require values::@is_same_type(sinp, cosp) "Expected sinp and cosp to have the same type" + @require $assignable(x, $typeof(*sinp)) "Expected x and sinp/cosp to have the same type" +*> macro sincos_ref(x, sinp, cosp) { $if @typeid(*sinp) == float.typeid: @@ -172,12 +172,12 @@ macro sincos_ref(x, sinp, cosp) $endif } -/** - * Return a vector with sin / cos of the given angle. +<* +Return a vector with sin / cos of the given angle. * - * @param x `the angle in radians` - * @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" - **/ + @param x `the angle in radians` + @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" +*> macro sincos(x) { $if @typeid(x) == float.typeid: @@ -190,9 +190,9 @@ macro sincos(x) return v; } -/** - * @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" - **/ +<* + @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" +*> macro atan(x) { $if @typeid(x) == float.typeid: @@ -202,9 +202,9 @@ macro atan(x) $endif } -/** - * @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" - **/ +<* + @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" +*> macro atanh(x) { $if @typeid(x) == float.typeid: @@ -214,9 +214,9 @@ macro atanh(x) $endif } -/** - * @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" - **/ +<* + @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" +*> macro acos(x) { $if @typeid(x) == float.typeid: @@ -226,9 +226,9 @@ macro acos(x) $endif } -/** - * @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" - **/ +<* + @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" +*> macro acosh(x) { $if @typeid(x) == float.typeid: @@ -238,9 +238,9 @@ macro acosh(x) $endif } -/** - * @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" - **/ +<* + @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" +*> macro asin(x) { $if @typeid(x) == float.typeid: @@ -250,9 +250,9 @@ macro asin(x) $endif } -/** - * @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" - **/ +<* + @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" +*> macro asinh(x) { $if @typeid(x) == float.typeid: @@ -262,121 +262,121 @@ macro asinh(x) $endif } -/** - * @require values::@is_floatlike(x) `The input must be a floating point value or float vector` - **/ +<* + @require values::@is_floatlike(x) `The input must be a floating point value or float vector` +*> macro ceil(x) => $$ceil(x); -/** - * Constrain the value to lie within the given interval. - * - * @param x "the value to clamp, may be a number or a numerical vector." - * @param lower "the lower bounds" - * @param upper "the upper bounds" - * @return "lower if x < lower, upper if x > upper, otherwise return x." - * - * @require types::is_numerical($typeof(x)) `The input must be a numerical value or numerical vector` - * @require values::@assign_to(lower, x) `The lower bound must be convertable to the value type.` - * @require values::@assign_to(upper, x) `The upper bound must be convertable to the value type.` - **/ +<* + Constrain the value to lie within the given interval. + + @param x "the value to clamp, may be a number or a numerical vector." + @param lower "the lower bounds" + @param upper "the upper bounds" + @return "lower if x < lower, upper if x > upper, otherwise return x." + + @require types::is_numerical($typeof(x)) `The input must be a numerical value or numerical vector` + @require values::@assign_to(lower, x) `The lower bound must be convertable to the value type.` + @require values::@assign_to(upper, x) `The upper bound must be convertable to the value type.` +*> macro clamp(x, lower, upper) => $$max(($typeof(x))lower, $$min(x, ($typeof(x))upper)); -/** - * @require values::@is_promotable_to_floatlike(mag) `The input must be a number value or float vector` - * @require $defined(($typeof(values::promote_int(mag)))mag) `It's not possible to cast the sign to the type of the magnitude` - **/ +<* + @require values::@is_promotable_to_floatlike(mag) `The input must be a number value or float vector` + @require $defined(($typeof(values::promote_int(mag)))mag) `It's not possible to cast the sign to the type of the magnitude` +*> macro copysign(mag, sgn) => $$copysign(values::promote_int_same(mag, sgn), ($typeof(values::promote_int_same(mag, sgn)))sgn); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` +*> macro cos(x) => $$cos(x); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` +*> macro cosec(x) => 1 / sin(x); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` +*> macro cosech(x) => 2 / (exp(x) - exp(-x)); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` +*> macro cosh(x) => (exp(x) + exp(-x)) / 2.0; -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` +*> macro cotan(x) => cos(x) / sin(x); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` +*> macro cotanh(x) => (exp(2.0 * x) + 1.0) / (exp(2.0 * x) - 1.0); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` +*> macro exp(x) => $$exp(values::promote_int(x)); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` +*> macro exp2(x) => $$exp2(values::promote_int(x)); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number value or float vector` +*> macro floor(x) => $$floor(values::promote_int(x)); -/** - * @require values::@is_promotable_to_floatlike(a) `The input must be a number or float vector` - * @require values::@is_promotable_to_floatlike(b) `The input must be a number or float vector` - * @require values::@is_promotable_to_floatlike(c) `The input must be a number or float vector` - * @require values::@is_same_vector_type(a, b) `The input types must be equal` - * @require values::@is_same_vector_type(a, c) `The input types must match` - **/ +<* + @require values::@is_promotable_to_floatlike(a) `The input must be a number or float vector` + @require values::@is_promotable_to_floatlike(b) `The input must be a number or float vector` + @require values::@is_promotable_to_floatlike(c) `The input must be a number or float vector` + @require values::@is_same_vector_type(a, b) `The input types must be equal` + @require values::@is_same_vector_type(a, c) `The input types must match` +*> macro fma(a, b, c) => $$fma(a, b, c); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` - * @require values::@is_promotable_to_floatlike(y) `The input must be a number or a float vector` - * @require values::@is_same_vector_type(x, y) `The input types must match` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` + @require values::@is_promotable_to_floatlike(y) `The input must be a number or a float vector` + @require values::@is_same_vector_type(x, y) `The input types must match` +*> macro hypot(x, y) => sqrt(sqr(x) + sqr(y)); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` +*> macro ln(x) => $$log(values::promote_int(x)); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` - * @require values::@is_promotable_to_floatlike(base) `The base must be a number or a float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` + @require values::@is_promotable_to_floatlike(base) `The base must be a number or a float vector` +*> macro log(x, base) { return $$log(values::promote_int_same(x, base)) / $$log(values::promote_int_same(base, x)); } -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` +*> macro log2(x) => $$log2(values::promote_int(x)); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` +*> macro log10(x) => $$log10(values::promote_int(x)); -/** - * @require types::is_numerical($typeof(x)) `The input must be a floating point value or float vector` - * @require types::is_same($typeof(x), $typeof(y)) `The input types must be equal` - **/ +<* + @require types::is_numerical($typeof(x)) `The input must be a floating point value or float vector` + @require types::is_same($typeof(x), $typeof(y)) `The input types must be equal` +*> macro max(x, y, ...) { $if $vacount == 0: @@ -390,10 +390,10 @@ macro max(x, y, ...) $endif } -/** - * @require types::is_numerical($typeof(x)) `The input must be a numerical value or numerical vector` - * @require types::is_same($typeof(x), $typeof(y)) `The input types must be equal` - **/ +<* + @require types::is_numerical($typeof(x)) `The input must be a numerical value or numerical vector` + @require types::is_same($typeof(x), $typeof(y)) `The input types must be equal` +*> macro min(x, y, ...) { $if $vacount == 0: @@ -407,21 +407,21 @@ macro min(x, y, ...) $endif } -/** - * @require types::@is_float(a) `The input must be a floating point value` - * @require types::@has_same(a, b, c) `The input types must be equal` - **/ +<* + @require types::@is_float(a) `The input must be a floating point value` + @require types::@has_same(a, b, c) `The input types must be equal` +*> macro muladd(a, b, c) => $$fmuladd(a, b, c); -/** - * @require values::@is_floatlike(x) `The input must be a floating point value or float vector` - **/ +<* + @require values::@is_floatlike(x) `The input must be a floating point value or float vector` +*> macro nearbyint(x) => $$nearbyint(x); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` - * @require $assignable(exp, $typeof(values::promote_int(x))) || values::@is_int(exp) `The input must be an integer, castable to the type of x` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` + @require $assignable(exp, $typeof(values::promote_int(x))) || values::@is_int(exp) `The input must be an integer, castable to the type of x` +*> macro pow(x, exp) { $if types::is_floatlike($typeof(exp)): @@ -431,9 +431,9 @@ macro pow(x, exp) $endif } -/** - * @require values::@is_promotable_to_float(x) : `The input must be integer or floating type` - **/ +<* + @require values::@is_promotable_to_float(x) : `The input must be integer or floating type` +*> macro frexp(x, int* e) { $switch ($typeof(x)) @@ -445,9 +445,9 @@ macro frexp(x, int* e) $endswitch } -/** - * @require values::@is_promotable_to_float(x) : `The input must be integer or floating type` - **/ +<* + @require values::@is_promotable_to_float(x) : `The input must be integer or floating type` +*> macro int signbit(x) { $switch ($typeof(x)) @@ -459,64 +459,64 @@ macro int signbit(x) $endswitch } -/** - * @require values::@is_floatlike(x) `The input must be a number or a float vector` - **/ +<* + @require values::@is_floatlike(x) `The input must be a number or a float vector` +*> macro rint(x) => $$rint(x); -/** - * @require values::@is_floatlike(x) `The input must be a floating point value or float vector` - **/ +<* + @require values::@is_floatlike(x) `The input must be a floating point value or float vector` +*> macro round(x) => $$round(x); -/** - * @require values::@is_floatlike(x) `The input must be a floating point value or float vector` - **/ +<* + @require values::@is_floatlike(x) `The input must be a floating point value or float vector` +*> macro round_to_decimals(x, int decimal_places) { var div = $$pow_int(($typeof(x))10, decimal_places); return round(div * x) / div; } -/** - * @require values::@is_floatlike(x) `The input must be a floating point value or float vector` - **/ +<* + @require values::@is_floatlike(x) `The input must be a floating point value or float vector` +*> macro roundeven(x) => $$roundeven(x); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` +*> macro sec(x) => 1 / cos(x); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` +*> macro sech(x) => 2 / (exp(x) + exp(-x)); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` +*> macro sin(x) => $$sin(values::promote_int(x)); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` +*> macro sinh(x) => (exp(x) - exp(-x)) / 2.0; -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` +*> macro sqr(x) => values::promote_int(x) * values::promote_int(x); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` +*> macro sqrt(x) => $$sqrt(values::promote_int(x)); -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` +*> macro tan(x) { var $Type = $typeof(x); @@ -530,9 +530,9 @@ macro tan(x) $endswitch } -/** - * @require values::@is_promotable_to_float(x) `The input must be a float` - **/ +<* + @require values::@is_promotable_to_float(x) `The input must be a float` +*> macro bool is_finite(x) { $switch ($typeof(x)) @@ -544,9 +544,9 @@ macro bool is_finite(x) $endswitch } -/** - * @require values::@is_promotable_to_float(x) `The input must be a float` - **/ +<* + @require values::@is_promotable_to_float(x) `The input must be a float` +*> macro is_nan(x) { $switch ($typeof(x)) @@ -558,9 +558,9 @@ macro is_nan(x) $endswitch } -/** - * @require values::@is_promotable_to_float(x) `The input must be a float` - **/ +<* + @require values::@is_promotable_to_float(x) `The input must be a float` +*> macro is_inf(x) { $switch ($typeof(x)) @@ -572,14 +572,14 @@ macro is_inf(x) $endswitch } -/** - * @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` - **/ +<* + @require values::@is_promotable_to_floatlike(x) `The input must be a number or a float vector` +*> macro tanh(x) => (exp(2.0 * x) - 1.0) / (exp(2.0 * x) + 1.0); -/** - * @require values::@is_floatlike(x) `The input must be a floating point value or float vector` - **/ +<* + @require values::@is_floatlike(x) `The input must be a floating point value or float vector` +*> macro trunc(x) => $$trunc(x); macro lerp(x, y, amount) @private => x + (y - x) * amount; @@ -595,18 +595,18 @@ macro normalize(x) @private return x * (1 / len); } -/** - * Use a mask to select values from either "then" or "else" vectors. - * - * @param mask "The mask to use for the select, 'true' will pick the then_value, 'false' the else_value" - * @param then_value "The vector to get elements from where the mask is 'true'" - * @param else_value "The vector to get elements from where the mask is 'false'" - * @require values::@is_vector(then_value) && values::@is_vector(else_value) "'Then' and 'else' must be vectors." - * @require values::@is_same_type(then_value, else_value) "'Then' and 'else' vectors must be of the same type." - * @require then_value.len == mask.len "Mask and selected vectors must be of the same width." - * - * @return "a vector of the same type as then/else" - **/ +<* + Use a mask to select values from either "then" or "else" vectors. + + @param mask "The mask to use for the select, 'true' will pick the then_value, 'false' the else_value" + @param then_value "The vector to get elements from where the mask is 'true'" + @param else_value "The vector to get elements from where the mask is 'false'" + @require values::@is_vector(then_value) && values::@is_vector(else_value) "'Then' and 'else' must be vectors." + @require values::@is_same_type(then_value, else_value) "'Then' and 'else' vectors must be of the same type." + @require then_value.len == mask.len "Mask and selected vectors must be of the same width." + + @return "a vector of the same type as then/else" +*> macro select(bool[<*>] mask, then_value, else_value) { return $$select(mask, then_value, else_value); @@ -951,14 +951,14 @@ macro int128 int128.sat_shl(int128 x, int128 y) => $$sat_shl(x, y); macro int128! int128.overflow_add(int128 x, int128 y) => overflow_add_helper(x, y); macro int128! int128.overflow_sub(int128 x, int128 y) => overflow_sub_helper(x, y); macro int128! int128.overflow_mul(int128 x, int128 y) => overflow_mul_helper(x, y); -/** - * @require values::@is_int(x) `The input must be an integer` - **/ +<* + @require values::@is_int(x) `The input must be an integer` +*> macro bool is_odd(x) => (bool)(x & 1); -/** - * @require values::@is_int(x) `The input must be an integer` - **/ +<* + @require values::@is_int(x) `The input must be an integer` +*> macro bool is_even(x) => !is_odd(x); macro bool char.is_even(char x) => is_even(x); @@ -991,9 +991,9 @@ macro bool uint128.is_odd(uint128 x) => is_odd(x); macro bool int128.is_even(int128 x) => is_even(x); macro bool int128.is_odd(int128 x) => is_odd(x); -/** - * @require types::is_underlying_int($typeof(x)) : `is_power_of_2 may only be used on integer types` - */ +<* + @require types::is_underlying_int($typeof(x)) : `is_power_of_2 may only be used on integer types` +*> macro bool is_power_of_2(x) { return x != 0 && (x & (x - 1)) == 0; @@ -1137,50 +1137,50 @@ macro bool @is_same_vector_or_scalar(#vector_value, #vector_or_scalar) @private return (values::@is_vector(#vector_or_scalar) &&& values::@is_same_vector_type(#vector_value, #vector_or_scalar)) ||| values::@is_int(#vector_or_scalar); } -/** - * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` - * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` - */ +<* + @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` +*> macro char[<*>] char[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div); -/** - * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` - * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` - */ +<* + @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` +*> macro ichar[<*>] ichar[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div); -/** - * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` - * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` - */ +<* + @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` +*> macro short[<*>] short[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div); -/** - * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` - * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` - */ +<* + @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` +*> macro ushort[<*>] ushort[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div); -/** - * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` - * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` - */ +<* + @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` +*> macro int[<*>] int[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div); -/** - * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` - * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` - */ +<* + @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` +*> macro uint[<*>] uint[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div); -/** - * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` - * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` - */ +<* + @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` +*> macro long[<*>] long[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div); -/** - * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` - * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` - */ +<* + @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` +*> macro ulong[<*>] ulong[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div); \ No newline at end of file diff --git a/lib/std/math/math_nolibc/atan.c3 b/lib/std/math/math_nolibc/atan.c3 index 167c77704..1a6e9a8d8 100644 --- a/lib/std/math/math_nolibc/atan.c3 +++ b/lib/std/math/math_nolibc/atan.c3 @@ -213,7 +213,7 @@ fn double _atan2(double y, double x) @weak @extern("atan2") @nostrip case 3: return -math::PI; /* atan(-0,-anything) =-pi */ } } - // when x = 0 */ + // when x = 0 if (ix | lx == 0) return m & 1 ? -math::PI_2 : math::PI_2; /* when x is INF */ if (ix == 0x7ff00000) diff --git a/lib/std/math/math_nolibc/exp2.c3 b/lib/std/math/math_nolibc/exp2.c3 index a14f3f363..f04fca9f2 100644 --- a/lib/std/math/math_nolibc/exp2.c3 +++ b/lib/std/math/math_nolibc/exp2.c3 @@ -88,8 +88,8 @@ fn double _exp2(double x) @extern("exp2") @weak @nostrip { if (abstop - _top12d(0x1p-54) >= 0x80000000) { - // Avoid spurious underflow for tiny x. */ - // Note: 0 is common input. */ + // Avoid spurious underflow for tiny x. + // Note: 0 is common input. return WANT_ROUNDING ? 1.0 + x : 1.0; } if (abstop >= _top12d(1024.0)) @@ -110,8 +110,8 @@ fn double _exp2(double x) @extern("exp2") @weak @nostrip if (2 * u > 2 * bitcast(928.0, ulong)) abstop = 0; } const SHIFT = __EXP2_DATA.exp2_shift; - // exp2(x) = 2^(k/N) * 2^r, with 2^r in [2^(-1/2N),2^(1/2N)]. */ - // x = k/N + r, with int k and r in [-1/2N, 1/2N]. */ + // exp2(x) = 2^(k/N) * 2^r, with 2^r in [2^(-1/2N),2^(1/2N)]. + // x = k/N + r, with int k and r in [-1/2N, 1/2N]. double kd = x + SHIFT; ulong ki = bitcast(kd, ulong); /* k. */ kd -= SHIFT; /* k/N for int k. */ diff --git a/lib/std/math/math_nolibc/rempi.c3 b/lib/std/math/math_nolibc/rempi.c3 index f802f4380..ac3172143 100644 --- a/lib/std/math/math_nolibc/rempi.c3 +++ b/lib/std/math/math_nolibc/rempi.c3 @@ -23,11 +23,11 @@ import std::math; * use __rem_pio2_large() for large x */ -/* +<* * invpio2: 53 bits of 2/pi * pio2_1: first 25 bits of pi/2 * pio2_1t: pi/2 - pio2_1 - */ + *> fn int __rem_pio2f(float x, double *y) { const double PIO4 = 0x1.921fb6p-1; @@ -62,7 +62,7 @@ fn int __rem_pio2f(float x, double *y) } if (ix >= 0x7f800000) { - // x is inf or NaN */ + // x is inf or NaN *y = x - (double)x; return 0; } @@ -365,7 +365,7 @@ fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec) * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) */ -/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +<* caller must handle the case when reduction is not needed: |x| ~<= pi/4 *> fn int __rem_pio2(double x, double *y) { const double PIO4 = 0x1.921fb54442d18p-1; @@ -452,7 +452,7 @@ fn int __rem_pio2(double x, double *y) case ix < 0x413921fb: break; // medium case ix >= 0x7ff00000: - // x is inf or NaN */ + // x is inf or NaN y[0] = y[1] = x - x; return 0; default: @@ -512,7 +512,7 @@ fn int __rem_pio2(double x, double *y) int ex = (int)(ix >> 20); if (ex - ey > 16) { - // 2nd round, good to 118 bits */ + // 2nd round, good to 118 bits double t = r; w = fnn * PIO2_2; r = t - w; diff --git a/lib/std/math/math_nolibc/tan.c3 b/lib/std/math/math_nolibc/tan.c3 index e9f3265f1..79ea73648 100644 --- a/lib/std/math/math_nolibc/tan.c3 +++ b/lib/std/math/math_nolibc/tan.c3 @@ -23,7 +23,7 @@ fn double tan(double x) @extern("tan") @weak @nostrip case ix <= 0x3fe921fb: if (ix < 0x3e400000) { - // |x| < 2**-27 */ + // |x| < 2**-27 /* raise inexact if x!=0 and underflow if subnormal */ force_eval_add(ix < 0x00100000 ? x / 0x1p120f : x + 0x1p120f, 0); return x; @@ -83,7 +83,7 @@ fn float tanf(float x) @extern("tanf") @weak @nostrip : __tandf(sign ? x + S2PI2 : x - S2PI2, 0); // |x| ~<= 9*pi/4 case ix <= 0x40e231d5: - // |x| ~<= 7*pi/4 */ + // |x| ~<= 7*pi/4 return ix <= 0x40afeddf ? __tandf(sign ? x + S3PI2 : x - S3PI2, 1) : __tandf(sign ? x + S4PI2 : x - S4PI2, 0); diff --git a/lib/std/math/math_random.c3 b/lib/std/math/math_random.c3 index e58929cd3..c43e7d1e3 100644 --- a/lib/std/math/math_random.c3 +++ b/lib/std/math/math_random.c3 @@ -1,39 +1,39 @@ -/** - * Randoms: - * General usage - - * 1. Create a Random (see std/math/random for various alternatives), or pick DefaultRandom - * 2. Define it `DefaultRandom my_random;` - * 3. Seed it: `random::seed(&my_random, some_seed);` or `rand::seed_entropy(&my_random);` - * 4. Use it with the functions in random: `float random_float = random::next_float(&my_random);` +<* +Randoms: +General usage - +1. Create a Random (see std/math/random for various alternatives), or pick DefaultRandom +2. Define it `DefaultRandom my_random;` +3. Seed it: `random::seed(&my_random, some_seed);` or `rand::seed_entropy(&my_random);` +4. Use it with the functions in random: `float random_float = random::next_float(&my_random);` * - * For just a simple integer between 0 and n (not including n), you can use `rand(n)`. - **/ +For just a simple integer between 0 and n (not including n), you can use `rand(n)`. +*> module std::math::random; -/** - * @require is_random(random) - **/ +<* + @require is_random(random) +*> macro void seed(random, seed) { random.set_seed(@as_char_view(seed)); } -/** - * Seed the random with some best effort entropy. +<* +Seed the random with some best effort entropy. * - * @require is_random(random) - **/ + @require is_random(random) +*> macro void seed_entropy(random) { random.set_seed(&&entropy()); } -/** - * Get the next value between 0 and range (not including range). +<* +Get the next value between 0 and range (not including range). * - * @require is_random(random) - * @require range > 0 - **/ + @require is_random(random) + @require range > 0 +*> macro int next(random, uint range) { if (range == 1) return 0; @@ -49,12 +49,12 @@ macro int next(random, uint range) return x; } -/** - * Get a random in the range [min, max], both included. +<* +Get a random in the range [min, max], both included. * - * @require is_random(random) - * @require max >= min - **/ + @require is_random(random) + @require max >= min +*> macro int next_in_range(random, int min, int max) { return next(random, max - min + 1) + min; @@ -65,28 +65,28 @@ def DefaultRandom = Sfc64Random; tlocal Sfc64Random default_random @private; tlocal bool default_random_initialized @private = false; -/** - * Seed the default random function. - */ +<* +Seed the default random function. +*> fn void srand(ulong seed) @builtin { default_random.set_seed(@as_char_view(seed)); default_random_initialized = true; } -/** - * Get a default random value between 0 and range (not including range) - **/ +<* +Get a default random value between 0 and range (not including range) +*> fn int rand(int range) @builtin { init_default_random(); return next(&default_random, range); } -/** - * Get a random in the range, both included. - * @require max >= min - **/ +<* +Get a random in the range, both included. + @require max >= min +*> fn int rand_in_range(int min, int max) @builtin { init_default_random(); @@ -100,32 +100,32 @@ fn double rnd() @builtin return val * 0x1.0p-53; } -/** - * Get 'true' or 'false' +<* +Get 'true' or 'false' * - * @require is_random(random) - **/ + @require is_random(random) +*> macro bool next_bool(random) { return (bool)(random.next_byte() & 1); } -/** - * Get a float between 0 and 1.0, not including 1.0. +<* +Get a float between 0 and 1.0, not including 1.0. * - * @require is_random(random) - **/ + @require is_random(random) +*> macro float next_float(random) { uint val = random.next_int() & (1 << 24 - 1); return val / (float)(1 << 24); } -/** - * Get a double between 0 and 1.0, not including 1.0. +<* +Get a double between 0 and 1.0, not including 1.0. * - * @require is_random(random) - **/ + @require is_random(random) +*> macro double next_double(random) { ulong val = random.next_long() & (1UL << 53 - 1); diff --git a/lib/std/math/random/math.lcg.c3 b/lib/std/math/random/math.lcg.c3 index 4ea4a4cb1..79e0fe2b0 100644 --- a/lib/std/math/random/math.lcg.c3 +++ b/lib/std/math/random/math.lcg.c3 @@ -29,9 +29,9 @@ fn ulong Lcg128Random.next_long(&self) @dynamic return result; } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Lcg128Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_long, bytes); fn uint128 Lcg128Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); fn uint Lcg128Random.next_int(&self) @dynamic => (uint)self.next_long(); @@ -56,9 +56,9 @@ fn uint Lcg64Random.next_int(&self) @dynamic return result; } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Lcg64Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int, bytes); fn uint128 Lcg64Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); fn ulong Lcg64Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); diff --git a/lib/std/math/random/math.mcg.c3 b/lib/std/math/random/math.mcg.c3 index b1b4e8745..4c57787c4 100644 --- a/lib/std/math/random/math.mcg.c3 +++ b/lib/std/math/random/math.mcg.c3 @@ -14,9 +14,9 @@ fn void Mcg128Random.set_seed(&self, char[] seed) @dynamic *self = (Mcg128Random)(random::make_seed(uint128, seed) | 1); } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Mcg128Random.next_bytes(&self, char[] bytes) @dynamic { @random_value_to_bytes(self.next_long, bytes); @@ -47,9 +47,9 @@ fn void Mcg64Random.set_seed(&self, char[] seed) @dynamic *self = (Mcg64Random)random::make_seed(ulong, seed) | 1; } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Mcg64Random.next_bytes(&self, char[] bytes) @dynamic { @random_value_to_bytes(self.next_int, bytes); @@ -86,9 +86,9 @@ fn ushort Mcg32Random.next_short(&self) @dynamic return result; } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Mcg32Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_short, bytes); fn uint128 Mcg32Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); fn ulong Mcg32Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); diff --git a/lib/std/math/random/math.msws.c3 b/lib/std/math/random/math.msws.c3 index efa3e3c67..61cdc7266 100644 --- a/lib/std/math/random/math.msws.c3 +++ b/lib/std/math/random/math.msws.c3 @@ -35,9 +35,9 @@ fn uint128 Msws128Random.next_int128(&self) @dynamic return s0 + s1; } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Msws128Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int128, bytes); fn ulong Msws128Random.next_long(&self) @dynamic => (ulong)self.next_int128(); fn uint Msws128Random.next_int(&self) @dynamic => (uint)self.next_int128(); @@ -72,9 +72,9 @@ fn ulong Msws64Random.next_long(&self) @dynamic return s0 + s1; } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Msws64Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_long, bytes); fn uint128 Msws64Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); fn uint Msws64Random.next_int(&self) @dynamic => (uint)self.next_long(); @@ -109,9 +109,9 @@ fn uint Msws32Random.next_int(&self) @dynamic return s0 + s1; } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Msws32Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int, bytes); fn uint128 Msws32Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); fn ulong Msws32Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); @@ -147,9 +147,9 @@ fn ushort Msws16Random.next_short(&self) @dynamic return s0 + s1; } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Msws16Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_short, bytes); fn uint128 Msws16Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); fn ulong Msws16Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); diff --git a/lib/std/math/random/math.pcg.c3 b/lib/std/math/random/math.pcg.c3 index bafa3ebdd..53d56c477 100644 --- a/lib/std/math/random/math.pcg.c3 +++ b/lib/std/math/random/math.pcg.c3 @@ -33,9 +33,9 @@ fn ulong Pcg128Random.next_long(&self) @dynamic return ((ulong)(xor >> ROT_SHIFT)).rotr(rot); } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Pcg128Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_long, bytes); fn uint128 Pcg128Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); fn uint Pcg128Random.next_int(&self) @dynamic => (uint)self.next_long(); @@ -61,9 +61,9 @@ fn uint Pcg64Random.next_int(&self) @dynamic return ((uint)(xor >> ROT_SHIFT)).rotr(rot); } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Pcg64Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int, bytes); fn uint128 Pcg64Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); fn ulong Pcg64Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); @@ -90,9 +90,9 @@ fn ushort Pcg32Random.next_short(&self) @dynamic return ((ushort)(xor >> ROT_SHIFT)).rotr(rot); } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Pcg32Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_short, bytes); fn uint128 Pcg32Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); fn ulong Pcg32Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); diff --git a/lib/std/math/random/math.seeder.c3 b/lib/std/math/random/math.seeder.c3 index af1fc35e4..3c4449ddb 100644 --- a/lib/std/math/random/math.seeder.c3 +++ b/lib/std/math/random/math.seeder.c3 @@ -13,10 +13,10 @@ macro make_seed($Type, char[] input) } // TODO: Make endian independent -/** - * @param [in] input - * @param [inout] out_buffer - **/ +<* + @param [in] input + @param [inout] out_buffer +*> fn void seeder(char[] input, char[] out_buffer) { $if env::BIG_ENDIAN: diff --git a/lib/std/math/random/math.sfc.c3 b/lib/std/math/random/math.sfc.c3 index 19f1ca6eb..acf05822e 100644 --- a/lib/std/math/random/math.sfc.c3 +++ b/lib/std/math/random/math.sfc.c3 @@ -28,9 +28,9 @@ fn uint128 Sfc128Random.next_int128(&self) @dynamic // TODO: Find good constant return result; } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Sfc128Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int128, bytes); fn ulong Sfc128Random.next_long(&self) @dynamic => (uint)self.next_int128(); fn uint Sfc128Random.next_int(&self) @dynamic => (uint)self.next_int128(); @@ -58,9 +58,9 @@ fn ulong Sfc64Random.next_long(&self) @dynamic return result; } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Sfc64Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_long, bytes); fn uint128 Sfc64Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); fn uint Sfc64Random.next_int(&self) @dynamic => (uint)self.next_long(); @@ -87,9 +87,9 @@ fn uint Sfc32Random.next_int(&sfc) @dynamic return result; } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Sfc32Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int, bytes); fn uint128 Sfc32Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); fn ulong Sfc32Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); @@ -117,9 +117,9 @@ fn ushort Sfc16Random.next_short(&seed) @dynamic return result; } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void Sfc16Random.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_short, bytes); fn uint128 Sfc16Random.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); fn ulong Sfc16Random.next_long(&self) @dynamic => @int_to_long(self.next_int()); diff --git a/lib/std/math/random/math.simple_random.c3 b/lib/std/math/random/math.simple_random.c3 index 06e751d94..07a43b3fe 100644 --- a/lib/std/math/random/math.simple_random.c3 +++ b/lib/std/math/random/math.simple_random.c3 @@ -20,9 +20,9 @@ fn uint SimpleRandom.next_int(&self) @dynamic return (uint)(nextseed >> (48 - 32)); } -/** - * @require bytes.len > 0 - **/ +<* + @require bytes.len > 0 +*> fn void SimpleRandom.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int, bytes); fn uint128 SimpleRandom.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); fn ulong SimpleRandom.next_long(&self) @dynamic => @int_to_long(self.next_int()); diff --git a/lib/std/math/uuid.c3 b/lib/std/math/uuid.c3 index 564d1eeee..8d309c2c6 100644 --- a/lib/std/math/uuid.c3 +++ b/lib/std/math/uuid.c3 @@ -4,18 +4,18 @@ import std::io; distinct Uuid (Printable) = char[16]; -/** - * Generate a version 4 UUID from the default random. - **/ +<* +Generate a version 4 UUID from the default random. +*> fn Uuid generate() { random::init_default_random(); return generate_from_random(&random::default_random); } -/** - * Generate a version 4 UUID from the given random. - **/ +<* +Generate a version 4 UUID from the given random. +*> fn Uuid generate_from_random(Random random) { Uuid uuid; diff --git a/lib/std/net/socket.c3 b/lib/std/net/socket.c3 index a4c109bd0..8ba01e54a 100644 --- a/lib/std/net/socket.c3 +++ b/lib/std/net/socket.c3 @@ -57,10 +57,10 @@ fn ulong! poll_ms(Poll[] polls, long timeout_ms) return poll(polls, time::ms(timeout_ms)) @inline; } -/** - * @param [inout] polls - * @param timeout "duration to poll." - **/ +<* + @param [inout] polls + @param timeout "duration to poll." +*> fn ulong! poll(Poll[] polls, Duration timeout) { long time_ms = timeout.to_ms(); diff --git a/lib/std/os/env.c3 b/lib/std/os/env.c3 index c0f8ea8ce..6d4c054ca 100644 --- a/lib/std/os/env.c3 +++ b/lib/std/os/env.c3 @@ -4,11 +4,11 @@ module std::os::env; import std::io::path, libc, std::os; -/** - * @param [in] name - * @require name.len > 0 - * @return! SearchResult.MISSING - **/ +<* + @param [in] name + @require name.len > 0 + @return! SearchResult.MISSING +*> fn String! get_var(String name, Allocator allocator = allocator::heap()) { @pool(allocator) @@ -41,11 +41,11 @@ fn String! get_var_temp(String name) return get_var(name, allocator::temp()); } -/** - * @param [in] name - * @param [in] value - * @require name.len > 0 - **/ +<* + @param [in] name + @param [in] value + @require name.len > 0 +*> fn bool set_var(String name, String value, bool overwrite = true) { @pool() @@ -69,9 +69,9 @@ fn bool set_var(String name, String value, bool overwrite = true) } -/** - * Returns the current user's home directory. - **/ +<* +Returns the current user's home directory. +*> fn String! get_home_dir(Allocator using = allocator::heap()) { String home; @@ -88,9 +88,9 @@ fn Path! get_config_dir(Allocator allocator = allocator::heap()) @deprecated("us return new_get_config_dir(allocator) @inline; } -/** - * Returns the current user's config directory. - **/ +<* +Returns the current user's config directory. +*> fn Path! new_get_config_dir(Allocator allocator = allocator::heap()) { @pool(allocator) @@ -111,10 +111,10 @@ fn Path! new_get_config_dir(Allocator allocator = allocator::heap()) } -/** - * @param [in] name - * @require name.len > 0 - **/ +<* + @param [in] name + @require name.len > 0 +*> fn bool clear_var(String name) { @pool() diff --git a/lib/std/os/subprocess.c3 b/lib/std/os/subprocess.c3 index 860771c2a..234b82856 100644 --- a/lib/std/os/subprocess.c3 +++ b/lib/std/os/subprocess.c3 @@ -114,9 +114,9 @@ fn WString convert_command_line_win32(String[] command_line) @inline @if(env::WI return str.str_view().to_temp_wstring()!!; } -/** - * @require !environment || !options.inherit_environment - **/ +<* + @require !environment || !options.inherit_environment +*> fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, String[] environment = {}) @if(env::WIN32) { void* rd, wr; @@ -241,9 +241,9 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str }; } -/** - * @require command_line.len > 0 - **/ +<* + @require command_line.len > 0 +*> fn ZString* tcopy_command_line(String[] command_line) @local @inline @if(env::POSIX) { ZString* copy = mem::temp_alloc_array(ZString, command_line.len + 1); @@ -276,9 +276,9 @@ fn String! execute_stdout_to_buffer(char[] buffer, String[] command_line, SubPro return (String)buffer[:len - 1]; } -/** - * @require !environment || !options.inherit_environment - **/ +<* + @require !environment || !options.inherit_environment +*> fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, String[] environment = {}) @if(env::POSIX) { CInt[2] stdinfd; @@ -405,9 +405,9 @@ fn void! SubProcess.terminate(&self) $endif } -/** - * @require size <= Win32_DWORD.max - **/ +<* + @require size <= Win32_DWORD.max +*> fn usz! read_from_file_win32(CFile file, Win32_HANDLE event_handle, char* buffer, usz size) @if(env::WIN32) @local { CInt fd = libc::fileno(file); diff --git a/lib/std/sort/binarysearch.c3 b/lib/std/sort/binarysearch.c3 index ae7180bf2..0a58c24ec 100644 --- a/lib/std/sort/binarysearch.c3 +++ b/lib/std/sort/binarysearch.c3 @@ -1,12 +1,12 @@ module std::sort; -/** - * Perform a binary search over the sorted array and return the index - * in [0, array.len) where x would be inserted or cmp(i) is true and cmp(j) is true for j in [i, array.len). - * @require @is_sortable(list) "The list must be sortable" - * @require @is_valid_cmp_fn(cmp, list, context) "Expected a comparison function which compares values" - * @require @is_valid_context(cmp, context) "Expected a valid context" - **/ +<* +Perform a binary search over the sorted array and return the index +in [0, array.len) where x would be inserted or cmp(i) is true and cmp(j) is true for j in [i, array.len). + @require @is_sortable(list) "The list must be sortable" + @require @is_valid_cmp_fn(cmp, list, context) "Expected a comparison function which compares values" + @require @is_valid_context(cmp, context) "Expected a valid context" +*> macro usz binarysearch(list, x, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin { usz i; diff --git a/lib/std/sort/countingsort.c3 b/lib/std/sort/countingsort.c3 index 70521f219..fed1870ab 100644 --- a/lib/std/sort/countingsort.c3 +++ b/lib/std/sort/countingsort.c3 @@ -3,11 +3,11 @@ import std::sort::is; import std::sort::cs; import std::sort::qs; -/** - * Sort list using the counting sort algorithm. - * @require @is_sortable(list) "The list must be indexable and support .len or .len()" - * @require @is_cmp_key_fn(key_fn, list) "Expected a transformation function which returns an unsigned integer." - **/ +<* +Sort list using the counting sort algorithm. + @require @is_sortable(list) "The list must be indexable and support .len or .len()" + @require @is_cmp_key_fn(key_fn, list) "Expected a transformation function which returns an unsigned integer." +*> macro countingsort(list, key_fn = EMPTY_MACRO_SLOT) @builtin { usz len = sort::@len_from_list(list); diff --git a/lib/std/sort/insertionsort.c3 b/lib/std/sort/insertionsort.c3 index 350e066d7..51dca7b73 100644 --- a/lib/std/sort/insertionsort.c3 +++ b/lib/std/sort/insertionsort.c3 @@ -1,11 +1,11 @@ module std::sort; import std::sort::is; -/** - * Sort list using the quick sort algorithm. - * @require @is_sortable(list) "The list must be indexable and support .len or .len()" - * @require @is_valid_cmp_fn(cmp, list, context) "Expected a comparison function which compares values" - **/ +<* +Sort list using the quick sort algorithm. + @require @is_sortable(list) "The list must be indexable and support .len or .len()" + @require @is_valid_cmp_fn(cmp, list, context) "Expected a comparison function which compares values" +*> macro insertionsort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin { usz len = sort::@len_from_list(list); diff --git a/lib/std/sort/quicksort.c3 b/lib/std/sort/quicksort.c3 index 3ce5722f0..e9ea163b7 100644 --- a/lib/std/sort/quicksort.c3 +++ b/lib/std/sort/quicksort.c3 @@ -1,12 +1,12 @@ module std::sort; import std::sort::qs; -/** - * Sort list using the quick sort algorithm. - * @require @is_sortable(list) "The list must be indexable and support .len or .len()" - * @require @is_valid_cmp_fn(cmp, list, context) "Expected a comparison function which compares values" - * @require @is_valid_context(cmp, context) "Expected a valid context" - **/ +<* +Sort list using the quick sort algorithm. + @require @is_sortable(list) "The list must be indexable and support .len or .len()" + @require @is_valid_cmp_fn(cmp, list, context) "Expected a comparison function which compares values" + @require @is_valid_context(cmp, context) "Expected a valid context" +*> macro quicksort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin { usz len = sort::@len_from_list(list); diff --git a/lib/std/threads/fixed_pool.c3 b/lib/std/threads/fixed_pool.c3 index 9f0c00517..be000576b 100644 --- a/lib/std/threads/fixed_pool.c3 +++ b/lib/std/threads/fixed_pool.c3 @@ -31,11 +31,11 @@ struct QueueItem @private any[] args; } -/** - * @require !self.initialized "ThreadPool must not be already initialized" - * @require threads > 0 && threads < 0x1000 `Threads should be greater than 0 and less than 0x1000` - * @require queue_size < 0x10000 `Queue size must be less than 65536` - **/ +<* + @require !self.initialized "ThreadPool must not be already initialized" + @require threads > 0 && threads < 0x1000 `Threads should be greater than 0 and less than 0x1000` + @require queue_size < 0x10000 `Queue size must be less than 65536` +*> fn void! FixedThreadPool.init(&self, usz threads, usz queue_size = 0) { if (queue_size == 0) queue_size = threads * 32; @@ -57,19 +57,19 @@ fn void! FixedThreadPool.init(&self, usz threads, usz queue_size = 0) } } -/* - * Stop all the threads and cleanup the pool. - * Any pending work will be dropped. - */ +<* + Stop all the threads and cleanup the pool. + Any pending work will be dropped. +*> fn void! FixedThreadPool.destroy(&self) { return self.@shutdown(stop_now); } -/* - * Stop all the threads and cleanup the pool. - * Any pending work will be processed. - */ +<* + Stop all the threads and cleanup the pool. + Any pending work will be processed. +*> fn void! FixedThreadPool.stop_and_destroy(&self) { return self.@shutdown(stop); @@ -105,10 +105,10 @@ macro void! FixedThreadPool.@shutdown(&self, #stop) @private } } -/* - * Push a new job to the pool. - * Returns whether the queue is full, in which case the job is ignored. - */ +<* + Push a new job to the pool. + return Excuse if the queue is full, in which case the job is ignored. +*> fn void! FixedThreadPool.push(&self, ThreadPoolFn func, args...) { self.mu.lock()!; diff --git a/lib/std/threads/os/thread_posix.c3 b/lib/std/threads/os/thread_posix.c3 index 61b1f7fbb..d543b9ab9 100644 --- a/lib/std/threads/os/thread_posix.c3 +++ b/lib/std/threads/os/thread_posix.c3 @@ -11,10 +11,10 @@ def NativeConditionVariable = Pthread_cond_t; def NativeThread = Pthread_t; def NativeOnceFlag = Pthread_once_t; -/** - * @require !self.is_initialized() : "Mutex is already initialized" - * @ensure self.is_initialized() - **/ +<* + @require !self.is_initialized() : "Mutex is already initialized" + @ensure self.is_initialized() +*> fn void! NativeMutex.init(&self, MutexType type) { Pthread_mutexattr_t attr; @@ -39,27 +39,27 @@ fn bool NativeMutex.is_initialized(&self) return self.initialized; } -/** - * @require self.is_initialized() : "Mutex was not initialized" - * @ensure !self.is_initialized() - **/ +<* + @require self.is_initialized() : "Mutex was not initialized" + @ensure !self.is_initialized() +*> fn void! NativeMutex.destroy(&self) { if (posix::pthread_mutex_destroy(&self.mutex)) return ThreadFault.DESTROY_FAILED?; *self = {}; } -/** - * @require self.is_initialized() : "Mutex was not initialized" - **/ +<* + @require self.is_initialized() : "Mutex was not initialized" +*> fn void! NativeMutex.lock(&self) { if (posix::pthread_mutex_lock(&self.mutex)) return ThreadFault.LOCK_FAILED?; } -/** - * @require self.is_initialized() : "Mutex was not initialized" - **/ +<* + @require self.is_initialized() : "Mutex was not initialized" +*> fn void! NativeMutex.lock_timeout(&self, ulong ms) { /* Try to acquire the lock and, if we fail, sleep for 5ms. */ @@ -83,17 +83,17 @@ fn void! NativeMutex.lock_timeout(&self, ulong ms) } } -/** - * @require self.is_initialized() : "Mutex was not initialized" - **/ +<* + @require self.is_initialized() : "Mutex was not initialized" +*> fn bool NativeMutex.try_lock(&self) { return !posix::pthread_mutex_trylock(&self.mutex); } -/** - * @require self.is_initialized() : "Mutex was not initialized" - **/ +<* + @require self.is_initialized() : "Mutex was not initialized" +*> fn void! NativeMutex.unlock(&self) { if (posix::pthread_mutex_unlock(&self.mutex)) return ThreadFault.UNLOCK_FAILED?; @@ -119,17 +119,17 @@ fn void! NativeConditionVariable.broadcast(&cond) if (posix::pthread_cond_broadcast(cond)) return ThreadFault.SIGNAL_FAILED?; } -/** - * @require mtx.is_initialized() - **/ +<* + @require mtx.is_initialized() +*> fn void! NativeConditionVariable.wait(&cond, NativeMutex* mtx) { if (posix::pthread_cond_wait(cond, &mtx.mutex)) return ThreadFault.WAIT_FAILED?; } -/** - * @require mtx.is_initialized() - **/ +<* + @require mtx.is_initialized() +*> fn void! NativeConditionVariable.wait_timeout(&cond, NativeMutex* mtx, ulong ms) { TimeSpec now; diff --git a/lib/std/threads/os/thread_win32.c3 b/lib/std/threads/os/thread_win32.c3 index 8181bc68c..94c265413 100644 --- a/lib/std/threads/os/thread_win32.c3 +++ b/lib/std/threads/os/thread_win32.c3 @@ -88,9 +88,9 @@ fn void! NativeMutex.lock(&mtx) } -/** - * @require mtx.timed "Only available for timed locks" - **/ +<* + @require mtx.timed "Only available for timed locks" +*> fn void! NativeMutex.lock_timeout(&mtx, ulong ms) { if (ms > uint.max) ms = uint.max; diff --git a/lib/std/threads/pool.c3 b/lib/std/threads/pool.c3 index c92f0077b..df80a7d30 100644 --- a/lib/std/threads/pool.c3 +++ b/lib/std/threads/pool.c3 @@ -23,9 +23,9 @@ struct QueueItem @private void* arg; } -/** - * @require !self.initialized "ThreadPool must not be already initialized" - **/ +<* + @require !self.initialized "ThreadPool must not be already initialized" +*> fn void! ThreadPool.init(&self) { defer catch @ok(self.destroy()); @@ -40,19 +40,19 @@ fn void! ThreadPool.init(&self) } } -/* - * Stop all the threads and cleanup the pool. - * Any pending work will be dropped. - */ +<* + Stop all the threads and cleanup the pool. + Any pending work will be dropped. +*> fn void! ThreadPool.destroy(&self) { return self.@shutdown(stop_now); } -/* - * Stop all the threads and cleanup the pool. - * Any pending work will be processed. - */ +<* + Stop all the threads and cleanup the pool. + Any pending work will be processed. +*> fn void! ThreadPool.stop_and_destroy(&self) { return self.@shutdown(stop); @@ -82,10 +82,10 @@ macro void! ThreadPool.@shutdown(&self, #stop) @private } } -/* - * Push a new job to the pool. - * Returns whether the queue is full, in which case the job is ignored. - */ +<* + Push a new job to the pool. + Returns whether the queue is full, in which case the job is ignored. +*> fn void! ThreadPool.push(&self, ThreadFn func, void* arg) { while (true) diff --git a/lib/std/time/datetime.c3 b/lib/std/time/datetime.c3 index 585b9b17b..3c5ee9c5d 100644 --- a/lib/std/time/datetime.c3 +++ b/lib/std/time/datetime.c3 @@ -6,13 +6,13 @@ fn DateTime now() return from_time(time::now()); } -/** - * @require day >= 1 && day < 32 - * @require hour >= 0 && hour < 24 - * @require min >= 0 && min < 60 - * @require sec >= 0 && sec < 60 - * @require us >= 0 && us < 999_999 - **/ +<* + @require day >= 1 && day < 32 + @require hour >= 0 && hour < 24 + @require min >= 0 && min < 60 + @require sec >= 0 && sec < 60 + @require us >= 0 && us < 999_999 +*> fn DateTime from_date(int year, Month month = JANUARY, int day = 1, int hour = 0, int min = 0, int sec = 0, int us = 0) { DateTime dt @noinit; @@ -20,14 +20,14 @@ fn DateTime from_date(int year, Month month = JANUARY, int day = 1, int hour = 0 return dt; } -/** - * @require day >= 1 && day < 32 - * @require hour >= 0 && hour < 24 - * @require min >= 0 && min < 60 - * @require sec >= 0 && sec < 60 - * @require us >= 0 && us < 999_999 - * @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600 - **/ +<* + @require day >= 1 && day < 32 + @require hour >= 0 && hour < 24 + @require min >= 0 && min < 60 + @require sec >= 0 && sec < 60 + @require us >= 0 && us < 999_999 + @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600 +*> fn TzDateTime from_date_tz(int year, Month month = JANUARY, int day = 1, int hour = 0, int min = 0, int sec = 0, int us = 0, int gmt_offset = 0) { return from_date(year, month, day, hour, min, sec, us).with_gmt_offset(gmt_offset); @@ -60,50 +60,50 @@ fn TzDateTime DateTime.to_local(&self) return dt; } -/** - * Update timestamp to gmt_offset while keeping the date and time - * values unchanged. - * - * @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600 - **/ +<* + Update timestamp to gmt_offset while keeping the date and time + values unchanged. + + @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600 +*> fn TzDateTime DateTime.with_gmt_offset(self, int gmt_offset) { TzDateTime dt = { self, 0 }; return dt.with_gmt_offset(gmt_offset); } -/** - * Update timestamp to gmt_offset while keeping the date and time - * values unchanged. - * - * @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600 - **/ +<* + Update timestamp to gmt_offset while keeping the date and time + values unchanged. + + @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600 +*> fn TzDateTime TzDateTime.with_gmt_offset(self, int gmt_offset) { self.time -= (Time)(gmt_offset - self.gmt_offset) * (Time)time::SEC; return { self.date_time, gmt_offset }; } -/** - * Update the date and time values to gmt_offset while keeping the - * timestamp unchanged. - * - * @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600 - * @ensure self.time == return.time - **/ +<* + Update the date and time values to gmt_offset while keeping the + timestamp unchanged. + + @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600 + @ensure self.time == return.time +*> fn TzDateTime DateTime.to_gmt_offset(self, int gmt_offset) { TzDateTime dt = { self, 0 }; return dt.to_gmt_offset(gmt_offset); } -/** - * Update the date and time values to gmt_offset while keeping the - * timestamp unchanged. - * - * @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600 - * @ensure self.time == return.time - **/ +<* + Update the date and time values to gmt_offset while keeping the + timestamp unchanged. + + @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600 + @ensure self.time == return.time +*> fn TzDateTime TzDateTime.to_gmt_offset(self, int gmt_offset) { if (self.gmt_offset == gmt_offset) return self; Time time = self.time + (Time)gmt_offset * (Time)time::SEC; @@ -112,13 +112,13 @@ fn TzDateTime TzDateTime.to_gmt_offset(self, int gmt_offset) { return { dt, gmt_offset }; } -/** - * @require day >= 1 && day < 32 - * @require hour >= 0 && hour < 24 - * @require min >= 0 && min <= 60 - * @require sec >= 0 && sec < 60 - * @require us >= 0 && us < 999_999 - **/ +<* + @require day >= 1 && day < 32 + @require hour >= 0 && hour < 24 + @require min >= 0 && min <= 60 + @require sec >= 0 && sec < 60 + @require us >= 0 && us < 999_999 +*> fn void DateTime.set_date(&self, int year, Month month = JANUARY, int day = 1, int hour = 0, int min = 0, int sec = 0, int us = 0) { Tm tm; @@ -203,10 +203,10 @@ fn DateTime from_time(Time time) return dt; } -/** - * @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600 - * @ensure time == return.time - **/ +<* + @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600 + @ensure time == return.time +*> fn TzDateTime from_time_tz(Time time, int gmt_offset) { return from_time(time).to_gmt_offset(gmt_offset); diff --git a/releasenotes.md b/releasenotes.md index 94788b0ee..34e1d6724 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -12,6 +12,7 @@ - Constant bytes <=> char[] conversion should work #1514. - Infer now works across ternary. - Interfaces now support .ptr and .type directly without casting to `any`. +- Switch to `<* *>` docs. ### Fixes - `Unsupported int[*] $x = { 1, 2, 3, 4 }` #1489. diff --git a/resources/examples/dynlib-test/add.c3 b/resources/examples/dynlib-test/add.c3 new file mode 100644 index 000000000..4f98223f6 --- /dev/null +++ b/resources/examples/dynlib-test/add.c3 @@ -0,0 +1,18 @@ +import std; +struct Foo(Printable) +{ + int a; +} + +fn usz! Foo.to_format(&self, Formatter* f) @dynamic +{ + return f.printf("Foo[%d]", self.a); +} + +fn int add(int a, int b) @export("adder") +{ + io::printn("In adder"); + Foo x = { a }; + io::printfn("Print foo: %s", x); + return a + b; +} \ No newline at end of file diff --git a/resources/examples/dynlib-test/test.c3 b/resources/examples/dynlib-test/test.c3 new file mode 100644 index 000000000..1c412fe11 --- /dev/null +++ b/resources/examples/dynlib-test/test.c3 @@ -0,0 +1,8 @@ +import std; +extern fn int adder(int a, int b); + +fn int main() +{ + io::printn(adder(1, 4)); + return 0; +} \ No newline at end of file diff --git a/resources/examples/swap.c3 b/resources/examples/swap.c3 index 1e903df15..daef50dbc 100644 --- a/resources/examples/swap.c3 +++ b/resources/examples/swap.c3 @@ -1,9 +1,9 @@ module test; import libc; -/** - * @require values::@assign_to(*b, *a) && values::@assign_to(*a, *b) - */ +<* + @require values::@assign_to(*b, *a) && values::@assign_to(*a, *b) +*> macro void @swap(&a, &b) { var temp = *a; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 7724c6563..351df12b1 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -869,7 +869,7 @@ typedef enum typedef enum { LEX_NORMAL, - LEX_DOCS, + LEX_CONTRACTS, } LexMode; typedef enum @@ -1241,7 +1241,7 @@ typedef enum TOKEN_LAST_KEYWORD = TOKEN_CT_VASPLAT, TOKEN_DOCS_START, // /** TOKEN_DOCS_END, // */ (may start with an arbitrary number of `*` - TOKEN_DOC_DIRECTIVE, // Any doc directive + TOKEN_DOCS_EOL, TOKEN_EOF, // \n - SHOULD ALWAYS BE THE LAST TOKEN. diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index b40843a71..76e544595 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -251,7 +251,7 @@ static void skip_whitespace(Lexer *lexer) switch (peek(lexer)) { case '/': - if (lexer->mode == LEX_DOCS) return; + if (lexer->mode == LEX_CONTRACTS) return; // The '//' case if (peek_next(lexer) == '/') { @@ -259,8 +259,8 @@ static void skip_whitespace(Lexer *lexer) parse_line_comment(lexer); continue; } - // '/*' but not '/**' - if (peek_next(lexer) == '*' && lexer->current[2] != '*') + // '/*' + if (peek_next(lexer) == '*') { skip(lexer, 2); parse_multiline_comment(lexer); @@ -268,8 +268,8 @@ static void skip_whitespace(Lexer *lexer) } return; case '\n': - // Doc lexing sees '\n' as a token. - if (lexer->mode == LEX_DOCS) return; + // Contract lexing sees '\n' as a token. + if (lexer->mode == LEX_CONTRACTS) return; FALLTHROUGH; case ' ': case '\t': @@ -352,7 +352,7 @@ static inline bool scan_ident(Lexer *lexer, TokenType normal, TokenType const_to switch (type) { case TOKEN_RETURN: - if (lexer->mode == LEX_DOCS) type = TOKEN_IDENT; + if (lexer->mode == LEX_CONTRACTS) type = TOKEN_IDENT; break; default: break; @@ -1174,99 +1174,54 @@ INLINE void skip_to_doc_line_end(Lexer *lexer) } -static bool lex_doc_directive(Lexer *lexer) -{ - begin_new_token(lexer); - next(lexer); - // Then our keyword - if (!scan_ident(lexer, TOKEN_AT_IDENT, TOKEN_AT_CONST_IDENT, TOKEN_AT_TYPE_IDENT, '@')) - { - return false; - } - - if (lexer->token_type != TOKEN_AT_IDENT) - { - add_error_token_at_current(lexer, "A doc directive was expected."); - return false; - } - lexer->token_type = TOKEN_DOC_DIRECTIVE; - return true; -} - -static bool scan_doc_line(Lexer *lexer) +/** + * Parse the <* *> directives comments + **/ +static bool parse_doc_start(Lexer *lexer) { - assert(lexer->mode == LEX_DOCS); -RETRY:; - char c = peek(lexer); - // Go through any initial line whitespace - while (c == ' ' || c == '\t') - { - if (reached_end(lexer)) goto EOF_REACHED; - c = next(lexer); - } - // Skip over all stars - while (c == '*') - { - if (reached_end(lexer)) goto EOF_REACHED; - c = next(lexer); - } - // We might have gotten to the end. - if (c == '/' && prev(lexer) == '*') - { - lexer->mode = LEX_NORMAL; - next(lexer); - return new_token(lexer, TOKEN_DOCS_END, "*/"); - } - - // We need to skip any space afterwards - while (c == ' ' || c == '\t') - { - if (reached_end(lexer)) goto EOF_REACHED; - c = next(lexer); - } - - // If we have '@' [_A-Za-z] then parse the directive - if (c == '@') + bool may_have_contract = true; + // Let's loop until we find the end or the contract. + while (!reached_end(lexer)) { - return lex_doc_directive(lexer); - } - - // Otherwise scan to the end of the line - while (1) - { - if (reached_end(lexer)) goto EOF_REACHED; - // We might find the end of the docs - if (c == '*' && peek_next(lexer) == '/') - { - next(lexer); - lexer->mode = LEX_NORMAL; - return new_token(lexer, TOKEN_DOCS_END, "*/"); - } - // If we find the end of the line we start from the beginning. - if (c == '\n') + char c = peek(lexer); + switch (c) { - next(lexer); - goto RETRY; + case '\n': + may_have_contract = true; + next(lexer); + continue; + case ' ': + case '\t': + next(lexer); + continue; + case '*': + // We might have <* Hello *> + if (peek_next(lexer) == '>') goto EXIT; + may_have_contract = false; + next(lexer); + continue; + case '@': + if (may_have_contract && char_is_lower(peek_next(lexer))) + { + // Found a contract + goto EXIT; + } + FALLTHROUGH; + default: + may_have_contract = false; + next(lexer); + continue; } - c = next(lexer); } -EOF_REACHED: - return add_error_token_at_start(lexer, "Missing '*/' to end the doc comment."); -} - - - -/** - * - * Parse the / ** * / directives comments - **/ -static bool parse_doc_start(Lexer *lexer) -{ - // Add the doc start token. - new_token(lexer, TOKEN_DOCS_START, lexer->lexing_start); - skip_to_doc_line_end(lexer); - lexer->mode = LEX_DOCS; - return true; +EXIT:; + // Now we either found: + // 1. "<* foo \n @param" + // 2. "<* foo *>" + // 3. "<* foo " + // + // In any case we can consider this having reached "the contracts" + lexer->mode = LEX_CONTRACTS; + return new_token(lexer, TOKEN_DOCS_START, lexer->lexing_start); } static bool lexer_scan_token_inner(Lexer *lexer) @@ -1284,7 +1239,8 @@ static bool lexer_scan_token_inner(Lexer *lexer) switch (c) { case '\n': - return scan_doc_line(lexer); + assert(lexer->mode == LEX_CONTRACTS); + return new_token(lexer, TOKEN_DOCS_EOL, ""); case '@': if (char_is_letter_(peek(lexer))) { @@ -1341,15 +1297,13 @@ static bool lexer_scan_token_inner(Lexer *lexer) if (match(lexer, '!')) return new_token(lexer, TOKEN_BANGBANG, "!!"); return match(lexer, '=') ? new_token(lexer, TOKEN_NOT_EQUAL, "!=") : new_token(lexer, TOKEN_BANG, "!"); case '/': - // We can't get any directives comments here. - if (lexer->mode != LEX_DOCS && match(lexer, '*')) - { - assert(peek(lexer) == '*'); - next(lexer); - return parse_doc_start(lexer); - } return match(lexer, '=') ? new_token(lexer, TOKEN_DIV_ASSIGN, "/=") : new_token(lexer, TOKEN_DIV, "/"); case '*': + if (lexer->mode == LEX_CONTRACTS && match(lexer, '>')) + { + lexer->mode = LEX_NORMAL; + return new_token(lexer, TOKEN_DOCS_END, "*>"); + } return match(lexer, '=') ? new_token(lexer, TOKEN_MULT_ASSIGN, "*=") : new_token(lexer, TOKEN_STAR, "*"); case '=': if (match(lexer, '>')) return new_token(lexer, TOKEN_IMPLIES, "=>"); @@ -1365,6 +1319,10 @@ static bool lexer_scan_token_inner(Lexer *lexer) if (match(lexer, '=')) return new_token(lexer, TOKEN_SHL_ASSIGN, "<<="); return new_token(lexer, TOKEN_SHL, "<<"); } + if (lexer->mode == LEX_NORMAL && match(lexer, '*')) + { + return parse_doc_start(lexer); + } return match(lexer, '=') ? new_token(lexer, TOKEN_LESS_EQ, "<=") : new_token(lexer, TOKEN_LESS, "<"); case '>': if (match(lexer, '>')) diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index d83cb7793..b1bbe3258 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -930,8 +930,6 @@ void llvm_set_linkonce(GenContext *c, LLVMValueRef global) llvm_set_comdat(c, global); } - - void llvm_value_set_int(GenContext *c, BEValue *value, Type *type, uint64_t i) { llvm_value_set(value, llvm_const_int(c, type, i), type); diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 5f9f67992..7082f5df2 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -5823,7 +5823,7 @@ static LLVMValueRef llvm_emit_dynamic_search(GenContext *c, LLVMValueRef type_id func = c->dyn_find_function = LLVMAddFunction(c->module, ".dyn_search", c->dyn_find_function_type); LLVMSetUnnamedAddress(func, LLVMGlobalUnnamedAddr); - LLVMSetLinkage(func, LLVMWeakODRLinkage); + LLVMSetLinkage(func, LLVMWeakAnyLinkage); llvm_set_comdat(c, func); LLVMBasicBlockRef entry; diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 2008c3529..a05004130 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -2484,6 +2484,13 @@ INLINE void append_docs(AstId **next, AstId *first, Ast *new_doc) *next = &new_doc->next; } +INLINE bool parse_doc_to_eol(ParseContext *c) +{ + if (try_consume(c, TOKEN_DOCS_EOL)) return true; + if (tok_is(c, TOKEN_DOCS_END)) return true; + return false; +} + /** * contract ::= expression_list (':'? STRING)? */ @@ -2644,78 +2651,65 @@ static bool parse_contracts(ParseContext *c, AstId *contracts_ref) if (!try_consume(c, TOKEN_DOCS_START)) return true; AstId **next = &contracts_ref; - uint32_t row_last_row = c->span.row; - while (1) + while (!try_consume(c, TOKEN_DOCS_END)) { - uint32_t row = c->span.row; - // Spin past the lines and line ends - switch (c->tok) + // Skip empty lines. + if (try_consume(c, TOKEN_DOCS_EOL)) continue; + + if (!tok_is(c, TOKEN_AT_IDENT)) + { + PRINT_ERROR_HERE("Expected a directive starting with '@' here, like '@param' or `@require`"); + return false; + } + const char *name = symstr(c); + if (name == kw_at_param) + { + if (!parse_contract_param(c, contracts_ref, next)) return false; + } + else if (name == kw_at_return) { - case TOKEN_DOC_DIRECTIVE: + advance(c); + if (tok_is(c, TOKEN_BANG)) { - const char *name = symstr(c); - if (name == kw_at_param) - { - if (!parse_contract_param(c, contracts_ref, next)) return false; - break; - } - else if (name == kw_at_return) - { - advance(c); - if (tok_is(c, TOKEN_BANG)) - { - if (!parse_doc_optreturn(c, contracts_ref, next)) return false; - break; - } - if (!consume(c, TOKEN_STRING, "Expected a string description.")) return false; - break; - } - else if (name == kw_at_deprecated) - { - advance(c); - (void)try_consume(c, TOKEN_STRING); - REMINDER("Implement @deprecated tracking"); - break; - } - else if (name == kw_at_require) - { - if (!parse_doc_contract(c, contracts_ref, next, CONTRACT_REQUIRE)) return false; - break; - } - else if (name == kw_at_ensure) - { - if (!parse_doc_contract(c, contracts_ref, next, CONTRACT_ENSURE)) return false; - break; - } - else if (name == kw_at_pure) - { - Ast *ast = ast_new_curr(c, AST_CONTRACT); - ast->contract_stmt.kind = CONTRACT_PURE; - append_docs(next, contracts_ref, ast); - advance(c); - break; - } - else - { - advance(c); - // Ignore - break; - } + if (!parse_doc_optreturn(c, contracts_ref, next)) return false; + } + else + { + if (!consume(c, TOKEN_STRING, "Expected a string description.")) return false; } - case TOKEN_DOCS_END: - advance(c); - return true; - default: - if (row_last_row == row) - { - PRINT_ERROR_HERE("Expected end of line."); - return false; - } - PRINT_ERROR_HERE("Expected a directive or a comment."); - return false; } - row_last_row = row; + else if (name == kw_at_deprecated) + { + advance(c); + (void)try_consume(c, TOKEN_STRING); + REMINDER("Implement @deprecated tracking"); + } + else if (name == kw_at_require) + { + if (!parse_doc_contract(c, contracts_ref, next, CONTRACT_REQUIRE)) return false; + } + else if (name == kw_at_ensure) + { + if (!parse_doc_contract(c, contracts_ref, next, CONTRACT_ENSURE)) return false; + } + else if (name == kw_at_pure) + { + Ast *ast = ast_new_curr(c, AST_CONTRACT); + ast->contract_stmt.kind = CONTRACT_PURE; + append_docs(next, contracts_ref, ast); + advance(c); + } + else + { + advance(c); + if (parse_doc_to_eol(c)) continue; + if (!consume(c, TOKEN_STRING, "Expected a string description for the custom contract '%s'.", name)) return false; + } + if (parse_doc_to_eol(c)) continue; + PRINT_ERROR_HERE("Expected end of line here."); + return false; } + return true; } static Decl *parse_include(ParseContext *c) diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index de50bb60f..58a9720f6 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -1462,8 +1462,8 @@ Ast *parse_stmt(ParseContext *c) case TOKEN_EOF: PRINT_ERROR_HERE("Reached the end of the file when expecting a statement."); return poisoned_ast; - case TOKEN_DOC_DIRECTIVE: - PRINT_ERROR_HERE("Unexpectedly encountered doc directives."); + case TOKEN_DOCS_EOL: + PRINT_ERROR_HERE("Unexpectedly reached end of line."); return poisoned_ast; } UNREACHABLE diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index d1e786d68..d0a764d21 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -3017,7 +3017,6 @@ static bool sema_analyse_ensure(SemaContext *context, Ast *directive) static bool sema_analyse_optional_returns(SemaContext *context, Ast *directive) { Ast **returns = NULL; - context->call_env.opt_returns = NULL; FOREACH(Ast *, ret, directive->contract_stmt.faults) { if (ret->contract_fault.resolved) continue; @@ -3045,8 +3044,9 @@ static bool sema_analyse_optional_returns(SemaContext *context, Ast *directive) } } RETURN_SEMA_ERROR(ret, "No fault value '%s' found.", ident); - NEXT:; - vec_add(context->call_env.opt_returns, ret->contract_fault.decl); +NEXT:; + Decl *d = ret->contract_fault.decl; + vec_add(context->call_env.opt_returns, d); } return true; } @@ -3063,6 +3063,7 @@ void sema_append_contract_asserts(AstId assert_first, Ast* compound_stmt) bool sema_analyse_contracts(SemaContext *context, AstId doc, AstId **asserts, SourceSpan call_span, bool *has_ensures) { + context->call_env.opt_returns = NULL; while (doc) { Ast *directive = astptr(doc); diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index 8348f423a..4e240962d 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -324,12 +324,9 @@ const char *token_type_to_string(TokenType type) case TOKEN_UPTR: return "uptr"; case TOKEN_DOCS_START: - return "/**"; + return "<*"; case TOKEN_DOCS_END: - return "*/"; - case TOKEN_DOC_DIRECTIVE: - return "DOC_DIRECTIVE"; - + return "*>"; case TOKEN_CT_ALIGNOF: return "$alignof"; case TOKEN_CT_ANDFN: @@ -416,6 +413,8 @@ const char *token_type_to_string(TokenType type) return "$stringify"; case TOKEN_CT_ECHO: return "$echo"; + case TOKEN_DOCS_EOL: + return ""; case TOKEN_EOF: return "EOF"; diff --git a/test/test_suite/contracts/constant_out.c3 b/test/test_suite/contracts/constant_out.c3 index 9f98a7081..43958ae35 100644 --- a/test/test_suite/contracts/constant_out.c3 +++ b/test/test_suite/contracts/constant_out.c3 @@ -11,9 +11,9 @@ fn void Abc.update(Abc* a, int ab) a.a = ab; } -/** - * @param [out] a - **/ +<* + @param [out] a +*> fn void Abc.update_fail(Abc* a, int ab) { a.a = ab; diff --git a/test/test_suite/contracts/ct_eval_of_ensure.c3 b/test/test_suite/contracts/ct_eval_of_ensure.c3 index 7c8209999..7ff1956ec 100644 --- a/test/test_suite/contracts/ct_eval_of_ensure.c3 +++ b/test/test_suite/contracts/ct_eval_of_ensure.c3 @@ -1,7 +1,7 @@ module test; -/** - * @ensure return > 100 - */ +<* + @ensure return > 100 + *> fn int test(int baz) { return 1; // #error: @ensure "return > 100" violated. diff --git a/test/test_suite/contracts/ensure_unsigned.c3 b/test/test_suite/contracts/ensure_unsigned.c3 index e0bbc1bd6..206524e7b 100644 --- a/test/test_suite/contracts/ensure_unsigned.c3 +++ b/test/test_suite/contracts/ensure_unsigned.c3 @@ -1,8 +1,8 @@ // Check that 0 <= buf is ok. -/** - * @ensure return <= buf.len - */ +<* + @ensure return <= buf.len + *> fn usz foo(char[] buf) { if (buf.len == 0) return 0; // ... return some index into buf diff --git a/test/test_suite/contracts/in_array.c3 b/test/test_suite/contracts/in_array.c3 index e5b88cb59..4ee8c9929 100644 --- a/test/test_suite/contracts/in_array.c3 +++ b/test/test_suite/contracts/in_array.c3 @@ -1,6 +1,6 @@ -/** - * @param [in] x - **/ +<* + @param [in] x +*> fn void test(int* x) { x[1] = 123; // #error: 'in' parameters may not be assigned to diff --git a/test/test_suite/contracts/in_out.c3 b/test/test_suite/contracts/in_out.c3 index 97ca78f7a..52c12af4c 100644 --- a/test/test_suite/contracts/in_out.c3 +++ b/test/test_suite/contracts/in_out.c3 @@ -1,30 +1,22 @@ struct Foo { int x; } -/** - * @param [out] f - **/ +<* @param [out] f *> fn void bar(Foo* f) { f.x = 123; } -/** - * @param [in] f - **/ +<* @param [in] f *> fn void foo(Foo* f) { bar(f); // #error: macro as an 'out' argument } -/** - * @param [in] f - **/ +<* @param [in] f *> fn void foo2(Foo* f) { } -/** - * @param [out] f - **/ +<* @param [out] f *> fn void baz(Foo *f) { foo2(f); // #error: may not be passed into a function diff --git a/test/test_suite/contracts/macro_ensure_static.c3 b/test/test_suite/contracts/macro_ensure_static.c3 index 0f3f92179..bd4368086 100644 --- a/test/test_suite/contracts/macro_ensure_static.c3 +++ b/test/test_suite/contracts/macro_ensure_static.c3 @@ -1,9 +1,7 @@ module debugstuff; -/** - * @ensure return > 0 - **/ +<* @ensure return > 0 *> macro check(int a) { if (a > 0) return 1; diff --git a/test/test_suite/contracts/out_subscript.c3 b/test/test_suite/contracts/out_subscript.c3 index 250491ec2..684ea8d22 100644 --- a/test/test_suite/contracts/out_subscript.c3 +++ b/test/test_suite/contracts/out_subscript.c3 @@ -1,7 +1,7 @@ -/** - * @param [out] z - * @param [out] out_data - **/ +<* + @param [out] z + @param [out] out_data + *> fn void tes2t(char* z, char[] out_data, char[] in_data) { z[0] = 2; z[0] += 1; // #error: 'out' parameters may not be read diff --git a/test/test_suite/contracts/pure.c3 b/test/test_suite/contracts/pure.c3 index 139931e44..6c3e8e662 100644 --- a/test/test_suite/contracts/pure.c3 +++ b/test/test_suite/contracts/pure.c3 @@ -1,8 +1,8 @@ module inlineme; -/** - * @pure - */ +<* + @pure + *> fn void test() { int x = 123; @@ -15,9 +15,7 @@ fn void test2() abc = 1233; } -/** - * @pure - */ +<* @pure *> fn void test3() { abc = 1233; // #error: '@pure' functions may not access globals diff --git a/test/test_suite/contracts/pure_calls.c3 b/test/test_suite/contracts/pure_calls.c3 index 6454bbc97..0430f4887 100644 --- a/test/test_suite/contracts/pure_calls.c3 +++ b/test/test_suite/contracts/pure_calls.c3 @@ -1,8 +1,8 @@ module inlineme; -/** - * @pure - */ +<* + @pure + *> fn void test() { int x = 123; @@ -18,9 +18,7 @@ fn void test2() abc = 1233; } -/** - * @pure - */ +<* @pure *> fn void test3() { } \ No newline at end of file diff --git a/test/test_suite/contracts/simple_test.c3t b/test/test_suite/contracts/simple_test.c3t index 379be7fc9..88e3863b4 100644 --- a/test/test_suite/contracts/simple_test.c3t +++ b/test/test_suite/contracts/simple_test.c3t @@ -1,30 +1,30 @@ // #target: macos-x64 -/** - * @param [inout] foo `test` - * @require baz > 100 `whatever` - * @ensure *foo > 231 -*/ +<* + @param [inout] foo `test` + @require baz > 100 `whatever` + @ensure *foo > 231 +*> fn void test(int *foo, int baz) { *foo = 444; } -/** - * @param [inout] foo `test` - * @require baz > 100 `whatever` - * @ensure return < 200 -*/ +<* + @param [inout] foo `test` + @require baz > 100 `whatever` + @ensure return < 200 +*> fn int test2(int *foo, int baz) { *foo = 444; return baz; } -/** - * @require x > 0 - * @ensure return > 0 - **/ +<* + @require x > 0 + @ensure return > 0 + *> fn int test3(int x) { return x + 1; diff --git a/test/test_suite/debug_symbols/defer_macro.c3t b/test/test_suite/debug_symbols/defer_macro.c3t index aef28657b..df5ae8172 100644 --- a/test/test_suite/debug_symbols/defer_macro.c3t +++ b/test/test_suite/debug_symbols/defer_macro.c3t @@ -557,7 +557,7 @@ declare { ptr, i64 } @arena_scratch_begin(ptr, i64) #0 declare void @arena_scratch_end(ptr, i64) #0 -define weak_odr ptr @.dyn_search(ptr %0, ptr %1) unnamed_addr { +define weak ptr @.dyn_search(ptr %0, ptr %1) unnamed_addr { entry: br label %check diff --git a/test/test_suite/dynamic/inherit_linux.c3t b/test/test_suite/dynamic/inherit_linux.c3t index 79d63b6be..196e856cf 100644 --- a/test/test_suite/dynamic/inherit_linux.c3t +++ b/test/test_suite/dynamic/inherit_linux.c3t @@ -158,7 +158,7 @@ entry: ret i32 0 } -define weak_odr ptr @.dyn_search(ptr %0, ptr %1) unnamed_addr comdat { +define weak ptr @.dyn_search(ptr %0, ptr %1) unnamed_addr comdat { entry: br label %check diff --git a/test/test_suite/dynamic/inherit_macos.c3t b/test/test_suite/dynamic/inherit_macos.c3t index 50f37f0e1..cb62b34df 100644 --- a/test/test_suite/dynamic/inherit_macos.c3t +++ b/test/test_suite/dynamic/inherit_macos.c3t @@ -147,7 +147,7 @@ entry: call void @inherit.main() ret i32 0 } -define weak_odr ptr @.dyn_search(ptr %0, ptr %1) unnamed_addr { +define weak ptr @.dyn_search(ptr %0, ptr %1) unnamed_addr { entry: br label %check diff --git a/test/test_suite/dynamic/overlapping_function_linux.c3t b/test/test_suite/dynamic/overlapping_function_linux.c3t index 6c63cecfa..b2af8b3ca 100644 --- a/test/test_suite/dynamic/overlapping_function_linux.c3t +++ b/test/test_suite/dynamic/overlapping_function_linux.c3t @@ -147,7 +147,7 @@ entry: } -define weak_odr ptr @.dyn_search(ptr %0, ptr %1) unnamed_addr comdat { +define weak ptr @.dyn_search(ptr %0, ptr %1) unnamed_addr comdat { entry: br label %check diff --git a/test/test_suite/dynamic/overlapping_function_macos.c3t b/test/test_suite/dynamic/overlapping_function_macos.c3t index 45841f000..a49c8a18a 100644 --- a/test/test_suite/dynamic/overlapping_function_macos.c3t +++ b/test/test_suite/dynamic/overlapping_function_macos.c3t @@ -145,7 +145,7 @@ entry: ret i32 0 } -define weak_odr ptr @.dyn_search(ptr %0, ptr %1) unnamed_addr { +define weak ptr @.dyn_search(ptr %0, ptr %1) unnamed_addr { entry: br label %check diff --git a/test/test_suite/errors/optional_contracts.c3 b/test/test_suite/errors/optional_contracts.c3 index 9ba764050..7540d47b2 100644 --- a/test/test_suite/errors/optional_contracts.c3 +++ b/test/test_suite/errors/optional_contracts.c3 @@ -10,24 +10,20 @@ fault Foo { XYZ } -/** - * - * @return! Abc.DEF "if x is blurb" - * @return! Foo, Abc.ABC, Abc - * @return! Foo, Abc.ABC - * hello world - **/ +<* + + hello world + @return! Foo, Abc.ABC + *> fn void! abc(int a, int b, int z) { return Abc.ZED?; // #error: This value does not match declared optional returns } -/** - * @return! Abc.DEF "if x is blurb" - * @return! Foo, Abc.ABC, Abc - * @return! Foo, Abc.ABC - * hello world - **/ +<* +hello world + @return! Foo, Abc.ABC + *> macro void! @abc(int a, int b, int z) { return Abc.ZED?; // #error: This value does not match declared optional returns diff --git a/test/test_suite/generic/generic_lambda_complex.c3t b/test/test_suite/generic/generic_lambda_complex.c3t index 298bb3687..385fb44c2 100644 --- a/test/test_suite/generic/generic_lambda_complex.c3t +++ b/test/test_suite/generic/generic_lambda_complex.c3t @@ -1,8 +1,6 @@ // #target: macos-x64 -/** - * @require Type.kindof == STRUCT - **/ +<* @require Type.kindof == STRUCT *> module abc(); import std::io; import std::collections::list; @@ -42,10 +40,10 @@ struct TextTag } } -/** - * @require self.tags.len == 0 "template already initialized" - * @require tag_start != tag_end - **/ +<* + @require self.tags.len == 0 "template already initialized" + @require tag_start != tag_end + *> fn void! TextTemplate.init(&self, String template, String tag_start = "{{", String tag_end = "}}", Allocator using = allocator::heap()) { diff --git a/test/test_suite/lexing/expected_directive.c3 b/test/test_suite/lexing/expected_directive.c3 index 57f71a053..7a9d65515 100644 --- a/test/test_suite/lexing/expected_directive.c3 +++ b/test/test_suite/lexing/expected_directive.c3 @@ -1,4 +1,4 @@ -/** +<* @hello -@param feij > 0 // #error: Expected end of line. -*/ +@param feij > 0 // #error: Expected end of line +*> diff --git a/test/test_suite/switch/switch_in_defer_macro.c3t b/test/test_suite/switch/switch_in_defer_macro.c3t index 72cf41ada..92acf7dfc 100644 --- a/test/test_suite/switch/switch_in_defer_macro.c3t +++ b/test/test_suite/switch/switch_in_defer_macro.c3t @@ -1,10 +1,10 @@ // #target: macos-x64 -/** - * @require Token.kindof == ENUM && $typefrom(Token.inner).kindof == UNSIGNED_INT - * @require $defined(((Token)0).token) - * @require $defined(((Comment)0).start) && $defined(((Comment)0).end) - **/ +<* + @require Token.kindof == ENUM && $typefrom(Token.inner).kindof == UNSIGNED_INT + @require $defined(((Token)0).token) + @require $defined(((Comment)0).start) && $defined(((Comment)0).end) + *> module lexer(); import std::io; import trie; @@ -462,9 +462,9 @@ fn int main(String[] args) io::printn("Hello, World!"); return 0; } -/** - * @require Index.kindof == TypeKind.UNSIGNED_INT - **/ +<* + @require Index.kindof == TypeKind.UNSIGNED_INT + *> module trie(); import std::collections::list; import trie::bitmap; @@ -496,17 +496,17 @@ fn void Trie.init(&self, usz initial_capacity = 8, Allocator using = allocator:: self.nodes.push(TrieNode{}); } -/** - * @require self.nodes.len() > 0 - **/ +<* + @require self.nodes.len() > 0 + *> fn Value! Trie.get(&self, char[] key) { return self.nodes[0].get(self, key); } -/** - * @require self.nodes.len() > 0 - **/ +<* + @require self.nodes.len() > 0 + *> fn Value! Trie.get_best(&self, char[] key) { TrieNode* root = &self.nodes[0]; @@ -514,17 +514,17 @@ fn Value! Trie.get_best(&self, char[] key) return root.get_best(self, key, 0); } -/** - * @require self.nodes.len() > 0 - **/ +<* + @require self.nodes.len() > 0 + *> fn void! Trie.set(&self, char[] key, Value value) { self.nodes[0].set(self, key, value)!!; } -/** - * @require self.nodes.len() > 0 - **/ +<* + @require self.nodes.len() > 0 + *> fn void! Trie.del(&self, char[] key) { if (key.len == 0)