0.6.0: init_new/init_temp removed. LinkedList API rewritten. List "pop" and "remove" function now return Optionals. RingBuffer API rewritten. Allocator interface changed. Deprecated Allocator, DString and mem functions removed. "identity" functions are now constants for Matrix and Complex numbers. @default implementations for interfaces removed. any* => any, same for interfaces. Emit local/private globals as "private" in LLVM, following C "static". Updated enum syntax. Add support [rgba] properties in vectors. Improved checks of aliased "void". Subarray -> slice. Fix of llvm codegen enum check. Improved alignment handling. Add --output-dir #1155. Removed List/Object append. GenericList renamed AnyList. Remove unused "unwrap". Fixes to cond. Optimize output in dead branches. Better checking of operator methods. Disallow any from implementing dynamic methods. Check for operator mismatch. Remove unnecessary bitfield. Remove numbering in --list* commands Old style enum declaration for params/type, but now the type is optional. Add note on #1086. Allow making distinct types out of "void", "typeid", "anyfault" and faults. Remove system linker build options. "Try" expressions must be simple expressions. Add optimized build to Mac tests. Register int. assert(false) only allowed in unused branches or in tests. Compile time failed asserts is a compile time error. Remove current_block_is_target. Bug when assigning an optional from an optional. Remove unused emit_zstring. Simplify phi code. Remove unnecessary unreachable blocks and remove unnecessary current_block NULL assignments. Proper handling of '.' and Win32 '//server' paths. Add "no discard" to expression blocks with a return value. Detect "unsigned >= 0" as errors. Fix issue with distinct void as a member #1147. Improve callstack debug information #1184. Fix issue with absolute output-dir paths. Lambdas were not type checked thoroughly #1185. Fix compilation warning #1187. Request jump table using @jump for switches. Path normalization - fix possible null terminator out of bounds. Improved error messages on inlined macros.

Upgrade of mingw in CI. Fix problems using reflection on interface types #1203. Improved debug information on defer. $foreach doesn't create an implicit syntactic scope.
Error if `@if` depends on `@if`. Updated Linux stacktrace. Fix of default argument stacktrace. Allow linking libraries directly by file path. Improve inlining warning messages. Added `index_of_char_from`. Compiler crash using enum nameof from different module #1205. Removed unused fields in find_msvc. Use vswhere to find msvc. Update tests for LLVM 19
This commit is contained in:
Christoffer Lerno
2024-02-23 00:18:43 +01:00
parent 321c5ec756
commit e293c435af
271 changed files with 7608 additions and 6181 deletions

View File

@@ -2,7 +2,7 @@ name: CI
on:
push:
branches: [ master, dev, ci_testing ]
branches: [ master, dev, ci_testing, experiments ]
pull_request:
branches: [ master ]
@@ -33,9 +33,9 @@ jobs:
- name: Compile and run some examples
run: |
cd resources
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\hello_world_many.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\time.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\fannkuch-redux.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run --print-linking examples\hello_world_many.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run --print-linking examples\time.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run --print-linking examples\fannkuch-redux.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\contextfree\boolerr.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\ls.c3
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\load_world.c3
@@ -122,11 +122,11 @@ jobs:
- name: Compile and run some examples
run: |
cd resources
../build/c3c compile-run examples/hello_world_many.c3
../build/c3c compile-run examples/time.c3
../build/c3c compile-run examples/fannkuch-redux.c3
../build/c3c compile-run examples/contextfree/boolerr.c3
../build/c3c compile-run examples/load_world.c3
../build/c3c compile-run --print-linking examples/hello_world_many.c3
../build/c3c compile-run --print-linking examples/time.c3
../build/c3c compile-run --print-linking examples/fannkuch-redux.c3
../build/c3c compile-run --print-linking examples/contextfree/boolerr.c3
../build/c3c compile-run --print-linking examples/load_world.c3
../build/c3c compile --test -g -O0 --threads 1 --target macos-x64 examples/constants.c3
- name: Build testproject
@@ -293,7 +293,7 @@ jobs:
../build/c3c compile-run examples/load_world.c3
../build/c3c compile-run examples/process.c3
../build/c3c compile-run examples/ls.c3
../build/c3c compile-run --system-linker=no linux_stack.c3
../build/c3c compile-run --linker=builtin linux_stack.c3
../build/c3c compile-run linux_stack.c3
- name: Compile run unit tests
@@ -309,7 +309,7 @@ jobs:
- name: Build testproject direct linker
run: |
cd resources/testproject
../../build/c3c run --debug-log --system-linker=no
../../build/c3c run --debug-log --linker=builtin
- name: run compiler tests
run: |
@@ -400,7 +400,7 @@ jobs:
../build/c3c compile-run examples/factorial_macro.c3
../build/c3c compile-run examples/fasta.c3
../build/c3c compile-run examples/process.c3
../build/c3c compile-run --system-linker=no linux_stack.c3
../build/c3c compile-run --linker=builtin linux_stack.c3
../build/c3c compile-run linux_stack.c3
- name: Compile run unit tests
@@ -416,7 +416,7 @@ jobs:
- name: Build testproject direct linker
run: |
cd resources/testproject
../../build/c3c run --debug-log --system-linker=no
../../build/c3c run --debug-log --linker=builtin
- name: run compiler tests
run: |
@@ -474,6 +474,7 @@ jobs:
../build/c3c compile-run examples/contextfree/boolerr.c3
../build/c3c compile-run examples/process.c3
../build/c3c compile-run examples/load_world.c3
../build/c3c compile-run -O5 examples/load_world.c3
- name: Compile run unit tests
run: |
@@ -488,7 +489,7 @@ jobs:
- name: Build testproject direct linker
run: |
cd resources/testproject
../../build/c3c run --debug-log --system-linker=no
../../build/c3c run --debug-log --linker=builtin
- name: Build testproject lib
run: |

View File

@@ -122,7 +122,7 @@ fn void main()
- No mandatory header files
- New semantic macro system
- Module based name spacing
- Subarrays (slices)
- Slices
- Compile time reflection
- Enhanced compile time execution
- Generics based on generic modules
@@ -212,6 +212,8 @@ More platforms will be supported in the future.
3. Unzip executable and standard lib.
4. Run `./c3c`.
(*Note that there is a known issue with debug symbol generation on MacOS 13, see issue #1086)
#### Installing on Arch Linux
There is an AUR package for the c3c compiler : [c3c-git](https://aur.archlinux.org/packages/c3c-git).

View File

@@ -124,7 +124,7 @@ macro @atomic_exec(#func, data, value, ordering) @local
case RELEASE: return #func(data, value, RELEASE);
case ACQUIRE_RELEASE: return #func(data, value, ACQUIRE_RELEASE);
case SEQ_CONSISTENT: return #func(data, value, SEQ_CONSISTENT);
default: assert(false, "Ordering may not be non-atomic or unordered.");
default: unreachable("Ordering may not be non-atomic or unordered.");
}
}

View File

@@ -9,7 +9,7 @@ macro @__atomic_compare_exchange_ordering_failure(ptr, expected, desired, $succe
case AtomicOrdering.RELAXED.ordinal: return $$compare_exchange(ptr, expected, desired, false, false, $success, AtomicOrdering.RELAXED.ordinal, $alignment);
case AtomicOrdering.ACQUIRE.ordinal: return $$compare_exchange(ptr, expected, desired, false, false, $success, AtomicOrdering.ACQUIRE.ordinal, $alignment);
case AtomicOrdering.SEQ_CONSISTENT.ordinal: return $$compare_exchange(ptr, expected, desired, false, false, $success, AtomicOrdering.SEQ_CONSISTENT.ordinal, $alignment);
default: assert(false, "Unrecognized failure ordering");
default: unreachable("Unrecognized failure ordering");
}
return 0;
}
@@ -23,12 +23,12 @@ macro @__atomic_compare_exchange_ordering_success(ptr, expected, desired, succes
case AtomicOrdering.RELEASE.ordinal: return @__atomic_compare_exchange_ordering_failure(ptr, expected, desired, AtomicOrdering.RELEASE.ordinal, failure, $alignment);
case AtomicOrdering.ACQUIRE_RELEASE.ordinal: return @__atomic_compare_exchange_ordering_failure(ptr, expected, desired, AtomicOrdering.ACQUIRE_RELEASE.ordinal, failure, $alignment);
case AtomicOrdering.SEQ_CONSISTENT.ordinal: return @__atomic_compare_exchange_ordering_failure(ptr, expected, desired, AtomicOrdering.SEQ_CONSISTENT.ordinal, failure, $alignment);
default: assert(false, "Unrecognized success ordering");
default: unreachable("Unrecognized success ordering");
}
return 0;
}
fn CInt __atomic_compare_exchange(CInt size, any* ptr, any* expected, any* desired, CInt success, CInt failure) @extern("__atomic_compare_exchange") @export
fn CInt __atomic_compare_exchange(CInt size, any ptr, any expected, any desired, CInt success, CInt failure) @extern("__atomic_compare_exchange") @export
{
switch (size)
{
@@ -57,7 +57,7 @@ fn CInt __atomic_compare_exchange(CInt size, any* ptr, any* expected, any* desir
nextcase;
$endif
default:
assert(false, "Unsuported size (%d) for atomic_compare_exchange", size);
unreachable("Unsuported size (%d) for atomic_compare_exchange", size);
}
return 0;
}

View File

@@ -1,18 +1,18 @@
// Copyright (c) 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.
module std::collections::generic_list;
module std::collections::anylist;
import std::io,std::math;
def GenericPredicate = fn bool(any* value);
def GenericTest = fn bool(any* type, any* context);
def AnyPredicate = fn bool(any value);
def AnyTest = fn bool(any type, any context);
struct GenericList (Printable)
struct AnyList (Printable)
{
usz size;
usz capacity;
Allocator* allocator;
any** entries;
Allocator allocator;
any* entries;
}
@@ -20,14 +20,14 @@ struct GenericList (Printable)
* @param initial_capacity "The initial capacity to reserve"
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
**/
fn GenericList* GenericList.new_init(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap())
fn AnyList* AnyList.new_init(&self, usz initial_capacity = 16, Allocator allocator = allocator::heap())
{
self.allocator = allocator;
self.size = 0;
if (initial_capacity > 0)
{
initial_capacity = math::next_power_of_2(initial_capacity);
self.entries = allocator::alloc_array(allocator, any*, initial_capacity);
self.entries = allocator::alloc_array(allocator, any, initial_capacity);
}
else
{
@@ -37,26 +37,17 @@ fn GenericList* GenericList.new_init(&self, usz initial_capacity = 16, Allocator
return self;
}
/**
* @param initial_capacity "The initial capacity to reserve"
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
**/
fn GenericList* GenericList.init_new(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
{
return self.new_init(initial_capacity, allocator) @inline;
}
/**
* Initialize the list using the temp allocator.
*
* @param initial_capacity "The initial capacity to reserve"
**/
fn GenericList* GenericList.temp_init(&self, usz initial_capacity = 16)
fn AnyList* AnyList.temp_init(&self, usz initial_capacity = 16)
{
return self.new_init(initial_capacity, allocator::temp()) @inline;
}
fn usz! GenericList.to_format(&self, Formatter* formatter) @dynamic
fn usz! AnyList.to_format(&self, Formatter* formatter) @dynamic
{
switch (self.size)
{
@@ -76,12 +67,12 @@ fn usz! GenericList.to_format(&self, Formatter* formatter) @dynamic
}
}
fn String GenericList.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic
fn String AnyList.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
{
return string::new_format("%s", *self, .allocator = allocator);
}
fn String GenericList.to_tstring(&self)
fn String AnyList.to_tstring(&self)
{
return string::tformat("%s", *self);
}
@@ -89,13 +80,13 @@ fn String GenericList.to_tstring(&self)
/**
* Push an element on the list by cloning it.
**/
macro void GenericList.push(&self, element)
macro void AnyList.push(&self, element)
{
if (!self.allocator) self.allocator = allocator::heap();
self.append_internal(allocator::clone(self.allocator, element));
}
fn void GenericList.append_internal(&self, any* element) @local
fn void AnyList.append_internal(&self, any element) @local
{
self.ensure_capacity();
self.entries[self.size++] = element;
@@ -104,7 +95,7 @@ fn void GenericList.append_internal(&self, any* element) @local
/**
* Free a retained element removed using *_retained.
**/
fn void GenericList.free_element(&self, any* element) @inline
fn void AnyList.free_element(&self, any element) @inline
{
allocator::free(self.allocator, element.ptr);
}
@@ -115,7 +106,7 @@ fn void GenericList.free_element(&self, any* element) @inline
*
* @return! CastResult.TYPE_MISMATCH, IteratorResult.NO_MORE_ELEMENT
**/
macro GenericList.pop(&self, $Type)
macro AnyList.pop(&self, $Type)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
defer self.free_element(self.entries[self.size]);
@@ -126,7 +117,7 @@ macro GenericList.pop(&self, $Type)
* Pop the last value and allocate the copy using the given allocator.
* @return! IteratorResult.NO_MORE_ELEMENT
**/
fn any*! GenericList.new_pop(&self, Allocator* allocator = allocator::heap())
fn any! AnyList.new_pop(&self, Allocator allocator = allocator::heap())
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
defer self.free_element(self.entries[self.size]);
@@ -137,19 +128,19 @@ fn any*! GenericList.new_pop(&self, Allocator* allocator = allocator::heap())
* Pop the last value and allocate the copy using the temp allocator
* @return! IteratorResult.NO_MORE_ELEMENT
**/
fn any*! GenericList.temp_pop(&self) => self.new_pop(allocator::temp());
fn any! AnyList.temp_pop(&self) => self.new_pop(allocator::temp());
/**
* Pop the last value. It must later be released using list.free_element()
* @return! IteratorResult.NO_MORE_ELEMENT
**/
fn any*! GenericList.pop_retained(&self)
fn any! AnyList.pop_retained(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
return self.entries[--self.size];
}
fn void GenericList.clear(&self)
fn void AnyList.clear(&self)
{
for (usz i = 0; i < self.size; i++)
{
@@ -161,7 +152,7 @@ fn void GenericList.clear(&self)
/**
* Same as pop() but pops the first value instead.
**/
macro GenericList.pop_first(&self, $Type)
macro AnyList.pop_first(&self, $Type)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
defer self.remove_at(0);
@@ -171,7 +162,7 @@ macro GenericList.pop_first(&self, $Type)
/**
* Same as pop_retained() but pops the first value instead.
**/
fn any*! GenericList.pop_first_retained(&self)
fn any! AnyList.pop_first_retained(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
defer self.remove_at(0);
@@ -181,7 +172,7 @@ fn any*! GenericList.pop_first_retained(&self)
/**
* Same as new_pop() but pops the first value instead.
**/
fn any*! GenericList.new_pop_first(&self, Allocator* allocator = allocator::heap())
fn any! AnyList.new_pop_first(&self, Allocator allocator = allocator::heap())
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
defer self.free_element(self.entries[self.size]);
@@ -192,19 +183,19 @@ fn any*! GenericList.new_pop_first(&self, Allocator* allocator = allocator::heap
/**
* Same as temp_pop() but pops the first value instead.
**/
fn any*! GenericList.temp_pop_first(&self) => self.new_pop_first(allocator::temp());
fn any! AnyList.temp_pop_first(&self) => self.new_pop_first(allocator::temp());
/**
* @require index < self.size
**/
fn void GenericList.remove_at(&self, usz index)
fn void AnyList.remove_at(&self, usz index)
{
if (!--self.size || index == self.size) return;
self.free_element(self.entries[index]);
self.entries[index .. self.size - 1] = self.entries[index + 1 .. self.size];
}
fn void GenericList.add_all(&self, GenericList* other_list)
fn void AnyList.add_all(&self, AnyList* other_list)
{
if (!other_list.size) return;
self.reserve(other_list.size);
@@ -217,7 +208,7 @@ fn void GenericList.add_all(&self, GenericList* other_list)
/**
* Reverse the elements in a list.
**/
fn void GenericList.reverse(&self)
fn void AnyList.reverse(&self)
{
if (self.size < 2) return;
usz half = self.size / 2U;
@@ -228,7 +219,7 @@ fn void GenericList.reverse(&self)
}
}
fn any*[] GenericList.array_view(&self)
fn any[] AnyList.array_view(&self)
{
return self.entries[:self.size];
}
@@ -236,7 +227,7 @@ fn any*[] GenericList.array_view(&self)
/**
* Push an element to the front of the list.
**/
macro void GenericList.push_front(&self, type)
macro void AnyList.push_front(&self, type)
{
self.insert_at(0, type);
}
@@ -244,16 +235,16 @@ macro void GenericList.push_front(&self, type)
/**
* @require index < self.size
**/
macro void GenericList.insert_at(&self, usz index, type) @local
macro void AnyList.insert_at(&self, usz index, type) @local
{
any* value = allocator::copy(self.allocator, type);
any value = allocator::copy(self.allocator, type);
self.insert_at_internal(self, index, value);
}
/**
* @require index < self.size
**/
fn void GenericList.insert_at_internal(&self, usz index, any* value) @local
fn void AnyList.insert_at_internal(&self, usz index, any value) @local
{
self.ensure_capacity();
for (usz i = self.size; i > index; i--)
@@ -268,7 +259,7 @@ fn void GenericList.insert_at_internal(&self, usz index, any* value) @local
/**
* @require self.size > 0
**/
fn void GenericList.remove_last(&self)
fn void AnyList.remove_last(&self)
{
self.free_element(self.entries[--self.size]);
}
@@ -276,37 +267,37 @@ fn void GenericList.remove_last(&self)
/**
* @require self.size > 0
**/
fn void GenericList.remove_first(&self)
fn void AnyList.remove_first(&self)
{
self.remove_at(0);
}
macro GenericList.first(&self, $Type)
macro AnyList.first(&self, $Type)
{
return *anycast(self.first_any(), $Type);
}
fn any*! GenericList.first_any(&self) @inline
fn any! AnyList.first_any(&self) @inline
{
return self.size ? self.entries[0] : IteratorResult.NO_MORE_ELEMENT?;
}
macro GenericList.last(&self, $Type)
macro AnyList.last(&self, $Type)
{
return *anycast(self.last_any(), $Type);
}
fn any*! GenericList.last_any(&self) @inline
fn any! AnyList.last_any(&self) @inline
{
return self.size ? self.entries[self.size - 1] : IteratorResult.NO_MORE_ELEMENT?;
}
fn bool GenericList.is_empty(&self) @inline
fn bool AnyList.is_empty(&self) @inline
{
return !self.size;
}
fn usz GenericList.len(&self) @operator(len) @inline
fn usz AnyList.len(&self) @operator(len) @inline
{
return self.size;
}
@@ -314,7 +305,7 @@ fn usz GenericList.len(&self) @operator(len) @inline
/**
* @require index < self.size "Index out of range"
**/
macro GenericList.get(&self, usz index, $Type)
macro AnyList.get(&self, usz index, $Type)
{
return *anycast(self.entries[index], $Type);
}
@@ -322,12 +313,12 @@ macro GenericList.get(&self, usz index, $Type)
/**
* @require index < self.size "Index out of range"
**/
fn any* GenericList.get_any(&self, usz index) @inline
fn any AnyList.get_any(&self, usz index) @inline
{
return self.entries[index];
}
fn void GenericList.free(&self)
fn void AnyList.free(&self)
{
if (!self.allocator) return;
self.clear();
@@ -336,9 +327,9 @@ fn void GenericList.free(&self)
self.entries = null;
}
fn void GenericList.swap(&self, usz i, usz j)
fn void AnyList.swap(&self, usz i, usz j)
{
any* temp = self.entries[i];
any temp = self.entries[i];
self.entries[i] = self.entries[j];
self.entries[j] = temp;
}
@@ -347,7 +338,7 @@ fn void GenericList.swap(&self, usz i, usz j)
* @param filter "The function to determine if it should be removed or not"
* @return "the number of deleted elements"
**/
fn usz GenericList.remove_if(&self, GenericPredicate filter)
fn usz AnyList.remove_if(&self, AnyPredicate filter)
{
return self._remove_if(filter, false);
}
@@ -356,12 +347,12 @@ fn usz GenericList.remove_if(&self, GenericPredicate filter)
* @param selection "The function to determine if it should be kept or not"
* @return "the number of deleted elements"
**/
fn usz GenericList.retain_if(&self, GenericPredicate selection)
fn usz AnyList.retain_if(&self, AnyPredicate selection)
{
return self._remove_if(selection, true);
}
macro usz GenericList._remove_if(&self, GenericPredicate filter, bool $invert) @local
macro usz AnyList._remove_if(&self, AnyPredicate filter, bool $invert) @local
{
usz size = self.size;
for (usz i = size, usz k = size; k > 0; k = i)
@@ -387,17 +378,17 @@ macro usz GenericList._remove_if(&self, GenericPredicate filter, bool $invert) @
return size - self.size;
}
fn usz GenericList.remove_using_test(&self, GenericTest filter, any* context)
fn usz AnyList.remove_using_test(&self, AnyTest filter, any context)
{
return self._remove_using_test(filter, false, context);
}
fn usz GenericList.retain_using_test(&self, GenericTest filter, any* context)
fn usz AnyList.retain_using_test(&self, AnyTest filter, any context)
{
return self._remove_using_test(filter, true, context);
}
macro usz GenericList._remove_using_test(&self, GenericTest filter, bool $invert, ctx) @local
macro usz AnyList._remove_using_test(&self, AnyTest filter, bool $invert, ctx) @local
{
usz size = self.size;
for (usz i = size, usz k = size; k > 0; k = i)
@@ -426,17 +417,17 @@ macro usz GenericList._remove_using_test(&self, GenericTest filter, bool $invert
/**
* Reserve at least min_capacity
**/
fn void GenericList.reserve(&self, usz min_capacity)
fn void AnyList.reserve(&self, usz min_capacity)
{
if (!min_capacity) return;
if (self.capacity >= min_capacity) return;
if (!self.allocator) self.allocator = allocator::heap();
min_capacity = math::next_power_of_2(min_capacity);
self.entries = allocator::realloc(self.allocator, self.entries, any*.sizeof * min_capacity);
self.entries = allocator::realloc(self.allocator, self.entries, any.sizeof * min_capacity);
self.capacity = min_capacity;
}
macro any* GenericList.@item_at(&self, usz index) @operator([])
macro any AnyList.@item_at(&self, usz index) @operator([])
{
return self.entries[index];
}
@@ -444,7 +435,7 @@ macro any* GenericList.@item_at(&self, usz index) @operator([])
/**
* @require index <= self.size "Index out of range"
**/
macro void GenericList.set(&self, usz index, value)
macro void AnyList.set(&self, usz index, value)
{
if (index == self.size)
{
@@ -455,7 +446,7 @@ macro void GenericList.set(&self, usz index, value)
self.entries[index] = allocator::copy(self.allocator, value);
}
fn void GenericList.ensure_capacity(&self, usz added = 1) @inline @private
fn void AnyList.ensure_capacity(&self, usz added = 1) @inline @private
{
usz new_size = self.size + added;
if (self.capacity >= new_size) return;

View File

@@ -86,31 +86,17 @@ struct GrowableBitSet
* @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())
fn GrowableBitSet* GrowableBitSet.new_init(&self, usz initial_capacity = 1, Allocator allocator = allocator::heap())
{
self.data.new_init(initial_capacity, allocator);
return self;
}
/**
* @param initial_capacity
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
**/
fn GrowableBitSet* GrowableBitSet.init_new(&self, usz initial_capacity = 1, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
{
return self.new_init(initial_capacity, allocator) @inline;
}
fn GrowableBitSet* GrowableBitSet.temp_init(&self, usz initial_capacity = 1)
{
return self.new_init(initial_capacity, allocator::temp()) @inline;
}
fn GrowableBitSet* GrowableBitSet.init_temp(&self, usz initial_capacity = 1) @deprecated("Replaced by temp_init")
{
return self.temp_init(initial_capacity);
}
fn void GrowableBitSet.free(&self)
{
self.data.free();

View File

@@ -25,7 +25,7 @@ fn usz! EnumMap.to_format(&self, Formatter* formatter) @dynamic
return n;
}
fn String EnumMap.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic
fn String EnumMap.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
{
return string::new_format("%s", *self, .allocator = allocator);
}

View File

@@ -141,7 +141,7 @@ fn usz! EnumSet.to_format(&set, Formatter* formatter) @dynamic
return n;
}
fn String EnumSet.to_new_string(&set, Allocator* allocator = allocator::heap()) @dynamic
fn String EnumSet.to_new_string(&set, Allocator allocator = allocator::heap()) @dynamic
{
return string::new_format("%s", *set, .allocator = allocator);
}

View File

@@ -3,6 +3,8 @@
// a copy of which can be found in the LICENSE_STDLIB file.
module std::collections::linkedlist(<Type>);
const ELEMENT_IS_EQUATABLE = types::is_equatable_type(Type);
struct Node @private
{
Node *next;
@@ -12,51 +14,28 @@ struct Node @private
struct LinkedList
{
Allocator *allocator;
Allocator allocator;
usz size;
Node *_first;
Node *_last;
}
fn void LinkedList.push(&self, Type value)
{
self.link_first(value);
}
fn void LinkedList.push_last(&self, Type value)
{
self.link_last(value);
}
/**
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
* @return "the initialized list"
**/
fn LinkedList* LinkedList.new_init(&self, Allocator* allocator = allocator::heap())
fn LinkedList* LinkedList.new_init(&self, Allocator allocator = allocator::heap())
{
*self = { .allocator = allocator };
return self;
}
/**
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
* @return "the initialized list"
**/
fn LinkedList* LinkedList.init_new(&self, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
{
return self.new_init(allocator);
}
fn LinkedList* LinkedList.temp_init(&self)
{
return self.new_init(allocator::temp()) @inline;
}
fn LinkedList* LinkedList.init_temp(&self) @deprecated("Replaced by temp_init")
{
return self.temp_init() @inline;
}
/**
* @require self.allocator
**/
@@ -71,7 +50,7 @@ macro Node* LinkedList.alloc_node(&self) @private
return allocator::alloc(self.allocator, Node);
}
fn void LinkedList.link_first(&self, Type value) @private
fn void LinkedList.push_front(&self, Type value)
{
Node *first = self._first;
Node *new_node = self.alloc_node();
@@ -88,7 +67,7 @@ fn void LinkedList.link_first(&self, Type value) @private
self.size++;
}
fn void LinkedList.link_last(&self, Type value) @private
fn void LinkedList.push(&self, Type value)
{
Node *last = self._last;
Node *new_node = self.alloc_node();
@@ -172,7 +151,7 @@ fn void LinkedList.set(&self, usz index, Type element)
/**
* @require index < self.size
**/
fn void LinkedList.remove(&self, usz index)
fn void LinkedList.remove_at(&self, usz index)
{
self.unlink(self.node_at_index(index));
}
@@ -180,14 +159,14 @@ fn void LinkedList.remove(&self, usz index)
/**
* @require index <= self.size
**/
fn void LinkedList.insert(&self, usz index, Type element)
fn void LinkedList.insert_at(&self, usz index, Type element)
{
switch (index)
{
case 0:
self.push(element);
self.push_front(element);
case self.size:
self.push_last(element);
self.push(element);
default:
self.link_before(self.node_at_index(index), element);
}
@@ -232,7 +211,53 @@ fn void LinkedList.unlink_first(&self) @private
self.size--;
}
fn bool LinkedList.remove_value(&self, Type t)
fn usz LinkedList.remove(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
{
usz start = self.size;
Node* node = self._first;
while (node)
{
switch
{
case equals(node.value, t):
Node* next = node.next;
self.unlink(node);
node = next;
default:
node = node.next;
}
}
return start - self.size;
}
fn Type! LinkedList.pop(&self)
{
if (!self._last) return IteratorResult.NO_MORE_ELEMENT?;
defer self.unlink_last();
return self._last.value;
}
fn Type! LinkedList.pop_front(&self)
{
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
defer self.unlink_first();
return self._first.value;
}
fn void! LinkedList.remove_last(&self) @maydiscard
{
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
self.unlink_last();
}
fn void! LinkedList.remove_first(&self) @maydiscard
{
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
self.unlink_first();
}
fn bool LinkedList.remove_first_match(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
{
for (Node* node = self._first; node != null; node = node.next)
{
@@ -245,7 +270,7 @@ fn bool LinkedList.remove_value(&self, Type t)
return false;
}
fn bool LinkedList.remove_last_value(&self, Type t)
fn bool LinkedList.remove_last_match(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
{
for (Node* node = self._last; node != null; node = node.prev)
{
@@ -257,26 +282,6 @@ fn bool LinkedList.remove_last_value(&self, Type t)
}
return false;
}
fn Type! LinkedList.pop(&self)
{
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
defer self.unlink_first();
return self._first.value;
}
fn void! LinkedList.remove_last(&self)
{
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
self.unlink_last();
}
fn void! LinkedList.remove_first(&self)
{
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
self.unlink_first();
}
/**
* @require self._last
**/

View File

@@ -5,7 +5,7 @@ module std::collections::list(<Type>);
import std::io,std::math;
def ElementPredicate = fn bool(Type *type);
def ElementTest = fn bool(Type *type, any* context);
def ElementTest = fn bool(Type *type, any context);
const ELEMENT_IS_EQUATABLE = types::is_equatable_type(Type);
const ELEMENT_IS_POINTER = Type.kindof == POINTER;
@@ -13,7 +13,7 @@ struct List (Printable)
{
usz size;
usz capacity;
Allocator *allocator;
Allocator allocator;
Type *entries;
}
@@ -22,7 +22,7 @@ struct List (Printable)
* @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())
fn List* List.new_init(&self, usz initial_capacity = 16, Allocator allocator = allocator::heap())
{
self.allocator = allocator;
self.size = 0;
@@ -39,15 +39,6 @@ fn List* List.new_init(&self, usz initial_capacity = 16, Allocator* allocator =
return self;
}
/**
* @param initial_capacity "The initial capacity to reserve"
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
**/
fn List* List.init_new(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
{
return self.new_init(initial_capacity, allocator) @inline;
}
/**
* Initialize the list using the temp allocator.
*
@@ -58,20 +49,10 @@ fn List* List.temp_init(&self, usz initial_capacity = 16)
return self.new_init(initial_capacity, allocator::temp()) @inline;
}
/**
* Initialize the list using the temp allocator.
*
* @param initial_capacity "The initial capacity to reserve"
**/
fn List* List.init_temp(&self, usz initial_capacity = 16) @deprecated("Replaced by temp_init")
{
return self.temp_init(initial_capacity) @inline;
}
/**
* @require self.size == 0 "The List must be empty"
**/
fn void List.init_wrapping_array(&self, Type[] types, Allocator* allocator = allocator::heap())
fn void List.init_wrapping_array(&self, Type[] types, Allocator allocator = allocator::heap())
{
self.allocator = allocator;
self.size = types.len;
@@ -99,7 +80,7 @@ fn usz! List.to_format(&self, Formatter* formatter) @dynamic
}
}
fn String List.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic
fn String List.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
{
return string::new_format("%s", *self, .allocator = allocator);
}
@@ -110,21 +91,14 @@ fn String List.to_tstring(&self)
}
fn void List.push(&self, Type element) @inline
{
self.append(element);
}
fn void List.append(&self, Type element)
{
self.ensure_capacity();
self.entries[self.size++] = element;
self.entries[self.size++] = element;
}
/**
* @require self.size > 0
**/
fn Type List.pop(&self)
fn Type! List.pop(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
return self.entries[--self.size];
}
@@ -136,11 +110,11 @@ fn void List.clear(&self)
/**
* @require self.size > 0
**/
fn Type List.pop_first(&self)
fn Type! List.pop_first(&self)
{
Type value = self.entries[0];
self.remove_at(0);
return value;
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
defer self.remove_at(0);
return self.entries[0];
}
/**
@@ -163,7 +137,7 @@ fn void List.add_all(&self, List* other_list)
}
fn Type[] List.to_new_array(&self, Allocator* allocator = allocator::heap())
fn Type[] List.to_new_array(&self, Allocator allocator = allocator::heap())
{
if (!self.size) return Type[] {};
Type[] result = allocator::alloc_array(allocator, Type, self.size);
@@ -232,30 +206,28 @@ fn void List.set_at(&self, usz index, Type type)
self.entries[index] = type;
}
/**
* @require self.size > 0
**/
fn void List.remove_last(&self)
fn void! List.remove_last(&self) @maydiscard
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
self.size--;
}
/**
* @require self.size > 0
**/
fn void List.remove_first(&self)
fn void! List.remove_first(&self) @maydiscard
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
self.remove_at(0);
}
fn Type* List.first(&self)
fn Type! List.first(&self)
{
return self.size ? &self.entries[0] : null;
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
return self.entries[0];
}
fn Type* List.last(&self)
fn Type! List.last(&self)
{
return self.size ? &self.entries[self.size - 1] : null;
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
return self.entries[self.size - 1];
}
fn bool List.is_empty(&self) @inline
@@ -335,12 +307,12 @@ macro usz List._remove_if(&self, ElementPredicate filter, bool $invert) @local
return size - self.size;
}
fn usz List.remove_using_test(&self, ElementTest filter, any* context)
fn usz List.remove_using_test(&self, ElementTest filter, any context)
{
return self._remove_using_test(filter, false, context);
}
fn usz List.retain_using_test(&self, ElementTest filter, any* context)
fn usz List.retain_using_test(&self, ElementTest filter, any context)
{
return self._remove_using_test(filter, true, context);
}
@@ -457,18 +429,38 @@ fn bool List.contains(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
}
/**
* @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)
{
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"
**/
fn bool List.remove_first_match(&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."
**/
fn usz List.remove(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
fn usz List.remove_all_matches(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
{
usz size = self.size;
for (usz i = size; i > 0; i--)
{
if (!equals(self.entries[i - 1], value)) continue;
for (usz j = i; j < size; j++)
for (usz j = i; j < self.size; j++)
{
self.entries[j - 1] = self.entries[j];
}
@@ -477,10 +469,10 @@ fn usz List.remove(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
return size - self.size;
}
fn void List.remove_all(&self, List* other_list) @if(ELEMENT_IS_EQUATABLE)
fn void List.remove_all_from(&self, List* other_list) @if(ELEMENT_IS_EQUATABLE)
{
if (!other_list.size) return;
foreach (v : other_list) self.remove(v);
foreach (v : other_list) self.remove_all_matches(v);
}
/**

View File

@@ -13,7 +13,7 @@ const bool COPY_KEYS = types::implements_copy(Key);
struct HashMap
{
Entry*[] table;
Allocator* allocator;
Allocator allocator;
uint count; // Number of elements
uint threshold; // Resize limit
float load_factor;
@@ -26,7 +26,7 @@ struct HashMap
* @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 = allocator::heap())
fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
capacity = math::next_power_of_2(capacity);
self.allocator = allocator;
@@ -36,18 +36,6 @@ fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, fl
return self;
}
/**
* @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 !map.allocator "Map was already initialized"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
fn HashMap* HashMap.init_new(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
{
return map.new_init(capacity, load_factor, allocator);
}
/**
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
@@ -59,16 +47,6 @@ fn HashMap* HashMap.temp_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, f
return self.new_init(capacity, load_factor, allocator::temp()) @inline;
}
/**
* @require capacity > 0 "The capacity must be 1 or higher"
* @require load_factor > 0.0 "The load factor must be higher than 0"
* @require !map.allocator "Map was already initialized"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
fn HashMap* HashMap.init_temp(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR) @deprecated("Replaced by temp_init")
{
return map.temp_init(capacity, load_factor) @inline;
}
/**
* Has this hash map been initialized yet?
@@ -85,23 +63,13 @@ fn bool HashMap.is_initialized(&map)
* @param [&inout] allocator "The allocator to use"
* @param [&in] other_map "The map to copy from."
**/
fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map, Allocator* allocator = allocator::heap())
fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map, Allocator allocator = allocator::heap())
{
self.new_init(other_map.table.len, other_map.load_factor, allocator);
self.put_all_for_create(other_map);
return self;
}
/**
* @param [&inout] allocator "The allocator to use"
* @param [&in] other_map "The map to copy from."
**/
fn HashMap* HashMap.init_new_from_map(&self, HashMap* other_map, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init_from_map")
{
return self.new_init_from_map(other_map, allocator) @inline;
}
/**
* @param [&in] other_map "The map to copy from."
**/
@@ -110,15 +78,6 @@ fn HashMap* HashMap.temp_init_from_map(&map, HashMap* other_map)
return map.new_init_from_map(other_map, allocator::temp()) @inline;
}
/**
* @param [&in] other_map "The map to copy from."
**/
fn HashMap* HashMap.init_temp_from_map(&map, HashMap* other_map) @deprecated("Replaced by temp_init_from_map")
{
return map.temp_init_from_map(other_map) @inline;
}
fn bool HashMap.is_empty(&map) @inline
{
return !map.count;
@@ -243,7 +202,7 @@ fn Key[] HashMap.key_tlist(&map)
return map.key_new_list(allocator::temp()) @inline;
}
fn Key[] HashMap.key_new_list(&map, Allocator* allocator = allocator::heap())
fn Key[] HashMap.key_new_list(&map, Allocator allocator = allocator::heap())
{
if (!map.count) return {};
@@ -287,7 +246,7 @@ fn Value[] HashMap.value_tlist(&map)
return map.value_new_list(allocator::temp()) @inline;
}
fn Value[] HashMap.value_new_list(&map, Allocator* allocator = allocator::heap())
fn Value[] HashMap.value_new_list(&map, Allocator allocator = allocator::heap())
{
if (!map.count) return {};
Value[] list = allocator::alloc_array(allocator, Value, map.count);

View File

@@ -11,7 +11,7 @@ const Object NULL_OBJECT = { .type = void*.typeid };
struct Object (Printable)
{
typeid type;
Allocator* allocator;
Allocator allocator;
union
{
uint128 i;
@@ -76,7 +76,7 @@ fn usz! Object.to_format(&self, Formatter* formatter) @dynamic
}
}
fn Object* new_obj(Allocator* allocator)
fn Object* new_obj(Allocator allocator)
{
return allocator::new(allocator, Object, { .allocator = allocator, .type = void.typeid });
}
@@ -86,22 +86,22 @@ fn Object* new_null()
return &NULL_OBJECT;
}
fn Object* new_int(int128 i, Allocator* allocator)
fn Object* new_int(int128 i, Allocator allocator)
{
return allocator::new(allocator, Object, { .i = i, .allocator = allocator, .type = int128.typeid });
}
macro Object* new_enum(e, Allocator* allocator)
macro Object* new_enum(e, Allocator allocator)
{
return allocator::new(allocator, Object, { .i = (int128)e, .allocator = allocator, .type = @typeid(e) });
}
fn Object* new_float(double f, Allocator* allocator)
fn Object* new_float(double f, Allocator allocator)
{
return allocator::new(allocator, Object, { .f = f, .allocator = allocator, .type = double.typeid });
}
fn Object* new_string(String s, Allocator* allocator)
fn Object* new_string(String s, Allocator allocator)
{
return allocator::new(allocator, Object, { .s = s.copy(allocator), .allocator = allocator, .type = String.typeid });
}
@@ -234,10 +234,10 @@ macro Object* Object.set_at(&self, usz index, String key, value)
* @require self.is_indexable()
* @ensure return != null
**/
macro Object* Object.append(&self, value)
macro Object* Object.push(&self, value)
{
Object* val = self.object_from_value(value);
self.append_object(val);
self.push_object(val);
return val;
}
@@ -268,10 +268,10 @@ fn usz Object.get_len(&self)
/**
* @require self.is_indexable()
**/
fn void Object.append_object(&self, Object* to_append)
fn void Object.push_object(&self, Object* to_append)
{
self.init_array_if_needed();
self.array.append(to_append);
self.array.push(to_append);
}
/**
@@ -282,11 +282,11 @@ fn void Object.set_object_at(&self, usz index, Object* to_set)
self.init_array_if_needed();
while (self.array.len() < index)
{
self.array.append(&NULL_OBJECT);
self.array.push(&NULL_OBJECT);
}
if (self.array.len() == index)
{
self.array.append(to_set);
self.array.push(to_set);
return;
}
self.array.get(index).free();

View File

@@ -36,12 +36,7 @@ struct PrivatePriorityQueue (Printable)
Heap heap;
}
fn void PrivatePriorityQueue.init_new(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @inline @deprecated("Replaced by new_init")
{
return self.new_init(initial_capacity, allocator);
}
fn void PrivatePriorityQueue.new_init(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @inline
fn void PrivatePriorityQueue.new_init(&self, usz initial_capacity = 16, Allocator allocator = allocator::heap()) @inline
{
self.heap.new_init(initial_capacity, allocator);
}
@@ -51,11 +46,6 @@ fn void PrivatePriorityQueue.temp_init(&self, usz initial_capacity = 16) @inline
self.heap.new_init(initial_capacity, allocator::temp()) @inline;
}
fn void PrivatePriorityQueue.init_temp(&self, usz initial_capacity = 16) @inline @deprecated("Replaced by temp_init")
{
return self.temp_init(initial_capacity) @inline;
}
fn void PrivatePriorityQueue.push(&self, Type element)
{
self.heap.push(element);
@@ -117,7 +107,7 @@ fn Type! PrivatePriorityQueue.pop(&self)
return self.heap.pop();
}
fn Type! PrivatePriorityQueue.peek(&self)
fn Type! PrivatePriorityQueue.first(&self)
{
if (!self.len()) return IteratorResult.NO_MORE_ELEMENT?;
return self.heap.get(0);
@@ -141,7 +131,7 @@ fn bool PrivatePriorityQueue.is_empty(&self)
/**
* @require index < self.len()
*/
fn Type PrivatePriorityQueue.peek_at(&self, usz index) @operator([])
fn Type PrivatePriorityQueue.get(&self, usz index) @operator([])
{
return self.heap[index];
}
@@ -151,7 +141,7 @@ fn usz! PrivatePriorityQueue.to_format(&self, Formatter* formatter) @dynamic
return self.heap.to_format(formatter);
}
fn String PrivatePriorityQueue.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic
fn String PrivatePriorityQueue.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
{
return self.heap.to_new_string(allocator);
}

View File

@@ -29,7 +29,7 @@ fn Type Range.get(&self, usz index) @operator([])
return (Type)(self.start + (usz)index);
}
fn String Range.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic
fn String Range.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
{
return string::new_format("[%s..%s]", self.start, self.end, .allocator = allocator);
}
@@ -66,7 +66,7 @@ fn usz! ExclusiveRange.to_format(&self, Formatter* formatter) @dynamic
return formatter.printf("[%s..<%s]", self.start, self.end)!;
}
fn String ExclusiveRange.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic
fn String ExclusiveRange.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
{
return string::new_format("[%s..<%s]", self.start, self.end, .allocator = allocator);
}

View File

@@ -12,7 +12,7 @@ fn void RingBuffer.init(&self) @inline
*self = {};
}
fn void RingBuffer.putc(&self, Type c)
fn void RingBuffer.push(&self, Type c)
{
if (self.written < SIZE)
{
@@ -26,7 +26,7 @@ fn void RingBuffer.putc(&self, Type c)
}
}
fn Type RingBuffer.getc(&self, usz index)
fn Type RingBuffer.get(&self, usz index) @operator([])
{
index %= SIZE;
usz avail = SIZE - self.head;
@@ -37,7 +37,7 @@ fn Type RingBuffer.getc(&self, usz index)
return self.buf[index - avail];
}
fn Type! RingBuffer.popc(&self)
fn Type! RingBuffer.pop(&self)
{
switch
{
@@ -52,7 +52,7 @@ fn Type! RingBuffer.popc(&self)
}
}
fn usz RingBuffer.get(&self, usz index, Type[] buffer)
fn usz RingBuffer.read(&self, usz index, Type[] buffer)
{
index %= SIZE;
if (self.written < SIZE)
@@ -87,7 +87,7 @@ fn usz RingBuffer.get(&self, usz index, Type[] buffer)
return n1 + n2;
}
fn void RingBuffer.push(&self, Type[] buffer)
fn void RingBuffer.write(&self, Type[] buffer)
{
usz i;
while (self.written < SIZE && i < buffer.len)

View File

@@ -52,7 +52,7 @@ fn void ArenaAllocator.reset(&self, usz mark) @dynamic => self.used = mark;
* @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
* @require size > 0
**/
fn void*! ArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic
fn void*! ArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
{
alignment = alignment_for_allocation(alignment);
usz total_len = self.data.len;
@@ -65,7 +65,7 @@ fn void*! ArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz
self.used = end;
ArenaAllocatorHeader* header = mem - ArenaAllocatorHeader.sizeof;
header.size = size;
if (clear) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT);
if (init_type == ZERO) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT);
return mem;
}
@@ -75,7 +75,7 @@ fn void*! ArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz
* @require old_pointer != null
* @require size > 0
**/
fn void*! ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignment, usz offset) @dynamic
fn void*! ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignment) @dynamic
{
alignment = alignment_for_allocation(alignment);
assert(old_pointer >= self.data.ptr, "Pointer originates from a different allocator.");
@@ -100,7 +100,7 @@ fn void*! ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignmen
return old_pointer;
}
// Otherwise just allocate new memory.
void* mem = self.acquire(size, false, alignment, 0)!;
void* mem = self.acquire(size, NO_ZERO, alignment)!;
mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
return mem;
}

View File

@@ -6,7 +6,7 @@ import std::math;
struct DynamicArenaAllocator (Allocator)
{
Allocator* backing_allocator;
Allocator backing_allocator;
DynamicArenaPage* page;
DynamicArenaPage* unused_page;
usz page_size;
@@ -16,7 +16,7 @@ struct DynamicArenaAllocator (Allocator)
* @param [&inout] allocator
* @require page_size >= 128
**/
fn void DynamicArenaAllocator.init(&self, usz page_size, Allocator* allocator)
fn void DynamicArenaAllocator.init(&self, usz page_size, Allocator allocator)
{
self.page = null;
self.unused_page = null;
@@ -77,7 +77,7 @@ fn void DynamicArenaAllocator.release(&self, void* ptr, bool) @dynamic
* @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, usz offset) @dynamic
fn void*! DynamicArenaAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
{
DynamicArenaPage* current_page = self.page;
alignment = alignment_for_allocation(alignment);
@@ -102,7 +102,7 @@ fn void*! DynamicArenaAllocator.resize(&self, void* old_pointer, usz size, usz a
current_page.used += add_size;
return old_pointer;
}
void* new_mem = self.acquire(size, false, alignment, 0)!;
void* new_mem = self.acquire(size, NO_ZERO, alignment)!;
mem::copy(new_mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT);
return new_mem;
}
@@ -158,7 +158,7 @@ fn void*! DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment) @loca
* @require size > 0 `acquire expects size > 0`
* @require !alignment || math::is_power_of_2(alignment)
*/
fn void*! DynamicArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic
fn void*! DynamicArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
{
alignment = alignment_for_allocation(alignment);
DynamicArenaPage* page = self.page;
@@ -195,6 +195,6 @@ fn void*! DynamicArenaAllocator.acquire(&self, usz size, bool clear, usz alignme
chunk.size = size;
return mem;
|}!;
if (clear) mem::clear(ptr, size, mem::DEFAULT_MEM_ALIGNMENT);
if (init_type == ZERO) mem::clear(ptr, size, mem::DEFAULT_MEM_ALIGNMENT);
return ptr;
}

View File

@@ -21,16 +21,16 @@ fn void SimpleHeapAllocator.init(&self, MemoryAllocFn allocator)
self.free_list = null;
}
fn void*! SimpleHeapAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic
fn void*! SimpleHeapAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
{
if (clear)
if (init_type == ZERO)
{
return alignment > 0 ? @aligned_alloc(self._calloc, size, alignment) : self._calloc(size);
}
return alignment > 0 ? @aligned_alloc(self._alloc, size, alignment) : self._alloc(size);
}
fn void*! SimpleHeapAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset) @dynamic
fn void*! SimpleHeapAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
{
return alignment > 0
? @aligned_realloc(self._calloc, self._free, old_pointer, size, alignment)

View File

@@ -12,9 +12,9 @@ module std::core::mem::allocator @if(env::POSIX);
import std::os;
import libc;
fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz offset) @dynamic
fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
{
if (clear)
if (init_type == ZERO)
{
void* data @noinit;
if (alignment > mem::DEFAULT_MEM_ALIGNMENT)
@@ -43,19 +43,9 @@ fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz
}
}
fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment, usz offset) @dynamic
fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
{
if (!new_bytes)
{
self.release(old_ptr, alignment > 0);
return null;
}
if (!old_ptr)
{
return self.acquire(new_bytes, false, alignment, 0);
}
if (alignment <= mem::DEFAULT_MEM_ALIGNMENT) return libc::realloc(old_ptr, new_bytes) ?: AllocationFailure.OUT_OF_MEMORY?;
void* new_ptr;
if (posix::posix_memalign(&new_ptr, alignment, new_bytes)) return AllocationFailure.OUT_OF_MEMORY?;
@@ -83,9 +73,9 @@ module std::core::mem::allocator @if(env::WIN32);
import std::os::win32;
import libc;
fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz offset) @dynamic
fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
{
if (clear)
if (init_type == ZERO)
{
if (alignment > 0)
{
@@ -101,7 +91,7 @@ fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz
return data;
}
fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment, usz offset) @dynamic
fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
{
if (alignment)
{
@@ -123,9 +113,9 @@ fn void LibcAllocator.release(&self, void* old_ptr, bool aligned) @dynamic
module std::core::mem::allocator @if(!env::WIN32 && !env::POSIX);
import libc;
fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz offset) @dynamic
fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
{
if (clear)
if (init_type == ZERO)
{
void* data = alignment ? @aligned_alloc(fn void*(usz bytes) => libc::calloc(bytes, 1), bytes, alignment)!! : libc::calloc(bytes, 1);
return data ?: AllocationFailure.OUT_OF_MEMORY?;
@@ -142,7 +132,7 @@ fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz
}
fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment, usz offset) @dynamic
fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
{
if (alignment)
{

View File

@@ -2,7 +2,7 @@ module std::core::mem::allocator;
struct OnStackAllocator (Allocator)
{
Allocator* backing_allocator;
Allocator backing_allocator;
char[] data;
usz used;
OnStackAllocatorExtraChunk* chunk;
@@ -20,7 +20,7 @@ struct OnStackAllocatorExtraChunk @local
* @param [&inout] allocator
* Initialize a memory arena for use using the provided bytes.
**/
fn void OnStackAllocator.init(&self, char[] data, Allocator* allocator)
fn void OnStackAllocator.init(&self, char[] data, Allocator allocator)
{
self.data = data;
self.backing_allocator = allocator;
@@ -103,18 +103,18 @@ fn OnStackAllocatorExtraChunk* on_stack_allocator_find_chunk(OnStackAllocator* a
* @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, usz deprecated) @dynamic
fn void*! OnStackAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
{
if (!allocation_in_stack_mem(self, old_pointer))
{
OnStackAllocatorExtraChunk* chunk = on_stack_allocator_find_chunk(self, old_pointer);
assert(chunk, "Tried to realloc pointer not belonging to the allocator");
return chunk.data = self.backing_allocator.resize(old_pointer, size, alignment, 0)!;
return chunk.data = self.backing_allocator.resize(old_pointer, size, alignment)!;
}
OnStackAllocatorHeader* header = old_pointer - OnStackAllocatorHeader.sizeof;
usz old_size = header.size;
void* mem = self.acquire(size, false, alignment, 0)!;
void* mem = self.acquire(size, NO_ZERO, alignment)!;
mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
return mem;
}
@@ -123,7 +123,7 @@ fn void*! OnStackAllocator.resize(&self, void* old_pointer, usz size, usz alignm
* @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
* @require size > 0
**/
fn void*! OnStackAllocator.acquire(&self, usz size, bool clear, usz alignment, usz deprecated) @dynamic
fn void*! OnStackAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
{
bool aligned = alignment > 0;
alignment = alignment_for_allocation(alignment);
@@ -132,7 +132,7 @@ fn void*! OnStackAllocator.acquire(&self, usz size, bool clear, usz alignment, u
void* unaligned_pointer_to_offset = start_mem + self.used + OnStackAllocatorHeader.sizeof ;
void* mem = mem::aligned_pointer(unaligned_pointer_to_offset, alignment);
usz end = (usz)(mem - self.data.ptr) + size;
Allocator* backing_allocator = self.backing_allocator;
Allocator backing_allocator = self.backing_allocator;
if (end > total_len)
{
@@ -140,7 +140,7 @@ fn void*! OnStackAllocator.acquire(&self, usz size, bool clear, usz alignment, u
defer catch allocator::free(backing_allocator, chunk);
defer try self.chunk = chunk;
*chunk = { .prev = self.chunk, .is_aligned = aligned };
return chunk.data = backing_allocator.acquire(size, clear, aligned ? alignment : 0, 0)!;
return chunk.data = backing_allocator.acquire(size, init_type, aligned ? alignment : 0)!;
}
self.used = end;
OnStackAllocatorHeader* header = mem - OnStackAllocatorHeader.sizeof;

View File

@@ -9,7 +9,7 @@ struct TempAllocatorChunk @local
struct TempAllocator (Allocator)
{
Allocator* backing_allocator;
Allocator backing_allocator;
TempAllocatorPage* last_page;
usz used;
usz capacity;
@@ -35,7 +35,7 @@ macro bool TempAllocatorPage.is_aligned(&self) => self.size & PAGE_IS_ALIGNED ==
/**
* @require size >= 16
**/
fn TempAllocator*! new_temp_allocator(usz size, Allocator* allocator)
fn TempAllocator*! new_temp_allocator(usz size, Allocator allocator)
{
TempAllocator* temp = allocator::alloc_with_padding(allocator, TempAllocator, size)!;
temp.last_page = null;
@@ -45,11 +45,6 @@ fn TempAllocator*! new_temp_allocator(usz size, Allocator* allocator)
return temp;
}
fn TempAllocator*! new_temp(usz size, Allocator* allocator) @deprecated("Use new_temp_allocator")
{
return new_temp_allocator(size, allocator);
}
fn usz TempAllocator.mark(&self) @dynamic => self.used;
fn void TempAllocator.release(&self, void* old_pointer, bool) @dynamic
@@ -94,13 +89,13 @@ fn void*! TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size,
*pointer_to_prev = page.prev_page;
usz page_size = page.pagesize();
// Clear on size > original size.
void* data = self.acquire(size, size > page_size, alignment, 0)!;
void* data = self.acquire(size, NO_ZERO, alignment)!;
mem::copy(data, &page.data[0], page_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
self.backing_allocator.release(real_pointer, page.is_aligned());
return data;
}
fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment, usz deprecated) @dynamic
fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment) @dynamic
{
TempAllocatorChunk *chunk = pointer - TempAllocatorChunk.sizeof;
if (chunk.size == (usz)-1)
@@ -111,8 +106,7 @@ fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment, us
return self._realloc_page(page, size, alignment);
}
// TODO optimize last allocation
TempAllocatorChunk* data = self.acquire(size, size > chunk.size, alignment, 0)!;
TempAllocatorChunk* data = self.acquire(size, NO_ZERO, alignment)!;
mem::copy(data, pointer, chunk.size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
return data;
@@ -123,7 +117,7 @@ fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment, us
* @require !alignment || math::is_power_of_2(alignment)
* @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
**/
fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz deprecated) @dynamic
fn void*! TempAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
{
alignment = alignment_for_allocation(alignment);
void* start_mem = &self.data;
@@ -142,7 +136,7 @@ fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz
TempAllocatorChunk* chunk_start = mem - TempAllocatorChunk.sizeof;
chunk_start.size = size;
self.used = new_usage;
if (clear) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT);
if (init_type == ZERO) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT);
return mem;
}
@@ -154,7 +148,7 @@ fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz
{
// This is actually simpler, since it will create the offset for us.
usz total_alloc_size = mem::aligned_offset(TempAllocatorPage.sizeof + size, alignment);
if (clear)
if (init_type == ZERO)
{
mem = allocator::calloc_aligned(self.backing_allocator, total_alloc_size, alignment)!;
}
@@ -171,7 +165,7 @@ fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz
// Here we might need to pad
usz padded_header_size = mem::aligned_offset(TempAllocatorPage.sizeof, mem::DEFAULT_MEM_ALIGNMENT);
usz total_alloc_size = padded_header_size + size;
void* alloc = self.backing_allocator.acquire(total_alloc_size, clear, 0, 0)!;
void* alloc = self.backing_allocator.acquire(total_alloc_size, init_type, 0)!;
// Find the page.
page = alloc + padded_header_size - TempAllocatorPage.sizeof;

View File

@@ -20,7 +20,7 @@ def AllocMap = HashMap(<uptr, Allocation>);
// is not compatible with allocators that uses mark()
struct TrackingAllocator (Allocator)
{
Allocator* inner_allocator;
Allocator inner_allocator;
AllocMap map;
usz mem_total;
usz allocs_total;
@@ -31,7 +31,7 @@ struct TrackingAllocator (Allocator)
*
* @param [&inout] allocator "The allocator to track"
**/
fn void TrackingAllocator.init(&self, Allocator* allocator)
fn void TrackingAllocator.init(&self, Allocator allocator)
{
*self = { .inner_allocator = allocator };
self.map.new_init(.allocator = allocator);
@@ -69,7 +69,7 @@ fn usz TrackingAllocator.total_allocated(&self) => self.mem_total;
**/
fn usz TrackingAllocator.total_allocation_count(&self) => self.allocs_total;
fn Allocation[] TrackingAllocator.allocations_tlist(&self, Allocator* allocator)
fn Allocation[] TrackingAllocator.allocations_tlist(&self, Allocator allocator)
{
return self.map.value_tlist();
}
@@ -79,9 +79,9 @@ fn Allocation[] TrackingAllocator.allocations_tlist(&self, Allocator* allocator)
**/
fn usz TrackingAllocator.allocation_count(&self) => self.map.count;
fn void*! TrackingAllocator.acquire(&self, usz size, bool clear, usz alignment, usz deprecated) @dynamic
fn void*! TrackingAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
{
void* data = self.inner_allocator.acquire(size, clear, alignment, 0)!;
void* data = self.inner_allocator.acquire(size, init_type, alignment)!;
self.allocs_total++;
void*[MAX_BACKTRACE] bt;
backtrace::capture_current(&bt);
@@ -91,9 +91,9 @@ fn void*! TrackingAllocator.acquire(&self, usz size, bool clear, usz alignment,
return data;
}
fn void*! TrackingAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz deprecated) @dynamic
fn void*! TrackingAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
{
void* data = self.inner_allocator.resize(old_pointer, size, alignment, 0)!;
void* data = self.inner_allocator.resize(old_pointer, size, alignment)!;
self.map.remove((uptr)old_pointer);
void*[MAX_BACKTRACE] bt;
backtrace::capture_current(&bt);
@@ -107,7 +107,7 @@ fn void TrackingAllocator.release(&self, void* old_pointer, bool is_aligned) @dy
{
if (catch self.map.remove((uptr)old_pointer))
{
assert(false, "Attempt to release untracked pointer %p, this is likely a bug.", old_pointer);
unreachable("Attempt to release untracked pointer %p, this is likely a bug.", old_pointer);
}
self.inner_allocator.release(old_pointer, is_aligned);
}
@@ -119,7 +119,7 @@ fn void TrackingAllocator.clear(&self)
fn void TrackingAllocator.print_report(&self) => self.fprint_report(io::stdout())!!;
fn void! TrackingAllocator.fprint_report(&self, OutStream* out)
fn void! TrackingAllocator.fprint_report(&self, OutStream out)
{
usz total = 0;

View File

@@ -45,17 +45,17 @@ macro rindex_of(array, element)
}
/**
* Concatenate two arrays or subarrays, returning a subarray containing the concatenation of them.
* 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) == SUBARRAY || @typekind(arr1) == ARRAY
* @require @typekind(arr2) == SUBARRAY || @typekind(arr2) == ARRAY
* @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())
macro concat_new(arr1, arr2, Allocator allocator = allocator::heap())
{
var $Type = $typeof(arr1[0]);
$Type[] result = allocator::alloc_array(allocator, $Type, arr1.len + arr2.len);
@@ -71,13 +71,13 @@ macro concat_new(arr1, arr2, Allocator* allocator = allocator::heap())
}
/**
* Concatenate two arrays or subarrays, returning a subarray containing the concatenation of them,
* 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) == SUBARRAY || @typekind(arr1) == ARRAY
* @require @typekind(arr2) == SUBARRAY || @typekind(arr2) == ARRAY
* @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
**/

View File

@@ -88,7 +88,7 @@ bitstruct UInt128LE : uint128 @littleendian
}
/**
* @require is_array_or_sub_of_char(bytes) "argument must be an array, a pointer to an array or a subarray of char"
* @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)
@@ -104,7 +104,7 @@ macro read(bytes, $Type)
}
/**
* @require is_arrayptr_or_sub_of_char(bytes) "argument must be a pointer to an array or a subarray of char"
* @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)
@@ -144,7 +144,7 @@ macro is_bitorder($Type)
$endswitch
}
macro bool is_array_or_sub_of_char(bytes)
macro bool is_array_or_slice_of_char(bytes)
{
$switch (@typekind(bytes))
$case POINTER:
@@ -154,7 +154,7 @@ macro bool is_array_or_sub_of_char(bytes)
return $Inner2.typeid == char.typeid;
$endif
$case ARRAY:
$case SUBARRAY:
$case SLICE:
var $Inner = $typefrom($typeof(bytes).inner);
return $Inner.typeid == char.typeid;
$default:
@@ -162,7 +162,7 @@ macro bool is_array_or_sub_of_char(bytes)
$endswitch
}
macro bool is_arrayptr_or_sub_of_char(bytes)
macro bool is_arrayptr_or_slice_of_char(bytes)
{
$switch (@typekind(bytes))
$case POINTER:
@@ -171,7 +171,7 @@ macro bool is_arrayptr_or_sub_of_char(bytes)
var $Inner2 = $typefrom($Inner.inner);
return $Inner2.typeid == char.typeid;
$endif
$case SUBARRAY:
$case SLICE:
var $Inner = $typefrom($typeof(bytes).inner);
return $Inner.typeid == char.typeid;
$default:

View File

@@ -61,7 +61,7 @@ macro void @swap(&a, &b) @builtin
* @ensure @typeis(return, $Type*)
* @return! CastResult.TYPE_MISMATCH
**/
macro anycast(any* v, $Type) @builtin
macro anycast(any v, $Type) @builtin
{
if (v.type != $Type.typeid) return CastResult.TYPE_MISMATCH?;
return ($Type*)v.ptr;
@@ -83,17 +83,18 @@ fn bool print_backtrace(String message, int backtraces_to_ignore) @if(env::NATIV
foreach (i, &trace : backtrace)
{
if (i < backtraces_to_ignore) continue;
String inline_suffix = trace.is_inline ? " [inline]" : "";
if (trace.is_unknown())
{
io::eprintn(" in ???");
io::eprintfn(" in ???%s", inline_suffix);
continue;
}
if (trace.has_file())
{
io::eprintfn(" in %s (%s:%d) [%s]", trace.function, trace.file, trace.line, trace.object_file);
io::eprintfn(" in %s (%s:%d) [%s]%s", trace.function, trace.file, trace.line, trace.object_file, inline_suffix);
continue;
}
io::eprintfn(" in %s (source unavailable) [%s]", trace.function, trace.object_file);
io::eprintfn(" in %s (source unavailable) [%s]%s", trace.function, trace.object_file, inline_suffix);
}
return true;
};
@@ -126,7 +127,7 @@ PanicFn panic = &default_panic;
fn void panicf(String fmt, String file, String function, uint line, args...)
{
@stack_mem(512; Allocator* allocator)
@stack_mem(512; Allocator allocator)
{
DString s;
s.new_init(.allocator = allocator);

View File

@@ -8,7 +8,7 @@ const usz MIN_CAPACITY @private = 16;
/**
* @require !self.data() "String already initialized"
**/
fn DString DString.new_init(&self, usz capacity = MIN_CAPACITY, Allocator* allocator = allocator::heap())
fn DString DString.new_init(&self, usz capacity = MIN_CAPACITY, Allocator allocator = allocator::heap())
{
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY;
StringData* data = allocator::alloc_with_padding(allocator, StringData, capacity)!!;
@@ -18,14 +18,6 @@ fn DString DString.new_init(&self, usz capacity = MIN_CAPACITY, Allocator* alloc
return *self = (DString)data;
}
/**
* @require !self.data() "String already initialized"
**/
fn DString DString.init_new(&self, usz capacity = MIN_CAPACITY, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
{
return self.new_init(capacity, allocator) @inline;
}
/**
* @require !self.data() "String already initialized"
**/
@@ -35,22 +27,14 @@ fn DString DString.temp_init(&self, usz capacity = MIN_CAPACITY)
return *self;
}
/**
* @require !self.data() "String already initialized"
**/
fn DString DString.init_temp(&self, usz capacity = MIN_CAPACITY) @deprecated("Replaced by temp_init")
{
return self.temp_init(capacity) @inline;
}
fn DString new_with_capacity(usz capacity, Allocator* allocator = allocator::heap())
fn DString new_with_capacity(usz capacity, Allocator allocator = allocator::heap())
{
return DString{}.new_init(capacity, allocator);
}
fn DString temp_with_capacity(usz capacity) => new_with_capacity(capacity, allocator::temp()) @inline;
fn DString new(String c = "", Allocator* allocator = allocator::heap())
fn DString new(String c = "", Allocator allocator = allocator::heap())
{
usz len = c.len;
StringData* data = (StringData*)new_with_capacity(len, allocator);
@@ -64,7 +48,7 @@ fn DString new(String c = "", Allocator* allocator = allocator::heap())
fn DString temp_new(String s = "") => new(s, allocator::temp()) @inline;
fn DString DString.new_concat(self, DString b, Allocator* allocator = allocator::heap())
fn DString DString.new_concat(self, DString b, Allocator allocator = allocator::heap())
{
DString string;
string.new_init(self.len() + b.len(), allocator);
@@ -75,8 +59,6 @@ fn DString DString.new_concat(self, DString b, Allocator* allocator = allocator:
fn DString DString.temp_concat(self, DString b) => self.new_concat(b, allocator::temp());
fn DString DString.new_tconcat(self, DString b) @deprecated("Replaced by temp_concat") => self.new_concat(b, allocator::temp());
fn ZString DString.zstr_view(&self)
{
StringData* data = self.data();
@@ -166,7 +148,7 @@ fn void DString.append_char32(&self, Char32 c)
fn DString DString.tcopy(&self) => self.copy(allocator::temp());
fn DString DString.copy(self, Allocator* allocator = null)
fn DString DString.copy(self, Allocator allocator = null)
{
if (!self)
{
@@ -180,7 +162,7 @@ fn DString DString.copy(self, Allocator* allocator = null)
return new_string;
}
fn ZString DString.copy_zstr(self, Allocator* allocator = allocator::heap())
fn ZString DString.copy_zstr(self, Allocator allocator = allocator::heap())
{
usz str_len = self.len();
if (!str_len)
@@ -194,7 +176,7 @@ fn ZString DString.copy_zstr(self, Allocator* allocator = allocator::heap())
return (ZString)zstr;
}
fn String DString.copy_str(self, Allocator* allocator = allocator::heap())
fn String DString.copy_str(self, Allocator allocator = allocator::heap())
{
return (String)self.copy_zstr(allocator)[:self.len()];
}
@@ -258,7 +240,7 @@ fn void DString.append_chars(&self, String str)
data.len += other_len;
}
fn Char32[] DString.copy_utf32(&self, Allocator* allocator = allocator::heap())
fn Char32[] DString.copy_utf32(&self, Allocator allocator = allocator::heap())
{
return self.str_view().to_new_utf32(allocator) @inline!!;
}
@@ -403,7 +385,7 @@ fn usz! DString.appendfn(&self, String format, args...) @maydiscard
return len + 1;
}
fn DString new_join(String[] s, String joiner, Allocator* allocator = allocator::heap())
fn DString new_join(String[] s, String joiner, Allocator allocator = allocator::heap())
{
if (!s.len) return (DString)null;
usz total_size = joiner.len * s.len;
@@ -450,7 +432,7 @@ fn void DString.reserve(&self, usz addition)
*self = (DString)allocator::realloc(data.allocator, data, StringData.sizeof + new_capacity);
}
fn usz! DString.read_from_stream(&self, InStream* reader)
fn usz! DString.read_from_stream(&self, InStream reader)
{
if (&reader.available)
{
@@ -482,7 +464,7 @@ fn usz! DString.read_from_stream(&self, InStream* reader)
struct StringData @private
{
Allocator* allocator;
Allocator allocator;
usz len;
usz capacity;
char[*] chars;

View File

@@ -123,6 +123,7 @@ const bool BIG_ENDIAN = $$PLATFORM_BIG_ENDIAN;
const bool I128_NATIVE_SUPPORT = $$PLATFORM_I128_SUPPORTED;
const bool F16_SUPPORT = $$PLATFORM_F16_SUPPORTED;
const bool F128_SUPPORT = $$PLATFORM_F128_SUPPORTED;
const REGISTER_SIZE = $$REGISTER_SIZE;
const bool COMPILER_SAFE_MODE = $$COMPILER_SAFE_MODE;
const bool DEBUG_SYMBOLS = $$DEBUG_SYMBOLS;
const usz LLVM_VERSION = $$LLVM_VERSION;

View File

@@ -343,9 +343,9 @@ macro void set_inline(void* dst, char val, usz $len, usz $dst_align = 0, bool $i
$$memset_inline(dst, val, $len, $is_volatile, $dst_align);
}
/**
* @require values::@inner_kind(a) == TypeKind.SUBARRAY || values::@inner_kind(a) == TypeKind.POINTER
* @require values::@inner_kind(b) == TypeKind.SUBARRAY || values::@inner_kind(b) == TypeKind.POINTER
* @require values::@inner_kind(a) != TypeKind.SUBARRAY || len == -1
* @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)
**/
@@ -356,7 +356,7 @@ macro bool equals(a, b, isz len = -1, usz $align = 0)
$endif
void* x @noinit;
void* y @noinit;
$if values::@inner_kind(a) == TypeKind.SUBARRAY:
$if values::@inner_kind(a) == TypeKind.SLICE:
len = a.len;
if (len != b.len) return false;
x = a.ptr;
@@ -403,9 +403,9 @@ macro type_alloc_must_be_aligned($Type)
/**
* Run with a specific allocator inside of the macro body.
**/
macro void @scoped(Allocator* allocator; @body())
macro void @scoped(Allocator allocator; @body())
{
Allocator* old_allocator = allocator::thread_allocator;
Allocator old_allocator = allocator::thread_allocator;
allocator::thread_allocator = allocator;
defer allocator::thread_allocator = old_allocator;
@body();
@@ -415,7 +415,7 @@ macro void @report_heap_allocs_in_scope(;@body())
{
TrackingAllocator tracker;
tracker.init(allocator::thread_allocator);
Allocator* old_allocator = allocator::thread_allocator;
Allocator old_allocator = allocator::thread_allocator;
allocator::thread_allocator = &tracker;
defer
{
@@ -426,7 +426,7 @@ macro void @report_heap_allocs_in_scope(;@body())
@body();
}
macro void @stack_mem(usz $size; @body(Allocator* mem)) @builtin
macro void @stack_mem(usz $size; @body(Allocator mem)) @builtin
{
char[$size] buffer;
OnStackAllocator allocator;
@@ -504,11 +504,6 @@ macro void @pool(TempAllocator* #other_temp = null; @body) @builtin
import libc;
macro TempAllocator* temp() @deprecated("Use allocator::temp()") => allocator::temp();
macro Allocator* current_allocator() @deprecated("Use allocator::heap()") => allocator::heap();
macro Allocator* heap() @deprecated("Use allocator::heap()") => allocator::heap();
module std::core::mem @if(WASM_NOLIBC);
SimpleHeapAllocator wasm_allocator @private;
@@ -552,10 +547,10 @@ fn void* malloc(usz size) @builtin @inline @nodiscard
return allocator::malloc(allocator::heap(), size);
}
fn void* tmalloc(usz size, usz alignment = 0, usz offset = 0) @builtin @inline @nodiscard
fn void* tmalloc(usz size, usz alignment = 0) @builtin @inline @nodiscard
{
if (!size) return null;
return allocator::temp().acquire(size, false, alignment, 0)!!;
return allocator::temp().acquire(size, NO_ZERO, alignment)!!;
}
/**
@@ -608,16 +603,6 @@ macro alloc_aligned($Type) @nodiscard
return ($Type*)malloc_aligned($Type.sizeof, $Type.alignof);
}
macro new_clear($Type) @deprecated("Use mem::new")
{
return new($Type);
}
macro new_temp($Type) @deprecated("Use mem::temp_alloc or mem::temp_new")
{
return tmalloc($Type.sizeof);
}
/**
* @require $vacount < 2 : "Too many arguments."
* @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type"
@@ -638,12 +623,6 @@ macro temp_alloc($Type) @nodiscard
return tmalloc($Type.sizeof);
}
macro new_temp_clear($Type) @deprecated("use mem::temp_new")
{
return tcalloc($Type.sizeof);
}
/**
* @require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_array_aligned' instead"
@@ -679,36 +658,16 @@ macro alloc_array_aligned($Type, usz elements) @nodiscard
return allocator::alloc_array(allocator::heap(), $Type, elements);
}
macro talloc_array($Type, usz elements) @nodiscard @deprecated("use mem::temp_alloc_array")
{
return temp_alloc_array($Type, elements);
}
macro temp_alloc_array($Type, usz elements) @nodiscard
{
return (($Type*)tmalloc($Type.sizeof * elements, $Type.alignof))[:elements];
}
macro temp_array($Type, usz elements) @nodiscard @deprecated("use mem::temp_alloc_array")
{
return temp_alloc_array($Type, elements);
}
macro temp_new_array($Type, usz elements) @nodiscard
{
return (($Type*)tcalloc($Type.sizeof * elements, $Type.alignof))[:elements];
}
macro new_zero_array($Type, usz elements) @deprecated("Use new_array")
{
return new_array($Type, elements);
}
macro temp_zero_array($Type, usz elements) @deprecated("Use temp_new_array")
{
return temp_new_array($Type, elements);
}
fn void* calloc(usz size) @builtin @inline @nodiscard
{
return allocator::calloc(allocator::heap(), size);
@@ -719,10 +678,10 @@ fn void* calloc_aligned(usz size, usz alignment) @builtin @inline @nodiscard
return allocator::calloc_aligned(allocator::heap(), size, alignment)!!;
}
fn void* tcalloc(usz size, usz alignment = 0, usz offset = 0) @builtin @inline @nodiscard
fn void* tcalloc(usz size, usz alignment = 0) @builtin @inline @nodiscard
{
if (!size) return null;
return allocator::temp().acquire(size, false, alignment, 0)!!;
return allocator::temp().acquire(size, ZERO, alignment)!!;
}
fn void* realloc(void *ptr, usz new_size) @builtin @inline @nodiscard
@@ -749,6 +708,6 @@ fn void* trealloc(void* ptr, usz size, usz alignment = mem::DEFAULT_MEM_ALIGNMEN
{
if (!size) return null;
if (!ptr) return tmalloc(size, alignment);
return allocator::temp().resize(ptr, size, alignment, 0)!!;
return allocator::temp().resize(ptr, size, alignment)!!;
}

View File

@@ -10,6 +10,11 @@ struct TrackingEnv
uint line;
}
enum AllocInitType
{
NO_ZERO,
ZERO
}
interface Allocator
{
@@ -18,18 +23,16 @@ interface Allocator
/**
* @require !alignment || math::is_power_of_2(alignment)
* @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
* @require offset == 0 `offset no longer supported`
* @require size > 0
**/
fn void*! acquire(usz size, bool clear, usz alignment, usz offset);
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 offset == 0 `offset no longer supported`
* @require ptr != null
* @require new_size > 0
**/
fn void*! resize(void* ptr, usz new_size, usz alignment, usz offset);
fn void*! resize(void* ptr, usz new_size, usz alignment = 0);
/**
* @require ptr != null
**/
@@ -49,51 +52,51 @@ fn usz alignment_for_allocation(usz alignment) @inline @private
return alignment < mem::DEFAULT_MEM_ALIGNMENT ? alignment = mem::DEFAULT_MEM_ALIGNMENT : alignment;
}
macro void* malloc(Allocator* allocator, usz size) @nodiscard
macro void* malloc(Allocator allocator, usz size) @nodiscard
{
return malloc_try(allocator, size)!!;
}
macro void*! malloc_try(Allocator* allocator, usz size) @nodiscard
macro void*! malloc_try(Allocator allocator, usz size) @nodiscard
{
if (!size) return null;
$if env::TESTING:
char* data = allocator.acquire(size, false, 0, 0)!;
char* data = allocator.acquire(size, NO_ZERO)!;
mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT);
return data;
$else
return allocator.acquire(size, false, 0, 0);
return allocator.acquire(size, NO_ZERO);
$endif
}
macro void* calloc(Allocator* allocator, usz size) @nodiscard
macro void* calloc(Allocator allocator, usz size) @nodiscard
{
return calloc_try(allocator, size)!!;
}
macro void*! calloc_try(Allocator* allocator, usz size) @nodiscard
macro void*! calloc_try(Allocator allocator, usz size) @nodiscard
{
if (!size) return null;
return allocator.acquire(size, true, 0, 0);
return allocator.acquire(size, ZERO);
}
macro void* realloc(Allocator* allocator, void* ptr, usz new_size) @nodiscard
macro void* realloc(Allocator allocator, void* ptr, usz new_size) @nodiscard
{
return realloc_try(allocator, ptr, new_size)!!;
}
macro void*! realloc_try(Allocator* allocator, void* ptr, usz new_size) @nodiscard
macro void*! realloc_try(Allocator allocator, void* ptr, usz new_size) @nodiscard
{
if (!new_size)
{
free(allocator, ptr);
return null;
}
if (!ptr) return allocator.acquire(new_size, false, 0, 0);
return allocator.resize(ptr, new_size, 0, 0);
if (!ptr) return allocator.acquire(new_size, NO_ZERO);
return allocator.resize(ptr, new_size);
}
macro void free(Allocator* allocator, void* ptr)
macro void free(Allocator allocator, void* ptr)
{
if (!ptr) return;
$if env::TESTING:
@@ -102,25 +105,25 @@ macro void free(Allocator* allocator, void* ptr)
allocator.release(ptr, false);
}
macro void*! malloc_aligned(Allocator* allocator, usz size, usz alignment, usz offset = 0) @nodiscard
macro void*! malloc_aligned(Allocator allocator, usz size, usz alignment) @nodiscard
{
if (!size) return null;
$if env::TESTING:
char* data = allocator.acquire(size, false, alignment, offset)!;
char* data = allocator.acquire(size, NO_ZERO, alignment)!;
mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT);
return data;
$else
return allocator.acquire(size, false, alignment, offset);
return allocator.acquire(size, NO_ZERO, alignment);
$endif
}
macro void*! calloc_aligned(Allocator* allocator, usz size, usz alignment, usz offset = 0) @nodiscard
macro void*! calloc_aligned(Allocator allocator, usz size, usz alignment) @nodiscard
{
if (!size) return null;
return allocator.acquire(size, true, alignment, offset);
return allocator.acquire(size, ZERO, alignment);
}
macro void*! realloc_aligned(Allocator* allocator, void* ptr, usz new_size, usz alignment, usz offset = 0) @nodiscard
macro void*! realloc_aligned(Allocator allocator, void* ptr, usz new_size, usz alignment) @nodiscard
{
if (!new_size)
{
@@ -131,23 +134,23 @@ macro void*! realloc_aligned(Allocator* allocator, void* ptr, usz new_size, usz
{
return malloc_aligned(allocator, new_size, alignment);
}
return allocator.resize(ptr, new_size, alignment, offset);
return allocator.resize(ptr, new_size, alignment);
}
macro void free_aligned(Allocator* allocator, void* ptr)
macro void free_aligned(Allocator allocator, void* ptr)
{
if (!ptr) return;
$if env::TESTING:
((char*)ptr)[0] = 0xBA;
$endif
allocator.release(ptr, true);
allocator.release(ptr, .aligned = true);
}
/**
* @require $vacount < 2 : "Too many arguments."
* @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type"
**/
macro new(Allocator* allocator, $Type, ...) @nodiscard
macro new(Allocator allocator, $Type, ...) @nodiscard
{
$if $vacount == 0:
return ($Type*)calloc(allocator, $Type.sizeof);
@@ -162,7 +165,7 @@ macro new(Allocator* allocator, $Type, ...) @nodiscard
* @require $vacount < 2 : "Too many arguments."
* @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type"
**/
macro new_try(Allocator* allocator, $Type, ...) @nodiscard
macro new_try(Allocator allocator, $Type, ...) @nodiscard
{
$if $vacount == 0:
return ($Type*)calloc_try(allocator, $Type.sizeof);
@@ -173,62 +176,62 @@ macro new_try(Allocator* allocator, $Type, ...) @nodiscard
$endif
}
macro new_with_padding(Allocator* allocator, $Type, usz padding) @nodiscard
macro new_with_padding(Allocator allocator, $Type, usz padding) @nodiscard
{
return ($Type*)calloc_try(allocator, $Type.sizeof + padding);
}
macro alloc(Allocator* allocator, $Type) @nodiscard
macro alloc(Allocator allocator, $Type) @nodiscard
{
return ($Type*)malloc(allocator, $Type.sizeof);
}
macro alloc_try(Allocator* allocator, $Type) @nodiscard
macro alloc_try(Allocator allocator, $Type) @nodiscard
{
return ($Type*)malloc_try(allocator, $Type.sizeof);
}
macro alloc_with_padding(Allocator* allocator, $Type, usz padding) @nodiscard
macro alloc_with_padding(Allocator allocator, $Type, usz padding) @nodiscard
{
return ($Type*)malloc_try(allocator, $Type.sizeof + padding);
}
macro new_array(Allocator* allocator, $Type, usz elements) @nodiscard
macro new_array(Allocator allocator, $Type, usz elements) @nodiscard
{
return new_array_try(allocator, $Type, elements)!!;
}
macro new_array_try(Allocator* allocator, $Type, usz elements) @nodiscard
macro new_array_try(Allocator allocator, $Type, usz elements) @nodiscard
{
return (($Type*)calloc_try(allocator, $Type.sizeof * elements))[:elements];
}
macro new_array_aligned(Allocator* allocator, $Type, usz elements) @nodiscard
macro new_array_aligned(Allocator allocator, $Type, usz elements) @nodiscard
{
return ((Type*)calloc_aligned(allocator, $Type.sizeof * elements, $Type.alignof))[:elements]!!;
}
macro alloc_array(Allocator* allocator, $Type, usz elements) @nodiscard
macro alloc_array(Allocator allocator, $Type, usz elements) @nodiscard
{
return alloc_array_try(allocator, $Type, elements)!!;
}
macro alloc_array_aligned(Allocator* allocator, $Type, usz elements) @nodiscard
macro alloc_array_aligned(Allocator allocator, $Type, usz elements) @nodiscard
{
return ((Type*)malloc_aligned(allocator, $Type.sizeof * elements, $Type.alignof))[:elements]!!;
}
macro alloc_array_try(Allocator* allocator, $Type, usz elements) @nodiscard
macro alloc_array_try(Allocator allocator, $Type, usz elements) @nodiscard
{
return (($Type*)malloc_try(allocator, $Type.sizeof * elements))[:elements];
}
macro clone(Allocator* allocator, value) @nodiscard
macro clone(Allocator allocator, value) @nodiscard
{
return new(allocator, $typeof(value), value);
}
fn any* clone_any(Allocator* allocator, any* value) @nodiscard
fn any clone_any(Allocator allocator, any value) @nodiscard
{
usz size = value.type.sizeof;
void* data = malloc(allocator, size);
@@ -236,106 +239,6 @@ fn any* clone_any(Allocator* allocator, any* value) @nodiscard
return any_make(data, value.type);
}
// Allocator "functions"
macro void*! Allocator.alloc_checked(&self, usz size) @deprecated("Use allocator::malloc_try")
{
return malloc_try(self, size);
}
macro void*! Allocator.calloc_checked(&self, usz size) @deprecated("Use allocator::calloc_try")
{
return calloc_try(self, size);
}
macro void*! Allocator.realloc_checked(&self, void* ptr, usz new_size) @deprecated("Use allocator::realloc_try")
{
return realloc_try(ptr, new_size);
}
macro Allocator.new_array(&self, $Type, usz size, usz end_padding = 0) @deprecated("Use allocator::alloc_array")
{
return (($Type*)self.alloc_checked($Type.sizeof * size + end_padding))[:size]!!;
}
macro Allocator.new_array_checked(&self, $Type, usz size, usz end_padding = 0) @deprecated("Use allocator::alloc_array_try")
{
return (($Type*)self.alloc_checked($Type.sizeof * size + end_padding))[:size];
}
macro Allocator.new_zero_array(&self, $Type, usz size, usz end_padding = 0) @deprecated("Use allocator::new_array")
{
return (($Type*)self.calloc_checked($Type.sizeof * size + end_padding))[:size]!!;
}
macro Allocator.new_zero_array_checked(&self, $Type, usz size, usz end_padding = 0) @deprecated("Use allocator::new_array_try")
{
return (($Type*)self.calloc_checked($Type.sizeof * size + end_padding))[:size];
}
macro Allocator.new(&self, $Type, usz end_padding = 0) @nodiscard @deprecated("Use allocator::alloc")
{
return ($Type*)self.alloc_checked($Type.sizeof + end_padding)!!;
}
macro Allocator.new_checked(&self, $Type, usz end_padding = 0) @nodiscard @deprecated("Use allocator::alloc_try")
{
return ($Type*)self.alloc_checked($Type.sizeof + end_padding);
}
macro Allocator.new_clear(&self, $Type, usz end_padding = 0) @nodiscard @deprecated("Use allocator::new")
{
return ($Type*)self.calloc_checked($Type.sizeof + end_padding)!!;
}
macro Allocator.new_clear_checked(&self, $Type, usz end_padding = 0) @nodiscard @deprecated("Use allocator::new_try")
{
return ($Type*)self.calloc_checked($Type.sizeof + end_padding);
}
macro Allocator.clone(&self, value) @deprecated("Use allocator::clone")
{
var x = self.alloc($typeof(value));
*x = value;
return x;
}
fn void* Allocator.alloc(&self, usz size) @nodiscard @deprecated("Use allocator::malloc")
{
return malloc(self, size);
}
fn void* Allocator.calloc(&self, usz size) @nodiscard @deprecated("Use allocator::calloc")
{
return calloc(self, size);
}
fn void* Allocator.realloc(&self, void* ptr, usz new_size) @nodiscard @deprecated("Use allocator::realloc")
{
return realloc(self, ptr, new_size);
}
fn void*! Allocator.alloc_aligned(&self, usz size, usz alignment, usz offset = 0) @deprecated("Use allocator::malloc_aligned")
{
return malloc_aligned(self, size, alignment, 0);
}
fn void*! Allocator.calloc_aligned(&self, usz size, usz alignment, usz offset = 0) @deprecated("Use allocator::calloc_aligned")
{
return calloc_aligned(self, size, alignment, 0);
}
fn void*! Allocator.realloc_aligned(&self, void* ptr, usz new_size, usz alignment = 0, usz offset = 0) @deprecated("Use allocator::realloc_aligned")
{
return realloc_aligned(self, ptr, new_size, alignment, 0);
}
fn void Allocator.free(&self, void* ptr) @deprecated("Use allocator::free")
{
free(self, ptr);
}
fn void Allocator.free_aligned(&self, void* ptr) @deprecated("Use allocator::free_aligned")
{
free_aligned(self, ptr);
}
/**
* @require bytes > 0
@@ -395,12 +298,12 @@ macro void*! @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes
// All allocators
tlocal Allocator* thread_allocator @private = &allocator::LIBC_ALLOCATOR;
tlocal Allocator thread_allocator @private = &allocator::LIBC_ALLOCATOR;
tlocal TempAllocator* thread_temp_allocator @private = null;
tlocal TempAllocator*[2] temp_allocator_pair @private;
Allocator* temp_base_allocator @private = &allocator::LIBC_ALLOCATOR;
Allocator temp_base_allocator @private = &allocator::LIBC_ALLOCATOR;
macro TempAllocator* create_default_sized_temp_allocator(Allocator* allocator) @local
macro TempAllocator* create_default_sized_temp_allocator(Allocator allocator) @local
{
$switch (env::MEMORY_ENV)
$case NORMAL:
@@ -414,7 +317,7 @@ macro TempAllocator* create_default_sized_temp_allocator(Allocator* allocator) @
$endswitch
}
macro Allocator* heap() => thread_allocator;
macro Allocator heap() => thread_allocator;
macro TempAllocator* temp()
{
@@ -432,7 +335,7 @@ fn void init_default_temp_allocators() @private
thread_temp_allocator = temp_allocator_pair[0];
}
fn TempAllocator *temp_allocator_next() @private
fn TempAllocator* temp_allocator_next() @private
{
if (!thread_temp_allocator)
{

View File

@@ -4,13 +4,13 @@
module std::core::runtime;
import libc, std::time, std::io, std::sort;
struct AnyStruct
struct AnyRaw
{
void* ptr;
typeid type;
}
struct SubArrayStruct
struct SliceRaw
{
void* ptr;
usz len;
@@ -24,7 +24,7 @@ struct BenchmarkUnit
BenchmarkFn func;
}
fn BenchmarkUnit[] benchmark_collection_create(Allocator* allocator = allocator::heap())
fn BenchmarkUnit[] benchmark_collection_create(Allocator allocator = allocator::heap())
{
BenchmarkFn[] fns = $$BENCHMARK_FNS;
String[] names = $$BENCHMARK_NAMES;
@@ -142,7 +142,7 @@ struct TestUnit
TestFn func;
}
fn TestUnit[] test_collection_create(Allocator* allocator = allocator::heap())
fn TestUnit[] test_collection_create(Allocator allocator = allocator::heap())
{
TestFn[] fns = $$TEST_FNS;
String[] names = $$TEST_NAMES;

View File

@@ -31,6 +31,11 @@ fault NumberConversion
FLOAT_OUT_OF_RANGE,
}
/**
* Return a temporary String created using the formatting function.
*
* @param [in] fmt `The formatting string`
**/
macro String tformat(String fmt, ...)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
@@ -38,6 +43,11 @@ macro String tformat(String fmt, ...)
return str.str_view();
}
/**
* Return a temporary ZString created using the formatting function.
*
* @param [in] fmt `The formatting string`
**/
macro ZString tformat_zstr(String fmt, ...)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
@@ -45,7 +55,13 @@ macro ZString tformat_zstr(String fmt, ...)
return str.zstr_view();
}
macro String new_format(String fmt, ..., Allocator* allocator = allocator::heap())
/**
* Return a new String created using the formatting function.
*
* @param [in] fmt `The formatting string`
* @param [inout] allocator `The allocator to use`
**/
macro String new_format(String fmt, ..., Allocator allocator = allocator::heap())
{
@pool(allocator)
{
@@ -55,7 +71,13 @@ macro String new_format(String fmt, ..., Allocator* allocator = allocator::heap(
};
}
macro ZString new_format_zstr(String fmt, ..., Allocator* allocator = allocator::heap())
/**
* Return a new ZString created using the formatting function.
*
* @param [in] fmt `The formatting string`
* @param [inout] allocator `The allocator to use`
**/
macro ZString new_format_zstr(String fmt, ..., Allocator allocator = allocator::heap())
{
@pool(allocator)
{
@@ -65,13 +87,21 @@ macro ZString new_format_zstr(String fmt, ..., 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`
**/
macro bool char_in_set(char c, String set)
{
foreach (ch : set) if (ch == c) return true;
return false;
}
fn String join_new(String[] s, String joiner, Allocator* allocator = allocator::heap())
fn String join_new(String[] s, String joiner, Allocator allocator = allocator::heap())
{
if (!s)
{
@@ -97,8 +127,12 @@ fn String join_new(String[] s, String joiner, Allocator* allocator = allocator::
}
/**
* @param [in] string
* @param [in] to_trim
* 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 ")
{
@@ -112,8 +146,12 @@ fn String String.trim(string, String to_trim = "\t\n\r ")
}
/**
* 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)
{
@@ -123,8 +161,12 @@ fn bool String.starts_with(string, String 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)
{
@@ -138,6 +180,8 @@ fn bool String.ends_with(string, String needle)
*
* @param [in] string
* @param [in] needle
* @pure
* @return `the substring with the prefix removed`
**/
fn String String.strip(string, String needle)
{
@@ -150,6 +194,8 @@ fn String String.strip(string, String needle)
*
* @param [in] string
* @param [in] needle
* @pure
* @return `the substring with the suffix removed`
**/
fn String String.strip_end(string, String needle)
{
@@ -169,7 +215,7 @@ fn String String.strip_end(string, String needle)
* @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())
fn String[] String.split(s, String needle, usz max = 0, Allocator allocator = allocator::heap())
{
usz capacity = 16;
usz i = 0;
@@ -212,6 +258,14 @@ fn String[] String.tsplit(s, String needle, usz max = 0)
return s.split(needle, max, allocator::temp()) @inline;
}
/**
* 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"
**/
fn bool String.contains(s, String needle)
{
return @ok(s.index_of(needle));
@@ -221,6 +275,7 @@ fn bool String.contains(s, String 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"
@@ -236,9 +291,32 @@ fn usz! String.index_of_char(s, char needle)
}
/**
* Find the index of the first incidence of a string.
* 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;
if (len <= start_index) return SearchResult.MISSING?;
for (usz i = start_index; i < len; i++)
{
if (s[i] == needle) return i;
}
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"
@@ -328,7 +406,7 @@ fn usz ZString.len(str)
}
fn ZString String.zstr_copy(s, Allocator* allocator = allocator::heap())
fn ZString String.zstr_copy(s, Allocator allocator = allocator::heap())
{
usz len = s.len;
char* str = allocator::malloc(allocator, len + 1);
@@ -337,7 +415,7 @@ fn ZString String.zstr_copy(s, Allocator* allocator = allocator::heap())
return (ZString)str;
}
fn String String.concat(s1, String s2, Allocator* allocator = allocator::heap())
fn String String.concat(s1, String s2, Allocator allocator = allocator::heap())
{
usz full_len = s1.len + s2.len;
char* str = allocator::malloc(allocator, full_len + 1);
@@ -353,7 +431,7 @@ fn String String.tconcat(s1, String s2) => s1.concat(s2, allocator::temp());
fn ZString String.zstr_tcopy(s) => s.zstr_copy(allocator::temp()) @inline;
fn String String.copy(s, Allocator* allocator = allocator::heap())
fn String String.copy(s, Allocator allocator = allocator::heap())
{
usz len = s.len;
char* str = allocator::malloc(allocator, len + 1);
@@ -362,7 +440,7 @@ fn String String.copy(s, Allocator* allocator = allocator::heap())
return (String)str[:len];
}
fn void String.free(&s, Allocator* allocator = allocator::heap())
fn void String.free(&s, Allocator allocator = allocator::heap())
{
if (!s.len) return;
allocator::free(allocator, s.ptr);
@@ -371,7 +449,7 @@ fn void String.free(&s, Allocator* allocator = allocator::heap())
fn String String.tcopy(s) => s.copy(allocator::temp()) @inline;
fn String ZString.copy(z, Allocator* allocator = allocator::temp())
fn String ZString.copy(z, Allocator allocator = allocator::temp())
{
return z.str_view().copy(allocator) @inline;
}
@@ -387,7 +465,7 @@ fn String ZString.tcopy(z)
* @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())
fn Char16[]! String.to_new_utf16(s, Allocator allocator = allocator::heap())
{
usz len16 = conv::utf16len_for_utf8(s);
Char16* data = allocator::alloc_array_try(allocator, Char16, len16 + 1)!;
@@ -407,7 +485,7 @@ fn Char16[]! String.to_temp_utf16(s)
return s.to_new_utf16(allocator::temp());
}
fn WString! String.to_new_wstring(s, Allocator* allocator = allocator::heap())
fn WString! String.to_new_wstring(s, Allocator allocator = allocator::heap())
{
return (WString)s.to_new_utf16(allocator).ptr;
}
@@ -417,7 +495,7 @@ fn WString! String.to_temp_wstring(s)
return (WString)s.to_temp_utf16().ptr;
}
fn Char32[]! String.to_new_utf32(s, Allocator* allocator = allocator::heap())
fn Char32[]! String.to_new_utf32(s, Allocator allocator = allocator::heap())
{
usz codepoints = conv::utf8_codepoints(s);
Char32* data = allocator::alloc_array_try(allocator, Char32, codepoints + 1)!;
@@ -431,29 +509,49 @@ fn Char32[]! String.to_temp_utf32(s)
return s.to_new_utf32(allocator::temp());
}
/**
* 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()) *c += 'a' - 'A';
foreach (&c : s) if (c.is_upper() @pure) *c += 'a' - 'A';
}
fn String String.new_ascii_to_lower(s, Allocator* allocator = allocator::heap())
fn String String.new_ascii_to_lower(s, Allocator allocator = allocator::heap())
{
String copy = s.copy(allocator);
copy.convert_ascii_to_lower();
return copy;
}
fn String String.temp_ascii_to_lower(s, Allocator* allocator = allocator::heap())
fn String String.temp_ascii_to_lower(s, Allocator allocator = allocator::heap())
{
return s.new_ascii_to_lower(allocator::temp());
}
/**
* 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()) *c -= 'a' - 'A';
foreach (&c : s) if (c.is_lower() @pure) *c -= 'a' - 'A';
}
fn String String.new_ascii_to_upper(s, Allocator* allocator = allocator::heap())
/**
* 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);
copy.convert_ascii_to_upper();
@@ -465,12 +563,16 @@ fn StringIterator String.iterator(s)
return { s, 0 };
}
/**
* @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());
}
fn String! new_from_utf32(Char32[] utf32, Allocator* allocator = allocator::heap())
fn String! new_from_utf32(Char32[] utf32, Allocator allocator = allocator::heap())
{
usz len = conv::utf8len_for_utf32(utf32);
char* data = allocator::malloc_try(allocator, len + 1)!;
@@ -480,7 +582,7 @@ fn String! new_from_utf32(Char32[] utf32, Allocator* allocator = allocator::heap
return (String)data[:len];
}
fn String! new_from_utf16(Char16[] utf16, Allocator* allocator = allocator::heap())
fn String! new_from_utf16(Char16[] utf16, Allocator allocator = allocator::heap())
{
usz len = conv::utf8len_for_utf16(utf16);
char* data = allocator::malloc_try(allocator, len + 1)!;
@@ -490,7 +592,7 @@ fn String! new_from_utf16(Char16[] utf16, Allocator* allocator = allocator::heap
return (String)data[:len];
}
fn String! new_from_wstring(WString wstring, Allocator* allocator = allocator::heap())
fn String! new_from_wstring(WString wstring, Allocator allocator = allocator::heap())
{
usz utf16_len;
while (wstring[utf16_len] != 0) utf16_len++;

View File

@@ -11,7 +11,7 @@ fault ConversionResult
/**
* @require $Type.kindof.is_int() || $Type.kindof == TypeKind.ENUM "Argument was not an integer"
**/
macro any_to_int(any* v, $Type)
macro any_to_int(any v, $Type)
{
typeid any_type = v.type;
TypeKind kind = any_type.kindof;
@@ -108,10 +108,10 @@ fn bool TypeKind.is_int(kind) @inline
return kind == TypeKind.SIGNED_INT || kind == TypeKind.UNSIGNED_INT;
}
macro bool is_subarray_convertable($Type)
macro bool is_slice_convertable($Type)
{
$switch ($Type.kindof)
$case SUBARRAY:
$case SLICE:
return true;
$case POINTER:
return $Type.inner.kindof == TypeKind.ARRAY;
@@ -298,10 +298,11 @@ enum TypeKind : char
FUNC,
OPTIONAL,
ARRAY,
SUBARRAY,
SLICE,
VECTOR,
DISTINCT,
POINTER,
INTERFACE,
}
struct TypeEnum

View File

@@ -3,22 +3,22 @@ import std::io;
struct CsvReader
{
InStream* stream;
InStream stream;
String separator;
}
fn void CsvReader.init(&self, InStream* stream, String separator = ",")
fn void CsvReader.init(&self, InStream stream, String separator = ",")
{
self.stream = stream;
self.separator = separator;
}
fn String[]! CsvReader.read_new_row(self, Allocator* allocator = allocator::heap())
fn String[]! CsvReader.read_new_row(self, Allocator allocator = allocator::heap())
{
return self.read_new_row_with_allocator(allocator::temp()) @inline;
}
fn String[]! CsvReader.read_new_row_with_allocator(self, Allocator* allocator = allocator::heap())
fn String[]! CsvReader.read_new_row_with_allocator(self, Allocator allocator = allocator::heap())
{
@pool(allocator)
{
@@ -45,7 +45,7 @@ macro CsvReader.@each_row(self, int rows = int.max; @body(String[] row))
String sep = self.separator;
while (rows--)
{
@stack_mem(512; Allocator* mem)
@stack_mem(512; Allocator mem)
{
String[] parts;
@pool()

View File

@@ -15,7 +15,7 @@ fault JsonParsingError
INVALID_NUMBER,
}
fn Object*! parse(InStream* s, Allocator* allocator = allocator::heap())
fn Object*! parse(InStream s, Allocator allocator = allocator::heap())
{
JsonContext context = { .last_string = dstring::new_with_capacity(64, allocator), .stream = s, .allocator = allocator };
defer context.last_string.free();
@@ -44,8 +44,8 @@ enum JsonTokenType @local
struct JsonContext @local
{
uint line;
InStream* stream;
Allocator* allocator;
InStream stream;
Allocator allocator;
JsonTokenType token;
DString last_string;
double last_number;
@@ -170,7 +170,7 @@ fn Object*! parse_array(JsonContext* context) @local
while (token != JsonTokenType.RBRACKET)
{
Object* element = parse_from_token(context, token)!;
list.append(element);
list.push(element);
token = advance(context)!;
if (token == JsonTokenType.COMMA)
{

View File

@@ -2,12 +2,12 @@ module std::io;
struct BitReader
{
InStream* reader;
InStream reader;
uint bits;
uint len;
}
fn void BitReader.init(&self, InStream* byte_reader)
fn void BitReader.init(&self, InStream byte_reader)
{
*self = { .reader = byte_reader };
}
@@ -40,12 +40,12 @@ fn char! BitReader.read_bits(&self, uint nbits)
struct BitWriter
{
OutStream* writer;
OutStream writer;
uint bits;
uint len;
}
fn void BitWriter.init(&self, OutStream* byte_writer)
fn void BitWriter.init(&self, OutStream byte_writer)
{
*self = { .writer = byte_writer };
}

View File

@@ -161,7 +161,7 @@ fn char[]! load_buffer(String filename, char[] buffer)
}
fn char[]! load_new(String filename, Allocator* allocator = allocator::heap())
fn char[]! load_new(String filename, Allocator allocator = allocator::heap())
{
File file = open(filename, "rb")!;
defer (void)file.close();

View File

@@ -6,7 +6,7 @@ const int PRINTF_NTOA_BUFFER_SIZE = 256;
interface Printable
{
fn String to_new_string(Allocator *allocator) @optional;
fn String to_new_string(Allocator allocator) @optional;
fn usz! to_format(Formatter* formatter) @optional;
}
@@ -72,7 +72,7 @@ fn usz! Formatter.out(&self, char c) @private
return 1;
}
fn usz! Formatter.print_with_function(&self, Printable* arg)
fn usz! Formatter.print_with_function(&self, Printable arg)
{
if (&arg.to_format)
{
@@ -98,7 +98,7 @@ fn usz! Formatter.print_with_function(&self, Printable* arg)
self.width = old_width;
self.prec = old_prec;
}
@stack_mem(1024; Allocator* mem)
@stack_mem(1024; Allocator mem)
{
return self.out_substr(arg.to_new_string(mem));
};
@@ -107,7 +107,7 @@ fn usz! Formatter.print_with_function(&self, Printable* arg)
}
fn usz! Formatter.out_str(&self, any* arg) @private
fn usz! Formatter.out_str(&self, any arg) @private
{
switch (arg.type.kindof)
{
@@ -119,7 +119,7 @@ fn usz! Formatter.out_str(&self, any* arg) @private
case FAULT:
return self.out_substr((*(anyfault*)arg.ptr).nameof);
case ANY:
return self.out_str(*(any**)arg);
return self.out_str(*(any*)arg);
case OPTIONAL:
unreachable();
case SIGNED_INT:
@@ -149,7 +149,7 @@ fn usz! Formatter.out_str(&self, any* arg) @private
return self.out_substr(*(bool*)arg.ptr ? "true" : "false");
default:
}
usz! n = self.print_with_function((Printable*)arg);
usz! n = self.print_with_function((Printable)arg);
if (catch err = n)
{
case SearchResult.MISSING:
@@ -246,7 +246,7 @@ fn usz! Formatter.out_str(&self, any* arg) @private
}
len += self.out_substr(">]")!;
return len;
case SUBARRAY:
case SLICE:
// this is SomeType[] so grab the "SomeType"
typeid inner = arg.type.inner;
if (inner == char.typeid)
@@ -291,7 +291,7 @@ fn void! out_null_fn(void* data @unused, char c @unused) @private
fn usz! Formatter.vprintf(&self, String format, any*[] anys)
fn usz! Formatter.vprintf(&self, String format, any[] anys)
{
if (!self.out_fn)
{
@@ -358,7 +358,7 @@ fn usz! Formatter.vprintf(&self, String format, any*[] anys)
// evaluate specifier
uint base = 0;
if (variant_index >= anys.len) return PrintFault.MISSING_ARG?;
any* current = anys[variant_index++];
any current = anys[variant_index++];
switch (c)
{
case 'd':

View File

@@ -10,7 +10,7 @@ fn usz! Formatter.adjust(&self, usz len) @local
return self.pad(' ', self.width, len);
}
fn uint128! int_from_any(any* arg, bool *is_neg) @private
fn uint128! int_from_any(any arg, bool *is_neg) @private
{
switch (arg.type.kindof)
{
@@ -63,14 +63,11 @@ fn uint128! int_from_any(any* arg, bool *is_neg) @private
}
}
fn FloatType! float_from_any(any* arg) @private
fn FloatType! float_from_any(any arg) @private
{
$if env::F128_SUPPORT:
if (arg.type == float128.typeid) return (FloatType)*((float128*)arg.ptr);
$endif
$if env::F16_SUPPORT:
if (arg.type == float16.typeid) return *((float16*)arg.ptr);
$endif
if (arg.type.kindof == TypeKind.DISTINCT)
{
return float_from_any(arg.as_inner());
@@ -588,14 +585,14 @@ fn usz! Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
}
fn usz! Formatter.ntoa_any(&self, any* arg, uint base) @private
fn usz! Formatter.ntoa_any(&self, any arg, uint base) @private
{
bool is_neg;
uint128 val = int_from_any(arg, &is_neg)!!;
return self.ntoa(val, is_neg, base) @inline;
}
fn usz! Formatter.out_char(&self, any* arg) @private
fn usz! Formatter.out_char(&self, any arg) @private
{
usz len = 1;
uint l = 1;
@@ -649,21 +646,21 @@ fn void! printf_advance_format(usz format_len, usz *index_ptr) @inline @private
if (val >= format_len) return FormattingFault.UNTERMINATED_FORMAT?;
}
fn any*! next_any(any** args_ptr, usz args_len, usz* arg_index_ptr) @inline @private
fn any! next_any(any* args_ptr, usz args_len, usz* arg_index_ptr) @inline @private
{
if (*arg_index_ptr >= args_len) return FormattingFault.MISSING_ARG?;
return args_ptr[(*arg_index_ptr)++];
}
fn int! printf_parse_format_field(
any** args_ptr, usz args_len, usz* args_index_ptr,
any* args_ptr, usz args_len, usz* args_index_ptr,
char* format_ptr, usz format_len, usz* index_ptr) @inline @private
{
char c = format_ptr[*index_ptr];
if (c.is_digit()) return simple_atoi(format_ptr, format_len, index_ptr);
if (c != '*') return 0;
printf_advance_format(format_len, index_ptr)!;
any* val = next_any(args_ptr, args_len, args_index_ptr)!;
any val = next_any(args_ptr, args_len, args_index_ptr)!;
if (!val.type.kindof.is_int()) return FormattingFault.INVALID_WIDTH_ARG?;
uint! intval = types::any_to_int(val, int);
return intval ?? FormattingFault.INVALID_WIDTH_ARG?;

View File

@@ -49,9 +49,9 @@ fault IoError
* @param stream
* @require @is_instream(stream)
**/
macro String! readline(stream = io::stdin(), Allocator* allocator = allocator::heap())
macro String! readline(stream = io::stdin(), Allocator allocator = allocator::heap())
{
bool $is_stream = @typeid(stream) == InStream*.typeid;
bool $is_stream = @typeid(stream) == InStream.typeid;
$if $is_stream:
$typeof(&stream.read_byte) func = &stream.read_byte;
char val = func((void*)stream)!;
@@ -108,14 +108,14 @@ macro usz! fprint(out, x)
$endswitch
}
fn usz! fprintf(OutStream* out, String format, args...)
fn usz! fprintf(OutStream out, String format, args...)
{
Formatter formatter;
formatter.init(&out_putstream_fn, &out);
return formatter.vprintf(format, args);
}
fn usz! fprintfn(OutStream* out, String format, args...) @maydiscard
fn usz! fprintfn(OutStream out, String format, args...) @maydiscard
{
Formatter formatter;
formatter.init(&out_putstream_fn, &out);
@@ -133,7 +133,7 @@ macro usz! fprintn(out, x = "")
usz len = fprint(out, x)!;
out.write_byte('\n')!;
$switch
$case @typeid(out) == OutStream*.typeid:
$case @typeid(out) == OutStream.typeid:
if (&out.flush) out.flush()!;
$case $defined(out.flush):
out.flush()!;
@@ -164,7 +164,7 @@ macro void eprintn(x)
fn void! out_putstream_fn(void* data, char c) @private
{
OutStream** stream = data;
OutStream* stream = data;
return (*stream).write_byte(c);
}
@@ -193,7 +193,7 @@ fn usz! printfn(String format, args...) @maydiscard
fn usz! eprintf(String format, args...) @maydiscard
{
Formatter formatter;
OutStream* stream = stderr();
OutStream stream = stderr();
formatter.init(&out_putstream_fn, &stream);
return formatter.vprintf(format, args);
}
@@ -202,7 +202,7 @@ fn usz! eprintf(String format, args...) @maydiscard
fn usz! eprintfn(String format, args...) @maydiscard
{
Formatter formatter;
OutStream* stream = stderr();
OutStream stream = stderr();
formatter.init(&out_putstream_fn, &stream);
usz len = formatter.vprintf(format, args)! + 1;
stderr().write_byte('\n')!;

View File

@@ -1,7 +1,7 @@
module std::io::os;
import libc, std::os;
macro String! getcwd(Allocator* allocator = allocator::heap())
macro String! getcwd(Allocator allocator = allocator::heap())
{
$switch
$case env::WIN32:

View File

@@ -1,7 +1,7 @@
module std::io::os @if(env::POSIX);
import std::io, std::os;
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator* allocator)
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator)
{
PathList list;
list.new_init(.allocator = allocator);
@@ -16,7 +16,7 @@ fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al
if (entry.d_type == posix::DT_LNK && no_symlinks) continue;
if (entry.d_type == posix::DT_DIR && no_dirs) continue;
Path path = path::new(name, allocator)!!;
list.append(path);
list.push(path);
}
return list;
}
@@ -24,7 +24,7 @@ fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al
module std::io::os @if(env::WIN32);
import std::time, std::os, std::io;
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator* allocator)
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator)
{
PathList list;
list.new_init(.allocator = allocator);
@@ -43,7 +43,7 @@ fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al
{
String filename = string::temp_from_wstring((WString)&find_data.cFileName)!;
if (filename == ".." || filename == ".") continue;
list.append(path::new(filename, allocator)!);
list.push(path::new(filename, allocator)!);
};
} while (win32::findNextFileW(find, &find_data));
return list;

View File

@@ -1,7 +1,7 @@
module std::io::os @if(env::LIBC);
import std::io::path, std::os;
fn Path! native_temp_directory(Allocator* allocator = allocator::heap()) @if(!env::WIN32)
fn Path! native_temp_directory(Allocator allocator = allocator::heap()) @if(!env::WIN32)
{
foreach (String env : { "TMPDIR", "TMP", "TEMP", "TEMPDIR" })
{
@@ -11,7 +11,7 @@ fn Path! native_temp_directory(Allocator* allocator = allocator::heap()) @if(!en
return path::new("/tmp", allocator);
}
fn Path! native_temp_directory(Allocator* allocator = allocator::heap()) @if(env::WIN32)
fn Path! native_temp_directory(Allocator allocator = allocator::heap()) @if(env::WIN32)
{
@pool(allocator)
{
@@ -25,7 +25,7 @@ fn Path! native_temp_directory(Allocator* allocator = allocator::heap()) @if(env
module std::io::os @if(env::NO_LIBC);
macro Path! native_temp_directory(Allocator* allocator = allocator::heap())
macro Path! native_temp_directory(Allocator allocator = allocator::heap())
{
return IoError.UNSUPPORTED_OPERATION?;
}

View File

@@ -1,5 +1,6 @@
module std::io::path;
import std::collections::list, std::io::os;
import std::os::win32;
const PathEnv DEFAULT_PATH_ENV = env::WIN32 ? PathEnv.WIN32 : PathEnv.POSIX;
const char PREFERRED_SEPARATOR_WIN32 = '\\';
@@ -26,7 +27,7 @@ enum PathEnv
POSIX
}
fn Path! getcwd(Allocator* allocator = allocator::heap())
fn Path! getcwd(Allocator allocator = allocator::heap())
{
@pool(allocator)
{
@@ -40,7 +41,7 @@ fn usz! file_size(Path path) => os::native_file_size(path.str_view());
fn bool exists(Path path) => os::native_file_or_dir_exists(path.str_view());
fn Path! tgetcwd() => getcwd(allocator::temp()) @inline;
fn void! chdir(Path path) => os::native_chdir(path) @inline;
fn Path! temp_directory(Allocator* allocator = allocator::heap()) => os::native_temp_directory(allocator);
fn Path! temp_directory(Allocator allocator = allocator::heap()) => os::native_temp_directory(allocator);
fn void! delete(Path path) => os::native_remove(path.str_view()) @inline;
macro bool is_separator(char c, PathEnv path_env = DEFAULT_PATH_ENV)
@@ -58,7 +59,7 @@ macro bool is_win32_separator(char c)
return c == '/' || c == '\\';
}
fn PathList! ls(Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "", Allocator* allocator = allocator::heap())
fn PathList! ls(Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "", Allocator allocator = allocator::heap())
{
$if $defined(os::native_ls):
return os::native_ls(dir, no_dirs, no_symlinks, mask, allocator);
@@ -105,7 +106,7 @@ fn void! rmtree(Path path)
$endif
}
fn Path! new(String path, Allocator* allocator = allocator::heap(), PathEnv path_env = DEFAULT_PATH_ENV)
fn Path! new(String path, Allocator allocator = allocator::heap(), PathEnv path_env = DEFAULT_PATH_ENV)
{
return { normalize(path.copy(allocator), path_env), path_env };
}
@@ -115,7 +116,7 @@ fn Path! temp_new(String path, PathEnv path_env = DEFAULT_PATH_ENV)
return new(path, allocator::temp(), path_env);
}
fn Path! new_win32_wstring(WString path, Allocator* allocator = allocator::heap())
fn Path! new_win32_wstring(WString path, Allocator allocator = allocator::heap())
{
@pool(allocator)
{
@@ -123,12 +124,12 @@ fn Path! new_win32_wstring(WString path, Allocator* allocator = allocator::heap(
};
}
fn Path! new_windows(String path, Allocator* allocator = allocator::heap())
fn Path! new_windows(String path, Allocator allocator = allocator::heap())
{
return new(path, allocator, WIN32);
}
fn Path! new_posix(String path, Allocator* allocator = allocator::heap())
fn Path! new_posix(String path, Allocator allocator = allocator::heap())
{
return new(path, allocator, POSIX);
}
@@ -143,7 +144,7 @@ fn bool Path.equals(self, Path p2)
*
* @param [in] filename
**/
fn Path! Path.append(self, String filename, Allocator* allocator = allocator::heap())
fn Path! Path.append(self, String filename, Allocator allocator = allocator::heap())
{
if (!self.path_string.len) return new(filename, allocator, self.env)!;
assert(!is_separator(self.path_string[^1], self.env));
@@ -166,7 +167,19 @@ fn usz Path.start_of_base_name(self) @local
if (!path_str.len) return 0;
if (self.env == PathEnv.WIN32)
{
return path_str.rindex_of_char('\\') + 1 ?? volume_name_len(path_str, self.env)!!;
if (try index = path_str.rindex_of_char('\\'))
{
// c:\ style path, we're done!
if (path_str[0] != '\\') return index + 1;
// Handle \\server\foo
// Find the \ before "foo"
usz last_index = 2 + path_str[2..].index_of_char('\\')!!;
// If they don't match, we're done
assert(last_index <= index, "Invalid normalized, path %d vs %s in %s", last_index, index, path_str);
if (last_index != index) return index + 1;
// Otherwise just default to the volume length.
}
return volume_name_len(path_str, self.env)!!;
}
return path_str.rindex_of_char('/') + 1 ?? 0;
}
@@ -176,28 +189,39 @@ fn bool! Path.is_absolute(self)
String path_str = self.str_view();
if (!path_str.len) return false;
usz path_start = volume_name_len(path_str, self.env)!;
if (path_start > 0 && path_str[0] == '\\') return true;
return path_start < path_str.len && is_separator(path_str[path_start], self.env);
}
fn Path! Path.absolute(self, Allocator* allocator = allocator::heap())
/**
* @require self.env == DEFAULT_PATH_ENV : "This method is only available on native paths"
**/
fn Path! Path.absolute(self, Allocator allocator = allocator::heap())
{
String path_str = self.str_view();
if (!path_str.len) path_str = ".";
if (!path_str.len) return PathResult.INVALID_PATH?;
if (self.is_absolute()!) return new(path_str, allocator, self.env);
if (path_str == ".")
{
@pool(allocator)
{
String cwd = os::getcwd(allocator::temp())!;
return new(cwd, allocator, self.env);
};
}
$if DEFAULT_PATH_ENV == WIN32:
@pool(allocator)
{
const usz BUFFER_LEN = 4096;
WString buffer = (WString)mem::temp_alloc_array(Char16, BUFFER_LEN);
buffer = win32::_wfullpath(buffer, path_str.to_temp_wstring()!, BUFFER_LEN);
if (!buffer) return PathResult.INVALID_PATH?;
return { string::new_from_wstring(buffer, allocator), WIN32 };
};
$else
String cwd = os::getcwd(allocator::temp())!;
return new(cwd, allocator, self.env);
}
switch (self.env)
{
case WIN32:
usz path_start = volume_name_len(path_str, self.env)!;
if (path_start > 0) return self;
case POSIX:
if (path_str[0] == PREFERRED_SEPARATOR_POSIX) return self;
}
String cwd = os::getcwd(allocator::temp())!;
return Path{ cwd, self.env }.append(path_str, allocator)!;
return Path { cwd, self.env }.append(path_str, allocator)!;
$endif
}
fn String Path.basename(self)
@@ -208,13 +232,21 @@ fn String Path.basename(self)
return path_str[basename_start..];
}
fn String Path.dirname(self)
{
usz basename_start = self.start_of_base_name();
String path_str = self.path_string;
if (basename_start == 0) return "";
if (basename_start == 0) return ".";
usz start = volume_name_len(path_str, self.env)!!;
if (basename_start <= start + 1) return path_str[:basename_start];
if (basename_start <= start + 1)
{
if (self.env == WIN32 && basename_start > start && path_str[0..1] == `\\`)
{
return path_str[:basename_start - 1];
}
return path_str[:basename_start];
}
return path_str[:basename_start - 1];
}
@@ -248,13 +280,20 @@ fn usz! volume_name_len(String path, PathEnv path_env) @local
while (count < len && path[count] == '\\') count++;
// Not 2 => folded paths
if (count != 2) return 0;
// Check that we have a name followed by '/'
// Check that we have a name followed by '\'
isz base_found = 0;
for (usz i = 2; i < len; i++)
{
char c = path[i];
if (is_win32_separator(c)) return i;
if (is_win32_separator(c))
{
if (base_found) return i;
base_found = i;
continue;
}
if (is_reserved_win32_path_char(c)) return PathResult.INVALID_PATH?;
}
if (base_found > 0 && base_found + 1 < len) return len;
return PathResult.INVALID_PATH?;
case 'A'..'Z':
case 'a'..'z':
@@ -281,6 +320,10 @@ fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV)
{
if (!path_str.len) return "";
usz path_start = volume_name_len(path_str, path_env)!;
if (path_start > 0 && path_env == PathEnv.WIN32)
{
for (usz i = 0; i < path_start; i++) if (path_str[i] == '/') path_str[i] = '\\';
}
usz path_len = path_str.len;
if (path_start == path_len) return path_str;
char path_separator = path_env == PathEnv.WIN32 ? PREFERRED_SEPARATOR_WIN32 : PREFERRED_SEPARATOR_POSIX;
@@ -384,7 +427,9 @@ fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV)
len++;
}
if (len > path_start + 1 && is_separator(path_str[len - 1], path_env)) len--;
path_str.ptr[len] = 0;
if (path_str.len > len) path_str.ptr[len] = 0;
// Empty path after normalization -> "."
if (!len) return ".";
return path_str[:len];
}
@@ -395,6 +440,7 @@ fn String Path.root_directory(self)
String path_str = self.str_view();
usz len = path_str.len;
if (!len) return "";
if (path_str == ".") return ".";
if (self.env == PathEnv.WIN32)
{
usz root_len = volume_name_len(path_str, self.env)!!;
@@ -417,11 +463,12 @@ 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"
*/
fn bool! Path.walk(self, PathWalker w, void* data)
{
const PATH_MAX = 512;
@stack_mem(PATH_MAX; Allocator* allocator)
@stack_mem(PATH_MAX; Allocator allocator)
{
Path abs = self.absolute(allocator)!;
PathList files = ls(abs, .allocator = allocator)!;
@@ -448,6 +495,11 @@ fn bool Path.has_suffix(self, String str)
return self.str_view().ends_with(str);
}
fn void Path.free_with_allocator(self, Allocator allocator)
{
allocator::free(allocator, self.path_string.ptr);
}
fn void Path.free(self)
{
free(self.path_string.ptr);
@@ -459,7 +511,7 @@ fn usz! Path.to_format(&self, Formatter* formatter) @dynamic
return formatter.print(self.str_view());
}
fn String Path.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic
fn String Path.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
{
return self.str_view().copy(allocator);
}

View File

@@ -9,7 +9,7 @@ interface InStream
fn usz! available() @optional;
fn usz! read(char[] buffer);
fn char! read_byte();
fn usz! write_to(OutStream* out) @optional;
fn usz! write_to(OutStream out) @optional;
fn void! pushback_byte() @optional;
}
@@ -21,10 +21,10 @@ interface OutStream
fn void! flush() @optional;
fn usz! write(char[] bytes);
fn void! write_byte(char c);
fn usz! read_to(InStream* in) @optional;
fn usz! read_to(InStream in) @optional;
}
fn usz! available(InStream* s)
fn usz! available(InStream s)
{
if (&s.available) return s.available();
if (&s.seek)
@@ -39,19 +39,19 @@ fn usz! available(InStream* s)
macro bool @is_instream(#expr)
{
return $assignable(#expr, InStream*);
return $assignable(#expr, InStream);
}
macro bool @is_outstream(#expr)
{
return $assignable(#expr, OutStream*);
return $assignable(#expr, OutStream);
}
/**
* @param [&out] ref
* @require @is_instream(stream)
**/
macro usz! read_any(stream, any* ref)
macro usz! read_any(stream, any ref)
{
return read_all(stream, ((char*)ref)[:ref.type.sizeof]);
}
@@ -61,7 +61,7 @@ macro usz! read_any(stream, any* ref)
* @require @is_outstream(stream)
* @ensure return == ref.type.sizeof
*/
macro usz! write_any(stream, any* ref)
macro usz! write_any(stream, any ref)
{
return write_all(stream, ((char*)ref)[:ref.type.sizeof]);
}
@@ -134,7 +134,7 @@ macro void! @pushback_using_seek(&s)
s.seek(-1, CURSOR)!;
}
fn usz! copy_to(InStream* in, OutStream* dst, char[] buffer = {})
fn usz! copy_to(InStream in, OutStream dst, char[] buffer = {})
{
if (buffer.len) return copy_through_buffer(in, dst, buffer);
if (&in.write_to) return in.write_to(dst);
@@ -156,7 +156,7 @@ fn usz! copy_to(InStream* in, OutStream* dst, char[] buffer = {})
$endswitch
}
macro usz! copy_through_buffer(InStream *in, OutStream* dst, char[] buffer) @local
macro usz! copy_through_buffer(InStream in, OutStream dst, char[] buffer) @local
{
usz total_copied;
while (true)

View File

@@ -2,7 +2,7 @@ module std::io;
struct ReadBuffer (InStream)
{
InStream* wrapped_stream;
InStream wrapped_stream;
char[] bytes;
usz read_idx;
usz write_idx;
@@ -14,7 +14,7 @@ struct ReadBuffer (InStream)
* @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)
fn ReadBuffer* ReadBuffer.init(&self, InStream wrapped_stream, char[] bytes)
{
*self = { .wrapped_stream = wrapped_stream, .bytes = bytes };
return self;
@@ -63,7 +63,7 @@ fn void! ReadBuffer.refill(&self) @local @inline
struct WriteBuffer (OutStream)
{
OutStream* wrapped_stream;
OutStream wrapped_stream;
char[] bytes;
usz index;
}
@@ -74,7 +74,7 @@ struct WriteBuffer (OutStream)
* @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)
fn WriteBuffer* WriteBuffer.init(&self, OutStream wrapped_stream, char[] bytes)
{
*self = { .wrapped_stream = wrapped_stream, .bytes = bytes };
return self;

View File

@@ -3,7 +3,7 @@ import std::math;
struct ByteBuffer (InStream, OutStream)
{
Allocator* allocator;
Allocator allocator;
usz max_read;
char[] bytes;
usz read_idx;
@@ -16,17 +16,7 @@ struct ByteBuffer (InStream, OutStream)
* 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.init_new(&self, usz max_read, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
{
return self.new_init(max_read, initial_capacity, allocator) @inline;
}
/**
* 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())
fn ByteBuffer*! ByteBuffer.new_init(&self, usz max_read, usz initial_capacity = 16, Allocator allocator = allocator::heap())
{
*self = { .allocator = allocator, .max_read = max_read };
initial_capacity = max(initial_capacity, 16);
@@ -34,11 +24,6 @@ fn ByteBuffer*! ByteBuffer.new_init(&self, usz max_read, usz initial_capacity =
return self;
}
fn ByteBuffer*! ByteBuffer.init_temp(&self, usz max_read, usz initial_capacity = 16) @deprecated("Replaced by temp_init")
{
return self.temp_init(max_read, initial_capacity) @inline;
}
fn ByteBuffer*! ByteBuffer.temp_init(&self, usz max_read, usz initial_capacity = 16)
{
return self.new_init(max_read, initial_capacity, allocator::temp());

View File

@@ -53,7 +53,7 @@ fn usz! ByteReader.seek(&self, isz offset, Seek seek) @dynamic
return new_index;
}
fn usz! ByteReader.write_to(&self, OutStream* writer) @dynamic
fn usz! ByteReader.write_to(&self, OutStream writer) @dynamic
{
if (self.index >= self.bytes.len) return 0;
usz written = writer.write(self.bytes[self.index..])!;

View File

@@ -5,7 +5,7 @@ struct ByteWriter (OutStream)
{
char[] bytes;
usz index;
Allocator* allocator;
Allocator allocator;
}
/**
@@ -14,23 +14,12 @@ struct ByteWriter (OutStream)
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
* @ensure (bool)allocator, self.index == 0
**/
fn ByteWriter* ByteWriter.new_init(&self, Allocator* allocator = allocator::heap())
fn ByteWriter* ByteWriter.new_init(&self, Allocator allocator = allocator::heap())
{
*self = { .bytes = {}, .allocator = allocator };
return self;
}
/**
* @param [&inout] self
* @param [&inout] allocator
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
* @ensure (bool)allocator, self.index == 0
**/
fn ByteWriter* ByteWriter.init_new(&self, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
{
return self.new_init(allocator) @inline;
}
/**
* @param [&inout] self
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
@@ -41,16 +30,6 @@ fn ByteWriter* ByteWriter.temp_init(&self)
return self.new_init(allocator::temp()) @inline;
}
/**
* @param [&inout] self
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
* @ensure self.index == 0
**/
fn ByteWriter* ByteWriter.init_temp(&self) @deprecated("Replaced by temp_init")
{
return self.temp_init() @inline;
}
fn ByteWriter* ByteWriter.init_with_buffer(&self, char[] data)
{
*self = { .bytes = data, .allocator = null };
@@ -97,7 +76,7 @@ fn void! ByteWriter.write_byte(&self, char c) @dynamic
* @param [&inout] self
* @param reader
**/
fn usz! ByteWriter.read_from(&self, InStream* reader) @dynamic
fn usz! ByteWriter.read_from(&self, InStream reader) @dynamic
{
usz start_index = self.index;
if (&reader.available)

View File

@@ -2,7 +2,7 @@ module std::io;
struct LimitReader (InStream)
{
InStream* wrapped_stream;
InStream wrapped_stream;
usz limit;
}
@@ -10,7 +10,7 @@ struct LimitReader (InStream)
* @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)
fn LimitReader* LimitReader.init(&self, InStream wrapped_stream, usz limit)
{
*self = { .wrapped_stream = wrapped_stream, .limit = limit };
return self;

View File

@@ -2,7 +2,7 @@ module std::io;
struct Scanner (InStream)
{
InStream* wrapped_stream;
InStream wrapped_stream;
char[] buf;
usz pattern_idx;
usz read_idx;
@@ -16,7 +16,7 @@ struct Scanner (InStream)
* @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)
fn void Scanner.init(&self, InStream stream, char[] buffer)
{
*self = { .wrapped_stream = stream, .buf = buffer };
}

View File

@@ -92,15 +92,13 @@ fault MatrixError
def Complexf = Complex(<float>);
def Complex = Complex(<double>);
def complexf_identity = complex::identity(<float>);
def complex_identity = complex::identity(<double>);
def COMPLEX_IDENTITY = complex::IDENTITY(<double>);
def COMPLEXF_IDENTITY = complex::IDENTITY(<float>);
def Quaternionf = Quaternion(<float>);
def Quaternion = Quaternion(<double>);
def QUATERNION_IDENTITY = quaternion::IDENTITY(<double>);
def QUATERNIONF_IDENTITY = quaternion::IDENTITY(<float>);
def quaternion_identity = quaternion::identity(<double>);
def quaternionf_identity = quaternion::identity(<float>);
def Matrix2f = Matrix2x2(<float>);
def Matrix2 = Matrix2x2(<double>);

View File

@@ -10,7 +10,7 @@ union Complex
}
macro Complex identity() => { 1, 0 };
const Complex IDENTITY = { 1, 0 };
macro Complex Complex.add(self, Complex b) => Complex { .v = self.v + b.v };
macro Complex Complex.add_each(self, Real b) => Complex { .v = self.v + b };
macro Complex Complex.sub(self, Complex b) => Complex { .v = self.v - b.v };

View File

@@ -11,7 +11,6 @@ union Quaternion
const Quaternion IDENTITY = { 0, 0, 0, 1 };
macro Quaternion identity() @deprecated("Replaced with QUATERNION_IDENTITY constant") => { 0, 0, 0, 1 };
macro Quaternion Quaternion.add(Quaternion a, Quaternion b) => Quaternion { .v = a.v + b.v };
macro Quaternion Quaternion.add_each(Quaternion a, Real b) => Quaternion { .v = a.v + b };
macro Quaternion Quaternion.sub(Quaternion a, Quaternion b) => Quaternion { .v = a.v - b.v };

View File

@@ -4,9 +4,9 @@ import std::ascii;
enum IpProtocol : char (AIFamily ai_family)
{
UNSPECIFIED (os::AF_UNSPEC),
IPV4 (os::AF_INET),
IPV6 (os::AF_INET6),
UNSPECIFIED = os::AF_UNSPEC,
IPV4 = os::AF_INET,
IPV6 = os::AF_INET6,
}
struct InetAddress (Printable)
@@ -56,7 +56,7 @@ fn usz! InetAddress.to_format(InetAddress* addr, Formatter* formatter) @dynamic
return formatter.printf("%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!;
}
fn String InetAddress.to_new_string(InetAddress* addr, Allocator* allocator = allocator::heap()) @dynamic
fn String InetAddress.to_new_string(InetAddress* addr, Allocator allocator = allocator::heap()) @dynamic
{
if (addr.is_ipv6)
{

View File

@@ -57,7 +57,7 @@ fn uint! ipv4toint(String s)
return out;
}
fn String! int_to_new_ipv4(uint val, Allocator* allocator = allocator::heap())
fn String! int_to_new_ipv4(uint val, Allocator allocator = allocator::heap())
{
char[3 * 4 + 3 + 1] buffer;
String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", val >> 24, (val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF)!;

View File

@@ -83,12 +83,12 @@ macro Socket new_socket(fd, ai)
enum SocketOption : char (CInt value)
{
REUSEADDR (os::SO_REUSEADDR),
REUSEPORT (os::SO_REUSEPORT) @if(!env::WIN32),
KEEPALIVE (os::SO_KEEPALIVE),
BROADCAST (os::SO_BROADCAST),
OOBINLINE (os::SO_OOBINLINE),
DONTROUTE (os::SO_DONTROUTE),
REUSEADDR = os::SO_REUSEADDR,
REUSEPORT @if(!env::WIN32) = os::SO_REUSEPORT,
KEEPALIVE = os::SO_KEEPALIVE,
BROADCAST = os::SO_BROADCAST,
OOBINLINE = os::SO_OOBINLINE,
DONTROUTE = os::SO_DONTROUTE,
}
fn bool! Socket.get_broadcast(&self) => self.get_option(BROADCAST);

View File

@@ -10,7 +10,7 @@ fault BacktraceFault
RESOLUTION_FAILED,
}
const Backtrace BACKTRACE_UNKNOWN = { 0, "", "", "", 0, null };
const Backtrace BACKTRACE_UNKNOWN = { 0, "", "", "", 0, null, false };
struct Backtrace (Printable)
{
@@ -19,7 +19,8 @@ struct Backtrace (Printable)
String object_file;
String file;
uint line;
Allocator* allocator;
Allocator allocator;
bool is_inline;
}
@@ -35,15 +36,16 @@ fn bool Backtrace.is_unknown(&self)
fn usz! Backtrace.to_format(&self, Formatter* formatter) @dynamic
{
String inline_suffix = self.is_inline ? " [inline]" : "";
if (self.has_file())
{
return formatter.printf("%s (in %s) (%s:%d)", self.function, self.object_file, self.file, self.line);
return formatter.printf("%s (in %s) (%s:%d)%s", self.function, self.object_file, self.file, self.line, inline_suffix);
}
if (self.is_unknown())
{
return formatter.printf("??? (in unknown)");
return formatter.printf("??? (in unknown)%s", inline_suffix);
}
return formatter.printf("%s (in %s) (source unavailable)", self.function, self.object_file);
return formatter.printf("%s (in %s) (source unavailable)%s", self.function, self.object_file, inline_suffix);
}
fn void Backtrace.free(&self)
{
@@ -53,7 +55,7 @@ fn void Backtrace.free(&self)
allocator::free(self.allocator, self.file);
}
fn Backtrace* Backtrace.init(&self, uptr offset, String function, String object_file, String file = "", uint line = 0, Allocator* allocator)
fn Backtrace* Backtrace.init(&self, uptr offset, String function, String object_file, String file = "", uint line = 0, Allocator allocator)
{
if (!allocator)
{
@@ -95,7 +97,7 @@ def symbolize_backtrace = linux::symbolize_backtrace @if(env::LINUX);
def symbolize_backtrace = win32::symbolize_backtrace @if(env::WIN32);
def symbolize_backtrace = darwin::symbolize_backtrace @if(env::DARWIN);
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator) @if(!env::NATIVE_STACKTRACE)
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator allocator) @if(!env::NATIVE_STACKTRACE)
{
return {};
}

View File

@@ -9,7 +9,7 @@ import std::io::path, libc, std::os;
* @require name.len > 0
* @return! SearchResult.MISSING
**/
fn String! get_var(String name, Allocator* allocator = allocator::heap())
fn String! get_var(String name, Allocator allocator = allocator::heap())
{
@pool(allocator)
{
@@ -72,7 +72,7 @@ fn bool set_var(String name, String value, bool overwrite = true)
/**
* Returns the current user's home directory.
**/
fn String! get_home_dir(Allocator* using = allocator::heap())
fn String! get_home_dir(Allocator using = allocator::heap())
{
String home;
$if !env::WIN32:
@@ -86,7 +86,7 @@ fn String! get_home_dir(Allocator* using = allocator::heap())
/**
* Returns the current user's config directory.
**/
fn Path! get_config_dir(Allocator* allocator = allocator::heap())
fn Path! get_config_dir(Allocator allocator = allocator::heap())
{
@pool(allocator)
{
@@ -126,7 +126,7 @@ fn bool clear_var(String name)
};
}
fn String! executable_path(Allocator *allocator = allocator::heap())
fn String! executable_path(Allocator allocator = allocator::heap())
{
$if env::DARWIN:
return darwin::executable_path(allocator);

View File

@@ -128,17 +128,17 @@ fn ulong! elf_module_image_base(String path) @local
return 0;
}
fn Backtrace! backtrace_load_from_exec(void* addr, Allocator* allocator) @local
fn void! backtrace_add_from_exec(BacktraceList* list, void* addr, Allocator allocator) @local
{
char[] buf = mem::temp_alloc_array(char, 1024);
String exec_path = process::execute_stdout_to_buffer(buf, {"realpath", "-e", string::tformat("/proc/%d/exe", posix::getpid())})!;
String obj_name = exec_path.copy(allocator);
String addr2line = process::execute_stdout_to_buffer(buf, {"addr2line", "-p", "-i", "-C", "-f", "-e", exec_path, string::tformat("0x%x", addr)})!;
return backtrace_from_addr2line(addr, addr2line, obj_name, "???", allocator);
return backtrace_add_addr2line(list, addr, addr2line, obj_name, "???", allocator);
}
fn Backtrace! backtrace_load_from_dlinfo(void* addr, Linux_Dl_info* info, Allocator* allocator) @local
fn void! backtrace_add_from_dlinfo(BacktraceList* list, void* addr, Linux_Dl_info* info, Allocator allocator) @local
{
char[] buf = mem::temp_alloc_array(char, 1024);
@@ -146,30 +146,19 @@ fn Backtrace! backtrace_load_from_dlinfo(void* addr, Linux_Dl_info* info, Alloca
ZString obj_path = info.dli_fname;
String sname = info.dli_sname ? info.dli_sname.str_view() : "???";
String addr2line = process::execute_stdout_to_buffer(buf, {"addr2line", "-p", "-i", "-C", "-f", "-e", obj_path.str_view(), string::tformat("0x%x", obj_addr - 1)})!;
return backtrace_from_addr2line(addr, addr2line, info.dli_fname.str_view(), sname, allocator);
return backtrace_add_addr2line(list, addr, addr2line, info.dli_fname.str_view(), sname, allocator);
}
fn Backtrace! backtrace_from_addr2line(void* addr, String addr2line, String obj_name, String func_name, Allocator* allocator) @local
fn Backtrace! backtrace_line_parse(String string, String obj_name, String func_name, bool is_inlined, Allocator allocator)
{
String[] parts = addr2line.tsplit(" at ");
if (parts.len != 2)
{
return {
.function = func_name.copy(allocator),
.object_file = obj_name.copy(allocator),
.offset = (uptr)addr,
.file = "".copy(allocator),
.line = 0,
.allocator = allocator
};
}
String[] parts = string.trim().tsplit(" at ");
if (parts.len != 2) return SearchResult.MISSING?;
uint line = 0;
uint line = 0;
String source = "";
if (!parts[1].contains("?") && parts[1].contains(":"))
{
usz index = parts[1].rindex_of_char(':')!;
source = parts[1][:index];
line = parts[1][index + 1..].to_uint()!;
}
@@ -179,25 +168,53 @@ fn Backtrace! backtrace_from_addr2line(void* addr, String addr2line, String obj_
.file = source.copy(allocator),
.line = line,
.allocator = allocator,
.is_inline = is_inlined
};
}
fn Backtrace! backtrace_load_element(void* addr, Allocator* allocator = allocator::heap()) @local
fn void! backtrace_add_addr2line(BacktraceList* list, void* addr, String addr2line, String obj_name, String func_name, Allocator allocator) @local
{
if (!addr) return backtrace::BACKTRACE_UNKNOWN;
String[] inline_parts = addr2line.tsplit("(inlined by)");
usz last = inline_parts.len - 1;
foreach (i, part : inline_parts)
{
bool is_inline = i != last;
Backtrace! trace = backtrace_line_parse(part, obj_name, func_name, is_inline, allocator);
if (catch trace)
{
list.push({
.function = func_name.copy(allocator),
.object_file = obj_name.copy(allocator),
.offset = (uptr)addr,
.file = "".copy(allocator),
.line = 0,
.allocator = allocator,
.is_inline = is_inline
});
continue;
}
list.push(trace);
}
}
fn void! backtrace_add_element(BacktraceList *list, void* addr, Allocator allocator = allocator::heap()) @local
{
if (!addr)
{
list.push(backtrace::BACKTRACE_UNKNOWN);
return;
}
@pool(allocator) {
Linux_Dl_info info;
if (dladdr(addr, &info) == 0)
{
return backtrace_load_from_exec(addr, allocator);
return backtrace_add_from_exec(list, addr, allocator);
}
return backtrace_load_from_dlinfo(addr, &info, allocator);
return backtrace_add_from_dlinfo(list, addr, &info, allocator);
};
}
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator)
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator allocator)
{
BacktraceList list;
list.new_init(backtrace.len, allocator);
@@ -213,8 +230,7 @@ fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator)
{
foreach (addr : backtrace)
{
Backtrace trace = backtrace_load_element(addr, allocator)!;
list.append(trace);
backtrace_add_element(&list, addr, allocator)!;
}
};
return list;

View File

@@ -68,7 +68,7 @@ struct Darwin_segment_command_64
}
fn String! executable_path(Allocator *allocator)
fn String! executable_path(Allocator allocator)
{
char[4096] path;
uint len = path.len;
@@ -93,7 +93,7 @@ fn uptr! load_address() @local
}
fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_address, Allocator* allocator = allocator::heap()) @local
fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_address, Allocator allocator = allocator::heap()) @local
{
@pool(allocator)
{
@@ -132,7 +132,7 @@ fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_a
};
}
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator)
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator allocator)
{
void *load_addr = (void *)load_address()!;
BacktraceList list;
@@ -150,7 +150,7 @@ fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator)
String execpath = executable_path(allocator::temp())!;
foreach (addr : backtrace)
{
list.append(backtrace_load_element(execpath, addr, load_addr, allocator) ?? backtrace::BACKTRACE_UNKNOWN);
list.push(backtrace_load_element(execpath, addr, load_addr, allocator) ?? backtrace::BACKTRACE_UNKNOWN);
}
};
return list;

View File

@@ -24,7 +24,7 @@ macro Class! class_by_name(ZString c)
return cls ?: ObjcFailure.CLASS_NOT_FOUND?;
}
macro Class[] class_get_list(Allocator *allocator = allocator::heap())
macro Class[] class_get_list(Allocator allocator = allocator::heap())
{
int num_classes = macos_objc_getClassList(null, 0);
if (!num_classes) return {};

View File

@@ -99,6 +99,8 @@ extern fn CFile _fdopen(int fd, ZString mode);
extern fn CInt _access(ZString path, CInt mode);
extern fn CInt _waccess(WString path, CInt mode);
extern fn WString _wfullpath(WString absPath, WString relPath, usz maxLength);
/*
extern ulong _win32_GetCurrentDirectoryW(ulong, Char16* buffer) @extern("GetCurrentDirectoryW");
extern bool _win32_CreateSymbolicLinkW(WString symlink_file, WString target_file, ulong flags) @extern("CreateSymbolicLinkW");

View File

@@ -152,7 +152,7 @@ struct Symbol
Win32_DWORD64 displacement;
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator)
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator allocator)
{
BacktraceList list;
list.new_init(backtrace.len, allocator);
@@ -161,12 +161,12 @@ fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator)
defer symCleanup(process);
foreach (addr : backtrace)
{
list.append(resolve_backtrace(addr, process, allocator) ?? backtrace::BACKTRACE_UNKNOWN);
list.push(resolve_backtrace(addr, process, allocator) ?? backtrace::BACKTRACE_UNKNOWN);
}
return list;
}
fn Backtrace! resolve_backtrace(void* addr, Win32_HANDLE process, Allocator* allocator)
fn Backtrace! resolve_backtrace(void* addr, Win32_HANDLE process, Allocator allocator)
{
Symbol symbol;
//Win32_DWORD image_type = load_modules()!;

View File

@@ -1,5 +1,52 @@
# C3C Release Notes
## 0.6.0 Change list
### Changes / improvements
- `@default` implementations for interfaces removed.
- `any*` => `any`, same for interfaces.
- Private / local globals now have `internal` visibility in LLVM.
- Updated enum syntax.
- 'rgba' also available for swizzling.
- The name "subarray" has been replaced by the more well known name "slice' across the codebase.
- Improved alignment handling.
- Add `--output-dir` to command line. #1155
- Allow making distinct types out of "void", "typeid", "anyfault" and faults.
- Removed `--system-linker` setting.
- "Try" expressions may not be any binary or unary expressions. So for example `try foo() + 1` is disallowed.
- Added `$$REGISTER_SIZE` for int register size.
- `assert(false)` only allowed in unused branches or in tests. Compile time failed asserts is a compile time error.
- Require expression blocks returning values to have the value used.
- Detect "unsigned >= 0" as errors.
- Improve callstack debug information #1184.
- Request jump table using @jump for switches.
- Improved inline debug information.
- Improved error messages on inlined macros.
- Introduce MSVC compatible SIMD ABI.
- `$foreach` doesn't create an implicit syntactic scope.
- Error of `@if` depends on `@if`
### Fixes
- Fixed issue in safe mode when converting enums.
- Better checking of operator methods.
- Bug when assigning an optional from an optional.
- Lambdas were not type checked thoroughly #1185.
- Fix problems using reflection on interface types #1203.
- `@param` with unnamed macro varargs could crash the compiler.
- Compiler crash using enum nameof from different module #1205.
### Stdlib changes
- "init_new/init_temp" removed.
- LinkedList API rewritten.
- List "pop" and "remove" function now return Optionals.
- RingBuffer API rewritten. Allocator interface changed.
- Deprecated Allocator, DString and mem functions removed.
- "identity" functions are now constants for Matrix and Complex numbers.
- Removed 'append' from Object and List, replaced by 'push'.
- `GenericList` renamed `AnyList`.
- Proper handling of '.' and Win32 '//server' paths.
- Path normalization - fix possible null terminator out of bounds.
## 0.5.6 Change list
### Changes / improvements
@@ -388,13 +435,13 @@
- Fixed errors on flexible array slices.
- Fix of `readdir` issues on macOS.
- Fix to slice assignment of distinct types.
- Fix of issue casting subarrays to distinct types.
- Fix of issue casting slices to distinct types.
- Fixes to `split`, `rindex_of`.
- List no longer uses the temp allocator by default.
- Remove test global when not in test mode.
- Fix sum/product on floats.
- Fix error on void! return of macros.
- Removed too permissive casts on subarrays.
- Removed too permissive casts on slices.
- Using C files correctly places objects in the build folder.
- Fix of overaligned deref.
- Fix negating a float vector.
@@ -497,7 +544,7 @@
- Added type.inner and type.len reflection.
- Support float mod operations.
- Add float.max/min.
- Allow [in] contract to be used on subarray types.
- Allow [in] contract to be used on slices.
- Add linker and linked dir arguments to build files.
- Auto-import std::core.
- LLVM 15 support.

View File

@@ -18,7 +18,7 @@ Some short names:
| int | cond | sw/sn | always | explptr | no | expand | explbase | edist | no | no | no | no | no | edist | no |
| float | cond | expl | sw/sn | no | no | expand | no | edist | no | no | no | no | no | no | no |
| pointer | cond | explptr | no | ptrconv | arve | expand | no | edist | no | no | no | yes | expl | no | expl |
| subarray | cond | no | no | no | saconv | no | no | edist | no? | no | no | no | no | no | no |
| slice | cond | no | no | no | saconv | no | no | edist | no? | no | no | no | no | no | no |
| vec | cond | no | no | no | no | as base | no | edist | expl | no | no | no | no | no | no |
| bits | no | explbase | no | no | no | no | no? | edist | explbase | no | no | no | no | no | no |
| distc | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist |

View File

@@ -9,7 +9,7 @@ fault InterpretError
INTEPRET_FAILED
}
fn void! print_error(usz pos, String err)
fn void! print_error_type_at(usz pos, String err)
{
io::printfn("Error at %s: %s", pos, err);
return InterpretError.INTEPRET_FAILED?;
@@ -25,10 +25,10 @@ fn void! brainf(String program)
switch (c)
{
case '<':
if (!mem) return print_error(sp, "Memory underflow");
if (!mem) return print_error_type_at(sp, "Memory underflow");
mem--;
case '>':
if (mem == BF_MEM - 1) return print_error(sp, "Memory overflow");
if (mem == BF_MEM - 1) return print_error_type_at(sp, "Memory overflow");
mem++;
case '+':
memory[mem]++;
@@ -45,7 +45,7 @@ fn void! brainf(String program)
usz start = sp - 1;
while (indent)
{
if (sp == program.len) return print_error(start, "No matching ']'");
if (sp == program.len) return print_error_type_at(start, "No matching ']'");
switch (program[sp++])
{
case ']': indent--;
@@ -59,7 +59,7 @@ fn void! brainf(String program)
usz indent = 1;
while (indent)
{
if (!sp) return print_error(start, "No matching '['");
if (!sp) return print_error_type_at(start, "No matching '['");
switch (program[--sp])
{
case ']': indent++;

View File

@@ -27,7 +27,7 @@ struct Summary
bool ok;
}
fn void! Summary.print(Summary *s, OutStream* out)
fn void! Summary.print(Summary *s, OutStream out)
{
io::fprintf(out, "Summary({ .title = %s, .ok = %s})", s.title.get() ?? "missing", s.ok)!;
}
@@ -76,7 +76,7 @@ fn void main()
const String[] URLS = { "good", "title-empty", "title-missing", "head-missing", "fail" };
DynamicArenaAllocator dynamic_arena;
dynamic_arena.init(1024, allocator::heap());
OutStream* out = io::stdout();
OutStream out = io::stdout();
foreach (String url : URLS)
{
mem::@scoped(&dynamic_arena)

View File

@@ -1,7 +1,7 @@
module levenshtein;
import std::math;
// This levenshtein exercises C3 subarrays.
// This levenshtein exercises C3 slices.
fn int levenshtein(String s, String t)
{
// if either string is empty, difference is inserting all chars

View File

@@ -29,7 +29,7 @@
"link-libc": false,
"opt": "O0",
"safe": false,
"system-linker": true,
"linker": "builtin",
"use-stdlib": false,
},
},
@@ -68,8 +68,8 @@
// The size of the symtab, which limits the amount
// of symbols that can be used. Should usually not be changed.
"symtab": 1048576,
// Use the system linker.
"system-linker": false,
// Select linker.
"linker": "cc",
// Include the standard library.
"use-stdlib": true,
// Set general level of x64 cpu: "baseline", "ssse3", "sse4", "avx1", "avx2-v1", "avx2-v2", "avx512", "native".

View File

@@ -7,7 +7,7 @@ fn void! main()
String command = env::WIN32 ? "dir" : "ls";
SubProcess x = process::create({ command }, { .search_user_path = true })!!;
x.join()!;
InStream* stream = &&x.stdout();
InStream stream = &&x.stdout();
while (try char b = stream.read_byte())
{
io::printf("%c", b);

View File

@@ -66,7 +66,7 @@
// of symbols that can be used. Should usually not be changed.
"symtab": 1048576,
// Use the system linker.
"system-linker": false,
"linker": "cc",
// Include the standard library.
"use-stdlib": true,
// Set general level of x64 cpu: "baseline", "ssse3", "sse4", "avx1", "avx2-v1", "avx2-v2", "avx512", "native".

View File

@@ -0,0 +1,11 @@
fn void main() {
foo();
}
fn void foo() {
bar();
}
macro bar() {
unreachable();
}

View File

@@ -320,7 +320,12 @@ relational_stmt_expr
| relational_stmt_expr relational_op additive_expr
;
rel_or_lambda_expr
try_catch_rhs_expr
: call_expr
| lambda_decl IMPLIES relational_expr
;
try_chain_expr
: relational_expr
| lambda_decl IMPLIES relational_expr
;
@@ -484,7 +489,7 @@ enum_list
enum_constant
: CONST_IDENT opt_attributes
| CONST_IDENT '(' arg_list ')' opt_attributes
| CONST_IDENT opt_attributes '=' constant_expr
;
identifier_list
@@ -493,9 +498,7 @@ identifier_list
;
enum_param_decl
: type
| type IDENT
| type IDENT '=' expr
: type IDENT
;
base_type
@@ -638,15 +641,15 @@ catch_unwrap
;
try_unwrap
: TRY rel_or_lambda_expr
| TRY IDENT '=' rel_or_lambda_expr
| TRY type IDENT '=' rel_or_lambda_expr
: TRY try_catch_rhs_expr
| TRY IDENT '=' try_chain_expr
| TRY type IDENT '=' try_chain_expr
;
try_unwrap_chain
: try_unwrap
| try_unwrap_chain AND_OP try_unwrap
| try_unwrap_chain AND_OP rel_or_lambda_expr
| try_unwrap_chain AND_OP try_chain_expr
;
default_stmt
@@ -1017,12 +1020,6 @@ enum_params
| enum_params ',' enum_param_decl
;
enum_param_list
: '(' enum_params ')'
| '(' ')'
| empty
;
struct_member_decl
: type identifier_list opt_attributes ';'
| struct_or_union IDENT opt_attributes struct_body
@@ -1034,12 +1031,14 @@ struct_member_decl
;
enum_spec
: ':' type enum_param_list
| empty
: ':' base_type '(' enum_params ')'
| ':' base_type
| ':' '(' enum_params ')'
;
enum_declaration
: ENUM TYPE_IDENT opt_interface_impl enum_spec opt_attributes '{' enum_list '}'
| ENUM TYPE_IDENT opt_interface_impl opt_attributes '{' enum_list '}'
;
faults

View File

@@ -12,7 +12,26 @@ fn void test1()
{
(void)test2();
}
fn void foo()
{
baz();
}
macro bar()
{
builtin::print_backtrace("bar", 1);
}
macro baz()
{
bar();
}
fn void main()
{
test1();
foo();
}

View File

@@ -21,7 +21,7 @@ fn void setstring(char* dst, String str)
dst[0] = 0;
}
fn void testAllocator(Allocator* a, int val)
fn void testAllocator(Allocator a, int val)
{
io::printn("Test");
void* data = allocator::malloc_aligned(a, val, 128, 16)!!;

View File

@@ -111,7 +111,7 @@ fn void testArrays()
printArray(&x);
printArray(y);
printArray(x[1..]);
puts("Array to pointer to subarray---");
puts("Array to pointer to slice---");
int* z = &x;
printArray(z[0..2]);
printf("Pointer to array: %p\nPointer to slice: %p\nPointer to first element of slice: %p\n", z, &y, &y[0]);

View File

@@ -137,12 +137,6 @@ typedef enum
SINGLE_MODULE_ON = 1
} SingleModule;
typedef enum
{
SYSTEM_LINKER_NOT_SET = -1,
SYSTEM_LINKER_OFF = 0,
SYSTEM_LINKER_ON = 1
} SystemLinker;
typedef enum
{
@@ -187,6 +181,13 @@ typedef enum
SOFT_FLOAT_YES = 1
} SoftFloat;
typedef enum
{
WIN64_SIMD_DEFAULT = -1,
WIN64_SIMD_FULL = 0,
WIN64_SIMD_ARRAY = 1
} Win64Simd;
typedef enum
{
STRUCT_RETURN_DEFAULT = -1,
@@ -366,6 +367,7 @@ typedef struct BuildOptions_
const char *testfn;
const char *cc;
const char *build_dir;
const char *output_dir;
const char *llvm_out;
const char *asm_out;
const char *obj_out;
@@ -373,6 +375,7 @@ typedef struct BuildOptions_
RelocModel reloc_model;
X86VectorCapability x86_vector_capability;
X86CpuSet x86_cpu_set;
Win64Simd win_64_simd;
FpOpt fp_math;
EmitStdlib emit_stdlib;
UseStdlib use_stdlib;
@@ -501,6 +504,7 @@ typedef struct
X86VectorCapability x86_vector_capability : 4;
RiscvFloatCapability riscv_float_capability : 4;
bool trap_on_wrap : 1;
Win64Simd pass_win64_simd_as_arrays : 3;
FpOpt fp_math;
SafetyLevel safe_mode;
X86CpuSet x86_cpu_set;

View File

@@ -47,6 +47,11 @@ static const char *riscv_capability[3] = {
[RISCVFLOAT_DOUBLE] = "double",
};
static const char *win64_simd_type[2] = {
[WIN64_SIMD_ARRAY] = "array",
[WIN64_SIMD_FULL] = "full",
};
static const char *fp_math[3] = {
[FP_STRICT] = "strict",
[FP_RELAXED] = "relaxed",

View File

@@ -105,6 +105,7 @@ static void usage(void)
OUTPUT(" -D <name> - Add feature flag <name>.");
OUTPUT(" -U <name> - Remove feature flag <name>.");
OUTPUT(" --trust=<option> - Trust level: none (default), include ($include allowed), full ($exec / exec allowed).");
OUTPUT(" --output-dir <dir> - Override general output directory.");
OUTPUT(" --build-dir <dir> - Override build output directory.");
OUTPUT(" --obj-out <dir> - Override object file output directory.");
OUTPUT(" --script-dir <dir> - Override the base directory for $exec.");
@@ -128,9 +129,7 @@ static void usage(void)
OUTPUT(" -l <library> - Link with the library provided.");
OUTPUT(" -L <library dir> - Append the directory to the linker search paths.");
OUTPUT(" -z <argument> - Send the <argument> as a parameter to the linker.");
OUTPUT(" --system-linker=<yes|no> - Use the system linker (default: no for cross compilation, yes otherwise). [deprecated]");
OUTPUT(" --cc <path> - Set C compiler (for C files in projects and use as system linker).");
OUTPUT(" --linker <path> - Use the linker in the given path. [deprecated]");
OUTPUT(" --linker=<option> [<path>] - Linker: builtin, cc, custom (default is 'cc'), 'custom' requires a path.");
OUTPUT("");
OUTPUT(" --use-stdlib=<yes|no> - Include the standard library (default: yes).");
@@ -147,6 +146,7 @@ static void usage(void)
OUTPUT(" --memory-env=<option> - Set the memory environment: normal, small, tiny, none.");
OUTPUT(" --strip-unused=<yes|no> - Strip unused code and globals from the output. (default: yes)");
OUTPUT(" --fp-math=<option> - FP math behaviour: strict, relaxed, fast.");
OUTPUT(" --win64-simd=<option> - Win64 SIMD ABI: array, full.");
OUTPUT("");
OUTPUT(" --debug-stats - Print debug statistics.");
OUTPUT(" --print-linking - Print linker arguments.");
@@ -693,31 +693,6 @@ static void parse_option(BuildOptions *options)
}
return;
}
if ((argopt = match_argopt("system-linker")))
{
puts("NOTE: 'system-linker' is deprecated, please use --linker instead.");
options->custom_linker_path = NULL;
switch ((SystemLinker)parse_multi_option(argopt, 2, on_off))
{
case SYSTEM_LINKER_ON:
options->linker_type = LINKER_TYPE_CC;
break;
case SYSTEM_LINKER_OFF:
options->linker_type = LINKER_TYPE_BUILTIN;
break;
default:
UNREACHABLE
}
return;
}
if (match_longopt("linker"))
{
if (at_end() || next_is_opt()) error_exit("error: --linker expects a valid linker name.");
options->linker_type = LINKER_TYPE_CUSTOM;
options->custom_linker_path = next_arg();
puts("NOTE: 'linker' is deprecated, please use --linker=custom <path> instead.");
return;
}
if ((argopt = match_argopt("link-libc")))
{
options->link_libc = (LinkLibc)parse_multi_option(argopt, 2, on_off);
@@ -743,6 +718,11 @@ static void parse_option(BuildOptions *options)
options->x86_vector_capability = (X86VectorCapability)parse_multi_option(argopt, 6, x86_vector_capability);
return;
}
if ((argopt = match_argopt("win64-simd")))
{
options->win_64_simd = (Win64Simd)parse_multi_option(argopt, 2, win64_simd_type);
return;
}
if ((argopt = match_argopt("x86cpu")))
{
options->x86_cpu_set = (X86CpuSet)parse_multi_option(argopt, 8, x86_cpu_set);
@@ -967,6 +947,12 @@ static void parse_option(BuildOptions *options)
options->macos.min_version = next_arg();
return;
}
if (match_longopt("output-dir"))
{
if (at_end() || next_is_opt()) error_exit("error: --output-dir needs a directory.");
options->output_dir = next_arg();
return;
}
if (match_longopt("build-dir"))
{
if (at_end() || next_is_opt()) error_exit("error: --build-dir needs a directory.");
@@ -1119,6 +1105,7 @@ BuildOptions parse_arguments(int argc, const char *argv[])
.reloc_model = RELOC_DEFAULT,
.backend = BACKEND_LLVM,
.x86_vector_capability = X86VECTOR_DEFAULT,
.win_64_simd = WIN64_SIMD_DEFAULT,
.fp_math = FP_DEFAULT,
.x86_cpu_set = X86CPU_DEFAULT,
.riscv_float_capability = RISCVFLOAT_DEFAULT,
@@ -1132,6 +1119,7 @@ BuildOptions parse_arguments(int argc, const char *argv[])
.single_module = SINGLE_MODULE_NOT_SET,
.files = NULL,
.build_dir = NULL,
.output_dir = NULL,
.script_dir = NULL,
};

View File

@@ -289,6 +289,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
target->emit_llvm = options->emit_llvm;
target->build_threads = options->build_threads;
target->emit_asm = options->emit_asm;
if (options->output_dir) target->output_dir = options->output_dir;
if (options->panicfn) target->panicfn = options->panicfn;
if (options->testfn) target->testfn = options->testfn;
if (options->benchfn) target->benchfn = options->benchfn;
@@ -317,6 +318,10 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
{
target->feature.riscv_float_capability = options->riscv_float_capability;
}
if (options->win_64_simd != WIN64_SIMD_DEFAULT)
{
target->feature.pass_win64_simd_as_arrays = options->win_64_simd;
}
if (command_accepts_files(options->command))
{
target->build_dir = options->build_dir ? options->build_dir : NULL;

View File

@@ -527,6 +527,7 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
// Use the fact that they correspond to 0, 1, -1
target->feature.x86_struct_return = get_valid_bool(json, "x86-stack-struct-return", type, target->feature.x86_struct_return);
target->feature.soft_float = get_valid_bool(json, "soft-float", type, target->feature.soft_float);
target->feature.pass_win64_simd_as_arrays = get_valid_bool(json, "win64-simd-array", type, target->feature.pass_win64_simd_as_arrays);
}
static void project_add_target(Project *project, BuildTarget *default_target, JSONObject *json, const char *name, const char *type, TargetType target_type)

View File

@@ -4,7 +4,7 @@
#include "compiler/c_abi_internal.h"
ABIArgInfo *win64_classify(Regs *regs, Type *type, bool is_return, bool is_vector)
ABIArgInfo *win64_classify(Regs *regs, Type *type, bool is_return, bool is_vector_call)
{
if (type_is_void(type)) return abi_arg_ignore();
@@ -19,7 +19,7 @@ ABIArgInfo *win64_classify(Regs *regs, Type *type, bool is_return, bool is_vecto
Type *base = NULL;
unsigned elements = 0;
if (is_vector && type_is_homogenous_aggregate(type, &base, &elements))
if (is_vector_call && type_is_homogenous_aggregate(type, &base, &elements))
{
// Enough registers AND return / builtin / vector
if (regs->float_regs >= elements &&
@@ -36,7 +36,8 @@ ABIArgInfo *win64_classify(Regs *regs, Type *type, bool is_return, bool is_vecto
// => to main handling.
}
ByteSize size = type_size(type);
if (type_is_abi_aggregate(type))
bool type_is_vector_to_pass_as_array = active_target.feature.pass_win64_simd_as_arrays && type_flat_is_vector(type);
if (type_is_vector_to_pass_as_array || type_is_abi_aggregate(type))
{
// Not 1, 2, 4, 8? Pass indirect.
if (size > 8 || !is_power_of_two(size))

View File

@@ -125,7 +125,7 @@ ABIArgInfo *x64_classify_reg_call_struct_type_check(Type *type, Registers *neede
assert(x64_type_is_structure(type));
// These are all passed in two registers.
if (type->type_kind == TYPE_SUBARRAY || type->type_kind == TYPE_ANY)
if (type->type_kind == TYPE_SLICE || type->type_kind == TYPE_ANY)
{
needed_registers->int_registers += 2;
return abi_arg_new_direct();
@@ -382,16 +382,14 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X
{
case LOWERED_TYPES:
case TYPE_FUNC:
case TYPE_ANY:
case TYPE_INTERFACE:
UNREACHABLE
case TYPE_VOID:
*current = CLASS_NO_CLASS;
break;
case TYPE_I128:
case TYPE_U128:
case TYPE_SUBARRAY:
case TYPE_ANYPTR:
case TYPE_SLICE:
case TYPE_ANY:
*lo_class = CLASS_INTEGER;
*hi_class = CLASS_INTEGER;
break;
@@ -565,8 +563,6 @@ AbiType x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_typ
case LOWERED_TYPES:
case TYPE_VOID:
case TYPE_FUNC:
case TYPE_ANY:
case TYPE_INTERFACE:
UNREACHABLE
case TYPE_U64:
case TYPE_I64:
@@ -597,11 +593,11 @@ AbiType x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_typ
}
break;
}
case TYPE_ANYPTR:
case TYPE_ANY:
if (offset < 8) return abi_type_get(type_ulong);
if (offset < 16) return abi_type_get(type_voidptr);
break;
case TYPE_SUBARRAY:
case TYPE_SLICE:
if (offset < 8) return abi_type_get(type_voidptr);
if (offset < 16) return abi_type_get(type_ulong);
break;
@@ -858,7 +854,7 @@ bool x64_type_is_structure(Type *type)
switch (type->type_kind)
{
case TYPE_STRUCT:
case TYPE_SUBARRAY:
case TYPE_SLICE:
case TYPE_ANY:
return true;
default:

View File

@@ -121,15 +121,13 @@ static bool x86_should_return_type_in_reg(Type *type)
case TYPE_OPTIONAL:
case TYPE_FLEXIBLE_ARRAY:
case TYPE_INTERFACE:
case TYPE_ANY:
case TYPE_INFPTR:
UNREACHABLE
case ALL_INTS:
case ALL_FLOATS:
case TYPE_BOOL:
case TYPE_POINTER:
case TYPE_SUBARRAY:
case TYPE_ANYPTR:
case TYPE_SLICE:
case TYPE_ANY:
return true;
case TYPE_ARRAY:
// Small arrays <= 8 bytes.
@@ -368,7 +366,7 @@ static inline ABIArgInfo *x86_classify_vector(Regs *regs, Type *type)
/**
* Handle:
* error type, struct, union, subarray,
* error type, struct, union, slice,
* string, array, error union, complex.
*/
static inline ABIArgInfo *x86_classify_aggregate(CallABI call, Regs *regs, Type *type)
@@ -459,8 +457,6 @@ static ABIArgInfo *x86_classify_argument(CallABI call, Regs *regs, Type *type)
case LOWERED_TYPES:
case TYPE_VOID:
case TYPE_FUNC:
case TYPE_ANY:
case TYPE_INTERFACE:
case TYPE_FLEXIBLE_ARRAY:
UNREACHABLE
case ALL_FLOATS:
@@ -472,8 +468,8 @@ static ABIArgInfo *x86_classify_argument(CallABI call, Regs *regs, Type *type)
return x86_classify_vector(regs, type);
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_SUBARRAY:
case TYPE_ANYPTR:
case TYPE_SLICE:
case TYPE_ANY:
case TYPE_ARRAY:
return x86_classify_aggregate(call, regs, type);
UNREACHABLE

View File

@@ -172,14 +172,12 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements)
switch (type->type_kind)
{
case LOWERED_TYPES:
case TYPE_ANY:
case TYPE_INTERFACE:
UNREACHABLE;
case TYPE_VOID:
case TYPE_FUNC:
case TYPE_SUBARRAY:
case TYPE_SLICE:
return false;
case TYPE_ANYPTR:
case TYPE_ANY:
*base = type_iptr->canonical;
*elements = 2;
return true;

View File

@@ -36,8 +36,8 @@ static inline Type *type_lowering(Type *type)
case TYPE_ENUM:
type = type->decl->enums.type_info->type;
continue;
case TYPE_INFPTR:
return type_anyptr;
case TYPE_INTERFACE:
return type_any;
case TYPE_ANYFAULT:
case TYPE_TYPEID:
case TYPE_FAULTTYPE:
@@ -55,7 +55,7 @@ static inline Type *type_lowering(Type *type)
if (flat == pointer) return type;
return type_get_ptr(flat);
}
case TYPE_SUBARRAY:
case TYPE_SLICE:
case TYPE_ARRAY:
case TYPE_VECTOR:
case TYPE_FLEXIBLE_ARRAY:
@@ -65,8 +65,8 @@ static inline Type *type_lowering(Type *type)
if (flat == arr_type) return type;
switch (type->type_kind)
{
case TYPE_SUBARRAY:
return type_get_subarray(flat);
case TYPE_SLICE:
return type_get_slice(flat);
case TYPE_ARRAY:
return type_get_array(flat, type->array.len);
case TYPE_VECTOR:

View File

@@ -316,6 +316,15 @@ void compiler_parse(void)
compiler_parsing_time = bench_mark();
}
static void create_output_dir(const char *dir)
{
if (!file_exists(dir))
{
if (!dir_make(dir)) error_exit("Failed to create output directory %s.", dir);
}
if (!file_is_dir(dir)) error_exit("Output directory is not a directory %s.", dir);
}
void compiler_compile(void)
{
sema_analysis_run();
@@ -498,11 +507,16 @@ void compiler_compile(void)
if (output_exe)
{
if (active_target.output_dir) output_exe = file_append_path(active_target.output_dir, output_exe);
if (active_target.output_dir)
{
create_output_dir(active_target.output_dir);
output_exe = file_append_path(active_target.output_dir, output_exe);
}
if (file_is_dir(output_exe))
{
error_exit("Cannot create exe with the name '%s' - there is already a directory with that name.", output_exe);
}
bool system_linker_available = link_libc() && platform_target.os != OS_TYPE_WIN32;
bool use_system_linker = system_linker_available && active_target.arch_os_target == default_target;
switch (active_target.linker_type)
@@ -569,7 +583,7 @@ void compiler_compile(void)
}
else
{
scratch_buffer_append("./");
if (name[0] != '/') scratch_buffer_append("./");
scratch_buffer_append(name);
}
name = scratch_buffer_to_string();
@@ -604,7 +618,11 @@ void compiler_compile(void)
}
else if (output_static)
{
if (active_target.output_dir) output_static = file_append_path(active_target.output_dir, output_static);
if (active_target.output_dir)
{
create_output_dir(active_target.output_dir);
output_static = file_append_path(active_target.output_dir, output_static);
}
if (file_is_dir(output_static))
{
error_exit("Cannot create a static library with the name '%s' - there is already a directory with that name.", output_exe);
@@ -620,7 +638,11 @@ void compiler_compile(void)
}
else if (output_dynamic)
{
if (active_target.output_dir) output_dynamic = file_append_path(active_target.output_dir, output_dynamic);
if (active_target.output_dir)
{
create_output_dir(active_target.output_dir);
output_dynamic = file_append_path(active_target.output_dir, output_dynamic);
}
if (file_is_dir(output_dynamic))
{
error_exit("Cannot create a dynamic library with the name '%s' - there is already a directory with that name.", output_exe);
@@ -784,7 +806,7 @@ void print_syntax(BuildOptions *options)
if (name[0] == '$' || (name[0] >= 'a' && name[0] <= 'z'))
{
if (name[1] == '$' || name[1] == '\0') continue;
printf("%3d %s\n", index++, name);
printf("%s\n", name);
}
}
}
@@ -802,33 +824,32 @@ void print_syntax(BuildOptions *options)
{
continue;
}
printf("%2d %s\n", index++, name);
printf("%s\n", name);
}
}
if (options->print_attributes)
{
for (int i = 0; i < NUMBER_OF_ATTRIBUTES; i++)
{
printf("%2d %s\n", i + 1, attribute_list[i]);
printf("%s\n", attribute_list[i]);
}
}
if (options->print_builtins)
{
for (int i = 0; i < NUMBER_OF_BUILTINS; i++)
{
printf("%3d $$%s\n", i + 1, builtin_list[i]);
printf("$$%s\n", builtin_list[i]);
}
puts("---");
for (int i = 0; i < NUMBER_OF_BUILTIN_DEFINES; i++)
{
printf("%2d $$%s\n", i + 1, builtin_defines[i]);
printf("$$%s\n", builtin_defines[i]);
}
}
if (options->print_type_properties)
{
for (int i = 0; i < NUMBER_OF_TYPE_PROPERTIES; i++)
{
printf("%2d .%s\n", i + 1, type_property_list[i]);
printf("%s\n", type_property_list[i]);
}
}
if (options->print_project_properties)
@@ -838,14 +859,14 @@ void print_syntax(BuildOptions *options)
puts("------------------");
for (int i = 0; i < project_default_keys_count; i++)
{
printf("%2d %-*s%s\n", i + 1, 35, project_default_keys[i][0], project_default_keys[i][1]);
printf("%-*s%s\n", 35, project_default_keys[i][0], project_default_keys[i][1]);
}
puts("");
puts("Target properties");
puts("-----------------");
for (int i = 0; i < project_target_keys_count; i++)
{
printf("%2d %-*s%s\n", i + 1, 35, project_target_keys[i][0], project_target_keys[i][1]);
printf("%-*s%s\n", 35, project_target_keys[i][0], project_target_keys[i][1]);
}
puts("");
}
@@ -985,6 +1006,7 @@ void compile()
setup_int_define("C_INT_SIZE", platform_target.width_c_int, type_int);
setup_int_define("C_LONG_SIZE", platform_target.width_c_long, type_int);
setup_int_define("C_LONG_LONG_SIZE", platform_target.width_c_long_long, type_int);
setup_int_define("REGISTER_SIZE", platform_target.width_register, type_int);
setup_bool_define("C_CHAR_IS_SIGNED", platform_target.signed_c_char);
setup_bool_define("PLATFORM_BIG_ENDIAN", platform_target.big_endian);
setup_bool_define("PLATFORM_I128_SUPPORTED", platform_target.int128);

View File

@@ -105,12 +105,11 @@ typedef enum
{
RESOLVE_TYPE_DEFAULT,
RESOLVE_TYPE_ALLOW_INFER = 0x01,
RESOLVE_TYPE_ALLOW_ANY = 0x02,
RESOLVE_TYPE_IS_POINTEE = 0x04,
RESOLVE_TYPE_ALLOW_FLEXIBLE = 0x08,
RESOLVE_TYPE_PTR = RESOLVE_TYPE_ALLOW_ANY | RESOLVE_TYPE_IS_POINTEE,
RESOLVE_TYPE_MACRO_METHOD = RESOLVE_TYPE_ALLOW_ANY | RESOLVE_TYPE_ALLOW_INFER,
RESOLVE_TYPE_FUNC_METHOD = RESOLVE_TYPE_ALLOW_ANY
RESOLVE_TYPE_IS_POINTEE = 0x02,
RESOLVE_TYPE_ALLOW_FLEXIBLE = 0x04,
RESOLVE_TYPE_PTR = RESOLVE_TYPE_IS_POINTEE,
RESOLVE_TYPE_MACRO_METHOD = RESOLVE_TYPE_ALLOW_INFER,
RESOLVE_TYPE_FUNC_METHOD = RESOLVE_TYPE_DEFAULT
} ResolveTypeKind;
struct ConstInitializer_
@@ -447,7 +446,6 @@ typedef struct
typedef struct VarDecl_
{
VarDeclKind kind : 8;
bool unwrap : 1;
bool shadow : 1;
bool vararg : 1;
bool is_static : 1;
@@ -567,7 +565,6 @@ typedef struct
bool attr_finalizer : 1;
bool attr_interface_method : 1;
bool attr_dynamic : 1;
bool attr_default : 1;
bool is_lambda : 1;
union
{
@@ -677,6 +674,7 @@ typedef struct Decl_
bool is_deprecated : 1;
bool is_cond : 1;
bool has_link : 1;
bool is_if : 1;
OperatorOverload operator : 4;
union
{
@@ -691,8 +689,8 @@ typedef struct Decl_
SectionId section_id;
uint16_t va_index;
};
AlignSize offset : 32;
AlignSize padding : 32;
AlignSize offset;
AlignSize padding;
struct CompilationUnit_ *unit;
Attr **attributes;
Type *type;
@@ -908,6 +906,11 @@ typedef struct
};
} ExprIdentifier;
typedef struct
{
SourceSpan loc;
Expr *inner;
} ExprDefaultArg;
typedef struct
{
@@ -1183,6 +1186,7 @@ struct Expr_
ExprCompoundLiteral expr_compound_literal; // 16
Expr** expression_list; // 8
ExprGenericIdent generic_ident_expr;
ExprDefaultArg default_arg_expr;
ExprIdentifierRaw hash_ident_expr; // 24
ExprIdentifier identifier_expr; // 24
Expr** initializer_list; // 8
@@ -1216,6 +1220,7 @@ static_assert(sizeof(Expr) == 56, "Expr not expected size");
typedef struct
{
AstId first_stmt;
AstId parent_defer;
} AstCompoundStmt;
@@ -1234,6 +1239,7 @@ typedef struct
bool no_exit : 1;
bool skip_first : 1;
bool if_chain : 1;
bool jump : 1;
} FlowCommon;
@@ -1273,20 +1279,31 @@ typedef struct
typedef struct
{
FlowCommon flow;
Ast **cases;
union
{
struct
{
ExprId cond;
AstId defer;
Ast **cases;
Ast *scope_defer;
};
struct
{
void *retry_block;
void *exit_block;
void *retry_var;
union
{
struct {
void *block;
void *var;
} retry;
struct {
uint16_t count;
int16_t min_index;
int16_t default_index;
void *jmptable;
} jump;
};
} codegen;
};
} AstSwitchStmt;
@@ -1329,6 +1346,7 @@ typedef struct
{
AstId prev_defer;
AstId body; // Compound statement
void *scope;
bool is_try : 1;
bool is_catch : 1;
} AstDeferStmt;
@@ -1506,7 +1524,7 @@ typedef struct Ast_
//static_assert(sizeof(AstContinueBreakStmt) == 24, "Ooops");
static_assert(sizeof(Ast) == 48, "Not expected size on 64 bit");
static_assert(sizeof(Ast) == 56, "Not expected size on 64 bit");
typedef struct Module_
{
@@ -1543,6 +1561,7 @@ typedef struct DynamicScope_
ScopeId scope_id;
bool allow_dead_code : 1;
bool jump_end : 1;
bool is_dead : 1;
ScopeFlags flags;
unsigned label_start;
unsigned current_local;
@@ -1669,6 +1688,7 @@ typedef struct
CallEnvKind kind : 8;
bool ensures : 1;
bool pure : 1;
SourceSpan in_if_resolution;
Decl **opt_returns;
union
{
@@ -1677,6 +1697,12 @@ typedef struct
};
} CallEnv;
typedef struct InliningSpan_
{
SourceSpan span;
struct InliningSpan_ *prev;
} InliningSpan;
struct SemaContext_
{
Module *core_module;
@@ -1686,7 +1712,7 @@ struct SemaContext_
CompilationUnit *compilation_unit;
CallEnv call_env;
Decl *current_macro;
SourceSpan inlining_span;
InliningSpan *inlined_at;
ScopeId scope_id;
unsigned macro_call_depth;
Ast *break_target;
@@ -1882,12 +1908,12 @@ extern TypeInfo *poisoned_type_info;
extern Type *type_bool, *type_void, *type_voidptr;
extern Type *type_float16, *type_float, *type_double, *type_f128;
extern Type *type_float16, *type_bfloat, *type_float, *type_double, *type_f128;
extern Type *type_ichar, *type_short, *type_int, *type_long, *type_isz;
extern Type *type_char, *type_ushort, *type_uint, *type_ulong, *type_usz;
extern Type *type_iptr, *type_uptr;
extern Type *type_u128, *type_i128;
extern Type *type_typeid, *type_anyfault, *type_anyptr, *type_typeinfo, *type_member;
extern Type *type_typeid, *type_anyfault, *type_any, *type_typeinfo, *type_member;
extern Type *type_untypedlist;
extern Type *type_wildcard;
extern Type *type_cint;
@@ -1916,6 +1942,7 @@ extern const char *kw_at_param;
extern const char *kw_at_pure;
extern const char *kw_at_require;
extern const char *kw_at_return;
extern const char *kw_at_jump;
extern const char *kw_check_assign;
extern const char *kw_deprecated;
extern const char *kw_in;
@@ -2281,12 +2308,12 @@ Decl **parse_include_file(File *file, CompilationUnit *unit);
bool parse_stdin(void);
Path *path_create_from_string(const char *string, uint32_t len, SourceSpan span);
#define SEMA_ERROR_HERE(...) sema_error_at(c->span, __VA_ARGS__)
#define RETURN_SEMA_ERROR_HERE(...) do { sema_error_at(c->span, __VA_ARGS__); return false; } while (0)
#define SEMA_ERROR_LAST(...) sema_error_at(c->prev_span, __VA_ARGS__)
#define RETURN_SEMA_ERROR_LAST(...) do { sema_error_at(c->prev_span, __VA_ARGS__); return false; } while (0)
#define SEMA_ERROR(_node, ...) sema_error_at((_node)->span, __VA_ARGS__)
#define RETURN_SEMA_ERROR(_node, ...) do { sema_error_at((_node)->span, __VA_ARGS__); return false; } while (0)
#define PRINT_ERROR_AT(_node, ...) print_error_at((_node)->span, __VA_ARGS__)
#define RETURN_PRINT_ERROR_AT(_val, _node, ...) do { print_error_at((_node)->span, __VA_ARGS__); return _val; } while (0)
#define PRINT_ERROR_HERE(...) print_error_at(c->span, __VA_ARGS__)
#define RETURN_PRINT_ERROR_HERE(...) do { print_error_at(c->span, __VA_ARGS__); return false; } while (0)
#define PRINT_ERROR_LAST(...) print_error_at(c->prev_span, __VA_ARGS__)
#define RETURN_PRINT_ERROR_LAST(...) do { print_error_at(c->prev_span, __VA_ARGS__); return false; } while (0)
#define SEMA_NOTE(_node, ...) sema_error_prev_at((_node)->span, __VA_ARGS__)
#define EXPAND_EXPR_STRING(str_) (str_)->const_expr.bytes.len, (str_)->const_expr.bytes.ptr
#define TABLE_MAX_LOAD 0.5
@@ -2297,18 +2324,20 @@ Decl *sema_decl_stack_find_decl_member(Decl *decl_owner, const char *symbol);
Decl *sema_decl_stack_resolve_symbol(const char *symbol);
void sema_decl_stack_restore(Decl **state);
void sema_decl_stack_push(Decl *decl);
bool sema_error_failed_cast(Expr *expr, Type *from, Type *to);
bool sema_error_failed_cast(SemaContext *context, Expr *expr, Type *from, Type *to);
bool sema_add_local(SemaContext *context, Decl *decl);
void sema_unwrap_var(SemaContext *context, Decl *decl);
void sema_rewrap_var(SemaContext *context, Decl *decl);
void sema_erase_var(SemaContext *context, Decl *decl);
void sema_erase_unwrapped(SemaContext *context, Decl *decl);
bool sema_analyse_cond_expr(SemaContext *context, Expr *expr);
bool sema_analyse_cond_expr(SemaContext *context, Expr *expr, CondResult *result);
bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allow_optional, bool *no_match_ref);
MemberIndex sema_get_initializer_const_array_size(SemaContext *context, Expr *initializer, bool *may_be_array, bool *is_const_size);
bool sema_analyse_expr(SemaContext *context, Expr *expr);
bool sema_expr_check_discard(Expr *expr);
bool sema_expr_check_discard(SemaContext *context, Expr *expr);
bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr);
bool sema_analyse_decl(SemaContext *context, Decl *decl);
bool sema_resolve_type_structure(SemaContext *context, Type *type, SourceSpan span);
@@ -2326,7 +2355,7 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl
Decl *sema_decl_stack_resolve_symbol(const char *symbol);
Decl *sema_find_decl_in_modules(Module **module_list, Path *path, const char *interned_name);
Decl *unit_resolve_parameterized_symbol(CompilationUnit *unit, NameResolve *name_resolve);
Decl *unit_resolve_parameterized_symbol(SemaContext *context, CompilationUnit *unit, NameResolve *name_resolve);
Decl *sema_resolve_type_method(CompilationUnit *unit, Type *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref);
Decl *sema_resolve_method(CompilationUnit *unit, Decl *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref);
Decl *sema_find_extension_method_in_list(Decl **extensions, Type *type, const char *method_name);
@@ -2344,15 +2373,16 @@ bool sema_resolve_array_like_len(SemaContext *context, TypeInfo *type_info, Arra
bool sema_resolve_type_info(SemaContext *context, TypeInfo *type_info, ResolveTypeKind kind);
void sema_error_at(SourceSpan loc, const char *message, ...);
void sema_error_at_after(SourceSpan loc, const char *message, ...);
void print_error_at(SourceSpan loc, const char *message, ...);
void print_error_after(SourceSpan loc, const char *message, ...);
void sema_error_prev_at(SourceSpan loc, const char *message, ...);
void sema_verror_range(SourceSpan location, const char *message, va_list args);
void sema_error(ParseContext *context, const char *message, ...);
void print_error(ParseContext *context, const char *message, ...);
void sema_warning_at(SourceSpan loc, const char *message, ...);
void sema_shadow_error(Decl *decl, Decl *old);
bool sema_type_error_on_binop(Expr *expr);
void sema_shadow_error(SemaContext *context, Decl *decl, Decl *old);
bool sema_type_error_on_binop(SemaContext *context, Expr *expr);
File *source_file_by_id(FileId file);
File *source_file_load(const char *filename, bool *already_loaded, const char **error);
@@ -2422,7 +2452,7 @@ Type *type_get_array(Type *arr_type, ArraySize len);
Type *type_get_indexed_type(Type *type);
Type *type_get_ptr(Type *ptr_type);
Type *type_get_ptr_recurse(Type *ptr_type);
Type *type_get_subarray(Type *arr_type);
Type *type_get_slice(Type *arr_type);
Type *type_get_inferred_array(Type *arr_type);
Type *type_get_inferred_vector(Type *arr_type);
Type *type_get_flexible_array(Type *arr_type);
@@ -2600,7 +2630,7 @@ INLINE bool type_len_is_inferred(Type *type)
type = type->optional;
continue;
case TYPE_ARRAY:
case TYPE_SUBARRAY:
case TYPE_SLICE:
case TYPE_FLEXIBLE_ARRAY:
case TYPE_VECTOR:
type = type->array.base;
@@ -2635,26 +2665,13 @@ INLINE bool type_is_any_raw(Type *type)
}
}
INLINE bool type_is_any_interface_ptr(Type *type)
{
switch (type->canonical->type_kind)
{
case TYPE_ANYPTR:
case TYPE_INFPTR:
return true;
default:
return false;
}
}
INLINE bool type_is_any(Type *type)
{
return type->canonical == type_anyptr;
return type->canonical == type_any;
}
INLINE bool type_is_anyfault(Type *type)
{
return type->canonical == type_anyfault;
}
INLINE bool type_is_optional(Type *type)
{
@@ -2838,29 +2855,50 @@ INLINE const char *type_invalid_storage_type_name(Type *type)
return "an untyped list";
case TYPE_TYPEINFO:
return "a type";
case TYPE_WILDCARD:
return "an empty value";
default:
UNREACHABLE;
}
}
INLINE bool type_is_invalid_storage_type(Type *type)
typedef enum
{
if (!type) return false;
STORAGE_NORMAL,
STORAGE_VOID,
STORAGE_COMPILE_TIME,
STORAGE_WILDCARD,
STORAGE_UNKNOWN
} StorageType;
static inline StorageType type_storage_type(Type *type)
{
if (!type) return STORAGE_NORMAL;
bool is_distinct = false;
RETRY:
if (type == type_wildcard_optional) return true;
if (type == type_wildcard_optional) return STORAGE_WILDCARD;
switch (type->type_kind)
{
case TYPE_VOID:
return is_distinct ? STORAGE_UNKNOWN : STORAGE_VOID;
case TYPE_WILDCARD:
return STORAGE_WILDCARD;
case TYPE_MEMBER:
case TYPE_UNTYPED_LIST:
case TYPE_TYPEINFO:
case TYPE_WILDCARD:
return true;
return STORAGE_COMPILE_TIME;
case TYPE_OPTIONAL:
type = type->optional;
goto RETRY;
case TYPE_TYPEDEF:
type = type->canonical;
goto RETRY;
case TYPE_DISTINCT:
is_distinct = true;
type = type->decl->distinct->type;
goto RETRY;
default:
return false;
return STORAGE_NORMAL;
}
}
@@ -2956,7 +2994,7 @@ static inline Type *type_base(Type *type)
}
}
}
static inline Type *type_flat_inline(Type *type)
static inline Type *type_flat_distinct_inline(Type *type)
{
do
{
@@ -3213,11 +3251,166 @@ INLINE bool exprid_is_constant_eval(ExprId expr, ConstantEvalKind eval_kind)
INLINE bool expr_poison(Expr *expr) { expr->expr_kind = EXPR_POISONED; expr->resolve_status = RESOLVE_DONE; return false; }
static inline void expr_list_set_span(Expr **expr, SourceSpan loc);
static inline void exprid_set_span(ExprId expr_id, SourceSpan loc);
INLINE void expr_set_span(Expr *expr, SourceSpan loc);
INLINE void const_init_set_span(ConstInitializer *init, SourceSpan loc)
{
RETRY:
switch (init->kind)
{
case CONST_INIT_ZERO:
return;
case CONST_INIT_STRUCT:
{
uint32_t members = vec_size(type_flatten(init->type)->decl->strukt.members);
for (uint32_t i = 0; i < members; i++)
{
const_init_set_span(init->init_struct[i], loc);
}
return;
}
case CONST_INIT_UNION:
init = init->init_union.element;
goto RETRY;
case CONST_INIT_VALUE:
expr_set_span(init->init_value, loc);
return;
case CONST_INIT_ARRAY:
{
FOREACH_BEGIN(ConstInitializer *init2, init->init_array.elements)
const_init_set_span(init2, loc);
FOREACH_END();
return;
}
case CONST_INIT_ARRAY_FULL:
{
FOREACH_BEGIN(ConstInitializer *init2, init->init_array_full)
const_init_set_span(init2, loc);
FOREACH_END();
return;
}
case CONST_INIT_ARRAY_VALUE:
const_init_set_span(init->init_array_value.element, loc);
return;
}
UNREACHABLE
}
static inline void expr_list_set_span(Expr **expr, SourceSpan loc);
static inline void exprid_set_span(ExprId expr_id, SourceSpan loc);
INLINE void expr_set_span(Expr *expr, SourceSpan loc)
{
expr->span = loc;
switch (expr->expr_kind)
{
case EXPR_CONST:
switch (expr->const_expr.const_kind)
{
case CONST_INITIALIZER:
const_init_set_span(expr->const_expr.initializer, loc);
return;
case CONST_UNTYPED_LIST:
expr_list_set_span(expr->const_expr.untyped_list, loc);
return;
default:
return;
}
expr_list_set_span(expr->expression_list, loc);
return;
case EXPR_CAST:
exprid_set_span(expr->cast_expr.expr, loc);
return;
case EXPR_INITIALIZER_LIST:
expr_list_set_span(expr->initializer_list, loc);
return;
case EXPR_DESIGNATED_INITIALIZER_LIST:
expr_list_set_span(expr->designated_init_list, loc);
return;
case EXPR_EXPRESSION_LIST:
case EXPR_ACCESS:
case EXPR_BITACCESS:
case EXPR_POISONED:
case EXPR_ASM:
case EXPR_BUILTIN:
case EXPR_BINARY:
case EXPR_BITASSIGN:
case EXPR_BUILTIN_ACCESS:
case EXPR_CALL:
case EXPR_CATCH_UNWRAP:
case EXPR_COMPILER_CONST:
case EXPR_COMPOUND_LITERAL:
case EXPR_COND:
case EXPR_CT_AND_OR:
case EXPR_CT_ARG:
case EXPR_CT_CALL:
case EXPR_CT_CASTABLE:
case EXPR_CT_IS_CONST:
case EXPR_CT_DEFINED:
case EXPR_CT_EVAL:
case EXPR_CT_IDENT:
case EXPR_DECL:
case EXPR_DESIGNATOR:
case EXPR_EMBED:
case EXPR_EXPR_BLOCK:
case EXPR_OPTIONAL:
case EXPR_FORCE_UNWRAP:
case EXPR_GENERIC_IDENT:
case EXPR_GROUP:
case EXPR_HASH_IDENT:
case EXPR_IDENTIFIER:
case EXPR_LAMBDA:
case EXPR_LAST_FAULT:
case EXPR_MACRO_BLOCK:
case EXPR_MACRO_BODY_EXPANSION:
case EXPR_NOP:
case EXPR_OPERATOR_CHARS:
case EXPR_OTHER_CONTEXT:
case EXPR_POINTER_OFFSET:
case EXPR_POST_UNARY:
case EXPR_RETHROW:
case EXPR_RETVAL:
case EXPR_SLICE:
case EXPR_SLICE_ASSIGN:
case EXPR_SLICE_COPY:
case EXPR_STRINGIFY:
case EXPR_SUBSCRIPT:
case EXPR_SWIZZLE:
case EXPR_SUBSCRIPT_ADDR:
case EXPR_SUBSCRIPT_ASSIGN:
case EXPR_TERNARY:
case EXPR_BENCHMARK_HOOK:
case EXPR_TEST_HOOK:
case EXPR_TRY_UNWRAP:
case EXPR_TRY_UNWRAP_CHAIN:
case EXPR_TYPEID:
case EXPR_TYPEID_INFO:
case EXPR_TYPEINFO:
case EXPR_UNARY:
case EXPR_ANYSWITCH:
case EXPR_VASPLAT:
case EXPR_MACRO_BODY:
case EXPR_DEFAULT_ARG:
break;
}
}
static inline void exprid_set_span(ExprId expr_id, SourceSpan loc)
{
if (expr_id) expr_set_span(exprptr(expr_id), loc);
}
static inline void expr_list_set_span(Expr **exprs, SourceSpan loc)
{
FOREACH_BEGIN(Expr *expr, exprs)
expr_set_span(expr, loc);
FOREACH_END();
}
INLINE void expr_replace(Expr *expr, Expr *replacement)
{
SourceSpan loc = expr->span;
*expr = *replacement;
expr->span = loc;
expr_set_span(expr, loc);
}
INLINE bool expr_ok(Expr *expr) { return expr == NULL || expr->expr_kind != EXPR_POISONED; }
@@ -3436,6 +3629,8 @@ INLINE void expr_rewrite_const_float(Expr *expr, Type *type, Real d)
Real real;
switch (kind)
{
case TYPE_F16:
case TYPE_BF16:
case TYPE_F32:
real = (float)d;
break;
@@ -3607,3 +3802,5 @@ INLINE const char *section_from_id(SectionId id)
{
return id ? global_context.section_list[id - 1] + SECTION_PREFIX_LEN : NULL;
}
extern char swizzle[256];

View File

@@ -4,7 +4,6 @@
#include "compiler_internal.h"
CompilationUnit *unit_create(File *file)
{
CompilationUnit *unit = CALLOCS(CompilationUnit);
@@ -26,11 +25,11 @@ static inline bool create_module_or_check_name(CompilationUnit *unit, Path *modu
{
if (unit->module->name->module != module_name->module)
{
SEMA_ERROR(module_name,
"Module name here '%s' did not match actual module '%s'.",
module_name->module,
module->name->module);
return false;
RETURN_PRINT_ERROR_AT(false,
module_name,
"Module name here '%s' did not match actual module '%s'.",
module_name->module,
module->name->module);
}
}
@@ -72,7 +71,9 @@ bool context_set_module_from_filename(ParseContext *context)
File *file = context->unit->file;
if (!filename_to_module_in_buffer(file->full_path))
{
sema_error(context, "The filename '%s' could not be converted to a valid module name, try using an explicit module name.", file->full_path);
print_error(context,
"The filename '%s' could not be converted to a valid module name, try using an explicit module name.",
file->full_path);
return false;
}
@@ -84,8 +85,8 @@ bool context_set_module_from_filename(ParseContext *context)
if (type != TOKEN_IDENT)
{
sema_error(context, "Generating a filename from the file '%s' resulted in a name that is a reserved keyword, "
"try using an explicit module name.", file->full_path);
print_error(context, "Generating a filename from the file '%s' resulted in a name that is a reserved keyword, "
"try using an explicit module name.", file->full_path);
return false;
}
Path *path = CALLOCS(Path);
@@ -100,8 +101,7 @@ bool context_set_module(ParseContext *context, Path *path, const char **generic_
// Note that we allow the illegal name for now, to be able to parse further.
if (!str_has_no_uppercase(path->module))
{
SEMA_ERROR(path, "A module name may not have any uppercase characters.");
return false;
RETURN_PRINT_ERROR_AT(false, path, "A module name may not have any uppercase characters.");
}
return create_module_or_check_name(context->unit, path, generic_parameters);
@@ -258,7 +258,7 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl)
return;
ERR:
assert(decl != old);
sema_shadow_error(decl, old);
sema_shadow_error(NULL, decl, old);
decl_poison(decl);
decl_poison(old);
}
@@ -269,8 +269,7 @@ bool unit_add_import(CompilationUnit *unit, Path *path, bool private_import)
if (!str_has_no_uppercase(path->module))
{
SEMA_ERROR(path, "A module is not expected to have any uppercase characters, please change it.");
return false;
RETURN_PRINT_ERROR_AT(false, path, "A module is not expected to have any uppercase characters, please change it.");
}
Decl *import = decl_calloc();

View File

@@ -440,6 +440,9 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
case EXPR_CT_IS_CONST:
MACRO_COPY_EXPR(expr->inner_expr);
return expr;
case EXPR_DEFAULT_ARG:
MACRO_COPY_EXPR(expr->default_arg_expr.inner);
return expr;
case EXPR_CT_DEFINED:
MACRO_COPY_EXPR_LIST(expr->expression_list);
return expr;
@@ -452,7 +455,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
case EXPR_MACRO_BLOCK:
MACRO_COPY_DECL_LIST(expr->macro_block.params);
MACRO_COPY_ASTID(expr->macro_block.first_stmt);
MACRO_COPY_DECL(expr->macro_block.macro);
fixup_decl(c, &expr->macro_block.macro);
return expr;
case EXPR_COMPOUND_LITERAL:
MACRO_COPY_EXPR(expr->expr_compound_literal.initializer);
@@ -625,6 +628,7 @@ RETRY:
break;
case AST_COMPOUND_STMT:
MACRO_COPY_ASTID(ast->compound_stmt.first_stmt);
fixup_astid(c, &ast->compound_stmt.parent_defer);
break;
case AST_CT_IF_STMT:
MACRO_COPY_EXPR(ast->ct_if_stmt.expr);
@@ -840,7 +844,7 @@ TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source)
copy->array.base = copy_type_info(c, source->array.base);
return copy;
case TYPE_INFO_INFERRED_ARRAY:
case TYPE_INFO_SUBARRAY:
case TYPE_INFO_SLICE:
case TYPE_INFO_INFERRED_VECTOR:
assert(source->resolve_status == RESOLVE_NOT_DONE);
copy->array.base = copy_type_info(c, source->array.base);

View File

@@ -17,7 +17,7 @@ typedef enum
#define LINES_SHOWN 4
#define MAX_WIDTH 120
static void print_error(SourceSpan location, const char *message, PrintType print_type)
static void print_error_type_at(SourceSpan location, const char *message, PrintType print_type)
{
if (!location.a)
{
@@ -154,7 +154,7 @@ static void print_error(SourceSpan location, const char *message, PrintType prin
static void vprint_error(SourceSpan location, const char *message, va_list args)
{
print_error(location, str_vprintf(message, args), PRINT_TYPE_ERROR);
print_error_type_at(location, str_vprintf(message, args), PRINT_TYPE_ERROR);
}
@@ -168,12 +168,12 @@ void sema_warning_at(SourceSpan loc, const char *message, ...)
{
va_list list;
va_start(list, message);
print_error(loc, str_vprintf(message, list), PRINT_TYPE_NOTE);
print_error_type_at(loc, str_vprintf(message, list), PRINT_TYPE_NOTE);
va_end(list);
}
void sema_error_at(SourceSpan loc, const char *message, ...)
void print_error_at(SourceSpan loc, const char *message, ...)
{
va_list list;
va_start(list, message);
@@ -181,7 +181,7 @@ void sema_error_at(SourceSpan loc, const char *message, ...)
va_end(list);
}
void sema_error_at_after(SourceSpan loc, const char *message, ...)
void print_error_after(SourceSpan loc, const char *message, ...)
{
loc.col += loc.length;
loc.length = 1;
@@ -201,14 +201,14 @@ void sema_error_prev_at(SourceSpan loc, const char *message, ...)
// Ignore errors
if (written <= MAX_ERROR_LEN - 2)
{
print_error(loc, buffer, PRINT_TYPE_NOTE);
print_error_type_at(loc, buffer, PRINT_TYPE_NOTE);
}
va_end(args);
return;
}
void sema_error(ParseContext *context, const char *message, ...)
void print_error(ParseContext *context, const char *message, ...)
{
global_context.errors_found++;
File *file = context->unit->file;

View File

@@ -4,6 +4,13 @@
// Only include this from compiler_common.h
typedef enum
{
COND_MISSING = -1,
COND_TRUE = 1,
COND_FALSE = 0,
} CondResult;
typedef enum
{
BINARYOP_ERROR,
@@ -110,10 +117,10 @@ typedef enum
CAST_PTRBOOL,
CAST_PTRPTR,
CAST_PTRINT,
CAST_SABOOL,
CAST_SLBOOL,
CAST_SAPTR,
CAST_SASA,
CAST_SAARR,
CAST_SLSL,
CAST_SLARR,
CAST_STRPTR,
CAST_STINLINE,
CAST_VECARR,
@@ -197,7 +204,7 @@ typedef enum
INTROSPECT_TYPE_FUNC = 13,
INTROSPECT_TYPE_OPTIONAL = 14,
INTROSPECT_TYPE_ARRAY = 15,
INTROSPECT_TYPE_SUBARRAY = 16,
INTROSPECT_TYPE_SLICE = 16,
INTROSPECT_TYPE_VECTOR = 17,
INTROSPECT_TYPE_DISTINCT = 18,
INTROSPECT_TYPE_POINTER = 19,
@@ -206,9 +213,10 @@ typedef enum
typedef enum
{
EXPR_POISONED,
EXPR_ACCESS,
EXPR_ANYSWITCH,
EXPR_ASM,
EXPR_BENCHMARK_HOOK,
EXPR_BINARY,
EXPR_BITACCESS,
EXPR_BITASSIGN,
@@ -225,17 +233,17 @@ typedef enum
EXPR_CT_ARG,
EXPR_CT_CALL,
EXPR_CT_CASTABLE,
EXPR_CT_IS_CONST,
EXPR_CT_DEFINED,
EXPR_CT_EVAL,
EXPR_CT_IDENT,
EXPR_CT_IS_CONST,
EXPR_DECL,
EXPR_DEFAULT_ARG,
EXPR_DESIGNATED_INITIALIZER_LIST,
EXPR_DESIGNATOR,
EXPR_EMBED,
EXPR_EXPRESSION_LIST,
EXPR_EXPR_BLOCK,
EXPR_OPTIONAL,
EXPR_FORCE_UNWRAP,
EXPR_GENERIC_IDENT,
EXPR_GROUP,
@@ -245,11 +253,14 @@ typedef enum
EXPR_LAMBDA,
EXPR_LAST_FAULT,
EXPR_MACRO_BLOCK,
EXPR_MACRO_BODY,
EXPR_MACRO_BODY_EXPANSION,
EXPR_NOP,
EXPR_OPERATOR_CHARS,
EXPR_OPTIONAL,
EXPR_OTHER_CONTEXT,
EXPR_POINTER_OFFSET,
EXPR_POISONED,
EXPR_POST_UNARY,
EXPR_RETHROW,
EXPR_RETVAL,
@@ -258,11 +269,10 @@ typedef enum
EXPR_SLICE_COPY,
EXPR_STRINGIFY,
EXPR_SUBSCRIPT,
EXPR_SWIZZLE,
EXPR_SUBSCRIPT_ADDR,
EXPR_SUBSCRIPT_ASSIGN,
EXPR_SWIZZLE,
EXPR_TERNARY,
EXPR_BENCHMARK_HOOK,
EXPR_TEST_HOOK,
EXPR_TRY_UNWRAP,
EXPR_TRY_UNWRAP_CHAIN,
@@ -270,9 +280,7 @@ typedef enum
EXPR_TYPEID_INFO,
EXPR_TYPEINFO,
EXPR_UNARY,
EXPR_ANYSWITCH,
EXPR_VASPLAT,
EXPR_MACRO_BODY,
} ExprKind;
typedef enum
@@ -389,7 +397,7 @@ typedef enum
TYPE_INFO_VECTOR,
TYPE_INFO_INFERRED_ARRAY,
TYPE_INFO_INFERRED_VECTOR,
TYPE_INFO_SUBARRAY,
TYPE_INFO_SLICE,
TYPE_INFO_POINTER,
TYPE_INFO_GENERIC,
} TypeInfoKind;
@@ -503,6 +511,7 @@ typedef enum
TOKEN_DOUBLE,
TOKEN_FLOAT,
TOKEN_FLOAT16,
TOKEN_BFLOAT,
TOKEN_INT128,
TOKEN_ICHAR,
TOKEN_INT,
@@ -617,7 +626,7 @@ typedef enum
#define NON_VOID_TYPE_TOKENS \
TOKEN_BOOL: case TOKEN_CHAR: case TOKEN_DOUBLE: case TOKEN_FLOAT: \
case TOKEN_FLOAT16: case TOKEN_INT128: case TOKEN_ICHAR: case TOKEN_INT: \
case TOKEN_FLOAT16: case TOKEN_BFLOAT: case TOKEN_INT128: case TOKEN_ICHAR: case TOKEN_INT: \
case TOKEN_IPTR: case TOKEN_LONG: \
case TOKEN_SHORT: case TOKEN_UINT128: case TOKEN_UINT: case TOKEN_ULONG: \
case TOKEN_UPTR: case TOKEN_USHORT: case TOKEN_USZ: \
@@ -662,8 +671,7 @@ typedef enum
TYPE_FLOAT_LAST = TYPE_F128,
TYPE_NUM_LAST = TYPE_FLOAT_LAST,
TYPE_ANY,
TYPE_ANYPTR,
TYPE_INFPTR,
TYPE_INTERFACE,
TYPE_ANYFAULT,
TYPE_TYPEID,
TYPE_POINTER,
@@ -671,12 +679,11 @@ typedef enum
TYPE_FUNC,
TYPE_STRUCT,
TYPE_UNION,
TYPE_INTERFACE,
TYPE_BITSTRUCT,
TYPE_FAULTTYPE,
TYPE_TYPEDEF,
TYPE_DISTINCT,
TYPE_SUBARRAY,
TYPE_SLICE,
TYPE_ARRAY,
TYPE_FIRST_ARRAYLIKE = TYPE_ARRAY,
TYPE_FLEXIBLE_ARRAY,
@@ -695,7 +702,7 @@ typedef enum
#define FLATTENED_TYPES TYPE_DISTINCT: case TYPE_OPTIONAL: case TYPE_TYPEDEF
#define LOWERED_TYPES CT_TYPES: case TYPE_ENUM: case TYPE_TYPEDEF: case TYPE_TYPEID: \
case TYPE_DISTINCT: case TYPE_ANYFAULT: case TYPE_FAULTTYPE: case TYPE_BITSTRUCT: \
case TYPE_OPTIONAL: case TYPE_INFPTR
case TYPE_OPTIONAL: case TYPE_INTERFACE
#define CT_TYPES TYPE_TYPEINFO: case TYPE_INFERRED_ARRAY: case TYPE_INFERRED_VECTOR: case TYPE_UNTYPED_LIST: \
case TYPE_POISONED: case TYPE_MEMBER: case TYPE_WILDCARD
#define ALL_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: case TYPE_I128: \
@@ -766,7 +773,8 @@ typedef enum
ATTR_MACRO = 1 << 14,
ATTR_DISTINCT = 1 << 15,
ATTR_ENUM_VALUE = 1 << 16,
ATTR_INTERFACE_METHOD = 1 << 17
ATTR_INTERFACE_METHOD = 1 << 17,
ATTR_PARAM = 1 << 18,
} AttributeDomain;
typedef enum
@@ -784,7 +792,6 @@ typedef enum
ATTRIBUTE_BIGENDIAN,
ATTRIBUTE_BUILTIN,
ATTRIBUTE_CALLCONV,
ATTRIBUTE_DEFAULT,
ATTRIBUTE_DEPRECATED,
ATTRIBUTE_DYNAMIC,
ATTRIBUTE_EXPORT,
@@ -1069,7 +1076,7 @@ typedef enum
CONV_INT,
CONV_FLOAT,
CONV_POINTER,
CONV_SUBARRAY,
CONV_SLICE,
CONV_VECTOR,
CONV_BITSTRUCT,
CONV_DISTINCT,

View File

@@ -127,6 +127,7 @@ bool expr_may_addr(Expr *expr)
case EXPR_GENERIC_IDENT:
case EXPR_EMBED:
case EXPR_MACRO_BODY:
case EXPR_DEFAULT_ARG:
case EXPR_LAST_FAULT:
return false;
}
@@ -250,6 +251,9 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
case EXPR_GROUP:
expr = expr->inner_expr;
goto RETRY;
case EXPR_DEFAULT_ARG:
expr = expr->default_arg_expr.inner;
goto RETRY;
case EXPR_INITIALIZER_LIST:
return expr_list_is_constant_eval(expr->initializer_list, eval_kind);
case EXPR_DESIGNATED_INITIALIZER_LIST:
@@ -360,7 +364,7 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_
case CAST_FPFP:
case CAST_FPINT:
case CAST_INTFP:
case CAST_SABOOL:
case CAST_SLBOOL:
case CAST_STINLINE:
case CAST_VECARR:
case CAST_ARRVEC:
@@ -372,7 +376,7 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_
case CAST_PTRPTR:
case CAST_APTSA:
case CAST_SAPTR:
case CAST_SASA:
case CAST_SLSL:
case CAST_VOID:
case CAST_ANYBOOL:
case CAST_ERPTR:
@@ -388,7 +392,7 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_
case CAST_IDINT:
case CAST_INTARRBS:
case CAST_BSINTARR:
case CAST_SAARR:
case CAST_SLARR:
if (eval_kind == CONSTANT_EVAL_CONSTANT_VALUE) return false;
return exprid_is_constant_eval(expr->cast_expr.expr, eval_kind);
@@ -494,7 +498,7 @@ bool expr_may_splat_as_vararg(Expr *expr, Type *variadic_base_type)
switch (canonical->type_kind)
{
case TYPE_ARRAY:
case TYPE_SUBARRAY:
case TYPE_SLICE:
return canonical->array.base == base_type;
case TYPE_POINTER:
if (canonical->pointer->type_kind == TYPE_ARRAY) return canonical->pointer->array.base == base_type;
@@ -576,8 +580,6 @@ void expr_rewrite_to_const_zero(Expr *expr, Type *type)
case TYPE_VOID:
case TYPE_INFERRED_VECTOR:
case TYPE_WILDCARD:
case TYPE_ANY:
case TYPE_INTERFACE:
UNREACHABLE
case ALL_INTS:
expr_rewrite_const_int(expr, type, 0);
@@ -590,8 +592,8 @@ void expr_rewrite_to_const_zero(Expr *expr, Type *type)
return;
case TYPE_POINTER:
case TYPE_FAULTTYPE:
case TYPE_ANYPTR:
case TYPE_INFPTR:
case TYPE_ANY:
case TYPE_INTERFACE:
case TYPE_ANYFAULT:
case TYPE_TYPEID:
expr_rewrite_const_null(expr, type);
@@ -611,7 +613,7 @@ void expr_rewrite_to_const_zero(Expr *expr, Type *type)
case TYPE_UNION:
case TYPE_BITSTRUCT:
case TYPE_ARRAY:
case TYPE_SUBARRAY:
case TYPE_SLICE:
case TYPE_INFERRED_ARRAY:
case TYPE_FLEXIBLE_ARRAY:
case TYPE_UNTYPED_LIST:
@@ -779,6 +781,8 @@ bool expr_is_pure(Expr *expr)
&& exprid_is_pure(expr->ternary_expr.then_expr);
case EXPR_ASM:
return false;
case EXPR_DEFAULT_ARG:
return expr_is_pure(expr->default_arg_expr.inner);
case EXPR_GROUP:
return expr_is_pure(expr->inner_expr);
}

View File

@@ -9,8 +9,8 @@ UNUSED static int precision_bits(TypeKind kind)
{
case TYPE_F16:
return 11;
/*case TYPE_BF16:
return 8;*/
case TYPE_BF16:
return 8;
case TYPE_F32:
return 24;
case TYPE_F64:
@@ -28,8 +28,8 @@ UNUSED static int max_exponent(TypeKind kind)
{
case TYPE_F16:
return 15;
/*case TYPE_BF16:
return 127;*/
case TYPE_BF16:
return 127;
case TYPE_F32:
return 127;
case TYPE_F64:
@@ -47,8 +47,8 @@ UNUSED static int min_exponent(TypeKind kind)
{
case TYPE_F16:
return -14;
/*case TYPE_BF16:
return -126;*/
case TYPE_BF16:
return -126;
case TYPE_F32:
return -126;
case TYPE_F64:
@@ -101,6 +101,43 @@ static char *err_invalid_float_width = "The float width is not valid, it must be
static char *err_float_out_of_range = "The float value is out of range.";
static char *err_float_format_invalid = "The float format is invalid.";
TypeKind float_suffix(char c, const char **index_ref, char** error_ref)
{
if (c == 'b' && (*index_ref)[0] == 'f' && (*index_ref)[1] == '1' && (*index_ref)[1] == '6')
{
(*index_ref) += 4;
return TYPE_BF16;
}
if (c == 'f')
{
int i = 0;
while ((c = *((*index_ref)++)) && (c >= '0' && c <= '9'))
{
if (i > 100)
{
if (error_ref) *error_ref = err_invalid_float_width;
return TYPE_POISONED;
}
i = i * 10 + c - '0';
}
switch (i)
{
case 0:
case 32:
return TYPE_F32;
case 16:
return TYPE_F16;
case 64:
return TYPE_F64;
case 128:
return TYPE_F128;
default:
if (error_ref) *error_ref = err_invalid_float_width;
return TYPE_POISONED;
}
}
return TYPE_F64;
}
/**
* This parses a float from a string. Unfortunately it is limited to parsing doubles as of now.
*
@@ -141,39 +178,8 @@ Float float_from_string(const char *string, char **error)
scratch_buffer_append_char(c);
}
}
TypeKind kind = TYPE_F64;
if (c == 'f')
{
int i = 0;
while ((c = *(index++)) && (c >= '0' && c <= '9'))
{
if (i > 100)
{
if (error) *error = err_invalid_float_width;
return (Float){ .type = TYPE_POISONED };
}
i = i * 10 + c - '0';
}
switch (i)
{
case 0:
case 32:
kind = TYPE_F32;
break;
case 16:
kind = TYPE_F16;
break;
case 64:
kind = TYPE_F64;
break;
case 128:
kind = TYPE_F128;
break;
default:
if (error) *error = err_invalid_float_width;
return (Float){ .type = TYPE_POISONED };
}
}
TypeKind kind = float_suffix(c, &index, error);
if (kind == TYPE_POISONED) return (Float){ .type = TYPE_POISONED };
const char *str = scratch_buffer_to_string();
char *end = NULL;
@@ -234,39 +240,8 @@ Float float_from_hex(const char *string, char **error)
scratch_buffer_append_char(c);
}
}
TypeKind kind = TYPE_F64;
if (c == 'f')
{
int i = 0;
while ((c = *(index++)) && (c >= '0' && c <= '9'))
{
if (i > 100)
{
if (error) *error = err_invalid_float_width;
return (Float){ .type = TYPE_POISONED };
}
i = i * 10 + c - '0';
}
switch (i)
{
case 0:
case 32:
kind = TYPE_F32;
break;
case 16:
kind = TYPE_F16;
break;
case 64:
kind = TYPE_F64;
break;
case 128:
kind = TYPE_F128;
break;
default:
if (error) *error = err_invalid_float_width;
return (Float){ .type = TYPE_POISONED };
}
}
TypeKind kind = float_suffix(c, &index, error);
if (kind == TYPE_POISONED) return (Float){ .type = TYPE_POISONED };
const char *str = scratch_buffer_to_string();
char *end = NULL;

View File

@@ -47,8 +47,6 @@ static void header_print_type(FILE *file, Type *type)
{
case CT_TYPES:
case TYPE_OPTIONAL:
case TYPE_INTERFACE:
case TYPE_ANY:
UNREACHABLE
case TYPE_VOID:
OUTPUT("void");
@@ -135,11 +133,11 @@ static void header_print_type(FILE *file, Type *type)
header_print_type(file, type->array.base);
OUTPUT(" arr[%d]; }", type->array.len);
return;
case TYPE_ANYPTR:
case TYPE_INFPTR:
case TYPE_ANY:
case TYPE_INTERFACE:
OUTPUT("c3any_t");
return;
case TYPE_SUBARRAY:
case TYPE_SLICE:
OUTPUT("c3slice_t");
return;
case TYPE_VECTOR:
@@ -370,8 +368,6 @@ RETRY:
case TYPE_MEMBER:
case TYPE_INFERRED_VECTOR:
case TYPE_WILDCARD:
case TYPE_INTERFACE:
case TYPE_ANY:
UNREACHABLE
case TYPE_VOID:
case TYPE_BOOL:
@@ -381,9 +377,9 @@ RETRY:
case TYPE_TYPEID:
case TYPE_BITSTRUCT:
case TYPE_FAULTTYPE:
case TYPE_SUBARRAY:
case TYPE_ANYPTR:
case TYPE_INFPTR:
case TYPE_SLICE:
case TYPE_ANY:
case TYPE_INTERFACE:
return;
case TYPE_POINTER:
type = type->pointer;
@@ -435,7 +431,7 @@ RETRY:
if (htable_get(table, type)) return;
{
Decl *decl = type->decl;
OUTPUT("typedef struct %s__subarray__ %s;\n", decl_get_extname(decl), decl_get_extname(decl));
OUTPUT("typedef struct %s__slice__ %s;\n", decl_get_extname(decl), decl_get_extname(decl));
htable_set(table, type, type);
header_ensure_member_types_exist(file, table, decl->strukt.members);
OUTPUT("%s %s__\n", struct_union_str(decl), decl->extname);

View File

@@ -135,7 +135,7 @@ void print_type(FILE *file, TypeInfo *type)
print_type(file, type->array.base);
fputs("[<>]", file);
break;
case TYPE_INFO_SUBARRAY:
case TYPE_INFO_SLICE:
print_type(file, type->array.base);
fputs("[]", file);
break;

View File

@@ -431,6 +431,7 @@ static void linker_setup_freebsd(const char ***args_ref, Linker linker_type)
static void add_linked_libs(const char ***args_ref, const char **libs, bool is_win)
{
FOREACH_BEGIN(const char *lib, libs)
INFO_LOG("Linking %s", lib);
const char *framework = str_remove_suffix(lib, ".framework");
if (framework)
{
@@ -451,7 +452,15 @@ static void add_linked_libs(const char ***args_ref, const char **libs, bool is_w
}
else
{
add_arg2("-l", lib);
if (str_has_suffix(lib, ".a") || str_has_suffix(lib, ".so") ||
str_has_suffix(lib, ".dylib") || str_has_suffix(lib, ".tbd"))
{
add_arg(lib);
}
else
{
add_arg2("-l", lib);
}
}
FOREACH_END();
}

View File

@@ -400,10 +400,10 @@ void llvm_emit_ptr_from_array(GenContext *c, BEValue *value)
case TYPE_VECTOR:
case TYPE_FLEXIBLE_ARRAY:
return;
case TYPE_SUBARRAY:
case TYPE_SLICE:
{
BEValue member;
llvm_emit_subarray_pointer(c, value, &member);
llvm_emit_slice_pointer(c, value, &member);
llvm_value_rvalue(c, &member);
llvm_value_set_address(value,
member.value,
@@ -543,16 +543,8 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
}
else
{
if (decl->var.kind == VARDECL_CONST || decl->var.kind == VARDECL_GLOBAL)
{
LLVMSetVisibility(global_ref, LLVMProtectedVisibility);
if (optional_ref) LLVMSetVisibility(optional_ref, LLVMProtectedVisibility);
}
else
{
LLVMSetLinkage(global_ref, LLVMInternalLinkage);
if (optional_ref) LLVMSetLinkage(optional_ref, LLVMInternalLinkage);
}
LLVMSetLinkage(global_ref, LLVMInternalLinkage);
if (optional_ref) LLVMSetLinkage(optional_ref, LLVMInternalLinkage);
}
decl->backend_ref = global_ref;
@@ -865,6 +857,19 @@ void llvm_value_set_decl(GenContext *c, BEValue *value, Decl *decl)
llvm_value_set_decl_address(c, value, decl);
}
LLVMBuilderRef llvm_create_function_entry(GenContext *c, LLVMValueRef func, LLVMBasicBlockRef *entry_block_ref)
{
LLVMBasicBlockRef entry = llvm_append_basic_block(c, func, "entry");
LLVMBuilderRef builder = llvm_create_builder(c);
LLVMPositionBuilderAtEnd(builder, entry);
if (entry_block_ref) *entry_block_ref = entry;
return builder;
}
LLVMBasicBlockRef llvm_append_basic_block(GenContext *c, LLVMValueRef function, const char *name)
{
return LLVMAppendBasicBlockInContext(c->context, function, name);
}
LLVMBasicBlockRef llvm_basic_block_new(GenContext *c, const char *name)
{
@@ -982,7 +987,6 @@ void llvm_add_global_decl(GenContext *c, Decl *decl)
bool same_module = decl_module(decl) == c->code_module;
const char *name = same_module ? "temp_global" : decl_get_extname(decl);
decl->backend_ref = llvm_add_global(c, name, decl->type, decl->alignment);
llvm_set_alignment(decl->backend_ref, decl->alignment);
if (!same_module)
{
LLVMSetLinkage(decl->backend_ref, LLVMExternalLinkage);
@@ -1211,9 +1215,7 @@ static void llvm_gen_test_main(GenContext *c)
LLVMTypeRef runner_type = LLVMFunctionType(c->byte_type, NULL, 0, true);
LLVMValueRef func = LLVMAddFunction(c->module, kw_main, main_type);
LLVMValueRef other_func = LLVMAddFunction(c->module, test_runner->extname, runner_type);
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, func, "entry");
LLVMBuilderRef builder = llvm_create_builder(c);
LLVMPositionBuilderAtEnd(builder, entry);
LLVMBuilderRef builder = llvm_create_function_entry(c, func, NULL);
LLVMValueRef val = LLVMBuildCall2(builder, runner_type, other_func, NULL, 0, "");
val = LLVMBuildSelect(builder, LLVMBuildTrunc(builder, val, c->bool_type, ""),
LLVMConstNull(cint), LLVMConstInt(cint, 1, false), "");
@@ -1273,11 +1275,11 @@ INLINE GenContext *llvm_gen_tests(Module** modules, unsigned module_count, LLVMC
decl_ref = LLVMConstNull(c->ptr_type);
}
LLVMValueRef count = llvm_const_int(c, type_usz, test_count);
Type *chars_array = type_get_subarray(type_chars);
Type *chars_array = type_get_slice(type_chars);
LLVMValueRef name_list = llvm_add_global(c, test_names_var_name, chars_array, type_alloca_alignment(chars_array));
LLVMSetGlobalConstant(name_list, 1);
LLVMSetInitializer(name_list, llvm_emit_aggregate_two(c, chars_array, name_ref, count));
Type *decls_array_type = type_get_subarray(type_voidptr);
Type *decls_array_type = type_get_slice(type_voidptr);
LLVMValueRef decl_list = llvm_add_global(c, test_fns_var_name, decls_array_type, type_alloca_alignment(decls_array_type));
LLVMSetGlobalConstant(decl_list, 1);
LLVMSetInitializer(decl_list, llvm_emit_aggregate_two(c, decls_array_type, decl_ref, count));
@@ -1309,9 +1311,7 @@ static void llvm_gen_benchmark_main(GenContext *c)
LLVMTypeRef runner_type = LLVMFunctionType(c->byte_type, NULL, 0, true);
LLVMValueRef func = LLVMAddFunction(c->module, kw_main, main_type);
LLVMValueRef other_func = LLVMAddFunction(c->module, benchmark_runner->extname, runner_type);
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, func, "entry");
LLVMBuilderRef builder = llvm_create_builder(c);
LLVMPositionBuilderAtEnd(builder, entry);
LLVMBuilderRef builder = llvm_create_function_entry(c, func, NULL);
LLVMValueRef val = LLVMBuildCall2(builder, runner_type, other_func, NULL, 0, "");
val = LLVMBuildSelect(builder, LLVMBuildTrunc(builder, val, c->bool_type, ""),
LLVMConstNull(cint), LLVMConstInt(cint, 1, false), "");
@@ -1371,11 +1371,11 @@ INLINE GenContext *llvm_gen_benchmarks(Module** modules, unsigned module_count,
decl_ref = LLVMConstNull(c->ptr_type);
}
LLVMValueRef count = llvm_const_int(c, type_usz, benchmark_count);
Type *chars_array = type_get_subarray(type_chars);
Type *chars_array = type_get_slice(type_chars);
LLVMValueRef name_list = llvm_add_global(c, benchmark_names_var_name, chars_array, type_alloca_alignment(chars_array));
LLVMSetGlobalConstant(name_list, 1);
LLVMSetInitializer(name_list, llvm_emit_aggregate_two(c, chars_array, name_ref, count));
Type *decls_array_type = type_get_subarray(type_voidptr);
Type *decls_array_type = type_get_slice(type_voidptr);
LLVMValueRef decl_list = llvm_add_global(c, benchmark_fns_var_name, decls_array_type, type_alloca_alignment(decls_array_type));
LLVMSetGlobalConstant(decl_list, 1);
LLVMSetInitializer(decl_list, llvm_emit_aggregate_two(c, decls_array_type, decl_ref, count));
@@ -1492,9 +1492,7 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
gencontext_init_file_emit(gen_context, unit);
gen_context->debug.compile_unit = unit->llvm.debug_compile_unit;
gen_context->debug.file = (DebugFile){
.debug_file = unit->llvm.debug_file,
.file_id = unit->file->file_id };
gen_context->debug.file = (DebugFile){ .debug_file = unit->llvm.debug_file, .file_id = unit->file->file_id };
FOREACH_BEGIN(Decl *method, unit->methods)
if (only_used && !method->is_live) continue;
@@ -1681,13 +1679,6 @@ LLVMValueRef llvm_emit_memcpy(GenContext *c, LLVMValueRef dest, unsigned dest_al
return LLVMBuildMemCpy(c->builder, dest, dest_align, source, src_align, llvm_const_int(c, type_ulong, len));
}
void llvm_emit_memcpy_to_decl(GenContext *c, Decl *decl, LLVMValueRef source, unsigned source_alignment)
{
if (source_alignment == 0) source_alignment = type_abi_alignment(decl->type);
assert(!decl->is_value);
llvm_emit_memcpy(c, decl->backend_ref, decl->alignment, source, source_alignment, type_size(decl->type));
}
TypeSize llvm_store_size(GenContext *c, LLVMTypeRef type)
{
return (TypeSize)LLVMStoreSizeOfType(c->target_data, type);

View File

@@ -115,14 +115,8 @@ INLINE void llvm_emit_compare_exchange(GenContext *c, BEValue *result_value, Exp
assert(is_power_of_two(alignment));
LLVMSetAlignment(result, alignment);
}
if (is_volatile)
{
LLVMSetVolatile(result, true);
}
if (is_weak)
{
LLVMSetWeak(result, true);
}
if (is_volatile) LLVMSetVolatile(result, true);
if (is_weak) LLVMSetWeak(result, true);
llvm_value_set(result_value, llvm_emit_extract_value(c, result, 0), type);
}
@@ -131,9 +125,6 @@ INLINE void llvm_emit_unreachable_stmt(GenContext *c, BEValue *result_value, Exp
{
llvm_value_set(result_value, LLVMBuildUnreachable(c->builder), type_void);
c->current_block = NULL;
c->current_block_is_target = false;
LLVMBasicBlockRef after_unreachable = llvm_basic_block_new(c, "after.unreachable");
llvm_emit_block(c, after_unreachable);
}
INLINE void llvm_emit_volatile_store(GenContext *c, BEValue *result_value, Expr *expr)
@@ -754,7 +745,7 @@ static inline void llvm_emit_any_make(GenContext *c, BEValue *value, Expr *expr)
Expr *typeid = args[1];
if (expr_is_const(typeid) && typeid->const_expr.typeid == type_void)
{
llvm_value_set(value, llvm_get_zero(c, type_anyptr), type_anyptr);
llvm_value_set(value, llvm_get_zero(c, type_any), type_any);
return;
}
BEValue ptr;
@@ -763,11 +754,11 @@ static inline void llvm_emit_any_make(GenContext *c, BEValue *value, Expr *expr)
BEValue typeid_value;
llvm_emit_expr(c, &typeid_value, typeid);
llvm_value_rvalue(c, &typeid_value);
LLVMValueRef var = llvm_get_undef(c, type_anyptr);
LLVMValueRef var = llvm_get_undef(c, type_any);
var = llvm_emit_insert_value(c, var, ptr.value, 0);
var = llvm_emit_insert_value(c, var, typeid_value.value, 1);
assert(!LLVMIsConstant(ptr.value) || !LLVMIsConstant(typeid_value.value) || LLVMIsConstant(var));
llvm_value_set(value, var, type_anyptr);
llvm_value_set(value, var, type_any);
}

View File

@@ -18,10 +18,15 @@ static LLVMMetadataRef llvm_debug_vector_type(GenContext *c, Type *type);
static LLVMMetadataRef llvm_debug_typedef_type(GenContext *c, Type *type);
static LLVMMetadataRef llvm_debug_array_type(GenContext *c, Type *type);
static LLVMMetadataRef llvm_debug_errunion_type(GenContext *c, Type *type);
static LLVMMetadataRef llvm_debug_subarray_type(GenContext *c, Type *type);
static LLVMMetadataRef llvm_debug_slice_type(GenContext *c, Type *type);
static LLVMMetadataRef llvm_debug_any_type(GenContext *c, Type *type);
static LLVMMetadataRef llvm_debug_enum_type(GenContext *c, Type *type, LLVMMetadataRef scope);
INLINE LLVMMetadataRef llvm_create_debug_location_with_inline(GenContext *c, unsigned row, unsigned col, LLVMMetadataRef scope)
{
return LLVMDIBuilderCreateDebugLocation(c->context, row, col,
scope, c->debug.block_stack->inline_loc ? c->debug.block_stack->inline_loc : NULL);
}
static inline LLVMMetadataRef llvm_get_debug_struct(GenContext *c, Type *type, const char *external_name, LLVMMetadataRef *elements, unsigned element_count, SourceSpan *loc, LLVMMetadataRef scope, LLVMDIFlags flags)
{
LLVMMetadataRef file = NULL;
@@ -40,11 +45,12 @@ static inline LLVMMetadataRef llvm_get_debug_struct(GenContext *c, Type *type, c
row,
type_size(type) * 8,
(uint32_t)(type_abi_alignment(type) * 8),
flags, NULL,
flags,
NULL, // Derived from
elements, element_count,
c->debug.runtime_version,
NULL, // VTable
external_name, strlen(external_name));
external_name, external_name_len);
if (type->backend_debug_type)
{
LLVMMetadataReplaceAllUsesWith(type->backend_debug_type, real);
@@ -67,22 +73,10 @@ static inline LLVMMetadataRef llvm_get_debug_member(GenContext *c, Type *type, c
}
void llvm_debug_scope_push(GenContext *context, LLVMMetadataRef debug_scope)
{
vec_add(context->debug.lexical_block_stack, debug_scope);
}
void llvm_debug_scope_pop(GenContext *context)
{
vec_pop(context->debug.lexical_block_stack);
}
LLVMMetadataRef llvm_debug_current_scope(GenContext *context)
{
if (vec_size(context->debug.lexical_block_stack) > 0)
{
return VECLAST(context->debug.lexical_block_stack);
}
if (context->debug.block_stack) return context->debug.block_stack->lexical_block;
return context->debug.compile_unit;
}
@@ -108,8 +102,8 @@ void llvm_emit_debug_global_var(GenContext *c, Decl *global)
void llvm_emit_debug_function(GenContext *c, Decl *decl)
{
LLVMDIFlags flags = LLVMDIFlagZero;
if (!decl->func_decl.body) return;
LLVMDIFlags flags = LLVMDIFlagZero;
flags |= LLVMDIFlagPrototyped;
if (decl->func_decl.signature.attrs.noreturn) flags |= LLVMDIFlagNoReturn;
@@ -159,13 +153,11 @@ void llvm_emit_debug_local_var(GenContext *c, Decl *decl)
decl->alignment);
decl->var.backend_debug_ref = var;
LLVMMetadataRef inline_at = NULL;
assert(!decl->is_value);
LLVMDIBuilderInsertDeclareAtEnd(c->debug.builder,
decl->backend_ref, var,
LLVMDIBuilderCreateExpression(c->debug.builder, NULL, 0),
LLVMDIBuilderCreateDebugLocation(c->context, row, col,
scope, inline_at),
llvm_create_debug_location_with_inline(c, row, col, scope),
LLVMGetInsertBlock(c->builder));
}
@@ -197,14 +189,11 @@ void llvm_emit_debug_parameter(GenContext *c, Decl *parameter, unsigned index)
llvm_get_debug_type(c, parameter->type),
always_preserve,
LLVMDIFlagZero);
LLVMMetadataRef inline_at = NULL;
if (parameter->is_value)
{
LLVMDIBuilderInsertDbgValueAtEnd(c->debug.builder, parameter->backend_value, parameter->var.backend_debug_ref,
LLVMDIBuilderCreateExpression(c->debug.builder, NULL, 0),
LLVMDIBuilderCreateDebugLocation(c->context, row, col, c->debug.function,
inline_at),
llvm_create_debug_location_with_inline(c, row, col, c->debug.function),
LLVMGetInsertBlock(c->builder));
return;
}
@@ -213,29 +202,30 @@ void llvm_emit_debug_parameter(GenContext *c, Decl *parameter, unsigned index)
parameter->backend_ref,
parameter->var.backend_debug_ref,
LLVMDIBuilderCreateExpression(c->debug.builder, NULL, 0),
LLVMDIBuilderCreateDebugLocation(c->context, row, col, c->debug.function,
inline_at),
llvm_create_debug_location_with_inline(c, row, col, c->debug.function),
LLVMGetInsertBlock(c->builder));
}
LLVMMetadataRef llvm_create_debug_location(GenContext *c, SourceSpan location)
{
LLVMMetadataRef scope = llvm_debug_current_scope(c);
unsigned row = location.row;
unsigned col = location.col;
return llvm_create_debug_location_with_inline(c, row ? row : 1, col ? col : 1, scope);
}
void llvm_emit_debug_location(GenContext *c, SourceSpan location)
{
if (llvm_is_global_eval(c)) return;
// Avoid re-emitting the same location.
LLVMMetadataRef oldloc = LLVMGetCurrentDebugLocation2(c->builder);
if (oldloc && c->last_emitted_loc.a == location.a) return;
LLVMMetadataRef scope = llvm_debug_current_scope(c);
unsigned row = location.row;
unsigned col = location.col;
LLVMMetadataRef loc = c->last_loc = llvm_create_debug_location(c, location);
c->last_emitted_loc.a = location.a;
LLVMMetadataRef loc = LLVMDIBuilderCreateDebugLocation(c->context,
row ? row : 1,
col ? col : 1,
scope, /* inlined at */ 0);
LLVMSetCurrentDebugLocation2(c->builder, loc);
}
static LLVMMetadataRef llvm_debug_forward_comp(GenContext *c, Type *type, const char *external_name, SourceSpan *loc, LLVMMetadataRef scope, LLVMDIFlags flags)
@@ -258,16 +248,34 @@ static LLVMMetadataRef llvm_debug_forward_comp(GenContext *c, Type *type, const
strlen(external_name));
}
void llvm_debug_push_lexical_scope(GenContext *context, SourceSpan location)
LLVMMetadataRef llvm_debug_create_macro(GenContext *c, Decl *macro)
{
SourceSpan location = macro->span;
const char *name = macro->name;
size_t namelen = strlen(name);
LLVMMetadataRef file = llvm_get_debug_file(c, location.file_id);
LLVMMetadataRef macro_type = NULL;
return LLVMDIBuilderCreateFunction(c->debug.builder, file, name, namelen, name, namelen,
file, location.row, macro_type, true, true, location.row, LLVMDIFlagZero, false);
}
DebugScope llvm_debug_create_lexical_scope(GenContext *context, SourceSpan location)
{
LLVMMetadataRef scope;
if (vec_size(context->debug.lexical_block_stack) > 0)
LLVMMetadataRef inline_at;
DebugScope *outline_at;
if (context->debug.block_stack)
{
scope = VECLAST(context->debug.lexical_block_stack);
scope = context->debug.block_stack->lexical_block;
inline_at = context->debug.block_stack->inline_loc;
outline_at = context->debug.block_stack->outline_loc;
}
else
{
scope = context->debug.compile_unit;
inline_at = NULL;
outline_at = NULL;
}
unsigned row = location.row;
@@ -277,15 +285,13 @@ void llvm_debug_push_lexical_scope(GenContext *context, SourceSpan location)
{
debug_file = llvm_get_debug_file(context, location.file_id);
}
LLVMMetadataRef block =
LLVMDIBuilderCreateLexicalBlock(context->debug.builder, scope, debug_file,
row ? row : 1,
col ? col : 1);
LLVMMetadataRef block = LLVMDIBuilderCreateLexicalBlock(context->debug.builder, scope, debug_file, row ? row : 1, col ? col : 1);
llvm_debug_scope_push(context, block);
return (DebugScope) { .lexical_block = block, .inline_loc = inline_at, .outline_loc = outline_at };
}
static LLVMMetadataRef llvm_debug_typeid_type(GenContext *context, Type *type)
{
return type->backend_debug_type = LLVMDIBuilderCreateBasicType(context->debug.builder,
@@ -402,7 +408,7 @@ static LLVMMetadataRef llvm_debug_structlike_type(GenContext *c, Type *type, LLV
return llvm_get_debug_struct(c, type, decl->name ? decl->extname : "", elements, vec_size(elements), &decl->span, scope, LLVMDIFlagZero);
}
static LLVMMetadataRef llvm_debug_subarray_type(GenContext *c, Type *type)
static LLVMMetadataRef llvm_debug_slice_type(GenContext *c, Type *type)
{
LLVMMetadataRef forward = llvm_debug_forward_comp(c, type, type->name, NULL, NULL, LLVMDIFlagZero);
type->backend_debug_type = forward;
@@ -564,8 +570,6 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type *
switch (type->type_kind)
{
case CT_TYPES:
case TYPE_INTERFACE:
case TYPE_ANY:
UNREACHABLE
case TYPE_BITSTRUCT:
case TYPE_OPTIONAL:
@@ -615,12 +619,12 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type *
case TYPE_FLEXIBLE_ARRAY:
case TYPE_ARRAY:
return type->backend_debug_type = llvm_debug_array_type(c, type);
case TYPE_SUBARRAY:
return type->backend_debug_type = llvm_debug_subarray_type(c, type);
case TYPE_SLICE:
return type->backend_debug_type = llvm_debug_slice_type(c, type);
case TYPE_ANYFAULT:
return type->backend_debug_type = llvm_debug_errunion_type(c, type);
case TYPE_INFPTR:
case TYPE_ANYPTR:
case TYPE_INTERFACE:
case TYPE_ANY:
return type->backend_debug_type = llvm_debug_any_type(c, type);
}
UNREACHABLE

Some files were not shown because too many files have changed in this diff Show More