mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Remove tscoped. Replace str_index_of with "starts_with". Updated copy_zstring/copy. Fixed utf conversion functions. Initial work on "Path". Lexer fix on \\. ABI fix using distinct types. (bool)"" now works correctly. Bug in $if with switches/loops as the first statement fixed. Version bump.
This commit is contained in:
committed by
Christoffer Lerno
parent
7d58ce0dcb
commit
f86ef8a743
@@ -88,7 +88,6 @@ private fn void*! temp_allocator_function(Allocator* data, usz size, usz alignme
|
||||
|
||||
private fn void! TempAllocator._free(TempAllocator* this, void* old_pointer)
|
||||
{
|
||||
|
||||
// TODO fix free
|
||||
assert((uptr)old_pointer >= (uptr)&this.data, "Pointer originates from a different allocator.");
|
||||
usz old_size = *(usz*)(old_pointer - DEFAULT_SIZE_PREFIX);
|
||||
|
||||
@@ -206,16 +206,6 @@ macro void @scoped(Allocator* allocator; @body())
|
||||
@body();
|
||||
}
|
||||
|
||||
macro void @tscoped(;@body())
|
||||
{
|
||||
Allocator* old_allocator = thread_allocator;
|
||||
TempAllocator* temp = temp_allocator();
|
||||
usz mark = temp.mark()!!;
|
||||
thread_allocator = temp;
|
||||
defer temp.reset(mark);
|
||||
defer thread_allocator = old_allocator;
|
||||
@body();
|
||||
}
|
||||
|
||||
macro talloc($Type) @builtin
|
||||
{
|
||||
|
||||
@@ -29,7 +29,17 @@ fn String join(char[][] s, char[] joiner)
|
||||
return res;
|
||||
}
|
||||
|
||||
fn usz! str_index_of(char[] s, char[] needle)
|
||||
fn bool starts_with(char[] s, char[] needle)
|
||||
{
|
||||
if (needle.len > s.len) return false;
|
||||
foreach (i, c : needle)
|
||||
{
|
||||
if (c != s[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn usz! index_of(char[] s, char[] needle)
|
||||
{
|
||||
usz match = 0;
|
||||
usz needed = needle.len;
|
||||
@@ -55,10 +65,10 @@ fn usz! str_index_of(char[] s, char[] needle)
|
||||
return SearchResult.MISSING!;
|
||||
}
|
||||
|
||||
fn ZString copy_zstring(char[] s)
|
||||
fn ZString copy_zstring(char[] s, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
usz len = s.len;
|
||||
char* str = malloc(len + 1);
|
||||
char* str = allocator.alloc(len + 1)!!;
|
||||
mem::copy(str, s.ptr, len);
|
||||
str[len] = 0;
|
||||
return (ZString)str;
|
||||
@@ -66,11 +76,7 @@ fn ZString copy_zstring(char[] s)
|
||||
|
||||
fn ZString tcopy_zstring(char[] s)
|
||||
{
|
||||
usz len = s.len;
|
||||
char* str = tmalloc(len + 1);
|
||||
mem::copy(str, s.ptr, len);
|
||||
str[len] = 0;
|
||||
return (ZString)str;
|
||||
return copy_zstring(s, mem::temp_allocator());
|
||||
}
|
||||
|
||||
fn bool compare(char[] a, char[] b)
|
||||
@@ -89,8 +95,6 @@ fault UnicodeResult
|
||||
CONVERSION_FAILED,
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn usz utf8_codepoints(char[] utf8)
|
||||
{
|
||||
usz len = 0;
|
||||
@@ -107,7 +111,7 @@ fn Char32[]! utf8to32(char[] utf8, Allocator* allocator = mem::current_allocator
|
||||
Char32* data = allocator.alloc(Char32.sizeof * (codepoints + 1))?;
|
||||
conv::utf8to32_unsafe(utf8, data)?;
|
||||
data[codepoints] = 0;
|
||||
return data[0..codepoints - 1];
|
||||
return data[:codepoints];
|
||||
}
|
||||
|
||||
fn char[] utf32to8(Char32[] utf32, Allocator* allocator = mem::current_allocator)
|
||||
@@ -116,7 +120,7 @@ fn char[] utf32to8(Char32[] utf32, Allocator* allocator = mem::current_allocator
|
||||
char* data = allocator.alloc(len + 1)!!;
|
||||
conv::utf32to8_unsafe(utf32, data);
|
||||
data[len] = 0;
|
||||
return data[0..len - 1];
|
||||
return data[:len];
|
||||
}
|
||||
|
||||
fn Char16[]! utf8to16(char[] utf8, Allocator* allocator = mem::current_allocator)
|
||||
@@ -125,7 +129,7 @@ fn Char16[]! utf8to16(char[] utf8, Allocator* allocator = mem::current_allocator
|
||||
Char16* data = allocator.alloc((len16 + 1) * Char16.sizeof)?;
|
||||
conv::utf8to16_unsafe(utf8, data)?;
|
||||
data[len16] = 0;
|
||||
return data[0..len16 - 1];
|
||||
return data[:len16];
|
||||
}
|
||||
|
||||
|
||||
@@ -134,21 +138,21 @@ fn char[]! utf16to8(Char16[] utf16, Allocator* allocator = mem::current_allocato
|
||||
usz len = conv::utf8len_for_utf16(utf16);
|
||||
char* data = allocator.alloc(len + 1)?;
|
||||
conv::utf16to8_unsafe(utf16, data)?;
|
||||
return data[0 .. len - 1];
|
||||
return data[:len];
|
||||
}
|
||||
|
||||
fn char[] copy(char[] s)
|
||||
fn char[] copy(char[] s, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
usz len = s.len;
|
||||
ZString str_copy = copy_zstring(s) @inline;
|
||||
return str_copy[..len];
|
||||
ZString str_copy = copy_zstring(s, allocator) @inline;
|
||||
return str_copy[:len];
|
||||
}
|
||||
|
||||
fn char[] tcopy(char[] s)
|
||||
{
|
||||
usz len = s.len;
|
||||
ZString str_copy = tcopy_zstring(s) @inline;
|
||||
return str_copy[..len];
|
||||
return str_copy[:len];
|
||||
}
|
||||
|
||||
fn char[] tconcat(char[] s1, char[] s2)
|
||||
|
||||
@@ -1,19 +1,173 @@
|
||||
module std::io::dir;
|
||||
|
||||
struct PlatformDir
|
||||
// In progress.
|
||||
define Path = distinct char[];
|
||||
|
||||
const PREFERRED_SEPARATOR = USE_WIN32_FILESYSTEM ? '\\' : '/';
|
||||
private const USE_WIN32_FILESYSTEM = env::OS_TYPE != OsType.WIN32;
|
||||
|
||||
fault PathResult
|
||||
{
|
||||
void* data;
|
||||
INVALID_PATH
|
||||
}
|
||||
|
||||
macro bool is_separator(char c)
|
||||
{
|
||||
$if (USE_WIN32_FILESYSTEM):
|
||||
return c == '/' || c == '\\';
|
||||
$else:
|
||||
return c == '/';
|
||||
$endif;
|
||||
}
|
||||
|
||||
const bool[256] RESERVED_PATH_CHAR_POSIX = {
|
||||
[0] = true,
|
||||
['/'] = true,
|
||||
};
|
||||
const bool[256] RESERVED_PATH_CHAR_WIN32 = {
|
||||
[0..31] = true,
|
||||
['>'] = true,
|
||||
['<'] = true,
|
||||
[':'] = true,
|
||||
['\"'] = true,
|
||||
['/'] = true,
|
||||
['\\'] = true,
|
||||
['|'] = true,
|
||||
['?'] = true,
|
||||
['*'] = true,
|
||||
};
|
||||
|
||||
macro bool is_reserved_path_char(char c)
|
||||
{
|
||||
$if (USE_WIN32_FILESYSTEM):
|
||||
return RESERVED_PATH_CHAR_WIN32[c];
|
||||
$else:
|
||||
return RESERVED_PATH_CHAR_POSIX[c];
|
||||
$endif;
|
||||
}
|
||||
|
||||
private fn usz! root_name_len(char[] path)
|
||||
{
|
||||
usz len = path.len;
|
||||
if (!len) return 0;
|
||||
$if (USE_WIN32_FILESYSTEM):
|
||||
switch (path[0])
|
||||
{
|
||||
case '\\':
|
||||
if (len < 2 || path[1] != '\\') break;
|
||||
if (len == 2 || is_separator(path[2])) return PathResult.INVALID_PATH!;
|
||||
for (usz i = 2; i < len; i++)
|
||||
{
|
||||
char c = path[i];
|
||||
if (is_separator(c)) return i;
|
||||
if (is_reserved_path_char(c)) return PathResult.INVALID_PATH!;
|
||||
}
|
||||
return len;
|
||||
case 'A'..'Z':
|
||||
case 'a'..'z':
|
||||
if (len < 2 || path[1] != ':') break;
|
||||
if (len < 3 || !is_separator(path[2])) return PathResult.INVALID_PATH!;
|
||||
return 2;
|
||||
}
|
||||
$endif;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private fn void! normalize_path(char[]* path_ref)
|
||||
{
|
||||
char[] path = *path_ref;
|
||||
if (!path.len) return;
|
||||
usz path_start = root_name_len(path)?;
|
||||
usz len = path_start;
|
||||
bool previous_was_separator = false;
|
||||
usz path_len = path.len;
|
||||
for (usz i = path_start; i < path_len; i++)
|
||||
{
|
||||
char c = path[i];
|
||||
// Fold foo///bar into foo/bar
|
||||
if (is_separator(c))
|
||||
{
|
||||
if (previous_was_separator)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
path.ptr[len++] = PREFERRED_SEPARATOR;
|
||||
previous_was_separator = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we get . we have different things that might happen:
|
||||
if (c == '.' && i < path_len - 1)
|
||||
{
|
||||
// Is this ./ or /./ ?
|
||||
if ((previous_was_separator || i == path_start) && is_separator(path[i + 1]))
|
||||
{
|
||||
// Then we skip this
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
// Is this /../ in that case we must walk back and erase(!)
|
||||
if (i < path_len - 2 && previous_was_separator && path[i + 1] == '.' && is_separator(path[i + 2]))
|
||||
{
|
||||
assert(len > path_start);
|
||||
len--;
|
||||
while (len > path_start && !is_separator(path[len - 1]))
|
||||
{
|
||||
len--;
|
||||
}
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (i != len) path[len] = c;
|
||||
previous_was_separator = false;
|
||||
len++;
|
||||
}
|
||||
path.ptr[len] = 0;
|
||||
*path_ref = path[:len];
|
||||
}
|
||||
|
||||
fn Path new_path(char[] path)
|
||||
{
|
||||
char[] copy = str::copy(path);
|
||||
normalize_path(©)!!;
|
||||
return (Path)copy;
|
||||
}
|
||||
|
||||
fn Path Path.root_name(Path path)
|
||||
{
|
||||
char[] path_str = (char[])path;
|
||||
usz len = root_name_len(path_str)!!;
|
||||
if (!len) return (Path)"";
|
||||
return (Path)path_str[0:len];
|
||||
}
|
||||
|
||||
fn Path Path.root_directory(Path path)
|
||||
{
|
||||
char[] path_str = (char[])path;
|
||||
usz len = path_str.len;
|
||||
if (!len) return (Path)"";
|
||||
$if (USE_WIN32_FILESYSTEM):
|
||||
usz root_len = root_name_len(path_str)!!;
|
||||
if (root_len == len || !is_separator(path_str[root_len])) return (Path)"";
|
||||
return (Path)path_str[root_len..root_len];
|
||||
$else:
|
||||
if (!is_separator(path_str[0])) return (Path)"";
|
||||
for (usz i = 1; i < len; i++)
|
||||
{
|
||||
if (is_separator(path_str[i]))
|
||||
{
|
||||
return (Path)path_str[:i];
|
||||
}
|
||||
}
|
||||
return path;
|
||||
$endif;
|
||||
}
|
||||
|
||||
|
||||
fn void Path.destroy(Path path)
|
||||
{
|
||||
free(path.ptr);
|
||||
}
|
||||
|
||||
define Dir = distinct PlatformDir*;
|
||||
|
||||
$if (env::OS_TYPE == OsType.WIN32):
|
||||
/*
|
||||
private extern ulong _win32_GetCurrentDirectoryW(ulong, Char16* buffer) @extname("GetCurrentDirectoryW");
|
||||
private extern bool _win32_CreateSymbolicLinkW(Char16* symlink_file, Char16* target_file, ulong flags) @extname("CreateSymbolicLinkW");
|
||||
private extern bool _win32_CreateDirectoryW(Char16* path_name, void* security_attributes) @extname("CreateDirectoryW");
|
||||
private extern bool _win32_DeleteFileW(Char16* file) @extname("DeleteFileW");
|
||||
private extern bool _win32_CopyFileW(Char16* from_file, Char16* to_file, bool no_overwrite) @extname("CopyFileW");
|
||||
private extern ulong _win32_GetFullPathNameW(Char16* file_name, ulong buffer_len, Char16* buffer, Char16** file_part) @extname("GetFullPathNameW");
|
||||
*/
|
||||
$endif;
|
||||
@@ -15,7 +15,7 @@ struct List
|
||||
/**
|
||||
* @require allocator != null "A valid allocator must be provided"
|
||||
**/
|
||||
fn void List.init(List* list, usz initial_capacity = 16, Allocator* allocator = mem::temp_allocator())
|
||||
fn void List.init(List* list, usz initial_capacity = 16, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
list.allocator = allocator;
|
||||
list.size = 0;
|
||||
@@ -31,6 +31,10 @@ fn void List.init(List* list, usz initial_capacity = 16, Allocator* allocator =
|
||||
list.capacity = initial_capacity;
|
||||
}
|
||||
|
||||
fn void List.tinit(List* list, usz initial_capacity = 16)
|
||||
{
|
||||
list.init(initial_capacity, mem::temp_allocator()) @inline;
|
||||
}
|
||||
|
||||
fn void List.push(List *list, Type element) @inline
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ struct HashMap
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
* @require allocator != null "The allocator must be non-null"
|
||||
**/
|
||||
fn void HashMap.init(HashMap* map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = mem::temp_allocator())
|
||||
fn void HashMap.init(HashMap* map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
capacity = math::next_power_of_2(capacity);
|
||||
map.allocator = allocator;
|
||||
@@ -37,12 +37,28 @@ fn void HashMap.init(HashMap* map, uint capacity = DEFAULT_INITIAL_CAPACITY, flo
|
||||
map.table = array::make(Entry*, capacity, allocator);
|
||||
}
|
||||
|
||||
fn void HashMap.init_from_map(HashMap* map, HashMap* other_map, Allocator* allocator = mem::temp_allocator())
|
||||
/**
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||
* @require !map.allocator "Map was already initialized"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
fn void HashMap.tinit(HashMap* map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
|
||||
{
|
||||
map.init(capacity, load_factor, mem::temp_allocator());
|
||||
}
|
||||
|
||||
fn void HashMap.init_from_map(HashMap* map, HashMap* other_map, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
map.init(other_map.table.len, other_map.load_factor, allocator);
|
||||
map.put_all_for_create(other_map);
|
||||
}
|
||||
|
||||
fn void HashMap.tinit_from_map(HashMap* map, HashMap* other_map)
|
||||
{
|
||||
map.init_from_map(other_map, mem::temp_allocator()) @inline;
|
||||
}
|
||||
|
||||
fn bool HashMap.is_empty(HashMap* map) @inline
|
||||
{
|
||||
return !map.count;
|
||||
@@ -138,7 +154,12 @@ fn void HashMap.destroy(HashMap* map)
|
||||
map.table = Entry*[] {};
|
||||
}
|
||||
|
||||
fn Key[] HashMap.key_list(HashMap* map, Allocator* allocator = mem::temp_allocator())
|
||||
fn Key[] HashMap.key_tlist(HashMap* map)
|
||||
{
|
||||
return map.key_list(mem::temp_allocator()) @inline;
|
||||
}
|
||||
|
||||
fn Key[] HashMap.key_list(HashMap* map, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
if (!map.count) return Key[] {};
|
||||
|
||||
@@ -155,7 +176,12 @@ fn Key[] HashMap.key_list(HashMap* map, Allocator* allocator = mem::temp_allocat
|
||||
return list;
|
||||
}
|
||||
|
||||
fn Value[] HashMap.value_list(HashMap* map, Allocator* allocator = mem::temp_allocator())
|
||||
fn Value[] HashMap.value_tlist(HashMap* map)
|
||||
{
|
||||
return map.value_list(mem::temp_allocator()) @inline;
|
||||
}
|
||||
|
||||
fn Value[] HashMap.value_list(HashMap* map, Allocator* allocator = mem::current_allocator())
|
||||
{
|
||||
if (!map.count) return Value[] {};
|
||||
Value[] list = array::make(Value, map.count, allocator);
|
||||
|
||||
@@ -28,7 +28,7 @@ macro Class! class_by_name(char* c)
|
||||
return cls;
|
||||
}
|
||||
|
||||
macro Class[] class_get_list(Allocator *allocator = mem::temp_allocator())
|
||||
macro Class[] class_get_list(Allocator *allocator = mem::current_allocator())
|
||||
{
|
||||
int num_classes = _macos_objc_getClassList(null, 0);
|
||||
if (!num_classes) return {};
|
||||
|
||||
12
lib/std/os/win32/files.c3
Normal file
12
lib/std/os/win32/files.c3
Normal file
@@ -0,0 +1,12 @@
|
||||
module std::os::win32::files;
|
||||
|
||||
$if (env::OS_TYPE == OsType.WIN32):
|
||||
/*
|
||||
private extern ulong _win32_GetCurrentDirectoryW(ulong, Char16* buffer) @extname("GetCurrentDirectoryW");
|
||||
private extern bool _win32_CreateSymbolicLinkW(Char16* symlink_file, Char16* target_file, ulong flags) @extname("CreateSymbolicLinkW");
|
||||
private extern bool _win32_CreateDirectoryW(Char16* path_name, void* security_attributes) @extname("CreateDirectoryW");
|
||||
private extern bool _win32_DeleteFileW(Char16* file) @extname("DeleteFileW");
|
||||
private extern bool _win32_CopyFileW(Char16* from_file, Char16* to_file, bool no_overwrite) @extname("CopyFileW");
|
||||
private extern ulong _win32_GetFullPathNameW(Char16* file_name, ulong buffer_len, Char16* buffer, Char16** file_part) @extname("GetFullPathNameW");
|
||||
*/
|
||||
$endif;
|
||||
@@ -931,9 +931,10 @@ static inline bool scan_string(Lexer *lexer)
|
||||
current++;
|
||||
break;
|
||||
}
|
||||
if (c == '\\' && *current == '"')
|
||||
if (c == '\\')
|
||||
{
|
||||
current++;
|
||||
c = *current;
|
||||
if (c != '\n' && c != '\0') current++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ LLVMValueRef llvm_coerce_int_ptr(GenContext *c, LLVMValueRef value, LLVMTypeRef
|
||||
|
||||
LLVMValueRef llvm_emit_coerce(GenContext *c, LLVMTypeRef coerced, BEValue *value, Type *original_type)
|
||||
{
|
||||
assert(original_type->canonical == value->type->canonical);
|
||||
assert(type_flatten_distinct(original_type) == type_flatten_distinct(value->type));
|
||||
LLVMTypeRef llvm_source_type = llvm_get_type(c, value->type);
|
||||
|
||||
// 1. If the types match then we're done, just load.
|
||||
|
||||
@@ -86,11 +86,13 @@ bool pointer_to_bool(Expr *expr, Type *type)
|
||||
{
|
||||
if (insert_runtime_cast_unless_const(expr, CAST_PTRBOOL, type)) return true;
|
||||
|
||||
// Must have been a null
|
||||
expr->const_expr.b = false;
|
||||
expr->type = type;
|
||||
expr->const_expr.narrowable = false;
|
||||
expr->const_expr.is_hex = false;
|
||||
if (expr->const_expr.const_kind == CONST_POINTER)
|
||||
{
|
||||
expr_rewrite_const_bool(expr, type, expr->const_expr.ptr != 0);
|
||||
return true;
|
||||
}
|
||||
assert(expr->const_expr.const_kind == CONST_STRING);
|
||||
expr_rewrite_const_bool(expr, type, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1796,9 +1796,9 @@ static bool sema_analyse_nextcase_stmt(SemaContext *context, Ast *statement)
|
||||
|
||||
static inline bool sema_analyse_then_overwrite(SemaContext *context, Ast *statement, AstId replacement)
|
||||
{
|
||||
statement->ast_kind = AST_NOP_STMT;
|
||||
if (!replacement)
|
||||
{
|
||||
statement->ast_kind = AST_NOP_STMT;
|
||||
return true;
|
||||
}
|
||||
AstId current = replacement;
|
||||
@@ -1814,9 +1814,9 @@ static inline bool sema_analyse_then_overwrite(SemaContext *context, Ast *statem
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Overwrite but store link.
|
||||
// NOP and insert after.
|
||||
last->next = statement->next;
|
||||
*statement = *astptr(replacement);
|
||||
statement->next = replacement;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.3.88"
|
||||
#define COMPILER_VERSION "0.3.89"
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user