mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Compare commits
8 Commits
0.4stripun
...
v0.4.x
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75a6ae7111 | ||
|
|
cf83651c79 | ||
|
|
4c1edfb941 | ||
|
|
82c3facb65 | ||
|
|
266dba466c | ||
|
|
379a5f670f | ||
|
|
8eaad81800 | ||
|
|
4baacc7d52 |
18
.github/workflows/main.yml
vendored
18
.github/workflows/main.yml
vendored
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -360,11 +360,16 @@ bool parse_module(ParseContext *c, AstId contracts)
|
||||
}
|
||||
Visibility visibility = VISIBLE_PUBLIC;
|
||||
Attr** attrs = NULL;
|
||||
if (!parse_attributes(c, &attrs, &visibility)) return false;
|
||||
bool is_cond;
|
||||
if (!parse_attributes(c, &attrs, &visibility, &is_cond)) return false;
|
||||
FOREACH_BEGIN(Attr *attr, attrs)
|
||||
if (attr->is_custom) RETURN_SEMA_ERROR(attr, "Custom attributes cannot be used with 'module'.");
|
||||
switch (attr->attr_kind)
|
||||
{
|
||||
case ATTRIBUTE_IF:
|
||||
if (c->unit->if_attr) RETURN_SEMA_ERROR(attr, "'@if' appeared more than once.");
|
||||
c->unit->if_attr = attr;
|
||||
continue;
|
||||
case ATTRIBUTE_TEST:
|
||||
c->unit->test_by_default = true;
|
||||
continue;
|
||||
@@ -791,7 +796,7 @@ Decl *parse_local_decl_after_type(ParseContext *c, TypeInfo *type)
|
||||
Decl *decl = decl_new_var_current(c, type, VARDECL_LOCAL);
|
||||
advance(c);
|
||||
|
||||
if (!parse_attributes(c, &decl->attributes, NULL)) return poisoned_decl;
|
||||
if (!parse_attributes(c, &decl->attributes, NULL, NULL)) return poisoned_decl;
|
||||
if (tok_is(c, TOKEN_EQ))
|
||||
{
|
||||
if (!decl)
|
||||
@@ -855,7 +860,7 @@ Decl *parse_const_declaration(ParseContext *c, bool is_global)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!parse_attributes(c, &decl->attributes, NULL)) return poisoned_decl;
|
||||
if (!parse_attributes(c, &decl->attributes, NULL, NULL)) return poisoned_decl;
|
||||
}
|
||||
|
||||
// Required initializer
|
||||
@@ -1024,7 +1029,9 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl)
|
||||
Visibility visibility = c->unit->default_visibility;
|
||||
if (decl->decl_kind == DECL_FUNC) decl->func_decl.attr_test = c->unit->test_by_default;
|
||||
decl->is_export = c->unit->export_by_default;
|
||||
if (!parse_attributes(c, &decl->attributes, &visibility)) return false;
|
||||
bool is_cond;
|
||||
if (!parse_attributes(c, &decl->attributes, &visibility, &is_cond)) return false;
|
||||
decl->is_cond = is_cond;
|
||||
decl->visibility = visibility;
|
||||
return true;
|
||||
}
|
||||
@@ -1036,9 +1043,10 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl)
|
||||
*
|
||||
* @return true if parsing succeeded, false if recovery is needed
|
||||
*/
|
||||
bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref)
|
||||
bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *cond_ref)
|
||||
{
|
||||
Visibility visibility = -1;
|
||||
if (cond_ref) *cond_ref = false;
|
||||
while (1)
|
||||
{
|
||||
Attr *attr;
|
||||
@@ -1061,12 +1069,16 @@ bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visib
|
||||
case ATTRIBUTE_LOCAL:
|
||||
parsed_visibility = VISIBLE_LOCAL;
|
||||
break;
|
||||
case ATTRIBUTE_IF:
|
||||
if (!cond_ref) RETURN_SEMA_ERROR(attr, "'%s' cannot be used here.", attr->name);
|
||||
*cond_ref = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (parsed_visibility != -1)
|
||||
{
|
||||
if (!visibility_ref) RETURN_SEMA_ERROR(attr, "'%s' cannot be used here.");
|
||||
if (!visibility_ref) RETURN_SEMA_ERROR(attr, "'%s' cannot be used here.", attr->name);
|
||||
if (visibility != -1) RETURN_SEMA_ERROR(attr, "Only a single visibility attribute may be added.");
|
||||
*visibility_ref = visibility = parsed_visibility;
|
||||
continue;
|
||||
@@ -1407,7 +1419,7 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Decl **body_params,
|
||||
}
|
||||
Decl *param = decl_new_var(name, span, type, param_kind);
|
||||
param->var.type_info = type;
|
||||
if (!parse_attributes(c, ¶m->attributes, NULL)) return false;
|
||||
if (!parse_attributes(c, ¶m->attributes, NULL, NULL)) return false;
|
||||
if (!no_name)
|
||||
{
|
||||
if (try_consume(c, TOKEN_EQ))
|
||||
@@ -1499,7 +1511,9 @@ bool parse_struct_body(ParseContext *c, Decl *parent)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!parse_attributes(c, &member->attributes, NULL)) return false;
|
||||
bool is_cond;
|
||||
if (!parse_attributes(c, &member->attributes, NULL, &is_cond)) return false;
|
||||
member->is_cond = true;
|
||||
if (!parse_struct_body(c, member)) return decl_poison(parent);
|
||||
}
|
||||
vec_add(parent->strukt.members, member);
|
||||
@@ -1539,7 +1553,9 @@ bool parse_struct_body(ParseContext *c, Decl *parent)
|
||||
RETURN_SEMA_ERROR(member, "Can't add another member: the count would exceed maximum of %d elements.", MAX_MEMBERS);
|
||||
}
|
||||
advance(c);
|
||||
if (!parse_attributes(c, &member->attributes, NULL)) return false;
|
||||
bool is_cond;
|
||||
if (!parse_attributes(c, &member->attributes, NULL, &is_cond)) return false;
|
||||
member->is_cond = true;
|
||||
if (!try_consume(c, TOKEN_COMMA)) break;
|
||||
if (was_inline)
|
||||
{
|
||||
@@ -1770,8 +1786,6 @@ static inline Decl *parse_typedef_declaration(ParseContext *c)
|
||||
return poisoned_decl;
|
||||
}
|
||||
|
||||
if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
|
||||
|
||||
CONSUME_OR_RET(TOKEN_EQ, poisoned_decl);
|
||||
bool distinct = false;
|
||||
bool is_inline = false;
|
||||
@@ -1800,6 +1814,8 @@ static inline Decl *parse_typedef_declaration(ParseContext *c)
|
||||
{
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
|
||||
|
||||
RANGE_EXTEND_PREV(decl);
|
||||
CONSUME_EOS_OR_RET(poisoned_decl);
|
||||
return decl;
|
||||
@@ -1818,6 +1834,8 @@ static inline Decl *parse_typedef_declaration(ParseContext *c)
|
||||
decl->define_decl.define_kind = DEFINE_TYPE_GENERIC;
|
||||
decl->define_decl.type_info = type_info;
|
||||
decl->define_decl.generic_params = params;
|
||||
if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
|
||||
|
||||
RANGE_EXTEND_PREV(decl);
|
||||
CONSUME_EOS_OR_RET(poisoned_decl);
|
||||
return decl;
|
||||
@@ -1840,6 +1858,8 @@ static inline Decl *parse_typedef_declaration(ParseContext *c)
|
||||
decl->decl_kind = DECL_TYPEDEF;
|
||||
decl_add_type(decl, TYPE_TYPEDEF);
|
||||
}
|
||||
if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
|
||||
|
||||
RANGE_EXTEND_PREV(decl);
|
||||
CONSUME_EOS_OR_RET(poisoned_decl);
|
||||
return decl;
|
||||
@@ -1941,6 +1961,8 @@ static inline Decl *parse_define_ident(ParseContext *c)
|
||||
if (!params) return poisoned_decl;
|
||||
decl->define_decl.generic_params = params;
|
||||
}
|
||||
if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
|
||||
|
||||
RANGE_EXTEND_PREV(decl);
|
||||
CONSUME_EOS_OR_RET(poisoned_decl);
|
||||
return decl;
|
||||
@@ -1969,15 +1991,17 @@ static inline Decl *parse_define_attribute(ParseContext *c)
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_decl);
|
||||
}
|
||||
|
||||
if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
|
||||
Attr **attributes = NULL;
|
||||
|
||||
CONSUME_OR_RET(TOKEN_EQ, poisoned_decl);
|
||||
CONSUME_OR_RET(TOKEN_LBRACE, poisoned_decl);
|
||||
|
||||
if (!parse_attributes(c, &attributes, NULL)) return poisoned_decl;
|
||||
bool is_cond;
|
||||
if (!parse_attributes(c, &attributes, NULL, &is_cond)) return poisoned_decl;
|
||||
CONSUME_OR_RET(TOKEN_RBRACE, poisoned_decl);
|
||||
decl->attr_decl.attrs = attributes;
|
||||
decl->is_cond = is_cond;
|
||||
if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
|
||||
CONSUME_EOS_OR_RET(poisoned_decl);
|
||||
return decl;
|
||||
}
|
||||
@@ -2367,7 +2391,9 @@ static inline Decl *parse_static_top_level(ParseContext *c)
|
||||
}
|
||||
advance(c);
|
||||
Attr *attr = NULL;
|
||||
if (!parse_attributes(c, &init->attributes, NULL)) return poisoned_decl;
|
||||
bool is_cond;
|
||||
if (!parse_attributes(c, &init->attributes, NULL, &is_cond)) return poisoned_decl;
|
||||
init->is_cond = is_cond;
|
||||
ASSIGN_ASTID_OR_RET(init->xxlizer.init, parse_compound_stmt(c), poisoned_decl);
|
||||
RANGE_EXTEND_PREV(init);
|
||||
return init;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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, ¶m->alignment);
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_enum(SemaContext *context, Decl *decl)
|
||||
static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *erase_decl)
|
||||
{
|
||||
if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_ENUM, erase_decl)) return decl_poison(decl);
|
||||
if (*erase_decl) return true;
|
||||
|
||||
// Resolve the type of the enum.
|
||||
if (!sema_resolve_type_info(context, decl->enums.type_info)) return false;
|
||||
|
||||
@@ -1025,7 +1070,6 @@ static inline bool sema_analyse_enum(SemaContext *context, Decl *decl)
|
||||
|
||||
DEBUG_LOG("* Enum type resolved to %s.", type->name);
|
||||
|
||||
if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_ENUM)) return decl_poison(decl);
|
||||
|
||||
Decl **associated_values = decl->enums.parameters;
|
||||
unsigned associated_value_count = vec_size(associated_values);
|
||||
@@ -1335,6 +1379,27 @@ INLINE void sema_set_method_ext_name(CompilationUnit *unit, const char *parent_n
|
||||
}
|
||||
method_like->extname = scratch_buffer_copy();
|
||||
}
|
||||
|
||||
bool sema_decl_if_cond(SemaContext *context, Decl *decl)
|
||||
{
|
||||
FOREACH_BEGIN(Attr *attr, decl->attributes)
|
||||
if (attr->attr_kind != ATTRIBUTE_IF) continue;
|
||||
if (vec_size(attr->exprs) != 1)
|
||||
{
|
||||
RETURN_SEMA_ERROR(attr, "Expected an argument to '@if'.");
|
||||
}
|
||||
Expr *expr = attr->exprs[0];
|
||||
if (!sema_analyse_ct_expr(context, expr)) return false;
|
||||
if (expr->type->canonical != type_bool)
|
||||
{
|
||||
RETURN_SEMA_ERROR(expr, "Expected a boolean value not %s.", type_quoted_error_string(expr->type));
|
||||
}
|
||||
if (expr->const_expr.b) return true;
|
||||
decl->decl_kind = DECL_ERASED;
|
||||
return false;
|
||||
FOREACH_END();
|
||||
UNREACHABLE
|
||||
}
|
||||
static inline bool unit_add_base_extension_method(CompilationUnit *unit, Type *parent_type, Decl *method_like)
|
||||
{
|
||||
sema_set_method_ext_name(unit, parent_type->name, method_like);
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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(¤t);
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user