mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 20:11:17 +00:00
Compare commits
27 Commits
dev3
...
latest-pre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
808ce6d605 | ||
|
|
09606a2998 | ||
|
|
0a21323652 | ||
|
|
c990b5aaf1 | ||
|
|
98e0985a10 | ||
|
|
5974bf6cd0 | ||
|
|
992890065a | ||
|
|
d4dbe27072 | ||
|
|
56a11ae3ca | ||
|
|
f1d03c194f | ||
|
|
0085fe73ad | ||
|
|
a238b62483 | ||
|
|
58022e7cca | ||
|
|
d2f046780d | ||
|
|
ec65c5761e | ||
|
|
0ed917cdc2 | ||
|
|
8373ab0509 | ||
|
|
8f7610345d | ||
|
|
8bd963ecaf | ||
|
|
dc52478c09 | ||
|
|
e1ec4b1235 | ||
|
|
7c68396c0d | ||
|
|
eae7d0c4a1 | ||
|
|
5055e86518 | ||
|
|
4b13ad692a | ||
|
|
7c81bb35ca | ||
|
|
5a82f672b5 |
@@ -142,7 +142,7 @@ fn void main()
|
||||
|
||||
### Current status
|
||||
|
||||
The current stable version of the compiler is **version 0.7.9**.
|
||||
The current stable version of the compiler is **version 0.7.10**.
|
||||
|
||||
The upcoming 0.7.x releases will focus on expanding the standard library,
|
||||
fixing bugs and improving compile time analysis.
|
||||
|
||||
51
benchmarks/stdlib/compression/deflate.c3
Normal file
51
benchmarks/stdlib/compression/deflate.c3
Normal file
@@ -0,0 +1,51 @@
|
||||
module deflate_benchmarks;
|
||||
import std::compression::deflate;
|
||||
|
||||
const uint SMALL_ITERATIONS = 50000;
|
||||
const uint LARGE_ITERATIONS = 100;
|
||||
|
||||
// Data to compress
|
||||
const char[] SMALL_DATA = { [0..1023] = 'A' };
|
||||
const char[] LARGE_DATA = { [0..1048575] = 'B' };
|
||||
|
||||
char[] small_compressed;
|
||||
char[] large_compressed;
|
||||
|
||||
fn void initialize_bench() @init
|
||||
{
|
||||
small_compressed = deflate::compress(mem, SMALL_DATA)!!;
|
||||
large_compressed = deflate::compress(mem, LARGE_DATA)!!;
|
||||
set_benchmark_warmup_iterations(2);
|
||||
set_benchmark_max_iterations(10);
|
||||
|
||||
set_benchmark_func_iterations($qnameof(deflate_compress_small), SMALL_ITERATIONS);
|
||||
set_benchmark_func_iterations($qnameof(deflate_decompress_small), SMALL_ITERATIONS);
|
||||
set_benchmark_func_iterations($qnameof(deflate_compress_large), LARGE_ITERATIONS);
|
||||
set_benchmark_func_iterations($qnameof(deflate_decompress_large), LARGE_ITERATIONS);
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
module deflate_benchmarks @benchmark;
|
||||
|
||||
import std::compression::deflate;
|
||||
import std::core::mem;
|
||||
|
||||
fn void deflate_compress_small() => @pool()
|
||||
{
|
||||
char[]? compressed = deflate::compress(tmem, SMALL_DATA);
|
||||
}
|
||||
|
||||
fn void deflate_decompress_small() => @pool()
|
||||
{
|
||||
char[]? decompressed = deflate::decompress(tmem, small_compressed);
|
||||
}
|
||||
|
||||
fn void deflate_compress_large() => @pool()
|
||||
{
|
||||
char[]? compressed = deflate::compress(tmem, LARGE_DATA);
|
||||
}
|
||||
|
||||
fn void deflate_decompress_large() => @pool()
|
||||
{
|
||||
char[]? decompressed = deflate::decompress(tmem, large_compressed);
|
||||
}
|
||||
@@ -32,8 +32,8 @@ fn void initialize_bench() @init
|
||||
$qnameof(sha1_16)[..^4],
|
||||
$qnameof(sha2_256_16)[..^4],
|
||||
$qnameof(sha2_512_16)[..^4],
|
||||
$qnameof(blake2s_256_16)[..^4],
|
||||
$qnameof(blake2b_256_16)[..^4],
|
||||
//$qnameof(blake2s_256_16)[..^4],
|
||||
//$qnameof(blake2b_256_16)[..^4],
|
||||
$qnameof(blake3_16)[..^4],
|
||||
$qnameof(ripemd_160_16)[..^4],
|
||||
$qnameof(whirlpool_16)[..^4],
|
||||
@@ -68,8 +68,8 @@ fn void md5_16() => md5::hash(common_16);
|
||||
fn void sha1_16() => sha1::hash(common_16);
|
||||
fn void sha2_256_16() => sha256::hash(common_16);
|
||||
fn void sha2_512_16() => sha512::hash(common_16);
|
||||
fn void blake2s_256_16() => blake2::s(256, common_16);
|
||||
fn void blake2b_256_16() => blake2::b(256, common_16);
|
||||
//fn void blake2s_256_16() => blake2::s(256, common_16);
|
||||
//fn void blake2b_256_16() => blake2::b(256, common_16);
|
||||
fn void blake3_16() => blake3::hash(common_16);
|
||||
fn void ripemd_160_16() => ripemd::hash{160}(common_16);
|
||||
fn void whirlpool_16() => whirlpool::hash(common_16);
|
||||
@@ -80,8 +80,8 @@ fn void md5_256() => md5::hash(common_256);
|
||||
fn void sha1_256() => sha1::hash(common_256);
|
||||
fn void sha2_256_256() => sha256::hash(common_256);
|
||||
fn void sha2_512_256() => sha512::hash(common_256);
|
||||
fn void blake2s_256_256() => blake2::s(256, common_256);
|
||||
fn void blake2b_256_256() => blake2::b(256, common_256);
|
||||
//fn void blake2s_256_256() => blake2::s(256, common_256);
|
||||
//fn void blake2b_256_256() => blake2::b(256, common_256);
|
||||
fn void blake3_256() => blake3::hash(common_256);
|
||||
fn void ripemd_160_256() => ripemd::hash{160}(common_256);
|
||||
fn void whirlpool_256() => whirlpool::hash(common_256);
|
||||
@@ -92,8 +92,8 @@ fn void md5_4kib() => md5::hash(common_4kib);
|
||||
fn void sha1_4kib() => sha1::hash(common_4kib);
|
||||
fn void sha2_256_4kib() => sha256::hash(common_4kib);
|
||||
fn void sha2_512_4kib() => sha512::hash(common_4kib);
|
||||
fn void blake2s_256_4kib() => blake2::s(256, common_4kib);
|
||||
fn void blake2b_256_4kib() => blake2::b(256, common_4kib);
|
||||
//fn void blake2s_256_4kib() => blake2::s(256, common_4kib);
|
||||
//fn void blake2b_256_4kib() => blake2::b(256, common_4kib);
|
||||
fn void blake3_4kib() => blake3::hash(common_4kib);
|
||||
fn void ripemd_160_4kib() => ripemd::hash{160}(common_4kib);
|
||||
fn void whirlpool_4kib() => whirlpool::hash(common_4kib);
|
||||
@@ -104,8 +104,8 @@ fn void md5_1mib() => md5::hash(common_1mib);
|
||||
fn void sha1_1mib() => sha1::hash(common_1mib);
|
||||
fn void sha2_256_1mib() => sha256::hash(common_1mib);
|
||||
fn void sha2_512_1mib() => sha512::hash(common_1mib);
|
||||
fn void blake2s_256_1mib() => blake2::s(256, common_1mib);
|
||||
fn void blake2b_256_1mib() => blake2::b(256, common_1mib);
|
||||
//fn void blake2s_256_1mib() => blake2::s(256, common_1mib);
|
||||
//fn void blake2b_256_1mib() => blake2::b(256, common_1mib);
|
||||
fn void blake3_1mib() => blake3::hash(common_1mib);
|
||||
fn void ripemd_160_1mib() => ripemd::hash{160}(common_1mib);
|
||||
fn void whirlpool_1mib() => whirlpool::hash(common_1mib);
|
||||
|
||||
@@ -115,8 +115,8 @@ macro bool is_native_atomic_type($Type)
|
||||
$case FLOAT:
|
||||
$case BOOL:
|
||||
return true;
|
||||
$case DISTINCT:
|
||||
$case CONST_ENUM:
|
||||
$case TYPEDEF:
|
||||
$case CONSTDEF:
|
||||
return is_native_atomic_type($Type.inner);
|
||||
$default:
|
||||
return false;
|
||||
|
||||
@@ -150,7 +150,7 @@ fn bool HashMap.is_initialized(&map)
|
||||
fn HashMap* HashMap.init_from_map(&self, Allocator allocator, HashMap* other_map)
|
||||
{
|
||||
self.init(allocator, other_map.table.len, other_map.load_factor);
|
||||
self.put_all_for_create(other_map);
|
||||
hashmap_put_all_for_create(self, other_map);
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ macro Value HashMap.@get_or_set(&map, Key key, Value #expr)
|
||||
if (e.hash == hash && equals(key, e.key)) return e.value;
|
||||
}
|
||||
Value val = #expr;
|
||||
map.add_entry(hash, key, val, index);
|
||||
hashmap_add_entry(map, hash, key, val, index);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -269,13 +269,13 @@ fn bool HashMap.set(&map, Key key, Value value) @operator([]=)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
map.add_entry(hash, key, value, index);
|
||||
hashmap_add_entry(map, hash, key, value, index);
|
||||
return false;
|
||||
}
|
||||
|
||||
fn void? HashMap.remove(&map, Key key) @maydiscard
|
||||
{
|
||||
if (!map.remove_entry_for_key(key)) return NOT_FOUND~;
|
||||
if (!hashmap_remove_entry_for_key(map, key)) return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn void HashMap.clear(&map)
|
||||
@@ -290,9 +290,9 @@ fn void HashMap.clear(&map)
|
||||
{
|
||||
Entry *to_delete = next;
|
||||
next = next.next;
|
||||
map.free_entry(to_delete);
|
||||
hashmap_free_entry(map, to_delete);
|
||||
}
|
||||
map.free_entry(entry);
|
||||
hashmap_free_entry(map, entry);
|
||||
*entry_ref = null;
|
||||
}
|
||||
map.count = 0;
|
||||
@@ -302,7 +302,7 @@ fn void HashMap.free(&map)
|
||||
{
|
||||
if (!map.is_initialized()) return;
|
||||
map.clear();
|
||||
map.free_internal(map.table.ptr);
|
||||
hashmap_free_internal(map, map.table.ptr);
|
||||
map.table = {};
|
||||
}
|
||||
|
||||
@@ -402,7 +402,7 @@ fn HashMapKeyIterator HashMap.key_iter(&self)
|
||||
|
||||
// --- private methods
|
||||
|
||||
fn void HashMap.add_entry(&map, uint hash, Key key, Value value, uint bucket_index) @private
|
||||
fn void hashmap_add_entry(HashMap* map, uint hash, Key key, Value value, uint bucket_index) @private
|
||||
{
|
||||
$if COPY_KEYS:
|
||||
key = key.copy(map.allocator);
|
||||
@@ -411,11 +411,11 @@ fn void HashMap.add_entry(&map, uint hash, Key key, Value value, uint bucket_ind
|
||||
map.table[bucket_index] = entry;
|
||||
if (map.count++ >= map.threshold)
|
||||
{
|
||||
map.resize(map.table.len * 2);
|
||||
hashmap_resize(map, map.table.len * 2);
|
||||
}
|
||||
}
|
||||
|
||||
fn void HashMap.resize(&map, uint new_capacity) @private
|
||||
fn void hashmap_resize(HashMap* map, uint new_capacity) @private
|
||||
{
|
||||
Entry*[] old_table = map.table;
|
||||
uint old_capacity = old_table.len;
|
||||
@@ -425,9 +425,9 @@ fn void HashMap.resize(&map, uint new_capacity) @private
|
||||
return;
|
||||
}
|
||||
Entry*[] new_table = allocator::new_array(map.allocator, Entry*, new_capacity);
|
||||
map.transfer(new_table);
|
||||
hashmap_transfer(map, new_table);
|
||||
map.table = new_table;
|
||||
map.free_internal(old_table.ptr);
|
||||
hashmap_free_internal(map, old_table.ptr);
|
||||
map.threshold = (uint)(new_capacity * map.load_factor);
|
||||
}
|
||||
|
||||
@@ -443,7 +443,7 @@ fn usz? HashMap.to_format(&self, Formatter* f) @dynamic
|
||||
return len + f.print(" }");
|
||||
}
|
||||
|
||||
fn void HashMap.transfer(&map, Entry*[] new_table) @private
|
||||
fn void hashmap_transfer(HashMap* map, Entry*[] new_table) @private
|
||||
{
|
||||
Entry*[] src = map.table;
|
||||
uint new_capacity = new_table.len;
|
||||
@@ -462,20 +462,20 @@ fn void HashMap.transfer(&map, Entry*[] new_table) @private
|
||||
}
|
||||
}
|
||||
|
||||
fn void HashMap.put_all_for_create(&map, HashMap* other_map) @private
|
||||
fn void hashmap_put_all_for_create(HashMap* map, HashMap* other_map) @private
|
||||
{
|
||||
if (!other_map.count) return;
|
||||
foreach (Entry *e : other_map.table)
|
||||
{
|
||||
while (e)
|
||||
{
|
||||
map.put_for_create(e.key, e.value);
|
||||
hashmap_put_for_create(map, e.key, e.value);
|
||||
e = e.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void HashMap.put_for_create(&map, Key key, Value value) @private
|
||||
fn void hashmap_put_for_create(HashMap* map, Key key, Value value) @private
|
||||
{
|
||||
uint hash = rehash(key.hash());
|
||||
uint i = index_for(hash, map.table.len);
|
||||
@@ -487,15 +487,15 @@ fn void HashMap.put_for_create(&map, Key key, Value value) @private
|
||||
return;
|
||||
}
|
||||
}
|
||||
map.create_entry(hash, key, value, i);
|
||||
hashmap_create_entry(map, hash, key, value, i);
|
||||
}
|
||||
|
||||
fn void HashMap.free_internal(&map, void* ptr) @inline @private
|
||||
fn void hashmap_free_internal(HashMap* map, void* ptr) @inline @private
|
||||
{
|
||||
allocator::free(map.allocator, ptr);
|
||||
}
|
||||
|
||||
fn bool HashMap.remove_entry_for_key(&map, Key key) @private
|
||||
fn bool hashmap_remove_entry_for_key(HashMap* map, Key key) @private
|
||||
{
|
||||
if (!map.count) return false;
|
||||
uint hash = rehash(key.hash());
|
||||
@@ -516,7 +516,7 @@ fn bool HashMap.remove_entry_for_key(&map, Key key) @private
|
||||
{
|
||||
prev.next = next;
|
||||
}
|
||||
map.free_entry(e);
|
||||
hashmap_free_entry(map, e);
|
||||
return true;
|
||||
}
|
||||
prev = e;
|
||||
@@ -525,7 +525,7 @@ fn bool HashMap.remove_entry_for_key(&map, Key key) @private
|
||||
return false;
|
||||
}
|
||||
|
||||
fn void HashMap.create_entry(&map, uint hash, Key key, Value value, int bucket_index) @private
|
||||
fn void hashmap_create_entry(HashMap* map, uint hash, Key key, Value value, int bucket_index) @private
|
||||
{
|
||||
Entry *e = map.table[bucket_index];
|
||||
$if COPY_KEYS:
|
||||
@@ -536,12 +536,12 @@ fn void HashMap.create_entry(&map, uint hash, Key key, Value value, int bucket_i
|
||||
map.count++;
|
||||
}
|
||||
|
||||
fn void HashMap.free_entry(&self, Entry *entry) @local
|
||||
fn void hashmap_free_entry(HashMap* map, Entry *entry) @local
|
||||
{
|
||||
$if COPY_KEYS:
|
||||
allocator::free(self.allocator, entry.key);
|
||||
allocator::free(map.allocator, entry.key);
|
||||
$endif
|
||||
self.free_internal(entry);
|
||||
hashmap_free_internal(map, entry);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ fn bool HashSet.is_initialized(&set)
|
||||
fn HashSet* HashSet.init_from_set(&self, Allocator allocator, HashSet* other_set)
|
||||
{
|
||||
self.init(allocator, other_set.table.len, other_set.load_factor);
|
||||
self.put_all_for_create(other_set);
|
||||
hashset_put_all_for_create(self, other_set);
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ fn bool HashSet.add(&set, Value value)
|
||||
{
|
||||
if (e.hash == hash && equals(value, e.value)) return false;
|
||||
}
|
||||
set.add_entry(hash, value, index);
|
||||
hashset_add_entry(set, hash, value, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ fn bool HashSet.contains(&set, Value value)
|
||||
*>
|
||||
fn void? HashSet.remove(&set, Value value) @maydiscard
|
||||
{
|
||||
if (!set.remove_entry_for_value(value)) return NOT_FOUND~;
|
||||
if (!hashset_remove_entry_for_value(set, value)) return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn usz HashSet.remove_all(&set, Value[] values)
|
||||
@@ -266,7 +266,7 @@ fn usz HashSet.remove_all(&set, Value[] values)
|
||||
usz total;
|
||||
foreach (v : values)
|
||||
{
|
||||
if (set.remove_entry_for_value(v)) total++;
|
||||
if (hashset_remove_entry_for_value(set, v)) total++;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
@@ -279,7 +279,7 @@ fn usz HashSet.remove_all_from(&set, HashSet* other)
|
||||
usz total;
|
||||
other.@each(;Value val)
|
||||
{
|
||||
if (set.remove_entry_for_value(val)) total++;
|
||||
if (hashset_remove_entry_for_value(set, val)) total++;
|
||||
};
|
||||
return total;
|
||||
}
|
||||
@@ -291,7 +291,7 @@ fn void HashSet.free(&set)
|
||||
{
|
||||
if (!set.is_initialized()) return;
|
||||
set.clear();
|
||||
set.free_internal(set.table.ptr);
|
||||
hashset_free_internal(set, set.table.ptr);
|
||||
*set = {};
|
||||
}
|
||||
|
||||
@@ -314,10 +314,10 @@ fn void HashSet.clear(&set)
|
||||
{
|
||||
Entry *to_delete = next;
|
||||
next = next.next;
|
||||
set.free_entry(to_delete);
|
||||
hashset_free_entry(set, to_delete);
|
||||
}
|
||||
|
||||
set.free_entry(entry);
|
||||
hashset_free_entry(set, entry);
|
||||
*entry_ref = null;
|
||||
}
|
||||
set.count = 0;
|
||||
@@ -327,7 +327,7 @@ fn void HashSet.reserve(&set, usz capacity)
|
||||
{
|
||||
if (capacity > set.threshold)
|
||||
{
|
||||
set.resize(math::next_power_of_2(capacity));
|
||||
hashset_resize(set, math::next_power_of_2(capacity));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,17 +464,17 @@ fn bool HashSet.is_subset(&self, HashSet* other)
|
||||
|
||||
// --- private methods
|
||||
|
||||
fn void HashSet.add_entry(&set, uint hash, Value value, uint bucket_index) @private
|
||||
fn void hashset_add_entry(HashSet* set, uint hash, Value value, uint bucket_index) @private
|
||||
{
|
||||
Entry* entry = allocator::new(set.allocator, Entry, { .hash = hash, .value = value, .next = set.table[bucket_index] });
|
||||
set.table[bucket_index] = entry;
|
||||
if (set.count++ >= set.threshold)
|
||||
{
|
||||
set.resize(set.table.len * 2);
|
||||
hashset_resize(set, set.table.len * 2);
|
||||
}
|
||||
}
|
||||
|
||||
fn void HashSet.resize(&self, usz new_capacity) @private
|
||||
fn void hashset_resize(HashSet* self, usz new_capacity) @private
|
||||
{
|
||||
Entry*[] old_table = self.table;
|
||||
usz old_capacity = old_table.len;
|
||||
@@ -484,9 +484,9 @@ fn void HashSet.resize(&self, usz new_capacity) @private
|
||||
return;
|
||||
}
|
||||
Entry*[] new_table = allocator::new_array(self.allocator, Entry*, new_capacity);
|
||||
self.transfer(new_table);
|
||||
hashset_transfer(self, new_table);
|
||||
self.table = new_table;
|
||||
self.free_internal(old_table.ptr);
|
||||
hashset_free_internal(self, old_table.ptr);
|
||||
self.threshold = (uint)(new_capacity * self.load_factor);
|
||||
}
|
||||
|
||||
@@ -502,7 +502,7 @@ fn usz? HashSet.to_format(&self, Formatter* f) @dynamic
|
||||
return len + f.print(" }");
|
||||
}
|
||||
|
||||
fn void HashSet.transfer(&self, Entry*[] new_table) @private
|
||||
fn void hashset_transfer(HashSet* self, Entry*[] new_table) @private
|
||||
{
|
||||
Entry*[] src = self.table;
|
||||
uint new_capacity = new_table.len;
|
||||
@@ -521,20 +521,20 @@ fn void HashSet.transfer(&self, Entry*[] new_table) @private
|
||||
}
|
||||
}
|
||||
|
||||
fn void HashSet.put_all_for_create(&set, HashSet* other_set) @private
|
||||
fn void hashset_put_all_for_create(HashSet* set, HashSet* other_set) @private
|
||||
{
|
||||
if (!other_set.count) return;
|
||||
foreach (Entry *e : other_set.table)
|
||||
{
|
||||
while (e)
|
||||
{
|
||||
set.put_for_create(e.value);
|
||||
hashset_put_for_create(set, e.value);
|
||||
e = e.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void HashSet.put_for_create(&set, Value value) @private
|
||||
fn void hashset_put_for_create(HashSet* set, Value value) @private
|
||||
{
|
||||
uint hash = rehash(value.hash());
|
||||
uint i = index_for(hash, set.table.len);
|
||||
@@ -546,15 +546,15 @@ fn void HashSet.put_for_create(&set, Value value) @private
|
||||
return;
|
||||
}
|
||||
}
|
||||
set.create_entry(hash, value, i);
|
||||
hashset_create_entry(set, hash, value, i);
|
||||
}
|
||||
|
||||
fn void HashSet.free_internal(&self, void* ptr) @inline @private
|
||||
fn void hashset_free_internal(HashSet* self, void* ptr) @inline @private
|
||||
{
|
||||
allocator::free(self.allocator, ptr);
|
||||
}
|
||||
|
||||
fn void HashSet.create_entry(&set, uint hash, Value value, int bucket_index) @private
|
||||
fn void hashset_create_entry(HashSet* set, uint hash, Value value, int bucket_index) @private
|
||||
{
|
||||
Entry* entry = allocator::new(set.allocator, Entry, {
|
||||
.hash = hash,
|
||||
@@ -569,7 +569,7 @@ fn void HashSet.create_entry(&set, uint hash, Value value, int bucket_index) @pr
|
||||
Removes the entry for the specified value if present
|
||||
@return "true if found and removed, false otherwise"
|
||||
*>
|
||||
fn bool HashSet.remove_entry_for_value(&set, Value value) @private
|
||||
fn bool hashset_remove_entry_for_value(HashSet* set, Value value) @private
|
||||
{
|
||||
if (!set.count) return false;
|
||||
uint hash = rehash(value.hash());
|
||||
@@ -590,7 +590,7 @@ fn bool HashSet.remove_entry_for_value(&set, Value value) @private
|
||||
{
|
||||
prev.next = next;
|
||||
}
|
||||
set.free_entry(e);
|
||||
hashset_free_entry(set, e);
|
||||
return true;
|
||||
}
|
||||
prev = e;
|
||||
@@ -600,7 +600,7 @@ fn bool HashSet.remove_entry_for_value(&set, Value value) @private
|
||||
return false;
|
||||
}
|
||||
|
||||
fn void HashSet.free_entry(&set, Entry *entry) @private
|
||||
fn void hashset_free_entry(HashSet* set, Entry *entry) @private
|
||||
{
|
||||
allocator::free(set.allocator, entry);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ fn bool InterfaceList.is_initialized(&self) @inline => self.allocator != null;
|
||||
macro void InterfaceList.push(&self, element)
|
||||
{
|
||||
if (!self.allocator) self.allocator = tmem;
|
||||
self._append(allocator::clone(self.allocator, element));
|
||||
interfacelist_append(self, allocator::clone(self.allocator, element));
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -381,7 +381,7 @@ fn usz? InterfaceList.to_format(&self, Formatter* formatter) @dynamic
|
||||
*>
|
||||
fn usz InterfaceList.remove_if(&self, InterfacePredicate filter)
|
||||
{
|
||||
return self._remove_if(filter, false);
|
||||
return interfacelist_remove_if(self, filter, false);
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -392,7 +392,7 @@ fn usz InterfaceList.remove_if(&self, InterfacePredicate filter)
|
||||
*>
|
||||
fn usz InterfaceList.retain_if(&self, InterfacePredicate selection)
|
||||
{
|
||||
return self._remove_if(selection, true);
|
||||
return interfacelist_remove_if(self, selection, true);
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -404,7 +404,7 @@ fn usz InterfaceList.retain_if(&self, InterfacePredicate selection)
|
||||
*>
|
||||
fn usz InterfaceList.remove_using_test(&self, InterfaceTest filter, Type context)
|
||||
{
|
||||
return self._remove_using_test(filter, false, context);
|
||||
return interfacelist_remove_using_test(self, filter, false, context);
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -416,7 +416,7 @@ fn usz InterfaceList.remove_using_test(&self, InterfaceTest filter, Type context
|
||||
*>
|
||||
fn usz InterfaceList.retain_using_test(&self, InterfaceTest selection, Type context)
|
||||
{
|
||||
return self._remove_using_test(selection, true, context);
|
||||
return interfacelist_remove_using_test(self, selection, true, context);
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -455,7 +455,7 @@ macro void InterfaceList.set(&self, usz index, value)
|
||||
|
||||
// -- private
|
||||
|
||||
fn void InterfaceList.ensure_capacity(&self, usz added = 1) @inline @private
|
||||
fn void interfacelist_ensure_capacity(InterfaceList* self, usz added = 1) @inline @private
|
||||
{
|
||||
usz new_size = self.size + added;
|
||||
if (self.capacity >= new_size) return;
|
||||
@@ -466,18 +466,18 @@ fn void InterfaceList.ensure_capacity(&self, usz added = 1) @inline @private
|
||||
self.reserve(new_capacity);
|
||||
}
|
||||
|
||||
fn void InterfaceList._append(&self, Type element) @local
|
||||
fn void interfacelist_append(InterfaceList* self, Type element) @local
|
||||
{
|
||||
self.ensure_capacity();
|
||||
interfacelist_ensure_capacity(self);
|
||||
self.entries[self.size++] = element;
|
||||
}
|
||||
|
||||
<*
|
||||
@require index < self.size
|
||||
*>
|
||||
fn void InterfaceList._insert_at(&self, usz index, Type value) @local
|
||||
fn void interfacelist_insert_at(InterfaceList* self, usz index, Type value) @local
|
||||
{
|
||||
self.ensure_capacity();
|
||||
interfacelist_ensure_capacity(self);
|
||||
for (usz i = self.size; i > index; i--)
|
||||
{
|
||||
self.entries[i] = self.entries[i - 1];
|
||||
@@ -486,7 +486,7 @@ fn void InterfaceList._insert_at(&self, usz index, Type value) @local
|
||||
self.entries[index] = value;
|
||||
}
|
||||
|
||||
macro usz InterfaceList._remove_using_test(&self, InterfaceTest filter, bool $invert, ctx) @local
|
||||
macro usz interfacelist_remove_using_test(InterfaceList* self, InterfaceTest filter, bool $invert, ctx) @local
|
||||
{
|
||||
usz size = self.size;
|
||||
for (usz i = size, usz k = size; k > 0; k = i)
|
||||
@@ -512,7 +512,7 @@ macro usz InterfaceList._remove_using_test(&self, InterfaceTest filter, bool $in
|
||||
return size - self.size;
|
||||
}
|
||||
|
||||
macro usz InterfaceList._remove_if(&self, InterfacePredicate filter, bool $invert) @local
|
||||
macro usz interfacelist_remove_if(InterfaceList* self, InterfacePredicate filter, bool $invert) @local
|
||||
{
|
||||
usz size = self.size;
|
||||
for (usz i = size, usz k = size; k > 0; k = i)
|
||||
|
||||
@@ -75,7 +75,7 @@ fn void LinkedBlockingQueue.free(&self)
|
||||
self.not_full.destroy();
|
||||
}
|
||||
|
||||
fn void LinkedBlockingQueue.link_entry(&self, QueueEntry* entry) @private
|
||||
fn void linkedblockingqueue_link_entry(LinkedBlockingQueue* self, QueueEntry* entry) @private
|
||||
{
|
||||
entry.next = null;
|
||||
entry.prev = self.tail;
|
||||
@@ -95,7 +95,7 @@ fn void LinkedBlockingQueue.link_entry(&self, QueueEntry* entry) @private
|
||||
}
|
||||
|
||||
|
||||
fn QueueEntry* LinkedBlockingQueue.unlink_head(&self) @private
|
||||
fn QueueEntry* linkedblockingqueue_unlink_head(LinkedBlockingQueue* self) @private
|
||||
{
|
||||
if (self.head == null) return null;
|
||||
|
||||
@@ -134,7 +134,7 @@ fn void LinkedBlockingQueue.push(&self, Value value)
|
||||
.next = null,
|
||||
.prev = null
|
||||
});
|
||||
self.link_entry(entry);
|
||||
linkedblockingqueue_link_entry(self, entry);
|
||||
|
||||
// Signal that queue is no longer empty
|
||||
self.not_empty.signal();
|
||||
@@ -156,7 +156,7 @@ fn Value LinkedBlockingQueue.poll(&self)
|
||||
self.not_empty.wait(&self.lock);
|
||||
}
|
||||
|
||||
QueueEntry* entry = self.unlink_head();
|
||||
QueueEntry* entry = linkedblockingqueue_unlink_head(self);
|
||||
Value value = entry.value;
|
||||
allocator::free(self.allocator, entry);
|
||||
if (self.capacity > 0)
|
||||
@@ -180,7 +180,7 @@ fn Value? LinkedBlockingQueue.pop(&self)
|
||||
{
|
||||
if (self.count == 0) return NO_MORE_ELEMENT~;
|
||||
|
||||
QueueEntry* entry = self.unlink_head();
|
||||
QueueEntry* entry = linkedblockingqueue_unlink_head(self);
|
||||
Value value = entry.value;
|
||||
allocator::free(self.allocator, entry);
|
||||
|
||||
@@ -217,7 +217,7 @@ fn Value? LinkedBlockingQueue.poll_timeout(&self, Duration timeout)
|
||||
if (!self.count) return NO_MORE_ELEMENT~;
|
||||
}
|
||||
|
||||
QueueEntry* entry = self.unlink_head();
|
||||
QueueEntry* entry = linkedblockingqueue_unlink_head(self);
|
||||
Value value = entry.value;
|
||||
allocator::free(self.allocator, entry);
|
||||
|
||||
@@ -273,7 +273,7 @@ fn void? LinkedBlockingQueue.try_push(&self, Value value)
|
||||
.next = null,
|
||||
.prev = null
|
||||
});
|
||||
self.link_entry(entry);
|
||||
linkedblockingqueue_link_entry(self, entry);
|
||||
self.not_empty.signal();
|
||||
};
|
||||
}
|
||||
@@ -307,7 +307,7 @@ fn void? LinkedBlockingQueue.push_timeout(&self, Value value, Duration timeout)
|
||||
.next = null,
|
||||
.prev = null
|
||||
});
|
||||
self.link_entry(entry);
|
||||
linkedblockingqueue_link_entry(self, entry);
|
||||
self.not_empty.signal();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ fn bool LinkedHashMap.is_initialized(&map)
|
||||
fn LinkedHashMap* LinkedHashMap.init_from_map(&self, Allocator allocator, LinkedHashMap* other_map)
|
||||
{
|
||||
self.init(allocator, other_map.table.len, other_map.load_factor);
|
||||
self.put_all_for_create(other_map);
|
||||
linkedhashmap_put_all_for_create(self, other_map);
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -242,13 +242,13 @@ fn bool LinkedHashMap.set(&map, Key key, Value value) @operator([]=)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
map.add_entry(hash, key, value, index);
|
||||
linkedhashmap_add_entry(map, hash, key, value, index);
|
||||
return false;
|
||||
}
|
||||
|
||||
fn void? LinkedHashMap.remove(&map, Key key) @maydiscard
|
||||
{
|
||||
if (!map.remove_entry_for_key(key)) return NOT_FOUND~;
|
||||
if (!linkedhashmap_remove_entry_for_key(map, key)) return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn void LinkedHashMap.clear(&map)
|
||||
@@ -259,7 +259,7 @@ fn void LinkedHashMap.clear(&map)
|
||||
while (entry)
|
||||
{
|
||||
LinkedEntry* next = entry.after;
|
||||
map.free_entry(entry);
|
||||
linkedhashmap_free_entry(map, entry);
|
||||
entry = next;
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ fn void LinkedHashMap.free(&map)
|
||||
{
|
||||
if (!map.is_initialized()) return;
|
||||
map.clear();
|
||||
map.free_internal(map.table.ptr);
|
||||
linkedhashmap_free_internal(map, map.table.ptr);
|
||||
map.table = {};
|
||||
}
|
||||
|
||||
@@ -396,7 +396,7 @@ fn bool LinkedHashMapIterator.has_next(&self)
|
||||
|
||||
// --- private methods
|
||||
|
||||
fn void LinkedHashMap.add_entry(&map, uint hash, Key key, Value value, uint bucket_index) @private
|
||||
fn void linkedhashmap_add_entry(LinkedHashMap* map, uint hash, Key key, Value value, uint bucket_index) @private
|
||||
{
|
||||
$if COPY_KEYS:
|
||||
key = key.copy(map.allocator);
|
||||
@@ -428,11 +428,11 @@ fn void LinkedHashMap.add_entry(&map, uint hash, Key key, Value value, uint buck
|
||||
|
||||
if (map.count++ >= map.threshold)
|
||||
{
|
||||
map.resize(map.table.len * 2);
|
||||
linkedhashmap_resize(map, map.table.len * 2);
|
||||
}
|
||||
}
|
||||
|
||||
fn void LinkedHashMap.resize(&map, uint new_capacity) @private
|
||||
fn void linkedhashmap_resize(LinkedHashMap* map, uint new_capacity) @private
|
||||
{
|
||||
LinkedEntry*[] old_table = map.table;
|
||||
uint old_capacity = old_table.len;
|
||||
@@ -502,7 +502,7 @@ fn void LinkedHashMap.resize(&map, uint new_capacity) @private
|
||||
}
|
||||
}
|
||||
|
||||
map.free_internal(old_table.ptr);
|
||||
linkedhashmap_free_internal(map, old_table.ptr);
|
||||
}
|
||||
|
||||
fn usz? LinkedHashMap.to_format(&self, Formatter* f) @dynamic
|
||||
@@ -517,7 +517,7 @@ fn usz? LinkedHashMap.to_format(&self, Formatter* f) @dynamic
|
||||
return len + f.print(" }");
|
||||
}
|
||||
|
||||
fn void LinkedHashMap.transfer(&map, LinkedEntry*[] new_table) @private
|
||||
fn void linkedhashmap_transfer(LinkedHashMap* map, LinkedEntry*[] new_table) @private
|
||||
{
|
||||
LinkedEntry*[] src = map.table;
|
||||
uint new_capacity = new_table.len;
|
||||
@@ -536,7 +536,7 @@ fn void LinkedHashMap.transfer(&map, LinkedEntry*[] new_table) @private
|
||||
}
|
||||
}
|
||||
|
||||
fn void LinkedHashMap.put_all_for_create(&map, LinkedHashMap* other_map) @private
|
||||
fn void linkedhashmap_put_all_for_create(LinkedHashMap* map, LinkedHashMap* other_map) @private
|
||||
{
|
||||
if (!other_map.count) return;
|
||||
other_map.@each(; Key key, Value value) {
|
||||
@@ -544,7 +544,7 @@ fn void LinkedHashMap.put_all_for_create(&map, LinkedHashMap* other_map) @privat
|
||||
};
|
||||
}
|
||||
|
||||
fn void LinkedHashMap.put_for_create(&map, Key key, Value value) @private
|
||||
fn void linkedhashmap_put_for_create(LinkedHashMap* map, Key key, Value value) @private
|
||||
{
|
||||
uint hash = rehash(key.hash());
|
||||
uint i = index_for(hash, map.table.len);
|
||||
@@ -556,15 +556,15 @@ fn void LinkedHashMap.put_for_create(&map, Key key, Value value) @private
|
||||
return;
|
||||
}
|
||||
}
|
||||
map.create_entry(hash, key, value, i);
|
||||
linkedhashmap_create_entry(map, hash, key, value, i);
|
||||
}
|
||||
|
||||
fn void LinkedHashMap.free_internal(&map, void* ptr) @inline @private
|
||||
fn void linkedhashmap_free_internal(LinkedHashMap* map, void* ptr) @inline @private
|
||||
{
|
||||
allocator::free(map.allocator, ptr);
|
||||
}
|
||||
|
||||
fn bool LinkedHashMap.remove_entry_for_key(&map, Key key) @private
|
||||
fn bool linkedhashmap_remove_entry_for_key(LinkedHashMap* map, Key key) @private
|
||||
{
|
||||
if (!map.count) return false;
|
||||
|
||||
@@ -605,7 +605,7 @@ fn bool LinkedHashMap.remove_entry_for_key(&map, Key key) @private
|
||||
}
|
||||
|
||||
map.count--;
|
||||
map.free_entry(e);
|
||||
linkedhashmap_free_entry(map, e);
|
||||
return true;
|
||||
}
|
||||
prev = e;
|
||||
@@ -614,23 +614,23 @@ fn bool LinkedHashMap.remove_entry_for_key(&map, Key key) @private
|
||||
return false;
|
||||
}
|
||||
|
||||
fn void LinkedHashMap.create_entry(&map, uint hash, Key key, Value value, int bucket_index) @private
|
||||
fn void linkedhashmap_create_entry(LinkedHashMap* map, uint hash, Key key, Value value, int bucket_index) @private
|
||||
{
|
||||
LinkedEntry *e = map.table[bucket_index];
|
||||
$if COPY_KEYS:
|
||||
key = key.copy(map.allocator);
|
||||
key = key.copy(map.allocator);
|
||||
$endif
|
||||
LinkedEntry* entry = allocator::new(map.allocator, LinkedEntry, { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] });
|
||||
map.table[bucket_index] = entry;
|
||||
map.count++;
|
||||
}
|
||||
|
||||
fn void LinkedHashMap.free_entry(&self, LinkedEntry *entry) @local
|
||||
fn void linkedhashmap_free_entry(LinkedHashMap* self, LinkedEntry *entry) @local
|
||||
{
|
||||
$if COPY_KEYS:
|
||||
allocator::free(self.allocator, entry.key);
|
||||
allocator::free(self.allocator, entry.key);
|
||||
$endif
|
||||
self.free_internal(entry);
|
||||
linkedhashmap_free_internal(self, entry);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ fn LinkedHashSet* LinkedHashSet.init_from_set(&self, Allocator allocator, Linked
|
||||
LinkedEntry* entry = other_set.head;
|
||||
while (entry) // Save insertion order
|
||||
{
|
||||
self.put_for_create(entry.value);
|
||||
linkedhashset_put_for_create(self, entry.value);
|
||||
entry = entry.after;
|
||||
}
|
||||
return self;
|
||||
@@ -223,7 +223,7 @@ fn bool LinkedHashSet.add(&set, Value value)
|
||||
{
|
||||
if (e.hash == hash && equals(value, e.value)) return false;
|
||||
}
|
||||
set.add_entry(hash, value, index);
|
||||
linkedhashset_add_entry(set, hash, value, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ fn bool LinkedHashSet.contains(&set, Value value)
|
||||
*>
|
||||
fn void? LinkedHashSet.remove(&set, Value value) @maydiscard
|
||||
{
|
||||
if (!set.remove_entry_for_value(value)) return NOT_FOUND~;
|
||||
if (!linkedhashset_remove_entry_for_value(set, value)) return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn usz LinkedHashSet.remove_all(&set, Value[] values)
|
||||
@@ -274,7 +274,7 @@ fn usz LinkedHashSet.remove_all(&set, Value[] values)
|
||||
usz total;
|
||||
foreach (v : values)
|
||||
{
|
||||
if (set.remove_entry_for_value(v)) total++;
|
||||
if (linkedhashset_remove_entry_for_value(set, v)) total++;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
@@ -287,7 +287,7 @@ fn usz LinkedHashSet.remove_all_from(&set, LinkedHashSet* other)
|
||||
usz total;
|
||||
other.@each(;Value val)
|
||||
{
|
||||
if (set.remove_entry_for_value(val)) total++;
|
||||
if (linkedhashset_remove_entry_for_value(set, val)) total++;
|
||||
};
|
||||
return total;
|
||||
}
|
||||
@@ -299,7 +299,7 @@ fn void LinkedHashSet.free(&set)
|
||||
{
|
||||
if (!set.is_initialized()) return;
|
||||
set.clear();
|
||||
set.free_internal(set.table.ptr);
|
||||
linkedhashset_free_internal(set, set.table.ptr);
|
||||
set.table = {};
|
||||
}
|
||||
|
||||
@@ -316,7 +316,7 @@ fn void LinkedHashSet.clear(&set)
|
||||
while (entry)
|
||||
{
|
||||
LinkedEntry* next = entry.after;
|
||||
set.free_entry(entry);
|
||||
linkedhashset_free_entry(set, entry);
|
||||
entry = next;
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ fn void LinkedHashSet.reserve(&set, usz capacity)
|
||||
{
|
||||
if (capacity > set.threshold)
|
||||
{
|
||||
set.resize(math::next_power_of_2(capacity));
|
||||
linkedhashset_resize(set, math::next_power_of_2(capacity));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,7 +451,7 @@ fn bool LinkedHashSet.is_subset(&self, LinkedHashSet* other)
|
||||
|
||||
// --- private methods
|
||||
|
||||
fn void LinkedHashSet.add_entry(&set, uint hash, Value value, uint bucket_index) @private
|
||||
fn void linkedhashset_add_entry(LinkedHashSet* set, uint hash, Value value, uint bucket_index) @private
|
||||
{
|
||||
LinkedEntry* entry = allocator::new(set.allocator, LinkedEntry, {
|
||||
.hash = hash,
|
||||
@@ -478,11 +478,11 @@ fn void LinkedHashSet.add_entry(&set, uint hash, Value value, uint bucket_index)
|
||||
|
||||
if (set.count++ >= set.threshold)
|
||||
{
|
||||
set.resize(set.table.len * 2);
|
||||
linkedhashset_resize(set, set.table.len * 2);
|
||||
}
|
||||
}
|
||||
|
||||
fn void LinkedHashSet.resize(&set, usz new_capacity) @private
|
||||
fn void linkedhashset_resize(LinkedHashSet* set, usz new_capacity) @private
|
||||
{
|
||||
LinkedEntry*[] old_table = set.table;
|
||||
usz old_capacity = old_table.len;
|
||||
@@ -552,7 +552,7 @@ fn void LinkedHashSet.resize(&set, usz new_capacity) @private
|
||||
}
|
||||
}
|
||||
|
||||
set.free_internal(old_table.ptr);
|
||||
linkedhashset_free_internal(set, old_table.ptr);
|
||||
}
|
||||
|
||||
fn usz? LinkedHashSet.to_format(&self, Formatter* f) @dynamic
|
||||
@@ -567,7 +567,7 @@ fn usz? LinkedHashSet.to_format(&self, Formatter* f) @dynamic
|
||||
return len + f.print(" }");
|
||||
}
|
||||
|
||||
fn void LinkedHashSet.transfer(&set, LinkedEntry*[] new_table) @private
|
||||
fn void linked_hashset_transfer(LinkedHashSet* set, LinkedEntry*[] new_table) @private
|
||||
{
|
||||
LinkedEntry*[] src = set.table;
|
||||
uint new_capacity = new_table.len;
|
||||
@@ -586,7 +586,7 @@ fn void LinkedHashSet.transfer(&set, LinkedEntry*[] new_table) @private
|
||||
}
|
||||
}
|
||||
|
||||
fn void LinkedHashSet.put_for_create(&set, Value value) @private
|
||||
fn void linkedhashset_put_for_create(LinkedHashSet* set, Value value) @private
|
||||
{
|
||||
uint hash = rehash(value.hash());
|
||||
uint i = index_for(hash, set.table.len);
|
||||
@@ -598,15 +598,15 @@ fn void LinkedHashSet.put_for_create(&set, Value value) @private
|
||||
return;
|
||||
}
|
||||
}
|
||||
set.create_entry(hash, value, i);
|
||||
linkedhashset_create_entry(set, hash, value, i);
|
||||
}
|
||||
|
||||
fn void LinkedHashSet.free_internal(&set, void* ptr) @inline @private
|
||||
fn void linkedhashset_free_internal(LinkedHashSet* set, void* ptr) @inline @private
|
||||
{
|
||||
allocator::free(set.allocator, ptr);
|
||||
}
|
||||
|
||||
fn void LinkedHashSet.create_entry(&set, uint hash, Value value, int bucket_index) @private
|
||||
fn void linkedhashset_create_entry(LinkedHashSet* set, uint hash, Value value, int bucket_index) @private
|
||||
{
|
||||
LinkedEntry* entry = allocator::new(set.allocator, LinkedEntry, {
|
||||
.hash = hash,
|
||||
@@ -633,7 +633,7 @@ fn void LinkedHashSet.create_entry(&set, uint hash, Value value, int bucket_inde
|
||||
set.count++;
|
||||
}
|
||||
|
||||
fn bool LinkedHashSet.remove_entry_for_value(&set, Value value) @private
|
||||
fn bool linkedhashset_remove_entry_for_value(LinkedHashSet* set, Value value) @private
|
||||
{
|
||||
if (!set.count) return false;
|
||||
|
||||
@@ -674,7 +674,7 @@ fn bool LinkedHashSet.remove_entry_for_value(&set, Value value) @private
|
||||
}
|
||||
|
||||
set.count--;
|
||||
set.free_entry(e);
|
||||
linkedhashset_free_entry(set, e);
|
||||
return true;
|
||||
}
|
||||
prev = e;
|
||||
@@ -683,7 +683,7 @@ fn bool LinkedHashSet.remove_entry_for_value(&set, Value value) @private
|
||||
return false;
|
||||
}
|
||||
|
||||
fn void LinkedHashSet.free_entry(&set, LinkedEntry *entry) @private
|
||||
fn void linkedhashset_free_entry(LinkedHashSet* set, LinkedEntry *entry) @private
|
||||
{
|
||||
allocator::free(set.allocator, entry);
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ fn usz? LinkedList.rindex_of(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
|
||||
*>
|
||||
fn void LinkedList.remove_at(&self, usz index)
|
||||
{
|
||||
self.unlink(self.node_at_index(index));
|
||||
linked_list_unlink(self, self.node_at_index(index));
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -232,47 +232,47 @@ fn void LinkedList.insert_at(&self, usz index, Type element)
|
||||
case self.size:
|
||||
self.push(element);
|
||||
default:
|
||||
self.link_before(self.node_at_index(index), element);
|
||||
linked_list_link_before(self, self.node_at_index(index), element);
|
||||
}
|
||||
}
|
||||
<*
|
||||
@require succ != null
|
||||
*>
|
||||
fn void LinkedList.link_before(&self, Node *succ, Type value) @private
|
||||
fn void linked_list_link_before(LinkedList* l, Node *succ, Type value) @private
|
||||
{
|
||||
Node* pred = succ.prev;
|
||||
Node* new_node = self.alloc_node();
|
||||
Node* new_node = l.alloc_node();
|
||||
*new_node = { .prev = pred, .next = succ, .value = value };
|
||||
succ.prev = new_node;
|
||||
if (!pred)
|
||||
{
|
||||
self._first = new_node;
|
||||
l._first = new_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
pred.next = new_node;
|
||||
}
|
||||
self.size++;
|
||||
l.size++;
|
||||
}
|
||||
|
||||
<*
|
||||
@require self._first != null
|
||||
@require l._first != null
|
||||
*>
|
||||
fn void LinkedList.unlink_first(&self) @private
|
||||
fn void linked_list_unlink_first(LinkedList* l) @private
|
||||
{
|
||||
Node* f = self._first;
|
||||
Node* f = l._first;
|
||||
Node* next = f.next;
|
||||
self.free_node(f);
|
||||
self._first = next;
|
||||
l.free_node(f);
|
||||
l._first = next;
|
||||
if (!next)
|
||||
{
|
||||
self._last = null;
|
||||
l._last = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
next.prev = null;
|
||||
}
|
||||
self.size--;
|
||||
l.size--;
|
||||
}
|
||||
|
||||
fn usz LinkedList.remove(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
|
||||
@@ -285,7 +285,7 @@ fn usz LinkedList.remove(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
case equals(node.value, t):
|
||||
Node* next = node.next;
|
||||
self.unlink(node);
|
||||
linked_list_unlink(self, node);
|
||||
node = next;
|
||||
default:
|
||||
node = node.next;
|
||||
@@ -297,7 +297,7 @@ fn usz LinkedList.remove(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
|
||||
fn Type? LinkedList.pop(&self)
|
||||
{
|
||||
if (!self._last) return NO_MORE_ELEMENT~;
|
||||
defer self.unlink_last();
|
||||
defer linked_list_unlink_last(self);
|
||||
return self._last.value;
|
||||
}
|
||||
|
||||
@@ -309,20 +309,20 @@ fn bool LinkedList.is_empty(&self)
|
||||
fn Type? LinkedList.pop_front(&self)
|
||||
{
|
||||
if (!self._first) return NO_MORE_ELEMENT~;
|
||||
defer self.unlink_first();
|
||||
defer linked_list_unlink_first(self);
|
||||
return self._first.value;
|
||||
}
|
||||
|
||||
fn void? LinkedList.remove_last(&self) @maydiscard
|
||||
{
|
||||
if (!self._first) return NO_MORE_ELEMENT~;
|
||||
self.unlink_last();
|
||||
linked_list_unlink_last(self);
|
||||
}
|
||||
|
||||
fn void? LinkedList.remove_first(&self) @maydiscard
|
||||
{
|
||||
if (!self._first) return NO_MORE_ELEMENT~;
|
||||
self.unlink_first();
|
||||
linked_list_unlink_first(self);
|
||||
}
|
||||
|
||||
|
||||
@@ -332,7 +332,7 @@ fn bool LinkedList.remove_first_match(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
if (node.value == t)
|
||||
{
|
||||
self.unlink(node);
|
||||
linked_list_unlink(self, node);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -345,7 +345,7 @@ fn bool LinkedList.remove_last_match(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
if (node.value == t)
|
||||
{
|
||||
self.unlink(node);
|
||||
linked_list_unlink(self, node);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -354,7 +354,7 @@ fn bool LinkedList.remove_last_match(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
|
||||
<*
|
||||
@require self._last != null
|
||||
*>
|
||||
fn void LinkedList.unlink_last(&self) @inline @private
|
||||
fn void linked_list_unlink_last(LinkedList* self) @inline @private
|
||||
{
|
||||
Node* l = self._last;
|
||||
Node* prev = l.prev;
|
||||
@@ -374,7 +374,7 @@ fn void LinkedList.unlink_last(&self) @inline @private
|
||||
<*
|
||||
@require x != null
|
||||
*>
|
||||
fn void LinkedList.unlink(&self, Node* x) @private
|
||||
fn void linked_list_unlink(LinkedList* self, Node* x) @private
|
||||
{
|
||||
Node* next = x.next;
|
||||
Node* prev = x.prev;
|
||||
|
||||
@@ -82,7 +82,7 @@ fn void List.init_wrapping_array(&self, Allocator allocator, Type[] types)
|
||||
self.allocator = allocator;
|
||||
self.capacity = types.len;
|
||||
self.entries = types.ptr;
|
||||
self.set_size(types.len);
|
||||
list_set_size(self, types.len);
|
||||
}
|
||||
|
||||
fn bool List.is_initialized(&self) @inline => self.allocator != null && self.allocator != (Allocator)&dummy;
|
||||
@@ -110,19 +110,19 @@ fn usz? List.to_format(&self, Formatter* formatter) @dynamic
|
||||
fn void List.push(&self, Type element) @inline
|
||||
{
|
||||
self.reserve(1);
|
||||
self.entries[self.set_size(self.size + 1)] = element;
|
||||
self.entries[list_set_size(self, self.size + 1)] = element;
|
||||
}
|
||||
|
||||
fn Type? List.pop(&self)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
defer self.set_size(self.size - 1);
|
||||
defer list_set_size(self, self.size - 1);
|
||||
return self.entries[self.size - 1];
|
||||
}
|
||||
|
||||
fn void List.clear(&self)
|
||||
{
|
||||
self.set_size(0);
|
||||
list_set_size(self, 0);
|
||||
}
|
||||
|
||||
fn Type? List.pop_first(&self)
|
||||
@@ -138,7 +138,7 @@ fn Type? List.pop_first(&self)
|
||||
fn void List.remove_at(&self, usz index)
|
||||
{
|
||||
usz new_size = self.size - 1;
|
||||
defer self.set_size(new_size);
|
||||
defer list_set_size(self, new_size);
|
||||
if (!new_size || index == new_size) return;
|
||||
self.entries[index .. new_size - 1] = self.entries[index + 1 .. new_size];
|
||||
}
|
||||
@@ -147,7 +147,7 @@ fn void List.add_all(&self, List* other_list)
|
||||
{
|
||||
if (!other_list.size) return;
|
||||
self.reserve(other_list.size);
|
||||
usz index = self.set_size(self.size + other_list.size);
|
||||
usz index = list_set_size(self, self.size + other_list.size);
|
||||
foreach (&value : other_list)
|
||||
{
|
||||
self.entries[index++] = *value;
|
||||
@@ -203,7 +203,7 @@ fn void List.add_array(&self, Type[] array) @deprecated("Use push_all")
|
||||
{
|
||||
if (!array.len) return;
|
||||
self.reserve(array.len);
|
||||
usz index = self.set_size(self.size + array.len);
|
||||
usz index = list_set_size(self, self.size + array.len);
|
||||
self.entries[index : array.len] = array[..];
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ fn void List.push_all(&self, Type[] array)
|
||||
{
|
||||
if (!array.len) return;
|
||||
self.reserve(array.len);
|
||||
usz index = self.set_size(self.size + array.len);
|
||||
usz index = list_set_size(self, self.size + array.len);
|
||||
self.entries[index : array.len] = array[..];
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ fn void List.push_front(&self, Type type) @inline
|
||||
fn void List.insert_at(&self, usz index, Type type)
|
||||
{
|
||||
self.reserve(1);
|
||||
self.set_size(self.size + 1);
|
||||
list_set_size(self, self.size + 1);
|
||||
for (isz i = self.size - 1; i > index; i--)
|
||||
{
|
||||
self.entries[i] = self.entries[i - 1];
|
||||
@@ -251,7 +251,7 @@ fn void List.set_at(&self, usz index, Type type)
|
||||
fn void? List.remove_last(&self) @maydiscard
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
self.set_size(self.size - 1);
|
||||
list_set_size(self, self.size - 1);
|
||||
}
|
||||
|
||||
fn void? List.remove_first(&self) @maydiscard
|
||||
@@ -299,7 +299,7 @@ fn void List.free(&self)
|
||||
{
|
||||
if (!self.allocator || self.allocator.ptr == &dummy || !self.capacity) return;
|
||||
|
||||
self.pre_free(); // Remove sanitizer annotation
|
||||
list_pre_free(self); // Remove sanitizer annotation
|
||||
|
||||
$if type_is_overaligned():
|
||||
allocator::free_aligned(self.allocator, self.entries);
|
||||
@@ -358,7 +358,7 @@ fn usz List.retain_using_test(&self, ElementTest filter, any context)
|
||||
return list_common::list_remove_using_test(self, filter, true, context);
|
||||
}
|
||||
|
||||
fn void List.ensure_capacity(&self, usz min_capacity) @local
|
||||
fn void list_ensure_capacity(List* self, usz min_capacity) @local
|
||||
{
|
||||
if (!min_capacity) return;
|
||||
if (self.capacity >= min_capacity) return;
|
||||
@@ -374,7 +374,7 @@ fn void List.ensure_capacity(&self, usz min_capacity) @local
|
||||
break;
|
||||
}
|
||||
|
||||
self.pre_free(); // Remove sanitizer annotation
|
||||
list_pre_free(self); // Remove sanitizer annotation
|
||||
|
||||
min_capacity = math::next_power_of_2(min_capacity);
|
||||
$if type_is_overaligned():
|
||||
@@ -384,7 +384,7 @@ fn void List.ensure_capacity(&self, usz min_capacity) @local
|
||||
$endif;
|
||||
self.capacity = min_capacity;
|
||||
|
||||
self.post_alloc(); // Add sanitizer annotation
|
||||
list_post_alloc(self); // Add sanitizer annotation
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -419,7 +419,7 @@ fn void List.reserve(&self, usz added)
|
||||
assert(new_size < usz.max / 2U);
|
||||
usz new_capacity = self.capacity ? 2U * self.capacity : 16U;
|
||||
while (new_capacity < new_size) new_capacity *= 2U;
|
||||
self.ensure_capacity(new_capacity);
|
||||
list_ensure_capacity(self, new_capacity);
|
||||
}
|
||||
|
||||
fn void List._update_size_change(&self,usz old_size, usz new_size)
|
||||
@@ -436,7 +436,7 @@ fn void List._update_size_change(&self,usz old_size, usz new_size)
|
||||
<*
|
||||
@require new_size == 0 || self.capacity != 0
|
||||
*>
|
||||
fn usz List.set_size(&self, usz new_size) @inline @private
|
||||
fn usz list_set_size(List* self, usz new_size) @inline @private
|
||||
{
|
||||
usz old_size = self.size;
|
||||
self._update_size_change(old_size, new_size);
|
||||
@@ -444,7 +444,7 @@ fn usz List.set_size(&self, usz new_size) @inline @private
|
||||
return old_size;
|
||||
}
|
||||
|
||||
macro void List.pre_free(&self) @private
|
||||
macro void list_pre_free(List* self) @private
|
||||
{
|
||||
if (!self.capacity) return;
|
||||
self._update_size_change(self.size, self.capacity);
|
||||
@@ -453,7 +453,7 @@ macro void List.pre_free(&self) @private
|
||||
<*
|
||||
@require self.capacity > 0
|
||||
*>
|
||||
macro void List.post_alloc(&self) @private
|
||||
macro void list_post_alloc(List* self) @private
|
||||
{
|
||||
self._update_size_change(self.capacity, self.size);
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ fn bool Object.is_indexable(&self) => self.is_empty() || self.is_array();
|
||||
<*
|
||||
@require self.is_keyable()
|
||||
*>
|
||||
fn void Object.init_map_if_needed(&self) @private
|
||||
fn void object_init_map_if_needed(Object* self) @private
|
||||
{
|
||||
if (self.is_empty())
|
||||
{
|
||||
@@ -163,7 +163,7 @@ fn void Object.init_map_if_needed(&self) @private
|
||||
<*
|
||||
@require self.is_indexable()
|
||||
*>
|
||||
fn void Object.init_array_if_needed(&self) @private
|
||||
fn void object_init_array_if_needed(Object* self) @private
|
||||
{
|
||||
if (self.is_empty())
|
||||
{
|
||||
@@ -175,9 +175,9 @@ fn void Object.init_array_if_needed(&self) @private
|
||||
<*
|
||||
@require self.is_keyable()
|
||||
*>
|
||||
fn void Object.set_object(&self, String key, Object* new_object) @private
|
||||
fn void object_set_object(Object* self, String key, Object* new_object) @private
|
||||
{
|
||||
self.init_map_if_needed();
|
||||
object_init_map_if_needed(self);
|
||||
Object*? val = self.map.get_entry(key).value;
|
||||
defer (void)val.free();
|
||||
self.map.set(key, new_object);
|
||||
@@ -214,7 +214,7 @@ macro Object* Object.object_from_value(&self, value) @private
|
||||
macro Object* Object.set(&self, String key, value)
|
||||
{
|
||||
Object* val = self.object_from_value(value);
|
||||
self.set_object(key, val);
|
||||
object_set_object(self, key, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ fn usz Object.get_len(&self)
|
||||
*>
|
||||
fn void Object.push_object(&self, Object* to_append)
|
||||
{
|
||||
self.init_array_if_needed();
|
||||
object_init_array_if_needed(self);
|
||||
self.array.push(to_append);
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ fn void Object.push_object(&self, Object* to_append)
|
||||
*>
|
||||
fn void Object.set_object_at(&self, usz index, Object* to_set)
|
||||
{
|
||||
self.init_array_if_needed();
|
||||
object_init_array_if_needed(self);
|
||||
while (self.array.len() < index)
|
||||
{
|
||||
self.array.push(&NULL_OBJECT);
|
||||
|
||||
1108
lib/std/compression/deflate.c3
Normal file
1108
lib/std/compression/deflate.c3
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ const uint PIXELS_MAX = 400000000;
|
||||
Purely informative. It will be saved to the file header,
|
||||
but does not affect how chunks are en-/decoded.
|
||||
*>
|
||||
const enum QOIColorspace : char
|
||||
constdef QOIColorspace : char
|
||||
{
|
||||
<* sRGB with linear alpha *>
|
||||
SRGB = 0,
|
||||
@@ -21,7 +21,7 @@ const enum QOIColorspace : char
|
||||
AUTO can be used when decoding to automatically determine
|
||||
the channels from the file's header.
|
||||
*>
|
||||
const enum QOIChannels : inline char
|
||||
constdef QOIChannels : inline char
|
||||
{
|
||||
AUTO = 0,
|
||||
RGB = 3,
|
||||
|
||||
1215
lib/std/compression/zip.c3
Normal file
1215
lib/std/compression/zip.c3
Normal file
File diff suppressed because it is too large
Load Diff
@@ -56,7 +56,7 @@ fn BackedArenaAllocator*? new_backed_allocator(usz size, Allocator allocator)
|
||||
fn void BackedArenaAllocator.destroy(&self)
|
||||
{
|
||||
self.reset(0);
|
||||
if (self.last_page) (void)self._free_page(self.last_page);
|
||||
if (self.last_page) (void)_free_page(self, self.last_page);
|
||||
allocator::free(self.backing_allocator, self);
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ fn void BackedArenaAllocator.reset(&self, usz mark)
|
||||
self.used = last_page.mark;
|
||||
ExtraPage *to_free = last_page;
|
||||
last_page = last_page.prev_page;
|
||||
self._free_page(to_free)!!;
|
||||
_free_page(self, to_free)!!;
|
||||
}
|
||||
self.last_page = last_page;
|
||||
$if env::COMPILER_SAFE_MODE || env::ADDRESS_SANITIZER:
|
||||
@@ -98,13 +98,13 @@ fn void BackedArenaAllocator.reset(&self, usz mark)
|
||||
self.used = mark;
|
||||
}
|
||||
|
||||
fn void? BackedArenaAllocator._free_page(&self, ExtraPage* page) @inline @local
|
||||
fn void? _free_page(BackedArenaAllocator* self, ExtraPage* page) @inline @local
|
||||
{
|
||||
void* mem = page.start;
|
||||
return self.backing_allocator.release(mem, page.is_aligned());
|
||||
}
|
||||
|
||||
fn void*? BackedArenaAllocator._realloc_page(&self, ExtraPage* page, usz size, usz alignment) @inline @local
|
||||
fn void*? _realloc_page(BackedArenaAllocator* self, ExtraPage* page, usz size, usz alignment) @inline @local
|
||||
{
|
||||
// Then the actual start pointer:
|
||||
void* real_pointer = page.start;
|
||||
@@ -133,7 +133,7 @@ fn void*? BackedArenaAllocator.resize(&self, void* pointer, usz size, usz alignm
|
||||
assert(self.last_page, "Realloc of unrelated pointer");
|
||||
// First grab the page
|
||||
ExtraPage *page = pointer - ExtraPage.sizeof;
|
||||
return self._realloc_page(page, size, alignment);
|
||||
return _realloc_page(self, page, size, alignment);
|
||||
}
|
||||
|
||||
AllocChunk* data = self.acquire(size, NO_ZERO, alignment)!;
|
||||
|
||||
@@ -137,12 +137,67 @@ fn void DynamicArenaAllocator.reset(&self)
|
||||
self.page = page;
|
||||
}
|
||||
|
||||
|
||||
|
||||
<*
|
||||
@require size > 0 : `acquire expects size > 0`
|
||||
@require !alignment || math::is_power_of_2(alignment)
|
||||
@return? mem::INVALID_ALLOC_SIZE, mem::OUT_OF_MEMORY
|
||||
*>
|
||||
fn void*? DynamicArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
|
||||
{
|
||||
alignment = alignment_for_allocation(alignment);
|
||||
DynamicArenaPage* page = self.page;
|
||||
|
||||
void* ptr @noinit;
|
||||
do SET_DONE:
|
||||
{
|
||||
if (!page && self.unused_page)
|
||||
{
|
||||
self.page = page = self.unused_page;
|
||||
self.unused_page = page.prev_arena;
|
||||
page.prev_arena = null;
|
||||
}
|
||||
if (!page)
|
||||
{
|
||||
ptr = _alloc_new(self, size, alignment)!;
|
||||
break SET_DONE;
|
||||
}
|
||||
void* start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof, alignment);
|
||||
usz new_used = start - page.memory + size;
|
||||
if ALLOCATE_NEW: (new_used > page.total)
|
||||
{
|
||||
if ((page = self.unused_page))
|
||||
{
|
||||
start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof, alignment);
|
||||
new_used = start + size - page.memory;
|
||||
if (page.total >= new_used)
|
||||
{
|
||||
self.unused_page = page.prev_arena;
|
||||
page.prev_arena = self.page;
|
||||
self.page = page;
|
||||
break ALLOCATE_NEW;
|
||||
}
|
||||
}
|
||||
ptr = _alloc_new(self, size, alignment)!;
|
||||
break SET_DONE;
|
||||
}
|
||||
page.used = new_used;
|
||||
assert(start + size == page.memory + page.used);
|
||||
ptr = start;
|
||||
DynamicArenaChunk* chunk = (DynamicArenaChunk*)ptr - 1;
|
||||
chunk.size = size;
|
||||
};
|
||||
if (init_type == ZERO) mem::clear(ptr, size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
<*
|
||||
@require math::is_power_of_2(alignment)
|
||||
@require size > 0
|
||||
@return? mem::INVALID_ALLOC_SIZE, mem::OUT_OF_MEMORY
|
||||
*>
|
||||
fn void*? DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment) @local
|
||||
fn void*? _alloc_new(DynamicArenaAllocator* self, usz size, usz alignment) @local
|
||||
{
|
||||
// First, make sure that we can align it, extending the page size if needed.
|
||||
usz page_size = max(self.page_size, mem::aligned_offset(size + DynamicArenaChunk.sizeof + alignment, alignment));
|
||||
@@ -166,57 +221,4 @@ fn void*? DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment) @loca
|
||||
self.page = page;
|
||||
page.current_stack_ptr = mem_start;
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
<*
|
||||
@require size > 0 : `acquire expects size > 0`
|
||||
@require !alignment || math::is_power_of_2(alignment)
|
||||
@return? mem::INVALID_ALLOC_SIZE, mem::OUT_OF_MEMORY
|
||||
*>
|
||||
fn void*? DynamicArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
|
||||
{
|
||||
alignment = alignment_for_allocation(alignment);
|
||||
DynamicArenaPage* page = self.page;
|
||||
|
||||
void* ptr @noinit;
|
||||
do SET_DONE:
|
||||
{
|
||||
if (!page && self.unused_page)
|
||||
{
|
||||
self.page = page = self.unused_page;
|
||||
self.unused_page = page.prev_arena;
|
||||
page.prev_arena = null;
|
||||
}
|
||||
if (!page)
|
||||
{
|
||||
ptr = self._alloc_new(size, alignment)!;
|
||||
break SET_DONE;
|
||||
}
|
||||
void* start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof, alignment);
|
||||
usz new_used = start - page.memory + size;
|
||||
if ALLOCATE_NEW: (new_used > page.total)
|
||||
{
|
||||
if ((page = self.unused_page))
|
||||
{
|
||||
start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof, alignment);
|
||||
new_used = start + size - page.memory;
|
||||
if (page.total >= new_used)
|
||||
{
|
||||
self.unused_page = page.prev_arena;
|
||||
page.prev_arena = self.page;
|
||||
self.page = page;
|
||||
break ALLOCATE_NEW;
|
||||
}
|
||||
}
|
||||
ptr = self._alloc_new(size, alignment)!;
|
||||
break SET_DONE;
|
||||
}
|
||||
page.used = new_used;
|
||||
assert(start + size == page.memory + page.used);
|
||||
ptr = start;
|
||||
DynamicArenaChunk* chunk = (DynamicArenaChunk*)ptr - 1;
|
||||
chunk.size = size;
|
||||
};
|
||||
if (init_type == ZERO) mem::clear(ptr, size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
@@ -32,58 +32,58 @@ fn void*? SimpleHeapAllocator.acquire(&self, usz size, AllocInitType init_type,
|
||||
{
|
||||
if (init_type == ZERO)
|
||||
{
|
||||
return alignment > 0 ? @aligned_alloc(self._calloc, size, alignment) : self._calloc(size);
|
||||
return alignment > 0 ? @aligned_alloc_fn(self, simple_alloc_calloc, size, alignment) : simple_alloc_calloc(self, size);
|
||||
}
|
||||
return alignment > 0 ? @aligned_alloc(self._alloc, size, alignment) : self._alloc(size);
|
||||
return alignment > 0 ? @aligned_alloc_fn(self, simple_alloc_alloc, size, alignment) : simple_alloc_alloc(self, size);
|
||||
}
|
||||
|
||||
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)
|
||||
: self._realloc(old_pointer, size);
|
||||
? @aligned_realloc_fn(self, simple_alloc_calloc, simple_alloc_free, old_pointer, size, alignment)
|
||||
: simple_alloc_realloc(self, old_pointer, size);
|
||||
}
|
||||
|
||||
fn void SimpleHeapAllocator.release(&self, void* old_pointer, bool aligned) @dynamic
|
||||
{
|
||||
if (aligned)
|
||||
{
|
||||
@aligned_free(self._free, old_pointer)!!;
|
||||
@aligned_free_fn(self, simple_alloc_free, old_pointer)!!;
|
||||
}
|
||||
else
|
||||
{
|
||||
self._free(old_pointer);
|
||||
simple_alloc_free(self, old_pointer);
|
||||
}
|
||||
}
|
||||
|
||||
<*
|
||||
@require old_pointer && bytes > 0
|
||||
*>
|
||||
fn void*? SimpleHeapAllocator._realloc(&self, void* old_pointer, usz bytes) @local
|
||||
fn void*? simple_alloc_realloc(SimpleHeapAllocator* self, void* old_pointer, usz bytes) @local
|
||||
{
|
||||
// Find the block header.
|
||||
Header* block = (Header*)old_pointer - 1;
|
||||
if (block.size >= bytes) return old_pointer;
|
||||
void* new = self._alloc(bytes)!;
|
||||
void* new = simple_alloc_alloc(self, bytes)!;
|
||||
usz max_to_copy = math::min(block.size, bytes);
|
||||
mem::copy(new, old_pointer, max_to_copy);
|
||||
self._free(old_pointer);
|
||||
simple_alloc_free(self, old_pointer);
|
||||
return new;
|
||||
}
|
||||
|
||||
fn void*? SimpleHeapAllocator._calloc(&self, usz bytes) @local
|
||||
fn void*? simple_alloc_calloc(SimpleHeapAllocator* self, usz bytes) @local
|
||||
{
|
||||
void* data = self._alloc(bytes)!;
|
||||
void* data = simple_alloc_alloc(self, bytes)!;
|
||||
mem::clear(data, bytes, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return data;
|
||||
}
|
||||
|
||||
fn void*? SimpleHeapAllocator._alloc(&self, usz bytes) @local
|
||||
fn void*? simple_alloc_alloc(SimpleHeapAllocator* self, usz bytes) @local
|
||||
{
|
||||
usz aligned_bytes = mem::aligned_offset(bytes, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
if (!self.free_list)
|
||||
{
|
||||
self.add_block(aligned_bytes)!;
|
||||
simple_alloc_add_block(self, aligned_bytes)!;
|
||||
}
|
||||
|
||||
Header* current = self.free_list;
|
||||
@@ -123,22 +123,22 @@ fn void*? SimpleHeapAllocator._alloc(&self, usz bytes) @local
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
self.add_block(aligned_bytes)!;
|
||||
return self._alloc(aligned_bytes);
|
||||
simple_alloc_add_block(self, aligned_bytes)!;
|
||||
return simple_alloc_alloc(self, aligned_bytes);
|
||||
}
|
||||
|
||||
fn void? SimpleHeapAllocator.add_block(&self, usz aligned_bytes) @local
|
||||
fn void? simple_alloc_add_block(SimpleHeapAllocator* self, usz aligned_bytes) @local
|
||||
{
|
||||
assert(mem::aligned_offset(aligned_bytes, mem::DEFAULT_MEM_ALIGNMENT) == aligned_bytes);
|
||||
char[] result = self.alloc_fn(aligned_bytes + Header.sizeof)!;
|
||||
Header* new_block = (Header*)result.ptr;
|
||||
new_block.size = result.len - Header.sizeof;
|
||||
new_block.next = null;
|
||||
self._free(new_block + 1);
|
||||
simple_alloc_free(self, new_block + 1);
|
||||
}
|
||||
|
||||
|
||||
fn void SimpleHeapAllocator._free(&self, void* ptr) @local
|
||||
fn void simple_alloc_free(SimpleHeapAllocator* self, void* ptr) @local
|
||||
{
|
||||
// Empty ptr -> do nothing.
|
||||
if (!ptr) return;
|
||||
|
||||
@@ -127,7 +127,7 @@ fn void TempAllocator.reset(&self)
|
||||
{
|
||||
TempAllocator* old = child;
|
||||
child = old.derived;
|
||||
old.destroy();
|
||||
temp_allocator_destroy(old);
|
||||
}
|
||||
self.capacity = self.original_capacity;
|
||||
$if env::ADDRESS_SANITIZER:
|
||||
@@ -142,17 +142,17 @@ fn void TempAllocator.reset(&self)
|
||||
fn void TempAllocator.free(&self)
|
||||
{
|
||||
self.reset();
|
||||
self.destroy();
|
||||
temp_allocator_destroy(self);
|
||||
}
|
||||
|
||||
fn void TempAllocator.destroy(&self) @local
|
||||
fn void temp_allocator_destroy(TempAllocator* self)
|
||||
{
|
||||
TempAllocatorPage *last_page = self.last_page;
|
||||
while (last_page)
|
||||
{
|
||||
TempAllocatorPage *to_free = last_page;
|
||||
last_page = last_page.prev_page;
|
||||
self._free_page(to_free)!!;
|
||||
_free_page(self, to_free)!!;
|
||||
}
|
||||
if (self.allocated)
|
||||
{
|
||||
@@ -179,33 +179,6 @@ fn void TempAllocator.release(&self, void* old_pointer, bool) @dynamic
|
||||
}
|
||||
|
||||
|
||||
fn void? TempAllocator._free_page(&self, TempAllocatorPage* page) @inline @local
|
||||
{
|
||||
void* mem = page.start;
|
||||
return self.backing_allocator.release(mem, page.is_aligned());
|
||||
}
|
||||
|
||||
fn void*? TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size, usz alignment) @inline @local
|
||||
{
|
||||
// Then the actual start pointer:
|
||||
void* real_pointer = page.start;
|
||||
|
||||
// Walk backwards to find the pointer to this page.
|
||||
TempAllocatorPage **pointer_to_prev = &self.last_page;
|
||||
// Remove the page from the list
|
||||
while (*pointer_to_prev != page)
|
||||
{
|
||||
pointer_to_prev = &((*pointer_to_prev).prev_page);
|
||||
}
|
||||
*pointer_to_prev = page.prev_page;
|
||||
usz page_size = page.pagesize();
|
||||
// Clear on size > original size.
|
||||
void* data = self.acquire(size, NO_ZERO, alignment)!;
|
||||
if (page_size > size) page_size = size;
|
||||
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) @dynamic
|
||||
{
|
||||
@@ -215,7 +188,7 @@ fn void*? TempAllocator.resize(&self, void* pointer, usz size, usz alignment) @d
|
||||
assert(self.last_page, "Realloc of non temp pointer");
|
||||
// First grab the page
|
||||
TempAllocatorPage *page = pointer - TempAllocatorPage.sizeof;
|
||||
return self._realloc_page(page, size, alignment);
|
||||
return _realloc_page(self, page, size, alignment);
|
||||
}
|
||||
bool is_realloc_of_last = chunk.size + pointer == &self.data[self.used];
|
||||
if (is_realloc_of_last)
|
||||
@@ -326,9 +299,39 @@ fn void*? TempAllocator.acquire(&self, usz size, AllocInitType init_type, usz al
|
||||
return &page.data[0];
|
||||
}
|
||||
|
||||
|
||||
fn void? _free_page(TempAllocator* self, TempAllocatorPage* page) @inline @local
|
||||
{
|
||||
void* mem = page.start;
|
||||
return self.backing_allocator.release(mem, page.is_aligned());
|
||||
}
|
||||
|
||||
fn void*? _realloc_page(TempAllocator* self, TempAllocatorPage* page, usz size, usz alignment) @inline @local
|
||||
{
|
||||
// Then the actual start pointer:
|
||||
void* real_pointer = page.start;
|
||||
|
||||
// Walk backwards to find the pointer to this page.
|
||||
TempAllocatorPage **pointer_to_prev = &self.last_page;
|
||||
// Remove the page from the list
|
||||
while (*pointer_to_prev != page)
|
||||
{
|
||||
pointer_to_prev = &((*pointer_to_prev).prev_page);
|
||||
}
|
||||
*pointer_to_prev = page.prev_page;
|
||||
usz page_size = page.pagesize();
|
||||
// Clear on size > original size.
|
||||
void* data = self.acquire(size, NO_ZERO, alignment)!;
|
||||
if (page_size > size) page_size = size;
|
||||
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;
|
||||
}
|
||||
|
||||
module std::core::mem::allocator @if((env::POSIX || env::WIN32) && $feature(VMEM_TEMP));
|
||||
import std::math;
|
||||
|
||||
|
||||
tlocal VmemOptions temp_allocator_default_options = {
|
||||
.shrink_on_reset = env::MEMORY_ENV != NORMAL,
|
||||
.protect_unused_pages = env::COMPILER_OPT_LEVEL <= O1 || env::COMPILER_SAFE_MODE,
|
||||
@@ -383,10 +386,10 @@ fn void TempAllocator.reset(&self)
|
||||
}
|
||||
fn void TempAllocator.free(&self)
|
||||
{
|
||||
self.destroy();
|
||||
_destroy(self);
|
||||
}
|
||||
|
||||
fn void TempAllocator.destroy(&self) @local
|
||||
fn void _destroy(TempAllocator* self) @local
|
||||
{
|
||||
TempAllocator* child = self.derived;
|
||||
if (!child) return;
|
||||
@@ -403,4 +406,4 @@ fn void*? TempAllocator.resize(&self, void* pointer, usz size, usz alignment) @d
|
||||
fn void TempAllocator.release(&self, void* old_pointer, bool b) @dynamic
|
||||
{
|
||||
self.vmem.release(old_pointer, b) @inline;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module std::core::string::ansi;
|
||||
import std::io;
|
||||
|
||||
const enum Ansi : inline String
|
||||
constdef Ansi : inline String
|
||||
{
|
||||
RESET = "\e[0m",
|
||||
BOLD = "\e[1m",
|
||||
|
||||
@@ -631,7 +631,7 @@ fn void DString.reverse(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn StringData* DString.data(self) @inline @private
|
||||
fn StringData* DString.data(self) @inline
|
||||
{
|
||||
return (StringData*)self;
|
||||
}
|
||||
@@ -658,9 +658,10 @@ fn usz? DString.read_from_stream(&self, InStream reader)
|
||||
if (&reader.available)
|
||||
{
|
||||
usz total_read = 0;
|
||||
while (usz available = reader.available()!)
|
||||
while (ulong available = reader.available()!)
|
||||
{
|
||||
self.reserve(available);
|
||||
if (available > isz.max) available = (ulong)isz.max;
|
||||
self.reserve((usz)available);
|
||||
StringData* data = self.data();
|
||||
usz len = reader.read(data.chars[data.len..(data.capacity - 1)])!;
|
||||
total_read += len;
|
||||
|
||||
@@ -126,6 +126,7 @@ const bool ARCH_64_BIT = $$REGISTER_SIZE == 64;
|
||||
const bool LIBC = $$COMPILER_LIBC_AVAILABLE;
|
||||
const bool NO_LIBC = !LIBC && !CUSTOM_LIBC;
|
||||
const bool CUSTOM_LIBC = $$CUSTOM_LIBC;
|
||||
const bool OLD_IO = $feature(OLD_IO);
|
||||
const CompilerOptLevel COMPILER_OPT_LEVEL = CompilerOptLevel.from_ordinal($$COMPILER_OPT_LEVEL);
|
||||
const bool BIG_ENDIAN = $$PLATFORM_BIG_ENDIAN;
|
||||
const bool I128_NATIVE_SUPPORT = $$PLATFORM_I128_SUPPORTED;
|
||||
|
||||
@@ -404,6 +404,28 @@ macro void*? @aligned_alloc(#alloc_fn, usz bytes, usz alignment)
|
||||
return mem;
|
||||
}
|
||||
|
||||
<*
|
||||
@require bytes > 0
|
||||
@require alignment > 0
|
||||
@require bytes <= isz.max
|
||||
*>
|
||||
macro void*? @aligned_alloc_fn(context, #alloc_fn, usz bytes, usz alignment)
|
||||
{
|
||||
if (alignment < void*.alignof) alignment = void*.alignof;
|
||||
usz header = AlignedBlock.sizeof + alignment;
|
||||
usz alignsize = bytes + header;
|
||||
$if $kindof(#alloc_fn(context, bytes)) == OPTIONAL:
|
||||
void* data = #alloc_fn(context, alignsize)!;
|
||||
$else
|
||||
void* data = #alloc_fn(context, alignsize);
|
||||
$endif
|
||||
void* mem = mem::aligned_pointer(data + AlignedBlock.sizeof, alignment);
|
||||
AlignedBlock* desc = (AlignedBlock*)mem - 1;
|
||||
assert(mem > data);
|
||||
*desc = { bytes, data };
|
||||
return mem;
|
||||
}
|
||||
|
||||
struct AlignedBlock
|
||||
{
|
||||
usz len;
|
||||
@@ -420,6 +442,16 @@ macro void? @aligned_free(#free_fn, void* old_pointer)
|
||||
$endif
|
||||
}
|
||||
|
||||
macro void? @aligned_free_fn(context, #free_fn, void* old_pointer)
|
||||
{
|
||||
AlignedBlock* desc = (AlignedBlock*)old_pointer - 1;
|
||||
$if $kindof(#free_fn(context, desc.start)) == OPTIONAL:
|
||||
#free_fn(context, desc.start)!;
|
||||
$else
|
||||
#free_fn(context, desc.start);
|
||||
$endif
|
||||
}
|
||||
|
||||
<*
|
||||
@require bytes > 0
|
||||
@require alignment > 0
|
||||
@@ -438,6 +470,23 @@ macro void*? @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes
|
||||
return new_data;
|
||||
}
|
||||
|
||||
<*
|
||||
@require bytes > 0
|
||||
@require alignment > 0
|
||||
*>
|
||||
macro void*? @aligned_realloc_fn(context, #calloc_fn, #free_fn, void* old_pointer, usz bytes, usz alignment)
|
||||
{
|
||||
AlignedBlock* desc = (AlignedBlock*)old_pointer - 1;
|
||||
void* data_start = desc.start;
|
||||
void* new_data = @aligned_alloc_fn(context, #calloc_fn, bytes, alignment)!;
|
||||
mem::copy(new_data, old_pointer, desc.len < bytes ? desc.len : bytes, 1, 1);
|
||||
$if $kindof(#free_fn(context, data_start)) == OPTIONAL:
|
||||
#free_fn(context, data_start)!;
|
||||
$else
|
||||
#free_fn(context, data_start);
|
||||
$endif
|
||||
return new_data;
|
||||
}
|
||||
|
||||
// All allocators
|
||||
alias mem @builtin = thread_allocator ;
|
||||
|
||||
@@ -54,7 +54,7 @@ struct FixedBlockPool
|
||||
@require calculate_actual_capacity(capacity, block_size) * block_size >= block_size
|
||||
: "Total memory would overflow"
|
||||
*>
|
||||
macro FixedBlockPool* FixedBlockPool.init(&self, Allocator allocator, usz block_size, usz capacity = INITIAL_CAPACITY, usz alignment = 0)
|
||||
fn FixedBlockPool* FixedBlockPool.init(&self, Allocator allocator, usz block_size, usz capacity = INITIAL_CAPACITY, usz alignment = 0)
|
||||
{
|
||||
self.allocator = allocator;
|
||||
self.tail = &self.head;
|
||||
@@ -64,7 +64,7 @@ macro FixedBlockPool* FixedBlockPool.init(&self, Allocator allocator, usz block_
|
||||
self.alignment = allocator::alignment_for_allocation(alignment);
|
||||
self.page_size = capacity * self.block_size;
|
||||
assert(self.page_size >= self.block_size, "Total memory would overflow %d %d", block_size, capacity);
|
||||
self.head.buffer = self.allocate_page();
|
||||
self.head.buffer = fixedblockpool_allocate_page(self);
|
||||
$if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER:
|
||||
asan::poison_memory_region(self.head.buffer, self.page_size);
|
||||
$endif
|
||||
@@ -119,7 +119,7 @@ fn void FixedBlockPool.free(&self)
|
||||
$if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER:
|
||||
asan::unpoison_memory_region(self.head.buffer, self.page_size);
|
||||
$endif
|
||||
self.free_page(self.head.buffer);
|
||||
fixedblockpool_free_page(self, self.head.buffer);
|
||||
FixedBlockPoolNode* iter = self.head.next;
|
||||
|
||||
while (iter)
|
||||
@@ -127,7 +127,7 @@ fn void FixedBlockPool.free(&self)
|
||||
$if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER:
|
||||
asan::unpoison_memory_region(iter.buffer, self.page_size);
|
||||
$endif
|
||||
self.free_page(iter.buffer);
|
||||
fixedblockpool_free_page(self, iter.buffer);
|
||||
FixedBlockPoolNode* current = iter;
|
||||
iter = iter.next;
|
||||
allocator::free(self.allocator, current);
|
||||
@@ -158,7 +158,7 @@ fn void* FixedBlockPool.alloc(&self)
|
||||
}
|
||||
|
||||
void* end = self.tail.buffer + (self.tail.capacity * self.block_size);
|
||||
if (self.next_free >= end) self.new_node();
|
||||
if (self.next_free >= end) fixedblockpool_new_node(self);
|
||||
void* ptr = self.next_free;
|
||||
self.next_free += self.block_size;
|
||||
$if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER:
|
||||
@@ -172,7 +172,7 @@ fn void* FixedBlockPool.alloc(&self)
|
||||
Deallocate a block from the block pool
|
||||
|
||||
@require self.initialized : "The block pool must be initialized"
|
||||
@require self.check_ptr(ptr) : "The pointer should be part of the pool"
|
||||
@require fixedblockpool_check_ptr(self, ptr) : "The pointer should be part of the pool"
|
||||
*>
|
||||
fn void FixedBlockPool.dealloc(&self, void* ptr)
|
||||
{
|
||||
@@ -193,7 +193,7 @@ fn void FixedBlockPool.dealloc(&self, void* ptr)
|
||||
<*
|
||||
@require self.initialized : "The block pool must be initialized"
|
||||
*>
|
||||
fn bool FixedBlockPool.check_ptr(&self, void *ptr) @local
|
||||
fn bool fixedblockpool_check_ptr(FixedBlockPool* self, void *ptr) @local
|
||||
{
|
||||
FixedBlockPoolNode* iter = &self.head;
|
||||
|
||||
@@ -210,10 +210,10 @@ fn bool FixedBlockPool.check_ptr(&self, void *ptr) @local
|
||||
<*
|
||||
@require self.grow_capacity > 0 : "How many blocks will it store"
|
||||
*>
|
||||
fn void FixedBlockPool.new_node(&self) @local
|
||||
fn void fixedblockpool_new_node(FixedBlockPool* self) @local
|
||||
{
|
||||
FixedBlockPoolNode* node = allocator::new(self.allocator, FixedBlockPoolNode);
|
||||
node.buffer = self.allocate_page();
|
||||
node.buffer = fixedblockpool_allocate_page(self);
|
||||
$if env::COMPILER_SAFE_MODE && env::ADDRESS_SANITIZER:
|
||||
asan::poison_memory_region(node.buffer, self.page_size);
|
||||
$endif
|
||||
@@ -224,14 +224,14 @@ fn void FixedBlockPool.new_node(&self) @local
|
||||
self.allocated += node.capacity;
|
||||
}
|
||||
|
||||
macro void* FixedBlockPool.allocate_page(&self) @private
|
||||
macro void* fixedblockpool_allocate_page(FixedBlockPool* self) @private
|
||||
{
|
||||
return self.alignment > mem::DEFAULT_MEM_ALIGNMENT
|
||||
? allocator::calloc_aligned(self.allocator, self.page_size, self.alignment)!!
|
||||
: allocator::calloc(self.allocator, self.page_size);
|
||||
}
|
||||
|
||||
macro void FixedBlockPool.free_page(&self, void* page) @private
|
||||
macro void fixedblockpool_free_page(FixedBlockPool* self, void* page) @private
|
||||
{
|
||||
if (self.alignment > mem::DEFAULT_MEM_ALIGNMENT)
|
||||
{
|
||||
|
||||
@@ -321,7 +321,7 @@ fn void? VirtualMemory.destroy(&self)
|
||||
return release(self.ptr, self.size);
|
||||
}
|
||||
|
||||
fn CInt VirtualMemoryAccess.to_posix(self) @if(env::POSIX) @private
|
||||
fn CInt VirtualMemoryAccess.to_posix(self) @if(env::POSIX)
|
||||
{
|
||||
switch (self)
|
||||
{
|
||||
@@ -336,7 +336,7 @@ fn CInt VirtualMemoryAccess.to_posix(self) @if(env::POSIX) @private
|
||||
}
|
||||
}
|
||||
|
||||
fn Win32_Protect VirtualMemoryAccess.to_win32(self) @if(env::WIN32) @private
|
||||
fn Win32_Protect VirtualMemoryAccess.to_win32(self) @if(env::WIN32)
|
||||
{
|
||||
switch (self)
|
||||
{
|
||||
|
||||
@@ -125,10 +125,11 @@ fn bool run_benchmarks(BenchmarkUnit[] benchmarks)
|
||||
char[] perc_str = { [0..19] = ' ', [20] = 0 };
|
||||
int perc = 0;
|
||||
uint print_step = current_benchmark_iterations / 100;
|
||||
if (print_step == 0) print_step = 1;
|
||||
|
||||
for (this_iteration = 0; this_iteration < current_benchmark_iterations; ++this_iteration, benchmark_nano_seconds = {})
|
||||
{
|
||||
if (0 == this_iteration % print_step) // only print right about when the % will update
|
||||
if (this_iteration % print_step == 0) // only print right about when the % will update
|
||||
{
|
||||
perc_str[0..(uint)math::floor((this_iteration / (float)current_benchmark_iterations) * 20)] = '#';
|
||||
perc = (uint)math::ceil(100 * (this_iteration / (float)current_benchmark_iterations));
|
||||
|
||||
@@ -142,7 +142,7 @@ fn void mute_output() @local
|
||||
File* stderr = io::stderr();
|
||||
*stderr = test_context.fake_stdout;
|
||||
*stdout = test_context.fake_stdout;
|
||||
(void)test_context.fake_stdout.seek(0, Seek.SET)!!;
|
||||
(void)test_context.fake_stdout.set_cursor(0)!!;
|
||||
}
|
||||
|
||||
fn void unmute_output(bool has_error) @local
|
||||
@@ -155,7 +155,7 @@ fn void unmute_output(bool has_error) @local
|
||||
*stderr = test_context.stored.stderr;
|
||||
*stdout = test_context.stored.stdout;
|
||||
|
||||
usz log_size = test_context.fake_stdout.seek(0, Seek.CURSOR)!!;
|
||||
ulong log_size = test_context.fake_stdout.cursor()!!;
|
||||
if (has_error)
|
||||
{
|
||||
io::printn(test_context.has_ansi_codes ? "[\e[0;31mFAIL\e[0m]" : "[FAIL]");
|
||||
@@ -165,7 +165,7 @@ fn void unmute_output(bool has_error) @local
|
||||
{
|
||||
test_context.fake_stdout.write_byte('\n')!!;
|
||||
test_context.fake_stdout.write_byte('\0')!!;
|
||||
(void)test_context.fake_stdout.seek(0, Seek.SET)!!;
|
||||
test_context.fake_stdout.set_cursor(0)!!;
|
||||
|
||||
io::printfn("\n========== TEST LOG ============");
|
||||
io::printfn("%s\n", test_context.current_test_name);
|
||||
|
||||
@@ -97,8 +97,8 @@ macro bool is_subtype_of($Type, $OtherType)
|
||||
macro bool is_numerical($Type)
|
||||
{
|
||||
$switch $Type.kindof:
|
||||
$case DISTINCT:
|
||||
$case CONST_ENUM:
|
||||
$case TYPEDEF:
|
||||
$case CONSTDEF:
|
||||
return is_numerical($Type.inner);
|
||||
$case SIGNED_INT:
|
||||
$case UNSIGNED_INT:
|
||||
@@ -170,7 +170,7 @@ macro bool is_unsigned($Type) @const
|
||||
|
||||
macro typeid flat_type($Type) @const
|
||||
{
|
||||
$if $Type.kindof == DISTINCT || $Type.kindof == CONST_ENUM:
|
||||
$if $Type.kindof == TYPEDEF || $Type.kindof == CONSTDEF:
|
||||
return flat_type($Type.inner);
|
||||
$else
|
||||
return $Type.typeid;
|
||||
@@ -179,7 +179,7 @@ macro typeid flat_type($Type) @const
|
||||
|
||||
macro TypeKind flat_kind($Type) @const
|
||||
{
|
||||
$if $Type.kindof == DISTINCT || $Type.kindof == CONST_ENUM:
|
||||
$if $Type.kindof == TYPEDEF || $Type.kindof == CONSTDEF:
|
||||
return flat_type($Type.inner);
|
||||
$else
|
||||
return $Type.kindof;
|
||||
@@ -203,8 +203,8 @@ macro bool is_flat_intlike($Type) @const
|
||||
$case UNSIGNED_INT:
|
||||
return true;
|
||||
$case VECTOR:
|
||||
$case DISTINCT:
|
||||
$case CONST_ENUM:
|
||||
$case TYPEDEF:
|
||||
$case CONSTDEF:
|
||||
return is_flat_intlike($Type.inner);
|
||||
$default:
|
||||
return false;
|
||||
@@ -230,7 +230,7 @@ macro bool is_underlying_int($Type) @const
|
||||
$case SIGNED_INT:
|
||||
$case UNSIGNED_INT:
|
||||
return true;
|
||||
$case DISTINCT:
|
||||
$case TYPEDEF:
|
||||
return is_underlying_int($Type.inner);
|
||||
$default:
|
||||
return false;
|
||||
@@ -258,7 +258,7 @@ macro bool is_vector($Type) @const
|
||||
|
||||
macro typeid inner_type($Type) @const
|
||||
{
|
||||
$if $Type.kindof == DISTINCT || $Type.kindof == CONST_ENUM:
|
||||
$if $Type.kindof == TYPEDEF || $Type.kindof == CONSTDEF:
|
||||
return inner_type($Type.inner);
|
||||
$else
|
||||
return $Type.typeid;
|
||||
@@ -298,7 +298,7 @@ macro bool may_load_atomic($Type) @const
|
||||
$case POINTER:
|
||||
$case FLOAT:
|
||||
return true;
|
||||
$case DISTINCT:
|
||||
$case TYPEDEF:
|
||||
$case ENUM:
|
||||
return may_load_atomic($Type.inner);
|
||||
$default:
|
||||
@@ -313,8 +313,8 @@ macro lower_to_atomic_compatible_type($Type) @const
|
||||
$case SIGNED_INT:
|
||||
$case UNSIGNED_INT:
|
||||
return $Type.typeid;
|
||||
$case DISTINCT:
|
||||
$case CONST_ENUM:
|
||||
$case TYPEDEF:
|
||||
$case CONSTDEF:
|
||||
return lower_to_atomic_compatible_type($Type.inner);
|
||||
$case FLOAT:
|
||||
$switch $Type:
|
||||
@@ -379,6 +379,9 @@ macro bool @comparable_value(#value) @const
|
||||
$endif
|
||||
}
|
||||
|
||||
const CONST_ENUM @builtin @deprecated("Use TypeKind.CONSTDEF instead") = TypeKind.CONSTDEF;
|
||||
const DISTINCT @builtin @deprecated("Use TypeKind.TYPEDEF instead") = TypeKind.TYPEDEF;
|
||||
|
||||
enum TypeKind : char
|
||||
{
|
||||
VOID,
|
||||
@@ -390,7 +393,7 @@ enum TypeKind : char
|
||||
FAULT,
|
||||
ANY,
|
||||
ENUM,
|
||||
CONST_ENUM,
|
||||
CONSTDEF,
|
||||
STRUCT,
|
||||
UNION,
|
||||
BITSTRUCT,
|
||||
@@ -399,7 +402,7 @@ enum TypeKind : char
|
||||
ARRAY,
|
||||
SLICE,
|
||||
VECTOR,
|
||||
DISTINCT,
|
||||
TYPEDEF,
|
||||
POINTER,
|
||||
INTERFACE,
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ macro quarter_round(uint* x, int a, int b, int c, int d) @local
|
||||
}
|
||||
|
||||
<* Process the next (or final) chunk of ingested data. *>
|
||||
fn void ChaCha20.mutate_keystream(&self) @local @inline
|
||||
fn void chacha20_mutate_keystream(ChaCha20* self) @local @inline
|
||||
{
|
||||
self.key_stream[..] = self.state[..];
|
||||
|
||||
@@ -137,7 +137,7 @@ fn void ChaCha20.transform(&self, char[] data)
|
||||
|
||||
for (usz x = offset; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..], x = offset)
|
||||
{
|
||||
self.mutate_keystream();
|
||||
chacha20_mutate_keystream(self);
|
||||
if (offset) foreach (i, &b : data[:offset]) *b ^= key_stream[i];
|
||||
char[] aligned_data = data[offset..];
|
||||
for (; x <= (BLOCK_SIZE - usz.sizeof); x += usz.sizeof)
|
||||
@@ -150,7 +150,7 @@ fn void ChaCha20.transform(&self, char[] data)
|
||||
// 3. Process any remaining bytes.
|
||||
if (data.len > 0)
|
||||
{
|
||||
self.mutate_keystream();
|
||||
chacha20_mutate_keystream(self);
|
||||
for (usz i = 0; i < data.len; i++) data[i] ^= key_stream[i];
|
||||
self.position = data.len;
|
||||
}
|
||||
|
||||
@@ -567,7 +567,7 @@ fn F25519Int F25519Int.inv(&s)
|
||||
|
||||
@param [&in] s
|
||||
*>
|
||||
fn F25519Int F25519Int.pow_2523(&s) @local
|
||||
fn F25519Int pow_2523(F25519Int* s) @local
|
||||
{
|
||||
F25519Int r = *s;
|
||||
|
||||
@@ -587,7 +587,7 @@ fn F25519Int F25519Int.pow_2523(&s) @local
|
||||
fn F25519Int F25519Int.sqrt(&s)
|
||||
{
|
||||
F25519Int twice = s.mul_s(2);
|
||||
F25519Int pow = twice.pow_2523();
|
||||
F25519Int pow = pow_2523(&twice);
|
||||
|
||||
return (twice * pow * pow - ONE) * s * pow;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ struct DelayedSchedulerEvent @local
|
||||
Clock execution_time;
|
||||
}
|
||||
|
||||
fn int DelayedSchedulerEvent.compare_to(self, DelayedSchedulerEvent other) @local
|
||||
fn int DelayedSchedulerEvent.compare_to(self, DelayedSchedulerEvent other)
|
||||
{
|
||||
switch
|
||||
{
|
||||
|
||||
@@ -49,43 +49,43 @@ macro @round(r, m, $s, #v) @local
|
||||
@g(r, m, $s, 7, #v[ 3], #v[ 4], #v[ 9], #v[14]);
|
||||
}
|
||||
|
||||
macro @common_compress(#instance, $rounds, $iv, $sigma, block) @local
|
||||
macro common_compress(instance, $rounds, $iv, $sigma, block) @local
|
||||
{
|
||||
$typeof(#instance.h[0])[16] m, v;
|
||||
$typeof(instance.h[0])[16] m, v;
|
||||
|
||||
((char*)&m)[:$sizeof(block)] = block[..];
|
||||
|
||||
v[:8] = #instance.h[..];
|
||||
v[:8] = instance.h[..];
|
||||
v[ 8] = $iv[0];
|
||||
v[ 9] = $iv[1];
|
||||
v[10] = $iv[2];
|
||||
v[11] = $iv[3];
|
||||
v[12] = $iv[4] ^ #instance.t[0];
|
||||
v[13] = $iv[5] ^ #instance.t[1];
|
||||
v[14] = $iv[6] ^ #instance.f[0];
|
||||
v[15] = $iv[7] ^ #instance.f[1];
|
||||
v[12] = $iv[4] ^ instance.t[0];
|
||||
v[13] = $iv[5] ^ instance.t[1];
|
||||
v[14] = $iv[6] ^ instance.f[0];
|
||||
v[15] = $iv[7] ^ instance.f[1];
|
||||
|
||||
$for usz $i = 0; $i < $rounds; $i++:
|
||||
@round($i, m, $sigma, v);
|
||||
$endfor
|
||||
|
||||
$for usz $i = 0; $i < 8; $i++:
|
||||
#instance.h[$i] ^= v[$i] ^ v[$i + 8];
|
||||
instance.h[$i] ^= v[$i] ^ v[$i + 8];
|
||||
$endfor
|
||||
}
|
||||
|
||||
macro @add_ctr(#instance, usz amount) @local
|
||||
macro _add_ctr(instance, usz amount) @local
|
||||
{
|
||||
#instance.t[0] += ($typeof(#instance.t[0]))amount;
|
||||
#instance.t[1] += ($typeof(#instance.t[0]))(#instance.t[0] < amount); // adds 1 on overflow of [0]
|
||||
instance.t[0] += ($typeof(instance.t[0]))amount;
|
||||
instance.t[1] += ($typeof(instance.t[0]))(instance.t[0] < amount); // adds 1 on overflow of [0]
|
||||
}
|
||||
|
||||
macro @common_init(#instance, $ParamType, $iv, usz out_len, char[] key = {}, char[] salt = {}, char[] personal = {}) @local
|
||||
macro common_init(instance, $ParamType, $iv, usz out_len, char[] key = {}, char[] salt = {}, char[] personal = {}) @local
|
||||
{
|
||||
mem::zero_volatile(@as_char_view(*#instance)); // explicitly because habits around hash init usually involve @noinit
|
||||
mem::zero_volatile(@as_char_view(*instance)); // explicitly because habits around hash init usually involve @noinit
|
||||
|
||||
#instance.h[..] = $iv[..];
|
||||
#instance.outlen = out_len;
|
||||
instance.h[..] = $iv[..];
|
||||
instance.outlen = out_len;
|
||||
|
||||
$ParamType p = {
|
||||
.digest_length = (char)out_len,
|
||||
@@ -96,59 +96,60 @@ macro @common_init(#instance, $ParamType, $iv, usz out_len, char[] key = {}, cha
|
||||
if (salt.len) p.salt[:salt.len] = salt[..];
|
||||
if (personal.len) p.personal[:personal.len] = personal[..];
|
||||
|
||||
array::@zip_into(((char*)&#instance.h)[:$sizeof(p)], ((char*)&p)[:$sizeof(p)], fn (a, b) => a ^ b); // bytes(self.h) ^= bytes(p)
|
||||
array::@zip_into(((char*)&instance.h)[:$sizeof(p)], ((char*)&p)[:$sizeof(p)], fn (a, b) => a ^ b); // bytes(self.h) ^= bytes(p)
|
||||
|
||||
if (key.len)
|
||||
{
|
||||
char[$sizeof($iv[0])*16] dummy = {};
|
||||
dummy[:key.len] = key[..];
|
||||
#instance.update(dummy[..]); // consume a FULL block
|
||||
instance.update(dummy[..]); // consume a FULL block
|
||||
mem::zero_volatile(dummy[..]); // do not optimize clearing this from the stack
|
||||
}
|
||||
}
|
||||
|
||||
macro @common_update(#instance, $block_size, char[] data) @local
|
||||
macro common_update(instance, $block_size, char[] data) @local
|
||||
{
|
||||
if (@unlikely(!data.len)) return;
|
||||
|
||||
usz fill = $block_size - #instance.buflen;
|
||||
usz fill = $block_size - instance.buflen;
|
||||
if (data.len > fill)
|
||||
{
|
||||
#instance.buf[#instance.buflen:fill] = data[:fill];
|
||||
#instance.buflen = 0;
|
||||
instance.buf[instance.buflen:fill] = data[:fill];
|
||||
instance.buflen = 0;
|
||||
|
||||
@add_ctr(#instance, $block_size);
|
||||
#instance.compress(#instance.buf);
|
||||
_add_ctr(instance, $block_size);
|
||||
instance._compress(instance.buf);
|
||||
|
||||
data = data[fill..];
|
||||
|
||||
for (; data.len > $block_size; data = data[$block_size..])
|
||||
{
|
||||
@add_ctr(#instance, $block_size);
|
||||
#instance.compress(data[:$block_size]);
|
||||
_add_ctr(instance, $block_size);
|
||||
instance._compress(data[:$block_size]);
|
||||
}
|
||||
}
|
||||
#instance.buf[#instance.buflen:data.len] = data[..];
|
||||
#instance.buflen += data.len;
|
||||
instance.buf[instance.buflen:data.len] = data[..];
|
||||
instance.buflen += data.len;
|
||||
}
|
||||
|
||||
macro @common_final(#instance, $output_length) @local
|
||||
macro common_final(instance, $output_length) @local
|
||||
{
|
||||
char[$output_length] result = {};
|
||||
if ($output_length != #instance.outlen) return result;
|
||||
if ($output_length != instance.outlen) return result;
|
||||
|
||||
@add_ctr(#instance, #instance.buflen);
|
||||
if (#instance.f[0]) return result; // technically an error return
|
||||
_add_ctr(instance, instance.buflen);
|
||||
if (instance.f[0]) return result; // technically an error return
|
||||
|
||||
if (#instance.last_node) #instance.f[1] = $typeof(#instance.h[0]).max;
|
||||
#instance.f[0] = $typeof(#instance.h[0]).max;
|
||||
var $max = $typeof(instance.h[0]).max;
|
||||
if (instance.last_node) instance.f[1] = $max;
|
||||
instance.f[0] = $max;
|
||||
|
||||
mem::zero_volatile(#instance.buf[#instance.buflen..]); // pad buffer with zeroes
|
||||
#instance.compress(#instance.buf);
|
||||
mem::zero_volatile(instance.buf[instance.buflen..]); // pad buffer with zeroes
|
||||
instance._compress(instance.buf);
|
||||
|
||||
defer mem::zero_volatile(@as_char_view(*#instance)); // destroy the current context implicitly
|
||||
defer mem::zero_volatile(@as_char_view(*instance)); // destroy the current context implicitly
|
||||
|
||||
result[:#instance.outlen] = @as_char_view(#instance.h)[:#instance.outlen];
|
||||
result[:instance.outlen] = @as_char_view(instance.h)[:instance.outlen];
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -244,13 +245,13 @@ alias b_512 = blake2b_512;
|
||||
@require !personal.ptr || (personal.len > 0 && personal.len <= BLAKE2B_PERSONALBYTES) : "A specified personalization's length must be within the proper range."
|
||||
*>
|
||||
fn void Blake2b.init(&self, usz out_len, char[] key = {}, char[] salt = {}, char[] personal = {})
|
||||
=> @common_init(self, Blake2bParam, BLAKE2B_IV, out_len, key, salt, personal);
|
||||
=> common_init(self, Blake2bParam, BLAKE2B_IV, out_len, key, salt, personal);
|
||||
|
||||
<*
|
||||
Core compression inline function for Blake2b.
|
||||
*>
|
||||
fn void Blake2b.compress(&self, char[BLAKE2B_BLOCKBYTES] block) @local @inline
|
||||
=> @common_compress(self, 12, BLAKE2B_IV, BLAKE2B_SIGMA, block);
|
||||
fn void Blake2b._compress(&self, char[BLAKE2B_BLOCKBYTES] block) @inline
|
||||
=> common_compress(self, 12, BLAKE2B_IV, BLAKE2B_SIGMA, block);
|
||||
|
||||
<*
|
||||
Add more data to the hash context or stream.
|
||||
@@ -258,7 +259,7 @@ fn void Blake2b.compress(&self, char[BLAKE2B_BLOCKBYTES] block) @local @inline
|
||||
@param[in] data : "The data to ingest into the hash context."
|
||||
*>
|
||||
fn void Blake2b.update(&self, char[] data)
|
||||
=> @common_update(self, BLAKE2B_BLOCKBYTES, data);
|
||||
=> common_update(self, BLAKE2B_BLOCKBYTES, data);
|
||||
|
||||
<*
|
||||
Finalize the hash context and return the hash result at the given size.
|
||||
@@ -267,9 +268,12 @@ fn void Blake2b.update(&self, char[] data)
|
||||
|
||||
@require $output_length == self.outlen : "The specified compile-time output size MUST be equal to the initialized output size."
|
||||
*>
|
||||
macro char[*] Blake2b.final(&self, $output_length)
|
||||
=> @common_final(self, $output_length);
|
||||
macro char[*] Blake2b.final(&self, $output_length) => _blake2b_final{$output_length}(self);
|
||||
|
||||
fn char[OUTPUT_LENGTH] _blake2b_final(Blake2b* self) <OUTPUT_LENGTH> @local
|
||||
{
|
||||
return common_final(self, OUTPUT_LENGTH);
|
||||
}
|
||||
|
||||
// ======================================================================================
|
||||
// BEGIN Blake2s contents. Do not separate this from Blake2b: there's not really a point.
|
||||
@@ -356,13 +360,13 @@ alias s_256 = blake2s_256;
|
||||
@require !personal.ptr || (personal.len > 0 && personal.len <= BLAKE2B_PERSONALBYTES) : "A specified personalization's length must be within the proper range."
|
||||
*>
|
||||
fn void Blake2s.init(&self, usz out_len, char[] key = {}, char[] salt = {}, char[] personal = {})
|
||||
=> @common_init(self, Blake2sParam, BLAKE2S_IV, out_len, key, salt, personal);
|
||||
=> common_init(self, Blake2sParam, BLAKE2S_IV, out_len, key, salt, personal);
|
||||
|
||||
<*
|
||||
Core compression inline function for Blake2s.
|
||||
*>
|
||||
fn void Blake2s.compress(&self, char[BLAKE2S_BLOCKBYTES] block) @local @inline
|
||||
=> @common_compress(self, 10, BLAKE2S_IV, BLAKE2S_SIGMA, block);
|
||||
fn void Blake2s._compress(&self, char[BLAKE2S_BLOCKBYTES] block) @inline
|
||||
=> common_compress(self, 10, BLAKE2S_IV, BLAKE2S_SIGMA, block);
|
||||
|
||||
<*
|
||||
Add more data to the hash context or stream.
|
||||
@@ -370,7 +374,7 @@ fn void Blake2s.compress(&self, char[BLAKE2S_BLOCKBYTES] block) @local @inline
|
||||
@param[in] data : "The data to ingest into the hash context."
|
||||
*>
|
||||
fn void Blake2s.update(&self, char[] data)
|
||||
=> @common_update(self, BLAKE2S_BLOCKBYTES, data);
|
||||
=> common_update(self, BLAKE2S_BLOCKBYTES, data);
|
||||
|
||||
<*
|
||||
Finalize the hash context and return the hash result at the given size.
|
||||
@@ -380,4 +384,4 @@ fn void Blake2s.update(&self, char[] data)
|
||||
@require $output_length == self.outlen : "The specified compile-time output size MUST be equal to the initialized output size."
|
||||
*>
|
||||
macro char[*] Blake2s.final(&self, $output_length)
|
||||
=> @common_final(self, $output_length);
|
||||
=> common_final(self, $output_length);
|
||||
|
||||
@@ -91,7 +91,7 @@ macro @simd_degree() @local
|
||||
}
|
||||
|
||||
<* Flags used during hash computation based on its state. *>
|
||||
const enum Blake3Flags : inline char
|
||||
constdef Blake3Flags : inline char
|
||||
{
|
||||
CHUNK_START = 1 << 0,
|
||||
CHUNK_END = 1 << 1,
|
||||
@@ -246,7 +246,7 @@ fn void Blake3.init(&self, char[] key = {}, char explicit_flags = 0)
|
||||
<*
|
||||
Reset the state of the hashing context, in case it should be reused without reloading the key value.
|
||||
*>
|
||||
fn void Blake3.reset(&self) @local @inline
|
||||
fn void _reset(Blake3* self) @local @inline
|
||||
{
|
||||
self.chunk.reset(self.key[..], 0);
|
||||
self.cv_stack_len = 0;
|
||||
@@ -255,7 +255,7 @@ fn void Blake3.reset(&self) @local @inline
|
||||
<*
|
||||
Private function to merge tree results.
|
||||
*>
|
||||
fn void Blake3.merge_cv_stack(&self, ulong total_len) @local @inline
|
||||
fn void _merge_cv_stack(Blake3* self, ulong total_len) @local @inline
|
||||
{
|
||||
usz post_merge_stack_len = (usz)@popcnt(total_len);
|
||||
for (; self.cv_stack_len > post_merge_stack_len; self.cv_stack_len--)
|
||||
@@ -269,9 +269,9 @@ fn void Blake3.merge_cv_stack(&self, ulong total_len) @local @inline
|
||||
<*
|
||||
Private function to add a new tree onto the stack.
|
||||
*>
|
||||
fn void Blake3.push_cv(&self, char* new_cv, ulong chunk_counter) @local @inline
|
||||
fn void Blake3.push_cv(&self, char* new_cv, ulong chunk_counter) @inline
|
||||
{
|
||||
self.merge_cv_stack(chunk_counter);
|
||||
_merge_cv_stack(self, chunk_counter);
|
||||
self.cv_stack[self.cv_stack_len * OUT_SIZE : OUT_SIZE] = new_cv[:OUT_SIZE];
|
||||
self.cv_stack_len++;
|
||||
}
|
||||
@@ -334,7 +334,7 @@ fn void Blake3.update(&self, char[] input, bool use_tbb = false)
|
||||
if (input.len > 0)
|
||||
{
|
||||
self.chunk.update(input);
|
||||
self.merge_cv_stack(self.chunk.chunk_counter);
|
||||
_merge_cv_stack(self, self.chunk.chunk_counter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,7 +400,7 @@ fn void Blake3.destroy(&self) @inline
|
||||
@param [in] key
|
||||
@param flags
|
||||
*>
|
||||
fn void Blake3ChunkState.init(&self, uint[] key, char flags) @local @inline
|
||||
fn void Blake3ChunkState.init(&self, uint[] key, char flags) @inline
|
||||
{
|
||||
mem::zero_volatile(@as_char_view(*self));
|
||||
self.cv[..] = key[..];
|
||||
@@ -413,7 +413,7 @@ fn void Blake3ChunkState.init(&self, uint[] key, char flags) @local @inline
|
||||
@param [in] key
|
||||
@param chunk_counter
|
||||
*>
|
||||
fn void Blake3ChunkState.reset(&self, uint[] key, ulong chunk_counter) @local @inline
|
||||
fn void Blake3ChunkState.reset(&self, uint[] key, ulong chunk_counter) @inline
|
||||
{
|
||||
self.init(key, self.flags); // maintain its own flags
|
||||
self.chunk_counter = chunk_counter; // update chunk counter
|
||||
@@ -422,7 +422,7 @@ fn void Blake3ChunkState.reset(&self, uint[] key, ulong chunk_counter) @local @i
|
||||
<*
|
||||
Get bytes length of consumed data.
|
||||
*>
|
||||
fn usz Blake3ChunkState.len(&self) @operator(len) @local @inline
|
||||
fn usz Blake3ChunkState.len(&self) @operator(len) @inline
|
||||
=> (BLOCK_SIZE * (usz)self.blocks_compressed) + (usz)self.buf_len;
|
||||
|
||||
<*
|
||||
@@ -430,7 +430,7 @@ fn usz Blake3ChunkState.len(&self) @operator(len) @local @inline
|
||||
|
||||
@param [in] data : "Data to ingest."
|
||||
*>
|
||||
fn usz Blake3ChunkState.fill_buf(&self, char[] data) @local @inline
|
||||
fn usz Blake3ChunkState.fill_buf(&self, char[] data) @inline
|
||||
{
|
||||
usz take = min(BLOCK_SIZE - (usz)self.buf_len, data.len);
|
||||
self.buf[self.buf_len:take] = data[:take];
|
||||
@@ -441,7 +441,7 @@ fn usz Blake3ChunkState.fill_buf(&self, char[] data) @local @inline
|
||||
<*
|
||||
Determine whether to set the CHUNK_START flag.
|
||||
*>
|
||||
fn char Blake3ChunkState.maybe_start_flag(&self) @local @inline
|
||||
fn char Blake3ChunkState.maybe_start_flag(&self) @inline
|
||||
=> !self.blocks_compressed ? Blake3Flags.CHUNK_START : 0;
|
||||
|
||||
<*
|
||||
@@ -449,7 +449,7 @@ fn char Blake3ChunkState.maybe_start_flag(&self) @local @inline
|
||||
|
||||
@param [in] input : "Incoming bytes to update with."
|
||||
*>
|
||||
fn void Blake3ChunkState.update(&self, char[] input) @local
|
||||
fn void Blake3ChunkState.update(&self, char[] input)
|
||||
{
|
||||
if (self.buf_len)
|
||||
{
|
||||
@@ -473,7 +473,7 @@ fn void Blake3ChunkState.update(&self, char[] input) @local
|
||||
<*
|
||||
Convert the chunk state to an "output" type with the right flags.
|
||||
*>
|
||||
fn Blake3Output Blake3ChunkState.output(&self) @local @inline
|
||||
fn Blake3Output Blake3ChunkState.output(&self) @inline
|
||||
=> make_output(self.cv[..], &self.buf, self.buf_len, self.chunk_counter, self.flags | self.maybe_start_flag() | Blake3Flags.CHUNK_END);
|
||||
|
||||
<*
|
||||
@@ -511,7 +511,7 @@ macro Blake3Output parent_output(char* block, uint[] key, char flags) @local
|
||||
|
||||
@param [&inout] cv
|
||||
*>
|
||||
macro void Blake3Output.chaining_value(&self, char* cv) @local
|
||||
macro void Blake3Output.chaining_value(&self, char* cv)
|
||||
{
|
||||
uint[KEY_SIZE_WORDS] cv_words;
|
||||
cv_words[..] = self.input_cv[..];
|
||||
@@ -525,7 +525,7 @@ macro void Blake3Output.chaining_value(&self, char* cv) @local
|
||||
@param seek
|
||||
@param [inout] into
|
||||
*>
|
||||
fn void Blake3Output.root_bytes(&self, usz seek, char[] into) @local
|
||||
fn void Blake3Output.root_bytes(&self, usz seek, char[] into)
|
||||
{
|
||||
if (!into.len) return;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
module std::hash::streebog;
|
||||
|
||||
|
||||
const enum StreebogLength : inline uint
|
||||
constdef StreebogLength : inline uint
|
||||
{
|
||||
SIZE_256 = 32,
|
||||
SIZE_512 = 64,
|
||||
@@ -147,13 +147,13 @@ fn void Streebog.update(&self, char[] data)
|
||||
macro char[*] Streebog.final(&self, StreebogLength $hash_size)
|
||||
{
|
||||
char[$hash_size] result;
|
||||
self._final_private();
|
||||
streebog_final_private(self);
|
||||
defer mem::zero_volatile(@as_char_view(*self)); // implicitly clear the structure when finalized
|
||||
result[..] = @as_char_view(self.h)[(BLOCK_SIZE - $hash_size)..];
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void Streebog._final_private(&self) @local
|
||||
fn void streebog_final_private(Streebog* self) @local
|
||||
{
|
||||
ulong[8] unprocessed_bits_count;
|
||||
usz index = self.index >> 3;
|
||||
|
||||
@@ -86,14 +86,14 @@ fn void Poly1305.update(&self, char[] input)
|
||||
}
|
||||
// ingest up to a block size to finish the partial, then advance the slice ptr
|
||||
self.temp[self.num:rem] = input[:rem];
|
||||
self.blocks(self.temp[..]);
|
||||
_blocks(self, self.temp[..]);
|
||||
input = input[rem..];
|
||||
}
|
||||
|
||||
usz even_length = input.len - (input.len % BLOCK_SIZE);
|
||||
if (even_length >= BLOCK_SIZE)
|
||||
{
|
||||
self.blocks(input[:even_length]); // consume blocks
|
||||
_blocks(self, input[:even_length]); // consume blocks
|
||||
input = input[even_length..]; // scroll to end (remainder)
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ fn char[TAG_SIZE] Poly1305.final(&self)
|
||||
{
|
||||
self.temp[self.num++] = 1; // partial blocks must end with 0x01
|
||||
self.temp[self.num..] = {}; // explicit zeros on the rest
|
||||
self.blocks(self.temp[..], 0); // chomp
|
||||
_blocks(self, self.temp[..], 0); // chomp
|
||||
}
|
||||
|
||||
uint128 t = (uint128)self.h[0] + 5;
|
||||
@@ -135,7 +135,7 @@ fn char[TAG_SIZE] Poly1305.final(&self)
|
||||
}
|
||||
|
||||
|
||||
fn void Poly1305.blocks(&self, char[] input, ulong pad_bit = 1) @local
|
||||
fn void _blocks(Poly1305* self, char[] input, ulong pad_bit = 1) @local
|
||||
{
|
||||
for (; input.len >= BLOCK_SIZE; input = input[BLOCK_SIZE..])
|
||||
{
|
||||
|
||||
@@ -68,18 +68,18 @@ fn void Sha256.update(&self, char[] data)
|
||||
usz len = min(BLOCK_SIZE - buffer_pos, data.len);
|
||||
self.buffer[buffer_pos:len] = data[:len];
|
||||
data = data[len..];
|
||||
if (buffer_pos + len == BLOCK_SIZE) self.transform();
|
||||
if (buffer_pos + len == BLOCK_SIZE) _transform(self);
|
||||
}
|
||||
|
||||
// When the data pointer is aligned, we can disregard unaligned loading in the `transform` macro.
|
||||
// We do this here from the outer call to reduce the expense of checking alignment on every single block.
|
||||
if (0 == (usz)data.ptr % usz.sizeof)
|
||||
{
|
||||
for (; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..]) self.transform((uint*)data.ptr);
|
||||
for (; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..]) _transform(self, (uint*)data.ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..]) self.transform_unaligned((uint*)data.ptr);
|
||||
for (; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..]) _transform_unaligned(self, (uint*)data.ptr);
|
||||
}
|
||||
|
||||
// Leftover data just gets stored away for the next update or final.
|
||||
@@ -102,7 +102,7 @@ fn char[HASH_SIZE] Sha256.final(&self)
|
||||
if (i > BLOCK_SIZE - 8)
|
||||
{
|
||||
self.buffer[i..] = 0x00;
|
||||
self.transform();
|
||||
_transform(self);
|
||||
i = 0; // Reset buffer index after transformation
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ fn char[HASH_SIZE] Sha256.final(&self)
|
||||
// Append the bitcount in big-endian format
|
||||
*(ulong*)(&self.buffer[BLOCK_SIZE - 8]) = env::BIG_ENDIAN ??? self.bitcount : bswap(self.bitcount);
|
||||
|
||||
self.transform();
|
||||
_transform(self);
|
||||
|
||||
// Convert state to the final hash
|
||||
foreach (x, s : self.state) *(uint*)(&hash[x * uint.sizeof]) = env::BIG_ENDIAN ??? s : bswap(s);
|
||||
@@ -121,10 +121,10 @@ fn char[HASH_SIZE] Sha256.final(&self)
|
||||
|
||||
// These wrappers are necessary to significantly reduce code generation from macro expansions.
|
||||
// Note that transformations on `self.buffer` (when incoming == null) should always be aligned.
|
||||
fn void Sha256.transform(&self, uint* incoming = null) @local @noinline => self.do_transform(incoming, true);
|
||||
fn void Sha256.transform_unaligned(&self, uint* incoming = null) @local @noinline => self.do_transform(incoming, false);
|
||||
fn void _transform(Sha256* self, uint* incoming = null) @local @noinline => _do_transform(self, incoming, true);
|
||||
fn void _transform_unaligned(Sha256* self, uint* incoming = null) @local @noinline => _do_transform(self, incoming, false);
|
||||
|
||||
macro Sha256.do_transform(&self, uint* incoming = null, bool $aligned = true) @local
|
||||
macro _do_transform(Sha256* self, uint* incoming = null, bool $aligned = true) @local
|
||||
{
|
||||
uint a, b, c, d, e, f, g, h, t1, t2 @noinit;
|
||||
uint[64] m @noinit;
|
||||
|
||||
@@ -100,7 +100,7 @@ fn void SipHash.update(&self, char[] data)
|
||||
self.v[3] ^= self.m;
|
||||
|
||||
$for var $i = 0; $i < BLOCK_ROUNDS; ++$i : // unrolled loop
|
||||
self.round();
|
||||
siphash_round(self);
|
||||
$endfor
|
||||
|
||||
self.v[0] ^= self.m;
|
||||
@@ -123,7 +123,7 @@ fn OutType SipHash.final(&self)
|
||||
$endif
|
||||
|
||||
$for var $i = 0; $i < FINALIZE_ROUNDS; ++$i : // unrolled loop
|
||||
self.round();
|
||||
siphash_round(self);
|
||||
$endfor
|
||||
|
||||
$if OutType.typeid == ulong.typeid :
|
||||
@@ -134,7 +134,7 @@ fn OutType SipHash.final(&self)
|
||||
self.v[1] ^= 0xDD;
|
||||
|
||||
$for var $i = 0; $i < FINALIZE_ROUNDS; ++$i : // unrolled loop
|
||||
self.round();
|
||||
siphash_round(self);
|
||||
$endfor
|
||||
|
||||
return lo | ((uint128)(self.v[0] ^ self.v[1] ^ self.v[2] ^ self.v[3]) << 64);
|
||||
@@ -142,7 +142,7 @@ fn OutType SipHash.final(&self)
|
||||
}
|
||||
|
||||
|
||||
fn void SipHash.round(&self) @local
|
||||
fn void siphash_round(SipHash* self) @local
|
||||
{
|
||||
self.v[0] += self.v[1];
|
||||
self.v[1] = self.v[1].rotl(13);
|
||||
|
||||
@@ -66,14 +66,14 @@ fn void Whirlpool.update(&self, char[] data)
|
||||
// If the algorithm is finalized during a 'partial' block, it has its own padding to fill the remaining gap.
|
||||
if (data.len < to_pad) return;
|
||||
|
||||
self.process_block(&self.block);
|
||||
_process_block(self, &self.block);
|
||||
data = data[to_pad..];
|
||||
}
|
||||
|
||||
// Digest blocks wholesale.
|
||||
while (data.len >= BLOCK_SIZE)
|
||||
{
|
||||
self.process_block(data);
|
||||
_process_block(self, data);
|
||||
|
||||
data = (data.len > BLOCK_SIZE) ? data[BLOCK_SIZE..] : {};
|
||||
}
|
||||
@@ -100,7 +100,7 @@ fn char[HASH_SIZE] Whirlpool.final(&self)
|
||||
{
|
||||
if (remainder < 64) self.block[remainder..63] = 0x00;
|
||||
|
||||
self.process_block(&self.block);
|
||||
_process_block(self, &self.block);
|
||||
remainder = 0;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ fn char[HASH_SIZE] Whirlpool.final(&self)
|
||||
self.block_128[3] = $$bswap(self.counter_low << 3);
|
||||
|
||||
// Process the final block.
|
||||
self.process_block(&self.block);
|
||||
_process_block(self, &self.block);
|
||||
|
||||
// Each ulong in the resultant hash should be bit-swapped before the final return.
|
||||
char[HASH_SIZE] hash @align(ulong.alignof);
|
||||
@@ -153,7 +153,7 @@ const ulong[10] RC @private = {
|
||||
};
|
||||
const ROUNDS = 10;
|
||||
|
||||
fn void Whirlpool.process_block(&self, char* block) @local
|
||||
fn void _process_block(Whirlpool* self, char* block) @local
|
||||
{
|
||||
ulong[2 * 8] k; // key
|
||||
ulong[2 * 8] state; // state
|
||||
|
||||
@@ -39,11 +39,16 @@ fn bool is_dir(String path)
|
||||
return os::native_is_dir(path);
|
||||
}
|
||||
|
||||
fn usz? get_size(String path)
|
||||
fn ulong? get_size(String path)
|
||||
{
|
||||
return os::native_file_size(path);
|
||||
}
|
||||
|
||||
fn void? set_modified_time(String path, Time_t time)
|
||||
{
|
||||
return os::native_set_modified_time(path, time);
|
||||
}
|
||||
|
||||
fn void? delete(String filename)
|
||||
{
|
||||
return os::native_remove(filename) @inline;
|
||||
@@ -63,10 +68,25 @@ fn void? File.reopen(&self, String filename, String mode)
|
||||
*>
|
||||
fn usz? File.seek(&self, isz offset, Seek seek_mode = Seek.SET) @dynamic
|
||||
{
|
||||
os::native_fseek(self.file, offset, seek_mode)!;
|
||||
return os::native_ftell(self.file);
|
||||
os::native_fseek(self.file, offset, (SeekOrigin)seek_mode.ordinal)!;
|
||||
return (usz)os::native_ftell(self.file);
|
||||
}
|
||||
|
||||
<*
|
||||
@require self.file != null
|
||||
*>
|
||||
fn void? File.set_cursor(&self, long offset, SeekOrigin whence = FROM_START) @dynamic
|
||||
{
|
||||
return os::native_fseek(self.file, offset, whence);
|
||||
}
|
||||
|
||||
<*
|
||||
@require self.file != null
|
||||
*>
|
||||
fn long? File.cursor(&self) @dynamic
|
||||
{
|
||||
return os::native_ftell(self.file);
|
||||
}
|
||||
|
||||
/*
|
||||
Implement later
|
||||
@@ -118,6 +138,14 @@ fn void? File.close(&self) @inline @dynamic
|
||||
self.file = null;
|
||||
}
|
||||
|
||||
fn ulong? File.size(&self) @dynamic
|
||||
{
|
||||
long curr = self.cursor()!;
|
||||
defer (void)self.set_cursor(curr);
|
||||
self.set_cursor(0, FROM_END)!;
|
||||
return self.cursor()!;
|
||||
}
|
||||
|
||||
<*
|
||||
@require self.file != null
|
||||
*>
|
||||
@@ -171,9 +199,8 @@ fn char[]? load_buffer(String filename, char[] buffer)
|
||||
{
|
||||
File file = open(filename, "rb")!;
|
||||
defer (void)file.close();
|
||||
usz len = file.seek(0, END)!;
|
||||
long len = file.size()!;
|
||||
if (len > buffer.len) return io::OVERFLOW~;
|
||||
file.seek(0, SET)!;
|
||||
usz read = 0;
|
||||
while (read < len)
|
||||
{
|
||||
@@ -187,16 +214,16 @@ fn char[]? load(Allocator allocator, String filename)
|
||||
{
|
||||
File file = open(filename, "rb")!;
|
||||
defer (void)file.close();
|
||||
usz len = file.seek(0, END)!;
|
||||
file.seek(0, SET)!;
|
||||
char* data = allocator::malloc_try(allocator, len)!;
|
||||
ulong len = file.size()!;
|
||||
if (len > usz.max) return io::OUT_OF_SPACE~;
|
||||
char* data = allocator::malloc_try(allocator, (usz)len)!;
|
||||
defer catch allocator::free(allocator, data);
|
||||
usz read = 0;
|
||||
while (read < len)
|
||||
while (read < (usz)len)
|
||||
{
|
||||
read += file.read(data[read:len - read])!;
|
||||
read += file.read(data[read:(usz)len - read])!;
|
||||
}
|
||||
return data[:len];
|
||||
return data[:(usz)len];
|
||||
}
|
||||
|
||||
fn char[]? load_path(Allocator allocator, Path path) => load(allocator, path.str_view());
|
||||
|
||||
@@ -45,10 +45,9 @@ fn FileMmap? mmap_file(File file, usz offset = 0, usz len = 0, VirtualMemoryAcce
|
||||
{
|
||||
if (len == 0)
|
||||
{
|
||||
usz cur = file.seek(0, CURSOR)!;
|
||||
defer file.seek(cur, SET)!!;
|
||||
usz file_size = file.seek(0, END)!;
|
||||
len = file_size - offset;
|
||||
ulong new_len = file.size()! - offset;
|
||||
if (new_len > (ulong)isz.max) return mem::OUT_OF_MEMORY~;
|
||||
len = (usz)new_len;
|
||||
}
|
||||
|
||||
// get the page size
|
||||
|
||||
@@ -91,16 +91,7 @@ fn void Formatter.init(&self, OutputFn out_fn, void* data = null)
|
||||
*self = { .data = data, .out_fn = out_fn};
|
||||
}
|
||||
|
||||
fn usz? Formatter.out(&self, char c) @private
|
||||
{
|
||||
if (catch err = self.out_fn(self.data, c))
|
||||
{
|
||||
if (self.first_fault) return self.first_fault~;
|
||||
self.first_fault = err;
|
||||
return err~;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
fn usz? Formatter.print_with_function(&self, Printable arg)
|
||||
{
|
||||
@@ -115,7 +106,7 @@ fn usz? Formatter.print_with_function(&self, Printable arg)
|
||||
self.width = old_width;
|
||||
self.prec = old_prec;
|
||||
}
|
||||
if (!arg) return self.out_substr("(null)");
|
||||
if (!arg) return formatter_out_substr(self, "(null)");
|
||||
return arg.to_format(self);
|
||||
}
|
||||
if (&arg.to_constant_string)
|
||||
@@ -129,161 +120,12 @@ fn usz? Formatter.print_with_function(&self, Printable arg)
|
||||
self.width = old_width;
|
||||
self.prec = old_prec;
|
||||
}
|
||||
if (!arg) return self.out_substr("(null)");
|
||||
return self.out_substr(arg.to_constant_string());
|
||||
if (!arg) return formatter_out_substr(self, "(null)");
|
||||
return formatter_out_substr(self, arg.to_constant_string());
|
||||
}
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn usz? Formatter.out_unknown(&self, String category, any arg) @private
|
||||
{
|
||||
return self.out_substr("<") + self.out_substr(category) + self.out_substr(" type:") + self.ntoa((iptr)arg.type, false, 16) + self.out_substr(", addr:") + self.ntoa((iptr)arg.ptr, false, 16) + self.out_substr(">");
|
||||
}
|
||||
fn usz? Formatter.out_collection(&self, any arg, String open, String close) @private
|
||||
{
|
||||
typeid inner = arg.type.inner;
|
||||
if (inner == void.typeid) inner = char.typeid;
|
||||
usz size = inner.sizeof;
|
||||
|
||||
usz alen;
|
||||
void* data_ptr;
|
||||
if (arg.type.kindof == SLICE)
|
||||
{
|
||||
String* temp = arg.ptr;
|
||||
data_ptr = temp.ptr;
|
||||
alen = temp.len;
|
||||
}
|
||||
else
|
||||
{
|
||||
data_ptr = arg.ptr;
|
||||
alen = arg.type.len;
|
||||
}
|
||||
|
||||
PrintFlags flags = self.flags;
|
||||
uint width = self.width;
|
||||
defer
|
||||
{
|
||||
self.flags = flags;
|
||||
self.width = width;
|
||||
}
|
||||
self.flags = {};
|
||||
self.width = 0;
|
||||
|
||||
usz len = self.out_substr(open)!;
|
||||
for (usz i = 0; i < alen; i++)
|
||||
{
|
||||
if (i != 0) len += self.out_substr(", ")!;
|
||||
len += self.out_str(any_make(data_ptr, inner))!;
|
||||
data_ptr += size;
|
||||
}
|
||||
len += self.out_substr(close)!;
|
||||
return len;
|
||||
}
|
||||
|
||||
fn usz? Formatter.out_str(&self, any arg) @private
|
||||
{
|
||||
switch (arg.type.kindof)
|
||||
{
|
||||
case VOID:
|
||||
return self.out_substr("void");
|
||||
case FAULT:
|
||||
fault f = *(fault*)arg.ptr;
|
||||
return self.out_substr(f ? f.nameof : "(empty-fault)");
|
||||
case INTERFACE:
|
||||
any a = *(any*)arg;
|
||||
return a ? self.out_str(a) : self.out_substr("(empty-interface)");
|
||||
case ANY:
|
||||
any a = *(any*)arg;
|
||||
return a ? self.out_str(a) : self.out_substr("(empty-any)");
|
||||
case OPTIONAL:
|
||||
unreachable();
|
||||
case SIGNED_INT:
|
||||
case UNSIGNED_INT:
|
||||
case FLOAT:
|
||||
case FUNC:
|
||||
case POINTER:
|
||||
PrintFlags flags = self.flags;
|
||||
uint width = self.width;
|
||||
defer
|
||||
{
|
||||
self.flags = flags;
|
||||
self.width = width;
|
||||
}
|
||||
self.flags = {};
|
||||
self.width = 0;
|
||||
switch (arg.type.kindof)
|
||||
{
|
||||
case SIGNED_INT:
|
||||
case UNSIGNED_INT:
|
||||
return self.ntoa_any(arg, 10) ?? self.out_substr("<INVALID>");
|
||||
case FLOAT:
|
||||
return self.ftoa(float_from_any(arg)) ?? self.out_substr("ERR");
|
||||
case FUNC:
|
||||
case POINTER:
|
||||
if (arg.type.kindof == POINTER && arg.type.inner != void.typeid)
|
||||
{
|
||||
void** pointer = arg.ptr;
|
||||
any deref = any_make(*pointer, arg.type.inner);
|
||||
usz? n = self.print_with_function((Printable)deref);
|
||||
if (try n) return n;
|
||||
if (@catch(n) != NOT_FOUND) n!;
|
||||
}
|
||||
return self.out_substr("0x")! + self.ntoa_any(arg, 16);
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
case BOOL:
|
||||
return self.out_substr(*(bool*)arg.ptr ? "true" : "false");
|
||||
default:
|
||||
}
|
||||
usz? n = self.print_with_function((Printable)arg);
|
||||
if (try n) return n;
|
||||
if (@catch(n) != NOT_FOUND) n!;
|
||||
switch (arg.type.kindof)
|
||||
{
|
||||
case TYPEID:
|
||||
return self.out_substr("typeid[")! + self.ntoa((iptr)*(typeid*)arg, false, 16)! + self.out_substr("]")!;
|
||||
case ENUM:
|
||||
usz i = types::any_to_enum_ordinal(arg, usz)!!;
|
||||
assert(i < arg.type.names.len, "Illegal enum value found, numerical value was %d.", i);
|
||||
return self.out_substr(arg.type.names[i]);
|
||||
case STRUCT:
|
||||
return self.out_unknown("struct", arg);
|
||||
case UNION:
|
||||
return self.out_unknown("union", arg);
|
||||
case BITSTRUCT:
|
||||
return self.out_unknown("bitstruct", arg);
|
||||
case CONST_ENUM:
|
||||
case DISTINCT:
|
||||
if (arg.type == String.typeid)
|
||||
{
|
||||
return self.out_substr(*(String*)arg);
|
||||
}
|
||||
if (arg.type == ZString.typeid)
|
||||
{
|
||||
return self.out_substr(*(ZString*)arg ? ((ZString*)arg).str_view() : "(null)");
|
||||
}
|
||||
if (arg.type == DString.typeid)
|
||||
{
|
||||
return self.out_substr(*(DString*)arg ? ((DString*)arg).str_view() : "(null)");
|
||||
}
|
||||
return self.out_str(arg.as_inner());
|
||||
case ARRAY:
|
||||
return self.out_collection(arg, "[", "]");
|
||||
case VECTOR:
|
||||
return self.out_collection(arg, "[<", ">]");
|
||||
case SLICE:
|
||||
return self.out_collection(arg, "[", "]");
|
||||
case ANY:
|
||||
case INTERFACE:
|
||||
unreachable("Already handled");
|
||||
default:
|
||||
}
|
||||
return self.out_substr("Invalid type");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fn void? out_null_fn(void* data @unused, char c @unused) @private
|
||||
{
|
||||
@@ -291,7 +133,7 @@ fn void? out_null_fn(void* data @unused, char c @unused) @private
|
||||
|
||||
macro usz? @report_fault(Formatter* f, $fault)
|
||||
{
|
||||
(void)f.out_substr($fault);
|
||||
(void)formatter_out_substr(f, $fault);
|
||||
return INVALID_FORMAT~;
|
||||
}
|
||||
|
||||
@@ -307,69 +149,14 @@ macro usz? @wrap_bad(Formatter* f, #action)
|
||||
return f.first_err(err)~;
|
||||
default:
|
||||
err = f.first_err(INVALID_ARGUMENT);
|
||||
f.out_substr("<INVALID>")!;
|
||||
formatter_out_substr(f, "<INVALID>")!;
|
||||
return err~;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
fn usz? Formatter.out_hex_buffer(&self, any arg) @private @inline
|
||||
{
|
||||
char[] out @noinit;
|
||||
switch (arg.type)
|
||||
{
|
||||
case char[]:
|
||||
case ichar[]:
|
||||
out = *(char[]*)arg;
|
||||
default:
|
||||
if (arg.type.kindof == ARRAY && (arg.type.inner == char.typeid || arg.type.inner == ichar.typeid))
|
||||
{
|
||||
out = ((char*)arg.ptr)[:arg.type.sizeof];
|
||||
break;
|
||||
}
|
||||
if (arg.type.kindof == POINTER)
|
||||
{
|
||||
// Maybe there is a more idiomatic way here
|
||||
out = ((*(char**)arg.ptr))[:arg.type.inner.sizeof];
|
||||
break;
|
||||
}
|
||||
return self.out_substr("<INVALID>");
|
||||
}
|
||||
usz len = out.len * 2;
|
||||
usz total;
|
||||
if (self.flags.left)
|
||||
{
|
||||
total += print_hex_chars(self, out, self.flags.uppercase)!;
|
||||
total += self.pad(' ', self.width, (isz)total)!;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self.width) total += self.pad(' ', self.width, (isz)len)!;
|
||||
total += print_hex_chars(self, out, self.flags.uppercase)!;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
fn usz? Formatter.out_str_pad(&self, any arg) @private @inline
|
||||
{
|
||||
usz total;
|
||||
if (self.width && !self.flags.left)
|
||||
{
|
||||
OutputFn out_fn = self.out_fn;
|
||||
self.out_fn = (OutputFn)&out_null_fn;
|
||||
usz len = self.out_str(arg)!;
|
||||
self.out_fn = out_fn;
|
||||
total += self.pad(' ', self.width, (isz)len)!;
|
||||
}
|
||||
usz len = self.out_str(arg)!;
|
||||
total += len;
|
||||
if (self.flags.left)
|
||||
{
|
||||
total += self.pad(' ', self.width, (isz)len)!;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
fn usz? Formatter.vprintf(&self, String format, any[] anys)
|
||||
{
|
||||
@@ -389,7 +176,7 @@ fn usz? Formatter.vprintf(&self, String format, any[] anys)
|
||||
if (c != '%')
|
||||
{
|
||||
// no
|
||||
total_len += self.out(c)!;
|
||||
total_len += self.print_char(c)!;
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
@@ -397,7 +184,7 @@ fn usz? Formatter.vprintf(&self, String format, any[] anys)
|
||||
c = format[i];
|
||||
if (c == '%')
|
||||
{
|
||||
total_len += self.out(c)!;
|
||||
total_len += self.print_char(c)!;
|
||||
continue;
|
||||
}
|
||||
// evaluate flags
|
||||
@@ -443,7 +230,7 @@ fn usz? Formatter.vprintf(&self, String format, any[] anys)
|
||||
if (variant_index >= anys.len)
|
||||
{
|
||||
self.first_err(NOT_ENOUGH_ARGUMENTS);
|
||||
total_len += self.out_substr("<MISSING>")!;
|
||||
total_len += formatter_out_substr(self, "<MISSING>")!;
|
||||
continue;
|
||||
}
|
||||
any current = anys[variant_index++];
|
||||
@@ -471,37 +258,37 @@ fn usz? Formatter.vprintf(&self, String format, any[] anys)
|
||||
self.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'a':
|
||||
total_len += @wrap_bad(self, self.atoa(float_from_any(current)))!;
|
||||
total_len += @wrap_bad(self, formatter_atoa(self, float_from_any(current)))!;
|
||||
continue;
|
||||
case 'F' :
|
||||
self.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'f':
|
||||
total_len += @wrap_bad(self, self.ftoa(float_from_any(current)))!;
|
||||
total_len += @wrap_bad(self, formatter_ftoa(self, float_from_any(current)))!;
|
||||
continue;
|
||||
case 'E':
|
||||
self.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'e':
|
||||
total_len += @wrap_bad(self, self.etoa(float_from_any(current)))!;
|
||||
total_len += @wrap_bad(self, formatter_etoa(self, float_from_any(current)))!;
|
||||
continue;
|
||||
case 'G':
|
||||
self.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'g':
|
||||
total_len += @wrap_bad(self, self.gtoa(float_from_any(current)))!;
|
||||
total_len += @wrap_bad(self, formatter_gtoa(self, float_from_any(current)))!;
|
||||
continue;
|
||||
case 'c':
|
||||
total_len += self.out_char(current)!;
|
||||
total_len += formatter_out_char(self, current)!;
|
||||
continue;
|
||||
case 'H':
|
||||
self.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'h':
|
||||
total_len += self.out_hex_buffer(current)!;
|
||||
total_len += formatter_out_hex_buffer(self, current)!;
|
||||
continue;
|
||||
case 's':
|
||||
total_len += self.out_str_pad(current)!;
|
||||
total_len += formatter_out_str_pad(self, current)!;
|
||||
continue;
|
||||
case 'p':
|
||||
self.flags.zeropad = true;
|
||||
@@ -509,7 +296,7 @@ fn usz? Formatter.vprintf(&self, String format, any[] anys)
|
||||
base = 16;
|
||||
default:
|
||||
self.first_err(INVALID_FORMAT);
|
||||
total_len += self.out_substr("<BAD FORMAT>")!;
|
||||
total_len += formatter_out_substr(self, "<BAD FORMAT>")!;
|
||||
continue;
|
||||
}
|
||||
if (base != 10)
|
||||
@@ -521,13 +308,25 @@ fn usz? Formatter.vprintf(&self, String format, any[] anys)
|
||||
if (self.flags.precision) self.flags.zeropad = false;
|
||||
|
||||
bool is_neg;
|
||||
total_len += @wrap_bad(self, self.ntoa(int_from_any(current, &is_neg), is_neg, base))!;
|
||||
total_len += @wrap_bad(self, formatter_ntoa(self, int_from_any(current, &is_neg), is_neg, base))!;
|
||||
}
|
||||
|
||||
if (self.first_fault) return self.first_fault~;
|
||||
return total_len;
|
||||
}
|
||||
|
||||
fn usz? Formatter.out(&self, char c) @deprecated("Use print_char") => self.print_char(c);
|
||||
|
||||
fn usz? Formatter.print_char(&self, char c)
|
||||
{
|
||||
if (catch err = self.out_fn(self.data, c))
|
||||
{
|
||||
if (self.first_fault) return self.first_fault~;
|
||||
self.first_fault = err;
|
||||
return err~;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
fn usz? Formatter.print(&self, String str)
|
||||
{
|
||||
@@ -536,6 +335,6 @@ fn usz? Formatter.print(&self, String str)
|
||||
// use null output function
|
||||
self.out_fn = &out_null_fn;
|
||||
}
|
||||
foreach (c : str) self.out(c)!;
|
||||
foreach (c : str) self.print_char(c)!;
|
||||
return str.len;
|
||||
}
|
||||
|
||||
@@ -13,10 +13,10 @@ fn usz? print_hex_chars(Formatter* f, char[] out, bool uppercase) @inline
|
||||
foreach (c : out)
|
||||
{
|
||||
char digit = c >> 4;
|
||||
f.out(digit + (digit < 10 ? '0' : past_10))!;
|
||||
f.print_char(digit + (digit < 10 ? '0' : past_10))!;
|
||||
len++;
|
||||
digit = c & 0xf;
|
||||
f.out(digit + (digit < 10 ? '0' : past_10))!;
|
||||
f.print_char(digit + (digit < 10 ? '0' : past_10))!;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
@@ -29,10 +29,10 @@ macro fault Formatter.first_err(&self, fault f)
|
||||
return f;
|
||||
}
|
||||
|
||||
fn usz? Formatter.adjust(&self, usz len) @local
|
||||
fn usz? formatter_adjust(Formatter* f, usz len) @local
|
||||
{
|
||||
if (!self.flags.left) return 0;
|
||||
return self.pad(' ', self.width, len);
|
||||
if (!f.flags.left) return 0;
|
||||
return formatter_pad(f, ' ', f.width, len);
|
||||
}
|
||||
|
||||
fn uint128? int_from_any(any arg, bool *is_neg) @private
|
||||
@@ -43,8 +43,8 @@ fn uint128? int_from_any(any arg, bool *is_neg) @private
|
||||
case POINTER:
|
||||
*is_neg = false;
|
||||
return (uint128)(uptr)*(void**)arg.ptr;
|
||||
case DISTINCT:
|
||||
case CONST_ENUM:
|
||||
case TYPEDEF:
|
||||
case CONSTDEF:
|
||||
return int_from_any(arg.as_inner(), is_neg);
|
||||
default:
|
||||
break;
|
||||
@@ -95,7 +95,7 @@ fn FloatType? float_from_any(any arg) @private
|
||||
$if env::F128_SUPPORT:
|
||||
if (arg.type == float128.typeid) return (FloatType)*((float128*)arg.ptr);
|
||||
$endif
|
||||
if (arg.type.kindof == DISTINCT || arg.type.kindof == CONST_ENUM)
|
||||
if (arg.type.kindof == TYPEDEF || arg.type.kindof == CONSTDEF)
|
||||
{
|
||||
return float_from_any(arg.as_inner());
|
||||
}
|
||||
@@ -156,11 +156,11 @@ fn uint simple_atoi(char* buf, usz maxlen, usz* len_ptr) @inline @private
|
||||
return i;
|
||||
}
|
||||
|
||||
fn usz? Formatter.out_substr(&self, String str) @private
|
||||
fn usz? formatter_out_substr(Formatter* f, String str) @private
|
||||
{
|
||||
usz l = conv::utf8_codepoints(str);
|
||||
uint prec = self.prec;
|
||||
if (self.flags.precision && l < prec) l = prec;
|
||||
uint prec = f.prec;
|
||||
if (f.flags.precision && l < prec) l = prec;
|
||||
usz index = 0;
|
||||
usz chars = str.len;
|
||||
char* ptr = str.ptr;
|
||||
@@ -168,17 +168,17 @@ fn usz? Formatter.out_substr(&self, String str) @private
|
||||
{
|
||||
char c = ptr[index];
|
||||
// Break if we have precision set and we ran out...
|
||||
if (c & 0xC0 != 0x80 && self.flags.precision && !prec--) break;
|
||||
self.out(c)!;
|
||||
if (c & 0xC0 != 0x80 && f.flags.precision && !prec--) break;
|
||||
f.print_char(c)!;
|
||||
index++;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
fn usz? Formatter.pad(&self, char c, isz width, isz len) @inline
|
||||
fn usz? formatter_pad(Formatter* f, char c, isz width, isz len) @inline
|
||||
{
|
||||
isz delta = width - len;
|
||||
for (isz i = 0; i < delta; i++) self.out(c)!;
|
||||
for (isz i = 0; i < delta; i++) f.print_char(c)!;
|
||||
return max(0, delta);
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ fn char* fmt_u(uint128 x, char* s)
|
||||
|
||||
fn usz? Formatter.out_chars(&self, char[] s)
|
||||
{
|
||||
foreach (c : s) self.out(c)!;
|
||||
foreach (c : s) self.print_char(c)!;
|
||||
return s.len;
|
||||
}
|
||||
|
||||
@@ -203,12 +203,12 @@ enum FloatFormatting
|
||||
HEX
|
||||
}
|
||||
|
||||
fn usz? Formatter.etoa(&self, double y) => self.floatformat(EXPONENTIAL, y);
|
||||
fn usz? Formatter.ftoa(&self, double y) => self.floatformat(FLOAT, y);
|
||||
fn usz? Formatter.gtoa(&self, double y) => self.floatformat(ADAPTIVE, y);
|
||||
fn usz? Formatter.atoa(&self, double y) => self.floatformat(HEX, y);
|
||||
fn usz? formatter_etoa(Formatter* self, double y) => formatter_floatformat(self, EXPONENTIAL, y);
|
||||
fn usz? formatter_ftoa(Formatter* self, double y) => formatter_floatformat(self, FLOAT, y);
|
||||
fn usz? formatter_gtoa(Formatter* self, double y) => formatter_floatformat(self, ADAPTIVE, y);
|
||||
fn usz? formatter_atoa(Formatter* self, double y) => formatter_floatformat(self, HEX, y);
|
||||
|
||||
fn usz? Formatter.floatformat_hex(&self, double y, bool is_neg, isz pl, isz p) @private @inline
|
||||
fn usz? formatter_floatformat_hex(Formatter* self, double y, bool is_neg, isz pl, isz p) @private @inline
|
||||
{
|
||||
double round = 8.0;
|
||||
// 0x / 0X
|
||||
@@ -261,18 +261,18 @@ fn usz? Formatter.floatformat_hex(&self, double y, bool is_neg, isz pl, isz p) @
|
||||
usz l = (usz)(p && outlen - 2 < p
|
||||
? p + 2 + explen
|
||||
: outlen + explen);
|
||||
if (!self.flags.left && !self.flags.zeropad) len += self.pad(' ', self.width, pl + l)!;
|
||||
if (is_neg || self.flags.plus) len += self.out(is_neg ? '-' : '+')!;
|
||||
if (!self.flags.left && !self.flags.zeropad) len += formatter_pad(self, ' ', self.width, pl + l)!;
|
||||
if (is_neg || self.flags.plus) len += self.print_char(is_neg ? '-' : '+')!;
|
||||
len += self.out_chars(self.flags.uppercase ? "0X" : "0x")!;
|
||||
if (self.flags.zeropad) len += self.pad('0', self.width, pl + l)!;
|
||||
if (self.flags.zeropad) len += formatter_pad(self, '0', self.width, pl + l)!;
|
||||
len += self.out_chars(buf[:outlen])!;
|
||||
len += self.pad('0', (isz)l - outlen - explen, 0)!;
|
||||
len += formatter_pad(self, '0', (isz)l - outlen - explen, 0)!;
|
||||
len += self.out_chars(estr[:explen])!;
|
||||
if (self.flags.left) len += self.pad(' ', self.width, pl + (isz)l)!;
|
||||
if (self.flags.left) len += formatter_pad(self, ' ', self.width, pl + (isz)l)!;
|
||||
return len;
|
||||
}
|
||||
|
||||
fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @private
|
||||
fn usz? formatter_floatformat(Formatter* self, FloatFormatting formatting, double y) @private
|
||||
{
|
||||
// This code is heavily based on musl's printf code
|
||||
const BUF_SIZE = (math::DOUBLE_MANT_DIG + 28) / 29 + 1
|
||||
@@ -290,17 +290,17 @@ fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
|
||||
{
|
||||
usz len;
|
||||
// Add padding
|
||||
if (!self.flags.left) len += self.pad(' ', self.width, 3 + pl)!;
|
||||
if (!self.flags.left) len += formatter_pad(self, ' ', self.width, 3 + pl)!;
|
||||
String s = self.flags.uppercase ? "INF" : "inf";
|
||||
if (math::is_nan(y)) s = self.flags.uppercase ? "NAN" : "nan";
|
||||
if (pl) len += self.out(is_neg ? '-' : '+')!;
|
||||
if (pl) len += self.print_char(is_neg ? '-' : '+')!;
|
||||
len += self.out_chars(s)!;
|
||||
if (self.flags.left) len += self.pad(' ', self.width, 3 + pl)!;
|
||||
if (self.flags.left) len += formatter_pad(self, ' ', self.width, 3 + pl)!;
|
||||
return len;
|
||||
}
|
||||
|
||||
isz p = self.flags.precision ? self.prec : -1;
|
||||
if (formatting == HEX) return self.floatformat_hex(y, is_neg, pl, p);
|
||||
if (formatting == HEX) return formatter_floatformat_hex(self, y, is_neg, pl, p);
|
||||
|
||||
// Rescale
|
||||
int e2;
|
||||
@@ -483,9 +483,9 @@ fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
|
||||
}
|
||||
if (l > int.max - pl) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
usz len;
|
||||
if (!self.flags.left && !self.flags.zeropad) len += self.pad(' ', self.width, pl + l)!;
|
||||
if (is_neg || self.flags.plus) len += self.out(is_neg ? '-' : '+')!;
|
||||
if (self.flags.zeropad) len += self.pad('0', self.width, pl + l)!;
|
||||
if (!self.flags.left && !self.flags.zeropad) len += formatter_pad(self, ' ', self.width, pl + l)!;
|
||||
if (is_neg || self.flags.plus) len += self.print_char(is_neg ? '-' : '+')!;
|
||||
if (self.flags.zeropad) len += formatter_pad(self, '0', self.width, pl + l)!;
|
||||
|
||||
char[9] buf_array;
|
||||
char* buf = &buf_array[0];
|
||||
@@ -506,14 +506,14 @@ fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
|
||||
}
|
||||
len += self.out_chars(s[:buf + 9 - s])!;
|
||||
}
|
||||
if (p || self.flags.hash) len += self.out('.')!;
|
||||
if (p || self.flags.hash) len += self.print_char('.')!;
|
||||
for (; d < z && p > 0; d++, p -= 9)
|
||||
{
|
||||
char* s = fmt_u(*d, buf + 9);
|
||||
while (s > buf) *--s = '0';
|
||||
len += self.out_chars(s[:math::min((isz)9, p)])!;
|
||||
}
|
||||
len += self.pad('0', p + 9, 9)!;
|
||||
len += formatter_pad(self, '0', p + 9, 9)!;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -528,21 +528,42 @@ fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
|
||||
}
|
||||
else
|
||||
{
|
||||
len += self.out(s++[0])!;
|
||||
if (p > 0 || self.flags.hash) len += self.out('.')!;
|
||||
len += self.print_char(s++[0])!;
|
||||
if (p > 0 || self.flags.hash) len += self.print_char('.')!;
|
||||
}
|
||||
len += self.out_chars(s[:math::min(buf + 9 - s, p)])!;
|
||||
p -= buf + 9 - s;
|
||||
}
|
||||
len += self.pad('0', p + 18, 18)!;
|
||||
len += formatter_pad(self, '0', p + 18, 18)!;
|
||||
len += self.out_chars(estr[:ebuf - estr])!;
|
||||
}
|
||||
|
||||
if (self.flags.left) len += self.pad(' ', self.width, pl + l)!;
|
||||
if (self.flags.left) len += formatter_pad(self, ' ', self.width, pl + l)!;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
fn usz? formatter_out_str_pad(Formatter* self, any arg) @private @inline
|
||||
{
|
||||
usz total;
|
||||
if (self.width && !self.flags.left)
|
||||
{
|
||||
OutputFn out_fn = self.out_fn;
|
||||
self.out_fn = (OutputFn)&out_null_fn;
|
||||
usz len = formatter_out_str(self, arg)!;
|
||||
self.out_fn = out_fn;
|
||||
total += formatter_pad(self, ' ', self.width, (isz)len)!;
|
||||
}
|
||||
usz len = formatter_out_str(self, arg)!;
|
||||
total += len;
|
||||
if (self.flags.left)
|
||||
{
|
||||
total += formatter_pad(self, ' ', self.width, (isz)len)!;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
const char[201] DIGIT_PAIRS @private =
|
||||
"00102030405060708090"
|
||||
"01112131415161718191"
|
||||
@@ -555,18 +576,18 @@ const char[201] DIGIT_PAIRS @private =
|
||||
"08182838485868788898"
|
||||
"09192939495969798999";
|
||||
|
||||
fn usz? Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
|
||||
fn usz? formatter_ntoa(Formatter* f, uint128 value, bool negative, uint base) @private
|
||||
{
|
||||
char[PRINTF_NTOA_BUFFER_SIZE] buf @noinit;
|
||||
usz len;
|
||||
|
||||
// no hash for 0 values
|
||||
if (!value) self.flags.hash = false;
|
||||
if (!value) f.flags.hash = false;
|
||||
|
||||
// write if precision != 0 or value is != 0
|
||||
if (!self.flags.precision || value)
|
||||
if (!f.flags.precision || value)
|
||||
{
|
||||
char past_10 = (self.flags.uppercase ? 'A' : 'a') - 10;
|
||||
char past_10 = (f.flags.uppercase ? 'A' : 'a') - 10;
|
||||
switch (base)
|
||||
{
|
||||
case 2:
|
||||
@@ -612,27 +633,26 @@ fn usz? Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
|
||||
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = '0' + (char)value & 0x7;
|
||||
value >>= 3;
|
||||
}
|
||||
while (value);
|
||||
} while (value);
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
return self.ntoa_format((String)buf[:PRINTF_NTOA_BUFFER_SIZE], len, negative, base);
|
||||
return formatter_ntoa_format(f, (String)buf[:PRINTF_NTOA_BUFFER_SIZE], len, negative, base);
|
||||
}
|
||||
|
||||
fn usz? Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint base) @private
|
||||
fn usz? formatter_ntoa_format(Formatter* f, String buf, usz len, bool negative, uint base) @private
|
||||
{
|
||||
// pad leading zeros
|
||||
if (!self.flags.left)
|
||||
if (!f.flags.left)
|
||||
{
|
||||
if (self.width && self.flags.zeropad && (negative || self.flags.plus || self.flags.space)) self.width--;
|
||||
while (len < self.prec)
|
||||
if (f.width && f.flags.zeropad && (negative || f.flags.plus || f.flags.space)) f.width--;
|
||||
while (len < f.prec)
|
||||
{
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = '0';
|
||||
}
|
||||
while (self.flags.zeropad && len < self.width)
|
||||
while (f.flags.zeropad && len < f.width)
|
||||
{
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = '0';
|
||||
@@ -640,9 +660,9 @@ fn usz? Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
|
||||
}
|
||||
|
||||
// handle hash
|
||||
if (self.flags.hash && base != 10)
|
||||
if (f.flags.hash && base != 10)
|
||||
{
|
||||
if (!self.flags.precision && len && len == self.prec && len == self.width)
|
||||
if (!f.flags.precision && len && len == f.prec && len == f.width)
|
||||
{
|
||||
len--;
|
||||
if (len) len--;
|
||||
@@ -653,11 +673,11 @@ fn usz? Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
|
||||
switch (base)
|
||||
{
|
||||
case 16:
|
||||
buf[len++] = self.flags.uppercase ? 'X' : 'x';
|
||||
buf[len++] = f.flags.uppercase ? 'X' : 'x';
|
||||
case 8:
|
||||
buf[len++] = self.flags.uppercase ? 'O' : 'o';
|
||||
buf[len++] = f.flags.uppercase ? 'O' : 'o';
|
||||
case 2:
|
||||
buf[len++] = self.flags.uppercase ? 'B' : 'b';
|
||||
buf[len++] = f.flags.uppercase ? 'B' : 'b';
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
@@ -670,35 +690,35 @@ fn usz? Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
|
||||
case negative:
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = '-';
|
||||
case self.flags.plus:
|
||||
case f.flags.plus:
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = '+';
|
||||
case self.flags.space:
|
||||
case f.flags.space:
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
if (len) self.out_reverse(buf[:len])!;
|
||||
if (len) formatter_out_reverse(f, buf[:len])!;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
fn usz? Formatter.ntoa_any(&self, any arg, uint base) @private
|
||||
fn usz? formatter_ntoa_any(Formatter* f, any arg, uint base) @private
|
||||
{
|
||||
bool is_neg;
|
||||
return self.ntoa(int_from_any(arg, &is_neg)!!, is_neg, base) @inline;
|
||||
return formatter_ntoa(f, int_from_any(arg, &is_neg)!!, is_neg, base) @inline;
|
||||
}
|
||||
|
||||
fn usz? Formatter.out_char(&self, any arg) @private
|
||||
fn usz? formatter_out_char(Formatter* f, any arg) @private
|
||||
{
|
||||
if (!arg.type.kindof.is_int())
|
||||
{
|
||||
return self.out_substr("<NOT CHAR>");
|
||||
return formatter_out_substr(f, "<NOT CHAR>");
|
||||
}
|
||||
usz len = 1;
|
||||
// pre padding
|
||||
if (!self.flags.left)
|
||||
if (!f.flags.left)
|
||||
{
|
||||
len += self.pad(' ', self.width, len)!;
|
||||
len += formatter_pad(f, ' ', f.width, len)!;
|
||||
}
|
||||
|
||||
// char output
|
||||
@@ -706,42 +726,42 @@ fn usz? Formatter.out_char(&self, any arg) @private
|
||||
switch (true)
|
||||
{
|
||||
case c < 0x7f:
|
||||
self.out((char)c)!;
|
||||
f.print_char((char)c)!;
|
||||
case c < 0x7ff:
|
||||
self.out((char)(0xC0 | c >> 6))!;
|
||||
self.out((char)(0x80 | (c & 0x3F)))!;
|
||||
f.print_char((char)(0xC0 | c >> 6))!;
|
||||
f.print_char((char)(0x80 | (c & 0x3F)))!;
|
||||
case c < 0xffff:
|
||||
self.out((char)(0xE0 | c >> 12))!;
|
||||
self.out((char)(0x80 | (c >> 6 & 0x3F)))!;
|
||||
self.out((char)(0x80 | (c & 0x3F)))!;
|
||||
f.print_char((char)(0xE0 | c >> 12))!;
|
||||
f.print_char((char)(0x80 | (c >> 6 & 0x3F)))!;
|
||||
f.print_char((char)(0x80 | (c & 0x3F)))!;
|
||||
default:
|
||||
self.out((char)(0xF0 | c >> 18))!;
|
||||
self.out((char)(0x80 | (c >> 12 & 0x3F)))!;
|
||||
self.out((char)(0x80 | (c >> 6 & 0x3F)))!;
|
||||
self.out((char)(0x80 | (c & 0x3F)))!;
|
||||
f.print_char((char)(0xF0 | c >> 18))!;
|
||||
f.print_char((char)(0x80 | (c >> 12 & 0x3F)))!;
|
||||
f.print_char((char)(0x80 | (c >> 6 & 0x3F)))!;
|
||||
f.print_char((char)(0x80 | (c & 0x3F)))!;
|
||||
}
|
||||
if (self.flags.left)
|
||||
if (f.flags.left)
|
||||
{
|
||||
len += self.pad(' ', self.width, len)!;
|
||||
len += formatter_pad(f, ' ', f.width, len)!;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
fn usz? Formatter.out_reverse(&self, char[] buf) @private
|
||||
fn usz? formatter_out_reverse(Formatter* f, char[] buf) @private
|
||||
{
|
||||
usz n;
|
||||
usz len = buf.len;
|
||||
// pad spaces up to given width
|
||||
if (!self.flags.zeropad && !self.flags.left)
|
||||
if (!f.flags.zeropad && !f.flags.left)
|
||||
{
|
||||
n += self.pad(' ', self.width, len)!;
|
||||
n += formatter_pad(f, ' ', f.width, len)!;
|
||||
}
|
||||
// reverse string
|
||||
while (len) n += self.out(buf[--len])!;
|
||||
while (len) n += f.print_char(buf[--len])!;
|
||||
|
||||
// append pad spaces up to given width
|
||||
n += self.adjust(n)!;
|
||||
n += formatter_adjust(f, n)!;
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -761,3 +781,197 @@ fn int? printf_parse_format_field(
|
||||
uint? intval = types::any_to_int(val, int);
|
||||
return intval ?? BAD_FORMAT~;
|
||||
}
|
||||
|
||||
fn usz? formatter_out_hex_buffer(Formatter* self, any arg) @private @inline
|
||||
{
|
||||
char[] out @noinit;
|
||||
switch (arg.type)
|
||||
{
|
||||
case char[]:
|
||||
case ichar[]:
|
||||
out = *(char[]*)arg;
|
||||
default:
|
||||
if (arg.type.kindof == ARRAY && (arg.type.inner == char.typeid || arg.type.inner == ichar.typeid))
|
||||
{
|
||||
out = ((char*)arg.ptr)[:arg.type.sizeof];
|
||||
break;
|
||||
}
|
||||
if (arg.type.kindof == POINTER)
|
||||
{
|
||||
// Maybe there is a more idiomatic way here
|
||||
out = ((*(char**)arg.ptr))[:arg.type.inner.sizeof];
|
||||
break;
|
||||
}
|
||||
return formatter_out_substr(self, "<INVALID>");
|
||||
}
|
||||
usz len = out.len * 2;
|
||||
usz total;
|
||||
if (self.flags.left)
|
||||
{
|
||||
total += print_hex_chars(self, out, self.flags.uppercase)!;
|
||||
total += formatter_pad(self, ' ', self.width, (isz)total)!;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self.width) total += formatter_pad(self, ' ', self.width, (isz)len)!;
|
||||
total += print_hex_chars(self, out, self.flags.uppercase)!;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
fn usz? formatter_out_unknown(Formatter* self, String category, any arg) @private
|
||||
{
|
||||
return formatter_out_substr(self, "<")
|
||||
+ formatter_out_substr(self, category)
|
||||
+ formatter_out_substr(self, " type:")
|
||||
+ formatter_ntoa(self, (iptr)arg.type, false, 16)
|
||||
+ formatter_out_substr(self, ", addr:")
|
||||
+ formatter_ntoa(self, (iptr)arg.ptr, false, 16)
|
||||
+ formatter_out_substr(self, ">");
|
||||
}
|
||||
|
||||
fn usz? formatter_out_collection(Formatter* self, any arg, String open, String close) @private
|
||||
{
|
||||
typeid inner = arg.type.inner;
|
||||
if (inner == void.typeid) inner = char.typeid;
|
||||
usz size = inner.sizeof;
|
||||
|
||||
usz alen;
|
||||
void* data_ptr;
|
||||
if (arg.type.kindof == SLICE)
|
||||
{
|
||||
String* temp = arg.ptr;
|
||||
data_ptr = temp.ptr;
|
||||
alen = temp.len;
|
||||
}
|
||||
else
|
||||
{
|
||||
data_ptr = arg.ptr;
|
||||
alen = arg.type.len;
|
||||
}
|
||||
|
||||
PrintFlags flags = self.flags;
|
||||
uint width = self.width;
|
||||
defer
|
||||
{
|
||||
self.flags = flags;
|
||||
self.width = width;
|
||||
}
|
||||
self.flags = {};
|
||||
self.width = 0;
|
||||
|
||||
usz len = formatter_out_substr(self, open)!;
|
||||
for (usz i = 0; i < alen; i++)
|
||||
{
|
||||
if (i != 0) len += formatter_out_substr(self, ", ")!;
|
||||
len += formatter_out_str(self, any_make(data_ptr, inner))!;
|
||||
data_ptr += size;
|
||||
}
|
||||
len += formatter_out_substr(self, close)!;
|
||||
return len;
|
||||
}
|
||||
|
||||
fn usz? formatter_out_str(Formatter* self, any arg) @private
|
||||
{
|
||||
switch (arg.type.kindof)
|
||||
{
|
||||
case VOID:
|
||||
return formatter_out_substr(self, "void");
|
||||
case FAULT:
|
||||
fault f = *(fault*)arg.ptr;
|
||||
return formatter_out_substr(self, f ? f.nameof : "(empty-fault)");
|
||||
case INTERFACE:
|
||||
any a = *(any*)arg;
|
||||
return a ? formatter_out_str(self, a) : formatter_out_substr(self, "(empty-interface)");
|
||||
case ANY:
|
||||
any a = *(any*)arg;
|
||||
return a ? formatter_out_str(self, a) : formatter_out_substr(self, "(empty-any)");
|
||||
case OPTIONAL:
|
||||
unreachable();
|
||||
case SIGNED_INT:
|
||||
case UNSIGNED_INT:
|
||||
case FLOAT:
|
||||
case FUNC:
|
||||
case POINTER:
|
||||
PrintFlags flags = self.flags;
|
||||
uint width = self.width;
|
||||
defer
|
||||
{
|
||||
self.flags = flags;
|
||||
self.width = width;
|
||||
}
|
||||
self.flags = {};
|
||||
self.width = 0;
|
||||
switch (arg.type.kindof)
|
||||
{
|
||||
case SIGNED_INT:
|
||||
case UNSIGNED_INT:
|
||||
return formatter_ntoa_any(self, arg, 10) ?? formatter_out_substr(self, "<INVALID>");
|
||||
case FLOAT:
|
||||
return formatter_ftoa(self, float_from_any(arg)) ?? formatter_out_substr(self, "ERR");
|
||||
case FUNC:
|
||||
case POINTER:
|
||||
if (arg.type.kindof == POINTER && arg.type.inner != void.typeid)
|
||||
{
|
||||
void** pointer = arg.ptr;
|
||||
any deref = any_make(*pointer, arg.type.inner);
|
||||
usz? n = self.print_with_function((Printable)deref);
|
||||
if (try n) return n;
|
||||
if (@catch(n) != NOT_FOUND) n!;
|
||||
}
|
||||
return formatter_out_substr(self, "0x")! + formatter_ntoa_any(self, arg, 16);
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
case BOOL:
|
||||
return formatter_out_substr(self, *(bool*)arg.ptr ? "true" : "false");
|
||||
default:
|
||||
}
|
||||
usz? n = self.print_with_function((Printable)arg);
|
||||
if (try n) return n;
|
||||
if (@catch(n) != NOT_FOUND) n!;
|
||||
switch (arg.type.kindof)
|
||||
{
|
||||
case TYPEID:
|
||||
return formatter_out_substr(self, "typeid[")! + formatter_ntoa(self, (iptr)*(typeid*)arg, false, 16)! + formatter_out_substr(self, "]")!;
|
||||
case ENUM:
|
||||
usz i = types::any_to_enum_ordinal(arg, usz)!!;
|
||||
assert(i < arg.type.names.len, "Illegal enum value found, numerical value was %d.", i);
|
||||
return formatter_out_substr(self, arg.type.names[i]);
|
||||
case STRUCT:
|
||||
return formatter_out_unknown(self, "struct", arg);
|
||||
case UNION:
|
||||
return formatter_out_unknown(self, "union", arg);
|
||||
case BITSTRUCT:
|
||||
return formatter_out_unknown(self, "bitstruct", arg);
|
||||
case CONSTDEF:
|
||||
case TYPEDEF:
|
||||
if (arg.type == String.typeid)
|
||||
{
|
||||
return formatter_out_substr(self, *(String*)arg);
|
||||
}
|
||||
if (arg.type == ZString.typeid)
|
||||
{
|
||||
return formatter_out_substr(self, *(ZString*)arg ? ((ZString*)arg).str_view() : "(null)");
|
||||
}
|
||||
if (arg.type == DString.typeid)
|
||||
{
|
||||
return formatter_out_substr(self, *(DString*)arg ? ((DString*)arg).str_view() : "(null)");
|
||||
}
|
||||
return formatter_out_str(self, arg.as_inner());
|
||||
case ARRAY:
|
||||
return formatter_out_collection(self, arg, "[", "]");
|
||||
case VECTOR:
|
||||
return formatter_out_collection(self, arg, "[<", ">]");
|
||||
case SLICE:
|
||||
return formatter_out_collection(self, arg, "[", "]");
|
||||
case ANY:
|
||||
case INTERFACE:
|
||||
unreachable("Already handled");
|
||||
default:
|
||||
}
|
||||
return formatter_out_substr(self, "Invalid type");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,14 @@ enum Seek
|
||||
END
|
||||
}
|
||||
|
||||
enum SeekOrigin
|
||||
{
|
||||
FROM_START,
|
||||
FROM_CURSOR,
|
||||
FROM_END
|
||||
}
|
||||
|
||||
|
||||
faultdef
|
||||
ALREADY_EXISTS,
|
||||
BUSY,
|
||||
@@ -358,7 +366,7 @@ fn usz? printfn(String format, args...) @format(0) @maydiscard
|
||||
PutcharBuffer buff;
|
||||
formatter.init(&out_putchar_buffer_fn, &buff);
|
||||
usz? len = formatter.vprintf(format, args);
|
||||
formatter.out('\n')!;
|
||||
formatter.print_char('\n')!;
|
||||
write_putchar_buffer(&buff, true)!;
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
@@ -49,16 +49,16 @@ fn void*? native_freopen(void* file, String filename, String mode) @inline => @
|
||||
return file ?: file_open_errno()~;
|
||||
}
|
||||
|
||||
fn void? native_fseek(void* file, isz offset, Seek seek_mode) @inline
|
||||
fn void? native_fseek(void* file, long offset, SeekOrigin seek_mode) @inline
|
||||
{
|
||||
if (libc::fseek(file, (SeekIndex)offset, seek_mode.ordinal)) return file_seek_errno()~;
|
||||
}
|
||||
|
||||
|
||||
fn usz? native_ftell(CFile file) @inline
|
||||
fn long? native_ftell(CFile file) @inline
|
||||
{
|
||||
long index = libc::ftell(file);
|
||||
return index >= 0 ? (usz)index : file_seek_errno()~;
|
||||
return index >= 0 ? index : file_seek_errno()~;
|
||||
}
|
||||
|
||||
fn usz? native_fwrite(CFile file, char[] buffer) @inline
|
||||
@@ -76,6 +76,11 @@ fn usz? native_fread(CFile file, char[] buffer) @inline
|
||||
return libc::fread(buffer.ptr, 1, buffer.len, file);
|
||||
}
|
||||
|
||||
fn void? native_fflush(CFile file) @inline @maydiscard
|
||||
{
|
||||
if (libc::fflush(file) != 0) return io::GENERAL_ERROR~;
|
||||
}
|
||||
|
||||
macro fault file_open_errno() @local
|
||||
{
|
||||
switch (libc::errno())
|
||||
@@ -123,3 +128,22 @@ macro fault file_seek_errno() @local
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct Utimbuf
|
||||
{
|
||||
Time_t actime;
|
||||
Time_t modtime;
|
||||
}
|
||||
|
||||
extern fn int utime(char* filename, void* times) @if(!env::WIN32);
|
||||
extern fn int _wutime(WChar* filename, void* times) @if(env::WIN32);
|
||||
|
||||
fn void? native_set_modified_time(String filename, libc::Time_t time) => @stack_mem(256; Allocator smem)
|
||||
{
|
||||
Utimbuf times = { time, time };
|
||||
$if env::WIN32:
|
||||
if (_wutime(filename.to_wstring(smem)!, ×)) return io::GENERAL_ERROR~;
|
||||
$else
|
||||
if (utime(filename.zstr_copy(smem), ×)) return io::GENERAL_ERROR~;
|
||||
$endif
|
||||
}
|
||||
|
||||
@@ -4,12 +4,14 @@ import libc;
|
||||
alias FopenFn = fn void*?(String, String);
|
||||
alias FreopenFn = fn void*?(void*, String, String);
|
||||
alias FcloseFn = fn void?(void*);
|
||||
alias FseekFn = fn void?(void*, isz, Seek);
|
||||
alias FtellFn = fn usz?(void*);
|
||||
alias FseekFn = fn void?(void*, long, SeekOrigin);
|
||||
alias FtellFn = fn long?(void*);
|
||||
alias FwriteFn = fn usz?(void*, char[] buffer);
|
||||
alias FreadFn = fn usz?(void*, char[] buffer);
|
||||
alias FflushFn = fn void?(void*);
|
||||
alias RemoveFn = fn void?(String);
|
||||
alias FputcFn = fn void?(int, void*);
|
||||
alias SetModifiedTimeFn = fn void?(String, libc::Time_t);
|
||||
|
||||
FopenFn native_fopen_fn @weak @if(!$defined(native_fopen_fn));
|
||||
FcloseFn native_fclose_fn @weak @if(!$defined(native_fclose_fn));
|
||||
@@ -18,8 +20,10 @@ FseekFn native_fseek_fn @weak @if(!$defined(native_fseek_fn));
|
||||
FtellFn native_ftell_fn @weak @if(!$defined(native_ftell_fn));
|
||||
FwriteFn native_fwrite_fn @weak @if(!$defined(native_fwrite_fn));
|
||||
FreadFn native_fread_fn @weak @if(!$defined(native_fread_fn));
|
||||
FflushFn native_fflush_fn @weak @if(!$defined(native_fflush_fn));
|
||||
RemoveFn native_remove_fn @weak @if(!$defined(native_remove_fn));
|
||||
FputcFn native_fputc_fn @weak @if(!$defined(native_fputc_fn));
|
||||
SetModifiedTimeFn native_set_modified_time_fn @weak @if(!$defined(native_set_modified_time_fn));
|
||||
|
||||
<*
|
||||
@require mode.len > 0
|
||||
@@ -52,13 +56,13 @@ fn void*? native_freopen(void* file, String filename, String mode) @inline
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
fn void? native_fseek(void* file, isz offset, Seek seek_mode) @inline
|
||||
fn void? native_fseek(void* file, long offset, SeekOrigin whence) @inline
|
||||
{
|
||||
if (native_fseek_fn) return native_fseek_fn(file, offset, seek_mode);
|
||||
if (native_fseek_fn) return native_fseek_fn(file, offset, whence);
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
fn usz? native_ftell(CFile file) @inline
|
||||
fn ulong? native_ftell(CFile file) @inline
|
||||
{
|
||||
if (native_ftell_fn) return native_ftell_fn(file);
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
@@ -76,8 +80,20 @@ fn usz? native_fread(CFile file, char[] buffer) @inline
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
fn void? native_fflush(CFile file) @inline @maydiscard
|
||||
{
|
||||
if (native_fflush_fn) return native_fflush_fn(file);
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
fn void? native_fputc(CInt c, CFile stream) @inline
|
||||
{
|
||||
if (native_fputc_fn) return native_fputc_fn(c, stream);
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
fn void? native_set_modified_time(String filename, libc::Time_t time) @inline
|
||||
{
|
||||
if (native_set_modified_time_fn) return native_set_modified_time_fn(filename, time);
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
@@ -47,14 +47,15 @@ fn usz? native_file_size(String path) @if(env::WIN32) => @pool()
|
||||
return (usz)size.quadPart;
|
||||
}
|
||||
|
||||
fn usz? native_file_size(String path) @if(!env::WIN32 && !env::DARWIN && !env::LINUX && !env::ANDROID && !env::BSD_FAMILY)
|
||||
fn ulong? native_file_size(String path) @if(!env::WIN32 && !env::DARWIN && !env::LINUX && !env::ANDROID && !env::BSD_FAMILY)
|
||||
{
|
||||
File f = file::open(path, "r")!;
|
||||
defer (void)f.close();
|
||||
return f.seek(0, Seek.END)!;
|
||||
f.set_cursor(0, FROM_END)!;
|
||||
return f.cursor();
|
||||
}
|
||||
|
||||
fn usz? native_file_size(String path) @if(env::DARWIN || env::LINUX || env::ANDROID || env::BSD_FAMILY)
|
||||
fn ulong? native_file_size(String path) @if(env::DARWIN || env::LINUX || env::ANDROID || env::BSD_FAMILY)
|
||||
{
|
||||
Stat stat;
|
||||
native_stat(&stat, path)!;
|
||||
|
||||
@@ -36,7 +36,7 @@ fn Path? cwd(Allocator allocator)
|
||||
|
||||
fn bool is_dir(Path path) => os::native_is_dir(path.str_view());
|
||||
fn bool is_file(Path path) => os::native_is_file(path.str_view());
|
||||
fn usz? file_size(Path path) => os::native_file_size(path.str_view());
|
||||
fn ulong? 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? tcwd() => cwd(tmem) @inline;
|
||||
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
module std::io;
|
||||
import std::math;
|
||||
|
||||
|
||||
|
||||
alias SetCursorFn = fn void?(void*, long offset, SeekOrigin whence = START);
|
||||
|
||||
|
||||
interface InStream
|
||||
{
|
||||
fn void? close() @optional;
|
||||
fn long? cursor() @optional;
|
||||
fn void? set_cursor(long offset, SeekOrigin whence = FROM_START) @optional;
|
||||
fn usz? seek(isz offset, Seek seek) @optional;
|
||||
fn usz len() @optional;
|
||||
fn usz? available() @optional;
|
||||
fn ulong? size() @optional;
|
||||
fn ulong? available() @optional;
|
||||
fn usz? read(char[] buffer);
|
||||
fn char? read_byte();
|
||||
fn usz? write_to(OutStream out) @optional;
|
||||
@@ -24,15 +32,23 @@ interface OutStream
|
||||
fn usz? read_to(InStream in) @optional;
|
||||
}
|
||||
|
||||
fn usz? available(InStream s)
|
||||
fn ulong? available(InStream s)
|
||||
{
|
||||
if (&s.available) return s.available();
|
||||
if (&s.set_cursor && &s.cursor)
|
||||
{
|
||||
long curr = s.cursor()!;
|
||||
s.set_cursor(0, FROM_END)!;
|
||||
ulong len = s.cursor()!;
|
||||
s.set_cursor(curr)!;
|
||||
return len - curr;
|
||||
}
|
||||
if (&s.seek)
|
||||
{
|
||||
usz curr = s.seek(0, Seek.CURSOR)!;
|
||||
usz len = s.seek(0, Seek.END)!;
|
||||
s.seek(curr, Seek.SET)!;
|
||||
return len - curr;
|
||||
return (ulong)len - (ulong)curr;
|
||||
}
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
@@ -177,6 +193,11 @@ macro usz? write_using_write_byte(s, char[] bytes)
|
||||
|
||||
macro void? pushback_using_seek(s)
|
||||
{
|
||||
if (&s.set_cursor)
|
||||
{
|
||||
s.set_cursor(-1, FROM_CURSOR)!;
|
||||
return;
|
||||
}
|
||||
s.seek(-1, CURSOR)!;
|
||||
}
|
||||
|
||||
@@ -407,11 +428,11 @@ macro ulong? read_le_ulong(stream)
|
||||
{
|
||||
ulong val = (ulong)stream.read_byte()!;
|
||||
val += (ulong)stream.read_byte()! << 8;
|
||||
val += (ulong)stream.read_byte()! << 16;
|
||||
val += (ulong)stream.read_byte()! << 16;
|
||||
val += (ulong)stream.read_byte()! << 24;
|
||||
val += (ulong)stream.read_byte()! << 32;
|
||||
val += (ulong)stream.read_byte()! << 40;
|
||||
val += (ulong)stream.read_byte()! << 48;
|
||||
val += (ulong)stream.read_byte()! << 48;
|
||||
return val + (ulong)stream.read_byte()! << 56;
|
||||
}
|
||||
|
||||
@@ -621,24 +642,30 @@ macro void? skip(stream, usz bytes)
|
||||
{
|
||||
if (!bytes) return;
|
||||
$switch:
|
||||
$case !$defined(stream.seek):
|
||||
for (usz i = 0; i < bytes; i++)
|
||||
{
|
||||
stream.read()!;
|
||||
}
|
||||
return;
|
||||
$case $typeof(stream) == InStream:
|
||||
if (!&stream.seek)
|
||||
{
|
||||
for (usz i = 0; i < bytes; i++)
|
||||
{
|
||||
stream.read()!;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!&stream.seek && !&stream.set_cursor)
|
||||
{
|
||||
for (usz i = 0; i < bytes; i++)
|
||||
{
|
||||
stream.read()!;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!&stream.set_cursor)
|
||||
{
|
||||
stream.seek(bytes, CURSOR)!;
|
||||
return;
|
||||
}
|
||||
stream.set_cursor(bytes, FROM_CURSOR)!;
|
||||
$case $defined(stream.set_cursor):
|
||||
stream.set_cursor(bytes, FROM_CURSOR)!;
|
||||
$case $defined(stream.seek):
|
||||
stream.seek(bytes, CURSOR)!;
|
||||
$default:
|
||||
stream.seek(bytes, CURSOR)!;
|
||||
for (usz i = 0; i < bytes; i++)
|
||||
{
|
||||
stream.read()!;
|
||||
}
|
||||
$endswitch
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ fn usz? ReadBuffer.read(&self, char[] bytes) @dynamic
|
||||
// Read directly into the input buffer.
|
||||
return self.wrapped_stream.read(bytes)!;
|
||||
}
|
||||
self.refill()!;
|
||||
readbuffer_refill(self)!;
|
||||
}
|
||||
usz n = min(self.write_idx - self.read_idx, bytes.len);
|
||||
bytes[:n] = self.bytes[self.read_idx:n];
|
||||
@@ -48,14 +48,14 @@ fn usz? ReadBuffer.read(&self, char[] bytes) @dynamic
|
||||
|
||||
fn char? ReadBuffer.read_byte(&self) @dynamic
|
||||
{
|
||||
if (self.read_idx == self.write_idx) self.refill()!;
|
||||
if (self.read_idx == self.write_idx) readbuffer_refill(self)!;
|
||||
if (self.read_idx == self.write_idx) return io::EOF~;
|
||||
char c = self.bytes[self.read_idx];
|
||||
self.read_idx++;
|
||||
return c;
|
||||
}
|
||||
|
||||
fn void? ReadBuffer.refill(&self) @local @inline
|
||||
fn void? readbuffer_refill(ReadBuffer* self) @local @inline
|
||||
{
|
||||
self.read_idx = 0;
|
||||
self.write_idx = self.wrapped_stream.read(self.bytes)!;
|
||||
@@ -92,7 +92,7 @@ fn void? WriteBuffer.close(&self) @dynamic
|
||||
|
||||
fn void? WriteBuffer.flush(&self) @dynamic
|
||||
{
|
||||
self.write_pending()!;
|
||||
write_buffer_write_pending(self)!;
|
||||
if (&self.wrapped_stream.flush) self.wrapped_stream.flush()!;
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ fn usz? WriteBuffer.write(&self, char[] bytes) @dynamic
|
||||
self.index += bytes.len;
|
||||
return bytes.len;
|
||||
}
|
||||
self.write_pending()!;
|
||||
write_buffer_write_pending(self)!;
|
||||
if (bytes.len >= self.bytes.len)
|
||||
{
|
||||
// Write directly to the stream.
|
||||
@@ -123,13 +123,13 @@ fn void? WriteBuffer.write_byte(&self, char c) @dynamic
|
||||
usz n = self.bytes.len - self.index;
|
||||
if (n == 0)
|
||||
{
|
||||
self.write_pending()!;
|
||||
write_buffer_write_pending(self)!;
|
||||
}
|
||||
self.bytes[self.index] = c;
|
||||
self.index += 1;
|
||||
}
|
||||
|
||||
fn void? WriteBuffer.write_pending(&self) @local
|
||||
fn void? write_buffer_write_pending(WriteBuffer* self) @local
|
||||
{
|
||||
self.index -= self.wrapped_stream.write(self.bytes[:self.index])!;
|
||||
if (self.index != 0) return INCOMPLETE_WRITE~;
|
||||
|
||||
@@ -104,28 +104,37 @@ fn void? ByteBuffer.pushback_byte(&self) @dynamic
|
||||
self.has_last = false;
|
||||
}
|
||||
|
||||
fn usz? ByteBuffer.seek(&self, isz offset, Seek seek) @dynamic
|
||||
fn long? ByteBuffer.cursor(&self) @dynamic
|
||||
{
|
||||
switch (seek)
|
||||
{
|
||||
case SET:
|
||||
if (offset < 0 || offset > self.write_idx) return INVALID_POSITION~;
|
||||
self.read_idx = offset;
|
||||
return offset;
|
||||
case CURSOR:
|
||||
if ((offset < 0 && self.read_idx < -offset) ||
|
||||
(offset > 0 && self.read_idx + offset > self.write_idx)) return INVALID_POSITION~;
|
||||
self.read_idx += offset;
|
||||
case END:
|
||||
if (offset < 0 || offset > self.write_idx) return INVALID_POSITION~;
|
||||
self.read_idx = self.write_idx - offset;
|
||||
}
|
||||
return self.read_idx;
|
||||
}
|
||||
|
||||
fn usz? ByteBuffer.available(&self) @inline @dynamic
|
||||
fn void? ByteBuffer.set_cursor(&self, long offset, SeekOrigin whence = FROM_START) @dynamic
|
||||
{
|
||||
return self.write_idx - self.read_idx;
|
||||
switch (whence)
|
||||
{
|
||||
case FROM_START:
|
||||
if (offset < 0 || offset > self.write_idx) return INVALID_POSITION~;
|
||||
self.read_idx = (usz)offset;
|
||||
case FROM_CURSOR:
|
||||
if ((offset < 0 && self.read_idx < -offset) ||
|
||||
(offset > 0 && self.read_idx + offset > self.write_idx)) return INVALID_POSITION~;
|
||||
self.read_idx += (usz)offset;
|
||||
case FROM_END:
|
||||
if (offset < 0 || offset > self.write_idx) return INVALID_POSITION~;
|
||||
self.read_idx = self.write_idx - (usz)offset;
|
||||
}
|
||||
}
|
||||
|
||||
fn usz? ByteBuffer.seek(&self, isz offset, Seek seek) @dynamic
|
||||
{
|
||||
self.set_cursor(offset, (SeekOrigin)seek.ordinal)!;
|
||||
return (usz)self.cursor();
|
||||
}
|
||||
|
||||
fn ulong? ByteBuffer.available(&self) @inline @dynamic
|
||||
{
|
||||
return (ulong)self.write_idx - self.read_idx;
|
||||
}
|
||||
|
||||
fn void ByteBuffer.grow(&self, usz n)
|
||||
|
||||
@@ -41,16 +41,26 @@ fn void? ByteReader.pushback_byte(&self) @dynamic
|
||||
|
||||
fn usz? ByteReader.seek(&self, isz offset, Seek seek) @dynamic
|
||||
{
|
||||
isz new_index;
|
||||
switch (seek)
|
||||
self.set_cursor((long)offset, (SeekOrigin)seek.ordinal)!;
|
||||
return (usz)self.cursor();
|
||||
}
|
||||
|
||||
fn long? ByteReader.cursor(&self) @dynamic
|
||||
{
|
||||
return self.index;
|
||||
}
|
||||
|
||||
fn void? ByteReader.set_cursor(&self, long offset, SeekOrigin whence = FROM_START) @dynamic
|
||||
{
|
||||
long new_index;
|
||||
switch (whence)
|
||||
{
|
||||
case SET: new_index = offset;
|
||||
case CURSOR: new_index = self.index + offset;
|
||||
case END: new_index = self.bytes.len + offset;
|
||||
case FROM_START: new_index = offset;
|
||||
case FROM_CURSOR: new_index = self.index + offset;
|
||||
case FROM_END: new_index = self.bytes.len + offset;
|
||||
}
|
||||
if (new_index < 0) return INVALID_POSITION~;
|
||||
self.index = new_index;
|
||||
return new_index;
|
||||
if (new_index < 0 || new_index > self.bytes.len) return INVALID_POSITION~;
|
||||
self.index = (usz)new_index;
|
||||
}
|
||||
|
||||
fn usz? ByteReader.write_to(&self, OutStream writer) @dynamic
|
||||
@@ -62,7 +72,7 @@ fn usz? ByteReader.write_to(&self, OutStream writer) @dynamic
|
||||
return written;
|
||||
}
|
||||
|
||||
fn usz? ByteReader.available(&self) @inline @dynamic
|
||||
fn ulong? ByteReader.available(&self) @inline @dynamic
|
||||
{
|
||||
return max(0, self.bytes.len - self.index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,9 +86,10 @@ fn usz? ByteWriter.read_from(&self, InStream reader) @dynamic
|
||||
usz start_index = self.index;
|
||||
if (&reader.available)
|
||||
{
|
||||
while (usz available = reader.available()!)
|
||||
while (ulong available = reader.available()!)
|
||||
{
|
||||
self.ensure_capacity(self.index + available)!;
|
||||
if (available > usz.max) return OUT_OF_SPACE~;
|
||||
self.ensure_capacity(self.index + (usz)available)!;
|
||||
usz read = reader.read(self.bytes[self.index..])!;
|
||||
self.index += read;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ fn char? LimitReader.read_byte(&self) @dynamic
|
||||
return self.wrapped_stream.read_byte();
|
||||
}
|
||||
|
||||
fn usz? LimitReader.available(&self) @inline @dynamic
|
||||
fn ulong? LimitReader.available(&self) @inline @dynamic
|
||||
{
|
||||
return self.limit;
|
||||
}
|
||||
@@ -168,13 +168,13 @@ bitstruct Tc_lflags : CUInt
|
||||
bool extproc : 16;
|
||||
}
|
||||
|
||||
const enum T_nldly : char
|
||||
constdef T_nldly : char
|
||||
{
|
||||
NL0 = 0b0,
|
||||
NL1 = 0b1,
|
||||
}
|
||||
|
||||
const enum T_crdly : char
|
||||
constdef T_crdly : char
|
||||
{
|
||||
CR0 = 0b00,
|
||||
CR1 = 0b01,
|
||||
@@ -182,7 +182,7 @@ const enum T_crdly : char
|
||||
CR3 = 0b11,
|
||||
}
|
||||
|
||||
const enum T_tabdly : char
|
||||
constdef T_tabdly : char
|
||||
{
|
||||
TAB0 = 0b00,
|
||||
TAB1 = 0b01,
|
||||
@@ -191,25 +191,25 @@ const enum T_tabdly : char
|
||||
XTABS = TAB3,
|
||||
}
|
||||
|
||||
const enum T_bsdly : char
|
||||
constdef T_bsdly : char
|
||||
{
|
||||
BS0 = 0b0,
|
||||
BS1 = 0b1,
|
||||
}
|
||||
|
||||
const enum T_ffdly : char
|
||||
constdef T_ffdly : char
|
||||
{
|
||||
FF0 = 0b0,
|
||||
FF1 = 0b1,
|
||||
}
|
||||
|
||||
const enum T_vtdly : char
|
||||
constdef T_vtdly : char
|
||||
{
|
||||
VT0 = 0b0,
|
||||
VT1 = 0b1,
|
||||
}
|
||||
|
||||
const enum T_csize : char
|
||||
constdef T_csize : char
|
||||
{
|
||||
CS5 = 0b00,
|
||||
CS6 = 0b01,
|
||||
@@ -217,7 +217,7 @@ const enum T_csize : char
|
||||
CS8 = 0b11,
|
||||
}
|
||||
|
||||
const enum Speed : CUInt
|
||||
constdef Speed : CUInt
|
||||
{
|
||||
B0 = 0o0000000,
|
||||
B50 = 0o0000001,
|
||||
@@ -253,7 +253,7 @@ const enum Speed : CUInt
|
||||
MAX_BAUD = B4000000,
|
||||
}
|
||||
|
||||
const enum Cc : inline char
|
||||
constdef Cc : inline char
|
||||
{
|
||||
VINTR = 0,
|
||||
VQUIT = 1,
|
||||
@@ -274,7 +274,7 @@ const enum Cc : inline char
|
||||
VEOL2 = 16,
|
||||
}
|
||||
|
||||
const enum Tcactions : CInt
|
||||
constdef Tcactions : CInt
|
||||
{
|
||||
TCOOFF = 0,
|
||||
TCOON = 1,
|
||||
|
||||
@@ -37,7 +37,7 @@ fn BigInt* BigInt.init(&self, int128 value)
|
||||
assert(value < 0 || tmp == 0 || !self.is_negative());
|
||||
assert(value >= 0 || tmp == -1 || self.is_negative());
|
||||
self.len = len;
|
||||
self.reduce_len();
|
||||
reduce_len(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -153,15 +153,11 @@ fn void BigInt.add_this(&self, BigInt other) @operator(+=)
|
||||
self.data[self.len++] = (uint)carry;
|
||||
}
|
||||
|
||||
self.reduce_len();
|
||||
reduce_len(self);
|
||||
|
||||
assert(sign != sign_arg || sign == self.is_negative(), "Overflow in addition");
|
||||
}
|
||||
|
||||
fn void BigInt.reduce_len(&self) @private
|
||||
{
|
||||
self.len = max(find_length(&self.data, self.len), 1);
|
||||
}
|
||||
|
||||
macro uint find_length(uint* data, uint length)
|
||||
{
|
||||
@@ -226,7 +222,7 @@ fn void BigInt.mult_this(&self, BigInt bi2) @operator(*=)
|
||||
|
||||
res.len = min(self.len + bi2.len, (uint)MAX_LEN);
|
||||
|
||||
res.reduce_len();
|
||||
reduce_len(&res);
|
||||
|
||||
// overflow check (result is -ve)
|
||||
assert(!res.is_negative(), "Multiplication overflow");
|
||||
@@ -265,7 +261,7 @@ fn void BigInt.negate(&self)
|
||||
assert(self.is_negative() != was_negative, "Overflow in negation");
|
||||
|
||||
self.len = MAX_LEN;
|
||||
self.reduce_len();
|
||||
reduce_len(self);
|
||||
}
|
||||
|
||||
macro bool BigInt.is_zero(&self) => self.len == 1 && self.data[0] == 0;
|
||||
@@ -301,7 +297,7 @@ fn BigInt* BigInt.sub_this(&self, BigInt other) @operator(-=)
|
||||
self.len = MAX_LEN;
|
||||
}
|
||||
|
||||
self.reduce_len();
|
||||
reduce_len(self);
|
||||
|
||||
// overflow check
|
||||
|
||||
@@ -311,7 +307,7 @@ fn BigInt* BigInt.sub_this(&self, BigInt other) @operator(-=)
|
||||
|
||||
fn int BigInt.bitcount(&self)
|
||||
{
|
||||
self.reduce_len();
|
||||
reduce_len(self);
|
||||
uint val = self.data[self.len - 1];
|
||||
uint mask = 0x80000000;
|
||||
int bits = 32;
|
||||
@@ -364,11 +360,11 @@ fn void BigInt.div_this(&self, BigInt other) @operator(/=)
|
||||
|
||||
if (other.len == 1)
|
||||
{
|
||||
self.single_byte_divide(&other, "ient, &remainder);
|
||||
single_byte_divide(self, &other, "ient, &remainder);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.multi_byte_divide(&other, "ient, &remainder);
|
||||
multi_byte_divide(self, &other, "ient, &remainder);
|
||||
}
|
||||
if (negate_answer)
|
||||
{
|
||||
@@ -407,11 +403,11 @@ fn void BigInt.mod_this(&self, BigInt bi2) @operator(%=)
|
||||
|
||||
if (bi2.len == 1)
|
||||
{
|
||||
self.single_byte_divide(&bi2, "ient, &remainder);
|
||||
single_byte_divide(self, &bi2, "ient, &remainder);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.multi_byte_divide(&bi2, "ient, &remainder);
|
||||
multi_byte_divide(self, &bi2, "ient, &remainder);
|
||||
}
|
||||
if (negate_answer)
|
||||
{
|
||||
@@ -425,7 +421,7 @@ fn void BigInt.bit_negate_this(&self)
|
||||
foreach (&r : self.data) *r = ~*r;
|
||||
|
||||
self.len = MAX_LEN;
|
||||
self.reduce_len();
|
||||
reduce_len(self);
|
||||
}
|
||||
|
||||
fn BigInt BigInt.bit_negate(self) @operator(~)
|
||||
@@ -523,7 +519,7 @@ fn usz? BigInt.to_format(&self, Formatter* format) @dynamic
|
||||
usz len;
|
||||
if (negative)
|
||||
{
|
||||
format.out('-')!;
|
||||
format.print_char('-')!;
|
||||
len++;
|
||||
a.negate();
|
||||
}
|
||||
@@ -580,7 +576,7 @@ fn String BigInt.to_string_with_radix(&self, int radix, Allocator allocator)
|
||||
|
||||
while (!a.is_zero())
|
||||
{
|
||||
a.single_byte_divide(&big_radix, "ient, &remainder);
|
||||
single_byte_divide(&a, &big_radix, "ient, &remainder);
|
||||
|
||||
if (remainder.data[0] < 10)
|
||||
{
|
||||
@@ -740,7 +736,7 @@ fn BigInt barrett_reduction(BigInt x, BigInt n, BigInt constant)
|
||||
}
|
||||
|
||||
r2.len = k_plus_one;
|
||||
r2.reduce_len();
|
||||
reduce_len(&r2);
|
||||
|
||||
r1.sub_this(r2);
|
||||
if (r1.is_negative())
|
||||
@@ -816,7 +812,7 @@ fn void BigInt.bit_and_this(&self, BigInt bi2)
|
||||
}
|
||||
self.len = MAX_LEN;
|
||||
|
||||
self.reduce_len();
|
||||
reduce_len(self);
|
||||
}
|
||||
|
||||
fn BigInt BigInt.bit_or(self, BigInt bi2) @operator(|)
|
||||
@@ -834,7 +830,7 @@ fn void BigInt.bit_or_this(&self, BigInt bi2)
|
||||
}
|
||||
self.len = MAX_LEN;
|
||||
|
||||
self.reduce_len();
|
||||
reduce_len(self);
|
||||
}
|
||||
|
||||
fn BigInt BigInt.bit_xor(self, BigInt bi2) @operator(^)
|
||||
@@ -852,7 +848,7 @@ fn void BigInt.bit_xor_this(&self, BigInt bi2)
|
||||
}
|
||||
self.len = MAX_LEN;
|
||||
|
||||
self.reduce_len();
|
||||
reduce_len(self);
|
||||
}
|
||||
|
||||
fn void BigInt.shl_this(&self, int shift) @operator(<<=)
|
||||
@@ -928,13 +924,18 @@ fn void BigInt.randomize_bits(&self, Random random, int bits)
|
||||
|
||||
module std::math::bigint @private;
|
||||
|
||||
fn void reduce_len(BigInt* self) @private
|
||||
{
|
||||
self.len = max(find_length(&self.data, self.len), 1);
|
||||
}
|
||||
|
||||
|
||||
<*
|
||||
@param [&inout] quotient
|
||||
@param [&in] bi2
|
||||
@param [&inout] remainder
|
||||
*>
|
||||
fn void BigInt.single_byte_divide(&self, BigInt* bi2, BigInt* quotient, BigInt* remainder)
|
||||
fn void single_byte_divide(BigInt* self, BigInt* bi2, BigInt* quotient, BigInt* remainder) @private
|
||||
{
|
||||
uint[MAX_LEN] result;
|
||||
int result_pos = 0;
|
||||
@@ -977,8 +978,8 @@ fn void BigInt.single_byte_divide(&self, BigInt* bi2, BigInt* quotient, BigInt*
|
||||
}
|
||||
|
||||
quotient.data[j..] = 0;
|
||||
quotient.reduce_len();
|
||||
remainder.reduce_len();
|
||||
reduce_len(quotient);
|
||||
reduce_len(remainder);
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -986,7 +987,7 @@ fn void BigInt.single_byte_divide(&self, BigInt* bi2, BigInt* quotient, BigInt*
|
||||
@param [&in] other
|
||||
@param [&inout] remainder
|
||||
*>
|
||||
fn void BigInt.multi_byte_divide(&self, BigInt* other, BigInt* quotient, BigInt* remainder)
|
||||
fn void multi_byte_divide(BigInt* self, BigInt* other, BigInt* quotient, BigInt* remainder)
|
||||
{
|
||||
uint[MAX_LEN] result;
|
||||
uint[MAX_LEN] r;
|
||||
@@ -1081,7 +1082,7 @@ fn void BigInt.multi_byte_divide(&self, BigInt* other, BigInt* quotient, BigInt*
|
||||
quotient.data[y] = 0;
|
||||
}
|
||||
|
||||
quotient.reduce_len();
|
||||
reduce_len(quotient);
|
||||
|
||||
remainder.len = shift_right(&r, remainder_len, shift);
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ macro void @loop_over_ai(AddrInfo* ai; @body(NativeSocket fd, AddrInfo* ai))
|
||||
|
||||
const Duration POLL_FOREVER = (Duration)-1;
|
||||
|
||||
const enum PollSubscribe
|
||||
constdef PollSubscribe
|
||||
{
|
||||
ANY_READ = os::POLLIN,
|
||||
PRIO_READ = os::POLLPRI,
|
||||
@@ -44,7 +44,7 @@ const PollSubscribe SUBSCRIBE_ANY_WRITE = (PollSubscribe)os::POLLOUT;
|
||||
const PollSubscribe SUBSCRIBE_OOB_WRITE = (PollSubscribe)os::POLLWRBAND;
|
||||
const PollSubscribe SUBSCRIBE_WRITE = (PollSubscribe)os::POLLWRNORM;
|
||||
|
||||
const enum PollEvent : ushort
|
||||
constdef PollEvent : ushort
|
||||
{
|
||||
READ_PRIO = os::POLLPRI,
|
||||
READ_OOB = os::POLLRDBAND,
|
||||
|
||||
@@ -18,7 +18,7 @@ const uint EPOLLWAKEUP = EpollEvents.EPOLLWAKEUP;
|
||||
const uint EPOLLONESHOT = EpollEvents.EPOLLONESHOT;
|
||||
const uint EPOLLET = EpollEvents.EPOLLET;
|
||||
|
||||
const enum EpollEvents : inline uint
|
||||
constdef EpollEvents : inline uint
|
||||
{
|
||||
EPOLLIN = 0x001,
|
||||
EPOLLPRI = 0x002,
|
||||
|
||||
@@ -186,7 +186,7 @@ fn ulong? elf_module_image_base(String path) @local
|
||||
bool is_little_endian = file.read_byte()! == 1;
|
||||
// Actually, not supported.
|
||||
if (!is_little_endian) return backtrace::IMAGE_NOT_FOUND~;
|
||||
file.seek(0)!;
|
||||
file.set_cursor(0)!;
|
||||
if (is_64)
|
||||
{
|
||||
Elf64_Ehdr file_header;
|
||||
@@ -195,7 +195,7 @@ fn ulong? elf_module_image_base(String path) @local
|
||||
for (isz i = 0; i < file_header.e_phnum; i++)
|
||||
{
|
||||
Elf64_Phdr header;
|
||||
file.seek((usz)file_header.e_phoff + (usz)file_header.e_phentsize * i)!;
|
||||
file.set_cursor(file_header.e_phoff + (long)file_header.e_phentsize * i)!;
|
||||
io::read_any(&file, &header)!;
|
||||
if (header.p_type == PT_PHDR) return header.p_vaddr - header.p_offset;
|
||||
}
|
||||
@@ -207,7 +207,7 @@ fn ulong? elf_module_image_base(String path) @local
|
||||
for (isz i = 0; i < file_header.e_phnum; i++)
|
||||
{
|
||||
Elf32_Phdr header;
|
||||
file.seek(file_header.e_phoff + (usz)file_header.e_phentsize * i)!;
|
||||
file.set_cursor(file_header.e_phoff + (long)file_header.e_phentsize * i)!;
|
||||
io::read_any(&file, &header)!;
|
||||
if (header.p_type == PT_PHDR) return (ulong)header.p_vaddr - header.p_offset;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ extern fn CFTypeRef CFType.retain(&self) @cname("CFRetain");
|
||||
extern fn void CFType.release(&self) @cname("CFRelease");
|
||||
extern fn CFIndex CFType.getRetainCount(&self) @cname("CFGetRetainCount");
|
||||
|
||||
const enum CFStringEncoding : uint
|
||||
constdef CFStringEncoding : uint
|
||||
{
|
||||
INVALID_ID = 0xffffffffU,
|
||||
MAC_ROMAN = 0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module std::os::darwin @if(env::DARWIN) @link("Foundation.framework");
|
||||
import std::os::macos::cf, std::os::macos::objc, std::io;
|
||||
|
||||
const enum NSSearchPathDomainMask : NSUInteger
|
||||
constdef NSSearchPathDomainMask : NSUInteger
|
||||
{
|
||||
USER = 1,
|
||||
LOCAL = 2,
|
||||
@@ -10,7 +10,7 @@ const enum NSSearchPathDomainMask : NSUInteger
|
||||
ALL = 0x0ffff
|
||||
}
|
||||
|
||||
const enum NSSearchPathDirectory : NSUInteger
|
||||
constdef NSSearchPathDirectory : NSUInteger
|
||||
{
|
||||
APPLICATION = 1,
|
||||
DEMO_APPLICATION,
|
||||
|
||||
@@ -88,7 +88,7 @@ enum ApplicationActivationPolicy : (int val) @deprecated("Use NSApplicationActiv
|
||||
PROHIBITED { 2 },
|
||||
}
|
||||
|
||||
const enum NSApplicationActivationPolicy : inline NSInteger
|
||||
constdef NSApplicationActivationPolicy : inline NSInteger
|
||||
{
|
||||
REGULAR = 0,
|
||||
ACCESSORY = 1,
|
||||
@@ -119,7 +119,7 @@ enum BackingStore : (int val) @deprecated("Use NSBackingStoreType.")
|
||||
BUFFERED { 2 }
|
||||
}
|
||||
|
||||
const enum NSBackingStoreType : inline NSUInteger
|
||||
constdef NSBackingStoreType : inline NSUInteger
|
||||
{
|
||||
RETAINED = 0,
|
||||
NONRETAINED = 1,
|
||||
@@ -164,7 +164,7 @@ enum EventType : (long val) @deprecated("Use NSEventType.")
|
||||
CHANGE_MODE { 38 },
|
||||
}
|
||||
|
||||
const enum NSEventType : inline NSUInteger
|
||||
constdef NSEventType : inline NSUInteger
|
||||
{
|
||||
LEFT_MOUSE_DOWN = 1,
|
||||
LEFT_MOUSE_UP = 2,
|
||||
@@ -280,7 +280,7 @@ enum EventMask : (long val) @deprecated("Use NSEventMask.")
|
||||
ANY { long.max },
|
||||
}
|
||||
|
||||
const enum NSEventMask : inline ulong
|
||||
constdef NSEventMask : inline ulong
|
||||
{
|
||||
LEFT_MOUSE_DOWN = 1ul << NSEventType.LEFT_MOUSE_DOWN,
|
||||
LEFT_MOUSE_UP = 1ul << NSEventType.LEFT_MOUSE_UP,
|
||||
@@ -333,7 +333,7 @@ enum EventModifierFlag : (int val) @deprecated("Use NSEventModifierFlags.")
|
||||
HELP { 1 << 22 },
|
||||
}
|
||||
|
||||
const enum NSEventModifierFlags : inline NSUInteger
|
||||
constdef NSEventModifierFlags : inline NSUInteger
|
||||
{
|
||||
CAPS_LOCK = 1 << 16,
|
||||
SHIFT = 1 << 17,
|
||||
@@ -346,7 +346,7 @@ const enum NSEventModifierFlags : inline NSUInteger
|
||||
DEVICE_INDEPENDENT_FLAGS_MASK = 0xffff0000UL,
|
||||
}
|
||||
|
||||
const enum NSWindowCollectionBehavior : inline NSUInteger
|
||||
constdef NSWindowCollectionBehavior : inline NSUInteger
|
||||
{
|
||||
DEFAULT = 0,
|
||||
CAN_JOIN_ALL_SPACES = 1 << 0,
|
||||
@@ -366,7 +366,7 @@ const enum NSWindowCollectionBehavior : inline NSUInteger
|
||||
CAN_JOIN_ALL_APPLICATIONS = 1 << 18,
|
||||
}
|
||||
|
||||
const enum NSWindowLevel : inline NSInteger
|
||||
constdef NSWindowLevel : inline NSInteger
|
||||
{
|
||||
NORMAL = 0,
|
||||
FLOATING = 3,
|
||||
@@ -379,7 +379,7 @@ const enum NSWindowLevel : inline NSInteger
|
||||
SCREEN_SAVER = 1000,
|
||||
}
|
||||
|
||||
const enum NSWindowStyleMask : inline NSUInteger
|
||||
constdef NSWindowStyleMask : inline NSUInteger
|
||||
{
|
||||
BORDERLESS = 0,
|
||||
TITLED = 1 << 0,
|
||||
@@ -396,20 +396,20 @@ const enum NSWindowStyleMask : inline NSUInteger
|
||||
HUD_WINDOW = 1 << 13
|
||||
}
|
||||
|
||||
const enum NSWindowTabbingMode : inline NSInteger
|
||||
constdef NSWindowTabbingMode : inline NSInteger
|
||||
{
|
||||
AUTOMATIC = 0,
|
||||
DISALLOWED = 2,
|
||||
PREFERRED = 1,
|
||||
}
|
||||
|
||||
const enum NSStatusItemLength : inline CGFloat
|
||||
constdef NSStatusItemLength : inline CGFloat
|
||||
{
|
||||
VARIABLE = -1.0,
|
||||
SQUARE = -2.0
|
||||
}
|
||||
|
||||
const enum NSApplicationTerminateReply : inline NSUInteger
|
||||
constdef NSApplicationTerminateReply : inline NSUInteger
|
||||
{
|
||||
CANCEL = 0,
|
||||
NOW = 1,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module std::os::process @if(env::WIN32 || env::POSIX);
|
||||
import std::io, libc, std::os;
|
||||
import std::io, libc, std::os, std::net::os;
|
||||
|
||||
// This code is based on https://github.com/sheredom/subprocess.h
|
||||
|
||||
@@ -321,10 +321,24 @@ fn SubProcess? create(String[] command_line, SubProcessOptions options = {}, Str
|
||||
if (posix::pipe(&stdoutfd)) return FAILED_TO_OPEN_STDOUT~;
|
||||
if (!options.combined_stdout_stderr && posix::pipe(&stderrfd)) return FAILED_TO_OPEN_STDERR~;
|
||||
|
||||
if (options.read_async)
|
||||
{
|
||||
((NativeSocket)stdoutfd[0]).set_non_blocking(true)!;
|
||||
((NativeSocket)stdoutfd[1]).set_non_blocking(true)!;
|
||||
if (!options.combined_stdout_stderr)
|
||||
{
|
||||
((NativeSocket)stderrfd[0]).set_non_blocking(true)!;
|
||||
((NativeSocket)stderrfd[1]).set_non_blocking(true)!;
|
||||
}
|
||||
}
|
||||
|
||||
if (posix::spawn_file_actions_addclose(&actions, stdinfd[1])) return FAILED_TO_OPEN_STDIN~;
|
||||
if (posix::spawn_file_actions_adddup2(&actions, stdinfd[0], libc::STDIN_FD)) return FAILED_TO_OPEN_STDIN~;
|
||||
if (posix::spawn_file_actions_addclose(&actions, stdinfd[0])) return FAILED_TO_OPEN_STDIN~;
|
||||
|
||||
if (posix::spawn_file_actions_addclose(&actions, stdoutfd[0])) return FAILED_TO_OPEN_STDOUT~;
|
||||
if (posix::spawn_file_actions_adddup2(&actions, stdoutfd[1], libc::STDOUT_FD)) return FAILED_TO_OPEN_STDOUT~;
|
||||
if (posix::spawn_file_actions_addclose(&actions, stdoutfd[1])) return FAILED_TO_OPEN_STDERR~;
|
||||
|
||||
if (options.combined_stdout_stderr)
|
||||
{
|
||||
@@ -334,13 +348,14 @@ fn SubProcess? create(String[] command_line, SubProcessOptions options = {}, Str
|
||||
{
|
||||
if (posix::spawn_file_actions_addclose(&actions, stderrfd[0])) return FAILED_TO_OPEN_STDERR~;
|
||||
if (posix::spawn_file_actions_adddup2(&actions, stderrfd[1], libc::STDERR_FD)) return FAILED_TO_OPEN_STDERR~;
|
||||
if (posix::spawn_file_actions_addclose(&actions, stderrfd[1])) return FAILED_TO_OPEN_STDERR~;
|
||||
}
|
||||
}
|
||||
|
||||
Pid_t child;
|
||||
@stack_mem(2048; Allocator mem)
|
||||
{
|
||||
ZString* command_line_copy = copy_command_line(mem, command_line);
|
||||
ZString* command_line_copy = copy_command_line(mem, command_line);
|
||||
ZString* used_environment = options.inherit_environment ? posix::environ : copy_env(mem, environment);
|
||||
if (options.search_user_path)
|
||||
{
|
||||
@@ -485,10 +500,15 @@ fn usz? read_from_file_win32(CFile file, Win32_HANDLE event_handle, char* buffer
|
||||
}
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
fn usz? read_from_file_posix(CFile file, char* buffer, usz size) @if(env::POSIX) @local
|
||||
{
|
||||
isz bytes_read = libc::read(libc::fileno(file), buffer, size);
|
||||
if (bytes_read < 0) return READ_FAILED~;
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
if (libc::errno() == errno::EAGAIN) return 0; // nothing to read but O_NONBLOCK (async) is used
|
||||
return READ_FAILED~;
|
||||
}
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
@@ -537,5 +557,6 @@ fn bool? SubProcess.is_running(&self)
|
||||
fn usz? SubProcess.write_to_stdin(&self, char[] buffer)
|
||||
{
|
||||
if (!self.stdin_file) return FAILED_TO_OPEN_STDIN~;
|
||||
defer try (void)os::native_fflush(self.stdin_file);
|
||||
return os::native_fwrite(self.stdin_file, buffer);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::os::win32 @if(env::WIN32);
|
||||
|
||||
const enum Win32_CODEPAGE : Win32_UINT
|
||||
constdef Win32_CODEPAGE : Win32_UINT
|
||||
{
|
||||
IBM037 = 037, // IBM EBCDIC US-Canada
|
||||
IBM437 = 437, // OEM United States
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::os::win32 @if(env::WIN32);
|
||||
|
||||
const enum Win32_AllocationType
|
||||
constdef Win32_AllocationType
|
||||
{
|
||||
MEM_COMMIT = 0x00001000,
|
||||
MEM_RESERVE = 0x00002000,
|
||||
@@ -12,7 +12,7 @@ const enum Win32_AllocationType
|
||||
MEM_WRITE_WATCH = 0x00200000
|
||||
}
|
||||
|
||||
const enum Win32_Protect : Win32_DWORD
|
||||
constdef Win32_Protect : Win32_DWORD
|
||||
{
|
||||
PAGE_EXECUTE = 0x10,
|
||||
PAGE_EXECUTE_READ = 0x20,
|
||||
@@ -29,7 +29,7 @@ const enum Win32_Protect : Win32_DWORD
|
||||
PAGE_WRITECOMBINE = 0x400,
|
||||
}
|
||||
|
||||
const enum Win32_FreeType : Win32_DWORD
|
||||
constdef Win32_FreeType : Win32_DWORD
|
||||
{
|
||||
MEM_DECOMMIT = 0x00004000,
|
||||
MEM_RELEASE = 0x00008000,
|
||||
|
||||
@@ -13,7 +13,7 @@ enum Win32_MEM_EXTENDED_PARAMETER_TYPE : CInt
|
||||
}
|
||||
alias Win32_PMEM_EXTENDED_PARAMETER_TYPE = Win32_MEM_EXTENDED_PARAMETER_TYPE;
|
||||
|
||||
const enum Win32_MEM_EXTENDED_PARAMETER_ATTRIBUTE : Win32_DWORD64
|
||||
constdef Win32_MEM_EXTENDED_PARAMETER_ATTRIBUTE : Win32_DWORD64
|
||||
{
|
||||
<* The allocation is non-pageable. *>
|
||||
NONPAGED = 0x02,
|
||||
|
||||
@@ -142,7 +142,7 @@ fn void NativeTimedMutex.destroy(&mtx)
|
||||
*mtx = {};
|
||||
}
|
||||
|
||||
fn void? NativeTimedMutex.wait_cond_var(&mtx, uint ms) @local
|
||||
fn void? _wait_cond_var(NativeTimedMutex *mtx, uint ms) @local
|
||||
{
|
||||
if (!win32::sleepConditionVariableSRW(&mtx.cond_var, &mtx.srw_lock, ms, 0))
|
||||
{
|
||||
@@ -169,7 +169,7 @@ fn void NativeTimedMutex.lock(&mtx)
|
||||
|
||||
while (mtx.locks)
|
||||
{
|
||||
mtx.wait_cond_var(win32::INFINITE)!!;
|
||||
_wait_cond_var(mtx, win32::INFINITE)!!;
|
||||
}
|
||||
mtx.locks = 1;
|
||||
mtx.owner_thread = current_thread;
|
||||
@@ -206,7 +206,7 @@ fn void? NativeTimedMutex.lock_timeout(&mtx, ulong ms)
|
||||
{
|
||||
ulong remaining_ms = remaining.to_ms();
|
||||
if (remaining_ms > uint.max) remaining_ms = uint.max;
|
||||
mtx.wait_cond_var((uint)remaining_ms)!;
|
||||
_wait_cond_var(mtx, (uint)remaining_ms)!;
|
||||
if (!mtx.locks)
|
||||
{
|
||||
// Got the lock
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
## 0.7.10 Change list
|
||||
|
||||
### Changes / improvements
|
||||
- Method resolution and `$define` now works together well unless definitions are out of order for real.
|
||||
- C3 is now using its own LLVM libraries when building releases.
|
||||
- Method resolution and `$defined` now works together well unless definitions are out of order for real.
|
||||
- Improve error message when using functions as values #2856
|
||||
- Improve support for Android with Termux.
|
||||
- Integrated download of the MSVC SDK when compiling for Windows.
|
||||
- For `c3c init` with library templates, provide example exported functions. #2898
|
||||
- `unsigned % signed` and `unsigned / signed` is no longer allowed without explicit casts, except for const denominators. #2928
|
||||
- New const enum declaration syntax.
|
||||
- New enum associated value syntax.
|
||||
- Individual warning settings added.
|
||||
- Change typedef and const enums to not convert from literals by default.
|
||||
@@ -17,7 +17,14 @@
|
||||
- Include actual element count in the error message when the array initializer size does not match the expected size.
|
||||
- Add `--print-large-functions` for checking which functions likely dominate the compile time.
|
||||
- Improve error message when providing `alias` with a typeid expression where a type was expected. #2944
|
||||
|
||||
- Const enums removed.
|
||||
- Constdef declarations introduced.
|
||||
- Properly support `@deprecated` as contract.
|
||||
- Support deprecating enum values.
|
||||
- Improve error when trying to use an extern const as a compile time constant. #2969
|
||||
- `vendor-fetch` command now lists all available packages by default. #2976
|
||||
- Typekind enums are changed CONST_ENUM -> CONSTDEF, DISTINCT -> TYPEDEF.
|
||||
|
||||
### Stdlib changes
|
||||
- Summarize sort macros as generic function wrappers to reduce the amount of generated code. #2831
|
||||
- Remove dependency on temp allocator in String.join.
|
||||
@@ -30,6 +37,10 @@
|
||||
- Add `array::even`, `array::odd`, and `array::unlace` macros. #2892
|
||||
- Add discrete and continuous distributions in `std::math::distributions`.
|
||||
- Add bitorder functions `store_le`, `load_le`, `store_be`, `store_le`.
|
||||
- Stream functions now use long/ulong rather than isz/usz for seek/available.
|
||||
- `instream.seek` is replaced by `set_cursor` and `cursor`.
|
||||
- `instream.available`, `cursor` etc are long/ulong rather than isz/usz to be correct on 32-bit.
|
||||
- Enable asynchronous, non-blocking reads of subprocess STDOUT/STDERR pipes on POSIX systems.
|
||||
|
||||
### Fixes
|
||||
- Add error message if directory with output file name already exists
|
||||
@@ -45,10 +56,12 @@
|
||||
- Improved underlining errors/warnings when unicode is used. #2887
|
||||
- Fix std::io::Formatter integer issue for large uint128 decimal values.
|
||||
- `--safe=no` disabled compile-time errors on compile-time known runtime @require checks #2936
|
||||
- On assert known false, the message was not show for no-args.
|
||||
- On assert known false, the message was not shown for no-args.
|
||||
- Adding the incorrect sized vector to a pointer vector would cause a crash.
|
||||
- Member access on a struct returned by the assignment expression, cause crash #2947
|
||||
- Trying to slice an indexable type leads to misleading error message #2958
|
||||
- Warn on use of visibility modifiers on methods. #2962
|
||||
- Compiler crash using `??` with a `void?` macro #2973
|
||||
|
||||
## 0.7.9 Change list
|
||||
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
module gl;
|
||||
|
||||
alias BitField = int;
|
||||
|
||||
enum BufferBit : int (int value)
|
||||
constdef BufferBit : int
|
||||
{
|
||||
COLOR = 0x00004000,
|
||||
STENCIL = 0x00000400,
|
||||
DEPTH = 0x00000100,
|
||||
}
|
||||
|
||||
enum Primitive : int (int value)
|
||||
constdef Primitive : int
|
||||
{
|
||||
POINTS = 0,
|
||||
LINES = 1,
|
||||
@@ -23,9 +21,9 @@ enum Primitive : int (int value)
|
||||
POLYGON = 9,
|
||||
}
|
||||
|
||||
extern fn void clear(BitField mask) @cname("glClear") @public;
|
||||
extern fn void clear(BufferBit mask) @cname("glClear") @public;
|
||||
|
||||
extern fn void begin(BitField mask) @cname("glBegin") @public;
|
||||
extern fn void begin(BufferBit mask) @cname("glBegin") @public;
|
||||
|
||||
extern fn void end() @cname("glEnd") @public;
|
||||
|
||||
|
||||
@@ -45,11 +45,11 @@ alias CameraUpdateFn = fn void(RLCamera2D* camera, Player* player, EnvItem[] env
|
||||
|
||||
enum CameraUpdateType : (ZString text, CameraUpdateFn func)
|
||||
{
|
||||
CENTER = { "Follow player center", &update_camera_center },
|
||||
CENTER_INSIDE_MAP = { "Follow player center, but clamp to map edges", &update_camera_center_inside_map },
|
||||
CENTER_SMOOTH_FOLLOW = { "Follow player center; smoothed", &update_camera_center_smooth_follow },
|
||||
EVEN_OUT_ON_LANDING = { "Follow player center horizontally; update player center vertically after landing", &update_camera_even_out_on_landing },
|
||||
PLAYER_BOUNDS_PUSH = { "Player push camera on getting too close to screen edge", &update_camera_player_bounds_push }
|
||||
CENTER { "Follow player center", &update_camera_center },
|
||||
CENTER_INSIDE_MAP { "Follow player center, but clamp to map edges", &update_camera_center_inside_map },
|
||||
CENTER_SMOOTH_FOLLOW { "Follow player center; smoothed", &update_camera_center_smooth_follow },
|
||||
EVEN_OUT_ON_LANDING { "Follow player center horizontally; update player center vertically after landing", &update_camera_even_out_on_landing },
|
||||
PLAYER_BOUNDS_PUSH { "Player push camera on getting too close to screen edge", &update_camera_player_bounds_push }
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
|
||||
@@ -18,10 +18,10 @@ const int SCREEN_HEIGHT = 450;
|
||||
|
||||
enum SnakeDirection : (RLVector2 dir)
|
||||
{
|
||||
RIGHT = { SQUARE_SIZE, 0 },
|
||||
DOWN = { 0, SQUARE_SIZE },
|
||||
LEFT = { -SQUARE_SIZE, 0 },
|
||||
UP = { 0, -SQUARE_SIZE }
|
||||
RIGHT {{ SQUARE_SIZE, 0 }},
|
||||
DOWN {{ 0, SQUARE_SIZE }},
|
||||
LEFT {{ -SQUARE_SIZE, 0 }},
|
||||
UP {{ 0, -SQUARE_SIZE }}
|
||||
}
|
||||
struct Snake
|
||||
{
|
||||
|
||||
@@ -97,6 +97,7 @@ typedef struct
|
||||
WarningLevel deprecation;
|
||||
WarningLevel methods_not_resolved;
|
||||
WarningLevel dead_code;
|
||||
WarningLevel method_visibility;
|
||||
} Warnings;
|
||||
|
||||
typedef enum
|
||||
|
||||
@@ -142,6 +142,7 @@ static void usage(bool full)
|
||||
print_opt("--use-old-compact-eq", "Enable the old ability to use '@compact' to make a struct comparable.");
|
||||
print_opt("--print-large-functions", "Print functions with large compile size.");
|
||||
print_opt("--warn-deadcode=<yes|no|error>", "Print warning on dead-code: yes, no, error.");
|
||||
print_opt("--warn-methodvisibility=<yes|no|error>", "Print warning when methods have ignored visibility attributes.");
|
||||
print_opt("--warn-methodsnotresolved=<yes|no|error>", "Print warning on methods not resolved when accessed: yes, no, error.");
|
||||
print_opt("--warn-deprecation=<yes|no|error>", "Print warning when using deprecated code and constructs: yes, no, error.");
|
||||
}
|
||||
@@ -444,7 +445,6 @@ static void parse_command(BuildOptions *options)
|
||||
if (arg_match("vendor-fetch"))
|
||||
{
|
||||
options->command = COMMAND_VENDOR_FETCH;
|
||||
if (at_end() || next_is_opt()) error_exit("error: vendor-fetch needs at least one library.");
|
||||
while (!at_end() && !next_is_opt())
|
||||
{
|
||||
const char *lib = next_arg();
|
||||
@@ -906,6 +906,11 @@ static void parse_option(BuildOptions *options)
|
||||
options->warnings.dead_code = parse_opt_select(WarningLevel, argopt, warnings);
|
||||
return;
|
||||
}
|
||||
if ((argopt = match_argopt("warn-methodvisibility")))
|
||||
{
|
||||
options->warnings.method_visibility = parse_opt_select(WarningLevel, argopt, warnings);
|
||||
return;
|
||||
}
|
||||
if ((argopt = match_argopt("warn-methodsnotresolved")))
|
||||
{
|
||||
options->warnings.methods_not_resolved = parse_opt_select(WarningLevel, argopt, warnings);
|
||||
@@ -1594,6 +1599,7 @@ BuildOptions parse_arguments(int argc, const char *argv[])
|
||||
.win_debug = WIN_DEBUG_DEFAULT,
|
||||
.fp_math = FP_DEFAULT,
|
||||
.x86_cpu_set = X86CPU_DEFAULT,
|
||||
.riscv_cpu_set = RISCV_CPU_DEFAULT,
|
||||
.riscv_abi = RISCV_ABI_DEFAULT,
|
||||
.memory_environment = MEMORY_ENV_NOT_SET,
|
||||
.win.crt_linking = WIN_CRT_DEFAULT,
|
||||
@@ -1666,7 +1672,8 @@ BuildOptions parse_arguments(int argc, const char *argv[])
|
||||
{
|
||||
FAIL_WITH_ERR("Missing a compiler command such as 'compile' or 'build'.");
|
||||
}
|
||||
if (build_options.arch_os_target_override == ANDROID_AARCH64)
|
||||
if (build_options.arch_os_target_override == ANDROID_AARCH64 ||
|
||||
build_options.arch_os_target_override == ANDROID_X86_64)
|
||||
{
|
||||
if (!build_options.android.ndk_path)
|
||||
{
|
||||
|
||||
@@ -536,6 +536,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
update_warning_if_not_set(&target->warnings.deprecation, WARNING_SILENT);
|
||||
update_warning_if_not_set(&target->warnings.methods_not_resolved, WARNING_WARN);
|
||||
update_warning_if_not_set(&target->warnings.dead_code, WARNING_SILENT);
|
||||
update_warning_if_not_set(&target->warnings.method_visibility, WARNING_WARN);
|
||||
break;
|
||||
case VALIDATION_NOT_SET:
|
||||
target->validation_level = VALIDATION_STRICT;
|
||||
@@ -544,16 +545,19 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
update_warning_if_not_set(&target->warnings.methods_not_resolved, WARNING_WARN);
|
||||
update_warning_if_not_set(&target->warnings.deprecation, WARNING_WARN);
|
||||
update_warning_if_not_set(&target->warnings.dead_code, WARNING_WARN);
|
||||
update_warning_if_not_set(&target->warnings.method_visibility, WARNING_WARN);
|
||||
break;
|
||||
case VALIDATION_OBNOXIOUS:
|
||||
update_warning_if_not_set(&target->warnings.methods_not_resolved, WARNING_ERROR);
|
||||
update_warning_if_not_set(&target->warnings.deprecation, WARNING_ERROR);
|
||||
update_warning_if_not_set(&target->warnings.dead_code, WARNING_ERROR);
|
||||
update_warning_if_not_set(&target->warnings.method_visibility, WARNING_ERROR);
|
||||
break;
|
||||
}
|
||||
update_warning(&target->warnings.deprecation, options->warnings.deprecation);
|
||||
update_warning(&target->warnings.dead_code, options->warnings.dead_code);
|
||||
update_warning(&target->warnings.methods_not_resolved, options->warnings.methods_not_resolved);
|
||||
update_warning(&target->warnings.method_visibility, options->warnings.method_visibility);
|
||||
|
||||
target->print_linking = options->print_linking || options->verbosity_level > 1;
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ static bool x86_should_return_type_in_reg(Type *type)
|
||||
case TYPE_FUNC_RAW:
|
||||
case TYPE_INTERFACE:
|
||||
case TYPE_OPTIONAL:
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
case TYPE_ALIAS:
|
||||
case TYPE_TYPEID:
|
||||
case TYPE_VECTOR:
|
||||
|
||||
@@ -590,7 +590,19 @@ static void init_asm_x86(PlatformTarget* target)
|
||||
Clobbers rax_mask = clobbers_make(X86_RAX, -1);
|
||||
Clobbers cc_flag_mask = clobbers_make(X86_CC, -1);
|
||||
Clobbers rax_cc_mask = clobbers_make_from(cc_flag_mask, X86_RAX, -1);
|
||||
Clobbers rcx_cc_mask = clobbers_make_from(cc_flag_mask, X86_RCX, -1);
|
||||
Clobbers rax_rdx_cc_mask = clobbers_make_from(cc_flag_mask, X86_RAX, X86_RDX, -1);
|
||||
Clobbers xmm_0_7_cc_mask = clobbers_make_from(cc_flag_mask, X86_XMM0, X86_XMM1, X86_XMM2, X86_XMM3, X86_XMM4, X86_XMM5, X86_XMM6, X86_XMM7, -1);
|
||||
Clobbers xmm_0_2_xmm_4_6_cc_mask = clobbers_make_from(cc_flag_mask, X86_XMM0, X86_XMM1, X86_XMM2, X86_XMM4, X86_XMM5, X86_XMM6, -1);
|
||||
Clobbers xmm_0_6_cc_mask = clobbers_make_from(cc_flag_mask, X86_XMM0, X86_XMM1, X86_XMM2, X86_XMM3, X86_XMM4, X86_XMM5, X86_XMM6, -1);
|
||||
Clobbers xmm0_mask = clobbers_make(X86_XMM0, -1);
|
||||
Clobbers xmm0_cc_mask = clobbers_make_from(cc_flag_mask, X86_XMM0, -1);
|
||||
Clobbers rax_xmm0_cc_mask = clobbers_make_from(cc_flag_mask, X86_RAX, X86_XMM0, -1);
|
||||
Clobbers lo16_vec_mask = clobbers_make(X86_XMM0, X86_XMM1, X86_XMM2, X86_XMM3, X86_XMM4, X86_XMM5, X86_XMM6, X86_XMM7,
|
||||
X86_XMM8, X86_XMM9, X86_XMM10, X86_XMM11, X86_XMM12, X86_XMM13, X86_XMM14, X86_XMM15, -1);
|
||||
|
||||
|
||||
|
||||
bool is_x64 = target->arch == ARCH_TYPE_X86_64;
|
||||
if (!is_x64)
|
||||
{
|
||||
@@ -610,9 +622,6 @@ static void init_asm_x86(PlatformTarget* target)
|
||||
reg_instr_clob(target, "adcl", cc_flag_mask, "rw:r32/mem, r32/mem/imm32/immi8");
|
||||
reg_instr_clob(target, "adcq", cc_flag_mask, "rw:r64/mem, r64/mem/immi32/immi8");
|
||||
|
||||
reg_instr_clob(target, "adcxl", cc_flag_mask, "r32, rw:r32/mem");
|
||||
reg_instr_clob(target, "adcxq", cc_flag_mask, "r64, rw:r64/mem");
|
||||
|
||||
reg_instr_clob(target, "addb", cc_flag_mask, "rw:r8/mem, r8/mem/imm8");
|
||||
reg_instr_clob(target, "addw", cc_flag_mask, "rw:r16/mem, r16/mem/imm16/immi8");
|
||||
reg_instr_clob(target, "addl", cc_flag_mask, "rw:r32/mem, r32/mem/imm32/immi8");
|
||||
@@ -626,13 +635,45 @@ static void init_asm_x86(PlatformTarget* target)
|
||||
reg_instr(target, "vaddps", "w:v128/v256/v512, v128/v256/v512, v128/v256/v512/mem");
|
||||
reg_instr(target, "vaddsd", "w:v128, v128, v128/mem");
|
||||
reg_instr(target, "vaddss", "w:v128, v128, v128/mem");
|
||||
|
||||
reg_instr(target, "bswapl", "rw:r32");
|
||||
reg_instr(target, "bswapq", "rw:r64");
|
||||
reg_instr_clob(target, "cbtw", rax_mask, NULL);
|
||||
reg_instr_clob(target, "cwtl", rax_mask, NULL);
|
||||
reg_instr_clob(target, "cltq", rax_mask, NULL);
|
||||
reg_instr_clob(target, "clc", rax_mask, NULL);
|
||||
reg_instr_clob(target, "cld", rax_mask, NULL);
|
||||
reg_instr(target, "clflush", "mem");
|
||||
reg_instr(target, "cmovaw", "w:r16, r16/mem");
|
||||
reg_instr(target, "cmoval", "w:r32, r32/mem");
|
||||
reg_instr(target, "cmovaq", "w:r64, r64/mem");
|
||||
reg_instr(target, "cmovaew", "w:r16, r16/mem");
|
||||
reg_instr(target, "cmovael", "w:r32, r32/mem");
|
||||
reg_instr(target, "cmovaeq", "w:r64, r64/mem");
|
||||
reg_instr(target, "cmovbw", "w:r16, r16/mem");
|
||||
reg_instr(target, "cmovbl", "w:r32, r32/mem");
|
||||
reg_instr(target, "cmovbq", "w:r64, r64/mem");
|
||||
reg_instr(target, "cmovbew", "w:r16, r16/mem");
|
||||
reg_instr(target, "cmovbel", "w:r32, r32/mem");
|
||||
reg_instr(target, "cmovbeq", "w:r64, r64/mem");
|
||||
reg_instr_clob(target, "cmpxchgb", rax_cc_mask, "rw:r8/mem, r8");
|
||||
reg_instr_clob(target, "cmpxchgl", rax_cc_mask, "rw:r16/mem, r16");
|
||||
reg_instr_clob(target, "cmpxchgw", rax_cc_mask, "rw:r32/mem, r32");
|
||||
reg_instr_clob(target, "cmpxchgq", rax_cc_mask, "rw:r64/mem, r64");
|
||||
reg_instr_clob(target, "cmpxchg8b", rax_cc_mask, "rw:r64/mem");
|
||||
reg_instr_clob(target, "cmpxchg16b", rax_cc_mask, "rw:r64/mem");
|
||||
reg_instr_clob(target, "decb", cc_flag_mask, "r8/mem");
|
||||
reg_instr_clob(target, "decw", cc_flag_mask, "r16/mem");
|
||||
reg_instr_clob(target, "decl", cc_flag_mask, "r32/mem");
|
||||
reg_instr_clob(target, "decq", cc_flag_mask, "r64/mem");
|
||||
reg_instr_clob(target, "divb", rax_rdx_cc_mask, "r8/mem");
|
||||
reg_instr_clob(target, "divw", rax_rdx_cc_mask, "r16/mem");
|
||||
reg_instr_clob(target, "divl", rax_rdx_cc_mask, "r32/mem");
|
||||
reg_instr_clob(target, "divq", rax_rdx_cc_mask, "r64/mem");
|
||||
reg_instr_clob(target, "idivb", rax_rdx_cc_mask, "r8/mem");
|
||||
reg_instr_clob(target, "idivw", rax_rdx_cc_mask, "r16/mem");
|
||||
reg_instr_clob(target, "idivl", rax_rdx_cc_mask, "r32/mem");
|
||||
reg_instr_clob(target, "idivq", rax_rdx_cc_mask, "r64/mem");
|
||||
|
||||
reg_instr(target, "movb", "w:r8/mem, r8/mem/imm8");
|
||||
reg_instr(target, "movsbw", "w:r16/mem, r8/mem");
|
||||
reg_instr(target, "movzbw", "w:r16/mem, r8/mem");
|
||||
@@ -715,10 +756,123 @@ static void init_asm_x86(PlatformTarget* target)
|
||||
reg_instr(target, "senduipi", "r64");
|
||||
reg_instr(target, "uiret", NULL);
|
||||
|
||||
reg_instr_clob(target, "xaddb", cc_flag_mask, "rw:r8/mem, rw:r8");
|
||||
reg_instr_clob(target, "xaddw", cc_flag_mask, "rw:r16/mem, rw:r16");
|
||||
reg_instr_clob(target, "xaddl", cc_flag_mask, "rw:r32/mem, rw:r32");
|
||||
reg_instr_clob(target, "xaddq", cc_flag_mask, "rw:r64/mem, rw:r64");
|
||||
reg_instr(target, "xchgb", "rw:r8/mem, rw:r8/mem");
|
||||
reg_instr(target, "xchgw", "rw:r16/mem, rw:r16/mem");
|
||||
reg_instr(target, "xchgl", "rw:r32/mem, rw:r32/mem");
|
||||
reg_instr(target, "xchgq", "rw:r64/mem, rw:r64/mem");
|
||||
|
||||
reg_instr_clob(target, "popcntw", cc_flag_mask, "w:r16, r16/mem");
|
||||
reg_instr_clob(target, "popcntl", cc_flag_mask, "w:r32, r32/mem");
|
||||
reg_instr_clob(target, "popcntq", cc_flag_mask, "w:r64, r64/mem");
|
||||
reg_instr_clob(target, "xgetbv", rax_rdx_cc_mask , NULL);
|
||||
|
||||
// BMI1
|
||||
reg_instr_clob(target, "andn", cc_flag_mask, "w:r32/r64, r32/r64, r32/r64/mem");
|
||||
reg_instr_clob(target, "bextr", cc_flag_mask, "w:r32/r64, r32/r64/mem, r32/r64");
|
||||
reg_instr_clob(target, "blsi", cc_flag_mask, "w:r32/r64, r32/r64/mem");
|
||||
reg_instr_clob(target, "blsmsk", cc_flag_mask, "w:r32/r64, r32/r64/mem");
|
||||
reg_instr_clob(target, "blsr", cc_flag_mask, "w:r32/r64, r32/r64/mem");
|
||||
reg_instr_clob(target, "tzcnt", cc_flag_mask, "w:r16/r32/r64, r16/r32/r64/mem");
|
||||
|
||||
// LZCNT
|
||||
reg_instr_clob(target, "lzcnt", cc_flag_mask, "w:r16/r32/r64, r16/r32/r64/mem");
|
||||
|
||||
// BMI2
|
||||
reg_instr(target, "bzhi", "w:r32/r64, r32/r64/mem, r32/r64");
|
||||
reg_instr(target, "mulx", "w:r32/r64, r32/r64, r32/r64/mem");
|
||||
reg_instr(target, "pdep", "w:r32/r64, r32/r64, r32/r64/mem");
|
||||
reg_instr(target, "pext", "w:r32/r64, r32/r64, r32/r64/mem");
|
||||
reg_instr(target, "rorx", "w:r32/r64, r32/r64/mem, imm8");
|
||||
reg_instr(target, "sarx", "w:r32/r64, r32/r64/mem, r32/r64");
|
||||
reg_instr(target, "shlx", "w:r32/r64, r32/r64/mem, r32/r64");
|
||||
reg_instr(target, "shrx", "w:r32/r64, r32/r64/mem, r32/r64");
|
||||
|
||||
// ADX
|
||||
reg_instr_clob(target, "adcx", cc_flag_mask, "rw:r32/r64, r32/r64/mem");
|
||||
reg_instr_clob(target, "adox", cc_flag_mask, "rw:r32/r64, r32/r64/mem");
|
||||
|
||||
// PCLMULQDQ
|
||||
reg_instr(target, "pclmulqdq", "rw:v128, v128/mem, imm8");
|
||||
reg_instr(target, "vpclmulqdq", "w:v128/v256/v512, v128/v256/v512, v128/v256/v512/mem, imm8");
|
||||
|
||||
// SSE4.2 and VEX versions (no EVEX PCMPGTQ)
|
||||
// Wish I could split crc32[l,q] here since it's got weird encodings, but AT&T does it's suffixes off of
|
||||
// the source here, which I thought was worse. Ideally this has no suffixes anyway.
|
||||
reg_instr_clob(target, "crc32", cc_flag_mask, "rw:r32/r64, r8/r16/r32/r64/mem");
|
||||
reg_instr_clob(target, "pcmpestri", rcx_cc_mask, "v128, v128, imm8");
|
||||
reg_instr_clob(target, "vpcmpestri", rcx_cc_mask, "v128, v128, imm8");
|
||||
reg_instr_clob(target, "pcmpestrm", xmm0_cc_mask, "v128, v128, imm8");
|
||||
reg_instr_clob(target, "vpcmpestrm", xmm0_cc_mask, "v128, v128, imm8");
|
||||
reg_instr_clob(target, "pcmpistri", rcx_cc_mask, "v128, v128, imm8");
|
||||
reg_instr_clob(target, "vpcmpistri", rcx_cc_mask, "v128, v128, imm8");
|
||||
reg_instr_clob(target, "popcnt", cc_flag_mask, "w:r16/r32/r64, r16/r32/r64/mem");
|
||||
reg_instr(target, "pcmpgtq", "rw:v128, v128/mem");
|
||||
reg_instr(target, "vpcmpgtq", "w:v128/v256, v128/v256, v128/v256/mem");
|
||||
|
||||
// VZERO*
|
||||
reg_instr_clob(target, "vzeroupper", lo16_vec_mask, NULL);
|
||||
reg_instr_clob(target, "vzeroall", lo16_vec_mask, NULL);
|
||||
|
||||
// AES VAES
|
||||
reg_instr(target, "aesdec", "rw:v128, v128/mem");
|
||||
reg_instr(target, "vaesdec", "w:v128/v256/v512, v128/v256/v512, v128/v256/v512/mem");
|
||||
reg_instr(target, "aesdeclast", "rw:v128, v128/mem");
|
||||
reg_instr(target, "vaesdeclast", "w:v128/v256/v512, v128/v256/v512, v128/v256/v512/mem");
|
||||
reg_instr(target, "aesenc", "rw:v128, v128/mem");
|
||||
reg_instr(target, "vaesenc", "w:v128/v256/v512, v128/v256/v512, v128/v256/v512/mem");
|
||||
reg_instr(target, "aesenclast", "rw:v128, v128/mem");
|
||||
reg_instr(target, "vaesenclast", "w:v128/v256/v512, v128/v256/v512, v128/v256/v512/mem");
|
||||
reg_instr(target, "aesimc", "w:v128, v128/mem");
|
||||
reg_instr(target, "vaesimc", "w:v128, v128/mem");
|
||||
reg_instr(target, "aeskeygenassist", "w:v128, v128/mem, imm8");
|
||||
reg_instr(target, "vaeskeygenassist", "w:v128, v128/mem, imm8");
|
||||
|
||||
// AESKLE
|
||||
reg_instr_clob(target, "aesdec128kl", cc_flag_mask, "rw:v128, mem"); // 384 bit mem load
|
||||
reg_instr_clob(target, "aesdec256kl", cc_flag_mask, "rw:v128, mem"); // 512 bit mem load
|
||||
reg_instr_clob(target, "aesenc128kl", cc_flag_mask, "rw:v128, mem"); // 384 bit mem load
|
||||
reg_instr_clob(target, "aesenc256kl", cc_flag_mask, "rw:v128, mem"); // 512 bit mem load
|
||||
reg_instr_clob(target, "encodekey128", xmm_0_2_xmm_4_6_cc_mask, "r32, r32");
|
||||
reg_instr_clob(target, "encodekey256", xmm_0_6_cc_mask, "r32, r32");
|
||||
|
||||
// AES_WIDE
|
||||
reg_instr_clob(target, "aesdecwide128kl", xmm_0_7_cc_mask, "mem"); // 384 bit mem load
|
||||
reg_instr_clob(target, "aesdecwide256kl", xmm_0_7_cc_mask, "mem"); // 512 bit mem load
|
||||
reg_instr_clob(target, "aesencwide128kl", xmm_0_7_cc_mask, "mem"); // 384 bit mem load
|
||||
reg_instr_clob(target, "aesencwide256kl", xmm_0_7_cc_mask, "mem"); // 512 bit mem load
|
||||
|
||||
// KEY_LOCKER
|
||||
reg_instr_clob(target, "loadiwkey", rax_xmm0_cc_mask, "v128, v128");
|
||||
|
||||
// SHA
|
||||
reg_instr(target, "sha1msg1", "rw:v128, v128/mem");
|
||||
reg_instr(target, "sha1msg2", "rw:v128, v128/mem");
|
||||
reg_instr(target, "sha1nexte", "rw:v128, v128/mem");
|
||||
reg_instr(target, "sha1rnds4", "rw:v128, v128/mem, imm8");
|
||||
reg_instr(target, "sha256msg1", "rw:v128, v128/mem");
|
||||
reg_instr(target, "sha256msg2", "rw:v128, v128/mem");
|
||||
reg_instr_clob(target, "sha256rnds2", xmm0_mask, "rw:v128, v128/mem");
|
||||
|
||||
// SHA512
|
||||
reg_instr(target, "vsha512msg1", "rw:v256, v128");
|
||||
reg_instr(target, "vsha512msg2", "rw:v256, v256");
|
||||
reg_instr(target, "vsha512rnds2", "rw:v256, v256, v128");
|
||||
|
||||
// SM3
|
||||
reg_instr(target, "vsm3msg1", "rw:v128, v128, v128/mem");
|
||||
reg_instr(target, "vsm3msg2", "rw:v128, v128, v128/mem");
|
||||
reg_instr(target, "vsm3rnds2", "rw:v128, v128, v128/mem, imm8");
|
||||
|
||||
// SM4
|
||||
reg_instr(target, "vsm4key4", "w:v128/v256, v128/v256, v128/v256/mem");
|
||||
reg_instr(target, "vsm4rnds4", "w:v128/v256, v128/v256, v128/v256/mem");
|
||||
|
||||
// RDRAND
|
||||
reg_instr_clob(target, "rdrand", cc_flag_mask, "w:r16/r32/r64");
|
||||
|
||||
// RDSEED
|
||||
reg_instr_clob(target, "rdseed", cc_flag_mask, "w:r16/r32/r64");
|
||||
|
||||
target->clobber_name_list = X86ClobberNames;
|
||||
target->extra_clobbers = "~{flags},~{dirflag},~{fspr}";
|
||||
|
||||
@@ -68,8 +68,8 @@ Decl *decl_new_with_type(const char *name, SourceSpan span, DeclKind decl_type)
|
||||
case DECL_ENUM:
|
||||
kind = TYPE_ENUM;
|
||||
break;
|
||||
case DECL_CONST_ENUM:
|
||||
kind = TYPE_CONST_ENUM;
|
||||
case DECL_CONSTDEF:
|
||||
kind = TYPE_CONSTDEF;
|
||||
break;
|
||||
case DECL_TYPEDEF:
|
||||
kind = TYPE_TYPEDEF;
|
||||
@@ -127,7 +127,7 @@ const char *decl_to_a_name(Decl *decl)
|
||||
case DECL_ALIAS: case DECL_ALIAS_PATH: case DECL_TYPE_ALIAS: return "an alias";
|
||||
case DECL_TYPEDEF: return "a distinct type";
|
||||
case DECL_ENUM: return "an enum";
|
||||
case DECL_CONST_ENUM: return "a raw enum";
|
||||
case DECL_CONSTDEF: return "a set of constants";
|
||||
case DECL_ENUM_CONSTANT: return "an enum value";
|
||||
case DECL_ERASED: return "an erased declaration";
|
||||
case DECL_FAULT: return "a fault";
|
||||
@@ -143,6 +143,7 @@ const char *decl_to_a_name(Decl *decl)
|
||||
case DECL_INTERFACE: return "an interface";
|
||||
case DECL_STRUCT: return "a struct";
|
||||
case DECL_UNION: return "a union";
|
||||
case DECL_CONTRACT: return "a contract";
|
||||
case DECL_VAR:
|
||||
switch (decl->var.kind)
|
||||
{
|
||||
@@ -346,7 +347,8 @@ bool decl_may_be_generic(Decl *decl)
|
||||
case DECL_GENERIC_INSTANCE:
|
||||
case DECL_IMPORT:
|
||||
case DECL_LABEL:
|
||||
case DECL_CONST_ENUM:
|
||||
case DECL_CONSTDEF:
|
||||
case DECL_CONTRACT:
|
||||
return false;
|
||||
case DECL_ATTRIBUTE:
|
||||
case DECL_BITSTRUCT:
|
||||
@@ -548,53 +550,6 @@ bool ast_supports_continue(Ast *stmt)
|
||||
return stmt->for_stmt.cond || !stmt->flow.skip_first;
|
||||
}
|
||||
|
||||
Ast *ast_contract_has_any(AstId contracts)
|
||||
{
|
||||
while (contracts)
|
||||
{
|
||||
Ast *current = astptr(contracts);
|
||||
contracts = current->next;
|
||||
ASSERT(current->ast_kind == AST_CONTRACT);
|
||||
switch (current->contract_stmt.kind)
|
||||
{
|
||||
case CONTRACT_UNKNOWN:
|
||||
case CONTRACT_PURE:
|
||||
case CONTRACT_PARAM:
|
||||
case CONTRACT_OPTIONALS:
|
||||
case CONTRACT_ENSURE:
|
||||
case CONTRACT_REQUIRE:
|
||||
return current;
|
||||
case CONTRACT_COMMENT:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Ast *ast_contract_has_any_non_require(AstId contracts)
|
||||
{
|
||||
while (contracts)
|
||||
{
|
||||
Ast *current = astptr(contracts);
|
||||
contracts = current->next;
|
||||
ASSERT(current->ast_kind == AST_CONTRACT);
|
||||
switch (current->contract_stmt.kind)
|
||||
{
|
||||
case CONTRACT_UNKNOWN:
|
||||
case CONTRACT_PURE:
|
||||
case CONTRACT_PARAM:
|
||||
case CONTRACT_OPTIONALS:
|
||||
case CONTRACT_ENSURE:
|
||||
return current;
|
||||
case CONTRACT_REQUIRE:
|
||||
case CONTRACT_COMMENT:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void scratch_buffer_append_but_mangle_underscore_dot(const char *name, const char *end, const char *suffix)
|
||||
{
|
||||
char c;
|
||||
|
||||
@@ -95,7 +95,7 @@ static const char *c_type_name(GenContext *c, Type *type)
|
||||
case TYPE_FUNC_RAW:
|
||||
case TYPE_ALIAS:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
case TYPE_UNTYPED_LIST:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
case TYPE_INFERRED_VECTOR:
|
||||
@@ -149,7 +149,7 @@ static bool c_emit_type_decl(GenContext *c, Type *type)
|
||||
case TYPE_FUNC_RAW:
|
||||
case TYPE_ALIAS:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
case TYPE_UNTYPED_LIST:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
case TYPE_INFERRED_VECTOR:
|
||||
@@ -654,7 +654,7 @@ static void c_emit_local_decl(GenContext *c, Decl *decl, CValue *value)
|
||||
case TYPE_POISONED:
|
||||
case TYPE_VOID:
|
||||
case TYPE_TYPEDEF:
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
case TYPE_FUNC_RAW:
|
||||
case TYPE_BITSTRUCT:
|
||||
case TYPE_ALIAS:
|
||||
@@ -858,10 +858,6 @@ static void c_emit_stmt(GenContext *c, Ast *stmt)
|
||||
break;
|
||||
case AST_NEXTCASE_STMT:
|
||||
break;
|
||||
case AST_CONTRACT:
|
||||
break;
|
||||
case AST_CONTRACT_FAULT:
|
||||
break;
|
||||
}
|
||||
PRINT("/* TODO */\n");
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ static inline LoweredType *type_lowering(Type *type)
|
||||
case TYPE_TYPEDEF:
|
||||
type = type->decl->distinct->type;
|
||||
continue;
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
case TYPE_ENUM:
|
||||
type = enum_inner_type(type);
|
||||
continue;
|
||||
@@ -106,7 +106,7 @@ static inline LoweredType *type_lowering_abi(Type *type)
|
||||
case TYPE_TYPEDEF:
|
||||
type = type->decl->distinct->type;
|
||||
continue;
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
case TYPE_ENUM:
|
||||
type = enum_inner_type(type);
|
||||
continue;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "compiler_internal.h"
|
||||
#include "../build/project.h"
|
||||
#include "../utils/json.h"
|
||||
#include <compiler_tests/benchmark.h>
|
||||
#include "../utils/whereami.h"
|
||||
#if LLVM_AVAILABLE
|
||||
@@ -1004,6 +1005,50 @@ void vendor_fetch(BuildOptions *options)
|
||||
const char** fetched_libraries = NULL;
|
||||
int total_libraries = (int)vec_size(options->libraries_to_fetch);
|
||||
|
||||
if (total_libraries == 0)
|
||||
{
|
||||
const char *tmp_dir = dir_make_temp_dir();
|
||||
const char *tmp_file = file_append_path(tmp_dir, "vendor_list.json");
|
||||
const char *error = download_file("https://api.github.com", "/repos/c3lang/vendor/contents/libraries/", tmp_file);
|
||||
if (error)
|
||||
{
|
||||
error_exit("Failed to fetch library list: %s", error);
|
||||
}
|
||||
|
||||
size_t size;
|
||||
char *json_str = file_read_all(tmp_file, &size);
|
||||
JsonParser parser;
|
||||
json_init_string(&parser, json_str);
|
||||
JSONObject *obj = json_parse(&parser);
|
||||
if (!obj || obj->type != J_ARRAY)
|
||||
{
|
||||
error_exit("Failed to parse library list.");
|
||||
}
|
||||
|
||||
printf("Available vendor libraries:\n");
|
||||
FOREACH(JSONObject *, entry, obj->elements)
|
||||
{
|
||||
JSONObject *name = json_map_get(entry, "name");
|
||||
JSONObject *type = json_map_get(entry, "type");
|
||||
if (name && type && str_eq(type->str, "dir"))
|
||||
{
|
||||
const char *n = name->str;
|
||||
if (n[0] == '.') continue;
|
||||
if (str_has_suffix(n, ".c3l"))
|
||||
{
|
||||
printf(" %s\n", str_remove_suffix(n, ".c3l"));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" %s\n", n);
|
||||
}
|
||||
}
|
||||
}
|
||||
file_delete_file(tmp_file);
|
||||
file_delete_dir(tmp_dir);
|
||||
return;
|
||||
}
|
||||
|
||||
for(int i = 0; i < total_libraries; i++)
|
||||
{
|
||||
const char *lib = options->libraries_to_fetch[i];
|
||||
@@ -1784,6 +1829,7 @@ static bool is_posix(OsType os)
|
||||
case OS_TYPE_FREEBSD:
|
||||
case OS_TYPE_OPENBSD:
|
||||
case OS_TYPE_SOLARIS:
|
||||
case OS_TYPE_ANDROID:
|
||||
return true;
|
||||
case OS_TYPE_WIN32:
|
||||
case OS_TYPE_WASI:
|
||||
|
||||
@@ -562,10 +562,10 @@ typedef struct
|
||||
OperatorOverload operator : 6;
|
||||
Signature signature;
|
||||
AstId body;
|
||||
AstId docs;
|
||||
DeclId docs;
|
||||
union
|
||||
{
|
||||
struct
|
||||
struct // Function related
|
||||
{
|
||||
bool attr_inline : 1;
|
||||
bool attr_noinline : 1;
|
||||
@@ -593,7 +593,7 @@ typedef struct
|
||||
Decl **lambda_ct_parameters;
|
||||
};
|
||||
};
|
||||
struct
|
||||
struct // Macro related
|
||||
{
|
||||
DeclId body_param;
|
||||
CompilationUnit *unit;
|
||||
@@ -604,7 +604,7 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
Signature signature;
|
||||
AstId docs;
|
||||
DeclId docs;
|
||||
} FnTypeDecl;
|
||||
|
||||
|
||||
@@ -617,8 +617,8 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
const char **parameters;
|
||||
AstId contracts;
|
||||
unsigned id;
|
||||
Expr **requires;
|
||||
Decl **instances;
|
||||
Decl *owner;
|
||||
Decl **decls;
|
||||
@@ -655,6 +655,34 @@ typedef struct
|
||||
};
|
||||
} DefineDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SourceSpan span;
|
||||
const char *name;
|
||||
InOutModifier modifier : 4;
|
||||
bool by_ref : 1;
|
||||
} ContractParam;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *decl_exprs;
|
||||
const char *comment;
|
||||
const char *expr_string;
|
||||
} ExprContract;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr **requires;
|
||||
Expr **ensures;
|
||||
ContractParam *params;
|
||||
bool pure;
|
||||
union
|
||||
{
|
||||
Expr **opt_returns;
|
||||
Decl **opt_returns_resolved;
|
||||
};
|
||||
} ContractsDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Path *alias_path;
|
||||
@@ -775,6 +803,7 @@ typedef struct Decl_
|
||||
Ast *ct_echo_decl;
|
||||
Decl** ct_else_decl;
|
||||
Decl** decls;
|
||||
ContractsDecl contracts_decl;
|
||||
DefineDecl define_decl;
|
||||
ModuleAliasDecl module_alias_decl;
|
||||
EnumConstantDecl enum_constant;
|
||||
@@ -1272,6 +1301,7 @@ struct Expr_
|
||||
ExprBuiltin builtin_expr; // 16
|
||||
ExprCall call_expr; // 40
|
||||
ExprCast cast_expr; // 12
|
||||
ExprContract contract_expr;
|
||||
ExprUnresolvedCatch unresolved_catch_expr; // 24
|
||||
ExprCatch catch_expr; // 24
|
||||
Expr** cond_expr; // 8
|
||||
@@ -1565,49 +1595,6 @@ typedef struct
|
||||
} AstAssertStmt;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool resolved;
|
||||
bool expanding;
|
||||
union
|
||||
{
|
||||
Expr *expr;
|
||||
Decl *decl;
|
||||
};
|
||||
} AstDocFault;
|
||||
|
||||
typedef struct AstDocDirective_
|
||||
{
|
||||
ContractKind kind : 4;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
const char *name;
|
||||
SourceSpan span;
|
||||
InOutModifier modifier : 4;
|
||||
bool by_ref : 1;
|
||||
} param;
|
||||
Ast **faults;
|
||||
struct
|
||||
{
|
||||
Expr *decl_exprs;
|
||||
const char *comment;
|
||||
const char *expr_string;
|
||||
} contract;
|
||||
struct
|
||||
{
|
||||
const char *directive_name;
|
||||
const char *rest_of_line;
|
||||
} generic;
|
||||
struct
|
||||
{
|
||||
const char *string;
|
||||
size_t strlen;
|
||||
};
|
||||
};
|
||||
} AstContractStmt;
|
||||
|
||||
typedef struct Ast_
|
||||
{
|
||||
SourceSpan span;
|
||||
@@ -1625,8 +1612,6 @@ typedef struct Ast_
|
||||
AstCompoundStmt compound_stmt; // 12
|
||||
AstId ct_compound_stmt;
|
||||
AstContinueBreakStmt contbreak_stmt;// 24
|
||||
AstContractStmt contract_stmt; // 32
|
||||
AstDocFault contract_fault; // 24
|
||||
AstId ct_else_stmt; // 4
|
||||
AstCtTypeAssignStmt ct_type_assign_stmt;
|
||||
AstCtForeachStmt ct_foreach_stmt; // 40
|
||||
@@ -2174,8 +2159,6 @@ bool ast_is_not_empty(Ast *ast);
|
||||
|
||||
bool ast_is_compile_time(Ast *ast);
|
||||
bool ast_supports_continue(Ast *stmt);
|
||||
Ast *ast_contract_has_any(AstId contracts);
|
||||
Ast *ast_contract_has_any_non_require(AstId contracts);
|
||||
INLINE void ast_append(AstId **succ, Ast *next);
|
||||
INLINE void ast_prepend(AstId *first, Ast *ast);
|
||||
INLINE bool ast_ok(Ast *ast);
|
||||
@@ -2299,6 +2282,7 @@ UNUSED bool i128_get_bit(const Int128 *op, int bit);
|
||||
void copy_begin(void);
|
||||
void copy_end(void);
|
||||
Expr *copy_expr_single(Expr *source_expr);
|
||||
Expr **copy_exprlist_macro(Expr **source_expr_list);
|
||||
Decl **copy_decl_list_single(Decl **decl_list);
|
||||
Decl **copy_decl_list_single_for_generic(Decl **decl_list, Decl *generic_instance);
|
||||
Attr **copy_attributes_single(Attr** attr_list);
|
||||
@@ -2907,7 +2891,7 @@ INLINE bool type_may_implement_interface(Type *type)
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
case TYPE_TYPEDEF:
|
||||
case TYPE_BITSTRUCT:
|
||||
return true;
|
||||
@@ -3006,7 +2990,7 @@ INLINE bool type_is_atomic(Type *type_flat)
|
||||
case ALL_SIGNED_INTS:
|
||||
case ALL_FLOATS:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
case TYPE_ANYFAULT:
|
||||
case TYPE_TYPEID:
|
||||
case TYPE_BOOL:
|
||||
@@ -3107,7 +3091,7 @@ INLINE const char *type_invalid_storage_type_name(Type *type)
|
||||
|
||||
INLINE Type *enum_inner_type(Type *enum_type)
|
||||
{
|
||||
assert(enum_type->type_kind == TYPE_ENUM || enum_type->type_kind == TYPE_CONST_ENUM);
|
||||
assert(enum_type->type_kind == TYPE_ENUM || enum_type->type_kind == TYPE_CONSTDEF);
|
||||
return enum_type->decl->enums.type_info->type;
|
||||
}
|
||||
|
||||
@@ -3174,7 +3158,7 @@ INLINE Type *type_flatten_for_bitstruct(Type *type)
|
||||
{
|
||||
type = type->decl->distinct->type;
|
||||
}
|
||||
if (type->type_kind == TYPE_ENUM || type->type_kind == TYPE_CONST_ENUM)
|
||||
if (type->type_kind == TYPE_ENUM || type->type_kind == TYPE_CONSTDEF)
|
||||
{
|
||||
type = enum_inner_type(type)->canonical;
|
||||
goto RETRY;
|
||||
@@ -3233,7 +3217,7 @@ static inline Type *type_base(Type *type)
|
||||
type = type->decl->distinct->type;
|
||||
break;
|
||||
case TYPE_ENUM:
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
type = enum_inner_type(type);
|
||||
break;
|
||||
case TYPE_OPTIONAL:
|
||||
@@ -3250,7 +3234,7 @@ static inline Type *type_base(Type *type)
|
||||
|
||||
static const bool is_distinct_like[TYPE_LAST + 1] = {
|
||||
[TYPE_ENUM] = true,
|
||||
[TYPE_CONST_ENUM] = true,
|
||||
[TYPE_CONSTDEF] = true,
|
||||
[TYPE_TYPEDEF] = true
|
||||
};
|
||||
|
||||
@@ -3305,7 +3289,7 @@ static inline Type *type_flatten_and_inline(Type *type)
|
||||
case TYPE_TYPEDEF:
|
||||
type = type->decl->distinct->type;
|
||||
continue;
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
type = type->decl->enums.type_info->type;
|
||||
continue;
|
||||
case TYPE_ENUM:
|
||||
@@ -3337,7 +3321,7 @@ static inline Type *type_flat_distinct_enum_inline(Type *type)
|
||||
if (!decl->is_substruct) return type;;
|
||||
type = decl->distinct->type;
|
||||
continue;
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
decl = type->decl;
|
||||
if (!decl->is_substruct) return type;
|
||||
type = decl->enums.type_info->type;
|
||||
@@ -3362,7 +3346,7 @@ INLINE bool type_is_user_defined(Type *type)
|
||||
{
|
||||
static const bool user_defined_types[TYPE_LAST + 1] = {
|
||||
[TYPE_ENUM] = true,
|
||||
[TYPE_CONST_ENUM] = true,
|
||||
[TYPE_CONSTDEF] = true,
|
||||
[TYPE_STRUCT] = true,
|
||||
[TYPE_FUNC_RAW] = true,
|
||||
[TYPE_UNION] = true,
|
||||
@@ -3404,7 +3388,7 @@ static inline Type *type_flatten_to_int(Type *type)
|
||||
case TYPE_BITSTRUCT:
|
||||
type = type->decl->strukt.container_type->type;
|
||||
break;
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
type = type->decl->enums.type_info->type;
|
||||
break;
|
||||
case TYPE_ENUM:
|
||||
@@ -3431,7 +3415,7 @@ static inline CanonicalType *type_distinct_inline(Type *type)
|
||||
case TYPE_ENUM:
|
||||
if (!type->decl->is_substruct) return type;
|
||||
FALLTHROUGH;
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
type = enum_inner_type(type);
|
||||
break;
|
||||
case TYPE_TYPEDEF:
|
||||
@@ -3454,7 +3438,7 @@ static inline FlatType *type_flatten(Type *type)
|
||||
type = type->canonical;
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
type = enum_inner_type(type);
|
||||
break;
|
||||
case TYPE_TYPEDEF:
|
||||
@@ -3485,7 +3469,7 @@ static inline Type *type_flatten_no_export(Type *type)
|
||||
if (type->decl->is_export) return type;
|
||||
type = type->decl->distinct->type;
|
||||
break;
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
if (type->decl->is_export) return type;
|
||||
type = enum_inner_type(type);
|
||||
break;
|
||||
@@ -3595,7 +3579,7 @@ static inline Type *type_flat_for_arithmethics(Type *type)
|
||||
case TYPE_OPTIONAL:
|
||||
type = type->optional;
|
||||
continue;
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
case TYPE_TYPEDEF:
|
||||
inner = type_inline(type);
|
||||
if (type->decl->is_substruct)
|
||||
@@ -3978,6 +3962,7 @@ static inline void expr_set_span(Expr *expr, SourceSpan loc)
|
||||
case EXPR_RVALUE:
|
||||
case EXPR_CT_SUBSCRIPT:
|
||||
case EXPR_IOTA_DECL:
|
||||
case EXPR_CONTRACT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -4328,7 +4313,7 @@ INLINE void expr_rewrite_const_int(Expr *expr, Type *type, uint64_t v)
|
||||
expr->type = type;
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
TypeKind kind = type_flatten(type)->type_kind;
|
||||
(&expr->const_expr)->ixx.i.high = 0;
|
||||
expr->const_expr.ixx.i.high = 0;
|
||||
if (type_kind_is_signed(kind))
|
||||
{
|
||||
if (v > (uint64_t)INT64_MAX) (&expr->const_expr)->ixx.i.high = UINT64_MAX;
|
||||
@@ -4350,10 +4335,10 @@ INLINE void expr_rewrite_const_int(Expr *expr, Type *type, uint64_t v)
|
||||
break;
|
||||
}
|
||||
}
|
||||
(&expr->const_expr)->ixx.i.low = v;
|
||||
(&expr->const_expr)->ixx.type = kind;
|
||||
(&expr->const_expr)->is_character = false;
|
||||
(&expr->const_expr)->const_kind = CONST_INTEGER;
|
||||
expr->const_expr.ixx.i.low = v;
|
||||
expr->const_expr.ixx.type = kind;
|
||||
expr->const_expr.is_character = false;
|
||||
expr->const_expr.const_kind = CONST_INTEGER;
|
||||
}
|
||||
|
||||
INLINE void expr_rewrite_to_int_to_float(Expr *expr, Type *type)
|
||||
|
||||
@@ -159,12 +159,13 @@ void decl_register(CompilationUnit *unit, Decl *decl)
|
||||
case DECL_IMPORT:
|
||||
case DECL_LABEL:
|
||||
case DECL_POISONED:
|
||||
case DECL_CONTRACT:
|
||||
UNREACHABLE_VOID
|
||||
case DECL_ATTRIBUTE:
|
||||
case DECL_BITSTRUCT:
|
||||
case DECL_TYPEDEF:
|
||||
case DECL_ENUM:
|
||||
case DECL_CONST_ENUM:
|
||||
case DECL_CONSTDEF:
|
||||
case DECL_STRUCT:
|
||||
case DECL_TYPE_ALIAS:
|
||||
case DECL_UNION:
|
||||
@@ -273,7 +274,7 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl)
|
||||
vec_add(unit->generic_defines, decl);
|
||||
decl_register(unit, decl);
|
||||
return;
|
||||
case DECL_CONST_ENUM:
|
||||
case DECL_CONSTDEF:
|
||||
case DECL_ENUM:
|
||||
ASSERT(decl->name);
|
||||
vec_add(unit->enums, decl);
|
||||
@@ -293,6 +294,7 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl)
|
||||
case DECL_GENERIC_INSTANCE:
|
||||
case DECL_IMPORT:
|
||||
case DECL_LABEL:
|
||||
case DECL_CONTRACT:
|
||||
UNREACHABLE_VOID
|
||||
case DECL_CT_EXEC:
|
||||
case DECL_CT_INCLUDE:
|
||||
|
||||
@@ -193,6 +193,13 @@ Expr *copy_expr_single(Expr *source_expr)
|
||||
return expr;
|
||||
}
|
||||
|
||||
Expr **copy_exprlist_macro(Expr **source_expr_list)
|
||||
{
|
||||
ASSERT(copy_struct.copy_in_use);
|
||||
Expr **list = copy_expr_list(©_struct, source_expr_list);
|
||||
return list;
|
||||
}
|
||||
|
||||
void copy_range(CopyStruct *c, Range *range)
|
||||
{
|
||||
switch (range->range_type)
|
||||
@@ -306,6 +313,9 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
MACRO_COPY_EXPR(expr->two_expr.first);
|
||||
MACRO_COPY_EXPR(expr->two_expr.last);
|
||||
return expr;
|
||||
case EXPR_CONTRACT:
|
||||
MACRO_COPY_EXPR(expr->contract_expr.decl_exprs);
|
||||
return expr;
|
||||
case EXPR_TYPECALL:
|
||||
case EXPR_CT_SUBSCRIPT:
|
||||
UNREACHABLE
|
||||
@@ -607,24 +617,6 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
void doc_ast_copy(CopyStruct *c, AstContractStmt *doc)
|
||||
{
|
||||
switch (doc->kind)
|
||||
{
|
||||
case CONTRACT_REQUIRE:
|
||||
case CONTRACT_ENSURE:
|
||||
MACRO_COPY_EXPR(doc->contract.decl_exprs);
|
||||
break;
|
||||
case CONTRACT_OPTIONALS:
|
||||
MACRO_COPY_AST_LIST(doc->faults);
|
||||
break;
|
||||
case CONTRACT_PARAM:
|
||||
case CONTRACT_PURE:
|
||||
case CONTRACT_UNKNOWN:
|
||||
case CONTRACT_COMMENT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_expr_asm_arg(CopyStruct *c, ExprAsmArg *arg)
|
||||
{
|
||||
@@ -683,19 +675,6 @@ RETRY:
|
||||
case AST_DECLS_STMT:
|
||||
MACRO_COPY_DECL_LIST(ast->decls_stmt);
|
||||
break;
|
||||
case AST_CONTRACT_FAULT:
|
||||
if (ast->contract_fault.resolved)
|
||||
{
|
||||
fixup_decl(c, &ast->contract_fault.decl);
|
||||
}
|
||||
else
|
||||
{
|
||||
MACRO_COPY_EXPR(ast->contract_fault.expr);
|
||||
}
|
||||
break;
|
||||
case AST_CONTRACT:
|
||||
doc_ast_copy(c, &source->contract_stmt);
|
||||
break;
|
||||
case AST_ASM_BLOCK_STMT:
|
||||
if (ast->asm_block_stmt.is_string)
|
||||
{
|
||||
@@ -1079,6 +1058,18 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
case DECL_GENERIC:
|
||||
case DECL_GENERIC_INSTANCE:
|
||||
UNREACHABLE;
|
||||
case DECL_CONTRACT:
|
||||
MACRO_COPY_EXPR_LIST(copy->contracts_decl.requires);
|
||||
MACRO_COPY_EXPR_LIST(copy->contracts_decl.ensures);
|
||||
if (copy->resolve_status == RESOLVE_DONE)
|
||||
{
|
||||
MACRO_COPY_DECL_LIST(copy->contracts_decl.opt_returns_resolved);
|
||||
}
|
||||
else
|
||||
{
|
||||
MACRO_COPY_EXPR_LIST(copy->contracts_decl.opt_returns);
|
||||
}
|
||||
break;
|
||||
case DECL_INTERFACE:
|
||||
copy_decl_type(copy);
|
||||
MACRO_COPY_TYPE_LIST(copy->interfaces);
|
||||
@@ -1117,7 +1108,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
break;
|
||||
case DECL_FAULT:
|
||||
break;
|
||||
case DECL_CONST_ENUM:
|
||||
case DECL_CONSTDEF:
|
||||
copy_decl_type(copy);
|
||||
MACRO_COPY_TYPE_LIST(copy->interfaces);
|
||||
MACRO_COPY_DECL_METHODS(copy->method_table);
|
||||
@@ -1139,7 +1130,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
case DECL_FUNC:
|
||||
copy_decl_type(copy);
|
||||
MACRO_COPY_TYPEID(copy->func_decl.type_parent);
|
||||
MACRO_COPY_ASTID(copy->func_decl.docs);
|
||||
MACRO_COPY_DECLID(copy->func_decl.docs);
|
||||
copy_signature_deep(c, ©->func_decl.signature);
|
||||
MACRO_COPY_ASTID(copy->func_decl.body);
|
||||
break;
|
||||
@@ -1204,7 +1195,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
case DECL_ALIAS_PATH:
|
||||
break;
|
||||
case DECL_MACRO:
|
||||
MACRO_COPY_ASTID(copy->func_decl.docs);
|
||||
MACRO_COPY_DECLID(copy->func_decl.docs);
|
||||
MACRO_COPY_TYPEID(decl->func_decl.type_parent);
|
||||
copy_signature_deep(c, ©->func_decl.signature);
|
||||
MACRO_COPY_ASTID(decl->func_decl.body);
|
||||
|
||||
@@ -317,7 +317,7 @@ void print_deprecation_at(SourceSpan loc, const char *message, ...)
|
||||
if (!compiler.build.lsp_output && !deprecation_hint)
|
||||
{
|
||||
deprecation_hint = true;
|
||||
eprintf("HINT: You may use --silence-deprecation to silence deprecation warnings.\n\n");
|
||||
eprintf("HINT: You may use --warn-deprecation=no to silence deprecation warnings.\n\n");
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@@ -553,8 +553,6 @@ typedef enum
|
||||
AST_CASE_STMT,
|
||||
AST_COMPOUND_STMT,
|
||||
AST_CONTINUE_STMT,
|
||||
AST_CONTRACT,
|
||||
AST_CONTRACT_FAULT,
|
||||
AST_CT_ASSERT,
|
||||
AST_CT_COMPOUND_STMT,
|
||||
AST_CT_ECHO_STMT,
|
||||
@@ -973,17 +971,6 @@ typedef enum
|
||||
CONST_MEMBER,
|
||||
} ConstKind;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CONTRACT_UNKNOWN,
|
||||
CONTRACT_COMMENT,
|
||||
CONTRACT_PURE,
|
||||
CONTRACT_REQUIRE,
|
||||
CONTRACT_PARAM,
|
||||
CONTRACT_OPTIONALS,
|
||||
CONTRACT_ENSURE,
|
||||
} ContractKind;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CONV_NO = -1,
|
||||
@@ -1034,6 +1021,7 @@ typedef enum
|
||||
DECL_CT_EXEC,
|
||||
DECL_CT_INCLUDE,
|
||||
DECL_DECLARRAY,
|
||||
DECL_CONTRACT,
|
||||
DECL_ALIAS,
|
||||
DECL_ALIAS_PATH,
|
||||
DECL_TYPEDEF,
|
||||
@@ -1050,7 +1038,7 @@ typedef enum
|
||||
DECL_LABEL,
|
||||
DECL_MACRO,
|
||||
DECL_INTERFACE,
|
||||
DECL_CONST_ENUM,
|
||||
DECL_CONSTDEF,
|
||||
DECL_STRUCT,
|
||||
DECL_TYPE_ALIAS,
|
||||
DECL_UNION,
|
||||
@@ -1117,6 +1105,7 @@ typedef enum
|
||||
EXPR_COMPOUND_LITERAL,
|
||||
EXPR_COND,
|
||||
EXPR_CONST,
|
||||
EXPR_CONTRACT,
|
||||
EXPR_CT_ARG,
|
||||
EXPR_CT_ASSIGNABLE,
|
||||
EXPR_CT_CALL,
|
||||
@@ -1225,7 +1214,7 @@ typedef enum
|
||||
INTROSPECT_TYPE_ANYFAULT = 6,
|
||||
INTROSPECT_TYPE_ANY = 7,
|
||||
INTROSPECT_TYPE_ENUM = 8,
|
||||
INTROSPECT_TYPE_CONST_ENUM = 9,
|
||||
INTROSPECT_TYPE_CONSTDEF = 9,
|
||||
INTROSPECT_TYPE_STRUCT = 10,
|
||||
INTROSPECT_TYPE_UNION = 11,
|
||||
INTROSPECT_TYPE_BITSTRUCT = 12,
|
||||
@@ -1579,7 +1568,7 @@ typedef enum
|
||||
TOKEN_BREAK,
|
||||
TOKEN_CASE,
|
||||
TOKEN_CATCH,
|
||||
TOKEN_CENUM,
|
||||
TOKEN_CONSTDEF,
|
||||
TOKEN_CONST,
|
||||
TOKEN_CONTINUE,
|
||||
TOKEN_DEFAULT,
|
||||
@@ -1754,7 +1743,7 @@ typedef enum
|
||||
TYPE_FUNC_PTR,
|
||||
TYPE_POINTER,
|
||||
TYPE_TYPEDEF,
|
||||
TYPE_CONST_ENUM,
|
||||
TYPE_CONSTDEF,
|
||||
TYPE_ENUM,
|
||||
TYPE_FUNC_RAW,
|
||||
TYPE_STRUCT,
|
||||
@@ -2141,7 +2130,7 @@ typedef enum
|
||||
case DECL_DECLARRAY: case DECL_ATTRIBUTE: case DECL_LABEL: \
|
||||
case DECL_ALIAS: case DECL_CT_ASSERT: case DECL_CT_EXEC: case DECL_FAULT: \
|
||||
case DECL_CT_ECHO: case DECL_CT_INCLUDE: case DECL_GROUP: \
|
||||
case DECL_BODYPARAM: case DECL_VAR: case DECL_ENUM_CONSTANT: \
|
||||
case DECL_BODYPARAM: case DECL_VAR: case DECL_ENUM_CONSTANT: case DECL_CONTRACT: \
|
||||
case DECL_POISONED: case DECL_ALIAS_PATH: case DECL_GENERIC: case DECL_GENERIC_INSTANCE
|
||||
|
||||
// -- Expr helper macros
|
||||
@@ -2149,7 +2138,7 @@ typedef enum
|
||||
case EXPR_CT_DEFINED: \
|
||||
case EXPR_CT_ASSIGNABLE: case EXPR_CT_IS_CONST: \
|
||||
case EXPR_CT_ARG: case EXPR_TYPEINFO: case EXPR_HASH_IDENT: \
|
||||
case EXPR_COMPILER_CONST: case EXPR_CT_CALL: \
|
||||
case EXPR_COMPILER_CONST: case EXPR_CT_CALL: case EXPR_CONTRACT: \
|
||||
case EXPR_SPLAT: case EXPR_STRINGIFY: case EXPR_TYPECALL: \
|
||||
case EXPR_CT_EVAL: case EXPR_MAYBE_DEREF
|
||||
|
||||
@@ -2188,7 +2177,7 @@ static_assert(EXPR_LAST < 128, "Too many expression types");
|
||||
|
||||
#define LOWERED_TYPES CT_TYPES: case TYPE_ENUM: case TYPE_ALIAS: case TYPE_TYPEID: \
|
||||
case TYPE_TYPEDEF: case TYPE_ANYFAULT: case TYPE_BITSTRUCT: \
|
||||
case TYPE_OPTIONAL: case TYPE_INTERFACE: case TYPE_CONST_ENUM
|
||||
case TYPE_OPTIONAL: case TYPE_INTERFACE: case TYPE_CONSTDEF
|
||||
|
||||
#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
|
||||
|
||||
@@ -490,6 +490,7 @@ bool expr_is_runtime_const(Expr *expr)
|
||||
case EXPR_ASM:
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
case EXPR_NAMED_ARGUMENT:
|
||||
case EXPR_CONTRACT:
|
||||
UNREACHABLE
|
||||
case EXPR_NOP:
|
||||
return true;
|
||||
@@ -687,7 +688,7 @@ void expr_rewrite_to_const_zero(Expr *expr, Type *type)
|
||||
expr->const_expr.fault = NULL;
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
break;
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
expr_rewrite_const_int(expr, type, 0);
|
||||
return;
|
||||
case TYPE_ENUM:
|
||||
@@ -800,6 +801,7 @@ bool expr_is_pure(Expr *expr)
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case UNRESOLVED_EXPRS:
|
||||
case EXPR_CONTRACT:
|
||||
UNREACHABLE
|
||||
case EXPR_BUILTIN:
|
||||
case EXPR_BENCHMARK_HOOK:
|
||||
|
||||
@@ -164,7 +164,7 @@ static void header_print_type(HeaderContext *c, Type *type)
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
PRINTF("%s", decl_get_extname(type->decl));
|
||||
return;
|
||||
case TYPE_BITSTRUCT:
|
||||
@@ -554,7 +554,7 @@ RETRY:
|
||||
case TYPE_ENUM:
|
||||
header_gen_enum(c, 0, type->decl);
|
||||
return;
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
// TODO;
|
||||
type = type_flatten(type);
|
||||
goto RETRY;
|
||||
|
||||
@@ -17,17 +17,18 @@
|
||||
#define FOREACH_DECL_END } } }
|
||||
#define INSERT_COMMA do { if (first) { first = false; } else { fputs(",\n", file); } } while(0)
|
||||
|
||||
static bool emit_docs(FILE *file, AstId contracts, int tabs)
|
||||
static bool emit_docs(FILE *file, DeclId contracts, int tabs)
|
||||
{
|
||||
if (!contracts) return false;
|
||||
Ast *ast = astptr(contracts);
|
||||
if (ast->contract_stmt.kind != CONTRACT_COMMENT) return false;
|
||||
return false;
|
||||
/*
|
||||
if (!contract->contracts_decl.comment) return false;
|
||||
for (int i = 0; i < tabs; i++) PRINT("\t");
|
||||
PRINT("\"comment\": \"");
|
||||
bool last_is_whitespace = true;
|
||||
for (size_t i = 0; i < ast->contract_stmt.strlen; i++)
|
||||
for (size_t i = 0; i < contract->contracts_decl.comment_len; i++)
|
||||
{
|
||||
unsigned char c = ast->contract_stmt.string[i];
|
||||
unsigned char c = contract->contracts_decl.comment[i];
|
||||
if (char_is_whitespace(c) || c < 31)
|
||||
{
|
||||
if (last_is_whitespace) continue;
|
||||
@@ -56,7 +57,7 @@ static bool emit_docs(FILE *file, AstId contracts, int tabs)
|
||||
}
|
||||
}
|
||||
PRINT("\"");
|
||||
return true;
|
||||
return true;*/
|
||||
}
|
||||
static inline void emit_modules(FILE *file)
|
||||
{
|
||||
@@ -95,7 +96,7 @@ static inline const char *decl_type_to_string(Decl *type)
|
||||
case DECL_STRUCT: return "struct";
|
||||
case DECL_UNION: return "union";
|
||||
case DECL_TYPE_ALIAS: return "type_alias";
|
||||
case DECL_CONST_ENUM: return "raw_enum";
|
||||
case DECL_CONSTDEF: return "constdef";
|
||||
case DECL_BODYPARAM:
|
||||
case DECL_DECLARRAY:
|
||||
case DECL_ERASED:
|
||||
@@ -104,6 +105,7 @@ static inline const char *decl_type_to_string(Decl *type)
|
||||
case DECL_VAR:
|
||||
case DECL_GENERIC:
|
||||
case DECL_GENERIC_INSTANCE:
|
||||
case DECL_CONTRACT:
|
||||
UNREACHABLE
|
||||
}
|
||||
UNREACHABLE
|
||||
|
||||
@@ -355,7 +355,9 @@ static const char *get_linux_crt_arch_glob(void)
|
||||
case LINUX_AARCH64:
|
||||
return "/usr/lib/aarch64*linux*/crt1.o";
|
||||
case LINUX_RISCV32:
|
||||
return "/usr/lib/riscv32*linux*/crt1.o";
|
||||
case LINUX_RISCV64:
|
||||
return "/usr/lib/riscv64*linux*/crt1.o";
|
||||
default:
|
||||
return "/usr/lib/*/crt1.o";
|
||||
}
|
||||
@@ -373,7 +375,9 @@ static const char *get_linux_crt_begin_arch_glob(void)
|
||||
case LINUX_AARCH64:
|
||||
return "/usr/lib/gcc/aarch64*linux*/*/crtbegin.o";
|
||||
case LINUX_RISCV32:
|
||||
return "/usr/lib/gcc/riscv32*linux*/*/crtbegin.o";
|
||||
case LINUX_RISCV64:
|
||||
return "/usr/lib/gcc/riscv64*linux*/*/crtbegin.o";
|
||||
default:
|
||||
return "/usr/lib/gcc/*/*/crtbegin.o";
|
||||
}
|
||||
@@ -382,29 +386,60 @@ static const char *get_linux_crt_begin_arch_glob(void)
|
||||
static const char *find_linux_crt(void)
|
||||
{
|
||||
if (compiler.build.linuxpaths.crt) return compiler.build.linuxpaths.crt;
|
||||
const char *arch_linux_crt1_path = "/usr/lib/crt1.o";
|
||||
const char *arch_linux_64_crt1_path = "/usr/lib64/crt1.o";
|
||||
if (file_exists(arch_linux_crt1_path))
|
||||
{
|
||||
const char *arch_linux_path = "/usr/lib";
|
||||
INFO_LOG("Found crt at %s", arch_linux_path);
|
||||
return arch_linux_path;
|
||||
}
|
||||
if (file_exists(arch_linux_64_crt1_path))
|
||||
{
|
||||
const char* arch_linux_path = "/usr/lib64";
|
||||
INFO_LOG("Found crt at %s", arch_linux_path);
|
||||
return arch_linux_path;
|
||||
}
|
||||
|
||||
const char *arch_glob_path = get_linux_crt_arch_glob();
|
||||
const char *path = find_arch_glob_path(arch_glob_path, 6);
|
||||
if (!path)
|
||||
|
||||
if (compiler.platform.arch == ARCH_TYPE_RISCV64 || compiler.platform.arch == ARCH_TYPE_RISCV32)
|
||||
{
|
||||
INFO_LOG("No crt in /usr/{lib,lib64}/*/");
|
||||
return NULL;
|
||||
const char *is_64 = compiler.platform.arch == ARCH_TYPE_RISCV64 ? "64" : "32";
|
||||
char *p1 = str_printf("/usr/*riscv%s*linux*/usr/lib/crt1.o", is_64);
|
||||
const char *path = find_arch_glob_path(p1, 6);
|
||||
if (path)
|
||||
{
|
||||
INFO_LOG("Found crt at %s", path);
|
||||
return path;
|
||||
}
|
||||
|
||||
char *p2 = str_printf("/usr/lib/riscv%s*linux*/crt1.o", is_64);
|
||||
path = find_arch_glob_path(p2, 6);
|
||||
if (path)
|
||||
{
|
||||
INFO_LOG("Found crt at %s", path);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
INFO_LOG("Found crt at %s", path);
|
||||
return path;
|
||||
else
|
||||
{
|
||||
const char *path = find_arch_glob_path(arch_glob_path, 6);
|
||||
if (path)
|
||||
{
|
||||
INFO_LOG("Found crt at %s", path);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_host_arch = compiler.platform.arch == target_host_arch();
|
||||
|
||||
if (is_host_arch)
|
||||
{
|
||||
const char *arch_linux_crt1_path = "/usr/lib/crt1.o";
|
||||
const char *arch_linux_64_crt1_path = "/usr/lib64/crt1.o";
|
||||
if (file_exists(arch_linux_crt1_path))
|
||||
{
|
||||
const char *arch_linux_path = "/usr/lib";
|
||||
INFO_LOG("Found crt at %s", arch_linux_path);
|
||||
return arch_linux_path;
|
||||
}
|
||||
if (file_exists(arch_linux_64_crt1_path))
|
||||
{
|
||||
const char* arch_linux_path = "/usr/lib64";
|
||||
INFO_LOG("Found crt at %s", arch_linux_path);
|
||||
return arch_linux_path;
|
||||
}
|
||||
}
|
||||
|
||||
INFO_LOG("No crt found in standard paths or via globs.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *find_linux_crt_begin(void)
|
||||
@@ -423,45 +458,57 @@ static const char *find_linux_crt_begin(void)
|
||||
|
||||
static const char *find_linux_ld(void)
|
||||
{
|
||||
if (compiler.platform.environment_type == ENV_TYPE_ANDROID) return "--dynamic-linker=/system/ld-android.so";
|
||||
if (compiler.platform.environment_type == ENV_TYPE_ANDROID) return "/system/ld-android.so";
|
||||
switch (compiler.build.linuxpaths.libc)
|
||||
{
|
||||
case LINUX_LIBC_MUSL:
|
||||
switch (compiler.platform.arch)
|
||||
{
|
||||
case ARCH_TYPE_ARM: return "--dynamic-linker=/lib/ld-musl-arm.so.1";
|
||||
case ARCH_TYPE_ARMB: return "--dynamic-linker=/lib/ld-musl-armeb.so.1";
|
||||
case ARCH_TYPE_AARCH64: return "--dynamic-linker=/lib/ld-musl-aarch64.so.1";
|
||||
case ARCH_TYPE_AARCH64_BE: return "--dynamic-linker=/lib/ld-musl-aarch64_be.so.1";
|
||||
case ARCH_TYPE_MIPS: return "--dynamic-linker=/lib/ld-musl-mips.so.1";
|
||||
case ARCH_TYPE_MIPSEL: return "--dynamic-linker=/lib/ld-musl-mipsel.so.1";
|
||||
case ARCH_TYPE_MIPS64: return "--dynamic-linker=/lib/ld-musl-mips64.so.1";
|
||||
case ARCH_TYPE_MIPS64EL: return "--dynamic-linker=/lib/ld-musl-mips64el.so.1";
|
||||
case ARCH_TYPE_PPC: return "--dynamic-linker=/lib/ld-musl-powerpc.so.1";
|
||||
case ARCH_TYPE_PPC64: return "--dynamic-linker=/lib/ld-musl-powerpc64.so.1";
|
||||
case ARCH_TYPE_RISCV32: return "--dynamic-linker=/lib/ld-musl-riscv32.so.1";
|
||||
case ARCH_TYPE_RISCV64: return "--dynamic-linker=/lib/ld-musl-riscv64.so.1";
|
||||
case ARCH_TYPE_X86: return "--dynamic-linker=/lib/ld-musl-i386.so.1";
|
||||
case ARCH_TYPE_X86_64: return "--dynamic-linker=/lib/ld-musl-x86_64.so.1";
|
||||
default: return "--dynamic-linker=/lib/ld-musl-unknown.so.1"; // a placeholder for now
|
||||
case ARCH_TYPE_ARM: return "/lib/ld-musl-arm.so.1";
|
||||
case ARCH_TYPE_ARMB: return "/lib/ld-musl-armeb.so.1";
|
||||
case ARCH_TYPE_AARCH64: return "/lib/ld-musl-aarch64.so.1";
|
||||
case ARCH_TYPE_AARCH64_BE: return "/lib/ld-musl-aarch64_be.so.1";
|
||||
case ARCH_TYPE_MIPS: return "/lib/ld-musl-mips.so.1";
|
||||
case ARCH_TYPE_MIPSEL: return "/lib/ld-musl-mipsel.so.1";
|
||||
case ARCH_TYPE_MIPS64: return "/lib/ld-musl-mips64.so.1";
|
||||
case ARCH_TYPE_MIPS64EL: return "/lib/ld-musl-mips64el.so.1";
|
||||
case ARCH_TYPE_PPC: return "/lib/ld-musl-powerpc.so.1";
|
||||
case ARCH_TYPE_PPC64: return "/lib/ld-musl-powerpc64.so.1";
|
||||
case ARCH_TYPE_RISCV32: return "/lib/ld-musl-riscv32.so.1";
|
||||
case ARCH_TYPE_RISCV64: return "/lib/ld-musl-riscv64.so.1";
|
||||
case ARCH_TYPE_X86: return "/lib/ld-musl-i386.so.1";
|
||||
case ARCH_TYPE_X86_64: return "/lib/ld-musl-x86_64.so.1";
|
||||
default: return "/lib/ld-musl-unknown.so.1"; // a placeholder for now
|
||||
}
|
||||
UNREACHABLE;
|
||||
break;
|
||||
case LINUX_LIBC_GNU:
|
||||
switch (compiler.platform.arch)
|
||||
{
|
||||
case ARCH_TYPE_ARM: return "--dynamic-linker=/lib/ld-linux.so.3";
|
||||
case ARCH_TYPE_AARCH64: return "--dynamic-linker=/lib/ld-linux-aarch64.so.1";
|
||||
case ARCH_TYPE_MIPS: return "--dynamic-linker=/lib/ld-linux-mipsn8.so.1";
|
||||
case ARCH_TYPE_MIPSEL: return "--dynamic-linker=/lib/ld-linux-mipsn8.so.1";
|
||||
case ARCH_TYPE_MIPS64: return "--dynamic-linker=/lib/ld-linux-mipsn8.so.1";
|
||||
case ARCH_TYPE_MIPS64EL: return "--dynamic-linker=/lib/ld-linux-mipsn8.so.1";
|
||||
case ARCH_TYPE_RISCV32: return "-dynamic-linker=/lib/ld-linux-riscv32-ilp32.so.1";
|
||||
case ARCH_TYPE_RISCV64: return "-dynamic-linker=/lib/ld-linux-riscv64-lp64.so.1";
|
||||
case ARCH_TYPE_SPARCV9: return "--dynamic-linker=/lib/ld-linux.so.2";
|
||||
case ARCH_TYPE_X86: return "--dynamic-linker=/lib64/ld-linux.so.2";
|
||||
case ARCH_TYPE_X86_64: return "--dynamic-linker=/lib64/ld-linux-x86-64.so.2";
|
||||
default: return "--dynamic-linker=/lib/ld-linux-unknown.so.2"; // another placeholder until we have all of them
|
||||
case ARCH_TYPE_ARM: return "/lib/ld-linux.so.3";
|
||||
case ARCH_TYPE_AARCH64: return "/lib/ld-linux-aarch64.so.1";
|
||||
case ARCH_TYPE_MIPS: return "/lib/ld-linux-mipsn8.so.1";
|
||||
case ARCH_TYPE_MIPSEL: return "/lib/ld-linux-mipsn8.so.1";
|
||||
case ARCH_TYPE_MIPS64: return "/lib/ld-linux-mipsn8.so.1";
|
||||
case ARCH_TYPE_MIPS64EL: return "/lib/ld-linux-mipsn8.so.1";
|
||||
case ARCH_TYPE_RISCV32:
|
||||
{
|
||||
unsigned flen = compiler.platform.riscv.flen;
|
||||
if (flen == 8) return "/lib/ld-linux-riscv32-ilp32d.so.1";
|
||||
if (flen == 4) return "/lib/ld-linux-riscv32-ilp32f.so.1";
|
||||
return "/lib/ld-linux-riscv32-ilp32.so.1";
|
||||
}
|
||||
case ARCH_TYPE_RISCV64:
|
||||
{
|
||||
unsigned flen = compiler.platform.riscv.flen;
|
||||
if (flen == 8) return "/lib/ld-linux-riscv64-lp64d.so.1";
|
||||
if (flen == 4) return "/lib/ld-linux-riscv64-lp64f.so.1";
|
||||
return "/lib/ld-linux-riscv64-lp64.so.1";
|
||||
}
|
||||
case ARCH_TYPE_SPARCV9: return "/lib/ld-linux.so.2";
|
||||
case ARCH_TYPE_X86: return "/lib64/ld-linux.so.2";
|
||||
case ARCH_TYPE_X86_64: return "/lib64/ld-linux-x86-64.so.2";
|
||||
default: return "/lib/ld-linux-unknown.so.2"; // another placeholder until we have all of them
|
||||
}
|
||||
FALLTHROUGH;
|
||||
default:
|
||||
@@ -507,6 +554,15 @@ static void linker_setup_linux(const char ***args_ref, Linker linker_type, bool
|
||||
{
|
||||
error_exit("Failed to find the C runtime at link time.");
|
||||
}
|
||||
|
||||
add_plain_arg("-m");
|
||||
add_plain_arg(ld_target(compiler.platform.arch));
|
||||
if (link_libc())
|
||||
{
|
||||
add_plain_arg("--dynamic-linker");
|
||||
add_plain_arg(find_linux_ld());
|
||||
}
|
||||
|
||||
if (is_pie_pic(compiler.platform.reloc_model))
|
||||
{
|
||||
add_concat_file_arg(crt_dir, "crti.o");
|
||||
@@ -523,14 +579,29 @@ static void linker_setup_linux(const char ***args_ref, Linker linker_type, bool
|
||||
}
|
||||
add_concat_file_arg(crt_dir, "crtn.o");
|
||||
add_concat_quote_arg("-L", crt_dir);
|
||||
add_plain_arg(find_linux_ld());
|
||||
add_concat_quote_arg("-L", crt_begin_dir);
|
||||
|
||||
if (compiler.platform.arch == ARCH_TYPE_RISCV64 || compiler.platform.arch == ARCH_TYPE_RISCV32)
|
||||
{
|
||||
const char *is_64 = compiler.platform.arch == ARCH_TYPE_RISCV64 ? "64" : "32";
|
||||
char *sysroot = str_printf("/usr/riscv%s-linux-gnu", is_64);
|
||||
if (file_is_dir(sysroot))
|
||||
{
|
||||
add_plain_arg(str_printf("--sysroot=%s", sysroot));
|
||||
}
|
||||
char *p1 = str_printf("/usr/riscv%s-linux-gnu/lib", is_64);
|
||||
if (file_is_dir(p1)) add_plain_arg(str_printf("-L%s", p1));
|
||||
char *p2 = str_printf("/usr/riscv%s-linux-gnu/usr/lib", is_64);
|
||||
if (file_is_dir(p2)) add_plain_arg(str_printf("-L%s", p2));
|
||||
}
|
||||
|
||||
if (compiler.linking.link_math) linking_add_link(&compiler.linking, "m");
|
||||
linking_add_link(&compiler.linking, "pthread");
|
||||
linking_add_link(&compiler.linking, "gcc");
|
||||
linking_add_link(&compiler.linking, "gcc_s");
|
||||
linking_add_link(&compiler.linking, "c");
|
||||
add_plain_arg("-L/usr/lib/");
|
||||
add_plain_arg("-L/lib/");
|
||||
add_plain_arg("-m");
|
||||
add_plain_arg(ld_target(compiler.platform.arch));
|
||||
}
|
||||
|
||||
static void linker_setup_android(const char ***args_ref, Linker linker_type, bool is_dylib)
|
||||
|
||||
@@ -1036,7 +1036,7 @@ static void llvm_emit_type_decls(GenContext *context, Decl *decl)
|
||||
case DECL_UNION:
|
||||
case DECL_ENUM:
|
||||
case DECL_BITSTRUCT:
|
||||
case DECL_CONST_ENUM:
|
||||
case DECL_CONSTDEF:
|
||||
llvm_get_typeid(context, decl->type);
|
||||
break;
|
||||
}
|
||||
@@ -1389,7 +1389,7 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
|
||||
case DECL_CT_ASSERT:
|
||||
case DECL_TYPEDEF:
|
||||
case DECL_ENUM:
|
||||
case DECL_CONST_ENUM:
|
||||
case DECL_CONSTDEF:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_IMPORT:
|
||||
case DECL_ALIAS_PATH:
|
||||
@@ -1407,6 +1407,7 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
|
||||
case DECL_INTERFACE:
|
||||
case DECL_GENERIC:
|
||||
case DECL_GENERIC_INSTANCE:
|
||||
case DECL_CONTRACT:
|
||||
UNREACHABLE;
|
||||
}
|
||||
UNREACHABLE
|
||||
|
||||
@@ -656,7 +656,7 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type *
|
||||
return type->backend_debug_type = llvm_debug_pointer_type(c, type);
|
||||
case TYPE_ENUM:
|
||||
return type->backend_debug_type = llvm_debug_enum_type(c, type, scope);
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
return type->backend_debug_type = llvm_debug_raw_enum_type(c, type, scope);
|
||||
case TYPE_FUNC_RAW:
|
||||
return type->backend_debug_type = llvm_debug_func_type(c, type);
|
||||
|
||||
@@ -3595,7 +3595,7 @@ static void llvm_emit_array_comp(GenContext *c, BEValue *result, BEValue *lhs, B
|
||||
case ALL_INTS:
|
||||
case TYPE_POINTER:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_CONST_ENUM:
|
||||
case TYPE_CONSTDEF:
|
||||
case TYPE_FUNC_PTR:
|
||||
case TYPE_INTERFACE:
|
||||
case TYPE_ANY:
|
||||
@@ -3921,7 +3921,7 @@ static void llvm_emit_else(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
assert(success_end_block && else_block_exit);
|
||||
|
||||
// We might have a void here
|
||||
if (!real_value.value)
|
||||
if (!real_value.value || LLVMIsUndef(real_value.value))
|
||||
{
|
||||
assert(type_flatten(expr->type) == type_void);
|
||||
assert(!else_value.value);
|
||||
@@ -6618,7 +6618,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
|
||||
INTROSPECT_TYPE_ARRAY, INTROSPECT_TYPE_POINTER,
|
||||
INTROSPECT_TYPE_VECTOR, INTROSPECT_TYPE_ENUM,
|
||||
INTROSPECT_TYPE_SLICE, INTROSPECT_TYPE_DISTINCT,
|
||||
INTROSPECT_TYPE_CONST_ENUM, INTROSPECT_TYPE_BITSTRUCT,
|
||||
INTROSPECT_TYPE_CONSTDEF, INTROSPECT_TYPE_BITSTRUCT,
|
||||
INTROSPECT_TYPE_OPTIONAL,
|
||||
};
|
||||
for (int i = 0; i < 8; i++)
|
||||
|
||||
@@ -165,6 +165,26 @@ void gencontext_begin_module(GenContext *c)
|
||||
{
|
||||
unsigned frame_pointer = compiler.platform.arch == ARCH_TYPE_AARCH64 ? 1 : 2;
|
||||
llvm_set_module_flag(c, LLVMModuleFlagBehaviorWarning, "frame-pointer", frame_pointer, type_uint);
|
||||
if (compiler.platform.arch == ARCH_TYPE_RISCV64 || compiler.platform.arch == ARCH_TYPE_RISCV32)
|
||||
{
|
||||
const char *abi_str = NULL;
|
||||
if (compiler.platform.arch == ARCH_TYPE_RISCV64)
|
||||
{
|
||||
unsigned flen = compiler.platform.riscv.flen;
|
||||
if (flen == 8) abi_str = "lp64d";
|
||||
else if (flen == 4) abi_str = "lp64f";
|
||||
else abi_str = "lp64";
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned flen = compiler.platform.riscv.flen;
|
||||
if (flen == 8) abi_str = "ilp32d";
|
||||
else if (flen == 4) abi_str = "ilp32f";
|
||||
else abi_str = "ilp32";
|
||||
}
|
||||
LLVMMetadataRef val = LLVMValueAsMetadata(LLVMMDStringInContext(c->context, abi_str, strlen(abi_str)));
|
||||
LLVMAddModuleFlag(c->module, LLVMModuleFlagBehaviorError, "target-abi", 10, val);
|
||||
}
|
||||
}
|
||||
|
||||
if (compiler.build.debug_info != DEBUG_INFO_NONE)
|
||||
|
||||
@@ -1655,10 +1655,8 @@ void llvm_emit_stmt(GenContext *c, Ast *ast)
|
||||
{
|
||||
case AST_POISONED:
|
||||
case AST_FOREACH_STMT:
|
||||
case AST_CONTRACT:
|
||||
case AST_ASM_STMT:
|
||||
case AST_ASM_LABEL:
|
||||
case AST_CONTRACT_FAULT:
|
||||
case AST_CASE_STMT:
|
||||
case AST_DEFAULT_STMT:
|
||||
case CT_AST:
|
||||
|
||||
@@ -25,7 +25,7 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl)
|
||||
UNREACHABLE_VOID
|
||||
case DECL_TYPE_ALIAS:
|
||||
return llvm_get_type(c, decl->type);
|
||||
case DECL_CONST_ENUM:
|
||||
case DECL_CONSTDEF:
|
||||
return llvm_get_type(c, decl->enums.type_info->type);
|
||||
case DECL_TYPEDEF:
|
||||
return llvm_get_type(c, decl->distinct->type);
|
||||
@@ -643,8 +643,8 @@ LLVMValueRef llvm_get_typeid(GenContext *c, Type *type)
|
||||
return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_DISTINCT, type_inline(type), 0, NULL, false);
|
||||
case TYPE_ENUM:
|
||||
return llvm_get_introspection_for_enum(c, type);
|
||||
case TYPE_CONST_ENUM:
|
||||
return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_CONST_ENUM, type_inline(type), vec_size(type->decl->enums.values), NULL, false);
|
||||
case TYPE_CONSTDEF:
|
||||
return llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_CONSTDEF, type_inline(type), vec_size(type->decl->enums.values), NULL, false);
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
return llvm_get_introspection_for_struct_union(c, type);
|
||||
|
||||
@@ -414,7 +414,7 @@ static Expr *parse_lambda(ParseContext *c, Expr *left, SourceSpan lhs_span UNUSE
|
||||
sig->params = decls;
|
||||
sig->rtype = return_type ? type_infoid(return_type) : 0;
|
||||
sig->variadic = variadic;
|
||||
if (!parse_attributes(c, &func->attributes, NULL, NULL, NULL)) return poisoned_expr;
|
||||
if (!parse_attributes(c, &func->attributes, NULL, NULL, NULL, "on lambda declarations")) return poisoned_expr;
|
||||
RANGE_EXTEND_PREV(func);
|
||||
if (tok_is(c, TOKEN_IMPLIES))
|
||||
{
|
||||
|
||||
@@ -13,8 +13,8 @@ typedef enum FunctionParse_
|
||||
FUNC_PARSE_INTERFACE,
|
||||
} FunctionParse;
|
||||
|
||||
static inline Decl *parse_enum_declaration(ParseContext *c, bool is_const);
|
||||
static inline Decl *parse_func_definition(ParseContext *c, AstId contracts, FunctionParse parse_kind);
|
||||
static inline Decl *parse_enum_declaration(ParseContext *c);
|
||||
static inline Decl *parse_func_definition(ParseContext *c, ContractDescription *contracts, FunctionParse parse_kind);
|
||||
static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl);
|
||||
static inline bool parse_enum_param_list(ParseContext *c, Decl*** parameters_ref, ArrayIndex *inline_index);
|
||||
static Decl *parse_ct_include(ParseContext *c);
|
||||
@@ -22,8 +22,7 @@ static Decl *parse_exec(ParseContext *c);
|
||||
static bool parse_attributes_for_global(ParseContext *c, Decl *decl);
|
||||
INLINE bool parse_decl_initializer(ParseContext *c, Decl *decl);
|
||||
INLINE Decl *decl_new_var_current(ParseContext *c, TypeInfo *type, VarDeclKind kind);
|
||||
static bool parse_contracts(ParseContext *c, AstId *contracts_ref);
|
||||
static Ast *contracts_first_real(AstId contracts);
|
||||
static bool parse_contracts(ParseContext *c, ContractDescription *contracts_ref);
|
||||
|
||||
INLINE Decl *decl_new_var_current(ParseContext *c, TypeInfo *type, VarDeclKind kind)
|
||||
{
|
||||
@@ -233,28 +232,23 @@ NEXT:;
|
||||
decl->generic_decl.id = generic_id++;
|
||||
}
|
||||
|
||||
bool parse_attach_contracts(Decl *generics, AstId contracts)
|
||||
bool parse_attach_contracts(Decl *generics, ContractDescription *contracts)
|
||||
{
|
||||
if (!contracts) return true;
|
||||
if (!generics)
|
||||
{
|
||||
Ast *first_contract = ast_contract_has_any(contracts);
|
||||
if (first_contract) RETURN_PRINT_ERROR_AT(false, first_contract, "Contracts can only be used with '@generic' declarations and modules.");
|
||||
if (contracts->has_contracts)
|
||||
{
|
||||
print_error_at(contracts->first_contract, "Contracts can only be used with '@generic' declarations and modules.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Ast *first_invalid_contract = ast_contract_has_any_non_require(contracts);
|
||||
if (first_invalid_contract)
|
||||
if (contracts->first_non_require.a)
|
||||
{
|
||||
RETURN_PRINT_ERROR_AT(false, first_invalid_contract, "Invalid constraint - only '@require' is valid for '@generic' declarations and modules.");
|
||||
}
|
||||
if (generics->generic_decl.contracts)
|
||||
{
|
||||
ast_last(astptrzero(generics->generic_decl.contracts))->next = contracts;
|
||||
}
|
||||
else
|
||||
{
|
||||
generics->generic_decl.contracts = contracts;
|
||||
print_error_at(contracts->first_non_require, "Invalid constraint - only '@require' is valid for '@generic' declarations and modules.");
|
||||
return false;
|
||||
}
|
||||
FOREACH(Expr *, e, contracts->requires) vec_add(generics->generic_decl.requires, e);
|
||||
return true;
|
||||
}
|
||||
void parse_attach_generics(ParseContext *c, Decl *generic_decl)
|
||||
@@ -267,7 +261,7 @@ void parse_attach_generics(ParseContext *c, Decl *generic_decl)
|
||||
/**
|
||||
* module ::= MODULE module_path ('{' module_params '}')? (@public|@private|@local|@test|@export|@cname) EOS
|
||||
*/
|
||||
bool parse_module(ParseContext *c, AstId contracts)
|
||||
bool parse_module(ParseContext *c, ContractDescription *contracts)
|
||||
{
|
||||
if (tok_is(c, TOKEN_STRING))
|
||||
{
|
||||
@@ -316,7 +310,7 @@ bool parse_module(ParseContext *c, AstId contracts)
|
||||
|
||||
ASSIGN_DECL_OR_RET(Decl *generic_decl, parse_generic_decl(c), false);
|
||||
|
||||
if (!parse_attributes(c, &attrs, &visibility, NULL, &is_cond)) return false;
|
||||
if (!parse_attributes(c, &attrs, &visibility, NULL, &is_cond, NULL)) return false;
|
||||
if (generic_decl_old)
|
||||
{
|
||||
SEMA_DEPRECATED(generic_decl_old, "Module-based generics is deprecated, use `<...>` instead.");
|
||||
@@ -937,7 +931,7 @@ Decl *parse_local_decl_after_type(ParseContext *c, TypeInfo *type)
|
||||
advance(c);
|
||||
|
||||
bool is_cond;
|
||||
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl;
|
||||
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond, "on local variables")) return poisoned_decl;
|
||||
decl->is_cond = is_cond;
|
||||
if (tok_is(c, TOKEN_EQ))
|
||||
{
|
||||
@@ -1018,7 +1012,7 @@ Decl *parse_const_declaration(ParseContext *c, bool is_global, bool is_extern)
|
||||
else
|
||||
{
|
||||
bool is_cond;
|
||||
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl;
|
||||
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond, "on local declarations")) return poisoned_decl;
|
||||
decl->is_cond = is_cond;
|
||||
}
|
||||
|
||||
@@ -1049,7 +1043,7 @@ Decl *parse_var_decl(ParseContext *c)
|
||||
case TOKEN_IDENT:
|
||||
decl = decl_new_var_current(c, NULL, VARDECL_LOCAL);
|
||||
advance(c);
|
||||
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl;
|
||||
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond, "on local declarations")) return poisoned_decl;
|
||||
decl->is_cond = is_cond;
|
||||
if (!tok_is(c, TOKEN_EQ))
|
||||
{
|
||||
@@ -1064,7 +1058,7 @@ Decl *parse_var_decl(ParseContext *c)
|
||||
decl = decl_new_var_current(c, NULL, c->tok == TOKEN_CT_IDENT ? VARDECL_LOCAL_CT : VARDECL_LOCAL_CT_TYPE);
|
||||
advance(c);
|
||||
span = c->span;
|
||||
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl;
|
||||
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond, "on local declarations")) return poisoned_decl;
|
||||
if (is_cond || decl->attributes)
|
||||
{
|
||||
print_error_at(span, "Attributes are not allowed on compile time variables.");
|
||||
@@ -1326,7 +1320,8 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl)
|
||||
bool is_cond;
|
||||
bool can_be_generic = decl_may_be_generic(decl);
|
||||
ASSIGN_DECL_OR_RET(Decl *generics, parse_generic_decl(c), false);
|
||||
if (!parse_attributes(c, &decl->attributes, &visibility, decl_needs_prefix(decl) ? &is_builtin : NULL, &is_cond)) return false;
|
||||
bool is_method = decl->decl_kind == DECL_FUNC && decl->func_decl.type_parent;
|
||||
if (!parse_attributes(c, &decl->attributes, &visibility, decl_needs_prefix(decl) ? &is_builtin : NULL, &is_cond, is_method ? "for method declarations" : NULL)) return false;
|
||||
if (generics)
|
||||
{
|
||||
if (!can_be_generic)
|
||||
@@ -1351,7 +1346,22 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool parse_attribute_list(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref, bool use_comma)
|
||||
static inline bool warn_method_visibility(Attr *attr, const char *mod, const char *err)
|
||||
{
|
||||
switch (compiler.build.warnings.method_visibility)
|
||||
{
|
||||
case WARNING_WARN:
|
||||
sema_warning_at(attr->span, "'%s' modifiers are ignored %s.", mod, err);
|
||||
return true;
|
||||
case WARNING_ERROR:
|
||||
print_error_at(attr->span, "'%s' modifiers are not allowed %s.", mod, err);
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool parse_attribute_list(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref, bool use_comma, const char *reject_visibility)
|
||||
{
|
||||
Visibility visibility = -1; // NOLINT
|
||||
if (cond_ref) *cond_ref = false;
|
||||
@@ -1370,12 +1380,36 @@ static inline bool parse_attribute_list(ParseContext *c, Attr ***attributes_ref,
|
||||
switch (attr->attr_kind)
|
||||
{
|
||||
case ATTRIBUTE_PUBLIC:
|
||||
if (reject_visibility && attributes_ref)
|
||||
{
|
||||
if (!warn_method_visibility(attr, "@public", reject_visibility)) return false;
|
||||
}
|
||||
else if (reject_visibility)
|
||||
{
|
||||
RETURN_PRINT_ERROR_AT(false, attr, "Visibility modifiers are not allowed %s.", reject_visibility);
|
||||
}
|
||||
parsed_visibility = VISIBLE_PUBLIC;
|
||||
break;
|
||||
case ATTRIBUTE_PRIVATE:
|
||||
if (reject_visibility && attributes_ref)
|
||||
{
|
||||
if (!warn_method_visibility(attr, "@private", reject_visibility)) return false;
|
||||
}
|
||||
else if (reject_visibility)
|
||||
{
|
||||
RETURN_PRINT_ERROR_AT(false, attr, "Visibility modifiers are not allowed %s.", reject_visibility);
|
||||
}
|
||||
parsed_visibility = VISIBLE_PRIVATE;
|
||||
break;
|
||||
case ATTRIBUTE_LOCAL:
|
||||
if (reject_visibility && attributes_ref)
|
||||
{
|
||||
if (!warn_method_visibility(attr, "@local", reject_visibility)) return false;
|
||||
}
|
||||
else if (reject_visibility)
|
||||
{
|
||||
RETURN_PRINT_ERROR_AT(false, attr, "Visibility modifiers are not allowed %s.", reject_visibility);
|
||||
}
|
||||
parsed_visibility = VISIBLE_LOCAL;
|
||||
break;
|
||||
case ATTRIBUTE_BUILTIN:
|
||||
@@ -1464,9 +1498,9 @@ Decl *parse_generic_decl(ParseContext *c)
|
||||
*
|
||||
* @return true if parsing succeeded, false if recovery is needed
|
||||
*/
|
||||
bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref)
|
||||
bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref, const char *reject_visibility)
|
||||
{
|
||||
return parse_attribute_list(c, attributes_ref, visibility_ref, builtin_ref, cond_ref, false);
|
||||
return parse_attribute_list(c, attributes_ref, visibility_ref, builtin_ref, cond_ref, false, reject_visibility);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1600,7 +1634,7 @@ static inline bool parse_enum_param_decl(ParseContext *c, Decl*** parameters)
|
||||
if (token_is_some_ident(c->tok)) RETURN_PRINT_ERROR_HERE("Expected a name starting with a lower-case letter.");
|
||||
RETURN_PRINT_ERROR_HERE("Expected a member name here.");
|
||||
}
|
||||
if (!parse_attributes(c, ¶m->attributes, NULL, NULL, NULL)) return false;
|
||||
if (!parse_attributes(c, ¶m->attributes, NULL, NULL, NULL, "on parameter declarations")) return false;
|
||||
vec_add(*parameters, param);
|
||||
RANGE_EXTEND_PREV(param);
|
||||
return true;
|
||||
@@ -1853,7 +1887,7 @@ CHECK_ELLIPSIS:
|
||||
Decl *param = decl_new_var(name, span, type, param_kind);
|
||||
param->var.type_info = type ? type_infoid(type) : 0;
|
||||
param->var.self_addr = ref;
|
||||
if (!parse_attributes(c, ¶m->attributes, NULL, NULL, NULL)) return false;
|
||||
if (!parse_attributes(c, ¶m->attributes, NULL, NULL, NULL, "on parameters")) return false;
|
||||
if (!no_name)
|
||||
{
|
||||
if (try_consume(c, TOKEN_EQ))
|
||||
@@ -1913,22 +1947,19 @@ static inline bool parse_fn_parameter_list(ParseContext *c, Signature *signature
|
||||
|
||||
// --- Parse types
|
||||
|
||||
static bool parse_element_contract(ParseContext *c, const char *error)
|
||||
static bool parse_element_contract(ParseContext *c, ContractDescription *contracts, const char *error)
|
||||
{
|
||||
AstId contracts = 0;
|
||||
if (!parse_contracts(c, &contracts)) return false;
|
||||
if (!contracts) return true;
|
||||
Ast *ast = astptr(contracts);
|
||||
while (ast)
|
||||
{
|
||||
if (ast->ast_kind != AST_CONTRACT || ast->contract_stmt.kind != CONTRACT_COMMENT)
|
||||
{
|
||||
RETURN_PRINT_ERROR_AT(false, ast, "No constraints are allowed on %s.", error);
|
||||
}
|
||||
ast = astptrzero(ast->next);
|
||||
}
|
||||
return true;
|
||||
if (!parse_contracts(c, contracts)) return false;
|
||||
if (!contracts->has_contracts) return true;
|
||||
print_error_at(contracts->first_contract, "No constraints are allowed on %s.", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
INLINE void attach_deprecation_from_contract(ParseContext *c, ContractDescription *contract, Decl *decl)
|
||||
{
|
||||
if (contract->deprecated) vec_add(decl->attributes, contract->deprecated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect pointer to after '{'
|
||||
*
|
||||
@@ -1954,7 +1985,8 @@ static bool parse_struct_body(ParseContext *c, Decl *parent)
|
||||
ArrayIndex index = 0;
|
||||
while (!tok_is(c, TOKEN_RBRACE))
|
||||
{
|
||||
if (!parse_element_contract(c, "struct/union members")) return decl_poison(parent);
|
||||
ContractDescription contracts = EMPTY_CONTRACT;
|
||||
if (!parse_element_contract(c, &contracts, "struct/union members")) return decl_poison(parent);
|
||||
TokenType token_type = c->tok;
|
||||
if (token_type == TOKEN_STRUCT || token_type == TOKEN_UNION || token_type == TOKEN_BITSTRUCT)
|
||||
{
|
||||
@@ -1993,10 +2025,11 @@ static bool parse_struct_body(ParseContext *c, Decl *parent)
|
||||
else
|
||||
{
|
||||
bool is_cond;
|
||||
if (!parse_attributes(c, &member->attributes, NULL, NULL, &is_cond)) return false;
|
||||
if (!parse_attributes(c, &member->attributes, NULL, NULL, &is_cond, "on struct and union fields")) return false;
|
||||
member->is_cond = true;
|
||||
if (!parse_struct_body(c, member)) return decl_poison(parent);
|
||||
}
|
||||
attach_deprecation_from_contract(c, &contracts, member);
|
||||
vec_add(parent->strukt.members, member);
|
||||
index++;
|
||||
if (index > MAX_MEMBERS)
|
||||
@@ -2036,7 +2069,7 @@ static bool parse_struct_body(ParseContext *c, Decl *parent)
|
||||
}
|
||||
advance(c);
|
||||
bool is_cond;
|
||||
if (!parse_attributes(c, &member->attributes, NULL, NULL, &is_cond)) return false;
|
||||
if (!parse_attributes(c, &member->attributes, NULL, NULL, &is_cond, "on struct and union fields")) return false;
|
||||
member->is_cond = true;
|
||||
if (!try_consume(c, TOKEN_COMMA)) break;
|
||||
if (was_inline)
|
||||
@@ -2159,10 +2192,11 @@ static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl)
|
||||
bool is_consecutive = false;
|
||||
while (!try_consume(c, TOKEN_RBRACE))
|
||||
{
|
||||
if (!parse_element_contract(c, "bitstruct members")) return decl_poison(decl);
|
||||
ContractDescription contracts = EMPTY_CONTRACT;
|
||||
if (!parse_element_contract(c, &contracts, "bitstruct members")) return decl_poison(decl);
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_base_type(c), false);
|
||||
Decl *member_decl = decl_new_var_current(c, type, VARDECL_BITMEMBER);
|
||||
|
||||
attach_deprecation_from_contract(c, &contracts, member_decl);
|
||||
if (!try_consume(c, TOKEN_IDENT))
|
||||
{
|
||||
if (try_consume(c, TOKEN_CONST_IDENT) || try_consume(c, TOKEN_TYPE_IDENT))
|
||||
@@ -2184,7 +2218,7 @@ static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl)
|
||||
is_consecutive = true;
|
||||
}
|
||||
bool is_cond = false;
|
||||
if (!parse_attributes(c, &member_decl->attributes, NULL, NULL, &is_cond)) return false;
|
||||
if (!parse_attributes(c, &member_decl->attributes, NULL, NULL, &is_cond, "on bitstruct fields")) return false;
|
||||
member_decl->is_cond = is_cond;
|
||||
CONSUME_OR_RET(TOKEN_EOS, false);
|
||||
unsigned index = vec_size(decl->strukt.members);
|
||||
@@ -2205,7 +2239,7 @@ static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl)
|
||||
member_decl->var.end = NULL;
|
||||
}
|
||||
bool is_cond = false;
|
||||
if (!parse_attributes(c, &member_decl->attributes, NULL, NULL, &is_cond)) return false;
|
||||
if (!parse_attributes(c, &member_decl->attributes, NULL, NULL, &is_cond, "on bitstruct fields")) return false;
|
||||
member_decl->is_cond = is_cond;
|
||||
CONSUME_EOS_OR_RET(false);
|
||||
if (is_consecutive)
|
||||
@@ -2224,13 +2258,13 @@ INLINE bool parse_interface_body(ParseContext *c, Decl *interface)
|
||||
Decl **fns = NULL;
|
||||
while (!try_consume(c, TOKEN_RBRACE))
|
||||
{
|
||||
AstId contracts = 0;
|
||||
if (!parse_contracts(c, &contracts)) return poisoned_decl;
|
||||
ContractDescription contracts_desc = EMPTY_CONTRACT;
|
||||
if (!parse_contracts(c, &contracts_desc)) return poisoned_decl;
|
||||
if (!tok_is(c, TOKEN_FN))
|
||||
{
|
||||
RETURN_PRINT_ERROR_HERE("Interfaces can only have function declarations, and they must start with 'fn' as usual.");
|
||||
}
|
||||
ASSIGN_DECL_OR_RET(Decl *interface_fn, parse_func_definition(c, contracts, FUNC_PARSE_INTERFACE), false);
|
||||
ASSIGN_DECL_OR_RET(Decl *interface_fn, parse_func_definition(c, &contracts_desc, FUNC_PARSE_INTERFACE), false);
|
||||
vec_add(fns, interface_fn);
|
||||
}
|
||||
interface->interface_methods = fns;
|
||||
@@ -2289,10 +2323,6 @@ static inline Decl *parse_bitstruct_declaration(ParseContext *c)
|
||||
|
||||
static inline Decl *parse_top_level_const_declaration(ParseContext *c, bool is_extern)
|
||||
{
|
||||
if (!is_extern && peek(c) == TOKEN_ENUM)
|
||||
{
|
||||
return parse_enum_declaration(c, true);
|
||||
}
|
||||
ASSIGN_DECL_OR_RET(Decl *decl, parse_const_declaration(c, true, is_extern), poisoned_decl);
|
||||
CONSUME_EOS_OR_RET(poisoned_decl);
|
||||
return decl;
|
||||
@@ -2346,6 +2376,17 @@ static inline void decl_add_type(Decl *decl, TypeKind kind)
|
||||
decl->type = type;
|
||||
}
|
||||
|
||||
static DeclId decl_from_contract_description(ContractDescription *description)
|
||||
{
|
||||
if (!description->has_contracts) return 0;
|
||||
Decl *decl = decl_new(DECL_CONTRACT, "contract", description->first);
|
||||
decl->contracts_decl.ensures = description->ensures;
|
||||
decl->contracts_decl.requires = description->requires;
|
||||
decl->contracts_decl.pure = description->pure;
|
||||
decl->contracts_decl.params = description->params;
|
||||
decl->contracts_decl.opt_returns = description->opt_returns;
|
||||
return declid(decl);
|
||||
}
|
||||
|
||||
/**
|
||||
* typedef_declaration ::= ALIAS TYPE_IDENT attributes? '=' typedef_type ';'
|
||||
@@ -2353,7 +2394,7 @@ static inline void decl_add_type(Decl *decl, TypeKind kind)
|
||||
* typedef_type ::= func_typedef | type generic_params?
|
||||
* func_typedef ::= 'fn' optional_type parameter_type_list
|
||||
*/
|
||||
static inline Decl *parse_alias_type(ParseContext *c, AstId contracts)
|
||||
static inline Decl *parse_alias_type(ParseContext *c, ContractDescription *contracts)
|
||||
{
|
||||
advance_and_verify(c, TOKEN_ALIAS);
|
||||
|
||||
@@ -2390,12 +2431,13 @@ static inline Decl *parse_alias_type(ParseContext *c, AstId contracts)
|
||||
decl->type_alias_decl.decl = decl_type;
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type_info, parse_optional_type(c), poisoned_decl);
|
||||
decl_type->fntype_decl.signature.rtype = type_infoid(type_info);
|
||||
decl_type->fntype_decl.docs = contracts;
|
||||
decl_type->fntype_decl.docs = decl_from_contract_description(contracts);
|
||||
if (!parse_fn_parameter_list(c, &(decl_type->fntype_decl.signature)))
|
||||
{
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (!parse_attributes(c, &decl_type->attributes, NULL, NULL, NULL)) return poisoned_decl;
|
||||
if (!parse_attributes(c, &decl_type->attributes, NULL, NULL, NULL, "on the target of an alias (maybe you intended it *before* the '='?)")) return poisoned_decl;
|
||||
attach_deprecation_from_contract(c, contracts, decl_type);
|
||||
RANGE_EXTEND_PREV(decl_type);
|
||||
RANGE_EXTEND_PREV(decl);
|
||||
CONSUME_EOS_OR_RET(poisoned_decl);
|
||||
@@ -2487,7 +2529,7 @@ static inline Decl *parse_alias_module(ParseContext *c, Decl *decl, TokenType to
|
||||
*
|
||||
* identifier_alias ::= path? (IDENT | CONST_IDENT | AT_IDENT)
|
||||
*/
|
||||
static inline Decl *parse_alias_ident(ParseContext *c, AstId contracts)
|
||||
static inline Decl *parse_alias_ident(ParseContext *c, ContractDescription *contracts)
|
||||
{
|
||||
// 1. Store the beginning of the "alias".
|
||||
advance_and_verify(c, TOKEN_ALIAS);
|
||||
@@ -2582,7 +2624,7 @@ static inline Decl *parse_attrdef(ParseContext *c)
|
||||
|
||||
bool is_cond;
|
||||
bool is_builtin = false;
|
||||
if (!parse_attribute_list(c, &attributes, NULL, decl_needs_prefix(decl) ? &is_builtin : NULL, &is_cond, true)) return poisoned_decl;
|
||||
if (!parse_attribute_list(c, &attributes, NULL, decl_needs_prefix(decl) ? &is_builtin : NULL, &is_cond, true, "cannot be aliased using 'attrdef'")) return poisoned_decl;
|
||||
decl->attr_decl.attrs = attributes;
|
||||
CONSUME_EOS_OR_RET(poisoned_decl);
|
||||
return decl;
|
||||
@@ -2591,7 +2633,7 @@ static inline Decl *parse_attrdef(ParseContext *c)
|
||||
/**
|
||||
* define_decl ::= ALIAS define_type_body
|
||||
*/
|
||||
static inline Decl *parse_alias(ParseContext *c, AstId contracts)
|
||||
static inline Decl *parse_alias(ParseContext *c, ContractDescription *contracts)
|
||||
{
|
||||
switch (peek(c))
|
||||
{
|
||||
@@ -2697,16 +2739,17 @@ static inline bool parse_func_macro_header(ParseContext *c, Decl *decl)
|
||||
* macro ::= MACRO macro_header '(' macro_params ')' opt_attributes macro_body
|
||||
* macro_body ::= IMPLIES expression ';' | compound_statement
|
||||
*/
|
||||
static inline Decl *parse_macro_declaration(ParseContext *c, AstId docs)
|
||||
static inline Decl *parse_macro_declaration(ParseContext *c, ContractDescription *contracts)
|
||||
{
|
||||
advance_and_verify(c, TOKEN_MACRO);
|
||||
|
||||
Decl *decl = decl_calloc();
|
||||
decl->decl_kind = DECL_MACRO;
|
||||
decl->func_decl.docs = docs;
|
||||
decl->func_decl.docs = decl_from_contract_description(contracts);
|
||||
if (!parse_func_macro_header(c, decl)) return poisoned_decl;
|
||||
if (!parse_macro_params(c, decl)) return poisoned_decl;
|
||||
if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
|
||||
attach_deprecation_from_contract(c, contracts, decl);
|
||||
if (tok_is(c, TOKEN_IMPLIES))
|
||||
{
|
||||
ASSIGN_ASTID_OR_RET(decl->func_decl.body,
|
||||
@@ -2719,10 +2762,12 @@ static inline Decl *parse_macro_declaration(ParseContext *c, AstId docs)
|
||||
|
||||
static inline Decl *parse_fault(ParseContext *c)
|
||||
{
|
||||
if (!parse_element_contract(c, "faults")) return poisoned_decl;
|
||||
ContractDescription contracts = EMPTY_CONTRACT;
|
||||
if (!parse_element_contract(c, &contracts, "faults")) return poisoned_decl;
|
||||
Decl *decl = decl_new(DECL_FAULT, symstr(c), c->span);
|
||||
if (!consume_const_name(c, "fault")) return poisoned_decl;
|
||||
if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
|
||||
attach_deprecation_from_contract(c, &contracts, decl);
|
||||
return decl;
|
||||
}
|
||||
|
||||
@@ -2795,15 +2840,16 @@ static inline bool parse_enum_param_list(ParseContext *c, Decl*** parameters_ref
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_enum_values(ParseContext *c, Decl*** values_ref, Visibility visibility, bool is_single_value, bool is_const_enum)
|
||||
static bool parse_enum_values(ParseContext *c, Decl*** values_ref, Visibility visibility, bool is_single_value, bool is_constdef)
|
||||
{
|
||||
Decl **values = NULL;
|
||||
bool deprecate_warn = true;
|
||||
while (!try_consume(c, TOKEN_RBRACE))
|
||||
{
|
||||
if (!parse_element_contract(c, "enum values")) return false;
|
||||
ContractDescription contracts = EMPTY_CONTRACT;
|
||||
if (!parse_element_contract(c, &contracts, "enum values")) return false;
|
||||
Decl *enum_const = decl_new(DECL_ENUM_CONSTANT, symstr(c), c->span);
|
||||
if (is_const_enum) enum_const->enum_constant.is_raw = is_const_enum;
|
||||
if (is_constdef) enum_const->enum_constant.is_raw = is_constdef;
|
||||
enum_const->visibility = visibility;
|
||||
const char *name = enum_const->name;
|
||||
if (!consume_const_name(c, "enum constant")) return false;
|
||||
@@ -2817,18 +2863,19 @@ static bool parse_enum_values(ParseContext *c, Decl*** values_ref, Visibility vi
|
||||
}
|
||||
}
|
||||
if (!parse_attributes_for_global(c, enum_const)) return false;
|
||||
attach_deprecation_from_contract(c, &contracts, enum_const);
|
||||
if (try_consume(c, TOKEN_EQ))
|
||||
{
|
||||
Expr **args = NULL;
|
||||
if (!is_const_enum && deprecate_warn)
|
||||
if (!is_constdef && deprecate_warn)
|
||||
{
|
||||
deprecate_warn = false;
|
||||
print_deprecation_at(c->prev_span, "Use () declaration of associated values instead.");
|
||||
PRINT_DEPRECATED_AT(c->prev_span, "Use {} declaration of associated values instead.");
|
||||
}
|
||||
if (is_single_value || !tok_is(c, TOKEN_LBRACE))
|
||||
{
|
||||
ASSIGN_EXPR_OR_RET(Expr *single, parse_constant_expr(c), false);
|
||||
if (is_const_enum)
|
||||
if (is_constdef)
|
||||
{
|
||||
enum_const->enum_constant.value = single;
|
||||
goto NEXT;
|
||||
@@ -2862,7 +2909,7 @@ static bool parse_enum_values(ParseContext *c, Decl*** values_ref, Visibility vi
|
||||
}
|
||||
enum_const->enum_constant.associated = args;
|
||||
}
|
||||
else if (!is_const_enum && try_consume(c, TOKEN_LBRACE))
|
||||
else if (!is_constdef && try_consume(c, TOKEN_LBRACE))
|
||||
{
|
||||
Expr **args = NULL;
|
||||
while (1)
|
||||
@@ -2913,13 +2960,13 @@ NEXT:
|
||||
* enum_body ::= enum_def (',' enum_def)* ','?
|
||||
* enum_def ::= CONST_IDENT ('(' arg_list ')')?
|
||||
*/
|
||||
static inline Decl *parse_enum_declaration(ParseContext *c, bool is_const)
|
||||
static inline Decl *parse_enum_declaration(ParseContext *c)
|
||||
{
|
||||
if (is_const) advance_and_verify(c, TOKEN_CONST);
|
||||
if (tok_is(c, TOKEN_CENUM))
|
||||
bool is_constdef = false;
|
||||
if (tok_is(c, TOKEN_CONSTDEF))
|
||||
{
|
||||
advance_and_verify(c, TOKEN_CENUM);
|
||||
is_const = true;
|
||||
advance_and_verify(c, TOKEN_CONSTDEF);
|
||||
is_constdef = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2928,23 +2975,22 @@ static inline Decl *parse_enum_declaration(ParseContext *c, bool is_const)
|
||||
|
||||
const char *name = symstr(c);
|
||||
SourceSpan span = c->span;
|
||||
if (!consume_type_name(c, "enum")) return poisoned_decl;
|
||||
if (!consume_type_name(c, is_constdef ? "constdef" : "enum" )) return poisoned_decl;
|
||||
TypeInfo **interfaces = NULL;
|
||||
if (!parse_interface_impls(c, &interfaces)) return poisoned_decl;
|
||||
TypeInfo *type = NULL;
|
||||
|
||||
bool val_is_inline = false;
|
||||
ArrayIndex inline_index = -1;
|
||||
bool is_const_enum = is_const;
|
||||
Decl **param_list = NULL;
|
||||
if (try_consume(c, TOKEN_COLON))
|
||||
{
|
||||
if (!is_const)
|
||||
if (!is_constdef)
|
||||
{
|
||||
is_const_enum = try_consume(c, TOKEN_CONST);
|
||||
if (is_const_enum)
|
||||
is_constdef = try_consume(c, TOKEN_CONST);
|
||||
if (is_constdef)
|
||||
{
|
||||
print_deprecation_at(c->prev_span, "Declare const enums using 'const enum' instead.");
|
||||
PRINT_DEPRECATED_AT(c->prev_span, "Declare constdefs using 'constdef' instead.");
|
||||
}
|
||||
}
|
||||
if (!tok_is(c, TOKEN_LPAREN) && !tok_is(c, TOKEN_LBRACE))
|
||||
@@ -2953,14 +2999,14 @@ static inline Decl *parse_enum_declaration(ParseContext *c, bool is_const)
|
||||
ASSIGN_TYPE_OR_RET(type, parse_optional_type_no_generic(c), poisoned_decl);
|
||||
if (type->optional)
|
||||
{
|
||||
RETURN_PRINT_ERROR_AT(poisoned_decl, type, "An enum can't have an optional type.");
|
||||
RETURN_PRINT_ERROR_AT(poisoned_decl, type, "An enum or constdef can't have an optional type.");
|
||||
}
|
||||
}
|
||||
if (is_const_enum)
|
||||
if (is_constdef)
|
||||
{
|
||||
if (tok_is(c, TOKEN_LPAREN))
|
||||
{
|
||||
PRINT_ERROR_HERE("Const enums cannot have associated values.");
|
||||
PRINT_ERROR_HERE("Constdefs cannot have associated values.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
}
|
||||
@@ -2970,7 +3016,7 @@ static inline Decl *parse_enum_declaration(ParseContext *c, bool is_const)
|
||||
}
|
||||
}
|
||||
|
||||
Decl *decl = decl_new_with_type(name, span, is_const_enum ? DECL_CONST_ENUM : DECL_ENUM);
|
||||
Decl *decl = decl_new_with_type(name, span, is_constdef ? DECL_CONSTDEF : DECL_ENUM);
|
||||
decl->interfaces = interfaces;
|
||||
if (param_list) decl->enums.parameters = param_list;
|
||||
if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
|
||||
@@ -2980,9 +3026,9 @@ static inline Decl *parse_enum_declaration(ParseContext *c, bool is_const)
|
||||
|
||||
decl->enums.type_info = type ? type : type_info_new_base(type_int, decl->span);
|
||||
decl->enums.inline_index = (int16_t)inline_index;
|
||||
decl->enums.inline_value = is_const_enum ? false : val_is_inline;
|
||||
if (is_const_enum && val_is_inline) decl->is_substruct = true;
|
||||
if (!parse_enum_values(c, &decl->enums.values, visibility, is_const_enum || expected_parameters == 1, is_const_enum)) return poisoned_decl;
|
||||
decl->enums.inline_value = is_constdef ? false : val_is_inline;
|
||||
if (is_constdef && val_is_inline) decl->is_substruct = true;
|
||||
if (!parse_enum_values(c, &decl->enums.values, visibility, is_constdef || expected_parameters == 1, is_constdef)) return poisoned_decl;
|
||||
return decl;
|
||||
}
|
||||
|
||||
@@ -2995,12 +3041,12 @@ static inline Decl *parse_enum_declaration(ParseContext *c, bool is_const)
|
||||
* func_body ::= ('=>' short_body) | compound_stmt
|
||||
*
|
||||
*/
|
||||
static inline Decl *parse_func_definition(ParseContext *c, AstId contracts, FunctionParse parse_kind)
|
||||
static inline Decl *parse_func_definition(ParseContext *c, ContractDescription *contracts, FunctionParse parse_kind)
|
||||
{
|
||||
advance_and_verify(c, TOKEN_FN);
|
||||
Decl *func = decl_calloc();
|
||||
func->decl_kind = DECL_FUNC;
|
||||
func->func_decl.docs = contracts;
|
||||
func->func_decl.docs = decl_from_contract_description(contracts);
|
||||
func->func_decl.attr_interface_method = parse_kind == FUNC_PARSE_INTERFACE;
|
||||
if (!parse_func_macro_header(c, func)) return poisoned_decl;
|
||||
if (func->name[0] == '@')
|
||||
@@ -3009,6 +3055,7 @@ static inline Decl *parse_func_definition(ParseContext *c, AstId contracts, Func
|
||||
}
|
||||
if (!parse_fn_parameter_list(c, &(func->func_decl.signature))) return poisoned_decl;
|
||||
if (!parse_attributes_for_global(c, func)) return poisoned_decl;
|
||||
attach_deprecation_from_contract(c, contracts, func);
|
||||
if (parse_kind != FUNC_PARSE_REGULAR)
|
||||
{
|
||||
if (tok_is(c, TOKEN_LBRACE) || tok_is(c, TOKEN_IMPLIES))
|
||||
@@ -3123,17 +3170,6 @@ static inline bool parse_import(ParseContext *c)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
INLINE void append_docs(AstId **next, AstId *first, Ast *new_doc)
|
||||
{
|
||||
if (!*first)
|
||||
{
|
||||
*first = astid(new_doc);
|
||||
}
|
||||
**next = astid(new_doc);
|
||||
*next = &new_doc->next;
|
||||
}
|
||||
|
||||
INLINE bool parse_doc_to_eol(ParseContext *c)
|
||||
{
|
||||
if (try_consume(c, TOKEN_DOCS_EOL)) return true;
|
||||
@@ -3187,27 +3223,20 @@ static bool parse_doc_direct_comment(ParseContext *c)
|
||||
/**
|
||||
* contract ::= expression_list (':'? STRING)?
|
||||
*/
|
||||
static inline bool parse_doc_contract(ParseContext *c, AstId *docs, AstId **docs_next, ContractKind kind)
|
||||
static inline bool parse_doc_contract(ParseContext *c, Expr ***list_ref, const char *prefix)
|
||||
{
|
||||
Ast *ast = ast_new_curr(c, AST_CONTRACT);
|
||||
ast->contract_stmt.kind = kind;
|
||||
Expr *expr = expr_new(EXPR_CONTRACT, c->span);
|
||||
const char *start = c->lexer.data.lex_start;
|
||||
advance(c);
|
||||
ASSIGN_EXPR_OR_RET(ast->contract_stmt.contract.decl_exprs, parse_expression_list(c, false), false);
|
||||
ASSIGN_EXPR_OR_RET(expr->contract_expr.decl_exprs, parse_expression_list(c, false), false);
|
||||
RANGE_EXTEND_PREV(expr);
|
||||
const char *end = start + 1;
|
||||
while (end[0] != '\n' && end[0] != '\0') end++;
|
||||
if (end > c->data.lex_start) end = c->data.lex_start;
|
||||
while (is_space(end[-1])) end--;
|
||||
scratch_buffer_clear();
|
||||
switch (kind)
|
||||
{
|
||||
case CONTRACT_ENSURE:
|
||||
scratch_buffer_append("@ensure \"");
|
||||
break;
|
||||
default:
|
||||
scratch_buffer_append("@require \"");
|
||||
break;
|
||||
}
|
||||
scratch_buffer_append(prefix);
|
||||
scratch_buffer_append(" \"");
|
||||
scratch_buffer_append_remove_space(start, (int)(end - start));
|
||||
scratch_buffer_append("\" violated");
|
||||
bool docs_to_comment = false;
|
||||
@@ -3225,18 +3254,18 @@ static inline bool parse_doc_contract(ParseContext *c, AstId *docs, AstId **docs
|
||||
scratch_buffer_append(": '");
|
||||
if (!parse_joined_strings(c, NULL, NULL)) return false;
|
||||
scratch_buffer_append("'.");
|
||||
ast->contract_stmt.contract.comment = scratch_buffer_copy();
|
||||
expr->contract_expr.comment = scratch_buffer_copy();
|
||||
if (!docs_to_comment)
|
||||
{
|
||||
SEMA_DEPRECATED(ast, "Not using ':' before the description is deprecated");
|
||||
SEMA_DEPRECATED(expr, "Not using ':' before the description is deprecated");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scratch_buffer_append(".");
|
||||
ast->contract_stmt.contract.expr_string = scratch_buffer_copy();
|
||||
expr->contract_expr.expr_string = scratch_buffer_copy();
|
||||
}
|
||||
append_docs(docs_next, docs, ast);
|
||||
vec_add(*list_ref, expr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3244,15 +3273,14 @@ static inline bool parse_doc_contract(ParseContext *c, AstId *docs, AstId **docs
|
||||
* param_contract ::= '@param' inout_attribute? any_identifier ( ':' STRING )?
|
||||
* inout_attribute ::= '[' '&'? ('in' | 'inout' | 'out') ']'
|
||||
*/
|
||||
static inline bool parse_contract_param(ParseContext *c, AstId *docs, AstId **docs_next)
|
||||
static inline bool parse_contract_param(ParseContext *c, ContractParam **list_ref)
|
||||
{
|
||||
Ast *ast = ast_new_curr(c, AST_CONTRACT);
|
||||
ast->contract_stmt.kind = CONTRACT_PARAM;
|
||||
advance(c);
|
||||
|
||||
// [inout] [in] [out]
|
||||
bool is_ref = false;
|
||||
InOutModifier mod = INOUT_ANY;
|
||||
SourceSpan span = c->span;
|
||||
if (try_consume(c, TOKEN_LBRACKET))
|
||||
{
|
||||
is_ref = try_consume(c, TOKEN_AMP);
|
||||
@@ -3277,16 +3305,17 @@ static inline bool parse_contract_param(ParseContext *c, AstId *docs, AstId **do
|
||||
CONSUME_OR_RET(TOKEN_RBRACKET, false);
|
||||
}
|
||||
|
||||
ContractParam param = { .span = span };
|
||||
switch (c->tok)
|
||||
{
|
||||
case TOKEN_IDENT:
|
||||
case TOKEN_CT_IDENT:
|
||||
case TOKEN_CT_TYPE_IDENT:
|
||||
case TOKEN_HASH_IDENT:
|
||||
ast->contract_stmt.param.name = symstr(c);
|
||||
param.name = symstr(c);
|
||||
break;
|
||||
case TOKEN_ELLIPSIS:
|
||||
ast->contract_stmt.param.name = NULL;
|
||||
param.name = NULL;
|
||||
break;
|
||||
case TOKEN_TYPE_IDENT:
|
||||
case TOKEN_CT_CONST_IDENT:
|
||||
@@ -3295,11 +3324,11 @@ static inline bool parse_contract_param(ParseContext *c, AstId *docs, AstId **do
|
||||
default:
|
||||
RETURN_PRINT_ERROR_HERE("Expected a parameter name here.");
|
||||
}
|
||||
ast->contract_stmt.param.modifier = mod;
|
||||
ast->contract_stmt.param.span = c->span;
|
||||
ast->contract_stmt.param.by_ref = is_ref;
|
||||
advance(c);
|
||||
param.modifier = mod;
|
||||
|
||||
param.by_ref = is_ref;
|
||||
advance(c);
|
||||
RANGE_EXTEND_PREV(¶m);
|
||||
if (parse_docs_to_comment(c))
|
||||
{
|
||||
if (!parse_doc_check_skip_string_eos(c))
|
||||
@@ -3327,55 +3356,40 @@ static inline bool parse_contract_param(ParseContext *c, AstId *docs, AstId **do
|
||||
}
|
||||
else
|
||||
{
|
||||
RANGE_EXTEND_PREV(ast);
|
||||
SEMA_DEPRECATED(ast, "Not using ':' before the string is deprecated.");
|
||||
SEMA_DEPRECATED(¶m, "Not using ':' before the string is deprecated.");
|
||||
}
|
||||
}
|
||||
append_docs(docs_next, docs, ast);
|
||||
vec_add(*list_ref, param);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool parse_doc_optreturn(ParseContext *c, AstId *docs, AstId **docs_next)
|
||||
static inline bool parse_doc_optreturn(ParseContext *c, Expr ***opt_return_ref)
|
||||
{
|
||||
Ast **returns = NULL;
|
||||
Ast *ast = ast_new_curr(c, AST_CONTRACT);
|
||||
ast->span = c->prev_span;
|
||||
advance_and_verify(c, TOKEN_QUESTION);
|
||||
ast->contract_stmt.kind = CONTRACT_OPTIONALS;
|
||||
while (1)
|
||||
{
|
||||
Ast *ret = ast_new_curr(c, AST_CONTRACT_FAULT);
|
||||
ASSIGN_EXPR_OR_RET(ret->contract_fault.expr, parse_expr(c), false);
|
||||
vec_add(returns, ret);
|
||||
ASSIGN_EXPR_OR_RET(Expr *expr, parse_expr(c), false);
|
||||
vec_add(*opt_return_ref, expr);
|
||||
if (!try_consume(c, TOKEN_COMMA)) break;
|
||||
}
|
||||
RANGE_EXTEND_PREV(ast);
|
||||
// Just ignore our potential string:
|
||||
if (!parse_doc_discarded_comment(c)) return false;
|
||||
ast->contract_stmt.faults = returns;
|
||||
append_docs(docs_next, docs, ast);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool parse_contracts(ParseContext *c, AstId *contracts_ref)
|
||||
static bool parse_contracts(ParseContext *c, ContractDescription *contracts_ref)
|
||||
{
|
||||
*contracts_ref = 0;
|
||||
if (!tok_is(c, TOKEN_DOCS_START)) return true;
|
||||
|
||||
AstId **next = &contracts_ref;
|
||||
if (c->data.strlen > 0)
|
||||
{
|
||||
Ast *ast = ast_new_curr(c, AST_CONTRACT);
|
||||
ast->contract_stmt.kind = CONTRACT_COMMENT;
|
||||
ast->contract_stmt.string = symstr(c);
|
||||
ast->contract_stmt.strlen = c->data.strlen;
|
||||
ast->span = c->span;
|
||||
append_docs(next, contracts_ref, ast);
|
||||
contracts_ref->comment = symstr(c);
|
||||
contracts_ref->comment_span = c->span;
|
||||
}
|
||||
|
||||
contracts_ref->first = c->span;
|
||||
advance_and_verify(c, TOKEN_DOCS_START);
|
||||
|
||||
bool return_comment = false;
|
||||
while (!try_consume(c, TOKEN_DOCS_END))
|
||||
{
|
||||
if (try_consume(c, TOKEN_DOCS_EOL)) continue;
|
||||
@@ -3383,44 +3397,103 @@ static bool parse_contracts(ParseContext *c, AstId *contracts_ref)
|
||||
{
|
||||
RETURN_PRINT_ERROR_HERE("Expected a directive starting with '@' here, like '@param' or `@require`");
|
||||
}
|
||||
if (!contracts_ref->first.a) contracts_ref->first = c->span;
|
||||
const char *name = symstr(c);
|
||||
if (name == kw_at_require)
|
||||
{
|
||||
if (!contracts_ref->has_contracts)
|
||||
{
|
||||
contracts_ref->first_contract = c->span;
|
||||
contracts_ref->has_contracts = true;
|
||||
}
|
||||
if (!parse_doc_contract(c, &contracts_ref->requires, "@require")) return false;
|
||||
goto END;
|
||||
}
|
||||
if (contracts_ref->first_non_require.a == 0)
|
||||
{
|
||||
contracts_ref->first_non_require = c->span;
|
||||
}
|
||||
if (name == kw_at_param)
|
||||
{
|
||||
if (!parse_contract_param(c, contracts_ref, next)) return false;
|
||||
if (!contracts_ref->has_contracts)
|
||||
{
|
||||
contracts_ref->first_contract = c->span;
|
||||
contracts_ref->has_contracts = true;
|
||||
}
|
||||
if (!parse_contract_param(c, &contracts_ref->params)) return false;
|
||||
}
|
||||
else if (name == kw_at_return)
|
||||
{
|
||||
advance(c);
|
||||
if (tok_is(c, TOKEN_QUESTION))
|
||||
{
|
||||
if (!parse_doc_optreturn(c, contracts_ref, next)) return false;
|
||||
if (!contracts_ref->has_contracts)
|
||||
{
|
||||
contracts_ref->first_contract = c->span;
|
||||
contracts_ref->has_contracts = true;
|
||||
}
|
||||
if (!parse_doc_optreturn(c, &contracts_ref->opt_returns)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (return_comment)
|
||||
{
|
||||
RETURN_PRINT_ERROR_HERE("Only one `@return` directive is allowed per contract.");
|
||||
}
|
||||
return_comment = true;
|
||||
if (!parse_doc_direct_comment(c)) return false;
|
||||
}
|
||||
}
|
||||
else if (name == kw_at_deprecated)
|
||||
{
|
||||
advance(c);
|
||||
if (!parse_doc_direct_comment(c)) return false;
|
||||
REMINDER("Implement @deprecated tracking");
|
||||
}
|
||||
else if (name == kw_at_require)
|
||||
{
|
||||
if (!parse_doc_contract(c, contracts_ref, next, CONTRACT_REQUIRE)) return false;
|
||||
if (contracts_ref->deprecated)
|
||||
{
|
||||
RETURN_PRINT_ERROR_HERE("Only one `@deprecated` directive is allowed per contract.");
|
||||
}
|
||||
Attr *attr = CALLOCS(Attr);
|
||||
attr->name = kw_at_deprecated;
|
||||
attr->span = c->prev_span;
|
||||
attr->path = NULL;
|
||||
attr->attr_kind = ATTRIBUTE_DEPRECATED;
|
||||
if (tok_is(c, TOKEN_DOCS_EOL) && peek(c) == TOKEN_STRING)
|
||||
{
|
||||
advance(c);
|
||||
}
|
||||
SourceSpan start = c->span;
|
||||
if (tok_is(c, TOKEN_STRING))
|
||||
{
|
||||
const char *str = NULL;
|
||||
size_t len;
|
||||
if (!parse_joined_strings(c, &str, &len)) return false;
|
||||
Expr *e = expr_new_const_string(extend_span_with_token(start, c->prev_span), str);
|
||||
vec_add(attr->exprs, e);
|
||||
}
|
||||
contracts_ref->deprecated = attr;
|
||||
}
|
||||
else if (name == kw_at_ensure)
|
||||
{
|
||||
if (!parse_doc_contract(c, contracts_ref, next, CONTRACT_ENSURE)) return false;
|
||||
if (!contracts_ref->has_contracts)
|
||||
{
|
||||
contracts_ref->first_contract = c->span;
|
||||
contracts_ref->has_contracts = true;
|
||||
}
|
||||
if (!parse_doc_contract(c, &contracts_ref->ensures, "@ensure")) return false;
|
||||
}
|
||||
else if (name == kw_at_pure)
|
||||
{
|
||||
Ast *ast = ast_new_curr(c, AST_CONTRACT);
|
||||
ast->contract_stmt.kind = CONTRACT_PURE;
|
||||
if (contracts_ref->pure)
|
||||
{
|
||||
RETURN_PRINT_ERROR_HERE("Multiple '@pure' declarations, please remove one.");
|
||||
}
|
||||
if (!contracts_ref->has_contracts)
|
||||
{
|
||||
contracts_ref->first_contract = c->span;
|
||||
contracts_ref->has_contracts = true;
|
||||
}
|
||||
contracts_ref->pure = true;
|
||||
advance(c);
|
||||
if (!parse_doc_direct_comment(c)) return false;
|
||||
append_docs(next, contracts_ref, ast);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3429,6 +3502,7 @@ static bool parse_contracts(ParseContext *c, AstId *contracts_ref)
|
||||
if (parse_doc_to_eol(c)) continue;
|
||||
RETURN_PRINT_ERROR_HERE("Expected a string description for the custom contract '%s'.", name);
|
||||
}
|
||||
END:
|
||||
if (parse_doc_to_eol(c)) continue;
|
||||
PRINT_ERROR_HERE("Expected the end of the contract here.");
|
||||
return false;
|
||||
@@ -3488,7 +3562,7 @@ END:
|
||||
*/
|
||||
Decl *parse_top_level_statement(ParseContext *c, ParseContext **context_out)
|
||||
{
|
||||
AstId contracts = 0;
|
||||
ContractDescription contracts = { .first = c->span };
|
||||
if (!parse_contracts(c, &contracts)) return poisoned_decl;
|
||||
Decl *decl;
|
||||
|
||||
@@ -3509,7 +3583,7 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **context_out)
|
||||
switch (tok)
|
||||
{
|
||||
case TOKEN_FN:
|
||||
decl = parse_func_definition(c, contracts, FUNC_PARSE_EXTERN);
|
||||
decl = parse_func_definition(c, &contracts, FUNC_PARSE_EXTERN);
|
||||
break;
|
||||
case TOKEN_CONST:
|
||||
decl = parse_top_level_const_declaration(c, true);
|
||||
@@ -3551,13 +3625,13 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **context_out)
|
||||
new_context->unit = unit_create(c->unit->file);
|
||||
*context_out = c = new_context;
|
||||
}
|
||||
if (!parse_module(c, contracts)) return poisoned_decl;
|
||||
if (!parse_module(c, &contracts)) return poisoned_decl;
|
||||
return NULL;
|
||||
case TOKEN_DOCS_START:
|
||||
PRINT_ERROR_HERE("There are more than one doc comment in a row, that is not allowed.");
|
||||
return poisoned_decl;
|
||||
case TOKEN_ALIAS:
|
||||
decl = parse_alias(c, contracts);
|
||||
decl = parse_alias(c, &contracts);
|
||||
if (decl->decl_kind == DECL_ALIAS_PATH)
|
||||
{
|
||||
if (!context_out)
|
||||
@@ -3574,11 +3648,11 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **context_out)
|
||||
attach_contracts = true;
|
||||
break;
|
||||
case TOKEN_FN:
|
||||
decl = parse_func_definition(c, contracts, c->unit->is_interface_file ? FUNC_PARSE_C3I : FUNC_PARSE_REGULAR);
|
||||
decl = parse_func_definition(c, &contracts, c->unit->is_interface_file ? FUNC_PARSE_C3I : FUNC_PARSE_REGULAR);
|
||||
break;
|
||||
case TOKEN_CT_ASSERT:
|
||||
{
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
if (contracts.has_contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
ASSIGN_AST_OR_RET(Ast *ast, parse_ct_assert_stmt(c), poisoned_decl);
|
||||
decl = decl_new_ct(DECL_CT_ASSERT, ast->span);
|
||||
decl->ct_assert_decl = ast;
|
||||
@@ -3586,7 +3660,7 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **context_out)
|
||||
}
|
||||
case TOKEN_CT_ERROR:
|
||||
{
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
if (contracts.has_contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
ASSIGN_AST_OR_RET(Ast *ast, parse_ct_error_stmt(c), poisoned_decl);
|
||||
decl = decl_new_ct(DECL_CT_ASSERT, ast->span);
|
||||
decl->ct_assert_decl = ast;
|
||||
@@ -3594,14 +3668,14 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **context_out)
|
||||
}
|
||||
case TOKEN_CT_ECHO:
|
||||
{
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
if (contracts.has_contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
ASSIGN_AST_OR_RET(Ast *ast, parse_ct_echo_stmt(c), poisoned_decl);
|
||||
decl = decl_new_ct(DECL_CT_ECHO, ast->span);
|
||||
decl->ct_echo_decl = ast;
|
||||
break;
|
||||
}
|
||||
case TOKEN_IMPORT:
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
if (contracts.has_contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
if (!context_out)
|
||||
{
|
||||
PRINT_ERROR_HERE("'import' may not appear inside a compile time statement.");
|
||||
@@ -3610,11 +3684,11 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **context_out)
|
||||
if (!parse_import(c)) return poisoned_decl;
|
||||
return NULL;
|
||||
case TOKEN_CT_INCLUDE:
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
if (contracts.has_contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_ct_include(c);
|
||||
break;
|
||||
case TOKEN_CT_EXEC:
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
if (contracts.has_contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_exec(c);
|
||||
break;
|
||||
case TOKEN_BITSTRUCT:
|
||||
@@ -3639,11 +3713,11 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **context_out)
|
||||
attach_contracts = true;
|
||||
break;
|
||||
case TOKEN_MACRO:
|
||||
decl = parse_macro_declaration(c, contracts);
|
||||
decl = parse_macro_declaration(c, &contracts);
|
||||
break;
|
||||
case TOKEN_ENUM:
|
||||
case TOKEN_CENUM:
|
||||
decl = parse_enum_declaration(c, false);
|
||||
case TOKEN_CONSTDEF:
|
||||
decl = parse_enum_declaration(c);
|
||||
attach_contracts = true;
|
||||
break;
|
||||
case TOKEN_FAULTDEF:
|
||||
@@ -3683,10 +3757,12 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **context_out)
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (!decl_ok(decl)) return decl;
|
||||
if (attach_contracts && contracts && !parse_attach_contracts(decl_template_get_generic(decl), contracts)) return poisoned_decl;
|
||||
attach_deprecation_from_contract(c, &contracts, decl);
|
||||
if (attach_contracts && contracts.has_contracts && !parse_attach_contracts(decl_template_get_generic(decl), &contracts)) return poisoned_decl;
|
||||
ASSERT(decl);
|
||||
return decl;
|
||||
CONTRACT_NOT_ALLOWED:
|
||||
RETURN_PRINT_ERROR_AT(poisoned_decl, astptr(contracts), "Contracts are only used for modules, functions and macros.");
|
||||
print_error_at(contracts.first, "Contracts are only used for modules, functions and macros.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
|
||||
|
||||
@@ -1444,7 +1444,7 @@ Ast *parse_stmt(ParseContext *c)
|
||||
case TOKEN_BIT_AND_ASSIGN:
|
||||
case TOKEN_BIT_OR_ASSIGN:
|
||||
case TOKEN_BIT_XOR_ASSIGN:
|
||||
case TOKEN_CENUM:
|
||||
case TOKEN_CONSTDEF:
|
||||
case TOKEN_COLON:
|
||||
case TOKEN_COMMA:
|
||||
case TOKEN_CT_CASE:
|
||||
|
||||
@@ -15,6 +15,24 @@ typedef enum
|
||||
PARAM_PARSE_ATTR,
|
||||
} ParameterParseKind;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *comment;
|
||||
SourceSpan comment_span;
|
||||
unsigned comment_len;
|
||||
Expr **requires;
|
||||
Expr **ensures;
|
||||
ContractParam *params;
|
||||
bool pure;
|
||||
bool has_contracts;
|
||||
SourceSpan first;
|
||||
SourceSpan first_non_require;
|
||||
SourceSpan first_contract;
|
||||
Expr **opt_returns;
|
||||
Attr *deprecated;
|
||||
} ContractDescription;
|
||||
|
||||
#define EMPTY_CONTRACT ((ContractDescription){ NULL })
|
||||
#define EXPECT_IDENT_FOR_OR(_name, _res) do { if (!expect_ident(c, _name)) return _res; } while(0)
|
||||
#define EXPECT_OR_RET(_tok, _res) do { if (!expect(c, _tok)) return _res; } while(0)
|
||||
#define CONSUME_OR_RET(_tok, _res) do { if (!expect(c, _tok)) return _res; advance(c); } while(0)
|
||||
@@ -46,7 +64,7 @@ Ast *parse_short_body(ParseContext *c, TypeInfoId return_type, bool is_regular_f
|
||||
|
||||
bool parse_attribute(ParseContext *c, Attr **attribute_ref, bool expect_eos);
|
||||
|
||||
bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref);
|
||||
bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref, const char *reject_visibility);
|
||||
Decl *parse_generic_decl(ParseContext *c);
|
||||
|
||||
bool parse_switch_body(ParseContext *c, Ast ***cases, TokenType case_type, TokenType default_type);
|
||||
@@ -74,7 +92,7 @@ INLINE void add_decl_to_list(Decl ***list, Decl *decl)
|
||||
vec_add(*list, decl);
|
||||
}
|
||||
|
||||
bool parse_module(ParseContext *c, AstId contracts);
|
||||
bool parse_module(ParseContext *c, ContractDescription *contracts);
|
||||
|
||||
bool try_consume(ParseContext *c, TokenType type);
|
||||
bool consume(ParseContext *c, TokenType type, const char *message, ...);
|
||||
|
||||
@@ -1238,7 +1238,7 @@ RETRY:;
|
||||
inner = decl->strukt.members[0]->type->canonical;
|
||||
break;
|
||||
case DECL_ENUM:
|
||||
case DECL_CONST_ENUM:
|
||||
case DECL_CONSTDEF:
|
||||
// Could be made to work.
|
||||
return false;
|
||||
default:
|
||||
@@ -1656,7 +1656,7 @@ static bool rule_enum_to_value(CastContext *cc, bool is_explicit, bool is_silent
|
||||
return cast_is_allowed(cc, is_explicit, is_silent);
|
||||
}
|
||||
|
||||
ASSERT(enum_decl->decl_kind != DECL_CONST_ENUM);
|
||||
ASSERT(enum_decl->decl_kind != DECL_CONSTDEF);
|
||||
|
||||
Type *inner = enum_decl->enums.type_info->type;
|
||||
if (!type_is_integer_or_bool_kind(type_flatten(cc->to)))
|
||||
@@ -2698,7 +2698,7 @@ static ConvGroup group_from_type[TYPE_LAST + 1] = {
|
||||
[TYPE_TYPEID] = CONV_TYPEID,
|
||||
[TYPE_POINTER] = CONV_POINTER,
|
||||
[TYPE_ENUM] = CONV_ENUM,
|
||||
[TYPE_CONST_ENUM] = CONV_RAW_ENUM,
|
||||
[TYPE_CONSTDEF] = CONV_RAW_ENUM,
|
||||
[TYPE_FUNC_PTR] = CONV_FUNC,
|
||||
[TYPE_STRUCT] = CONV_STRUCT,
|
||||
[TYPE_UNION] = CONV_UNION,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user