diff --git a/lib/std/collections/enumset.c3 b/lib/std/collections/enumset.c3 index d5128c50e..7638cf546 100644 --- a/lib/std/collections/enumset.c3 +++ b/lib/std/collections/enumset.c3 @@ -7,142 +7,141 @@ **/ module std::collections::enumset; +def EnumSetType = $typefrom(private::type_for_enum_elements(Enum.elements)) @private ; const IS_CHAR_ARRAY = Enum.elements > 128; - -$switch - -$case (Enum.elements > 128): -def EnumSetType @private = char[(Enum.elements + 7) / 8]; - -$case (Enum.elements > 64): -def EnumSetType @private = uint128; - -$case (Enum.elements > 32 || $$C_INT_SIZE > 32): -def EnumSetType @private = ulong; - -$case (Enum.elements > 16 || $$C_INT_SIZE > 16): -def EnumSetType @private = uint; - -$case (Enum.elements > 8 || $$C_INT_SIZE > 8): -def EnumSetType @private = ushort; - -$default: -def EnumSetType @private = char; - -$endswitch - def EnumSet = distinct EnumSetType; + fn void EnumSet.add(EnumSet* this, Enum v) { -$if IS_CHAR_ARRAY: - (*this)[v / 8] |= (char)(1u << (v % 8)); -$else - *this = (EnumSet)((EnumSetType)*this | 1u << (EnumSetType)v); -$endif + $if IS_CHAR_ARRAY: + (*this)[(usz)v / 8] |= (char)(1u << ((usz)v % 8)); + $else + *this = (EnumSet)((EnumSetType)*this | 1u << (EnumSetType)v); + $endif } fn void EnumSet.clear(EnumSet* this) { -$if IS_CHAR_ARRAY: - *this = {}; -$else - *this = 0; -$endif + $if IS_CHAR_ARRAY: + *this = {}; + $else + *this = 0; + $endif } fn bool EnumSet.remove(EnumSet* this, Enum v) { -$if IS_CHAR_ARRAY: - if (!this.has(v) @inline) return false; - (*this)[v / 8] &= (char)~(1 << (v % 8)); - return true; -$else - EnumSetType old = (EnumSetType)*this; - EnumSetType new = old & ~(1u << (EnumSetType)v); - *this = (EnumSet)new; - return old != new; -$endif + $if IS_CHAR_ARRAY: + if (!this.has(v) @inline) return false; + (*this)[(usz)v / 8] &= (char)~(1u << ((usz)v % 8)); + return true; + $else + EnumSetType old = (EnumSetType)*this; + EnumSetType new = old & ~(1u << (EnumSetType)v); + *this = (EnumSet)new; + return old != new; + $endif } fn bool EnumSet.has(EnumSet* this, Enum v) { -$if IS_CHAR_ARRAY: - return (bool)(((*this)[v / 8] << (v % 8)) & 0x01); -$else - return ((EnumSetType)*this & (1u << (EnumSetType)v)) != 0; -$endif + $if IS_CHAR_ARRAY: + return (bool)(((*this)[(usz)v / 8] << ((usz)v % 8)) & 0x01); + $else + return ((EnumSetType)*this & (1u << (EnumSetType)v)) != 0; + $endif } fn void EnumSet.add_all(EnumSet* this, EnumSet s) { -$if IS_CHAR_ARRAY: - foreach (i, c : s) (*this)[i] |= c; -$else - *this = (EnumSet)((EnumSetType)*this | (EnumSetType)s); -$endif + $if IS_CHAR_ARRAY: + foreach (i, c : s) (*this)[i] |= c; + $else + *this = (EnumSet)((EnumSetType)*this | (EnumSetType)s); + $endif } fn void EnumSet.retain_all(EnumSet* this, EnumSet s) { -$if IS_CHAR_ARRAY: - foreach (i, c : s) (*this)[i] &= c; -$else - *this = (EnumSet)((EnumSetType)*this & (EnumSetType)s); -$endif + $if IS_CHAR_ARRAY: + foreach (i, c : s) (*this)[i] &= c; + $else + *this = (EnumSet)((EnumSetType)*this & (EnumSetType)s); + $endif } fn void EnumSet.remove_all(EnumSet* this, EnumSet s) { -$if IS_CHAR_ARRAY: - foreach (i, c : s) (*this)[i] &= ~c; -$else - *this = (EnumSet)((EnumSetType)*this & ~(EnumSetType)s); -$endif + $if IS_CHAR_ARRAY: + foreach (i, c : s) (*this)[i] &= ~c; + $else + *this = (EnumSet)((EnumSetType)*this & ~(EnumSetType)s); + $endif } fn EnumSet EnumSet.and_of(EnumSet* this, EnumSet s) { -$if IS_CHAR_ARRAY: - EnumSet copy = *this; - copy.retain_all(s); - return copy; -$else - return (EnumSet)((EnumSetType)*this & (EnumSetType)s); -$endif + $if IS_CHAR_ARRAY: + EnumSet copy = *this; + copy.retain_all(s); + return copy; + $else + return (EnumSet)((EnumSetType)*this & (EnumSetType)s); + $endif } fn EnumSet EnumSet.or_of(EnumSet* this, EnumSet s) { -$if IS_CHAR_ARRAY: - EnumSet copy = *this; - copy.add_all(s); - return copy; -$else - return (EnumSet)((EnumSetType)*this | (EnumSetType)s); -$endif + $if IS_CHAR_ARRAY: + EnumSet copy = *this; + copy.add_all(s); + return copy; + $else + return (EnumSet)((EnumSetType)*this | (EnumSetType)s); + $endif } fn EnumSet EnumSet.diff_of(EnumSet* this, EnumSet s) { -$if IS_CHAR_ARRAY: - EnumSet copy = *this; - copy.remove_all(s); - return copy; -$else - return (EnumSet)((EnumSetType)*this & ~(EnumSetType)s); -$endif + $if IS_CHAR_ARRAY: + EnumSet copy = *this; + copy.remove_all(s); + return copy; + $else + return (EnumSet)((EnumSetType)*this & ~(EnumSetType)s); + $endif } fn EnumSet EnumSet.xor_of(EnumSet* this, EnumSet s) { -$if IS_CHAR_ARRAY: - EnumSet copy = *this; - foreach (i, c : s) copy[i] ^= c; - return copy; -$else - return (EnumSet)((EnumSetType)*this ^ (EnumSetType)s); -$endif + $if IS_CHAR_ARRAY: + EnumSet copy = *this; + foreach (i, c : s) copy[i] ^= c; + return copy; + $else + return (EnumSet)((EnumSetType)*this ^ (EnumSetType)s); + $endif +} + +module std::collections::enumset::private; + +macro typeid type_for_enum_elements(usz $elements) +{ + $switch + $case ($elements > 128): + return char[($elements + 7) / 8].typeid; + $case ($elements > 64): + return uint128.typeid; + $case ($elements > 32 || $$C_INT_SIZE > 32): + return ulong.typeid; + $case ($elements > 16 || $$C_INT_SIZE > 16): + return uint.typeid; + $case ($elements > 8 || $$C_INT_SIZE > 8): + return ushort.typeid; + $default: + return char.typeid; + $endswitch; } \ No newline at end of file diff --git a/lib/std/collections/list.c3 b/lib/std/collections/list.c3 index 06fdda514..ba01f884c 100644 --- a/lib/std/collections/list.c3 +++ b/lib/std/collections/list.c3 @@ -5,6 +5,8 @@ module std::collections::list; import std::math; def ElementPredicate = fn bool(Type *type); +const ELEMENT_IS_EQUATABLE = types::is_equatable_type(Type); +const ELEMENT_IS_POINTER = Type.kindof == POINTER; struct List { @@ -38,24 +40,28 @@ fn void List.tinit(List* list, usz initial_capacity = 16) list.init(initial_capacity, mem::temp()) @inline; } +fn void! List.to_format(List* list, Formatter* formatter) @dynamic +{ + switch (list.size) + { + case 0: + formatter.print("[]")!; + case 1: + formatter.printf("[%s]", list.entries[0])!; + default: + formatter.print("[")!; + foreach (i, element : list.entries[:list.size]) + { + if (i != 0) formatter.print(", ")!; + formatter.printf("%s", element)!; + } + formatter.print("]")!; + } +} + fn String List.to_string(List* list, Allocator* using = mem::heap()) @dynamic { - if (!list.size) return "[]".copy(using); - if (list.size == 1) return string::printf("[%s]", list.entries[0], .using = using); - - @stack_mem(512 + 128; Allocator* mem) - { - DString str; - str.init(512, mem); - str.append("["); - foreach (i, element : list.entries[:list.size]) - { - if (i != 0) str.append(", "); - str.printf("%s", element); - } - str.printf("]"); - return str.copy_str(using); - }; + return string::printf("%s", *list); } fn void List.push(List* list, Type element) @inline @@ -301,9 +307,8 @@ fn void List.ensure_capacity(List* list, usz added = 1) @inline @private // Functions for equatable types -$if types::is_equatable_type(Type): -fn usz! List.index_of(List* list, Type type) +fn usz! List.index_of(List* list, Type type) @if(ELEMENT_IS_EQUATABLE) { foreach (i, v : list) { @@ -312,7 +317,7 @@ fn usz! List.index_of(List* list, Type type) return SearchResult.MISSING?; } -fn usz! List.rindex_of(List* list, Type type) +fn usz! List.rindex_of(List* list, Type type) @if(ELEMENT_IS_EQUATABLE) { foreach_r (i, v : list) { @@ -321,7 +326,7 @@ fn usz! List.rindex_of(List* list, Type type) return SearchResult.MISSING?; } -fn bool List.equals(List* list, List other_list) +fn bool List.equals(List* list, List other_list) @if(ELEMENT_IS_EQUATABLE) { if (list.size != other_list.size) return false; foreach (i, v : list) @@ -338,7 +343,7 @@ fn bool List.equals(List* list, List other_list) * @param value "The value to search for" * @return "True if the value is found, false otherwise" **/ -fn bool List.contains(List* list, Type value) +fn bool List.contains(List* list, Type value) @if(ELEMENT_IS_EQUATABLE) { foreach (i, v : list) { @@ -353,7 +358,7 @@ fn bool List.contains(List* list, Type value) * @param value "The value to remove" * @return "the number of deleted elements." **/ -fn usz List.remove(List* list, Type value) +fn usz List.remove(List* list, Type value) @if(ELEMENT_IS_EQUATABLE) { usz size = list.size; for (usz i = size; i > 0; i--) @@ -368,29 +373,24 @@ fn usz List.remove(List* list, Type value) return size - list.size; } -fn void List.remove_all(List* list, List* other_list) +fn void List.remove_all(List* list, List* other_list) @if(ELEMENT_IS_EQUATABLE) { if (!other_list.size) return; foreach (v : other_list) list.remove(v); } - -$endif - -$if Type.kindof == POINTER: - /** * @param [&in] list * @return "The number non-null values in the list" **/ -fn usz List.compact_count(List* list) +fn usz List.compact_count(List* list) @if(ELEMENT_IS_POINTER) { usz vals = 0; foreach (v : list) if (v) vals++; return vals; } -fn usz List.compact(List* list) +fn usz List.compact(List* list) @if(ELEMENT_IS_POINTER) { usz size = list.size; for (usz i = size; i > 0; i--) @@ -404,5 +404,3 @@ fn usz List.compact(List* list) } return size - list.size; } - -$endif \ No newline at end of file diff --git a/lib/std/collections/map.c3 b/lib/std/collections/map.c3 index 6c265313f..3aa9d544b 100644 --- a/lib/std/collections/map.c3 +++ b/lib/std/collections/map.c3 @@ -7,7 +7,7 @@ import std::math; const uint DEFAULT_INITIAL_CAPACITY = 16; const uint MAXIMUM_CAPACITY = 1u << 31; const float DEFAULT_LOAD_FACTOR = 0.75; - +const VALUE_IS_EQUATABLE = types::is_equatable(Value); struct HashMap { @@ -216,8 +216,7 @@ fn Value[] HashMap.value_list(HashMap* map, Allocator* using = mem::heap()) return list; } -$if types::is_equatable(Value): -fn bool HashMap.has_value(HashMap* map, Value v) +fn bool HashMap.has_value(HashMap* map, Value v) @if(VALUE_IS_EQUATABLE) { if (!map.count) return false; foreach (Entry* entry : map.table) @@ -230,7 +229,6 @@ fn bool HashMap.has_value(HashMap* map, Value v) } return false; } -$endif // --- private methods diff --git a/lib/std/collections/object.c3 b/lib/std/collections/object.c3 index 10592657f..b81e6d0b0 100644 --- a/lib/std/collections/object.c3 +++ b/lib/std/collections/object.c3 @@ -209,25 +209,25 @@ macro Object* object_from_value(value) @private { var $Type = $typeof(value); -$switch - $case types::is_int($Type): - return new_int(value); - $case types::is_float($Type): - return new_float(value); - $case $Type.typeid == String.typeid: - return new_string(value); - $case $Type.typeid == bool.typeid: - return new_bool(value); - $case $Type.typeid == Object*.typeid: - return value; - $case $Type.typeid == void*.typeid: - assert(value == null); - return &NULL_OBJECT; - $case $checks(String s = value): - return new_string(value); - $default: - $error "Unsupported object type."; -$endswitch + $switch + $case types::is_int($Type): + return new_int(value); + $case types::is_float($Type): + return new_float(value); + $case $Type.typeid == String.typeid: + return new_string(value); + $case $Type.typeid == bool.typeid: + return new_bool(value); + $case $Type.typeid == Object*.typeid: + return value; + $case $Type.typeid == void*.typeid: + assert(value == null); + return &NULL_OBJECT; + $case $checks(String s = value): + return new_string(value); + $default: + $error "Unsupported object type."; + $endswitch } @@ -468,7 +468,7 @@ fn Object* Object.get_or_create_obj(Object* o, String key) return container; } -def ObjectInternalMap @private = HashMap; -def ObjectInternalList @private = List; -def ObjectInternalMapEntry @private = Entry; +def ObjectInternalMap = HashMap @private; +def ObjectInternalList = List @private; +def ObjectInternalMapEntry = Entry @private; diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index 197be536a..a756dd455 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -181,11 +181,11 @@ macro enum_by_name($Type, String enum_name) @builtin **/ macro bool @likely(bool #value, $probability = 1.0) @builtin { -$if $probability == 1.0: - return $$expect(#value, true); -$else - return $$expect_with_probability(#value, true, $probability); -$endif + $if $probability == 1.0: + return $$expect(#value, true); + $else + return $$expect_with_probability(#value, true, $probability); + $endif } /** @@ -197,11 +197,11 @@ $endif **/ macro bool @unlikely(bool #value, $probability = 1.0) @builtin { -$if $probability == 1.0: - return $$expect(#value, false); -$else - return $$expect_with_probability(#value, false, $probability); -$endif + $if $probability == 1.0: + return $$expect(#value, false); + $else + return $$expect_with_probability(#value, false, $probability); + $endif } /** @@ -212,9 +212,9 @@ $endif macro @expect(#value, expected, $probability = 1.0) @builtin { $if $probability == 1.0: - return $$expect(#value, ($typeof(#value))expected); + return $$expect(#value, ($typeof(#value))expected); $else - return $$expect_with_probability(#value, expected, $probability); + return $$expect_with_probability(#value, expected, $probability); $endif } diff --git a/lib/std/core/builtin_comparison.c3 b/lib/std/core/builtin_comparison.c3 index 6bbd53235..aef0c5292 100644 --- a/lib/std/core/builtin_comparison.c3 +++ b/lib/std/core/builtin_comparison.c3 @@ -8,14 +8,14 @@ module std::core::builtin; **/ macro less(a, b) @builtin { -$switch + $switch $case $defined(a.less): return a.less(b); $case $defined(a.compare_to): return a.compare_to(b) < 0; $default: return a < b; -$endswitch + $endswitch } /** @@ -23,14 +23,14 @@ $endswitch **/ macro less_eq(a, b) @builtin { -$switch + $switch $case $defined(a.less): return !b.less(a); $case $defined(a.compare_to): return a.compare_to(b) <= 0; $default: return a <= b; -$endswitch + $endswitch } /** @@ -38,14 +38,14 @@ $endswitch **/ macro greater(a, b) @builtin { -$switch + $switch $case $defined(a.less): return b.less(a); $case $defined(a.compare_to): return a.compare_to(b) > 0; $default: return a > b; -$endswitch + $endswitch } /** @@ -53,14 +53,14 @@ $endswitch **/ macro greater_eq(a, b) @builtin { -$switch + $switch $case $defined(a.less): return !a.less(b); $case $defined(a.compare_to): return a.compare_to(b) >= 0; $default: return a >= b; -$endswitch + $endswitch } /** @@ -68,7 +68,7 @@ $endswitch **/ macro bool equals(a, b) @builtin { -$switch + $switch $case $defined(a.equals): return a.equals(b); $case $defined(a.compare_to): @@ -77,7 +77,7 @@ $switch return !a.less(b) && !b.less(a); $default: return a == b; -$endswitch + $endswitch } macro min(x, ...) @builtin diff --git a/lib/std/core/cinterop.c3 b/lib/std/core/cinterop.c3 index 07b1201f4..23f869447 100644 --- a/lib/std/core/cinterop.c3 +++ b/lib/std/core/cinterop.c3 @@ -16,72 +16,40 @@ $assert C_SHORT_SIZE <= C_INT_SIZE; $assert C_INT_SIZE <= C_LONG_SIZE; $assert C_LONG_SIZE <= C_LONG_LONG_SIZE; -$switch ($$C_INT_SIZE) -$case 64: - def CInt = long; - def CUInt = ulong; -$case 32: - def CInt = int; - def CUInt = uint; -$case 16: - def CInt = short; - def CUInt = ushort; -$default: - $error "Invalid C int size"; -$endswitch - -$switch ($$C_LONG_SIZE) -$case 64: - def CLong = long; - def CULong = ulong; -$case 32: - def CLong = int; - def CULong = uint; -$case 16: - def CLong = short; - def CULong = ushort; -$default: - $error "Invalid C long size"; -$endswitch - -$switch ($$C_SHORT_SIZE) -$case 32: - def CShort = int; - def CUShort = uint; -$case 16: - def CShort = short; - def CUShort = ushort; -$case 8: - def CShort = ichar; - def CUShort = char; -$default: - $error "Invalid C short size"; -$endswitch - -$switch ($$C_LONG_LONG_SIZE) -$case 128: - def CLongLong = int128; - def CULongLong = uint128; -$case 64: - def CLongLong = long; - def CULongLong = ulong; -$case 32: - def CLongLong = int; - def CULongLong = uint; -$case 16: - def CLongLong = short; - def CULongLong = ushort; -$default: - $error "Invalid C long long size"; -$endswitch - - - +def CShort = $typefrom(signed_int_from_bitsize($$C_SHORT_SIZE)); +def CUShort = $typefrom(unsigned_int_from_bitsize($$C_SHORT_SIZE)); +def CInt = $typefrom(signed_int_from_bitsize($$C_INT_SIZE)); +def CUInt = $typefrom(unsigned_int_from_bitsize($$C_INT_SIZE)); +def CLong = $typefrom(signed_int_from_bitsize($$C_LONG_SIZE)); +def CULong = $typefrom(unsigned_int_from_bitsize($$C_LONG_SIZE)); +def CLongLong = $typefrom(signed_int_from_bitsize($$C_LONG_LONG_SIZE)); +def CULongLong = $typefrom(unsigned_int_from_bitsize($$C_LONG_LONG_SIZE)); def CSChar = ichar; def CUChar = char; -$if $$C_CHAR_IS_SIGNED: - def CChar = ichar; -$else - def CChar = char; -$endif +def CChar = $typefrom($$C_CHAR_IS_SIGNED ? ichar.typeid : char.typeid); + +// Helper macros +macro typeid signed_int_from_bitsize(usz $bitsize) @private +{ + $switch ($bitsize) + $case 128: return int128.typeid; + $case 64: return long.typeid; + $case 32: return int.typeid; + $case 16: return short.typeid; + $case 8: return ichar.typeid; + $default: $error("Invalid bitsize"); + $endswitch +} + +macro typeid unsigned_int_from_bitsize(usz $bitsize) @private +{ + $switch ($bitsize) + $case 128: return uint128.typeid; + $case 64: return ulong.typeid; + $case 32: return uint.typeid; + $case 16: return ushort.typeid; + $case 8: return char.typeid; + $default: $error("Invalid bitsize"); + $endswitch +} diff --git a/lib/std/core/env.c3 b/lib/std/core/env.c3 index cc2e50ebd..c013da824 100644 --- a/lib/std/core/env.c3 +++ b/lib/std/core/env.c3 @@ -128,6 +128,22 @@ const bool BENCHMARKING = $$BENCHMARKING; const bool TESTING = $$TESTING; const MemoryEnvironment MEMORY_ENV = (MemoryEnvironment)$$MEMORY_ENVIRONMENT; +const LINUX_LIBC @builtin = env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == LINUX; +const DARWIN_LIBC @builtin = env::COMPILER_LIBC_AVAILABLE && env::os_is_darwin(); +const WIN32_LIBC @builtin = env::COMPILER_LIBC_AVAILABLE && env::os_is_win32(); +const POSIX_LIBC @builtin = env::COMPILER_LIBC_AVAILABLE && env::os_is_posix(); +const OPENBSD_LIBC @builtin = env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OPENBSD; +const FREEBSD_LIBC @builtin = env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == FREEBSD; +const NETBSD_LIBC @builtin = env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == NETBSD; +const WASI_LIBC @builtin = env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == WASI; +const WASM_NOLIBC @builtin = !env::COMPILER_LIBC_AVAILABLE && env::ARCH_TYPE == ArchType.WASM32 || env::ARCH_TYPE == ArchType.WASM64; +const bool NO_LIBC = !env::COMPILER_LIBC_AVAILABLE; +const bool WIN32 = OS_TYPE == WIN32; +const bool DARWIN = OS_TYPE == IOS || OS_TYPE == MACOS || OS_TYPE == TVOS || OS_TYPE == WATCHOS; +const bool LINUX = OS_TYPE == LINUX; +const bool POSIX = os_is_posix(); +const bool WASI = OS_TYPE == WASI; + macro bool os_is_win32() { return OS_TYPE == WIN32; @@ -177,15 +193,15 @@ macro bool os_is_posix() **/ fn String! get_var(String name) { -$if COMPILER_LIBC_AVAILABLE && !os_is_win32(): + $if COMPILER_LIBC_AVAILABLE && !WIN32_LIBC: @pool() { ZString val = libc::getenv(name.zstr_tcopy()); return val ? val.as_str() : SearchResult.MISSING?; }; -$else + $else return ""; -$endif + $endif } @@ -196,7 +212,7 @@ $endif **/ fn void set_var(String name, String value, bool overwrite = true) { -$if COMPILER_LIBC_AVAILABLE && !os_is_win32(): + $if COMPILER_LIBC_AVAILABLE && !WIN32_LIBC: @pool() { if (libc::setenv(name.zstr_tcopy(), value.zstr_copy(), (int)overwrite)) @@ -204,7 +220,7 @@ $if COMPILER_LIBC_AVAILABLE && !os_is_win32(): unreachable(); } }; -$endif + $endif } /** @@ -213,7 +229,7 @@ $endif **/ fn void clear_var(String name) { -$if COMPILER_LIBC_AVAILABLE && !os_is_win32(): + $if COMPILER_LIBC_AVAILABLE && !WIN32_LIBC: @pool() { if (libc::unsetenv(name.zstr_tcopy())) @@ -221,6 +237,6 @@ $if COMPILER_LIBC_AVAILABLE && !os_is_win32(): unreachable(); } }; -$endif + $endif } diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index 3fa2fd010..50d2d687b 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -411,10 +411,10 @@ macro TempAllocator* temp() macro Allocator* current_allocator() => thread_allocator; macro Allocator* heap() => thread_allocator; -$if !env::COMPILER_LIBC_AVAILABLE && env::ARCH_TYPE == ArchType.WASM32 || env::ARCH_TYPE == ArchType.WASM64: + +module std::core::mem @if(WASM_NOLIBC); SimpleHeapAllocator wasm_allocator @private; - extern int __heap_base; static initialize @priority(1) @@ -425,7 +425,4 @@ static initialize @priority(1) if (start > mem::DEFAULT_MEM_ALIGNMENT) allocator::wasm_memory.use = start; wasm_allocator.init(fn (x) => allocator::wasm_memory.allocate_block(x)); thread_allocator = &wasm_allocator; -} -$endif - - +} \ No newline at end of file diff --git a/lib/std/core/private/main_stub.c3 b/lib/std/core/private/main_stub.c3 index f374b3e15..524c619e3 100644 --- a/lib/std/core/private/main_stub.c3 +++ b/lib/std/core/private/main_stub.c3 @@ -55,7 +55,7 @@ macro int @main_to_void_main_args(#m, int argc, char** argv) return 0; } -$if env::os_is_win32(): +module std::core::main_stub @if(env::os_is_win32()); extern fn Char16** _win_command_line_to_argv_w(ushort* cmd_line, int* argc_ptr) @extern("CommandLineToArgvW"); @@ -164,5 +164,3 @@ macro int @wmain_to_void_main_args(#m, int argc, Char16** argv) #m(args); return 0; } - -$endif \ No newline at end of file diff --git a/lib/std/core/runtime.c3 b/lib/std/core/runtime.c3 index f593d6ef4..e9d7d04ec 100644 --- a/lib/std/core/runtime.c3 +++ b/lib/std/core/runtime.c3 @@ -88,12 +88,12 @@ fn bool __run_default_test_runner() return test_runner_create().run(); } -$if !env::COMPILER_LIBC_AVAILABLE && env::ARCH_TYPE == ArchType.WASM32 || env::ARCH_TYPE == ArchType.WASM64: + +module std::core::runtime @if(WASM_NOLIBC); extern fn void __wasm_call_ctors(); fn void wasm_initialize() @extern("_initialize") @wasm { // The linker synthesizes this to call constructors. __wasm_call_ctors(); -} -$endif \ No newline at end of file +} \ No newline at end of file diff --git a/lib/std/hash/sha1.c3 b/lib/std/hash/sha1.c3 index 941e8d0bc..cf3701730 100644 --- a/lib/std/hash/sha1.c3 +++ b/lib/std/hash/sha1.c3 @@ -96,12 +96,12 @@ macro @blk(&block, i) @local macro @blk0(&block, i) @local { -$if env::BIG_ENDIAN: - return block.l[i]; -$else - return block.l[i] = (block.l[i].rotl(24) & 0xFF00FF00) - | (block.l[i].rotl(8) & 0x00FF00FF); -$endif + $if env::BIG_ENDIAN: + return block.l[i]; + $else + return block.l[i] = (block.l[i].rotl(24) & 0xFF00FF00) + | (block.l[i].rotl(8) & 0x00FF00FF); + $endif } macro @r0(&block, v, &w, x, y, &z, i) @local diff --git a/lib/std/io/io_printf.c3 b/lib/std/io/io_printf.c3 index c2c1a3356..23f6a5575 100644 --- a/lib/std/io/io_printf.c3 +++ b/lib/std/io/io_printf.c3 @@ -144,6 +144,7 @@ macro bool! Formatter.print_with_function(Formatter* this, any arg) return false; } + fn void! Formatter.out_str(Formatter* this, any arg) @private { switch (arg.type.kindof) @@ -425,3 +426,18 @@ fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys) return this.idx; } + +fn usz! Formatter.print(Formatter* this, String str) +{ + if (!this.out_fn) + { + // use null output function + this.out_fn = &out_null_fn; + } + usz len = str.len; + for (usz i = 0; i < len; i++) + { + this.out(str[i])!; + } + return this.idx; +} diff --git a/lib/std/io/io_stream.c3 b/lib/std/io/io_stream.c3 index b0fa75c57..f2c834795 100644 --- a/lib/std/io/io_stream.c3 +++ b/lib/std/io/io_stream.c3 @@ -169,21 +169,21 @@ fn usz! Stream.copy_to(Stream* s, Stream* dst, char[] buffer = {}) if (buffer.len) return copy_through_buffer(s, dst, buffer); if (WriteToStreamFn func = s.fns.write_stream_fn) return func(s, dst); if (ReadFromStreamFn func = dst.fns.read_stream_fn) return func(dst, s); -$switch (env::MEMORY_ENV) -$case NORMAL: - @pool() - { - return copy_through_buffer(s, dst, tmalloc(char, 4096)); - }; -$case SMALL: - @pool() - { - return copy_through_buffer(s, dst, tmalloc(char, 1024)); - }; -$case TINY: -$case NONE: - return copy_through_buffer(s, dst, &&(char[256]{})); -$endswitch + $switch (env::MEMORY_ENV) + $case NORMAL: + @pool() + { + return copy_through_buffer(s, dst, tmalloc(char, 4096)); + }; + $case SMALL: + @pool() + { + return copy_through_buffer(s, dst, tmalloc(char, 1024)); + }; + $case TINY: + $case NONE: + return copy_through_buffer(s, dst, &&(char[256]{})); + $endswitch } macro usz! copy_through_buffer(Stream* s, Stream* dst, char[] buffer) @local diff --git a/lib/std/io/os/chdir.c3 b/lib/std/io/os/chdir.c3 index b7bba0476..bee71a546 100644 --- a/lib/std/io/os/chdir.c3 +++ b/lib/std/io/os/chdir.c3 @@ -1,44 +1,30 @@ module std::io::os; import libc; - -$switch - -$case env::COMPILER_LIBC_AVAILABLE && env::os_is_posix(): - -macro void! native_chdir(Path p) -{ - if (posix::chdir(p.as_zstr())) - { - switch (libc::errno()) - { - case errno::EACCES: return IoError.NO_PERMISSION?; - case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?; - case errno::ENOTDIR: return IoError.FILE_NOT_DIR?; - case errno::ENOENT: return IoError.FILE_NOT_FOUND?; - case errno::ELOOP: return IoError.SYMLINK_FAILED?; - default: return IoError.GENERAL_ERROR?; - } - } -} - -$case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32(): - macro void! native_chdir(Path path) { - @pool() - { - // TODO improve with better error handling. - if (win32::win32_SetCurrentDirectoryW(path.as_str().to_temp_utf16()!!)) return; - }; - return IoError.GENERAL_ERROR?; + $switch + $case POSIX_LIBC: + if (posix::chdir(path.as_zstr())) + { + switch (libc::errno()) + { + case errno::EACCES: return IoError.NO_PERMISSION?; + case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?; + case errno::ENOTDIR: return IoError.FILE_NOT_DIR?; + case errno::ENOENT: return IoError.FILE_NOT_FOUND?; + case errno::ELOOP: return IoError.SYMLINK_FAILED?; + default: return IoError.GENERAL_ERROR?; + } + } + $case WIN32_LIBC: + @pool() + { + // TODO improve with better error handling. + if (win32::win32_SetCurrentDirectoryW(path.as_str().to_temp_utf16()!!)) return; + }; + return IoError.GENERAL_ERROR?; + $default: + unreachable("'getcwd' not available"); + $endswitch } - -$default: - -fn void! native_chdir(Path path) -{ - unreachable("'getcwd' not available"); -} - -$endswitch \ No newline at end of file diff --git a/lib/std/io/os/file.c3 b/lib/std/io/os/file.c3 index 1c40a8ebf..717a8a332 100644 --- a/lib/std/io/os/file.c3 +++ b/lib/std/io/os/file.c3 @@ -9,28 +9,13 @@ def FtellFn = fn usz!(void*); def FwriteFn = fn usz!(void*, char[] buffer); def FreadFn = fn usz!(void*, char[] buffer); -$if !$defined(native_fopen_fn): -FopenFn native_fopen_fn @weak; -$endif -$if !$defined(native_fclose_fn): -FcloseFn native_fclose_fn @weak; -$endif -$if !$defined(native_freopen_fn): -FreopenFn native_freopen_fn @weak; -$endif -$if !$defined(native_fseek_fn): -FseekFn native_fseek_fn @weak; -$endif -$if !$defined(native_ftell_fn): -FtellFn native_ftell_fn @weak; -$endif -$if !$defined(native_fwrite_fn): -FwriteFn native_fwrite_fn @weak; -$endif -$if !$defined(native_fread_fn): -FreadFn native_fread_fn @weak; -$endif - +FopenFn native_fopen_fn @weak @if(!$defined(native_fopen_fn)); +FcloseFn native_fclose_fn @weak @if(!$defined(native_fclose_fn)); +FreopenFn native_freopen_fn @weak @if(!$defined(native_freopen_fn)); +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)); /** * @require mode.len > 0 @@ -38,20 +23,20 @@ $endif **/ fn void*! native_fopen(String filename, String mode) @inline { -$if !env::COMPILER_LIBC_AVAILABLE: + $if !env::COMPILER_LIBC_AVAILABLE: if (native_fopen_fn) return native_fopen_fn(filename, mode); unreachable("Tried to call fopen without support."); -$else - @pool() - { - $if env::os_is_win32(): - void* file = (CFile)_wfopen(filename.to_temp_utf16(), filename.to_temp_utf16())!; $else - void* file = libc::fopen(filename.zstr_tcopy(), mode.zstr_tcopy()); + @pool() + { + $if env::os_is_win32(): + void* file = (CFile)_wfopen(filename.to_temp_utf16(), filename.to_temp_utf16())!; + $else + void* file = libc::fopen(filename.zstr_tcopy(), mode.zstr_tcopy()); + $endif + return file ?: file_open_errno()?; + }; $endif - return file ?: file_open_errno()?; - }; -$endif } /** @@ -60,71 +45,71 @@ $endif **/ fn void*! native_freopen(void* file, String filename, String mode) @inline { -$if !env::COMPILER_LIBC_AVAILABLE: + $if !env::COMPILER_LIBC_AVAILABLE: if (native_freopen_fn) return native_freopen_fn(file, filename, mode); unreachable("Tried to call freopen without support."); -$else - @pool() - { - $if env::os_is_win32(): - file = _wfreopen(filename.to_temp_utf16(), mode.to_temp_utf16(), file)!; $else - file = libc::freopen(filename.zstr_tcopy(), mode.zstr_tcopy(), file); + @pool() + { + $if env::os_is_win32(): + file = _wfreopen(filename.to_temp_utf16(), mode.to_temp_utf16(), file)!; + $else + file = libc::freopen(filename.zstr_tcopy(), mode.zstr_tcopy(), file); + $endif + return file ?: file_open_errno()?; + }; $endif - return file ?: file_open_errno()?; - }; -$endif } fn void! native_fseek(void* file, isz offset, Seek seek_mode) @inline { -$if !env::COMPILER_LIBC_AVAILABLE: - if (native_fseek_fn) return native_fseek_fn(file, offset, seek_mode); - unreachable("Tried to call fseek without support."); -$else - $if env::os_is_win32(): - bool success = _fseeki64(file, (long)offset, (int)seek_mode) == 0; + $if !env::COMPILER_LIBC_AVAILABLE: + if (native_fseek_fn) return native_fseek_fn(file, offset, seek_mode); + unreachable("Tried to call fseek without support."); $else - bool success = libc::fseek(file, (SeekIndex)offset, (CInt)seek_mode) == 0; + $if env::os_is_win32(): + bool success = _fseeki64(file, (long)offset, (int)seek_mode) == 0; + $else + bool success = libc::fseek(file, (SeekIndex)offset, (CInt)seek_mode) == 0; + $endif + if (!success) return file_seek_errno()?; $endif - if (!success) return file_seek_errno()?; -$endif } fn usz! native_ftell(CFile file) @inline { -$if !env::COMPILER_LIBC_AVAILABLE: - if (native_ftell_fn) return native_ftell_fn(file); - unreachable("Tried to call ftell without support."); -$else - $if env::os_is_win32(): - long index = _ftelli64(file); - return index >= 0 ? index : file_seek_errno()?; + $if !env::COMPILER_LIBC_AVAILABLE: + if (native_ftell_fn) return native_ftell_fn(file); + unreachable("Tried to call ftell without support."); $else - SeekIndex index = libc::ftell(file); - return index >= 0 ? index : file_seek_errno()?; + $if env::os_is_win32(): + long index = _ftelli64(file); + return index >= 0 ? index : file_seek_errno()?; + $else + SeekIndex index = libc::ftell(file); + return index >= 0 ? index : file_seek_errno()?; + $endif $endif -$endif } fn usz! native_fwrite(CFile file, char[] buffer) @inline { -$if !env::COMPILER_LIBC_AVAILABLE: - if (native_fwrite_fn) return native_fwrite_fn(file, buffer); - unreachable("Tried to call fwrite without support."); -$else - return libc::fwrite(buffer.ptr, 1, buffer.len, file); -$endif + $if !env::COMPILER_LIBC_AVAILABLE: + if (native_fwrite_fn) return native_fwrite_fn(file, buffer); + unreachable("Tried to call fwrite without support."); + $else + return libc::fwrite(buffer.ptr, 1, buffer.len, file); + $endif } fn usz! native_fread(CFile file, char[] buffer) @inline { -$if !env::COMPILER_LIBC_AVAILABLE: - if (native_fread_fn) return native_fread_fn(file, buffer); - unreachable("Tried to call fread without support."); -$else - return libc::fread(buffer.ptr, 1, buffer.len, file); -$endif + $if !env::COMPILER_LIBC_AVAILABLE: + if (native_fread_fn) return native_fread_fn(file, buffer); + unreachable("Tried to call fread without support."); + $else + return libc::fread(buffer.ptr, 1, buffer.len, file); + $endif } macro anyfault file_open_errno() @local @@ -175,13 +160,10 @@ macro anyfault file_seek_errno() @local } // Win functions -$if env::os_is_win32(): -extern fn void* _wfopen(Char16*, Char16*) @local; -extern fn void* _wfreopen(Char16*, Char16*, CFile) @local; -extern fn int _fseeki64(CFile, long, int) @local; -extern fn long _ftelli64(CFile) @local; -$endif +extern fn void* _wfopen(Char16*, Char16*) @local @if(WIN32_LIBC); +extern fn void* _wfreopen(Char16*, Char16*, CFile) @local @if(WIN32_LIBC); +extern fn int _fseeki64(CFile, long, int) @local @if(WIN32_LIBC); +extern fn long _ftelli64(CFile) @local @if(WIN32_LIBC); -$if env::os_is_posix(): -extern fn CInt access(ZString path, CInt mode); -$endif +// Posix functions +extern fn CInt access(ZString path, CInt mode) @if(POSIX_LIBC); diff --git a/lib/std/io/os/fileinfo_darwin.c3 b/lib/std/io/os/fileinfo_darwin.c3 index 9b344ce2b..e92054e3b 100644 --- a/lib/std/io/os/fileinfo_darwin.c3 +++ b/lib/std/io/os/fileinfo_darwin.c3 @@ -1,8 +1,6 @@ -module std::io::file::os; +module std::io::file::os @if(DARWIN_LIBC); import libc; -$if env::os_is_darwin(): - struct DarwinTimespec @private { long tv_sec; @@ -97,5 +95,4 @@ fn void! read_stat(Darwin64Stat* stat, String path) @local } } }; -} -$endif \ No newline at end of file +} \ No newline at end of file diff --git a/lib/std/io/os/fileinfo_other.c3 b/lib/std/io/os/fileinfo_other.c3 index 7ff9392ff..a3aa917a0 100644 --- a/lib/std/io/os/fileinfo_other.c3 +++ b/lib/std/io/os/fileinfo_other.c3 @@ -1,7 +1,25 @@ module std::io::file::os; +const USE_DARWIN_INODE64 = env::os_is_darwin() && env::ARCH_TYPE == X86_64; + +extern fn NativeDirentry* readdir(void*) @extern("readdir") @if(!USE_DARWIN_INODE64) ; +extern fn NativeDirentry* readdir(void*) @extern("readdir$INODE64") @if(USE_DARWIN_INODE64); + +struct NativeDirentry +{ + usz ino; + usz seekoff @if(env::os_is_darwin()); + isz seekoff @if(!env::os_is_darwin()); + ushort reclen; + ushort namelen @if(env::os_is_darwin()); + char type; + char[1024] name @if(env::os_is_darwin()); + char[*] name @if(!env::os_is_darwin()); +} + +module std::io::file::os @if(!env::os_is_win32()); + // native_temp_directory, for non Win32 -$if !env::os_is_win32(): fn Path! native_temp_directory(Allocator* using = mem::heap()) { @@ -13,7 +31,7 @@ fn Path! native_temp_directory(Allocator* using = mem::heap()) return path::new("/tmp", using); } -$if env::COMPILER_LIBC_AVAILABLE: +module std::io::file::os @if(env::COMPILER_LIBC_AVAILABLE && !env::os_is_win32()); extern fn void* opendir(ZString); extern fn void closedir(void*); @@ -80,11 +98,7 @@ fn void! native_rmtree(Path dir) os::native_rmdir(dir)!; } -$endif - -$endif - -$if !env::os_is_darwin() && !env::os_is_win32(): +module std::io::file::os @if(!env::os_is_darwin() && !env::os_is_win32()); fn usz! native_file_size(String path) { @@ -93,89 +107,38 @@ fn usz! native_file_size(String path) return f.seek(0, Seek.END)!; } -$if env::os_is_posix() && env::COMPILER_LIBC_AVAILABLE: - fn bool native_file_or_dir_exists(String path) { - @pool() - { - return os::access(path.zstr_tcopy(), 0 /* F_OK */) != -1; - }; + $if POSIX_LIBC: + @pool() + { + return os::access(path.zstr_tcopy(), 0 /* F_OK */) != -1; + }; + $else + unreachable("Tried to call file_or_dir_exists without support."); + return false; + $endif } fn bool native_is_file(String path) { - File! f = file::open(path, "r"); - defer (void)f.close(); - return @ok(f); + $if POSIX_LIBC: + File! f = file::open(path, "r"); + defer (void)f.close(); + return @ok(f); + $else + unreachable("Tried to call is_file without support."); + return false; + $endif } fn bool native_is_dir(String path) { - return native_file_or_dir_exists(path) && !native_is_file(path); + $if POSIX_LIBC: + return native_file_or_dir_exists(path) && !native_is_file(path); + $else + unreachable("Tried to call is_dir without support."); + return false; + $endif } -$else - -fn bool native_file_or_dir_exists(String path) -{ - unreachable("Tried to call file_or_dir_exists without support."); -} - -fn bool native_is_dir(String path) -{ - unreachable("Tried to call is_dir without support."); -} - -fn bool native_is_file(String path) -{ - unreachable("Tried to call is_file without support."); -} - -$endif - -$endif - -$switch (env::OS_TYPE) -$case IOS: -$case MACOS: -$case TVOS: -$case WATCHOS: - -$if env::ARCH_TYPE == X86_64: -extern fn NativeDirentry* readdir(void*) @extern("readdir$INODE64"); -$else -extern fn NativeDirentry* readdir(void*) @extern("readdir"); -$endif - -struct NativeDirentry -{ - usz ino; - usz seekoff; - ushort reclen; - ushort namelen; - char type; - char[1024] name; -} -$case LINUX: -extern fn NativeDirentry* readdir(void*); -struct NativeDirentry -{ - usz ino; - isz seekoff; - ushort reclen; - char type; - char[*] name; -} -$default: -// Fix this as we go along. -extern fn NativeDirentry* readdir(void*); -struct NativeDirentry -{ - usz ino; - isz seekoff; - ushort reclen; - char type; - char[*] name; -} -$endswitch diff --git a/lib/std/io/os/fileinfo_win32.c3 b/lib/std/io/os/fileinfo_win32.c3 index 6e334982b..55d9541ff 100644 --- a/lib/std/io/os/fileinfo_win32.c3 +++ b/lib/std/io/os/fileinfo_win32.c3 @@ -1,8 +1,6 @@ -module std::io::file::os; +module std::io::file::os @if(env::os_is_win32()); import std::os::win32; -$if env::os_is_win32(): - const Win32_DWORD FILE_ATTRIBUTE_READONLY = 0x01; const Win32_DWORD FILE_ATTRIBUTE_HIDDEN = 0x02; const Win32_DWORD FILE_ATTRIBUTE_SYSTEM = 0x04; @@ -110,4 +108,3 @@ fn Path! native_temp_directory(Allocator* using = mem::heap()) } } */ -$endif \ No newline at end of file diff --git a/lib/std/io/os/getcwd.c3 b/lib/std/io/os/getcwd.c3 index 4f0240f2e..97268616e 100644 --- a/lib/std/io/os/getcwd.c3 +++ b/lib/std/io/os/getcwd.c3 @@ -1,51 +1,42 @@ module std::io::os; import libc; -$switch - -$case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32(): - macro String! getcwd(Allocator* using = mem::heap()) { - const DEFAULT_BUFFER = 256; - Char16[DEFAULT_BUFFER] buffer; - Char16 *res = win32::_wgetcwd(&buffer, DEFAULT_BUFFER); - bool free = false; - defer if (free) libc::free(res); - if (!res) - { - if (libc::errno() != errno::ERANGE) return IoError.GENERAL_ERROR?; - res = win32::_wgetcwd(null, 0); - free = true; - } - Char16[] str16 = res[:win32::wcslen(res)]; - return string::from_utf16(str16, using); + $switch + $case WIN32_LIBC: + const DEFAULT_BUFFER = 256; + Char16[DEFAULT_BUFFER] buffer; + Char16 *res = win32::_wgetcwd(&buffer, DEFAULT_BUFFER); + bool free = false; + defer if (free) libc::free(res); + if (!res) + { + if (libc::errno() != errno::ERANGE) return IoError.GENERAL_ERROR?; + res = win32::_wgetcwd(null, 0); + free = true; + } + Char16[] str16 = res[:win32::wcslen(res)]; + return string::from_utf16(str16, using); + + $case POSIX_LIBC: + const usz DEFAULT_BUFFER = 256; + char[DEFAULT_BUFFER] buffer; + ZString res = posix::getcwd(&buffer, DEFAULT_BUFFER); + bool free = false; + if (!res) + { + // Improve error + if (libc::errno() != errno::ERANGE) return IoError.GENERAL_ERROR?; + res = posix::getcwd(null, 0); + free = true; + } + defer if (free) libc::free((void*)res); + return res.copy(using); + + $default: + unreachable("'getcwd' not available"); + return ""; + $endswitch } -$case env::COMPILER_LIBC_AVAILABLE && env::os_is_posix(): - -macro String! getcwd(Allocator* using = mem::heap()) -{ - const usz DEFAULT_BUFFER = 256; - char[DEFAULT_BUFFER] buffer; - ZString res = posix::getcwd(&buffer, DEFAULT_BUFFER); - bool free = false; - if (!res) - { - // Improve error - if (libc::errno() != errno::ERANGE) return IoError.GENERAL_ERROR?; - res = posix::getcwd(null, 0); - free = true; - } - defer if (free) libc::free((void*)res); - return res.copy(using); -} - -$default: - -fn String! getcwd(Allocator* using = mem::heap()) -{ - unreachable("'getcwd' not available"); -} - -$endswitch \ No newline at end of file diff --git a/lib/std/io/os/mkdir.c3 b/lib/std/io/os/mkdir.c3 index 7b65813fb..673a79856 100644 --- a/lib/std/io/os/mkdir.c3 +++ b/lib/std/io/os/mkdir.c3 @@ -4,60 +4,48 @@ import std::io::path; import std::os::win32; import std::os::posix; -$switch - $case env::COMPILER_LIBC_AVAILABLE && env::os_is_posix(): macro bool! native_mkdir(Path path, MkdirPermissions permissions) { - if (!posix::mkdir(path.as_zstr(), permissions == NORMAL ? 0o777 : 0o700)) return true; - switch (libc::errno()) - { - case errno::EACCES: - case errno::EPERM: - case errno::EROFS: - case errno::EFAULT: return IoError.NO_PERMISSION?; - case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?; - case errno::EDQUOT: - case errno::ENOSPC: return IoError.OUT_OF_SPACE?; - case errno::EISDIR: - case errno::EEXIST: return false; - case errno::ELOOP: return IoError.SYMLINK_FAILED?; - case errno::ENOTDIR: return IoError.FILE_NOT_FOUND?; - default: return IoError.GENERAL_ERROR?; - } -} - - $case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32(): - -macro bool! native_mkdir(Path path, MkdirPermissions permissions) -{ - @pool() - { - // TODO security attributes - if (win32::win32_CreateDirectoryW(path.as_str().to_temp_utf16()!!, null)) return true; - switch (win32::win32_GetLastError()) - { - case win32::ERROR_ACCESS_DENIED: - return IoError.NO_PERMISSION?; - case win32::ERROR_DISK_FULL: - return IoError.OUT_OF_SPACE?; - case win32::ERROR_ALREADY_EXISTS: - return false; - case win32::ERROR_PATH_NOT_FOUND: - return IoError.FILE_NOT_FOUND?; - default: - return IoError.GENERAL_ERROR?; - } - }; -} - - $default: - -fn bool! native_mkdir(Path path, MkdirPermissions permissions) -{ - unreachable("'mkdir' not available"); - return false; -} - - -$endswitch \ No newline at end of file + $switch + $case POSIX_LIBC: + if (!posix::mkdir(path.as_zstr(), permissions == NORMAL ? 0o777 : 0o700)) return true; + switch (libc::errno()) + { + case errno::EACCES: + case errno::EPERM: + case errno::EROFS: + case errno::EFAULT: return IoError.NO_PERMISSION?; + case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?; + case errno::EDQUOT: + case errno::ENOSPC: return IoError.OUT_OF_SPACE?; + case errno::EISDIR: + case errno::EEXIST: return false; + case errno::ELOOP: return IoError.SYMLINK_FAILED?; + case errno::ENOTDIR: return IoError.FILE_NOT_FOUND?; + default: return IoError.GENERAL_ERROR?; + } + $case WIN32_LIBC: + @pool() + { + // TODO security attributes + if (win32::win32_CreateDirectoryW(path.as_str().to_temp_utf16()!!, null)) return true; + switch (win32::win32_GetLastError()) + { + case win32::ERROR_ACCESS_DENIED: + return IoError.NO_PERMISSION?; + case win32::ERROR_DISK_FULL: + return IoError.OUT_OF_SPACE?; + case win32::ERROR_ALREADY_EXISTS: + return false; + case win32::ERROR_PATH_NOT_FOUND: + return IoError.FILE_NOT_FOUND?; + default: + return IoError.GENERAL_ERROR?; + } + }; + $default: + unreachable("'mkdir' not available"); + return false; + $endswitch +} \ No newline at end of file diff --git a/lib/std/io/os/rmdir.c3 b/lib/std/io/os/rmdir.c3 index 0aa3f4d19..f9126a954 100644 --- a/lib/std/io/os/rmdir.c3 +++ b/lib/std/io/os/rmdir.c3 @@ -4,58 +4,46 @@ import std::io::path; import std::os::win32; import std::os::posix; -$switch - -$case env::COMPILER_LIBC_AVAILABLE && env::os_is_posix(): - macro bool! native_rmdir(Path path) { - if (!posix::rmdir(path.as_zstr())) return true; - switch (libc::errno()) - { - case errno::EBUSY: return IoError.BUSY?; - case errno::EACCES: - case errno::EPERM: - case errno::EROFS: - case errno::EFAULT: return IoError.NO_PERMISSION?; - case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?; - case errno::ENOTDIR: - case errno::ENOENT: return false; - case errno::ENOTEMPTY: return IoError.DIR_NOT_EMPTY?; - case errno::ELOOP: return IoError.SYMLINK_FAILED?; - default: return IoError.GENERAL_ERROR?; - } + $switch + $case POSIX_LIBC: + if (!posix::rmdir(path.as_zstr())) return true; + switch (libc::errno()) + { + case errno::EBUSY: return IoError.BUSY?; + case errno::EACCES: + case errno::EPERM: + case errno::EROFS: + case errno::EFAULT: return IoError.NO_PERMISSION?; + case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?; + case errno::ENOTDIR: + case errno::ENOENT: return false; + case errno::ENOTEMPTY: return IoError.DIR_NOT_EMPTY?; + case errno::ELOOP: return IoError.SYMLINK_FAILED?; + default: return IoError.GENERAL_ERROR?; + } + $case WIN32_LIBC: + @pool() + { + if (win32::win32_RemoveDirectoryW(path.as_str().to_temp_utf16()!!)) return true; + switch (win32::win32_GetLastError()) + { + case win32::ERROR_ACCESS_DENIED: + return IoError.NO_PERMISSION?; + case win32::ERROR_CURRENT_DIRECTORY: + return IoError.BUSY?; + case win32::ERROR_DIR_NOT_EMPTY: + return IoError.DIR_NOT_EMPTY?; + case win32::ERROR_DIRECTORY: + case win32::ERROR_PATH_NOT_FOUND: + return false; + default: + return IoError.GENERAL_ERROR?; + } + }; + $default: + unreachable("'rmdir' not available"); + return false; + $endswitch } - -$case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32(): - -macro bool! native_rmdir(Path path) -{ - @pool() - { - if (win32::win32_RemoveDirectoryW(path.as_str().to_temp_utf16()!!)) return true; - switch (win32::win32_GetLastError()) - { - case win32::ERROR_ACCESS_DENIED: - return IoError.NO_PERMISSION?; - case win32::ERROR_CURRENT_DIRECTORY: - return IoError.BUSY?; - case win32::ERROR_DIR_NOT_EMPTY: - return IoError.DIR_NOT_EMPTY?; - case win32::ERROR_DIRECTORY: - case win32::ERROR_PATH_NOT_FOUND: - return false; - default: - return IoError.GENERAL_ERROR?; - } - }; -} - -$default: - -fn bool! native_rmdir(Path path) -{ - unreachable("'rmdir' not available"); -} - -$endswitch \ No newline at end of file diff --git a/lib/std/io/path.c3 b/lib/std/io/path.c3 index 39ebe46e1..526d8a57b 100644 --- a/lib/std/io/path.c3 +++ b/lib/std/io/path.c3 @@ -96,11 +96,11 @@ fn bool! rmdir(Path path) fn void! rmtree(Path path) { if (!path.path_string.len) return PathResult.INVALID_PATH?; -$if $defined(os::native_rmtree): - return os::native_rmtree(path); -$else - assert(false, "rmtree is not available"); -$endif + $if $defined(os::native_rmtree): + return os::native_rmtree(path); + $else + assert(false, "rmtree is not available"); + $endif } fn Path! new(String path, Allocator* using = mem::heap(), PathEnv path_env = DEFAULT_PATH_ENV) diff --git a/lib/std/libc/libc.c3 b/lib/std/libc/libc.c3 index 64edd4549..2214851d6 100644 --- a/lib/std/libc/libc.c3 +++ b/lib/std/libc/libc.c3 @@ -35,7 +35,7 @@ def TerminateFunction = fn void(); def CompareFunction = fn int(void*, void*); def JmpBuf = uptr[$$JMP_BUF_SIZE]; -$if env::COMPILER_LIBC_AVAILABLE: +module libc @if(env::COMPILER_LIBC_AVAILABLE); extern fn double atof(char* str); extern fn int atoi(char* str); @@ -59,13 +59,12 @@ extern fn int rand(); extern fn void srand(uint seed); extern fn void longjmp(JmpBuf* buffer, CInt value); -$if env::os_is_win32(): + // TODO win32 aarch64 -extern fn CInt _setjmp(void* frameptr, JmpBuf* buffer); -macro CInt setjmp(JmpBuf* buffer) => _setjmp($$frameaddress(), buffer); -$else -extern fn CInt setjmp(JmpBuf* buffer); -$endif +extern fn CInt _setjmp(void* frameptr, JmpBuf* buffer) @if(env::WIN32); +macro CInt setjmp(JmpBuf* buffer) @if(env::WIN32) => _setjmp($$frameaddress(), buffer); + +extern fn CInt setjmp(JmpBuf* buffer) @if(!env::WIN32); // MB functions omitted // string @@ -97,7 +96,110 @@ extern fn void* calloc(usz count, usz size); extern fn void* free(void*); extern fn void* realloc(void* ptr, usz size); -$else +extern fn int fclose(CFile stream); +extern fn void clearerr(CFile stream); +extern fn int feof(CFile stream); +extern fn int ferror(CFile stream); +extern fn int fflush(CFile stream); +extern fn int fgetpos(CFile stream, Fpos* pos); +extern fn CFile fopen(ZString filename, ZString mode); +extern fn usz fread(void* ptr, usz size, usz nmemb, CFile stream); +extern fn CFile freopen(ZString filename, ZString mode, CFile stream); +extern fn CFile fmemopen(void* ptr, usz size, ZString mode); +extern fn int fseek(CFile stream, SeekIndex offset, int whence); +extern fn int fsetpos(CFile stream, Fpos* pos); +extern fn SeekIndex ftell(CFile stream); +extern fn usz fwrite(void* ptr, usz size, usz nmemb, CFile stream); +extern fn int remove(char* filename); +extern fn int rename(char* old_name, char* new_name); +extern fn void rewind(CFile stream); +extern fn void setbuf(CFile stream, char* buffer); +extern fn void setvbuf(CFile stream, char* buffer, int mode, usz size); +extern fn CFile tmpnam(char* str); +extern fn int fprintf(CFile stream, char* format, ...); +extern fn int printf(char* format, ...); +extern fn int sprintf(char* str, char* format, ...); +extern fn int snprintf(char* str, usz size, char* format, ...); +extern fn int fscanf(CFile stream, char* format, ...); +extern fn int scanf(char* format, ...); +extern fn int sscanf(char* str, char* format, ...); +extern fn int fgetc(CFile stream); +extern fn char* fgets(char* str, int n, CFile stream); +extern fn int fputc(int c, CFile stream); +extern fn int getc(CFile stream); +extern fn int getchar(); +extern fn int putc(int c, CFile stream); +extern fn int putchar(int c); +extern fn int puts(char* str); +extern fn int ungetc(int c, CFile stream); +extern fn void perror(char* str); +extern fn isz getline(char** linep, usz* linecapp, CFile stream); + +extern fn int timespec_get(TimeSpec* ts, int base); +extern fn int nanosleep(TimeSpec* req, TimeSpec* remaining); + +extern fn ZString asctime(Tm *timeptr); +extern fn Clock_t clock(); +extern fn ZString ctime(Time_t *timer); +extern fn double difftime(Time_t time1, Time_t time2); +extern fn Tm* gmtime(Time_t *timer); +extern fn Tm* localtime(Time_t *timer); +extern fn usz strftime(char* str, usz maxsize, char* format, Tm *timeptr); +extern fn Time_t time(Time_t *timer); + +// signal +def SignalFunction = fn void(int); +extern fn SignalFunction signal(int sig, SignalFunction function); +// Incomplete + +module libc @if(LINUX_LIBC); +extern CFile __stdin @extern("stdin"); +extern CFile __stdout @extern("stdout"); +extern CFile __stderr @extern("stderr"); +extern fn usz malloc_usable_size(void* ptr); +macro usz malloc_size(void* ptr) => malloc_usable_size(ptr); +extern fn void* aligned_alloc(usz align, usz size); +macro CFile stdin() => __stdin; +macro CFile stdout() => __stdout; +macro CFile stderr() => __stderr; + +module libc @if(DARWIN_LIBC); +extern CFile __stdinp; +extern CFile __stdoutp; +extern CFile __stderrp; +extern fn usz malloc_size(void* ptr); +extern fn void* aligned_alloc(usz align, usz size); +macro CFile stdin() => __stdinp; +macro CFile stdout() => __stdoutp; +macro CFile stderr() => __stderrp; + +module libc @if(WIN32_LIBC); +extern fn CFile __acrt_iob_func(CInt c); +extern fn usz _msize(void* ptr); +macro usz malloc_size(void* ptr) => _msize(ptr); +macro CFile stdin() => __acrt_iob_func(0); +macro CFile stdout() => __acrt_iob_func(1); +macro CFile stderr() => __acrt_iob_func(2); +extern fn Tm* _gmtime64_s(Tm* buf, Time_t *timer); +extern fn Tm* _localtime64_s(Tm* buf, Time_t *timer); +extern fn void _get_timezone(CLong *timezone); +macro Tm* gmtime_r(Time_t *timer, Tm* buf) => _gmtime64_s(buf, timer); +macro Tm* localtime_r(Time_t *timer, Tm* buf) => _localtime64_s(buf, timer); +extern fn Time_t mktime(Tm *timeptr) @extern("_mktime64"); +extern fn Time_t timegm(Tm *timeptr) @extern("_mkgmtime64"); + +module libc @if(env::COMPILER_LIBC_AVAILABLE && !env::WIN32 && !env::LINUX && !env::DARWIN); +macro CFile stdin() { return (CFile*)(uptr)0; } +macro CFile stdout() { return (CFile*)(uptr)1; } +macro CFile stderr() { return (CFile*)(uptr)2; } + +module libc @if(env::COMPILER_LIBC_AVAILABLE && !env::WIN32); +extern fn Tm* gmtime_r(Time_t *timer, Tm* buf); +extern fn Tm* localtime_r(Time_t *timer, Tm* buf); +extern fn Time_t mktime(Tm *timeptr); +extern fn Time_t timegm(Tm *timeptr); + +module libc @if(!env::COMPILER_LIBC_AVAILABLE); fn void longjmp(JmpBuf* buffer, CInt value) @weak @extern("longjmp") @nostrip { @@ -144,110 +246,6 @@ fn void* memset(void* dest, CInt value, usz n) @weak @extern("memset") @nostrip return dest; } -$endif - -// stdio - -def Fpos = long; -def CFile = void*; - -$switch -$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == LINUX: - extern CFile __stdin @extern("stdin"); - extern CFile __stdout @extern("stdout"); - extern CFile __stderr @extern("stderr"); - extern fn usz malloc_usable_size(void* ptr); - macro usz malloc_size(void* ptr) { return malloc_usable_size(ptr); } - extern fn void* aligned_alloc(usz align, usz size); - macro CFile stdin() { return __stdin; } - macro CFile stdout() { return __stdout; } - macro CFile stderr() { return __stderr; } -$case env::COMPILER_LIBC_AVAILABLE && env::os_is_darwin(): - extern CFile __stdinp; - extern CFile __stdoutp; - extern CFile __stderrp; - extern fn usz malloc_size(void* ptr); - extern fn void* aligned_alloc(usz align, usz size); - macro CFile stdin() { return __stdinp; } - macro CFile stdout() { return __stdoutp; } - macro CFile stderr() { return __stderrp; } -$case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32(): - extern fn CFile __acrt_iob_func(CInt c); - extern fn usz _msize(void* ptr); - macro usz malloc_size(void* ptr) { return _msize(ptr); } - macro CFile stdin() { return __acrt_iob_func(0); } - macro CFile stdout() { return __acrt_iob_func(1); } - macro CFile stderr() { return __acrt_iob_func(2); } -$default: - macro CFile stdin() { return (CFile*)(uptr)0; } - macro CFile stdout() { return (CFile*)(uptr)1; } - macro CFile stderr() { return (CFile*)(uptr)2; } -$endswitch - -const HAS_MALLOC_SIZE = - env::OS_TYPE == LINUX - || env::os_is_win32() - || env::os_is_darwin(); - -// The following needs to be set per arch+os -// For now I have simply pulled the defaults from MacOS -const int SEEK_SET = 0; -const int SEEK_CUR = 1; -const int SEEK_END = 2; -const int _IOFBF = 0; // Fully buffered -const int _IOLBF = 1; // Line buffered -const int _IONBF = 2; // Unbuffered -const int BUFSIZ = 1024; -const int EOF = -1; -const int FOPEN_MAX = 20; -const int FILENAME_MAX = 1024; - -def Errno = distinct CInt; -def SeekIndex = CLong; - -$if env::COMPILER_LIBC_AVAILABLE: - -extern fn int fclose(CFile stream); -extern fn void clearerr(CFile stream); -extern fn int feof(CFile stream); -extern fn int ferror(CFile stream); -extern fn int fflush(CFile stream); -extern fn int fgetpos(CFile stream, Fpos* pos); -extern fn CFile fopen(ZString filename, ZString mode); -extern fn usz fread(void* ptr, usz size, usz nmemb, CFile stream); -extern fn CFile freopen(ZString filename, ZString mode, CFile stream); -extern fn CFile fmemopen(void* ptr, usz size, ZString mode); -extern fn int fseek(CFile stream, SeekIndex offset, int whence); -extern fn int fsetpos(CFile stream, Fpos* pos); -extern fn SeekIndex ftell(CFile stream); -extern fn usz fwrite(void* ptr, usz size, usz nmemb, CFile stream); -extern fn int remove(char* filename); -extern fn int rename(char* old_name, char* new_name); -extern fn void rewind(CFile stream); -extern fn void setbuf(CFile stream, char* buffer); -extern fn void setvbuf(CFile stream, char* buffer, int mode, usz size); -extern fn CFile tmpnam(char* str); -extern fn int fprintf(CFile stream, char* format, ...); -extern fn int printf(char* format, ...); -extern fn int sprintf(char* str, char* format, ...); -extern fn int snprintf(char* str, usz size, char* format, ...); -extern fn int fscanf(CFile stream, char* format, ...); -extern fn int scanf(char* format, ...); -extern fn int sscanf(char* str, char* format, ...); -extern fn int fgetc(CFile stream); -extern fn char* fgets(char* str, int n, CFile stream); -extern fn int fputc(int c, CFile stream); -extern fn int getc(CFile stream); -extern fn int getchar(); -extern fn int putc(int c, CFile stream); -extern fn int putchar(int c); -extern fn int puts(char* str); -extern fn int ungetc(int c, CFile stream); -extern fn void perror(char* str); -extern fn isz getline(char** linep, usz* linecapp, CFile stream); - -$else - fn int fseek(CFile stream, SeekIndex offset, int whence) @weak @extern("fseek") @nostrip { unreachable("'fseek' not available."); @@ -315,12 +313,40 @@ fn int puts(ZString str) @weak @extern("puts") @nostrip unreachable("'puts' not available."); } -$endif +module libc; + +// stdio + +def Fpos = long; +def CFile = void*; + + +const HAS_MALLOC_SIZE = + env::OS_TYPE == LINUX + || env::os_is_win32() + || env::os_is_darwin(); + +// The following needs to be set per arch+os +// For now I have simply pulled the defaults from MacOS +const int SEEK_SET = 0; +const int SEEK_CUR = 1; +const int SEEK_END = 2; +const int _IOFBF = 0; // Fully buffered +const int _IOLBF = 1; // Line buffered +const int _IONBF = 2; // Unbuffered +const int BUFSIZ = 1024; +const int EOF = -1; +const int FOPEN_MAX = 20; +const int FILENAME_MAX = 1024; + +def Errno = distinct CInt; +def SeekIndex = CLong; + // vsprintf vprintf not supported // time.h -struct TmCommon @private +struct Tm { int tm_sec; /* seconds after the minute [0-60] */ int tm_min; /* minutes after the hour [0-59] */ @@ -331,112 +357,33 @@ struct TmCommon @private int tm_wday; /* days since Sunday [0-6] */ int tm_yday; /* days since January 1 [0-365] */ int tm_isdst; /* Daylight Savings Time flag */ + TimeOffset tm_gmtoff @if(!env::WIN32); /* offset from UTC in seconds */ + char *tm_zone @if(!env::WIN32); /* timezone abbreviation */ + int tm_nsec @if(env::WASI); + } - -$switch (env::OS_TYPE) - -$case WIN32: - -def Tm = TmCommon; - -$case WASI: - -def TimeOffset = int; -struct Tm -{ - inline TmCommon common; - TimeOffset tm_gmtoff; /* offset from UTC in seconds */ - char *tm_zone; /* timezone abbreviation */ - int tm_nsec; -} - -$case MACOS: -$case IOS: -$case TVOS: -$case WATCHOS: -$case OPENBSD: -$case FREEBSD: -$default: - -def TimeOffset = CLong; -struct Tm -{ - inline TmCommon common; - TimeOffset tm_gmtoff; /* offset from UTC in seconds */ - char *tm_zone; /* timezone abbreviation */ -} - -$endswitch - - -$if env::os_is_win32(): - struct TimeSpec { Time_t s; - ulong ns; + ulong ns @if(env::WIN32); + CLong ns @if(!env::WIN32); } -def Time_t = long; -def Clock_t = ulong; +def Time_t = long @if(env::WIN32); +def Time_t = CLong @if(!env::WIN32); +def Clock_t = ulong @if(env::WIN32); +def Clock_t = CULong @if(!env::WIN32); -$else - -struct TimeSpec -{ - Time_t s; - CLong ns; -} - -def Time_t = CLong; -def Clock_t = CULong; - -$endif +def TimeOffset = int @if(env::WASI) ; +def TimeOffset = CLong @if(!env::WASI) ; const int TIME_UTC = 1; -extern fn int timespec_get(TimeSpec* ts, int base); -extern fn int nanosleep(TimeSpec* req, TimeSpec* remaining); // Likely wrong, must be per platform. const CLOCKS_PER_SEC = 1000000; - -extern fn ZString asctime(Tm *timeptr); -extern fn Clock_t clock(); -extern fn ZString ctime(Time_t *timer); -extern fn double difftime(Time_t time1, Time_t time2); -extern fn Tm* gmtime(Time_t *timer); - -extern fn Tm* localtime(Time_t *timer); - -$if env::os_is_win32(): -extern fn Tm* _gmtime64_s(Tm* buf, Time_t *timer); -extern fn Tm* _localtime64_s(Tm* buf, Time_t *timer); -extern fn void _get_timezone(CLong *timezone); - -macro Tm* gmtime_r(Time_t *timer, Tm* buf) => _gmtime64_s(buf, timer); -macro Tm* localtime_r(Time_t *timer, Tm* buf) => _localtime64_s(buf, timer); - -extern fn Time_t mktime(Tm *timeptr) @extern("_mktime64"); -extern fn Time_t timegm(Tm *timeptr) @extern("_mkgmtime64"); -$else -extern fn Tm* gmtime_r(Time_t *timer, Tm* buf); -extern fn Tm* localtime_r(Time_t *timer, Tm* buf); -extern fn Time_t mktime(Tm *timeptr); -extern fn Time_t timegm(Tm *timeptr); -$endif - -extern fn usz strftime(char* str, usz maxsize, char* format, Tm *timeptr); -extern fn Time_t time(Time_t *timer); - -// signal -def SignalFunction = fn void(int); -extern fn SignalFunction signal(int sig, SignalFunction function); -// Incomplete - - module libc::errno; const Errno OK = 0; @@ -451,11 +398,9 @@ const Errno ENOEXEC = 8; // Exec format error const Errno EBADF = 9; // Bad file number const Errno ECHILD = 10; // No child processes -$if env::os_is_darwin(): -const Errno EAGAIN = 35; // Try again Macos -$else -const Errno EAGAIN = 11; // Try again -$endif + +const Errno EAGAIN @if(env::DARWIN) = 35; // Try again Macos +const Errno EAGAIN @if(!env::DARWIN) = 11; // Try again const Errno ENOMEM = 12; // Out of memory const Errno EACCES = 13; // Permission denied @@ -481,9 +426,7 @@ const Errno EPIPE = 32; // Broken pipe const Errno EDOM = 33; // Math argument out of domain of func const Errno ERANGE = 34; // Math result not representable -$switch (env::OS_TYPE) - -$case MACOS: +module libc::errno @if(env::DARWIN); const Errno EDEADLK = 11; // Resource deadlock would occur MacOS const Errno ENAMETOOLONG = 63; // File name too long MacOS const Errno ELOOP = 62; // Too many symbolic links encountered @@ -494,8 +437,13 @@ const Errno ENETUNREACH = 51; // Network is unreachable MacOS const Errno ENETRESET = 52; // Network dropped connection because of reset MacOS const Errno EOPNOTSUPP = 45; // Operation not supported on transport endpoint const Errno ENOTEMPTY = 66; // Directory not empty +const Errno ETIMEDOUT = 60; // Connection timed out +const Errno EINPROGRESS = 36; // Operation now in progress MacOS +const Errno EALREADY = 37; // Operation already in progress MacOS +const Errno EDQUOT = 69; // Quota exceeded, MacOS +const Errno EWOULDBLOCK = 35; // Operation would block -$case WIN32: +module libc::errno @if(env::WIN32); const Errno EDEADLK = 36; // Resource deadlock would occur Win32 const Errno ENAMETOOLONG = 38; // File name too long Win32 const Errno ELOOP = 114; // Too many symbolic links encountered @@ -506,8 +454,13 @@ const Errno ENETUNREACH = 118; // Network is unreachable const Errno ENETRESET = 117; // Network dropped connection because of reset const Errno EOPNOTSUPP = 130; // Operation not supported on transport endpoint const Errno ENOTEMPTY = 41; // Directory not empty +const Errno ETIMEDOUT = 138; // Connection timed out +const Errno EALREADY = 103; // Operation already in progress +const Errno EINPROGRESS = 112; // Operation now in progress Win32 +const Errno EDQUOT = -122; // Quota exceeded, not in Win32 +const Errno EWOULDBLOCK = 140; // Operation would block -$default: +module libc::errno @if(!env::WIN32 && !env::DARWIN); const Errno EDEADLK = 35; // Resource deadlock would occur Linux (others?) const Errno ENAMETOOLONG = 36; // File name too long Linux (others?) const Errno ELOOP = 40; // Too many symbolic links encountered @@ -518,9 +471,11 @@ const Errno ENETUNREACH = 101; // Network is unreachable const Errno ENETRESET = 102; // Network dropped connection because of reset const Errno EOPNOTSUPP = 95; // Operation not supported on transport endpoint const Errno ENOTEMPTY = 39; // Directory not empty - -$endswitch - +const Errno ETIMEDOUT = 110; // Connection timed out +const Errno EALREADY = 114; // Operation already in progress +const Errno EINPROGRESS = 115; // Operation now in progress +const Errno EDQUOT = 122; // Quota exceeded +const Errno EWOULDBLOCK = 41; // Operation would block /* @@ -594,29 +549,6 @@ const Errno EHOSTDOWN = 112; /* Host is down */ const Errno EHOSTUNREACH = 113; /* No route to host */ */ -$switch (env::OS_TYPE) - -$case MACOS: -const Errno ETIMEDOUT = 60; // Connection timed out -const Errno EINPROGRESS = 36; // Operation now in progress MacOS -const Errno EALREADY = 37; // Operation already in progress MacOS -const Errno EDQUOT = 69; // Quota exceeded, MacOS -const Errno EWOULDBLOCK = 35; // Operation would block - -$case WIN32: -const Errno ETIMEDOUT = 138; // Connection timed out -const Errno EALREADY = 103; // Operation already in progress -const Errno EINPROGRESS = 112; // Operation now in progress Win32 -const Errno EDQUOT = -122; // Quota exceeded, not in Win32 -const Errno EWOULDBLOCK = 140; // Operation would block - -$default: -const Errno ETIMEDOUT = 110; // Connection timed out -const Errno EALREADY = 114; // Operation already in progress -const Errno EINPROGRESS = 115; // Operation now in progress -const Errno EDQUOT = 122; // Quota exceeded -const Errno EWOULDBLOCK = 41; // Operation would block -$endswitch /* const Errno ESTALE = 116; /* Stale NFS file handle */ diff --git a/lib/std/libc/os/errno.c3 b/lib/std/libc/os/errno.c3 index 0325b56d0..47fef8719 100644 --- a/lib/std/libc/os/errno.c3 +++ b/lib/std/libc/os/errno.c3 @@ -1,38 +1,28 @@ module libc::os; +// Linux +extern fn int* __errno_location() @if(LINUX_LIBC); +macro int errno() @if(LINUX_LIBC) => *__errno_location(); +macro void errno_set(int err) @if(LINUX_LIBC) => *(__errno_location()) = err; -$switch +// Darwin +extern fn int* __error() @if(DARWIN_LIBC); +macro int errno() @if(DARWIN_LIBC) => *__error(); +macro void errno_set(int err) @if(DARWIN_LIBC) => *(__error()) = err; -$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == LINUX: - -extern fn int* __errno_location(); -macro int errno() => *__errno_location(); -macro void errno_set(int err) => *(__errno_location()) = err; - -$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == MACOS: - -extern fn int* __error(); -macro int errno() => *__error(); -macro void errno_set(int err) => *(__error()) = err; - -$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == WIN32: - -macro int errno() +// Win32 +macro int errno() @if(WIN32_LIBC) { int holder; _get_errno(&holder); return holder; } +macro void errno_set(int err) @if(WIN32_LIBC) => _set_errno(err); +extern fn void _get_errno(int* result) @if(WIN32_LIBC); +extern fn void _set_errno(int err) @if(WIN32_LIBC); -macro void errno_set(int err) => _set_errno(err); - -extern fn void _get_errno(int* result); -extern fn void _set_errno(int err); - -$default: - -tlocal int _errno_c3 = 0; -fn void errno_set(int err) => _errno_c3 = err; -fn int errno() => _errno_c3; - -$endswitch +// Default +const ERRNO_DEFAULT @local = !LINUX_LIBC && !DARWIN_LIBC && !WIN32_LIBC; +tlocal int _errno_c3 @if(ERRNO_DEFAULT) = 0; +fn void errno_set(int err) @if(ERRNO_DEFAULT) => _errno_c3 = err; +fn int errno() @if(ERRNO_DEFAULT) => _errno_c3; \ No newline at end of file diff --git a/lib/std/math/math.c3 b/lib/std/math/math.c3 index 3e406a908..890e3cd38 100644 --- a/lib/std/math/math.c3 +++ b/lib/std/math/math.c3 @@ -471,14 +471,14 @@ macro sqrt(x) => $$sqrt(values::promote_int(x)); macro tan(x) { var $Type = $typeof(x); -$switch - $case types::is_vector($Type): - return $$sin(x) / $$cos(x); - $case $Type.typeid == float.typeid: - return _tanf(x); - $default: - return _tan(x); -$endswitch + $switch + $case types::is_vector($Type): + return $$sin(x) / $$cos(x); + $case $Type.typeid == float.typeid: + return _tanf(x); + $default: + return _tan(x); + $endswitch } /** @@ -487,11 +487,11 @@ $endswitch macro bool is_finite(x) { $switch ($typeof(x)) - $case float: - $case float16: - return bitcast((float)x, uint) & 0x7fffffff < 0x7f800000; - $default: - return bitcast((double)x, ulong) & (~0u64 >> 1) < 0x7ffu64 << 52; + $case float: + $case float16: + return bitcast((float)x, uint) & 0x7fffffff < 0x7f800000; + $default: + return bitcast((double)x, ulong) & (~0u64 >> 1) < 0x7ffu64 << 52; $endswitch } diff --git a/lib/std/math/math_nolibc/__cos.c3 b/lib/std/math/math_nolibc/__cos.c3 index 564a89dc8..d2d588efc 100644 --- a/lib/std/math/math_nolibc/__cos.c3 +++ b/lib/std/math/math_nolibc/__cos.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); /* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */ /* @@ -31,4 +29,3 @@ fn double __cos(double x, double y) @extern("__cos") @weak @nostrip return w + (((1.0 - w) - hz) + (z * r - x * y)); } -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/__cosdf.c3 b/lib/std/math/math_nolibc/__cosdf.c3 index 9b039d59b..6b5977b2f 100644 --- a/lib/std/math/math_nolibc/__cosdf.c3 +++ b/lib/std/math/math_nolibc/__cosdf.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); /* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */ /* @@ -32,5 +30,3 @@ fn float __cosdf(double x) @extern("__cosdf") @weak @nostrip double r = C2 + z * C3; return (float)(((1.0f + z * C0) + w * C1) + (w * z) * r); } - -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/__sin.c3 b/lib/std/math/math_nolibc/__sin.c3 index e6b841c03..2090fc77c 100644 --- a/lib/std/math/math_nolibc/__sin.c3 +++ b/lib/std/math/math_nolibc/__sin.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); /* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */ /* @@ -31,5 +29,3 @@ fn double __sin(double x, double y, int iy) @extern("__sin") @weak @nostrip ? x + v * (S1 + z * r) : x - ((z * (0.5 * y - v * r) - y) - v * S1); } - -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/__sindf.c3 b/lib/std/math/math_nolibc/__sindf.c3 index 19242723b..3ed9b936f 100644 --- a/lib/std/math/math_nolibc/__sindf.c3 +++ b/lib/std/math/math_nolibc/__sindf.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); /* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */ /* @@ -31,4 +29,3 @@ fn float __sindf(double x) @extern("__sindf") @weak @nostrip return (float)((x + s * (S1F + z * S2F)) + s * w * r); } -$endif diff --git a/lib/std/math/math_nolibc/__tan.c3 b/lib/std/math/math_nolibc/__tan.c3 index 28f8cd93a..a44cbc193 100644 --- a/lib/std/math/math_nolibc/__tan.c3 +++ b/lib/std/math/math_nolibc/__tan.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); /* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ /* @@ -79,5 +77,3 @@ fn double __tan(double x, double y, int odd) @extern("__tan") @weak @nostrip double a0 = bitcast(d, double); return a0 + a * (1.0 + a0 * w0 + a0 * v); } - -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/__tandf.c3 b/lib/std/math/math_nolibc/__tandf.c3 index 34bad3a86..8a03e6523 100644 --- a/lib/std/math/math_nolibc/__tandf.c3 +++ b/lib/std/math/math_nolibc/__tandf.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); /* origin: FreeBSD /usr/src/lib/msun/src/k_tanf.c */ /* @@ -52,5 +50,3 @@ fn float __tandf(double x, int odd) @extern("__tandf") @weak @nostrip r = (x + s * u) + (s * w) * (t + w * r); return (float)(odd ? -1.0 / r : r); } - -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/atan.c3 b/lib/std/math/math_nolibc/atan.c3 index 113749e5c..f5c1002d6 100644 --- a/lib/std/math/math_nolibc/atan.c3 +++ b/lib/std/math/math_nolibc/atan.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc::atan; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); const double[*] ATANHI @private = { 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ @@ -320,5 +318,3 @@ fn float _atan2f(float y, float x) @weak @extern("atan2f") @nostrip default: return (z - PI_LO_F) - PI_F; /* atan(-,-) */ } } - -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/ceil.c3 b/lib/std/math/math_nolibc/ceil.c3 index f71d6c33e..4c0c3e046 100644 --- a/lib/std/math/math_nolibc/ceil.c3 +++ b/lib/std/math/math_nolibc/ceil.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); fn double _ceil(double x) @weak @extern("ceil") @nostrip { @@ -42,4 +40,3 @@ fn float _ceilf(float x) @weak @extern("ceilf") @nostrip return bitcast(u, float); } -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/cos.c3 b/lib/std/math/math_nolibc/cos.c3 index fc1ef7231..76e59393c 100644 --- a/lib/std/math/math_nolibc/cos.c3 +++ b/lib/std/math/math_nolibc/cos.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); fn float _cosf(float x) @extern("cosf") @weak @nostrip { @@ -54,7 +52,7 @@ fn float _cosf(float x) @extern("cosf") @weak @nostrip * ==================================================== */ -fn double _cos(double x) @extern("cos") @weak @nostrip +fn double _cos(double x) @weak @nostrip { // High word of x. uint ix = (uint)(bitcast(x, ulong) >> 32); @@ -87,5 +85,3 @@ fn double _cos(double x) @extern("cos") @weak @nostrip } } } - -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/exp2.c3 b/lib/std/math/math_nolibc/exp2.c3 index 0598bfd7b..2215a663d 100644 --- a/lib/std/math/math_nolibc/exp2.c3 +++ b/lib/std/math/math_nolibc/exp2.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); macro uint _top12f(float x) @private => bitcast(x, uint) >> 20; @@ -141,4 +139,3 @@ fn double _exp2(double x) @extern("exp2") @weak @nostrip is no spurious underflow here even without fma. */ return scale + scale * tmp; } -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/floor.c3 b/lib/std/math/math_nolibc/floor.c3 index f95391cfb..475e17e49 100644 --- a/lib/std/math/math_nolibc/floor.c3 +++ b/lib/std/math/math_nolibc/floor.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); fn double _floor(double x) @weak @extern("floor") @nostrip { @@ -42,4 +40,3 @@ fn float _floorf(float x) @weak @extern("floorf") @nostrip return bitcast(u, float); } -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/pow.c3 b/lib/std/math/math_nolibc/pow.c3 index 8eaf309ad..269fdabed 100644 --- a/lib/std/math/math_nolibc/pow.c3 +++ b/lib/std/math/math_nolibc/pow.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); fn float powf_broken(float x, float f) @extern("powf") @weak @nostrip { @@ -11,5 +9,3 @@ fn double pow_broken(double x, double y) @extern("pow") @weak @nostrip { unreachable("'pow' not supported"); } - -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/rempi.c3 b/lib/std/math/math_nolibc/rempi.c3 index 4914500c1..7ecf8ab98 100644 --- a/lib/std/math/math_nolibc/rempi.c3 +++ b/lib/std/math/math_nolibc/rempi.c3 @@ -1,8 +1,6 @@ -module std::math::nolibc; +module std::math::nolibc @if(env::NO_LIBC); import std::math; -$if !env::COMPILER_LIBC_AVAILABLE: - /* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ /* * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. @@ -537,4 +535,3 @@ fn int __rem_pio2(double x, double *y) } -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/round.c3 b/lib/std/math/math_nolibc/round.c3 index 53856b870..ce6fdfcac 100644 --- a/lib/std/math/math_nolibc/round.c3 +++ b/lib/std/math/math_nolibc/round.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); fn double _round(double x) @extern("round") @weak @nostrip { @@ -53,4 +51,3 @@ fn float _roundf(float x) @extern("roundf") @weak @nostrip return y; } -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/scalbn.c3 b/lib/std/math/math_nolibc/scalbn.c3 index 69c416ac2..f8f63706a 100644 --- a/lib/std/math/math_nolibc/scalbn.c3 +++ b/lib/std/math/math_nolibc/scalbn.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); fn double _scalbn(double x, int n) @weak @extern("scalbn") @nostrip { @@ -27,5 +25,3 @@ fn double _scalbn(double x, int n) @weak @extern("scalbn") @nostrip } return x * bitcast(((ulong)(0x3ff + n)) << 52, double); } - -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/sin.c3 b/lib/std/math/math_nolibc/sin.c3 index e5cdad2f9..6e7dc8f69 100644 --- a/lib/std/math/math_nolibc/sin.c3 +++ b/lib/std/math/math_nolibc/sin.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); /* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ /* @@ -119,4 +117,3 @@ fn double sin(double x) @extern("sin") @weak @nostrip } } } -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/sincos.c3 b/lib/std/math/math_nolibc/sincos.c3 index b5a851bd5..92b64eeaf 100644 --- a/lib/std/math/math_nolibc/sincos.c3 +++ b/lib/std/math/math_nolibc/sincos.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); /* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ /* @@ -156,4 +154,3 @@ fn void sincos(double x, double *sin, double *cos) @extern("sincos") @weak @nost } } } -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/tan.c3 b/lib/std/math/math_nolibc/tan.c3 index ab1530263..3817462d6 100644 --- a/lib/std/math/math_nolibc/tan.c3 +++ b/lib/std/math/math_nolibc/tan.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); /* origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */ /* @@ -100,4 +98,3 @@ fn float tanf(float x) @extern("tanf") @weak @nostrip } } -$endif \ No newline at end of file diff --git a/lib/std/math/math_nolibc/trig.c3 b/lib/std/math/math_nolibc/trig.c3 index 09b5eed4c..334f3c3da 100644 --- a/lib/std/math/math_nolibc/trig.c3 +++ b/lib/std/math/math_nolibc/trig.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc::trig; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); fn double sincos_broken(double x) @extern("sincos") @weak @nostrip { @@ -8,4 +6,3 @@ fn double sincos_broken(double x) @extern("sincos") @weak @nostrip } -$endif diff --git a/lib/std/math/math_nolibc/trunc.c3 b/lib/std/math/math_nolibc/trunc.c3 index 6ab8dee04..c3065bb8f 100644 --- a/lib/std/math/math_nolibc/trunc.c3 +++ b/lib/std/math/math_nolibc/trunc.c3 @@ -1,6 +1,4 @@ -module std::math::nolibc; - -$if !env::COMPILER_LIBC_AVAILABLE: +module std::math::nolibc @if(env::NO_LIBC); fn double _trunc(double x) @weak @extern("trunc") @nostrip { @@ -28,4 +26,3 @@ fn float _truncf(float x) @weak @extern("truncf") @nostrip return bitcast(i, float); } -$endif \ No newline at end of file diff --git a/lib/std/net/os/common.c3 b/lib/std/net/os/common.c3 index 5c10ede95..6dbb0c884 100644 --- a/lib/std/net/os/common.c3 +++ b/lib/std/net/os/common.c3 @@ -1,21 +1,32 @@ module std::net::os; -$if $defined(PLATFORM_AF_INET): +struct AddrInfo +{ + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + usz ai_addrlen; + void* ai_addr; + char* ai_canonname; + AddrInfo* ai_next; +} -$if !$defined(PLATFORM_O_NONBLOCK): - const PLATFORM_O_NONBLOCK = 0; -$endif +const bool SUPPORTS_INET = env::WIN32 || env::DARWIN || env::LINUX; + +const PLATFORM_O_NONBLOCK @if(!$defined(PLATFORM_O_NONBLOCK)) = 0; const AI_PASSIVE = 0x1; const AI_CANONNAME = 0x2; const AI_NUMERICHOST = 0x4; const int AF_UNSPEC = 0; -const int AF_INET = PLATFORM_AF_INET; -const int AF_APPLETALK = PLATFORM_AF_APPLETALK; -const int AF_IPX = PLATFORM_AF_IPX; -const int AF_INET6 = PLATFORM_AF_INET6; +const int AF_INET @if(SUPPORTS_INET) = PLATFORM_AF_INET; +const int AF_APPLETALK @if(SUPPORTS_INET) = PLATFORM_AF_APPLETALK; +const int AF_IPX @if(SUPPORTS_INET) = PLATFORM_AF_IPX; +const int AF_INET6 @if(SUPPORTS_INET) = PLATFORM_AF_INET6; const O_NONBLOCK = PLATFORM_O_NONBLOCK; -$endif \ No newline at end of file + + diff --git a/lib/std/net/os/darwin.c3 b/lib/std/net/os/darwin.c3 index d609ce26f..a066cb4bc 100644 --- a/lib/std/net/os/darwin.c3 +++ b/lib/std/net/os/darwin.c3 @@ -1,8 +1,6 @@ -module std::net::os; +module std::net::os @if(env::DARWIN); import libc; -$if env::os_is_darwin(): - const AI_NUMERICSERV = 0x1000; const AI_ALL = 0x100; const AI_V4MAPPED_CFG = 0x200; @@ -11,18 +9,6 @@ const AI_V4MAPPED = 0x800; const AI_UNUSABLE = 0x10000000; const AI_DEFAULT = AI_V4MAPPED_CFG | AI_ADDRCONFIG; -struct AddrInfo -{ - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - usz ai_addrlen; - void* ai_addr; - char* ai_canonname; - AddrInfo* ai_next; -} - const int PLATFORM_AF_UNIX = 1; const int PLATFORM_AF_INET = 2; const int PLATFORM_AF_IMPLINK = 3; @@ -61,7 +47,4 @@ const int PLATFORM_AF_IEEE80211 = 37; const int PLATFORM_AF_UTUN = 38; const int PLATFORM_AF_VSOCK = 40; const int PLATFORM_AF_MAX = 41; - -const int PLATFORM_O_NONBLOCK = 0x30; - -$endif \ No newline at end of file +const int PLATFORM_O_NONBLOCK = 0x30; \ No newline at end of file diff --git a/lib/std/net/os/linux.c3 b/lib/std/net/os/linux.c3 index 803370314..edc61704b 100644 --- a/lib/std/net/os/linux.c3 +++ b/lib/std/net/os/linux.c3 @@ -1,20 +1,6 @@ -module std::net::os; +module std::net::os @if(env::LINUX); import libc; -$if env::OS_TYPE == LINUX: - -struct AddrInfo -{ - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - usz ai_addrlen; - void* ai_addr; - char* ai_canonname; - AddrInfo* ai_next; -} - const int PLATFORM_AF_UNIX = 1; const int PLATFORM_AF_INET = 2; const int PLATFORM_AF_AX25 = 3; @@ -26,6 +12,4 @@ const int PLATFORM_AF_AAL5 = 8; const int PLATFORM_AF_X25 = 9; const int PLATFORM_AF_INET6 = 10; -const PLATFORM_O_NONBLOCK = 0o4000; - -$endif \ No newline at end of file +const PLATFORM_O_NONBLOCK = 0o4000; \ No newline at end of file diff --git a/lib/std/net/os/posix.c3 b/lib/std/net/os/posix.c3 index 9468d447c..567954c12 100644 --- a/lib/std/net/os/posix.c3 +++ b/lib/std/net/os/posix.c3 @@ -1,8 +1,6 @@ -module std::net::os; +module std::net::os @if(env::POSIX && SUPPORTS_INET); import libc; -$if !env::os_is_win32() && $defined(AddrInfo): - const int F_GETFL = 3; const int F_SETFL = 4; @@ -37,6 +35,4 @@ macro void! NativeSocket.set_non_blocking(NativeSocket this) macro bool NativeSocket.is_non_blocking(NativeSocket this) { return fcntl(this, F_GETFL, 0) & O_NONBLOCK == O_NONBLOCK; -} - -$endif +} \ No newline at end of file diff --git a/lib/std/net/os/win32.c3 b/lib/std/net/os/win32.c3 index b8bd90e60..4a637f94d 100644 --- a/lib/std/net/os/win32.c3 +++ b/lib/std/net/os/win32.c3 @@ -1,6 +1,4 @@ -module std::net::os; - -$if env::os_is_win32(): +module std::net::os @if(env::WIN32); const int PLATFORM_AF_INET = 1; const int PLATFORM_AF_IPX = 6; @@ -10,18 +8,6 @@ const int PLATFORM_AF_INET6 = 23; const int PLATFORM_AF_IRDA = 26; const int PLATFORM_AF_BTH = 32; -struct AddrInfo -{ - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - usz ai_addrlen; - char* ai_canonname; - void* ai_addr; - AddrInfo* ai_next; -} - def NativeSocket = distinct uptr; extern fn int wsa_startup(int, void*) @extern("WSAStartup"); @@ -29,5 +15,3 @@ extern fn int ioctlsocket(NativeSocket, long cmd, ulong *argp); extern fn int closesocket(NativeSocket); macro NativeSocket.close(NativeSocket this) => closesocket(this); - -$endif \ No newline at end of file diff --git a/lib/std/os/macos/cf_allocator.c3 b/lib/std/os/macos/cf_allocator.c3 index 905e19838..2cb45a63b 100644 --- a/lib/std/os/macos/cf_allocator.c3 +++ b/lib/std/os/macos/cf_allocator.c3 @@ -1,6 +1,4 @@ -module std::os::macos::cf; - -$if env::os_is_darwin(): +module std::os::macos::cf @if(DARWIN_LIBC); def CFAllocatorRef = distinct void*; def CFAllocatorContextRef = distinct void*; @@ -18,4 +16,3 @@ extern fn CFAllocatorRef _macos_CFAllocatorGetDefault() @extern("CFAllocatorGetD extern fn void _macos_CFAllocatorSetDefault(CFAllocatorRef allocator) @extern("CFAllocatorSetDefault"); extern fn void* _macos_CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) @extern("CFAllocatorAllocate"); extern fn CFIndex _macos_CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) @extern("CFAllocatorGetPreferredSizeForSize"); -$endif \ No newline at end of file diff --git a/lib/std/os/macos/cf_array.c3 b/lib/std/os/macos/cf_array.c3 index 61f0e51ac..a4fc9fbe2 100644 --- a/lib/std/os/macos/cf_array.c3 +++ b/lib/std/os/macos/cf_array.c3 @@ -1,6 +1,4 @@ -module std::os::macos::cf; - -$if env::os_is_darwin(): +module std::os::macos::cf @if(DARWIN_LIBC); def CFArrayRef = distinct void*; def CFArrayCallBacksRef = distinct void*; @@ -11,4 +9,3 @@ extern fn CFIndex _macos_CFArrayGetCount(CFArrayRef array) @extern("CFArrayGetCo extern fn void _macos_CFArrayAppendArray(CFMutableArrayRef theArray, CFArrayRef otherArray, CFRange otherRange) @extern("CFArrayAppendArray"); extern fn CFMutableArrayRef _macos_CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, CFArrayCallBacksRef callBacks) @extern("CFArrayCreateMutable"); extern fn void _macos_CFArrayAppendValue(CFMutableArrayRef theArray, void *value) @extern("CFArrayAppendValue"); -$endif \ No newline at end of file diff --git a/lib/std/os/macos/core_foundation.c3 b/lib/std/os/macos/core_foundation.c3 index 839eacbe9..1700a8021 100644 --- a/lib/std/os/macos/core_foundation.c3 +++ b/lib/std/os/macos/core_foundation.c3 @@ -1,6 +1,4 @@ -module std::os::macos::cf; - -$if env::os_is_darwin(): +module std::os::macos::cf @if(DARWIN_LIBC); def CFTypeRef = distinct void*; def CFIndex = isz; @@ -12,5 +10,3 @@ struct CFRange extern fn CFTypeRef _macos_CFRetain(CFTypeRef cf) @extern("CFRetain"); extern fn void _macos_CFRelease(CFTypeRef cf) @extern("CFRelease"); - -$endif \ No newline at end of file diff --git a/lib/std/os/macos/objc.c3 b/lib/std/os/macos/objc.c3 index b524cb990..9813f53a9 100644 --- a/lib/std/os/macos/objc.c3 +++ b/lib/std/os/macos/objc.c3 @@ -1,6 +1,4 @@ -module std::os::macos::objc; - -$if env::os_is_darwin(): +module std::os::macos::objc @if(DARWIN_LIBC); def Class = distinct void*; def Method = distinct void*; @@ -45,5 +43,5 @@ extern fn Method _macos_class_getClassMethod(Class cls, Selector name) @extern(" extern fn bool _macos_class_respondsToSelector(Class cls, Selector name) @extern("class_respondsToSelector"); extern fn Selector _macos_sel_registerName(char* str) @extern("sel_registerName"); extern fn Class _macos_objc_lookUpClass(char* name) @extern("objc_lookUpClass"); -$endif + diff --git a/lib/std/os/posix/files.c3 b/lib/std/os/posix/files.c3 index 862b8d69f..6fc5a86a5 100644 --- a/lib/std/os/posix/files.c3 +++ b/lib/std/os/posix/files.c3 @@ -1,10 +1,6 @@ -module std::os::posix; - -$if env::os_is_posix() && env::COMPILER_LIBC_AVAILABLE: +module std::os::posix @if(POSIX_LIBC); extern fn int rmdir(ZString); extern fn int mkdir(ZString, ushort mode_t); extern fn int chdir(ZString); extern fn ZString getcwd(char* pwd, usz len); - -$endif \ No newline at end of file diff --git a/lib/std/os/win32/files.c3 b/lib/std/os/win32/files.c3 index eb38d3473..5e3698d58 100644 --- a/lib/std/os/win32/files.c3 +++ b/lib/std/os/win32/files.c3 @@ -1,6 +1,4 @@ -module std::os::win32; - -$if env::os_is_win32(): +module std::os::win32 @if(WIN32_LIBC); enum Win32_GET_FILEEX_INFO_LEVELS { @@ -63,4 +61,3 @@ extern bool _win32_CreateSymbolicLinkW(Char16* symlink_file, Char16* target_file extern bool _win32_CopyFileW(Char16* from_file, Char16* to_file, bool no_overwrite) @extern("CopyFileW"); extern ulong _win32_GetFullPathNameW(Char16* file_name, ulong buffer_len, Char16* buffer, Char16** file_part) @extern("GetFullPathNameW"); */ -$endif \ No newline at end of file diff --git a/lib/std/os/win32/general.c3 b/lib/std/os/win32/general.c3 index 59d80d91e..c71fbf9ad 100644 --- a/lib/std/os/win32/general.c3 +++ b/lib/std/os/win32/general.c3 @@ -1,6 +1,4 @@ -module std::os::win32; - -$if env::os_is_win32(): +module std::os::win32 @if(WIN32_LIBC); extern fn Win32_DWORD win32_GetLastError() @extern("GetLastError"); @@ -224,4 +222,3 @@ const Win32_DWORD ERROR_MR_MID_NOT_FOUND = 0x13D; const Win32_DWORD ERROR_SCOPE_NOT_FOUND = 0x13E; const Win32_DWORD ERROR_UNDEFINED_SCOPE = 0x13F; -$endif \ No newline at end of file diff --git a/lib/std/os/win32/process.c3 b/lib/std/os/win32/process.c3 index e4708f8a1..28e9c5e42 100644 --- a/lib/std/os/win32/process.c3 +++ b/lib/std/os/win32/process.c3 @@ -1,6 +1,4 @@ -module std::os::win32; - -$if env::os_is_win32(): +module std::os::win32 @if(WIN32_LIBC); extern fn bool win32_CreateProcessW( Win32_LPCWSTR lpApplicationName, @@ -14,5 +12,3 @@ extern fn bool win32_CreateProcessW( Win32_LPSTARTUPINFOW lpStartupInfo, Win32_LPPROCESS_INFORMATION lpProcessInformation ) @extern("CreateProcessW"); - -$endif \ No newline at end of file diff --git a/lib/std/os/win32/wsa.c3 b/lib/std/os/win32/wsa.c3 index e893cb63c..5498ffe12 100644 --- a/lib/std/os/win32/wsa.c3 +++ b/lib/std/os/win32/wsa.c3 @@ -1,16 +1,12 @@ -module std::os::win32; +module std::os::win32 @if(WIN32_LIBC); def WSAError = distinct int; -$if env::os_is_win32(): - extern fn WSAError win32_WSAGetLastError() @extern("WSAGetLastError"); extern fn void win32_WSASetLastError(WSAError error) @extern("WSASetLastError"); -$endif -module std::os::win32::wsa; +module std::os::win32::wsa @if(env::WIN32); -$if env::os_is_win32(): const WSAError INVALID_HANDLE = 6; const WSAError NOT_ENOUGHT_MEMORY = 8; const WSAError INVALID_PARAMETER = 87; @@ -32,5 +28,4 @@ const WSAError EMSGSIZE = 10040; const WSAError EPROTOTYPE = 10041; const WSAError ENOPROTOOPT = 10042; const WSAError EPROTONOSUPPORT = 10043; -const WSAError ESOCKTNOSUPPORT = 10044; -$endif \ No newline at end of file +const WSAError ESOCKTNOSUPPORT = 10044; \ No newline at end of file diff --git a/lib/std/threads/os/thread_posix.c3 b/lib/std/threads/os/thread_posix.c3 index e9ac6581d..b195534c2 100644 --- a/lib/std/threads/os/thread_posix.c3 +++ b/lib/std/threads/os/thread_posix.c3 @@ -1,8 +1,6 @@ -module std::thread::os; +module std::thread::os @if(thread::THREAD_MODEL == ThreadModel.POSIX); import libc; -$if thread::THREAD_MODEL == ThreadModel.POSIX: - const PTHREAD_MUTEX_NORMAL = 0; const PTHREAD_MUTEX_ERRORCHECK = 1; const PTHREAD_MUTEX_RECURSIVE = 2; @@ -13,23 +11,6 @@ def NativeThread = Pthread; def NativeOnceFlag = PthreadOnce; def Pthread = distinct void*; - -$if env::OS_TYPE == LINUX: -def PthreadMutex = distinct ulong[5]; -def PthreadAttribute = distinct ulong[7]; -def PthreadMutexAttribute = distinct uint; -def PthreadCondAttribute = distinct uint; -def PthreadCond = distinct ulong[6]; -def PthreadOnce = distinct uint; -$else -def PthreadMutex = distinct ulong[8]; -def PthreadMutexAttribute = distinct ulong[2]; -def PthreadAttribute = distinct ulong[8]; -def PthreadCond = distinct ulong[6]; -def PthreadCondAttribute = distinct ulong[8]; -def PthreadOnce = distinct ulong[2]; -$endif - def PosixThreadFn = fn void*(void*); extern fn int pthread_attr_destroy(PthreadAttribute*); @@ -236,4 +217,18 @@ fn void! native_sleep(double s) if (libc::nanosleep(&to, null)) return ThreadFault.INTERRUPTED?; } -$endif \ No newline at end of file +module std::thread::os @if(thread::THREAD_MODEL == ThreadModel.POSIX && !env::LINUX); +def PthreadMutex = distinct ulong[8]; +def PthreadMutexAttribute = distinct ulong[2]; +def PthreadAttribute = distinct ulong[8]; +def PthreadCond = distinct ulong[6]; +def PthreadCondAttribute = distinct ulong[8]; +def PthreadOnce = distinct ulong[2]; + +module std::thread::os @if(thread::THREAD_MODEL == ThreadModel.POSIX && env::LINUX); +def PthreadMutex = distinct ulong[5]; +def PthreadAttribute = distinct ulong[7]; +def PthreadMutexAttribute = distinct uint; +def PthreadCondAttribute = distinct uint; +def PthreadCond = distinct ulong[6]; +def PthreadOnce = distinct uint; diff --git a/lib/std/threads/os/thread_win32.c3 b/lib/std/threads/os/thread_win32.c3 index da6cc446a..84548a932 100644 --- a/lib/std/threads/os/thread_win32.c3 +++ b/lib/std/threads/os/thread_win32.c3 @@ -1,6 +1,4 @@ -module std::thread::os; - -$if thread::THREAD_MODEL == ThreadModel.WIN32: +module std::thread::os @if(thread::THREAD_MODEL == ThreadModel.WIN32); def NativeThread = Win32_HANDLE; @@ -345,5 +343,3 @@ fn void! native_sleep_nano(ulong ns) { return native_sleep_ms(ns < 1000_000 ? 1 : ns / 1000_000); } - -$endif \ No newline at end of file diff --git a/lib/std/time/clock.c3 b/lib/std/time/clock.c3 index 331d1e270..643ffdbe1 100644 --- a/lib/std/time/clock.c3 +++ b/lib/std/time/clock.c3 @@ -2,11 +2,11 @@ module std::time::clock; fn Clock now() { -$if $defined(native_clock): - return os::native_clock(); -$else - return 0; -$endif + $if $defined(native_clock): + return os::native_clock(); + $else + return 0; + $endif } fn NanoDuration Clock.mark(Clock* this) diff --git a/lib/std/time/datetime.c3 b/lib/std/time/datetime.c3 index 318536b1a..2fa546aed 100644 --- a/lib/std/time/datetime.c3 +++ b/lib/std/time/datetime.c3 @@ -36,14 +36,14 @@ fn TzDateTime DateTime.to_local(DateTime* this) dt.weekday = !tm.tm_wday ? Weekday.SUNDAY : (Weekday)tm.tm_wday + 1; dt.year_day = (ushort)tm.tm_yday; dt.time = this.time; -$if $defined(tm.tm_gmtoff): - dt.gmt_offset = (int)tm.tm_gmtoff; -$else - $assert $defined(libc::_get_timezone); - CLong timezone; - libc::_get_timezone(&timezone); - dt.gmt_offset = (int)-timezone; -$endif + $if $defined(tm.tm_gmtoff): + dt.gmt_offset = (int)tm.tm_gmtoff; + $else + $assert $defined(libc::_get_timezone); + CLong timezone; + libc::_get_timezone(&timezone); + dt.gmt_offset = (int)-timezone; + $endif return dt; } diff --git a/lib/std/time/os/time_darwin.c3 b/lib/std/time/os/time_darwin.c3 index d5e03b866..8aafe6360 100644 --- a/lib/std/time/os/time_darwin.c3 +++ b/lib/std/time/os/time_darwin.c3 @@ -1,6 +1,4 @@ -module std::time::os; - -$if env::os_is_darwin(): +module std::time::os @if(DARWIN_LIBC); struct Darwin_mach_timebase_info { @@ -23,6 +21,3 @@ fn Clock native_clock() } return (Clock)(mach_absolute_time() * timebase.numer / timebase.denom); } - - -$endif diff --git a/lib/std/time/os/time_posix.c3 b/lib/std/time/os/time_posix.c3 index 80192c8a6..4a1f09f7a 100644 --- a/lib/std/time/os/time_posix.c3 +++ b/lib/std/time/os/time_posix.c3 @@ -1,17 +1,31 @@ -module std::time::os; +module std::time::os @if(POSIX_LIBC); import libc; -$if env::os_is_posix() && env::COMPILER_LIBC_AVAILABLE: +extern fn void clock_gettime(int type, TimeSpec *time); -$switch (env::OS_TYPE) -$case OPENBSD: +fn Time native_timestamp() +{ + TimeSpec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return (Time)(ts.s * 1_000_000i64 + ts.ns / 1_000i64); +} + +fn Clock native_clock() @if(!DARWIN_LIBC) +{ + TimeSpec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (Clock)((ulong)ts.s * 1_000_000_000u64 + (ulong)ts.ns); +} + +module std::time::os @if(OPENBSD_LIBC); const CLOCK_REALTIME = 0; const CLOCK_PROCESS_CPUTIME_ID = 2; const CLOCK_MONOTONIC = 3; const CLOCK_THREAD_CPUTIME_ID = 4; const CLOCK_UPTIME = 5; const CLOCK_BOOTTIME = 6; -$case FREEBSD: + +module std::time::os @if(FREEBSD_LIBC); const CLOCK_REALTIME = 0; const CLOCK_VIRTUAL = 1; const CLOCK_PROF = 2; @@ -29,21 +43,21 @@ const CLOCK_PROCESS_CPUTIME_ID = 15; const CLOCK_BOOTTIME = CLOCK_UPTIME; const CLOCK_REALTIME_COARSE = CLOCK_REALTIME_FAST; const CLOCK_MONOTONIC_COARSE = CLOCK_MONOTONIC_FAST; -$case NETBSD: + +module std::time::os @if(NETBSD_LIBC); const CLOCK_REALTIME = 0; const CLOCK_VIRTUAL = 1; const CLOCK_PROF = 2; const CLOCK_MONOTONIC = 3; const CLOCK_THREAD_CPUTIME_ID = 0x20000000; const CLOCK_PROCESS_CPUTIME_ID = 0x40000000; -$case WASI: + +module std::time::os @if(WASI_LIBC); // Not implemented const CLOCK_REALTIME = 0; const CLOCK_MONOTONIC = 0; -$case MACOS: -$case TVOS: -$case IOS: -$case WATCHOS: + +module std::time::os @if(DARWIN_LIBC); const CLOCK_REALTIME = 0; const CLOCK_MONOTONIC = 6; const CLOCK_MONOTONIC_RAW = 4; @@ -52,8 +66,8 @@ const CLOCK_UPTIME_RAW = 8; const CLOCK_UPTIME_RAW_APPROX = 9; const CLOCK_PROCESS_CPUTIME_ID = 12; const CLOCK_THREAD_CPUTIME_ID = 16; -$case LINUX: -$default: + +module std::time::os @if(LINUX_LIBC); const CLOCK_REALTIME = 0; const CLOCK_MONOTONIC = 1; const CLOCK_PROCESS_CPUTIME_ID = 2; @@ -65,24 +79,4 @@ const CLOCK_BOOTTIME = 7; const CLOCK_REALTIME_ALARM = 8; const CLOCK_BOOTTIME_ALARM = 9; const CLOCK_TAI = 11; -$endswitch -extern fn void clock_gettime(int type, TimeSpec *time); - -fn Time native_timestamp() -{ - TimeSpec ts; - clock_gettime(CLOCK_REALTIME, &ts); - return (Time)(ts.s * 1_000_000i64 + ts.ns / 1_000i64); -} - -$if !env::os_is_darwin(): -fn Clock native_clock() -{ - TimeSpec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (Clock)((ulong)ts.s * 1_000_000_000u64 + (ulong)ts.ns); -} -$endif - -$endif diff --git a/lib/std/time/os/time_win32.c3 b/lib/std/time/os/time_win32.c3 index 5505f9b60..fbe0f8c3f 100644 --- a/lib/std/time/os/time_win32.c3 +++ b/lib/std/time/os/time_win32.c3 @@ -1,8 +1,6 @@ -module std::time::os; +module std::time::os @if(WIN32_LIBC); import std::os::win32; -$if env::os_is_win32() && env::COMPILER_LIBC_AVAILABLE: - extern fn void win32_GetSystemTimeAsFileTime(Win32_FILETIME* time) @extern("GetSystemTimeAsFileTime"); extern fn Win32_BOOL win32_QueryPerformanceFrequency(Win32_LARGE_INTEGER* lpFrequency) @extern("QueryPerformanceFrequency"); extern fn Win32_BOOL win32_QueryPerformanceCounter(Win32_LARGE_INTEGER* lpPerformanceCount) @extern("QueryPerformanceCounter"); @@ -28,6 +26,4 @@ fn Time native_timestamp() win32_GetSystemTimeAsFileTime(&ft); ulong result = (ulong)ft.dwHighDateTime << 32 | ft.dwLowDateTime; return (Time)(result / WINDOWS_TICK_US - WIN_TO_UNIX_EPOCH_US); -} - -$endif \ No newline at end of file +} \ No newline at end of file diff --git a/lib/std/time/time.c3 b/lib/std/time/time.c3 index 76c671113..e308e5f27 100644 --- a/lib/std/time/time.c3 +++ b/lib/std/time/time.c3 @@ -1,9 +1,9 @@ module std::time; -def Time @inline = distinct long; -def TimeDuration @inline = distinct long; -def Clock @inline = distinct ulong; -def NanoDuration @inline = distinct long; +def Time = distinct long @inline; +def TimeDuration = distinct long @inline; +def Clock = distinct ulong @inline; +def NanoDuration = distinct long @inline; const TimeDuration MICROSECONDS_PER_SECOND = 1_000_000; const TimeDuration MICROSECONDS_PER_MINUTE = MICROSECONDS_PER_SECOND * 60; @@ -61,11 +61,11 @@ enum Month : char fn Time now() { -$if $defined(native_timestamp): - return os::native_timestamp(); -$else - return 0; -$endif + $if $defined(native_timestamp): + return os::native_timestamp(); + $else + return 0; + $endif } fn Time Time.add_seconds(Time time, long seconds) => time + (Time)(seconds * (long)MICROSECONDS_PER_SECOND); diff --git a/resources/testfragments/parsertest.c3 b/resources/testfragments/parsertest.c3 deleted file mode 100644 index 094e26158..000000000 --- a/resources/testfragments/parsertest.c3 +++ /dev/null @@ -1,242 +0,0 @@ -module foo <$foo, #bar, Integer>; -import bar as eok local; -import bar2 as eok2; -import bar3 local; - -macro void @foo(int i, $e) -{ - $e = 1; - printf("Helo"); -} -macro @goo(i, $e) -{ - -} - -struct Foo -{ - $if $use_bar > 0: - { - int bar; - } - int baz; -} - - -macro @soom!(i, $e) -{} - -local struct Foom -{ - int i; - Foom *test; - int*** j; - int*[][]* k; -} - -struct Hej -{ - int x; -} - -enum FEok : int { - IFEJ -} - - -enum Test -{ - FOO = 1 + 2, - BAR, -} - -enum Test2 : int -{ - FOO = 1, - BAR, -} - -union Foomt -{ - int i; - double d; -} - -error Errors -{ - BADERROR, - OTHER_ERROR -} - -fn Foom test(int a) -{ - while (int x = 0, int y = 3; int y = foo()) - { - a++; - } - while (int x = 0) - { - a++; - } - while (int x, y = 3; x > 0 && b < 0) - { - a++; - } - return 1 + 2; -} - -fn boo::Bar zab::Baz.sd(die::Eij i) throws Zab // , sij:Zig -{ - float a = 0, b = 3, double c = 1, d; - int i = 0; -} - -generic int boor(i) -{ - case int: - return 1; - case double: - return 100; - default: - return 1000; -} - -generic boor2(i) -{ - case int: - return "Helo"; - default: - return 10001; -} - -$switch - -$case $e > 0: -{ - fn void foo() {} -} -$case $e < 0: -{ - fn void foo() { printf("HELO"); } -} -$default: -{ - fn void foo() { printf("OLEH"); } -} -$endswitch - -$if $e > 0: -{ - fn void foo() {} -} - -$if $b > 0: -{ -} -$else -{ - generic test(i) { } -} - -#if $b > 0 - -#else - -#endif - -generic boofer2(i, g, eok) -{ - case int, String, type($eoo) - return "Helo"; - default - return 1000; -} - - - -fn void hello() throws Errors -{ - int i, j; - throw FOO; - throw awesome::FOO; - defer close(b); - foo::Bar x = 3; - try foo(); - try foo() else 1; - foo(try 1); - type($error) fk; - type(int).size + fk; - Errors {}; - Ferrors{a = 1, b = 20, b = { token }}; - Ferrors{1, 3, 1+4}; - $erro = 1; - FOO: - goto FOO; - type($error) fk; - foo::@macrof(); - int i = foo ? 2 : 4; - @macros(); - type(foo::y) z; - type(int) * 2; - $error = type(int); - double[4] a; - foo[1 + 2] * b; - type((i > 0) ? type(int) : type(double)) doek; - $e = type(type(type(Bar))); - $e = foo ? type(int) : type(Bar); - $e = type(type(foo::$eofk)); - if (a == 0 && 1 == b) - { - i = 0; - } - while (bpb >= 3) - { - a(); - } - do - { - } while (0); - for (i = 0;;) - {} - for (i = 0, j = 3; i < 0; i++, j++) {} - for (int i = 0; i < 100; i++) - { - i++; - } - int i = 1; - i + 1 * 100; - &i; - int j = i; - 2; - i++; - switch (int foo = 1; bar) - { - case 1: - next; - continue; - default: - break; - } - do { - i++; - } while (a < 0); - while (a > 0) - { - a--; - } - while (int a = 4; int b = 20) - { - a + 1; - } - return; -} - -def Foo* as Bar; -def fn void(int, Foo*) as Zoo; - - - -fn void test2() -{ - return; -} \ No newline at end of file diff --git a/resources/testproject/hello_world.c3 b/resources/testproject/hello_world.c3 index bb698702f..376c0ebe3 100644 --- a/resources/testproject/hello_world.c3 +++ b/resources/testproject/hello_world.c3 @@ -1,14 +1,9 @@ module hello_world; import std; import bar; -$if env::os_is_win32(): -fn int test_doubler(int x) -{ - return x * x; -} -$else -extern fn int test_doubler(int); -$endif + +fn int test_doubler(int x) @if(env::WIN32) => x * x; +extern fn int test_doubler(int) @if(!env::WIN32); extern fn void printf(char *, ...); fn int main() diff --git a/src/compiler/ast.c b/src/compiler/ast.c index b837f7e23..6b4cf865e 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -97,6 +97,7 @@ Decl *decl_new_with_type(const char *name, SourceSpan loc, DeclKind decl_type) case DECL_CT_ECHO: case DECL_CT_INCLUDE: case DECL_GLOBALS: + case DECL_ERASED: UNREACHABLE } Type *type = type_new(kind, name ? name : "$anon"); @@ -117,6 +118,8 @@ const char *decl_to_a_name(Decl *decl) { switch (decl->decl_kind) { + case DECL_ERASED: + return "an erased declaration"; case DECL_BODYPARAM: return "a body parameter"; case DECL_DECLARRAY: @@ -215,6 +218,8 @@ const char *decl_to_a_name(Decl *decl) // Set the external name of a declaration void decl_set_external_name(Decl *decl) { + if (decl->decl_kind == DECL_ERASED) return; + // Already has the extname set using an attribute? // if so we're done. if (decl->has_extname) return; diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 46fb0ac50..53583687d 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -679,6 +679,7 @@ typedef struct Decl_ bool is_live : 1; bool no_strip : 1; bool is_deprecated : 1; + bool is_cond : 1; OperatorOverload operator : 4; union { @@ -1581,6 +1582,7 @@ struct CompilationUnit_ Decl **attributes; Decl **faulttypes; Visibility default_visibility; + Attr *if_attr; bool export_by_default; bool is_interface_file; bool test_by_default; @@ -1594,6 +1596,7 @@ struct CompilationUnit_ Decl **methods; Decl **macro_methods; Decl **global_decls; + Decl **global_cond_decls; Decl *main_function; HTable local_symbols; int lambda_count; diff --git a/src/compiler/context.c b/src/compiler/context.c index 468c90eff..7ce06d083 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -120,6 +120,8 @@ void decl_register(Decl *decl) if (decl->visibility > VISIBLE_PUBLIC) return; switch (decl->decl_kind) { + case DECL_ERASED: + return; case DECL_INITIALIZE: case DECL_FINALIZE: case DECL_POISONED: @@ -163,6 +165,8 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl) switch (decl->decl_kind) { + case DECL_ERASED: + return; case DECL_POISONED: break; case DECL_MACRO: diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 8e561c455..178f1b9cd 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -859,6 +859,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl) { case DECL_POISONED: break; + case DECL_ERASED: case DECL_CT_INCLUDE: break; case DECL_INITIALIZE: diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 6803837cf..f6c512d4b 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -126,6 +126,7 @@ typedef enum typedef enum { DECL_POISONED = 0, + DECL_ERASED, DECL_ATTRIBUTE, DECL_BITSTRUCT, DECL_CT_CASE, @@ -766,6 +767,7 @@ typedef enum ATTRIBUTE_EXPORT, ATTRIBUTE_EXTERN, ATTRIBUTE_EXTNAME, + ATTRIBUTE_IF, ATTRIBUTE_INLINE, ATTRIBUTE_INTERFACE, ATTRIBUTE_LITTLEENDIAN, @@ -814,7 +816,9 @@ typedef enum ANALYSIS_MODULE_HIERARCHY, ANALYSIS_MODULE_TOP, ANALYSIS_IMPORTS, - ANALYSIS_REGISTER_GLOBALS, + ANALYSIS_REGISTER_GLOBAL_DECLARATIONS, + ANALYSIS_REGISTER_CONDITIONAL_UNITS, + ANALYSIS_REGISTER_CONDITIONAL_DECLARATIONS, ANALYSIS_CONDITIONAL_COMPILATION, ANALYSIS_DECLS, ANALYSIS_CT_ECHO, diff --git a/src/compiler/headers.c b/src/compiler/headers.c index 29863103f..ccb997cbe 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -308,6 +308,8 @@ static void header_gen_type_decl(FILE *file, int indent, Decl *decl) case DECL_BODYPARAM: case DECL_FUNC: UNREACHABLE + case DECL_ERASED: + return; case DECL_BITSTRUCT: header_print_type(file, decl->bitstruct.base_type->type); return; diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index e807f859f..1957975c8 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -786,6 +786,7 @@ static void llvm_emit_type_decls(GenContext *context, Decl *decl) case DECL_VAR: case DECL_ENUM_CONSTANT: case DECL_FAULTVALUE: + case DECL_ERASED: UNREACHABLE; case DECL_TYPEDEF: if (decl->typedef_decl.is_func) @@ -1028,6 +1029,8 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl) } switch (decl->decl_kind) { + case DECL_ERASED: + UNREACHABLE case DECL_VAR: if (decl->var.kind == VARDECL_UNWRAPPED) { diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 9692de821..d05058202 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -14,6 +14,7 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl) { switch (decl->decl_kind) { + case DECL_ERASED: case DECL_VAR: case DECL_ENUM_CONSTANT: case DECL_FAULTVALUE: diff --git a/src/compiler/number.c b/src/compiler/number.c index d4b82993e..df5a8ae53 100644 --- a/src/compiler/number.c +++ b/src/compiler/number.c @@ -130,7 +130,7 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp UNREACHABLE } assert((op == BINARYOP_EQ) || (op == BINARYOP_NE)); - return (op == BINARYOP_EQ) && is_eq; + return op == BINARYOP_EQ ? is_eq : !is_eq; } bool expr_const_in_range(const ExprConst *left, const ExprConst *right, const ExprConst *right_to) diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 16086f13d..afc243dc9 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -417,7 +417,7 @@ static Expr *parse_lambda(ParseContext *c, Expr *left) sig->params = decls; sig->rtype = return_type ? type_infoid(return_type) : 0; sig->variadic = variadic; - if (!parse_attributes(c, &func->attributes, NULL)) return poisoned_expr; + if (!parse_attributes(c, &func->attributes, NULL, NULL)) return poisoned_expr; if (tok_is(c, TOKEN_IMPLIES)) { diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index a91984696..f6932198b 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -360,11 +360,16 @@ bool parse_module(ParseContext *c, AstId contracts) } Visibility visibility = VISIBLE_PUBLIC; Attr** attrs = NULL; - if (!parse_attributes(c, &attrs, &visibility)) return false; + bool is_cond; + if (!parse_attributes(c, &attrs, &visibility, &is_cond)) return false; FOREACH_BEGIN(Attr *attr, attrs) if (attr->is_custom) RETURN_SEMA_ERROR(attr, "Custom attributes cannot be used with 'module'."); switch (attr->attr_kind) { + case ATTRIBUTE_IF: + if (c->unit->if_attr) RETURN_SEMA_ERROR(attr, "'@if' appeared more than once."); + c->unit->if_attr = attr; + continue; case ATTRIBUTE_TEST: c->unit->test_by_default = true; continue; @@ -791,7 +796,7 @@ Decl *parse_local_decl_after_type(ParseContext *c, TypeInfo *type) Decl *decl = decl_new_var_current(c, type, VARDECL_LOCAL); advance(c); - if (!parse_attributes(c, &decl->attributes, NULL)) return poisoned_decl; + if (!parse_attributes(c, &decl->attributes, NULL, NULL)) return poisoned_decl; if (tok_is(c, TOKEN_EQ)) { if (!decl) @@ -855,7 +860,7 @@ Decl *parse_const_declaration(ParseContext *c, bool is_global) } else { - if (!parse_attributes(c, &decl->attributes, NULL)) return poisoned_decl; + if (!parse_attributes(c, &decl->attributes, NULL, NULL)) return poisoned_decl; } // Required initializer @@ -1024,7 +1029,9 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl) Visibility visibility = c->unit->default_visibility; if (decl->decl_kind == DECL_FUNC) decl->func_decl.attr_test = c->unit->test_by_default; decl->is_export = c->unit->export_by_default; - if (!parse_attributes(c, &decl->attributes, &visibility)) return false; + bool is_cond; + if (!parse_attributes(c, &decl->attributes, &visibility, &is_cond)) return false; + decl->is_cond = is_cond; decl->visibility = visibility; return true; } @@ -1036,9 +1043,10 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl) * * @return true if parsing succeeded, false if recovery is needed */ -bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref) +bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *cond_ref) { Visibility visibility = -1; + if (cond_ref) *cond_ref = false; while (1) { Attr *attr; @@ -1061,12 +1069,16 @@ bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visib case ATTRIBUTE_LOCAL: parsed_visibility = VISIBLE_LOCAL; break; + case ATTRIBUTE_IF: + if (!cond_ref) RETURN_SEMA_ERROR(attr, "'%s' cannot be used here.", attr->name); + *cond_ref = true; + break; default: break; } if (parsed_visibility != -1) { - if (!visibility_ref) RETURN_SEMA_ERROR(attr, "'%s' cannot be used here."); + if (!visibility_ref) RETURN_SEMA_ERROR(attr, "'%s' cannot be used here.", attr->name); if (visibility != -1) RETURN_SEMA_ERROR(attr, "Only a single visibility attribute may be added."); *visibility_ref = visibility = parsed_visibility; continue; @@ -1407,7 +1419,7 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Decl **body_params, } Decl *param = decl_new_var(name, span, type, param_kind); param->var.type_info = type; - if (!parse_attributes(c, ¶m->attributes, NULL)) return false; + if (!parse_attributes(c, ¶m->attributes, NULL, NULL)) return false; if (!no_name) { if (try_consume(c, TOKEN_EQ)) @@ -1499,7 +1511,9 @@ bool parse_struct_body(ParseContext *c, Decl *parent) } else { - if (!parse_attributes(c, &member->attributes, NULL)) return false; + bool is_cond; + if (!parse_attributes(c, &member->attributes, NULL, &is_cond)) return false; + member->is_cond = true; if (!parse_struct_body(c, member)) return decl_poison(parent); } vec_add(parent->strukt.members, member); @@ -1539,7 +1553,9 @@ bool parse_struct_body(ParseContext *c, Decl *parent) RETURN_SEMA_ERROR(member, "Can't add another member: the count would exceed maximum of %d elements.", MAX_MEMBERS); } advance(c); - if (!parse_attributes(c, &member->attributes, NULL)) return false; + bool is_cond; + if (!parse_attributes(c, &member->attributes, NULL, &is_cond)) return false; + member->is_cond = true; if (!try_consume(c, TOKEN_COMMA)) break; if (was_inline) { @@ -1770,8 +1786,6 @@ static inline Decl *parse_typedef_declaration(ParseContext *c) return poisoned_decl; } - if (!parse_attributes_for_global(c, decl)) return poisoned_decl; - CONSUME_OR_RET(TOKEN_EQ, poisoned_decl); bool distinct = false; bool is_inline = false; @@ -1800,6 +1814,8 @@ static inline Decl *parse_typedef_declaration(ParseContext *c) { return poisoned_decl; } + if (!parse_attributes_for_global(c, decl)) return poisoned_decl; + RANGE_EXTEND_PREV(decl); CONSUME_EOS_OR_RET(poisoned_decl); return decl; @@ -1818,6 +1834,8 @@ static inline Decl *parse_typedef_declaration(ParseContext *c) decl->define_decl.define_kind = DEFINE_TYPE_GENERIC; decl->define_decl.type_info = type_info; decl->define_decl.generic_params = params; + if (!parse_attributes_for_global(c, decl)) return poisoned_decl; + RANGE_EXTEND_PREV(decl); CONSUME_EOS_OR_RET(poisoned_decl); return decl; @@ -1840,6 +1858,8 @@ static inline Decl *parse_typedef_declaration(ParseContext *c) decl->decl_kind = DECL_TYPEDEF; decl_add_type(decl, TYPE_TYPEDEF); } + if (!parse_attributes_for_global(c, decl)) return poisoned_decl; + RANGE_EXTEND_PREV(decl); CONSUME_EOS_OR_RET(poisoned_decl); return decl; @@ -1941,6 +1961,8 @@ static inline Decl *parse_define_ident(ParseContext *c) if (!params) return poisoned_decl; decl->define_decl.generic_params = params; } + if (!parse_attributes_for_global(c, decl)) return poisoned_decl; + RANGE_EXTEND_PREV(decl); CONSUME_EOS_OR_RET(poisoned_decl); return decl; @@ -1969,15 +1991,17 @@ static inline Decl *parse_define_attribute(ParseContext *c) CONSUME_OR_RET(TOKEN_RPAREN, poisoned_decl); } - if (!parse_attributes_for_global(c, decl)) return poisoned_decl; Attr **attributes = NULL; CONSUME_OR_RET(TOKEN_EQ, poisoned_decl); CONSUME_OR_RET(TOKEN_LBRACE, poisoned_decl); - if (!parse_attributes(c, &attributes, NULL)) return poisoned_decl; + bool is_cond; + if (!parse_attributes(c, &attributes, NULL, &is_cond)) return poisoned_decl; CONSUME_OR_RET(TOKEN_RBRACE, poisoned_decl); decl->attr_decl.attrs = attributes; + decl->is_cond = is_cond; + if (!parse_attributes_for_global(c, decl)) return poisoned_decl; CONSUME_EOS_OR_RET(poisoned_decl); return decl; } @@ -2367,7 +2391,9 @@ static inline Decl *parse_static_top_level(ParseContext *c) } advance(c); Attr *attr = NULL; - if (!parse_attributes(c, &init->attributes, NULL)) return poisoned_decl; + bool is_cond; + if (!parse_attributes(c, &init->attributes, NULL, &is_cond)) return poisoned_decl; + init->is_cond = is_cond; ASSIGN_ASTID_OR_RET(init->xxlizer.init, parse_compound_stmt(c), poisoned_decl); RANGE_EXTEND_PREV(init); return init; diff --git a/src/compiler/parser.c b/src/compiler/parser.c index e481b505a..0f41d6b0c 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -72,7 +72,14 @@ static inline void parse_translation_unit(ParseContext *c) if (!decl) continue; if (decl_ok(decl)) { - add_decl_to_list(&c->unit->global_decls, decl); + if (decl->is_cond) + { + add_decl_to_list(&c->unit->global_cond_decls, decl); + } + else + { + add_decl_to_list(&c->unit->global_decls, decl); + } } else { diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index e804205cb..6f47eb992 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -49,7 +49,8 @@ Ast* parse_compound_stmt(ParseContext *c); Ast *parse_short_body(ParseContext *c, TypeInfoId return_type, bool require_eos); bool parse_attribute(ParseContext *c, Attr **attribute_ref, bool expect_eos); -bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref); + +bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *cond_ref); bool parse_switch_body(ParseContext *c, Ast ***cases, TokenType case_type, TokenType default_type); Expr *parse_ct_expression_list(ParseContext *c, bool allow_decl); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 7b8563273..8c74552ee 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -5,9 +5,9 @@ #include "sema_internal.h" -static inline bool sema_analyse_func_macro(SemaContext *context, Decl *decl, bool is_func); -static inline bool sema_analyse_func(SemaContext *context, Decl *decl); -static inline bool sema_analyse_macro(SemaContext *context, Decl *decl); +static inline bool sema_analyse_func_macro(SemaContext *context, Decl *decl, bool is_func, bool *erase_decl); +static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *erase_decl); +static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *erase_decl); static inline bool sema_analyse_signature(SemaContext *context, Signature *sig); static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl); static inline bool sema_check_param_uniqueness_and_type(Decl **decls, Decl *current, unsigned current_index, unsigned count); @@ -26,27 +26,28 @@ static inline bool sema_analyse_operator_len(Decl *method); static bool sema_check_operator_method_validity(Decl *method); static inline const char *method_name_by_decl(Decl *method_like); -static bool sema_analyse_struct_union(SemaContext *context, Decl *decl); -static bool sema_analyse_bitstruct(SemaContext *context, Decl *decl); +static bool sema_analyse_struct_union(SemaContext *context, Decl *decl, bool *erase_decl); +static bool sema_analyse_bitstruct(SemaContext *context, Decl *decl, bool *erase_decl); static bool sema_analyse_union_members(SemaContext *context, Decl *decl, Decl **members); static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl **members); -static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent, Decl *decl); +static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent, Decl *decl, bool *erase_decl); static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *decl, unsigned index, bool allow_overlap); static inline bool sema_analyse_doc_header(AstId doc, Decl **params, Decl **extra_params, bool *pure_ref); static const char *attribute_domain_to_string(AttributeDomain domain); -static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, AttributeDomain domain); +static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, AttributeDomain domain, bool *erase_decl); static bool sema_analyse_attributes_inner(SemaContext *context, Decl *decl, Attr **attrs, AttributeDomain domain, - Decl *top); -static bool sema_analyse_attributes(SemaContext *context, Decl *decl, Attr** attrs, AttributeDomain domain); -static bool sema_analyse_attributes_for_var(SemaContext *context, Decl *decl); + Decl *top, bool *erase_decl); +static bool sema_analyse_attributes(SemaContext *context, Decl *decl, Attr **attrs, AttributeDomain domain, + bool *erase_decl); +static bool sema_analyse_attributes_for_var(SemaContext *context, Decl *decl, bool *erase_decl); static bool sema_check_section(SemaContext *context, Attr *attr); static inline bool sema_analyse_attribute_decl(SemaContext *c, Decl *decl); -static inline bool sema_analyse_typedef(SemaContext *context, Decl *decl); +static inline bool sema_analyse_typedef(SemaContext *context, Decl *decl, bool *erase_decl); bool sema_analyse_decl_type(SemaContext *context, Type *type, SourceSpan span); -static inline bool sema_analyse_define(SemaContext *c, Decl *decl); +static inline bool sema_analyse_define(SemaContext *c, Decl *decl, bool *erase_decl); static inline bool sema_analyse_distinct(SemaContext *context, Decl *decl); static CompilationUnit *unit_copy(Module *module, CompilationUnit *unit); @@ -55,7 +56,7 @@ static Module *module_instantiate_generic(SemaContext *context, Module *module, SourceSpan from); static inline bool sema_analyse_enum_param(SemaContext *context, Decl *param, bool *has_default); -static inline bool sema_analyse_enum(SemaContext *context, Decl *decl); +static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *erase_decl); static inline bool sema_analyse_error(SemaContext *context, Decl *decl); @@ -131,7 +132,7 @@ static inline bool sema_check_param_uniqueness_and_type(Decl **decls, Decl *curr return true; } -static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent, Decl *decl) +static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent, Decl *decl, bool *erase_decl) { if (decl->resolve_status == RESOLVE_DONE) return decl_ok(decl); if (decl->resolve_status == RESOLVE_RUNNING) @@ -140,6 +141,27 @@ static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent } assert(!decl->unit || decl->unit->module->is_generic); decl->unit = parent->unit; + + AttributeDomain domain = ATTR_MEMBER; + switch (decl->decl_kind) + { + case DECL_BITSTRUCT: + domain = ATTR_BITSTRUCT; + break; + case DECL_UNION: + domain = ATTR_UNION; + break; + case DECL_STRUCT: + domain = ATTR_STRUCT; + break; + case DECL_VAR: + break; + default: + UNREACHABLE + } + if (!sema_analyse_attributes(context, decl, decl->attributes, domain, erase_decl)) return decl_poison(decl); + if (*erase_decl) return true; + if (decl->name) { Decl *other = sema_decl_stack_resolve_symbol(decl->name); @@ -187,15 +209,18 @@ static bool sema_analyse_union_members(SemaContext *context, Decl *decl, Decl ** AlignSize max_alignment = 0; bool has_named_parameter = false; - VECEACH(members, i) + unsigned member_count = vec_size(members); + for (unsigned i = 0; i < member_count; i++) { + AGAIN:; Decl *member = members[i]; if (!decl_ok(member)) { decl_poison(decl); continue; } - if (!sema_analyse_struct_member(context, decl, member)) + bool erase_decl = false; + if (!sema_analyse_struct_member(context, decl, member, &erase_decl)) { if (decl_ok(decl)) { @@ -204,6 +229,13 @@ static bool sema_analyse_union_members(SemaContext *context, Decl *decl, Decl ** } continue; } + if (erase_decl) + { + vec_erase_ptr_at(members, i); + member_count--; + if (i < member_count) goto AGAIN; + break; + } if (member->type->type_kind == TYPE_INFERRED_ARRAY) { SEMA_ERROR(member, "Flexible array members not allowed in unions."); @@ -286,15 +318,18 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl * AlignSize offset = 0; bool is_packed = decl->is_packed; unsigned member_count = vec_size(members); + Decl **struct_members = decl->strukt.members; for (unsigned i = 0; i < member_count; i++) { - Decl *member = decl->strukt.members[i]; + AGAIN:; + Decl *member = struct_members[i]; if (!decl_ok(member)) { decl_poison(decl); continue; } - if (!sema_analyse_struct_member(context, decl, member)) + bool erase_decl = false; + if (!sema_analyse_struct_member(context, decl, member, &erase_decl)) { if (decl_ok(decl)) { @@ -303,6 +338,13 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl * } continue; } + if (erase_decl) + { + vec_erase_ptr_at(struct_members, i); + member_count--; + if (i < member_count) goto AGAIN; + break; + } Type *member_type = type_flatten(member->type); if (member_type->type_kind == TYPE_STRUCT && member_type->decl->has_variable_array) { @@ -334,9 +376,6 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl * AlignSize member_natural_alignment; if (!sema_set_abi_alignment(context, member->type, &member_natural_alignment)) return decl_poison(decl); AlignSize member_alignment = is_packed ? 1 : member_natural_alignment; - Attr **attributes = member->attributes; - - if (!sema_analyse_attributes(context, member, attributes, ATTR_MEMBER)) return decl_poison(decl); if (member->alignment) { @@ -417,7 +456,7 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl * return true; } -static bool sema_analyse_struct_union(SemaContext *context, Decl *decl) +static bool sema_analyse_struct_union(SemaContext *context, Decl *decl, bool *erase_decl) { AttributeDomain domain; switch (decl->decl_kind) @@ -435,8 +474,8 @@ static bool sema_analyse_struct_union(SemaContext *context, Decl *decl) UNREACHABLE } - if (!sema_analyse_attributes(context, decl, decl->attributes, domain)) return decl_poison(decl); - + if (!sema_analyse_attributes(context, decl, decl->attributes, domain, erase_decl)) return decl_poison(decl); + if (*erase_decl) return true; DEBUG_LOG("Beginning analysis of %s.", decl->name ? decl->name : ".anon"); bool success; @@ -628,10 +667,10 @@ AFTER_BIT_CHECK: return true; } -static bool sema_analyse_bitstruct(SemaContext *context, Decl *decl) +static bool sema_analyse_bitstruct(SemaContext *context, Decl *decl, bool *erase_decl) { - if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_BITSTRUCT)) return decl_poison(decl); - + if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_BITSTRUCT, erase_decl)) return decl_poison(decl); + if (*erase_decl) return true; DEBUG_LOG("Beginning analysis of %s.", decl->name ? decl->name : ".anon"); if (!sema_resolve_type_info(context, decl->bitstruct.base_type)) return false; Type *type = decl->bitstruct.base_type->type->canonical; @@ -767,7 +806,9 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig) SEMA_ERROR(param, "Only typed parameters are allowed for functions."); return false; } - if (!sema_analyse_attributes_for_var(context, param)) return false; + bool erase_decl = false; + if (!sema_analyse_attributes_for_var(context, param, &erase_decl)) return false; + assert(!erase_decl); break; case VARDECL_PARAM_CT_TYPE: if (!is_macro) @@ -874,9 +915,10 @@ Type *sema_analyse_function_signature(SemaContext *context, Decl *parent, CallAB return type; } -static inline bool sema_analyse_typedef(SemaContext *context, Decl *decl) +static inline bool sema_analyse_typedef(SemaContext *context, Decl *decl, bool *erase_decl) { - if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_DEFINE)) return decl_poison(decl); + if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_DEFINE, erase_decl)) return decl_poison(decl); + if (*erase_decl) return true; if (decl->typedef_decl.is_func) { @@ -1007,8 +1049,11 @@ static inline bool sema_analyse_enum_param(SemaContext *context, Decl *param, bo return sema_set_abi_alignment(context, param->type, ¶m->alignment); } -static inline bool sema_analyse_enum(SemaContext *context, Decl *decl) +static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *erase_decl) { + if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_ENUM, erase_decl)) return decl_poison(decl); + if (*erase_decl) return true; + // Resolve the type of the enum. if (!sema_resolve_type_info(context, decl->enums.type_info)) return false; @@ -1025,7 +1070,6 @@ static inline bool sema_analyse_enum(SemaContext *context, Decl *decl) DEBUG_LOG("* Enum type resolved to %s.", type->name); - if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_ENUM)) return decl_poison(decl); Decl **associated_values = decl->enums.parameters; unsigned associated_value_count = vec_size(associated_values); @@ -1335,6 +1379,27 @@ INLINE void sema_set_method_ext_name(CompilationUnit *unit, const char *parent_n } method_like->extname = scratch_buffer_copy(); } + +bool sema_decl_if_cond(SemaContext *context, Decl *decl) +{ + FOREACH_BEGIN(Attr *attr, decl->attributes) + if (attr->attr_kind != ATTRIBUTE_IF) continue; + if (vec_size(attr->exprs) != 1) + { + RETURN_SEMA_ERROR(attr, "Expected an argument to '@if'."); + } + Expr *expr = attr->exprs[0]; + if (!sema_analyse_ct_expr(context, expr)) return false; + if (expr->type->canonical != type_bool) + { + RETURN_SEMA_ERROR(expr, "Expected a boolean value not %s.", type_quoted_error_string(expr->type)); + } + if (expr->const_expr.b) return true; + decl->decl_kind = DECL_ERASED; + return false; + FOREACH_END(); + UNREACHABLE +} static inline bool unit_add_base_extension_method(CompilationUnit *unit, Type *parent_type, Decl *method_like) { sema_set_method_ext_name(unit, parent_type->name, method_like); @@ -1477,17 +1542,18 @@ static const char *attribute_domain_to_string(AttributeDomain domain) #define EXPORTED_USER_DEFINED_TYPES ATTR_ENUM | ATTR_UNION | ATTR_STRUCT #define USER_DEFINED_TYPES EXPORTED_USER_DEFINED_TYPES | ATTR_BITSTRUCT -static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, AttributeDomain domain) +static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, AttributeDomain domain, bool *erase_decl) { AttributeType type = attr->attr_kind; assert(type >= 0 && type < NUMBER_OF_ATTRIBUTES); static AttributeDomain attribute_domain[NUMBER_OF_ATTRIBUTES] = { - [ATTRIBUTE_ALIGN] = ATTR_FUNC | ATTR_CONST | ATTR_LOCAL | ATTR_GLOBAL | ATTR_STRUCT | ATTR_UNION | ATTR_MEMBER, + [ATTRIBUTE_ALIGN] = ATTR_FUNC | ATTR_CONST | ATTR_LOCAL | ATTR_GLOBAL | ATTR_BITSTRUCT | ATTR_STRUCT | ATTR_UNION | ATTR_MEMBER, [ATTRIBUTE_BIGENDIAN] = ATTR_BITSTRUCT, - [ATTRIBUTE_BUILTIN] = ATTR_MACRO | ATTR_FUNC, + [ATTRIBUTE_BUILTIN] = ATTR_MACRO | ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST, [ATTRIBUTE_CDECL] = ATTR_FUNC, [ATTRIBUTE_DEPRECATED] = USER_DEFINED_TYPES | ATTR_FUNC | ATTR_MACRO | ATTR_CONST | ATTR_GLOBAL | ATTR_MEMBER, [ATTRIBUTE_DYNAMIC] = ATTR_FUNC, + [ATTRIBUTE_IF] = (AttributeDomain)~(ATTR_CALL | ATTR_LOCAL), [ATTRIBUTE_INTERFACE] = ATTR_FUNC, [ATTRIBUTE_EXPORT] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES, [ATTRIBUTE_NOSTRIP] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES, @@ -1683,6 +1749,15 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, case ATTRIBUTE_NOSTRIP: decl->no_strip = true; return true; + case ATTRIBUTE_IF: + if (!expr) RETURN_SEMA_ERROR(attr, "'@if' requires a boolean argument."); + if (!sema_analyse_expr(context, expr)) return false; + if (expr->type->canonical != type_bool || !expr_is_const(expr)) + { + RETURN_SEMA_ERROR(expr, "Expected a boolean compile time constant value."); + } + if (!expr->const_expr.b) *erase_decl = true; + return true; case ATTRIBUTE_EXTNAME: case ATTRIBUTE_SECTION: case ATTRIBUTE_EXTERN: @@ -1816,7 +1891,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, // TODO consider doing this evaluation early, it should be possible. static bool sema_analyse_attributes_inner(SemaContext *context, Decl *decl, Attr **attrs, AttributeDomain domain, - Decl *top) + Decl *top, bool *erase_decl) { // Detect cycles of the type @Foo = @BarCyclic, @BarCyclic = @BarCyclic if (context->macro_call_depth > 1024) @@ -1833,7 +1908,8 @@ static bool sema_analyse_attributes_inner(SemaContext *context, Decl *decl, Attr if (!attr->is_custom) { // Analyse it and move on. - if (!sema_analyse_attribute(context, decl, attr, domain)) return false; + if (!sema_analyse_attribute(context, decl, attr, domain, erase_decl)) return false; + if (*erase_decl) return true; continue; } @@ -1892,9 +1968,11 @@ static bool sema_analyse_attributes_inner(SemaContext *context, Decl *decl, Attr } // Now we've added everything to the evaluation context, so we can (recursively) // apply it to the contained attributes, which in turn may be derived attributes. - if (!sema_analyse_attributes_inner(&eval_context, decl, attributes, domain, top ? top : attr_decl)) goto ERR; + if (!sema_analyse_attributes_inner(&eval_context, decl, attributes, domain, top ? top : attr_decl, erase_decl)) goto ERR; // Then destroy the eval context. sema_context_destroy(&eval_context); + // Stop evaluating on erase. + if (*erase_decl) return true; continue; ERR: sema_context_destroy(&eval_context); @@ -1903,9 +1981,10 @@ ERR: return true; } -static bool sema_analyse_attributes(SemaContext *context, Decl *decl, Attr** attrs, AttributeDomain domain) +static bool sema_analyse_attributes(SemaContext *context, Decl *decl, Attr **attrs, AttributeDomain domain, + bool *erase_decl) { - return sema_analyse_attributes_inner(context, decl, attrs, domain, NULL); + return sema_analyse_attributes_inner(context, decl, attrs, domain, NULL, erase_decl); } static inline bool sema_analyse_doc_header(AstId doc, Decl **params, Decl **extra_params, bool *pure_ref) @@ -2269,15 +2348,24 @@ REGISTER_MAIN: return true; } -static inline bool sema_analyse_func_macro(SemaContext *context, Decl *decl, bool is_func) +static inline bool sema_analyse_func_macro(SemaContext *context, Decl *decl, bool is_func, bool *erase_decl) { - if (!sema_analyse_attributes(context, decl, decl->attributes, is_func ? ATTR_FUNC : ATTR_MACRO)) return decl_poison(decl); + if (!sema_analyse_attributes(context, + decl, + decl->attributes, + is_func ? ATTR_FUNC : ATTR_MACRO, + erase_decl)) return decl_poison(decl); return true; } -static inline bool sema_analyse_xxlizer(SemaContext *context, Decl *decl) +static inline bool sema_analyse_xxlizer(SemaContext *context, Decl *decl, bool *erase_decl) { - if (!sema_analyse_attributes(context, decl, decl->attributes, decl->decl_kind == DECL_INITIALIZE ? ATTR_INITIALIZER : ATTR_FINALIZER)) return decl_poison(decl); + if (!sema_analyse_attributes(context, + decl, + decl->attributes, + decl->decl_kind == DECL_INITIALIZE ? ATTR_INITIALIZER : ATTR_FINALIZER, + erase_decl)) return decl_poison(decl); + if (*erase_decl) return true; if (decl->xxlizer.priority == 0) decl->xxlizer.priority = MAX_PRIORITY; context->call_env = (CallEnv) { .kind = decl->decl_kind == DECL_INITIALIZE ? CALL_ENV_INITIALIZER : CALL_ENV_FINALIZER }; context->rtype = type_void; @@ -2318,11 +2406,13 @@ SKIP_NEW_RETURN: return sema_analyse_statement(context, body); } -static inline bool sema_analyse_func(SemaContext *context, Decl *decl) +static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *erase_decl) { DEBUG_LOG("----Analysing function %s", decl->name); - if (!sema_analyse_func_macro(context, decl, true)) return false; + if (!sema_analyse_func_macro(context, decl, true, erase_decl)) return false; + + if (*erase_decl) return true; if (decl->name == kw___run_default_test_runner) { @@ -2487,11 +2577,12 @@ static bool sema_analyse_macro_method(SemaContext *context, Decl *decl) return unit_add_method_like(context->unit, parent_type->canonical, decl); } -static inline bool sema_analyse_macro(SemaContext *context, Decl *decl) +static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *erase_decl) { decl->func_decl.unit = context->unit; - if (!sema_analyse_func_macro(context, decl, false)) return false; + if (!sema_analyse_func_macro(context, decl, false, erase_decl)) return false; + if (*erase_decl) return true; if (!sema_analyse_signature(context, &decl->func_decl.signature)) return decl_poison(decl); if (!decl->func_decl.signature.is_at_macro && decl->func_decl.body_param) @@ -2547,7 +2638,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl) } -static bool sema_analyse_attributes_for_var(SemaContext *context, Decl *decl) +static bool sema_analyse_attributes_for_var(SemaContext *context, Decl *decl, bool *erase_decl) { AttributeDomain domain; switch (decl->var.kind) @@ -2562,7 +2653,7 @@ static bool sema_analyse_attributes_for_var(SemaContext *context, Decl *decl) domain = ATTR_LOCAL; break; } - if (!sema_analyse_attributes(context, decl, decl->attributes, domain)) return decl_poison(decl); + if (!sema_analyse_attributes(context, decl, decl->attributes, domain, erase_decl)) return decl_poison(decl); return true; } @@ -2693,8 +2784,15 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) if (!sema_add_local(context, decl)) return decl_poison(decl); } - if (!sema_analyse_attributes_for_var(context, decl)) return decl_poison(decl); + bool erase_decl = false; + if (!sema_analyse_attributes_for_var(context, decl, &erase_decl)) return decl_poison(decl); + if (erase_decl) + { + decl->decl_kind = DECL_ERASED; + decl->resolve_status = RESOLVE_DONE; + return true; + } // 1. Local or global constants: const int FOO = 123. if (!decl->var.type_info) { @@ -2852,6 +2950,7 @@ static CompilationUnit *unit_copy(Module *module, CompilationUnit *unit) CompilationUnit *copy = unit_create(unit->file); copy->imports = copy_decl_list_single(unit->imports); copy->global_decls = copy_decl_list_single(unit->global_decls); + copy->global_cond_decls = copy_decl_list_single(unit->global_cond_decls); copy->module = module; assert(!unit->functions && !unit->macro_methods && !unit->methods && !unit->enums && !unit->ct_ifs && !unit->types); return copy; @@ -3103,6 +3202,11 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl) } if (global_context.errors_found) return decl_poison(decl); Decl *symbol = module_find_symbol(instantiated_module, name); + if (!symbol) + { + SEMA_ERROR(decl, "The generic module '%s' does not have '%s' for this parameterization.", module->name->module, name); + return decl_poison(decl); + } if (was_initiated && instantiated_module->contracts) { SourceSpan error_span = extend_span_with_token(params[0]->span, params[parameter_count - 1]->span); @@ -3111,7 +3215,6 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl) return decl_poison(decl); } } - assert(symbol); if (!sema_analyse_decl(c, symbol)) return false; unit_register_external_symbol(c->compilation_unit, symbol); switch (decl->define_decl.define_kind) @@ -3173,9 +3276,9 @@ static inline bool sema_analyse_attribute_decl(SemaContext *c, Decl *decl) return true; } -static inline bool sema_analyse_define(SemaContext *c, Decl *decl) +static inline bool sema_analyse_define(SemaContext *c, Decl *decl, bool *erase_decl) { - if (!sema_analyse_attributes(c, decl, decl->attributes, ATTR_DEFINE)) return decl_poison(decl); + if (!sema_analyse_attributes(c, decl, decl->attributes, ATTR_DEFINE, erase_decl)) return decl_poison(decl); // 1. The plain define if (decl->define_decl.define_kind == DEFINE_IDENT_ALIAS) @@ -3207,51 +3310,55 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl) } decl->resolve_status = RESOLVE_RUNNING; assert(decl->unit); + bool erase_decl = false; + bool set_external_name = false; switch (decl->decl_kind) { + case DECL_ERASED: + break; case DECL_BITSTRUCT: - if (!sema_analyse_bitstruct(context, decl)) goto FAILED; - decl_set_external_name(decl); + if (!sema_analyse_bitstruct(context, decl, &erase_decl)) goto FAILED; + set_external_name = true; break; case DECL_STRUCT: case DECL_UNION: - if (!sema_analyse_struct_union(context, decl)) goto FAILED; - decl_set_external_name(decl); + if (!sema_analyse_struct_union(context, decl, &erase_decl)) goto FAILED; + set_external_name = true; break; case DECL_FUNC: - if (!sema_analyse_func(context, decl)) goto FAILED; + if (!sema_analyse_func(context, decl, &erase_decl)) goto FAILED; break; case DECL_MACRO: - if (!sema_analyse_macro(context, decl)) goto FAILED; + if (!sema_analyse_macro(context, decl, &erase_decl)) goto FAILED; break; case DECL_VAR: if (!sema_analyse_var_decl(context, decl, false)) goto FAILED; - decl_set_external_name(decl); + set_external_name = true; break; case DECL_ATTRIBUTE: if (!sema_analyse_attribute_decl(context, decl)) goto FAILED; break; case DECL_DISTINCT: if (!sema_analyse_distinct(context, decl)) goto FAILED; - decl_set_external_name(decl); + set_external_name = true; break; case DECL_TYPEDEF: - if (!sema_analyse_typedef(context, decl)) goto FAILED; + if (!sema_analyse_typedef(context, decl, &erase_decl)) goto FAILED; break; case DECL_ENUM: - if (!sema_analyse_enum(context, decl)) goto FAILED; - decl_set_external_name(decl); + if (!sema_analyse_enum(context, decl, &erase_decl)) goto FAILED; + set_external_name = true; break; case DECL_FAULT: if (!sema_analyse_error(context, decl)) goto FAILED; - decl_set_external_name(decl); + set_external_name = true; break; case DECL_DEFINE: - if (!sema_analyse_define(context, decl)) goto FAILED; + if (!sema_analyse_define(context, decl, &erase_decl)) goto FAILED; break; case DECL_INITIALIZE: case DECL_FINALIZE: - if (!sema_analyse_xxlizer(context, decl)) goto FAILED; + if (!sema_analyse_xxlizer(context, decl, &erase_decl)) goto FAILED; break; case DECL_POISONED: case DECL_IMPORT: @@ -3271,6 +3378,12 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl) case DECL_GLOBALS: UNREACHABLE } + if (erase_decl) + { + decl->decl_kind = DECL_ERASED; + set_external_name = false; + } + if (set_external_name) decl_set_external_name(decl); decl->resolve_status = RESOLVE_DONE; sema_context_destroy(&temp_context); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 8f318ad27..7849c3a26 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -563,6 +563,7 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr) case DECL_FINALIZE: case DECL_CT_INCLUDE: case DECL_GLOBALS: + case DECL_ERASED: UNREACHABLE case DECL_POISONED: return expr_poison(expr); @@ -791,6 +792,7 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to, if (decl->decl_kind == DECL_VAR || decl->decl_kind == DECL_FUNC || decl->decl_kind == DECL_MACRO) { + if (!sema_analyse_decl(context, decl)) return false; if (decl->unit->module != context->unit->module && !decl->is_autoimport && !expr->identifier_expr.path) { const char *message; diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index 17abe2622..f881ae04b 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -53,7 +53,9 @@ void sema_append_contract_asserts(AstId assert_first, Ast* compound_stmt); void sema_analyse_pass_top(Module *module); void sema_analyse_pass_module_hierarchy(Module *module); void sema_analysis_pass_process_imports(Module *module); -void sema_analysis_pass_register_globals(Module *module); +void sema_analysis_pass_register_global_declarations(Module *module); +void sema_analysis_pass_register_conditional_units(Module *module); +void sema_analysis_pass_register_conditional_declarations(Module *module); void sema_analysis_pass_conditional_compilation(Module *module); void sema_analysis_pass_decls(Module *module); void sema_analysis_pass_ct_assert(Module *module); @@ -84,6 +86,7 @@ bool cast_widen_top_down(SemaContext *context, Expr *expr, Type *type); bool cast_promote_vararg(Expr *arg); Type *cast_numeric_arithmetic_promotion(Type *type); void cast_to_int_to_max_bit_size(SemaContext *context, Expr *lhs, Expr *rhs, Type *left_type, Type *right_type); +bool sema_decl_if_cond(SemaContext *context, Decl *decl); bool sema_analyse_checked(SemaContext *context, Ast *directive, SourceSpan span); diff --git a/src/compiler/sema_liveness.c b/src/compiler/sema_liveness.c index 81d3b69f0..15397e800 100644 --- a/src/compiler/sema_liveness.c +++ b/src/compiler/sema_liveness.c @@ -514,6 +514,8 @@ RETRY: decl->is_live = true; switch (decl->decl_kind) { + case DECL_ERASED: + return; case DECL_TYPEDEF: if (!decl->typedef_decl.is_func) { diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 8a99540ba..348e0ea1f 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -110,23 +110,87 @@ void sema_analysis_pass_process_imports(Module *module) DEBUG_LOG("Pass finished processing %d import(s) with %d error(s).", import_count, global_context.errors_found); } -void sema_analysis_pass_register_globals(Module *module) +INLINE void register_global_decls(CompilationUnit *unit, Decl **decls) +{ + VECEACH(decls, i) + { + unit_register_global_decl(unit, decls[i]); + } + vec_resize(decls, 0); +} + +void sema_analysis_pass_register_global_declarations(Module *module) { DEBUG_LOG("Pass: Register globals for module '%s'.", module->name->module); + VECEACH(module->units, index) + { + CompilationUnit *unit = module->units[index]; + if (unit->if_attr) continue; + unit->module = module; + DEBUG_LOG("Processing %s.", unit->file->name); + register_global_decls(unit, unit->global_decls); + } + DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); +} + +void sema_analysis_pass_register_conditional_units(Module *module) +{ + DEBUG_LOG("Pass: Register conditional units for %s", module->name->module); + VECEACH(module->units, index) + { + CompilationUnit *unit = module->units[index]; + Attr *if_attr = unit->if_attr; + if (!if_attr) continue; + if (vec_size(if_attr->exprs) != 1) + { + SEMA_ERROR(if_attr, "Expected one parameter."); + break; + } + Expr *expr = if_attr->exprs[0]; + SemaContext context; + sema_context_init(&context, unit); + bool success = sema_analyse_ct_expr(&context, expr); + sema_context_destroy(&context); + if (!success) continue; + if (!expr_is_const(expr) || expr->type->canonical != type_bool) + { + SEMA_ERROR(expr, "Expected a constant boolean expression."); + break; + } + if (!expr->const_expr.b) + { + vec_resize(unit->global_decls, 0); + vec_resize(unit->global_cond_decls, 0); + continue; + } + register_global_decls(unit, unit->global_decls); + } + DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); +} + +void sema_analysis_pass_register_conditional_declarations(Module *module) +{ + DEBUG_LOG("Pass: Register conditional declarations for module '%s'.", module->name->module); VECEACH(module->units, index) { CompilationUnit *unit = module->units[index]; unit->module = module; DEBUG_LOG("Processing %s.", unit->file->name); - Decl **decls = unit->global_decls; + Decl **decls = unit->global_cond_decls; VECEACH(decls, i) { - unit_register_global_decl(unit, decls[i]); + Decl *decl = decls[i]; + SemaContext context; + sema_context_init(&context, unit); + if (sema_decl_if_cond(&context, decl)) + { + unit_register_global_decl(unit, decl); + } + sema_context_destroy(&context); } - vec_resize(unit->global_decls, 0); + vec_resize(decls, 0); } - DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); } diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index f785dfe22..d66820343 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -183,6 +183,8 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in decl = decl_flatten(decl); switch (decl->decl_kind) { + case DECL_ERASED: + UNREACHABLE case DECL_STRUCT: case DECL_BITSTRUCT: case DECL_UNION: diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index f4907c11e..a742fdd72 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -138,8 +138,14 @@ void sema_analyze_stage(Module *module, AnalysisStage stage) case ANALYSIS_IMPORTS: sema_analysis_pass_process_imports(module); break; - case ANALYSIS_REGISTER_GLOBALS: - sema_analysis_pass_register_globals(module); + case ANALYSIS_REGISTER_GLOBAL_DECLARATIONS: + sema_analysis_pass_register_global_declarations(module); + break; + case ANALYSIS_REGISTER_CONDITIONAL_UNITS: + sema_analysis_pass_register_conditional_units(module); + break; + case ANALYSIS_REGISTER_CONDITIONAL_DECLARATIONS: + sema_analysis_pass_register_conditional_declarations(module); break; case ANALYSIS_CONDITIONAL_COMPILATION: sema_analysis_pass_conditional_compilation(module); @@ -181,6 +187,7 @@ static void register_generic_decls(CompilationUnit *unit, Decl **decls) case DECL_FINALIZE: case DECL_CT_IF: case DECL_CT_SWITCH: + case DECL_ERASED: continue; case DECL_ATTRIBUTE: break; @@ -217,6 +224,7 @@ static void analyze_generic_module(Module *module) { CompilationUnit *unit = module->units[index]; register_generic_decls(unit, unit->global_decls); + register_generic_decls(unit, unit->global_cond_decls); } sema_analyze_stage(module, ANALYSIS_MODULE_HIERARCHY); } diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index e52384a66..3a9f73a3a 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -301,6 +301,7 @@ void symtab_init(uint32_t capacity) attribute_list[ATTRIBUTE_EXPORT] = KW_DEF("@export"); attribute_list[ATTRIBUTE_EXTERN] = KW_DEF("@extern"); attribute_list[ATTRIBUTE_EXTNAME] = KW_DEF("@extname"); + attribute_list[ATTRIBUTE_IF] = KW_DEF("@if"); attribute_list[ATTRIBUTE_INLINE] = KW_DEF("@inline"); attribute_list[ATTRIBUTE_INTERFACE] = KW_DEF("@interface"); attribute_list[ATTRIBUTE_LITTLEENDIAN] = KW_DEF("@littleendian"); diff --git a/src/utils/lib.h b/src/utils/lib.h index 37d99a8c4..9e88d7c4b 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -163,6 +163,7 @@ static inline uint32_t fnv1a(const char *key, uint32_t len); INLINE uint32_t vec_size(const void *vec); static inline void vec_resize(void *vec, uint32_t new_size); static inline void vec_pop(void *vec); +static inline void vec_erase_ptr_at(void *vec, unsigned i); #define NUMBER_CHAR_CASE '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9' #define UPPER_CHAR_CASE 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': \ @@ -238,6 +239,20 @@ static inline void vec_pop(void *vec) header[-1].size--; } +static inline void vec_erase_ptr_at(void *vec, unsigned i) +{ + assert(vec); + unsigned size = vec_size(vec); + assert(size > i); + void **vecptr = (void**)vec; + for (int j = i + 1; j < size; j++) + { + vecptr[j - 1] = vecptr[j]; + } + VHeader_ *header = vec; + header[-1].size--; +} + static inline void* expand_(void *vec, size_t element_size) { VHeader_ *header; diff --git a/src/version.h b/src/version.h index 6cf17232c..907962da0 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.525" \ No newline at end of file +#define COMPILER_VERSION "0.4.526" \ No newline at end of file diff --git a/test/test_suite/attributes/user_defined_attributes.c3t b/test/test_suite/attributes/user_defined_attributes.c3t index 8847102cb..1fa117e4a 100644 --- a/test/test_suite/attributes/user_defined_attributes.c3t +++ b/test/test_suite/attributes/user_defined_attributes.c3t @@ -5,7 +5,7 @@ module test; def @Foo = { @noreturn @weak }; def @Align(y) = { @align(y) }; -def @Align16(x) @private = { @Align(8 * x) @align(1024) }; +def @Align16(x) = { @Align(8 * x) @align(1024) } @private; def @Test = { @noinline }; def @TestZero = { }; struct Foo diff --git a/test/test_suite/compile_time/compile_time_pointers.c3t b/test/test_suite/compile_time/compile_time_pointers.c3t index 59a9d5082..fa552fcbc 100644 --- a/test/test_suite/compile_time/compile_time_pointers.c3t +++ b/test/test_suite/compile_time/compile_time_pointers.c3t @@ -11,9 +11,7 @@ const int* BOB = (int*)16 - 1; const int* BAB = (int*)16 + 1; const isz AO = BAB - BOB; -$if ZAB > 100: -int abc = 123; -$endif +int abc @if(ZAB > 100) = 123; fn void test() { diff --git a/test/test_suite/compile_time/ct_if.c3t b/test/test_suite/compile_time/ct_if.c3t index 91af81769..8770f2e24 100644 --- a/test/test_suite/compile_time/ct_if.c3t +++ b/test/test_suite/compile_time/ct_if.c3t @@ -1,68 +1,7 @@ -$if 0: -$else - $switch - $case false: - $case false: - $case false: - $default: - int x = 1; - $endswitch -$endif +int x @if(false) = 1; -$switch -$case false: -$assert false; -$case false: -$assert false; -$default: -$assert true; -$endswitch - -$if 1: -$assert true; -int d = 5; -$else -$assert false; -$endif - -$switch -$case false: -$assert true; -$case true: -$assert true; -int c = 5; -$default: -$assert false; -$endswitch - -$switch -$case false: -$assert true; -$case true: -$assert true; -int b = 4; -$case false: -$assert false; -$default: -$assert false; -$endswitch - -$switch -$case false: -$assert true; -$case false: -$assert false; -$case true: -$assert true; -int a = 3; -$default: -$assert false; -$endswitch +int d @if(true) = 5; /* #expect: ct_if.ll @ct_if.d = local_unnamed_addr global i32 5, align 4 -@ct_if.c = local_unnamed_addr global i32 5, align 4 -@ct_if.b = local_unnamed_addr global i32 4, align 4 -@ct_if.a = local_unnamed_addr global i32 3, align 4 -@ct_if.x = local_unnamed_addr global i32 1, align 4 \ No newline at end of file diff --git a/test/test_suite/compile_time/ct_if_fails.c3 b/test/test_suite/compile_time/ct_if_fails.c3 deleted file mode 100644 index c9a640429..000000000 --- a/test/test_suite/compile_time/ct_if_fails.c3 +++ /dev/null @@ -1,31 +0,0 @@ -int x; -$if x > 0: -$endif - -$if 0: - $assert false; -$endif - -$if 1: -$else -$endif - -$if 1: -$else -$else // #error: Expected the start of a global declaration here -$endif - - -$switch -$case true: -$case true: -$default: -$endswitch - -$switch -$case true: -$case true: -$case true: -$default: -$endswitch - diff --git a/test/test_suite/compile_time/ct_switch_top_level.c3t b/test/test_suite/compile_time/ct_switch_top_level.c3t index 99bee2cb2..c213d4217 100644 --- a/test/test_suite/compile_time/ct_switch_top_level.c3t +++ b/test/test_suite/compile_time/ct_switch_top_level.c3t @@ -15,12 +15,10 @@ macro tester() $endswitch } -$switch (bool.typeid) -$case int: - int oefke = 23; -$default: - int oeoekgokege = 343432; -$endswitch + +const BOOL_TYPEID = bool.typeid; +int oefke @if(BOOL_TYPEID == int.typeid) = 23; +int oeoekgokege @if(BOOL_TYPEID != int.typeid) = 343432; fn int main() { @@ -38,7 +36,7 @@ target triple = "x86_64-apple-darwin" @test.oeoekgokege = local_unnamed_addr global i32 343432, align 4 @.str = private unnamed_addr constant [7 x i8] c"Hello\0A\00", align 1 -@.str.1 = private unnamed_addr constant [7 x i8] c"Hello\0A\00", align 1 +@.str.2 = private unnamed_addr constant [7 x i8] c"Hello\0A\00", align 1 define i32 @main() #0 { entry: @@ -47,7 +45,7 @@ entry: %i = alloca i32, align 4 call void (ptr, ...) @printf(ptr @.str) store i32 0, ptr %z, align 4 - call void (ptr, ...) @printf(ptr @.str.1) + call void (ptr, ...) @printf(ptr @.str.2) store i32 0, ptr %z1, align 4 store i32 1, ptr %i, align 4 ret i32 1 diff --git a/test/test_suite/compile_time/stringify.c3t b/test/test_suite/compile_time/stringify.c3t index 546a5882b..12432da13 100644 --- a/test/test_suite/compile_time/stringify.c3t +++ b/test/test_suite/compile_time/stringify.c3t @@ -8,16 +8,16 @@ macro @timeit(#call) long t = (long)libc::clock(); var $Type = $typeof(#call); var $is_void = $Type.typeid == void.typeid; -$if $is_void: - #call; -$else - $Type result = #call; -$endif + $if $is_void: + #call; + $else + $Type result = #call; + $endif long diff = (long)libc::clock() - t; libc::printf("'%s' took %lld us\n", $stringify(#call), diff); -$if !$is_void: - return result; -$endif + $if !$is_void: + return result; + $endif } fn void test() diff --git a/test/test_suite/constants/init_order.c3t b/test/test_suite/constants/init_order.c3t index 96d1e0355..c8890c104 100644 --- a/test/test_suite/constants/init_order.c3t +++ b/test/test_suite/constants/init_order.c3t @@ -12,9 +12,7 @@ macro foo() const Z = foo(); -$if !$defined(A) && Z == 1: - const A = 222; -$endif +const A @if(!$defined(A) && Z == 1) = 222; const B = foo(); diff --git a/test/test_suite/import/import_error_out_of_order.c3 b/test/test_suite/import/import_error_out_of_order.c3 deleted file mode 100644 index 8ce736166..000000000 --- a/test/test_suite/import/import_error_out_of_order.c3 +++ /dev/null @@ -1,9 +0,0 @@ -module foo; - -fn void hello() {} - -$if true: - -import bar; // #error: 'import' may not appear inside a compile - -$endif \ No newline at end of file diff --git a/test/test_suite/macros/userland_bitcast.c3t b/test/test_suite/macros/userland_bitcast.c3t index 724aaa843..b9dad9812 100644 --- a/test/test_suite/macros/userland_bitcast.c3t +++ b/test/test_suite/macros/userland_bitcast.c3t @@ -6,36 +6,36 @@ macro testbitcast(expr, $Type) $Type x @noinit; var $size = (usz)($sizeof(expr)); -$switch - $case $alignof(expr) >= 8 && $Type.alignof >= 8: - ulong *b = (ulong*)(&expr); - ulong *to = (ulong*)(&x); - for (usz i = 0; i < $size; i += 8) - { - to[i] = b[i]; - } - $case $alignof(expr) >= 4 && $Type.alignof >= 4: - uint* b = (uint*)(&expr); - uint* to = (uint*)(&x); - for (usz i = 0; i < $size; i += 4) - { - to[i] = b[i]; - } - $case $alignof(expr) >= 2 && $Type.alignof >= 2: - ushort* b = (ushort*)(&expr); - ushort* to = (ushort*)(&x); - for (usz i = 0; i < $size; i += 2) - { - to[i] = b[i]; - } - $default: - char* b = (char*)(&expr); - char* to = (char*)(&x); - for (usz i = 0; i < $size; i++) - { - to[i] = b[i]; - } -$endswitch + $switch + $case $alignof(expr) >= 8 && $Type.alignof >= 8: + ulong *b = (ulong*)(&expr); + ulong *to = (ulong*)(&x); + for (usz i = 0; i < $size; i += 8) + { + to[i] = b[i]; + } + $case $alignof(expr) >= 4 && $Type.alignof >= 4: + uint* b = (uint*)(&expr); + uint* to = (uint*)(&x); + for (usz i = 0; i < $size; i += 4) + { + to[i] = b[i]; + } + $case $alignof(expr) >= 2 && $Type.alignof >= 2: + ushort* b = (ushort*)(&expr); + ushort* to = (ushort*)(&x); + for (usz i = 0; i < $size; i += 2) + { + to[i] = b[i]; + } + $default: + char* b = (char*)(&expr); + char* to = (char*)(&x); + for (usz i = 0; i < $size; i++) + { + to[i] = b[i]; + } + $endswitch return x; }