Compare commits

..

8 Commits

Author SHA1 Message Date
Christoffer Lerno
75a6ae7111 Enable LLVM 15 2023-06-12 09:42:23 +02:00
Christoffer Lerno
cf83651c79 The new @if directive. 2023-06-11 18:56:37 +02:00
Christoffer Lerno
4c1edfb941 Dev (#777)
* The new @if directive.
2023-06-10 23:16:28 +02:00
Christoffer Lerno
82c3facb65 --obj, --emit-stdlib, --strip-unused 2023-06-09 09:37:07 +02:00
Christoffer Lerno
266dba466c Rename to no-emit-stdlib 2023-06-06 15:25:25 +02:00
Christoffer Lerno
379a5f670f Add no-obj and no-stdlib-codegen options. 2023-06-06 15:22:28 +02:00
Christoffer Lerno
8eaad81800 Dead strip by default. Add list to_string. Fix missing check for dynamic calls. 2023-06-05 14:54:17 +02:00
Christoffer Lerno
4baacc7d52 Formatting. 2023-06-03 12:08:11 +02:00
113 changed files with 1537 additions and 1763 deletions

View File

@@ -184,7 +184,7 @@ jobs:
fail-fast: false
matrix:
build_type: [Release, Debug]
llvm_version: [16]
llvm_version: [15, 16, 17]
steps:
- uses: actions/checkout@v3
@@ -195,15 +195,23 @@ jobs:
- name: Install Clang ${{matrix.llvm_version}}
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
if [[ "${{matrix.llvm_version}}" < 16 ]]; then
sudo apt remove libllvm15
fi
if [[ "${{matrix.llvm_version}}" < 17 ]]; then
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{matrix.llvm_version}} main"
sudo apt-get update
sudo apt-get install -y -t llvm-toolchain-focal-${{matrix.llvm_version}} libpolly-${{matrix.llvm_version}}-dev \
clang-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}}-dev \
lld-${{matrix.llvm_version}} liblld-${{matrix.llvm_version}}-dev libmlir-${{matrix.llvm_version}} \
libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools
else
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main"
sudo apt-get install -y -t llvm-toolchain-focal libpolly-${{matrix.llvm_version}}-dev \
clang-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}}-dev \
lld-${{matrix.llvm_version}} liblld-${{matrix.llvm_version}}-dev libmlir-${{matrix.llvm_version}} \
libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools
fi
sudo apt-get update
sudo apt-get install -y clang-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}}-dev lld-${{matrix.llvm_version}} liblld-${{matrix.llvm_version}}-dev
sudo apt-get install -y libmlir-${{matrix.llvm_version}} libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools
sudo apt-get install -y libpolly-${{matrix.llvm_version}}-dev
- name: CMake
run: |
cmake -B build \

View File

@@ -7,142 +7,141 @@
**/
module std::collections::enumset<Enum>;
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;
}

View File

@@ -5,6 +5,8 @@ module std::collections::list<Type>;
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,6 +40,30 @@ 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
{
return string::printf("%s", *list);
}
fn void List.push(List* list, Type element) @inline
{
list.append(element);
@@ -281,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)
{
@@ -292,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)
{
@@ -301,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)
@@ -318,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)
{
@@ -333,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--)
@@ -348,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--)
@@ -384,5 +404,3 @@ fn usz List.compact(List* list)
}
return size - list.size;
}
$endif

View File

@@ -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

View File

@@ -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<String, Object*>;
def ObjectInternalList @private = List<Object*>;
def ObjectInternalMapEntry @private = Entry<String, Object*>;
def ObjectInternalMap = HashMap<String, Object*> @private;
def ObjectInternalList = List<Object*> @private;
def ObjectInternalMapEntry = Entry<String, Object*> @private;

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -135,15 +135,16 @@ macro bool! Formatter.print_with_function(Formatter* this, any arg)
this.width = old_width;
this.prec = old_prec;
}
@pool()
@stack_mem(512; Allocator* mem)
{
this.out_substr(arg.to_string(mem::temp()))!;
this.out_substr(arg.to_string(mem))!;
return true;
};
}
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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
$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
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -50,18 +50,18 @@ fn void! InetAddress.to_format(InetAddress* addr, Formatter* formatter) @dynamic
formatter.printf("%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!;
}
fn String! InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap()) @dynamic
fn String InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap()) @dynamic
{
if (addr.is_ipv6)
{
char[8 * 5 + 1] buffer;
String res = (String)io::bprintf(&buffer, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
addr.ipv6.a, addr.ipv6.b, addr.ipv6.c, addr.ipv6.d,
addr.ipv6.e, addr.ipv6.f, addr.ipv6.g, addr.ipv6.h)!;
addr.ipv6.e, addr.ipv6.f, addr.ipv6.g, addr.ipv6.h)!!;
return res.copy(using);
}
char[3 * 4 + 3 + 1] buffer;
String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!;
String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!!;
return res.copy(using);
}

View File

@@ -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

View File

@@ -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
const int PLATFORM_O_NONBLOCK = 0x30;

View File

@@ -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
const PLATFORM_O_NONBLOCK = 0o4000;

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
const WSAError ESOCKTNOSUPPORT = 10044;

View File

@@ -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
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;

View File

@@ -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

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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()

View File

@@ -114,6 +114,10 @@ static void usage(void)
OUTPUT(" --emit-llvm - Emit LLVM IR as a .ll file per module.");
OUTPUT(" --asm-out <dir> - Override asm output directory for '--emit-asm'.");
OUTPUT(" --emit-asm - Emit asm as a .s file per module.");
OUTPUT(" --obj - Emit object files. (Enabled by default)");
OUTPUT(" --no-obj - Do not output object files, this is only valid for `compile-only`.");
OUTPUT(" --emit-stdlib - Output files for the standard library. (Enabled by default)");
OUTPUT(" --no-emit-stdlib - Do not output object files (nor asm or ir) for the standard library.");
OUTPUT(" --target <target> - Compile for a particular architecture + OS target.");
OUTPUT(" --threads <number> - Set the number of threads to use for compilation.");
OUTPUT(" --safe - Set mode to 'safe', generating runtime traps on overflows and contract violations.");
@@ -134,7 +138,8 @@ static void usage(void)
OUTPUT(" --x86vec=<option> - Set max type of vector use: none, mmx, sse, avx, avx512, native.");
OUTPUT(" --riscvfloat=<option> - Set type of RISC-V float support: none, float, double");
OUTPUT(" --memory-env=<option> - Set the memory environment: normal, small, tiny, none.");
OUTPUT(" --strip-unused - Strip unused code and globals from the output (experimental)");
OUTPUT(" --strip-unused - Strip unused code and globals from the output. (Enabled by default)");
OUTPUT(" --no-strip-unused - Do not strip unused code and globals from the output.");
OUTPUT("");
OUTPUT(" --debug-stats - Print debug statistics.");
#ifndef NDEBUG
@@ -549,9 +554,14 @@ static void parse_option(BuildOptions *options)
print_version();
exit_compiler(COMPILER_SUCCESS_EXIT);
}
if (match_longopt("no-strip-unused"))
{
options->no_strip_unused = true;
return;
}
if (match_longopt("strip-unused"))
{
options->strip_unused = true;
options->no_strip_unused = false;
return;
}
if ((argopt = match_argopt("x86vec")))
@@ -585,6 +595,26 @@ static void parse_option(BuildOptions *options)
OUTPUT("C3 is low level programming language based on C.");
exit_compiler(COMPILER_SUCCESS_EXIT);
}
if (match_longopt("no-obj"))
{
options->no_obj = true;
return;
}
if (match_longopt("obj"))
{
options->no_obj = false;
return;
}
if (match_longopt("no-emit-stdlib"))
{
options->no_emit_stdlib = true;
return;
}
if (match_longopt("emit-stdlib"))
{
options->no_emit_stdlib = false;
return;
}
if (match_longopt("debug-log"))
{
debug_log = true;
@@ -871,7 +901,6 @@ BuildOptions parse_arguments(int argc, const char *argv[])
BuildOptions build_options = {
.path = ".",
.emit_llvm = false,
.emit_bitcode = true,
.optimization_setting_override = OPT_SETTING_NOT_SET,
.debug_info_override = DEBUG_INFO_NOT_SET,
.safe_mode = -1,

View File

@@ -321,11 +321,12 @@ typedef struct BuildOptions_
int safe_mode;
bool emit_llvm;
bool emit_asm;
bool emit_bitcode;
bool test_mode;
bool no_stdlib;
bool no_entry;
bool no_libc;
bool no_obj;
bool no_emit_stdlib;
bool force_linker;
bool read_stdin;
bool print_output;
@@ -340,7 +341,7 @@ typedef struct BuildOptions_
X86CpuSet x86_cpu_set;
RiscvFloatCapability riscv_float_capability;
MemoryEnvironment memory_environment;
bool strip_unused;
bool no_strip_unused;
bool print_keywords;
bool print_attributes;
bool print_builtins;
@@ -414,7 +415,7 @@ typedef struct
bool emit_asm;
bool no_stdlib;
bool no_libc;
bool strip_unused;
bool no_strip_unused;
bool emit_object_files;
bool force_linker;
bool benchmarking;
@@ -422,6 +423,7 @@ typedef struct
bool read_stdin;
bool print_output;
bool no_entry;
bool no_emit_stdlib;
int build_threads;
OptimizationLevel optimization_level;
MemoryEnvironment memory_environment;

View File

@@ -199,7 +199,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
{
target->feature.safe_mode = options->safe_mode == 1;
}
if (options->strip_unused) target->strip_unused = true;
if (options->no_strip_unused || options->test_mode) target->no_strip_unused = true;
if (options->memory_environment != MEMORY_ENV_NOT_SET)
{
@@ -302,6 +302,11 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
target->emit_asm = false;
target->emit_object_files = false;
}
if (options->no_obj)
{
target->emit_object_files = false;
}
target->no_emit_stdlib = options->no_emit_stdlib;
for (int i = 0; i < options->lib_dir_count; i++)
{
vec_add(target->libdirs, options->lib_dir[i]);

View File

@@ -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;

View File

@@ -484,21 +484,29 @@ void compiler_compile(void)
printf("Program finished with exit code %d.\n", ret);
}
}
if (output_static)
else if (output_static)
{
if (!static_lib_linker(output_static, obj_files, output_file_count))
{
error_exit("Failed to produce static library '%s'.", output_static);
}
compiler_link_time = bench_mark();
compiler_print_bench();
printf("Static library '%s' created.", output_static);
}
if (output_dynamic)
else if (output_dynamic)
{
if (!dynamic_lib_linker(output_dynamic, obj_files, output_file_count))
{
error_exit("Failed to produce static library '%s'.", output_dynamic);
}
printf("Dynamic library '%s' created.", output_dynamic);
compiler_link_time = bench_mark();
compiler_print_bench();
}
else
{
compiler_print_bench();
}
free(obj_files);
}

View File

@@ -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;

View File

@@ -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:

View File

@@ -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:

View File

@@ -126,6 +126,7 @@ typedef enum
typedef enum
{
DECL_POISONED = 0,
DECL_ERASED,
DECL_ATTRIBUTE,
DECL_BITSTRUCT,
DECL_CT_CASE,
@@ -734,8 +735,8 @@ typedef enum
ATTR_STRUCT = 1 << 4,
ATTR_UNION = 1 << 5,
ATTR_CONST = 1 << 6,
ATTR_ERROR = 1 << 7,
ATTR_TYPEDEF = 1 << 8,
ATTR_FAULT = 1 << 7,
ATTR_DEF = 1 << 8,
ATTR_MEMBER = 1 << 9,
ATTR_INTERFACE = 1 << 10,
ATTR_CALL = 1 << 11,
@@ -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,

View File

@@ -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;

View File

@@ -286,7 +286,7 @@ static void linker_setup_macos(const char ***args_ref, LinkerType linker_type)
}
add_arg("-arch");
add_arg(arch_to_linker_arch(platform_target.arch));
if (active_target.strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
if (!active_target.no_strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
{
add_arg("-no_exported_symbols");
add_arg("-dead_strip");
@@ -398,9 +398,9 @@ static void linker_setup_linux(const char ***args_ref, LinkerType linker_type)
const char *crt_begin_dir = find_linux_crt_begin();
const char *crt_dir = find_linux_crt();
if (active_target.strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
if (!active_target.no_strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
{
add_arg("-dead_strip");
add_arg("--gc-sections");
}
if (!crt_begin_dir || !crt_dir)
@@ -448,9 +448,9 @@ static void linker_setup_freebsd(const char ***args_ref, LinkerType linker_type)
{
error_exit("Failed to find the C runtime at link time.");
}
if (active_target.strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
if (!active_target.no_strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
{
add_arg("-dead_strip");
add_arg("--gc-sections");
}
if (is_pie_pic(platform_target.reloc_model))

View File

@@ -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)
{
@@ -1265,9 +1268,21 @@ LLVMMetadataRef llvm_get_debug_file(GenContext *c, FileId file_id)
return file;
}
static bool module_is_stdlib(Module *module)
{
if (module->name->len < 3) return false;
if (module->name->len == 3 && strcmp(module->name->module, "std") == 0) return true;
if (module->name->len > 5 && memcmp(module->name->module, "std::", 5) == 0) return true;
if (module->name->len == 4 && strcmp(module->name->module, "libc") == 0) return true;
if (module->name->len > 6 && memcmp(module->name->module, "libc::", 6) == 0) return true;
return false;
}
static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context)
{
if (!vec_size(module->units)) return NULL;
if (active_target.no_emit_stdlib && module_is_stdlib(module)) return NULL;
assert(intrinsics_setup);
bool has_elements = false;
@@ -1275,7 +1290,7 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
gencontext_init(gen_context, module, shared_context);
gencontext_begin_module(gen_context);
bool only_used = active_target.strip_unused && !active_target.testing;
bool only_used = !active_target.no_strip_unused;
FOREACH_BEGIN(CompilationUnit *unit, module->units)
@@ -1296,10 +1311,12 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
FOREACH_END();
FOREACH_BEGIN(Decl *type_decl, unit->types)
if (only_used && !type_decl->is_live) continue;
llvm_emit_type_decls(gen_context, type_decl);
FOREACH_END();
FOREACH_BEGIN(Decl *enum_decl, unit->enums)
if (only_used && !enum_decl->is_live) continue;
llvm_emit_type_decls(gen_context, enum_decl);
FOREACH_END();
@@ -1384,8 +1401,6 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
llvm_emit_constructors_and_destructors(gen_context);
// EmitDeferred()
if (llvm_use_debug(gen_context))
{
LLVMDIBuilderFinalize(gen_context->debug.builder);

View File

@@ -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:

View File

@@ -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)

View File

@@ -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))
{

View File

@@ -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, &param->attributes, NULL)) return false;
if (!parse_attributes(c, &param->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;

View File

@@ -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
{

View File

@@ -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);

View File

@@ -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)
@@ -429,14 +468,14 @@ static bool sema_analyse_struct_union(SemaContext *context, Decl *decl)
domain = ATTR_UNION;
break;
case DECL_FAULT:
domain = ATTR_ERROR;
domain = ATTR_FAULT;
break;
default:
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, &param->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);
@@ -1457,10 +1522,10 @@ static const char *attribute_domain_to_string(AttributeDomain domain)
return "union";
case ATTR_CONST:
return "constant";
case ATTR_ERROR:
return "error type";
case ATTR_TYPEDEF:
return "typedef";
case ATTR_FAULT:
return "fault";
case ATTR_DEF:
return "def";
case ATTR_CALL:
return "call";
case ATTR_INITIALIZER:
@@ -1475,25 +1540,25 @@ static const char *attribute_domain_to_string(AttributeDomain domain)
UNREACHABLE
}
#define EXPORTED_USER_DEFINED_TYPES ATTR_ENUM | ATTR_UNION | ATTR_STRUCT
#define EXPORTED_USER_DEFINED_TYPES ATTR_ENUM | ATTR_UNION | ATTR_STRUCT | ATTR_FAULT
#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_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,
[ATTRIBUTE_EXTNAME] = (AttributeDomain)~(ATTR_CALL | ATTR_BITSTRUCT | ATTR_DEFINE | ATTR_MACRO | ATTR_XXLIZER),
[ATTRIBUTE_EXTERN] = (AttributeDomain)~(ATTR_CALL | ATTR_BITSTRUCT | ATTR_DEFINE | ATTR_MACRO | ATTR_XXLIZER),
[ATTRIBUTE_EXTNAME] = (AttributeDomain)~(ATTR_CALL | ATTR_BITSTRUCT | ATTR_DEFINE | ATTR_MACRO | ATTR_XXLIZER),
[ATTRIBUTE_IF] = (AttributeDomain)~(ATTR_CALL | ATTR_LOCAL),
[ATTRIBUTE_INLINE] = ATTR_FUNC | ATTR_CALL,
[ATTRIBUTE_INTERFACE] = ATTR_FUNC,
[ATTRIBUTE_LITTLEENDIAN] = ATTR_BITSTRUCT,
[ATTRIBUTE_LOCAL] = ATTR_FUNC | ATTR_MACRO | ATTR_GLOBAL | ATTR_CONST | USER_DEFINED_TYPES | ATTR_DEFINE,
[ATTRIBUTE_MAYDISCARD] = ATTR_FUNC | ATTR_MACRO,
@@ -1502,7 +1567,8 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
[ATTRIBUTE_NOINIT] = ATTR_GLOBAL | ATTR_LOCAL,
[ATTRIBUTE_NOINLINE] = ATTR_FUNC | ATTR_CALL,
[ATTRIBUTE_NORETURN] = ATTR_FUNC | ATTR_MACRO,
[ATTRIBUTE_OBFUSCATE] = ATTR_ENUM,
[ATTRIBUTE_NOSTRIP] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES,
[ATTRIBUTE_OBFUSCATE] = ATTR_ENUM | ATTR_FAULT,
[ATTRIBUTE_OPERATOR] = ATTR_MACRO | ATTR_FUNC,
[ATTRIBUTE_OVERLAP] = ATTR_BITSTRUCT,
[ATTRIBUTE_PACKED] = ATTR_STRUCT | ATTR_UNION,
@@ -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)
{
@@ -2332,6 +2422,7 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
return false;
}
global_context.test_func = decl;
if (active_target.testing) decl->no_strip = true;
}
bool is_test = decl->func_decl.attr_test;
Signature *sig = &decl->func_decl.signature;
@@ -2486,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)
@@ -2546,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)
@@ -2561,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;
}
@@ -2692,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)
{
@@ -2851,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;
@@ -3102,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);
@@ -3110,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)
@@ -3172,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)
@@ -3206,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:
@@ -3270,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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -178,12 +178,14 @@ static void sema_trace_stmt_liveness(Ast *ast)
static void sema_trace_const_initializer_liveness(ConstInitializer *const_init)
{
RETRY:
switch (const_init->kind)
{
case CONST_INIT_ZERO:
return;
case CONST_INIT_ARRAY_VALUE:
UNREACHABLE
const_init = const_init->init_array_value.element;
goto RETRY;
case CONST_INIT_ARRAY_FULL:
{
bool was_modified = false;
@@ -204,8 +206,8 @@ static void sema_trace_const_initializer_liveness(ConstInitializer *const_init)
return;
}
case CONST_INIT_UNION:
sema_trace_const_initializer_liveness(const_init->init_union.element);
return;
const_init = const_init->init_union.element;
goto RETRY;
case CONST_INIT_STRUCT:
{
Decl *decl = const_init->type->decl;
@@ -353,8 +355,16 @@ RETRY:
sema_trace_expr_list_liveness(expr->designated_init_list);
return;
case EXPR_EXPR_BLOCK:
sema_trace_stmt_liveness(astptr(expr->expr_block.first_stmt));
{
AstId current = expr->expr_block.first_stmt;
if (!current) return;
do
{
Ast *value = ast_next(&current);
sema_trace_stmt_liveness(value);
} while (current);
return;
}
case EXPR_IDENTIFIER:
sema_trace_decl_liveness(expr->identifier_expr.decl);
return;
@@ -452,10 +462,15 @@ void sema_trace_liveness(void)
{
sema_trace_decl_liveness(global_context.main);
}
bool keep_tests = active_target.testing;
FOREACH_BEGIN(Decl *function, global_context.method_extensions)
if (function->func_decl.attr_dynamic) function->no_strip = true;
if (function->is_export || function->no_strip) sema_trace_decl_liveness(function);
FOREACH_END();
FOREACH_BEGIN(Module *module, global_context.module_list)
FOREACH_BEGIN(CompilationUnit *unit, module->units)
FOREACH_BEGIN(Decl *function, unit->functions)
if (function->is_export || function->no_strip) sema_trace_decl_liveness(function);
if (function->is_export || function->no_strip || (function->func_decl.attr_test && keep_tests)) sema_trace_decl_liveness(function);
FOREACH_END();
FOREACH_BEGIN(Decl *method, unit->methods)
if (method->is_export || method->no_strip) sema_trace_decl_liveness(method);
@@ -463,26 +478,69 @@ void sema_trace_liveness(void)
FOREACH_BEGIN(Decl *var, unit->vars)
if (var->is_export || var->no_strip) sema_trace_decl_liveness(var);
FOREACH_END();
FOREACH_BEGIN(Decl *method, unit->local_method_extensions)
if (method->is_export || method->no_strip) sema_trace_decl_liveness(method);
FOREACH_END();
FOREACH_BEGIN(Decl *xxlizer, unit->xxlizers)
sema_trace_decl_liveness(xxlizer);
FOREACH_END();
FOREACH_END();
FOREACH_END();
}
INLINE void sema_trace_type_liveness(Type *type)
{
if (!type || !type_is_user_defined(type)) return;
sema_trace_decl_liveness(type->decl);
}
INLINE void sema_trace_decl_dynamic_methods(Decl *decl)
{
Decl **methods = decl->methods;
unsigned method_count = vec_size(methods);
if (!method_count) return;
for (unsigned i = 0; i < method_count; i++)
{
Decl *method = methods[i];
if (!method->func_decl.attr_dynamic) continue;
sema_trace_decl_liveness(method);
}
}
static void sema_trace_decl_liveness(Decl *decl)
{
RETRY:
if (!decl || decl->is_live) return;
decl->is_live = true;
switch (decl->decl_kind)
{
case DECL_POISONED:
case DECL_ATTRIBUTE:
case DECL_BITSTRUCT:
case DECL_ERASED:
return;
case DECL_TYPEDEF:
if (!decl->typedef_decl.is_func)
{
sema_trace_type_liveness(decl->typedef_decl.type_info->type);
return;
}
FOREACH_BEGIN(Decl *param, decl->typedef_decl.function_signature.params)
sema_trace_decl_liveness(param);
FOREACH_END();
sema_trace_type_liveness(typeinfotype(decl->typedef_decl.function_signature.rtype));
return;
case DECL_DEFINE:
decl = decl->define_decl.alias;
goto RETRY;
case DECL_DISTINCT:
case DECL_ENUM:
case DECL_ENUM_CONSTANT:
case DECL_BITSTRUCT:
case DECL_FAULT:
case DECL_STRUCT:
case DECL_UNION:
sema_trace_decl_dynamic_methods(decl);
return;
case DECL_POISONED:
case DECL_ATTRIBUTE:
case DECL_ENUM_CONSTANT:
case DECL_FAULTVALUE:
return;
case DECL_CT_CASE:
@@ -508,20 +566,27 @@ static void sema_trace_decl_liveness(Decl *decl)
{
case VARDECL_REWRAPPED:
case VARDECL_UNWRAPPED:
return;
break;
case VARDECL_PARAM_EXPR:
case VARDECL_PARAM_CT:
case VARDECL_PARAM_REF:
case VARDECL_PARAM:
sema_trace_type_liveness(decl->type);
if (decl->var.init_expr && decl->var.init_expr->resolve_status == RESOLVE_DONE)
{
sema_trace_expr_liveness(decl->var.init_expr);
}
break;
default:
sema_trace_type_liveness(decl->type);
sema_trace_expr_liveness(decl->var.init_expr);
break;
}
sema_trace_expr_liveness(decl->var.init_expr);
return;
case DECL_INITIALIZE:
case DECL_FINALIZE:
sema_trace_stmt_liveness(astptrzero(decl->xxlizer.init));
return;
case DECL_STRUCT:
case DECL_TYPEDEF:
case DECL_UNION:
return;
case DECL_DECLARRAY:
UNREACHABLE
}

View File

@@ -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);
}

View File

@@ -2927,6 +2927,49 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func)
func->name);
return false;
}
Signature any_sig = any->func_decl.signature;
Signature this_sig = func->func_decl.signature;
Type *any_rtype = typeinfotype(any_sig.rtype);
Type *this_rtype = typeinfotype(this_sig.rtype);
if (any_rtype->canonical != this_rtype->canonical)
{
SEMA_ERROR(type_infoptr(this_sig.rtype), "The prototype method has a return type %s, but this function returns %s, they need to match.",
type_quoted_error_string(any_rtype), type_quoted_error_string(this_rtype));
SEMA_NOTE(type_infoptr(any_sig.rtype), "The interface definition is here.");
return false;
}
Decl **any_params = any_sig.params;
Decl **this_params = this_sig.params;
unsigned any_param_count = vec_size(any_params);
unsigned this_param_count = vec_size(this_params);
if (any_param_count != this_param_count)
{
if (any_param_count > this_param_count)
{
SEMA_ERROR(func, "This function is missing parameters, %d parameters were expected.", any_param_count);
SEMA_NOTE(any_params[this_param_count], "Compare with the interface definition.");
return false;
}
else
{
SEMA_ERROR(this_params[any_param_count], "This function has too many parameters (%d).", this_param_count);
SEMA_NOTE(any, "Compare with the interface, which has only %d parameter%s.",
any_param_count, any_param_count == 1 ? "" : "s");
}
return false;
}
FOREACH_BEGIN_IDX(i, Decl *param, this_params)
if (i == 0) continue;
if (param->type->canonical != any_params[i]->type->canonical)
{
SEMA_ERROR(param->var.type_info, "The prototype argument has type %s, but in this function it has type %s. Please make them match.",
type_quoted_error_string(any_params[i]->type), type_quoted_error_string(param->type));
SEMA_NOTE(any_params[i]->var.type_info, "The interface definition is here.");
return false;
}
FOREACH_END();
func->func_decl.any_prototype = declid(any);
}
Signature *signature = &func->func_decl.signature;

View File

@@ -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:

View File

@@ -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);
}
@@ -373,12 +381,13 @@ RESOLVE_LAMBDA:;
if (found_lambda) goto RESOLVE_LAMBDA;
halt_on_error();
if (active_target.strip_unused && !active_target.testing)
assign_panicfn();
if (!active_target.no_strip_unused)
{
sema_trace_liveness();
}
assign_panicfn();
compiler_sema_time = bench_mark();

View File

@@ -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");

View File

@@ -25,6 +25,15 @@ static void cleanup()
int main_real(int argc, const char *argv[])
{
printf("------------------------------------------------------------\n"
" PLEASE NOTE, this version of the compiler has enabled dead\n"
" code stripping by default. This functionality has not been\n"
" completely audited, so if you run into any linking error, \n"
" please use --no-strip-unused to disable the feature. \n"
" If possible, file an error here: \n"
" https://github.com/c3lang/c3c/issues\n"
" Thank you!\n"
"------------------------------------------------------------\n");
bench_begin();
// Setjmp will allow us to add things like fuzzing with

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