mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Compare commits
21 Commits
latest-0.7
...
v0.5.x
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14d7fd1d08 | ||
|
|
43c11118ec | ||
|
|
407dec0238 | ||
|
|
9b21f411ba | ||
|
|
cbb2cad2b8 | ||
|
|
f99baf479e | ||
|
|
4fc1e39fa2 | ||
|
|
5a6443060e | ||
|
|
ab2e18e255 | ||
|
|
4548c474bc | ||
|
|
c644af7ced | ||
|
|
f6697b33bf | ||
|
|
a4df94d228 | ||
|
|
edd0a4022b | ||
|
|
f7e7e16c25 | ||
|
|
ddfc9313e0 | ||
|
|
7e7a4094f1 | ||
|
|
e90254da03 | ||
|
|
c1b57f9391 | ||
|
|
522a7a9011 | ||
|
|
fc849c1440 |
33
.github/workflows/main.yml
vendored
33
.github/workflows/main.yml
vendored
@@ -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
|
||||
@@ -112,8 +112,8 @@ jobs:
|
||||
install: git binutils mingw-w64-x86_64-clang mingw-w64-x86_64-ninja mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-python
|
||||
- shell: msys2 {0}
|
||||
run: |
|
||||
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-llvm-18.1.5-1-any.pkg.tar.zst
|
||||
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-lld-18.1.5-1-any.pkg.tar.zst
|
||||
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-llvm-18.1.6-1-any.pkg.tar.zst
|
||||
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-lld-18.1.6-1-any.pkg.tar.zst
|
||||
- name: CMake
|
||||
run: |
|
||||
cmake -B build -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
@@ -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: |
|
||||
|
||||
@@ -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).
|
||||
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
**/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
**/
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)!!;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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?;
|
||||
|
||||
@@ -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')!;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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..])!;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
@@ -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>);
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)!;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {};
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {};
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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()!;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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".
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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".
|
||||
|
||||
11
resources/examples/stacktrace_example.c3
Normal file
11
resources/examples/stacktrace_example.c3
Normal file
@@ -0,0 +1,11 @@
|
||||
fn void main() {
|
||||
foo();
|
||||
}
|
||||
|
||||
fn void foo() {
|
||||
bar();
|
||||
}
|
||||
|
||||
macro bar() {
|
||||
unreachable();
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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)!!;
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user