Merge branch 'master' into llvm-integration

This commit is contained in:
gingerBill
2020-02-23 10:39:57 +00:00
18 changed files with 299 additions and 156 deletions
+2 -7
View File
@@ -30,17 +30,15 @@ Default_File_Logger_Opts :: Options{
File_Console_Logger_Data :: struct {
lowest_level: Level,
file_handle: os.Handle,
ident : string,
}
create_file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "") -> Logger {
data := new(File_Console_Logger_Data);
data.lowest_level = lowest;
data.file_handle = h;
data.ident = ident;
return Logger{file_console_logger_proc, data, opt};
return Logger{file_console_logger_proc, data, lowest, opt};
}
destroy_file_logger ::proc(log : ^Logger) {
@@ -52,10 +50,9 @@ destroy_file_logger ::proc(log : ^Logger) {
create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "") -> Logger {
data := new(File_Console_Logger_Data);
data.lowest_level = lowest;
data.file_handle = os.INVALID_HANDLE;
data.ident = ident;
return Logger{file_console_logger_proc, data, opt};
return Logger{file_console_logger_proc, data, lowest, opt};
}
destroy_console_logger ::proc(log : ^Logger) {
@@ -65,8 +62,6 @@ destroy_console_logger ::proc(log : ^Logger) {
file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
data := cast(^File_Console_Logger_Data)logger_data;
if level < data.lowest_level do return;
h : os.Handle;
if(data.file_handle != os.INVALID_HANDLE) do h = data.file_handle;
else do h = level <= Level.Error ? context.stdout : context.stderr;
+25 -10
View File
@@ -60,9 +60,10 @@ Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Opt
Logger :: runtime.Logger;
/*
Logger :: struct {
procedure: Logger_Proc,
data: rawptr,
options: Options,
procedure: Logger_Proc,
data: rawptr,
lowest_level: Level,
options: Logger_Options,
}
*/
@@ -74,7 +75,7 @@ create_multi_logger :: proc(logs: ..Logger) -> Logger {
data := new(Multi_Logger_Data);
data.loggers = make([]Logger, len(logs));
copy(data.loggers, logs);
return Logger{multi_logger_proc, data, nil};
return Logger{multi_logger_proc, data, Level.Debug, nil};
}
destroy_multi_logger :: proc(log : ^Logger) {
@@ -98,18 +99,32 @@ nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Optio
}
nil_logger :: proc() -> Logger {
return Logger{nil_logger_proc, nil, nil};
return Logger{nil_logger_proc, nil, Level.Debug, nil};
}
// TODO(bill): Should these be redesigned so that they are do not rely upon `package fmt`?
debug :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Debug, fmt_str=fmt_str, args=args, location=location);
info :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Info, fmt_str=fmt_str, args=args, location=location);
warn :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location);
error :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Error, fmt_str=fmt_str, args=args, location=location);
fatal :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Fatal, fmt_str=fmt_str, args=args, location=location);
debugf :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Debug, fmt_str=fmt_str, args=args, location=location);
infof :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Info, fmt_str=fmt_str, args=args, location=location);
warnf :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location);
errorf :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Error, fmt_str=fmt_str, args=args, location=location);
fatalf :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Fatal, fmt_str=fmt_str, args=args, location=location);
debug :: proc(args : ..any, location := #caller_location) do log(level=Level.Debug, args=args, location=location);
info :: proc(args : ..any, location := #caller_location) do log(level=Level.Info, args=args, location=location);
warn :: proc(args : ..any, location := #caller_location) do log(level=Level.Warning, args=args, location=location);
error :: proc(args : ..any, location := #caller_location) do log(level=Level.Error, args=args, location=location);
fatal :: proc(args : ..any, location := #caller_location) do log(level=Level.Fatal, args=args, location=location);
log :: proc(level : Level, args : ..any, location := #caller_location) {
logger := context.logger;
if level < logger.lowest_level do return;
str := fmt.tprint(..args); //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
logger.procedure(logger.data, level, str, logger.options, location);
}
logf :: proc(level : Level, fmt_str : string, args : ..any, location := #caller_location) {
logger := context.logger;
if level < logger.lowest_level do return;
str := len(args) > 0 ? fmt.tprintf(fmt_str, ..args) : fmt.tprint(fmt_str); //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
logger.procedure(logger.data, level, str, logger.options, location);
}
+1 -1
View File
@@ -357,7 +357,7 @@ matrix_mul_vector :: proc(a: $A/[$I][$J]$E, b: $B/[I]E) -> (c: B)
IS_NUMERIC(E) {
for i in 0..<I {
for j in 0..<J {
c[i] += a[i][j] * b[i];
c[j] += a[i][j] * b[i];
}
}
return;
+11 -9
View File
@@ -742,26 +742,28 @@ atan2_f64 :: proc(y, x: f64) -> f64 {
atan2 :: proc{atan2_f32, atan2_f64};
atan_f32 :: proc(x: f32) -> f32 {
return atan2_f32(1.0, x);
return atan2_f32(1, x);
}
atan :: proc{atan_f32};
atan_f64 :: proc(x: f64) -> f64 {
return atan2_f64(1, x);
}
atan :: proc{atan_f32, atan_f64};
asin_f32 :: proc(x: f32) -> f32 {
return atan2_f32(x, sqrt_f32(1 - x*x));
return atan2_f32(x, 1 + sqrt_f32(1 - x*x));
}
asin_f64 :: proc(x: f64) -> f64 {
return atan2_f64(x, sqrt_f64(1 - x*x));
return atan2_f64(x, 1 + sqrt_f64(1 - x*x));
}
asin :: proc{asin_f32};
asin :: proc{asin_f32, asin_f64};
acos_f32 :: proc(x: f32) -> f32 {
return atan2_f32(sqrt_f32(1 - x), sqrt_f32(1 + x));
return 2 * atan2_f32(sqrt_f32(1 - x), sqrt_f32(1 + x));
}
acos_f64 :: proc(x: f64) -> f64 {
return atan2_f64(sqrt_f64(1 - x), sqrt_f64(1 + x));
return 2 * atan2_f64(sqrt_f64(1 - x), sqrt_f64(1 + x));
}
acos :: proc{acos_f32};
acos :: proc{acos_f32, acos_f64};
sinh_f32 :: proc(x: f32) -> f32 {
+11 -1
View File
@@ -45,8 +45,18 @@ copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawpt
return runtime.mem_copy_non_overlapping(dst, src, len);
}
compare :: inline proc "contextless" (a, b: []byte) -> int {
return compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
// NOTE(tetra): no-abc is okay here because if the slices are empty, `&a[0]` is just nil+0 == nil, which
// compare_byte_ptrs handles fine when the passed length is also zero.
res := #no_bounds_check compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
if res == 0 && len(a) != len(b) {
return len(a) <= len(b) ? -1 : +1;
} else if len(a) == 0 && len(b) == 0 {
return 0;
} else {
return res;
}
}
compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int #no_bounds_check {
x := slice_ptr(a, n);
y := slice_ptr(b, n);
+33
View File
@@ -5,6 +5,7 @@ foreign import libc "system:c"
import "core:runtime"
import "core:strings"
import "core:c"
OS :: "darwin";
@@ -263,6 +264,8 @@ X_OK :: 1; // Test for execute permission
F_OK :: 0; // Test for file existance
foreign libc {
@(link_name="__error") __error :: proc() -> ^int ---;
@(link_name="open") _unix_open :: proc(path: cstring, flags: int, #c_vararg mode: ..any) -> Handle ---;
@(link_name="close") _unix_close :: proc(handle: Handle) ---;
@(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---;
@@ -278,6 +281,8 @@ foreign libc {
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---;
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---;
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---;
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---;
@(link_name="exit") _unix_exit :: proc(status: int) ---;
}
@@ -289,6 +294,10 @@ foreign dl {
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---;
}
get_last_error :: proc() -> int {
return __error()^;
}
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
cstr := strings.clone_to_cstring(path);
handle := _unix_open(cstr, flags, mode);
@@ -394,6 +403,30 @@ getenv :: proc(name: string) -> (string, bool) {
return string(cstr), true;
}
get_current_directory :: proc() -> string {
page_size := get_page_size(); // NOTE(tetra): See note in os_linux.odin/get_current_directory.
buf := make([dynamic]u8, page_size);
for {
cwd := _unix_getcwd(cstring(#no_bounds_check &buf[0]), c.size_t(len(buf)));
if cwd != nil {
return string(cwd);
}
if Errno(get_last_error()) != ERANGE {
return "";
}
resize(&buf, len(buf)+page_size);
}
unreachable();
return "";
}
set_current_directory :: proc(path: string) -> (err: Errno) {
cstr := strings.clone_to_cstring(path, context.temp_allocator);
res := _unix_chdir(cstr);
if res == -1 do return Errno(get_last_error());
return ERROR_NONE;
}
exit :: inline proc(code: int) -> ! {
_unix_exit(code);
}
+142 -111
View File
@@ -5,6 +5,7 @@ foreign import libc "system:c"
import "core:runtime"
import "core:strings"
import "core:c"
OS :: "linux";
@@ -15,94 +16,95 @@ Syscall :: distinct int;
INVALID_HANDLE :: ~Handle(0);
ERROR_NONE: Errno : 0;
EPERM: Errno : 1;
ENOENT: Errno : 2;
ESRCH: Errno : 3;
EINTR: Errno : 4;
EIO: Errno : 5;
ENXIO: Errno : 6;
EBADF: Errno : 9;
EAGAIN: Errno : 11;
ENOMEM: Errno : 12;
EACCES: Errno : 13;
EFAULT: Errno : 14;
EEXIST: Errno : 17;
ENODEV: Errno : 19;
ENOTDIR: Errno : 20;
EISDIR: Errno : 21;
EINVAL: Errno : 22;
ENFILE: Errno : 23;
EMFILE: Errno : 24;
ETXTBSY: Errno : 26;
EFBIG: Errno : 27;
ENOSPC: Errno : 28;
ESPIPE: Errno : 29;
EROFS: Errno : 30;
EPIPE: Errno : 32;
ERROR_NONE: Errno : 0;
EPERM: Errno : 1;
ENOENT: Errno : 2;
ESRCH: Errno : 3;
EINTR: Errno : 4;
EIO: Errno : 5;
ENXIO: Errno : 6;
EBADF: Errno : 9;
EAGAIN: Errno : 11;
ENOMEM: Errno : 12;
EACCES: Errno : 13;
EFAULT: Errno : 14;
EEXIST: Errno : 17;
ENODEV: Errno : 19;
ENOTDIR: Errno : 20;
EISDIR: Errno : 21;
EINVAL: Errno : 22;
ENFILE: Errno : 23;
EMFILE: Errno : 24;
ETXTBSY: Errno : 26;
EFBIG: Errno : 27;
ENOSPC: Errno : 28;
ESPIPE: Errno : 29;
EROFS: Errno : 30;
EPIPE: Errno : 32;
EDEADLK: Errno : 35; /* Resource deadlock would occur */
ENAMETOOLONG: Errno : 36; /* File name too long */
ENOLCK: Errno : 37; /* No record locks available */
ERANGE: Errno : 34; /* Result too large */
EDEADLK: Errno : 35; /* Resource deadlock would occur */
ENAMETOOLONG: Errno : 36; /* File name too long */
ENOLCK: Errno : 37; /* No record locks available */
ENOSYS: Errno : 38; /* Invalid system call number */
ENOSYS: Errno : 38; /* Invalid system call number */
ENOTEMPTY: Errno : 39; /* Directory not empty */
ELOOP: Errno : 40; /* Too many symbolic links encountered */
EWOULDBLOCK: Errno : EAGAIN; /* Operation would block */
ENOMSG: Errno : 42; /* No message of desired type */
EIDRM: Errno : 43; /* Identifier removed */
ECHRNG: Errno : 44; /* Channel number out of range */
EL2NSYNC: Errno : 45; /* Level 2 not synchronized */
EL3HLT: Errno : 46; /* Level 3 halted */
EL3RST: Errno : 47; /* Level 3 reset */
ELNRNG: Errno : 48; /* Link number out of range */
EUNATCH: Errno : 49; /* Protocol driver not attached */
ENOCSI: Errno : 50; /* No CSI structure available */
EL2HLT: Errno : 51; /* Level 2 halted */
EBADE: Errno : 52; /* Invalid exchange */
EBADR: Errno : 53; /* Invalid request descriptor */
EXFULL: Errno : 54; /* Exchange full */
ENOANO: Errno : 55; /* No anode */
EBADRQC: Errno : 56; /* Invalid request code */
EBADSLT: Errno : 57; /* Invalid slot */
EDEADLOCK: Errno : EDEADLK;
EBFONT: Errno : 59; /* Bad font file format */
ENOSTR: Errno : 60; /* Device not a stream */
ENODATA: Errno : 61; /* No data available */
ETIME: Errno : 62; /* Timer expired */
ENOSR: Errno : 63; /* Out of streams resources */
ENONET: Errno : 64; /* Machine is not on the network */
ENOPKG: Errno : 65; /* Package not installed */
EREMOTE: Errno : 66; /* Object is remote */
ENOLINK: Errno : 67; /* Link has been severed */
EADV: Errno : 68; /* Advertise error */
ESRMNT: Errno : 69; /* Srmount error */
ECOMM: Errno : 70; /* Communication error on send */
EPROTO: Errno : 71; /* Protocol error */
EMULTIHOP: Errno : 72; /* Multihop attempted */
EDOTDOT: Errno : 73; /* RFS specific error */
EBADMSG: Errno : 74; /* Not a data message */
EOVERFLOW: Errno : 75; /* Value too large for defined data type */
ENOTUNIQ: Errno : 76; /* Name not unique on network */
EBADFD: Errno : 77; /* File descriptor in bad state */
EREMCHG: Errno : 78; /* Remote address changed */
ELIBACC: Errno : 79; /* Can not access a needed shared library */
ELIBBAD: Errno : 80; /* Accessing a corrupted shared library */
ELIBSCN: Errno : 81; /* .lib section in a.out corrupted */
ELIBMAX: Errno : 82; /* Attempting to link in too many shared libraries */
ELIBEXEC: Errno : 83; /* Cannot exec a shared library directly */
EILSEQ: Errno : 84; /* Illegal byte sequence */
ERESTART: Errno : 85; /* Interrupted system call should be restarted */
ESTRPIPE: Errno : 86; /* Streams pipe error */
EUSERS: Errno : 87; /* Too many users */
ENOTSOCK: Errno : 88; /* Socket operation on non-socket */
EDESTADDRREQ: Errno : 89; /* Destination address required */
EMSGSIZE: Errno : 90; /* Message too long */
EPROTOTYPE: Errno : 91; /* Protocol wrong type for socket */
ENOPROTOOPT: Errno : 92; /* Protocol not available */
EPROTONOSUPPORT: Errno : 93; /* Protocol not supported */
ESOCKTNOSUPPORT: Errno : 94; /* Socket type not supported */
ENOTEMPTY: Errno : 39; /* Directory not empty */
ELOOP: Errno : 40; /* Too many symbolic links encountered */
EWOULDBLOCK: Errno : EAGAIN; /* Operation would block */
ENOMSG: Errno : 42; /* No message of desired type */
EIDRM: Errno : 43; /* Identifier removed */
ECHRNG: Errno : 44; /* Channel number out of range */
EL2NSYNC: Errno : 45; /* Level 2 not synchronized */
EL3HLT: Errno : 46; /* Level 3 halted */
EL3RST: Errno : 47; /* Level 3 reset */
ELNRNG: Errno : 48; /* Link number out of range */
EUNATCH: Errno : 49; /* Protocol driver not attached */
ENOCSI: Errno : 50; /* No CSI structure available */
EL2HLT: Errno : 51; /* Level 2 halted */
EBADE: Errno : 52; /* Invalid exchange */
EBADR: Errno : 53; /* Invalid request descriptor */
EXFULL: Errno : 54; /* Exchange full */
ENOANO: Errno : 55; /* No anode */
EBADRQC: Errno : 56; /* Invalid request code */
EBADSLT: Errno : 57; /* Invalid slot */
EDEADLOCK: Errno : EDEADLK;
EBFONT: Errno : 59; /* Bad font file format */
ENOSTR: Errno : 60; /* Device not a stream */
ENODATA: Errno : 61; /* No data available */
ETIME: Errno : 62; /* Timer expired */
ENOSR: Errno : 63; /* Out of streams resources */
ENONET: Errno : 64; /* Machine is not on the network */
ENOPKG: Errno : 65; /* Package not installed */
EREMOTE: Errno : 66; /* Object is remote */
ENOLINK: Errno : 67; /* Link has been severed */
EADV: Errno : 68; /* Advertise error */
ESRMNT: Errno : 69; /* Srmount error */
ECOMM: Errno : 70; /* Communication error on send */
EPROTO: Errno : 71; /* Protocol error */
EMULTIHOP: Errno : 72; /* Multihop attempted */
EDOTDOT: Errno : 73; /* RFS specific error */
EBADMSG: Errno : 74; /* Not a data message */
EOVERFLOW: Errno : 75; /* Value too large for defined data type */
ENOTUNIQ: Errno : 76; /* Name not unique on network */
EBADFD: Errno : 77; /* File descriptor in bad state */
EREMCHG: Errno : 78; /* Remote address changed */
ELIBACC: Errno : 79; /* Can not access a needed shared library */
ELIBBAD: Errno : 80; /* Accessing a corrupted shared library */
ELIBSCN: Errno : 81; /* .lib section in a.out corrupted */
ELIBMAX: Errno : 82; /* Attempting to link in too many shared libraries */
ELIBEXEC: Errno : 83; /* Cannot exec a shared library directly */
EILSEQ: Errno : 84; /* Illegal byte sequence */
ERESTART: Errno : 85; /* Interrupted system call should be restarted */
ESTRPIPE: Errno : 86; /* Streams pipe error */
EUSERS: Errno : 87; /* Too many users */
ENOTSOCK: Errno : 88; /* Socket operation on non-socket */
EDESTADDRREQ: Errno : 89; /* Destination address required */
EMSGSIZE: Errno : 90; /* Message too long */
EPROTOTYPE: Errno : 91; /* Protocol wrong type for socket */
ENOPROTOOPT: Errno : 92; /* Protocol not available */
EPROTONOSUPPORT:Errno : 93; /* Protocol not supported */
ESOCKTNOSUPPORT:Errno : 94; /* Socket type not supported */
EOPNOTSUPP: Errno : 95; /* Operation not supported on transport endpoint */
EPFNOSUPPORT: Errno : 96; /* Protocol family not supported */
EAFNOSUPPORT: Errno : 97; /* Address family not supported by protocol */
@@ -259,29 +261,31 @@ foreign libc {
@(link_name="__errno_location") __errno_location :: proc() -> ^int ---;
@(link_name="syscall") syscall :: proc(number: Syscall, #c_vararg args: ..any) -> int ---;
@(link_name="open") _unix_open :: proc(path: cstring, flags: int, mode: int) -> Handle ---;
@(link_name="close") _unix_close :: proc(fd: Handle) -> int ---;
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
@(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 ---;
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---;
@(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---;
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---;
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---;
@(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 ---;
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---;
@(link_name="getpagesize") _unix_getpagesize :: proc() -> i32 ---;
@(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^Stat) -> int ---;
@(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^Stat) -> int ---;
@(link_name="access") _unix_access :: proc(path: cstring, mask: int) -> int ---;
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---;
@(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^Stat) -> c.int ---;
@(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^Stat) -> c.int ---;
@(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---;
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---;
@(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---;
@(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---;
@(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---;
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---;
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---;
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---;
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---;
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---;
@(link_name="exit") _unix_exit :: proc(status: int) -> ! ---;
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---;
}
foreign dl {
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: int) -> rawptr ---;
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---;
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---;
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---;
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---;
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---;
}
@@ -295,7 +299,7 @@ get_last_error :: proc() -> int {
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
cstr := strings.clone_to_cstring(path);
handle := _unix_open(cstr, flags, mode);
handle := _unix_open(cstr, c.int(flags), c.int(mode));
delete(cstr);
if handle == -1 {
return INVALID_HANDLE, Errno(get_last_error());
@@ -312,26 +316,26 @@ close :: proc(fd: Handle) -> Errno {
}
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
bytes_read := _unix_read(fd, &data[0], len(data));
bytes_read := _unix_read(fd, &data[0], c.size_t(len(data)));
if bytes_read == -1 {
return -1, Errno(get_last_error());
}
return bytes_read, ERROR_NONE;
return int(bytes_read), ERROR_NONE;
}
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE;
}
bytes_written := _unix_write(fd, &data[0], len(data));
bytes_written := _unix_write(fd, &data[0], c.size_t(len(data)));
if bytes_written == -1 {
return -1, Errno(get_last_error());
}
return bytes_written, ERROR_NONE;
return int(bytes_written), ERROR_NONE;
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
res := _unix_seek(fd, offset, i32(whence));
res := _unix_seek(fd, offset, c.int(whence));
if res == -1 {
return -1, Errno(get_last_error());
}
@@ -397,7 +401,7 @@ fstat :: inline proc(fd: Handle) -> (Stat, Errno) {
access :: inline proc(path: string, mask: int) -> (bool, Errno) {
cstr := strings.clone_to_cstring(path);
defer delete(cstr);
result := _unix_access(cstr, mask);
result := _unix_access(cstr, c.int(mask));
if result == -1 {
return false, Errno(get_last_error());
}
@@ -406,11 +410,11 @@ access :: inline proc(path: string, mask: int) -> (bool, Errno) {
heap_alloc :: proc(size: int) -> rawptr {
assert(size >= 0);
return _unix_calloc(1, size);
return _unix_calloc(1, c.size_t(size));
}
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
return _unix_realloc(ptr, new_size);
return _unix_realloc(ptr, c.size_t(new_size));
}
heap_free :: proc(ptr: rawptr) {
@@ -427,8 +431,35 @@ getenv :: proc(name: string) -> (string, bool) {
return string(cstr), true;
}
get_current_directory :: proc() -> string {
// NOTE(tetra): I would use PATH_MAX here, but I was not able to find
// an authoritative value for it across all systems.
// The largest value I could find was 4096, so might as well use the page size.
page_size := get_page_size();
buf := make([dynamic]u8, page_size);
for {
cwd := _unix_getcwd(cstring(#no_bounds_check &buf[0]), c.size_t(len(buf)));
if cwd != nil {
return string(cwd);
}
if Errno(get_last_error()) != ERANGE {
return "";
}
resize(&buf, len(buf)+page_size);
}
unreachable();
return "";
}
set_current_directory :: proc(path: string) -> (err: Errno) {
cstr := strings.clone_to_cstring(path, context.temp_allocator);
res := _unix_chdir(cstr);
if res == -1 do return Errno(get_last_error());
return ERROR_NONE;
}
exit :: proc(code: int) -> ! {
_unix_exit(code);
_unix_exit(c.int(code));
}
current_thread_id :: proc "contextless" () -> int {
@@ -438,7 +469,7 @@ current_thread_id :: proc "contextless" () -> int {
dlopen :: inline proc(filename: string, flags: int) -> rawptr {
cstr := strings.clone_to_cstring(filename);
defer delete(cstr);
handle := _unix_dlopen(cstr, flags);
handle := _unix_dlopen(cstr, c.int(flags));
return handle;
}
dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {
+35
View File
@@ -2,6 +2,7 @@
package os
import "core:sys/win32"
import "core:intrinsics"
OS :: "windows";
@@ -265,6 +266,40 @@ get_page_size :: proc() -> int {
}
// NOTE(tetra): GetCurrentDirectory is not thread safe with SetCurrentDirectory and GetFullPathName;
// The current directory is stored as a global variable in the process.
@private cwd_gate := false;
get_current_directory :: proc() -> string {
for intrinsics.atomic_xchg(&cwd_gate, true) {}
sz_utf16 := win32.get_current_directory_w(0, nil);
dir_buf_wstr := make([]u16, sz_utf16, context.temp_allocator); // the first time, it _includes_ the NUL.
sz_utf16 = win32.get_current_directory_w(u32(len(dir_buf_wstr)), cast(win32.Wstring) &dir_buf_wstr[0]);
assert(int(sz_utf16)+1 == len(dir_buf_wstr)); // the second time, it _excludes_ the NUL.
intrinsics.atomic_store(&cwd_gate, false);
dir_utf8 := win32.utf16_to_utf8(dir_buf_wstr);
return dir_utf8[:len(dir_utf8)-1]; // NOTE(tetra): Remove the NUL.
}
set_current_directory :: proc(path: string) -> (err: Errno) {
wstr := win32.utf8_to_wstring(path);
for intrinsics.atomic_xchg(&cwd_gate, true) {}
defer intrinsics.atomic_store(&cwd_gate, false);
res := win32.set_current_directory_w(wstr);
if res == 0 do return Errno(win32.get_last_error());
return;
}
exit :: proc(code: int) -> ! {
win32.exit_process(u32(code));
}
+5 -4
View File
@@ -276,9 +276,10 @@ Logger_Options :: bit_set[Logger_Option];
Logger_Proc :: #type proc(data: rawptr, level: Logger_Level, text: string, options: Logger_Options, location := #caller_location);
Logger :: struct {
procedure: Logger_Proc,
data: rawptr,
options: Logger_Options,
procedure: Logger_Proc,
data: rawptr,
lowest_level: Logger_Level,
options: Logger_Options,
}
Context :: struct {
@@ -434,7 +435,7 @@ default_logger_proc :: proc(data: rawptr, level: Logger_Level, text: string, opt
}
default_logger :: proc() -> Logger {
return Logger{default_logger_proc, nil, nil};
return Logger{default_logger_proc, nil, Logger_Level.Debug, nil};
}
+1 -1
View File
@@ -103,7 +103,7 @@ _log2 :: proc(x: int) -> int {
return res;
}
merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) where intrinsics.type_is_ordered(T) {
merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
merge :: proc(a: A, start, mid, end: int, f: proc(T, T) -> int) {
s, m := start, mid;
+2
View File
@@ -52,6 +52,8 @@ unsafe_string_to_cstring :: proc(str: string) -> cstring {
return cstring(d.data);
}
// Compares two strings, returning a value representing which one comes first lexiographically.
// -1 for `a`; 1 for `b`, or 0 if they are equal.
compare :: proc(lhs, rhs: string) -> int {
return mem.compare(transmute([]byte)lhs, transmute([]byte)rhs);
}
+5
View File
@@ -35,6 +35,11 @@ foreign kernel32 {
@(link_name="GetVersionExA") get_version :: proc(osvi: ^OS_Version_Info_Ex_A) ---;
@(link_name="GetCurrentThreadId") get_current_thread_id :: proc() -> u32 ---;
// NOTE(tetra): Not thread safe with SetCurrentDirectory and GetFullPathName;
// The current directory is stored as a global variable in the process.
@(link_name="GetCurrentDirectoryW") get_current_directory_w :: proc(len: u32, buf: Wstring) -> u32 ---;
@(link_name="SetCurrentDirectoryW") set_current_directory_w :: proc(buf: Wstring) -> u32 ---;
@(link_name="GetSystemTimeAsFileTime") get_system_time_as_file_time :: proc(system_time_as_file_time: ^Filetime) ---;
@(link_name="FileTimeToLocalFileTime") file_time_to_local_file_time :: proc(file_time: ^Filetime, local_file_time: ^Filetime) -> Bool ---;
@(link_name="FileTimeToSystemTime") file_time_to_system_time :: proc(file_time: ^Filetime, system_time: ^Systemtime) -> Bool ---;
+1 -1
View File
@@ -1207,7 +1207,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
}
bool where_clause_ok = evaluate_where_clauses(ctx, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true);
bool where_clause_ok = evaluate_where_clauses(ctx, nullptr, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true);
if (!where_clause_ok) {
// NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
return;
+10 -3
View File
@@ -2260,6 +2260,8 @@ bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) {
x->mode = Addressing_Value;
} else if (is_type_slice(type) && is_type_string(x->type)) {
x->mode = Addressing_Value;
} else if (is_type_union(type)) {
x->mode = Addressing_Value;
}
return true;
}
@@ -5942,7 +5944,9 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
Entity *e = sig_params[operand_index];
Type *t = e->type;
Operand o = operands[operand_index];
call->viral_state_flags |= o.expr->viral_state_flags;
if (o.expr != nullptr) {
call->viral_state_flags |= o.expr->viral_state_flags;
}
if (e->kind == Entity_TypeName) {
// GB_ASSERT(!variadic);
@@ -6296,7 +6300,7 @@ Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize
}
bool evaluate_where_clauses(CheckerContext *ctx, Scope *scope, Array<Ast *> *clauses, bool print_err) {
bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Scope *scope, Array<Ast *> *clauses, bool print_err) {
if (clauses != nullptr) {
for_array(i, *clauses) {
Ast *clause = (*clauses)[i];
@@ -6304,9 +6308,11 @@ bool evaluate_where_clauses(CheckerContext *ctx, Scope *scope, Array<Ast *> *cla
check_expr(ctx, &o, clause);
if (o.mode != Addressing_Constant) {
if (print_err) error(clause, "'where' clauses expect a constant boolean evaluation");
if (print_err && call_expr) error(call_expr, "at caller location");
return false;
} else if (o.value.kind != ExactValue_Bool) {
if (print_err) error(clause, "'where' clauses expect a constant boolean evaluation");
if (print_err && call_expr) error(call_expr, "at caller location");
return false;
} else if (!o.value.value_bool) {
if (print_err) {
@@ -6348,6 +6354,7 @@ bool evaluate_where_clauses(CheckerContext *ctx, Scope *scope, Array<Ast *> *cla
}
}
if (call_expr) error(call_expr, "at caller location");
}
return false;
}
@@ -6613,7 +6620,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
ctx.curr_proc_sig = e->type;
GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit);
if (!evaluate_where_clauses(&ctx, decl->scope, &decl->proc_lit->ProcLit.where_clauses, false)) {
if (!evaluate_where_clauses(&ctx, operand->expr, decl->scope, &decl->proc_lit->ProcLit.where_clauses, false)) {
continue;
}
}
+7 -1
View File
@@ -314,7 +314,11 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs)
gbString str = expr_to_string(lhs->expr);
if (e != nullptr && e->flags & EntityFlag_Param) {
error(lhs->expr, "Cannot assign to '%s' which is a procedure parameter", str);
if (e->flags & EntityFlag_Using) {
error(lhs->expr, "Cannot assign to '%s' which is from a 'using' procedure parameter", str);
} else {
error(lhs->expr, "Cannot assign to '%s' which is a procedure parameter", str);
}
} else {
error(lhs->expr, "Cannot assign to '%s'", str);
}
@@ -497,6 +501,8 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b
Entity *f = found->elements.entries[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, expr);
if (e->flags & EntityFlag_Value) uvar->flags |= EntityFlag_Value;
if (e->flags & EntityFlag_Param) uvar->flags |= EntityFlag_Param;
Entity *prev = scope_insert(ctx->scope, uvar);
if (prev != nullptr) {
gbString expr_str = expr_to_string(expr);
+2 -2
View File
@@ -527,7 +527,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
if (st->where_clauses.count > 0 && st->polymorphic_params == nullptr) {
error(st->where_clauses[0], "'where' clauses can only be used on structures with polymorphic parameters");
} else {
bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &st->where_clauses, true);
bool where_clause_ok = evaluate_where_clauses(ctx, node, ctx->scope, &st->where_clauses, true);
}
check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context);
}
@@ -714,7 +714,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) {
error(ut->where_clauses[0], "'where' clauses can only be used on unions with polymorphic parameters");
} else {
bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &ut->where_clauses, true);
bool where_clause_ok = evaluate_where_clauses(ctx, node, ctx->scope, &ut->where_clauses, true);
}
+4 -3
View File
@@ -5714,7 +5714,7 @@ irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t) {
}
// TODO(bill): Actually figure out what the conversion needs to be correctly 'cause LLVM
return ir_emit_bitcast(proc, value, dst);
return ir_emit_bitcast(proc, value, t);
}
@@ -7348,10 +7348,11 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
GB_ASSERT(are_types_identical(ir_type(left), key_type));
Type *it = bit_set_to_int(rt);
left = ir_emit_conv(proc, left, it);
irValue *lower = ir_value_constant(it, exact_value_i64(rt->BitSet.lower));
irValue *key = ir_emit_arith(proc, Token_Sub, left, lower, ir_type(left));
irValue *bit = ir_emit_arith(proc, Token_Shl, v_one, key, ir_type(left));
irValue *key = ir_emit_arith(proc, Token_Sub, left, lower, it);
irValue *bit = ir_emit_arith(proc, Token_Shl, v_one, key, it);
bit = ir_emit_conv(proc, bit, it);
irValue *old_value = ir_emit_bitcast(proc, right, it);
+2 -2
View File
@@ -1529,11 +1529,11 @@ int main(int arg_count, char const **arg_ptr) {
// Shared libraries are .dylib on MacOS and .so on Linux.
#if defined(GB_SYSTEM_OSX)
output_ext = STR_LIT(".dylib");
link_settings = "-dylib -dynamic";
#else
output_ext = STR_LIT(".so");
link_settings = "-shared";
#endif
link_settings = "-shared";
} else {
// TODO: Do I need anything here?
link_settings = "";