mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 07:08:48 +00:00
Semicolons are required; when condition for certain file scope declarations; #import syntax change
This commit is contained in:
+2
-30
@@ -1,34 +1,6 @@
|
|||||||
#import "fmt.odin"
|
#import "fmt.odin";
|
||||||
#import "utf8.odin"
|
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
MAX :: 64
|
fmt.println("Hellope");
|
||||||
buf: [MAX]rune
|
|
||||||
backing: [MAX]byte
|
|
||||||
offset: int
|
|
||||||
|
|
||||||
msg := "Hello"
|
|
||||||
|
|
||||||
count := utf8.rune_count(msg)
|
|
||||||
assert(count <= MAX)
|
|
||||||
runes := buf[:count]
|
|
||||||
|
|
||||||
offset = 0
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
s := msg[offset:]
|
|
||||||
r, len := utf8.decode_rune(s)
|
|
||||||
runes[count-i-1] = r
|
|
||||||
offset += len
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = 0
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
data, len := utf8.encode_rune(runes[i])
|
|
||||||
copy(backing[offset:], data[:len])
|
|
||||||
offset += len
|
|
||||||
}
|
|
||||||
|
|
||||||
reverse := backing[:offset] as string
|
|
||||||
fmt.println(reverse) // olleH
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+94
-94
@@ -1,60 +1,60 @@
|
|||||||
#import "win32.odin"
|
#import "win32.odin" when ODIN_OS == "windows";
|
||||||
#import "fmt.odin"
|
#import "fmt.odin";
|
||||||
#import "math.odin"
|
#import "math.odin";
|
||||||
#import "os.odin"
|
#import "os.odin";
|
||||||
#import "opengl.odin" as gl
|
#import gl "opengl.odin";
|
||||||
|
|
||||||
TWO_HEARTS :: '💕'
|
TWO_HEARTS :: '💕';
|
||||||
|
|
||||||
win32_perf_count_freq := win32.GetQueryPerformanceFrequency()
|
win32_perf_count_freq := win32.GetQueryPerformanceFrequency();
|
||||||
time_now :: proc() -> f64 {
|
time_now :: proc() -> f64 {
|
||||||
assert(win32_perf_count_freq != 0)
|
assert(win32_perf_count_freq != 0);
|
||||||
|
|
||||||
counter: i64
|
counter: i64;
|
||||||
win32.QueryPerformanceCounter(^counter)
|
win32.QueryPerformanceCounter(^counter);
|
||||||
result := counter as f64 / win32_perf_count_freq as f64
|
result := counter as f64 / win32_perf_count_freq as f64;
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
win32_print_last_error :: proc() {
|
win32_print_last_error :: proc() {
|
||||||
err_code := win32.GetLastError() as int
|
err_code := win32.GetLastError() as int;
|
||||||
if err_code != 0 {
|
if err_code != 0 {
|
||||||
fmt.println("GetLastError: %", err_code)
|
fmt.println("GetLastError: %", err_code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yuk!
|
// Yuk!
|
||||||
to_c_string :: proc(s: string) -> []u8 {
|
to_c_string :: proc(s: string) -> []u8 {
|
||||||
c_str := new_slice(u8, s.count+1)
|
c_str := new_slice(u8, s.count+1);
|
||||||
copy(c_str, s as []byte)
|
copy(c_str, s as []byte);
|
||||||
c_str[s.count] = 0
|
c_str[s.count] = 0;
|
||||||
return c_str
|
return c_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Window :: struct {
|
Window :: struct {
|
||||||
width, height: int
|
width, height: int;
|
||||||
wc: win32.WNDCLASSEXA
|
wc: win32.WNDCLASSEXA;
|
||||||
dc: win32.HDC
|
dc: win32.HDC;
|
||||||
hwnd: win32.HWND
|
hwnd: win32.HWND;
|
||||||
opengl_context, rc: win32.HGLRC
|
opengl_context, rc: win32.HGLRC;
|
||||||
c_title: []u8
|
c_title: []u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) -> (Window, bool) {
|
make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) -> (Window, bool) {
|
||||||
using win32
|
using win32;
|
||||||
|
|
||||||
w: Window
|
w: Window;
|
||||||
w.width, w.height = msg, height
|
w.width, w.height = msg, height;
|
||||||
|
|
||||||
class_name := "Win32-Odin-Window\x00"
|
class_name := "Win32-Odin-Window\x00";
|
||||||
c_class_name := class_name.data
|
c_class_name := class_name.data;
|
||||||
if title[title.count-1] != 0 {
|
if title[title.count-1] != 0 {
|
||||||
w.c_title = to_c_string(title)
|
w.c_title = to_c_string(title);
|
||||||
} else {
|
} else {
|
||||||
w.c_title = title as []u8
|
w.c_title = title as []u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
instance := GetModuleHandleA(nil)
|
instance := GetModuleHandleA(nil);
|
||||||
|
|
||||||
w.wc = WNDCLASSEXA{
|
w.wc = WNDCLASSEXA{
|
||||||
size = size_of(WNDCLASSEXA) as u32,
|
size = size_of(WNDCLASSEXA) as u32,
|
||||||
@@ -65,8 +65,8 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
|
|||||||
};
|
};
|
||||||
|
|
||||||
if RegisterClassExA(^w.wc) == 0 {
|
if RegisterClassExA(^w.wc) == 0 {
|
||||||
win32_print_last_error()
|
win32_print_last_error();
|
||||||
return w, false
|
return w, false;
|
||||||
}
|
}
|
||||||
|
|
||||||
w.hwnd = CreateWindowExA(0,
|
w.hwnd = CreateWindowExA(0,
|
||||||
@@ -74,14 +74,14 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
|
|||||||
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
|
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
|
||||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
w.width as i32, w.height as i32,
|
w.width as i32, w.height as i32,
|
||||||
nil, nil, instance, nil)
|
nil, nil, instance, nil);
|
||||||
|
|
||||||
if w.hwnd == nil {
|
if w.hwnd == nil {
|
||||||
win32_print_last_error()
|
win32_print_last_error();
|
||||||
return w, false
|
return w, false;
|
||||||
}
|
}
|
||||||
|
|
||||||
w.dc = GetDC(w.hwnd)
|
w.dc = GetDC(w.hwnd);
|
||||||
|
|
||||||
{
|
{
|
||||||
pfd := PIXELFORMATDESCRIPTOR{
|
pfd := PIXELFORMATDESCRIPTOR{
|
||||||
@@ -94,122 +94,122 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
|
|||||||
depth_bits = 24,
|
depth_bits = 24,
|
||||||
stencil_bits = 8,
|
stencil_bits = 8,
|
||||||
layer_type = PFD_MAIN_PLANE,
|
layer_type = PFD_MAIN_PLANE,
|
||||||
}
|
};
|
||||||
|
|
||||||
SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), nil)
|
SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), nil);
|
||||||
w.opengl_context = wglCreateContext(w.dc)
|
w.opengl_context = wglCreateContext(w.dc);
|
||||||
wglMakeCurrent(w.dc, w.opengl_context)
|
wglMakeCurrent(w.dc, w.opengl_context);
|
||||||
|
|
||||||
attribs := [8]i32{
|
attribs := [8]i32{
|
||||||
WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
|
WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
|
||||||
WGL_CONTEXT_MINOR_VERSION_ARB, 1,
|
WGL_CONTEXT_MINOR_VERSION_ARB, 1,
|
||||||
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
||||||
0, // NOTE(bill): tells the proc that this is the end of attribs
|
0, // NOTE(bill): tells the proc that this is the end of attribs
|
||||||
}
|
};
|
||||||
|
|
||||||
wglCreateContextAttribsARB := wglGetProcAddress(("wglCreateContextAttribsARB\x00" as string).data) as wglCreateContextAttribsARBType
|
wglCreateContextAttribsARB := wglGetProcAddress(("wglCreateContextAttribsARB\x00" as string).data) as wglCreateContextAttribsARBType;
|
||||||
w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0])
|
w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0]);
|
||||||
wglMakeCurrent(w.dc, w.rc)
|
wglMakeCurrent(w.dc, w.rc);
|
||||||
SwapBuffers(w.dc)
|
SwapBuffers(w.dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return w, true
|
return w, true;
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_window :: proc(w: ^Window) {
|
destroy_window :: proc(w: ^Window) {
|
||||||
free(w.c_title.data)
|
free(w.c_title.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
display_window :: proc(w: ^Window) {
|
display_window :: proc(w: ^Window) {
|
||||||
win32.SwapBuffers(w.dc)
|
win32.SwapBuffers(w.dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
run :: proc() {
|
run :: proc() {
|
||||||
using win32
|
using win32;
|
||||||
using math
|
using math;
|
||||||
|
|
||||||
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
|
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
|
||||||
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
|
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
|
||||||
os.exit(0)
|
os.exit(0);
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
return DefWindowProcA(hwnd, msg, wparam, lparam)
|
return DefWindowProcA(hwnd, msg, wparam, lparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc)
|
window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc);
|
||||||
if !window_success {
|
if !window_success {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
defer destroy_window(^window)
|
defer destroy_window(^window);
|
||||||
|
|
||||||
gl.init()
|
gl.init();
|
||||||
|
|
||||||
|
|
||||||
prev_time := time_now()
|
prev_time := time_now();
|
||||||
running := true
|
running := true;
|
||||||
|
|
||||||
pos := Vec2{100, 100}
|
pos := Vec2{100, 100};
|
||||||
|
|
||||||
for running {
|
for running {
|
||||||
curr_time := time_now()
|
curr_time := time_now();
|
||||||
dt := (curr_time - prev_time) as f32
|
dt := (curr_time - prev_time) as f32;
|
||||||
prev_time = curr_time
|
prev_time = curr_time;
|
||||||
|
|
||||||
msg: MSG
|
msg: MSG;
|
||||||
for PeekMessageA(^msg, nil, 0, 0, PM_REMOVE) > 0 {
|
for PeekMessageA(^msg, nil, 0, 0, PM_REMOVE) > 0 {
|
||||||
if msg.message == WM_QUIT {
|
if msg.message == WM_QUIT {
|
||||||
running = false
|
running = false;
|
||||||
}
|
}
|
||||||
TranslateMessage(^msg)
|
TranslateMessage(^msg);
|
||||||
DispatchMessageA(^msg)
|
DispatchMessageA(^msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_key_down(Key_Code.ESCAPE) {
|
if is_key_down(Key_Code.ESCAPE) {
|
||||||
running = false
|
running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
SPEED :: 500
|
SPEED :: 500;
|
||||||
v: Vec2
|
v: Vec2;
|
||||||
|
|
||||||
if is_key_down(Key_Code.RIGHT) { v[0] += 1 }
|
if is_key_down(Key_Code.RIGHT) { v[0] += 1; }
|
||||||
if is_key_down(Key_Code.LEFT) { v[0] -= 1 }
|
if is_key_down(Key_Code.LEFT) { v[0] -= 1; }
|
||||||
if is_key_down(Key_Code.UP) { v[1] += 1 }
|
if is_key_down(Key_Code.UP) { v[1] += 1; }
|
||||||
if is_key_down(Key_Code.DOWN) { v[1] -= 1 }
|
if is_key_down(Key_Code.DOWN) { v[1] -= 1; }
|
||||||
|
|
||||||
v = vec2_norm0(v)
|
v = vec2_norm0(v);
|
||||||
|
|
||||||
pos += v * Vec2{SPEED * dt}
|
pos += v * Vec2{SPEED * dt};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
gl.ClearColor(0.5, 0.7, 1.0, 1.0)
|
gl.ClearColor(0.5, 0.7, 1.0, 1.0);
|
||||||
gl.Clear(gl.COLOR_BUFFER_BIT)
|
gl.Clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
gl.LoadIdentity()
|
gl.LoadIdentity();
|
||||||
gl.Ortho(0, window.width as f64,
|
gl.Ortho(0, window.width as f64,
|
||||||
0, window.height as f64, 0, 1)
|
0, window.height as f64, 0, 1);
|
||||||
|
|
||||||
draw_rect :: proc(x, y, w, h: f32) {
|
draw_rect :: proc(x, y, w, h: f32) {
|
||||||
gl.Begin(gl.TRIANGLES)
|
gl.Begin(gl.TRIANGLES);
|
||||||
defer gl.End()
|
defer gl.End();
|
||||||
|
|
||||||
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0)
|
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0);
|
||||||
gl.Color3f(0, 1, 0); gl.Vertex3f(x+w, y, 0)
|
gl.Color3f(0, 1, 0); gl.Vertex3f(x+w, y, 0);
|
||||||
gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0)
|
gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0);
|
||||||
|
|
||||||
gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0)
|
gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0);
|
||||||
gl.Color3f(1, 1, 0); gl.Vertex3f(x, y+h, 0)
|
gl.Color3f(1, 1, 0); gl.Vertex3f(x, y+h, 0);
|
||||||
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0)
|
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_rect(pos.x, pos.y, 50, 50)
|
draw_rect(pos.x, pos.y, 50, 50);
|
||||||
|
|
||||||
display_window(^window)
|
display_window(^window);
|
||||||
ms_to_sleep := (16 - 1000*dt) as i32
|
ms_to_sleep := (16 - 1000*dt) as i32;
|
||||||
if ms_to_sleep > 0 {
|
if ms_to_sleep > 0 {
|
||||||
win32.Sleep(ms_to_sleep)
|
win32.Sleep(ms_to_sleep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+74
-74
@@ -1,10 +1,10 @@
|
|||||||
#import "fmt.odin" as fmt
|
#import "fmt.odin";
|
||||||
|
|
||||||
#foreign_system_library "Ws2_32"
|
#foreign_system_library "Ws2_32" when ODIN_OS == "windows";
|
||||||
|
|
||||||
|
|
||||||
SOCKET :: type uint
|
SOCKET :: type uint;
|
||||||
INVALID_SOCKET :: ~(0 as SOCKET)
|
INVALID_SOCKET :: ~(0 as SOCKET);
|
||||||
|
|
||||||
AF :: enum i32 {
|
AF :: enum i32 {
|
||||||
UNSPEC = 0, // unspecified
|
UNSPEC = 0, // unspecified
|
||||||
@@ -37,45 +37,45 @@ AF :: enum i32 {
|
|||||||
MAX = 26,
|
MAX = 26,
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCK_STREAM :: 1
|
SOCK_STREAM :: 1;
|
||||||
SOCKET_ERROR :: -1
|
SOCKET_ERROR :: -1;
|
||||||
IPPROTO_TCP :: 6
|
IPPROTO_TCP :: 6;
|
||||||
AI_PASSIVE :: 0x0020
|
AI_PASSIVE :: 0x0020;
|
||||||
SOMAXCONN :: 128
|
SOMAXCONN :: 128;
|
||||||
|
|
||||||
SD_RECEIVE :: 0
|
SD_RECEIVE :: 0;
|
||||||
SD_SEND :: 1
|
SD_SEND :: 1;
|
||||||
SD_BOTH :: 2
|
SD_BOTH :: 2;
|
||||||
|
|
||||||
WSADESCRIPTION_LEN :: 256
|
WSADESCRIPTION_LEN :: 256;
|
||||||
WSASYS_STATUS_LEN :: 128
|
WSASYS_STATUS_LEN :: 128;
|
||||||
WSADATA :: struct #ordered {
|
WSADATA :: struct #ordered {
|
||||||
version: i16
|
version: i16;
|
||||||
high_version: i16
|
high_version: i16;
|
||||||
|
|
||||||
|
|
||||||
// NOTE(bill): This is x64 ordering
|
// NOTE(bill): This is x64 ordering
|
||||||
max_sockets: u16
|
max_sockets: u16;
|
||||||
max_udp_dg: u16
|
max_udp_dg: u16;
|
||||||
vendor_info: ^byte
|
vendor_info: ^byte;
|
||||||
description: [WSADESCRIPTION_LEN+1]byte
|
description: [WSADESCRIPTION_LEN+1]byte;
|
||||||
system_status: [WSASYS_STATUS_LEN+1]byte
|
system_status: [WSASYS_STATUS_LEN+1]byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
addrinfo :: struct #ordered {
|
addrinfo :: struct #ordered {
|
||||||
flags: i32
|
flags: i32;
|
||||||
family: i32
|
family: i32;
|
||||||
socktype: i32
|
socktype: i32;
|
||||||
protocol: i32
|
protocol: i32;
|
||||||
addrlen: uint
|
addrlen: uint;
|
||||||
canonname: ^u8
|
canonname: ^u8;
|
||||||
addr: ^sockaddr
|
addr: ^sockaddr;
|
||||||
next: ^addrinfo
|
next: ^addrinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
sockaddr :: struct #ordered {
|
sockaddr :: struct #ordered {
|
||||||
family: u16
|
family: u16;
|
||||||
data: [14]byte
|
data: [14]byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -94,52 +94,52 @@ shutdown :: proc(s: SOCKET, how: i32) -> i32
|
|||||||
WSAGetLastError :: proc() -> i32 #foreign #dll_import
|
WSAGetLastError :: proc() -> i32 #foreign #dll_import
|
||||||
|
|
||||||
to_c_string :: proc(s: string) -> ^byte {
|
to_c_string :: proc(s: string) -> ^byte {
|
||||||
c_str := new_slice(byte, s.count+1)
|
c_str := new_slice(byte, s.count+1);
|
||||||
assert(c_str.data != null)
|
assert(c_str.data != nil);
|
||||||
copy(c_str, s as []byte)
|
copy(c_str, s as []byte);
|
||||||
c_str[s.count] = 0
|
c_str[s.count] = 0;
|
||||||
return c_str.data
|
return c_str.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
run :: proc() {
|
run :: proc() {
|
||||||
wsa: WSADATA
|
wsa: WSADATA;
|
||||||
res: ^addrinfo = null
|
res: ^addrinfo = nil;
|
||||||
hints: addrinfo
|
hints: addrinfo;
|
||||||
s, client: SOCKET
|
s, client: SOCKET;
|
||||||
|
|
||||||
if WSAStartup(2 | (2 << 8), ^wsa) != 0 {
|
if WSAStartup(2 | (2 << 8), ^wsa) != 0 {
|
||||||
fmt.println("WSAStartup failed: ", WSAGetLastError())
|
fmt.println("WSAStartup failed: ", WSAGetLastError());
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
defer WSACleanup()
|
defer WSACleanup();
|
||||||
|
|
||||||
hints.family = AF.INET as i32
|
hints.family = AF.INET as i32;
|
||||||
hints.socktype = SOCK_STREAM
|
hints.socktype = SOCK_STREAM;
|
||||||
hints.protocol = IPPROTO_TCP
|
hints.protocol = IPPROTO_TCP;
|
||||||
hints.flags = AI_PASSIVE
|
hints.flags = AI_PASSIVE;
|
||||||
|
|
||||||
if getaddrinfo(null, to_c_string("8080"), ^hints, ^res) != 0 {
|
if getaddrinfo(nil, to_c_string("8080"), ^hints, ^res) != 0 {
|
||||||
fmt.println("getaddrinfo failed: ", WSAGetLastError())
|
fmt.println("getaddrinfo failed: ", WSAGetLastError());
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
defer freeaddrinfo(res)
|
defer freeaddrinfo(res);
|
||||||
|
|
||||||
s = socket(res.family, res.socktype, res.protocol)
|
s = socket(res.family, res.socktype, res.protocol);
|
||||||
if s == INVALID_SOCKET {
|
if s == INVALID_SOCKET {
|
||||||
fmt.println("socket failed: ", WSAGetLastError())
|
fmt.println("socket failed: ", WSAGetLastError());
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
defer closesocket(s)
|
defer closesocket(s);
|
||||||
|
|
||||||
bind(s, res.addr, res.addrlen as i32)
|
bind(s, res.addr, res.addrlen as i32);
|
||||||
listen(s, SOMAXCONN)
|
listen(s, SOMAXCONN);
|
||||||
|
|
||||||
client = accept(s, null, null)
|
client = accept(s, nil, 0);
|
||||||
if client == INVALID_SOCKET {
|
if client == INVALID_SOCKET {
|
||||||
fmt.println("socket failed: ", WSAGetLastError())
|
fmt.println("socket failed: ", WSAGetLastError());
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
defer closesocket(client)
|
defer closesocket(client);
|
||||||
|
|
||||||
html :=
|
html :=
|
||||||
`HTTP/1.1 200 OK
|
`HTTP/1.1 200 OK
|
||||||
@@ -154,27 +154,27 @@ Content-type: text/html
|
|||||||
<h1 style="color: orange;">Odin Server Demo</h1>
|
<h1 style="color: orange;">Odin Server Demo</h1>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`
|
`;
|
||||||
|
|
||||||
buf: [1024]byte
|
buf: [1024]byte;
|
||||||
for {
|
for {
|
||||||
bytes := recv(client, ^buf[0], buf.count as i32, 0)
|
bytes := recv(client, ^buf[0], buf.count as i32, 0);
|
||||||
if bytes > 0 {
|
if bytes > 0 {
|
||||||
// fmt.println(buf[:bytes] as string)
|
// fmt.println(buf[:bytes] as string);
|
||||||
bytes_sent := send(client, html.data, (html.count-1) as i32, 0)
|
bytes_sent := send(client, html.data, (html.count-1) as i32, 0);
|
||||||
if bytes_sent == SOCKET_ERROR {
|
if bytes_sent == SOCKET_ERROR {
|
||||||
fmt.println("send failed: ", WSAGetLastError())
|
fmt.println("send failed: ", WSAGetLastError());
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
} else if bytes == 0 {
|
} else if bytes == 0 {
|
||||||
fmt.println("Connection closing...")
|
fmt.println("Connection closing...");
|
||||||
break
|
break;
|
||||||
} else {
|
} else {
|
||||||
fmt.println("recv failed: ", WSAGetLastError())
|
fmt.println("recv failed: ", WSAGetLastError());
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shutdown(client, SD_SEND)
|
shutdown(client, SD_SEND);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -301,7 +301,7 @@ namespaces_and_files :: proc() {
|
|||||||
#import "file.odin" as _
|
#import "file.odin" as _
|
||||||
|
|
||||||
// Exporting import
|
// Exporting import
|
||||||
#load "file.odin"
|
#include "file.odin"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Talk about scope rules and diagram
|
// Talk about scope rules and diagram
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Demo 002
|
// Demo 002
|
||||||
#load "basic.odin"
|
#include "basic.odin"
|
||||||
#load "math.odin"
|
#include "math.odin"
|
||||||
// #load "game.odin"
|
// #include "game.odin"
|
||||||
|
|
||||||
#thread_local tls_int: int
|
#thread_local tls_int: int
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#load "win32.odin"
|
#include "win32.odin"
|
||||||
|
|
||||||
assume :: proc(cond: bool) #foreign "llvm.assume"
|
assume :: proc(cond: bool) #foreign "llvm.assume"
|
||||||
|
|
||||||
|
|||||||
+138
-140
@@ -1,34 +1,34 @@
|
|||||||
#import "win32.odin"
|
#import "win32.odin";
|
||||||
#import "fmt.odin"
|
#import "fmt.odin";
|
||||||
#import "os.odin"
|
#import "os.odin";
|
||||||
|
|
||||||
CANVAS_WIDTH :: 128
|
CANVAS_WIDTH :: 128;
|
||||||
CANVAS_HEIGHT :: 128
|
CANVAS_HEIGHT :: 128;
|
||||||
CANVAS_SCALE :: 3
|
CANVAS_SCALE :: 3;
|
||||||
FRAME_TIME :: 1.0/30.0
|
FRAME_TIME :: 1.0/30.0;
|
||||||
WINDOW_TITLE : string : "Punity\x00"
|
WINDOW_TITLE :: "Punity\x00";
|
||||||
|
|
||||||
_ := compile_assert(CANVAS_WIDTH % 16 == 0)
|
_ := compile_assert(CANVAS_WIDTH % 16 == 0);
|
||||||
|
|
||||||
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE
|
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE;
|
||||||
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE
|
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE;
|
||||||
|
|
||||||
|
|
||||||
STACK_CAPACITY :: 1<<20
|
STACK_CAPACITY :: 1<<20;
|
||||||
STORAGE_CAPACITY :: 1<<20
|
STORAGE_CAPACITY :: 1<<20;
|
||||||
|
|
||||||
DRAW_LIST_RESERVE :: 128
|
DRAW_LIST_RESERVE :: 128;
|
||||||
|
|
||||||
MAX_KEYS :: 256
|
MAX_KEYS :: 256;
|
||||||
|
|
||||||
Core :: struct {
|
Core :: struct {
|
||||||
stack: ^Bank
|
stack: ^Bank;
|
||||||
storage: ^Bank
|
storage: ^Bank;
|
||||||
|
|
||||||
running: bool
|
running: bool;
|
||||||
key_modifiers: u32
|
key_modifiers: u32;
|
||||||
key_states: [MAX_KEYS]byte
|
key_states: [MAX_KEYS]byte;
|
||||||
key_deltas: [MAX_KEYS]byte
|
key_deltas: [MAX_KEYS]byte;
|
||||||
|
|
||||||
perf_frame,
|
perf_frame,
|
||||||
perf_frame_inner,
|
perf_frame_inner,
|
||||||
@@ -36,70 +36,70 @@ Core :: struct {
|
|||||||
perf_audio,
|
perf_audio,
|
||||||
perf_blit,
|
perf_blit,
|
||||||
perf_blit_cvt,
|
perf_blit_cvt,
|
||||||
perf_blit_gdi: Perf_Span
|
perf_blit_gdi: Perf_Span;
|
||||||
|
|
||||||
frame: i64
|
frame: i64;
|
||||||
|
|
||||||
canvas: Canvas
|
canvas: Canvas;
|
||||||
draw_list: ^Draw_List
|
draw_list: ^Draw_List;
|
||||||
}
|
}
|
||||||
|
|
||||||
Perf_Span :: struct {
|
Perf_Span :: struct {
|
||||||
stamp: f64
|
stamp: f64;
|
||||||
delta: f32
|
delta: f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bank :: struct {
|
Bank :: struct {
|
||||||
memory: []byte
|
memory: []byte;
|
||||||
cursor: int
|
cursor: int;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bank_State :: struct {
|
Bank_State :: struct {
|
||||||
state: Bank
|
state: Bank;
|
||||||
bank: ^Bank
|
bank: ^Bank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Color :: raw_union {
|
Color :: raw_union {
|
||||||
using channels: struct{ a, b, g, r: byte }
|
using channels: struct{ a, b, g, r: byte; };
|
||||||
rgba: u32
|
rgba: u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
Palette :: struct {
|
Palette :: struct {
|
||||||
colors: [256]Color
|
colors: [256]Color;
|
||||||
colors_count: byte
|
colors_count: byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Rect :: raw_union {
|
Rect :: raw_union {
|
||||||
using minmax: struct {
|
using minmax: struct {
|
||||||
min_x, min_y, max_x, max_y: int
|
min_x, min_y, max_x, max_y: int;
|
||||||
}
|
};
|
||||||
using pos: struct {
|
using pos: struct {
|
||||||
left, top, right, bottom: int
|
left, top, right, bottom: int;
|
||||||
}
|
};
|
||||||
e: [4]int
|
e: [4]int;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bitmap :: struct {
|
Bitmap :: struct {
|
||||||
pixels: []byte
|
pixels: []byte;
|
||||||
width: int
|
width: int;
|
||||||
height: int
|
height: int;
|
||||||
}
|
}
|
||||||
|
|
||||||
Font :: struct {
|
Font :: struct {
|
||||||
using bitmap: Bitmap
|
using bitmap: Bitmap;
|
||||||
char_width: int
|
char_width: int;
|
||||||
char_height: int
|
char_height: int;
|
||||||
}
|
}
|
||||||
|
|
||||||
Canvas :: struct {
|
Canvas :: struct {
|
||||||
using bitmap: ^Bitmap
|
using bitmap: ^Bitmap;
|
||||||
palette: Palette
|
palette: Palette;
|
||||||
translate_x: int
|
translate_x: int;
|
||||||
translate_y: int
|
translate_y: int;
|
||||||
clip: Rect
|
clip: Rect;
|
||||||
font: ^Font
|
font: ^Font;
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawFlag :: enum {
|
DrawFlag :: enum {
|
||||||
@@ -114,7 +114,7 @@ Draw_List :: struct {
|
|||||||
Item :: struct {
|
Item :: struct {
|
||||||
|
|
||||||
}
|
}
|
||||||
items: []Item
|
items: []Item;
|
||||||
}
|
}
|
||||||
|
|
||||||
Key :: enum {
|
Key :: enum {
|
||||||
@@ -272,37 +272,36 @@ Key :: enum {
|
|||||||
|
|
||||||
|
|
||||||
key_down :: proc(k: Key) -> bool {
|
key_down :: proc(k: Key) -> bool {
|
||||||
return _core.key_states[k] != 0
|
return _core.key_states[k] != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
key_pressed :: proc(k: Key) -> bool {
|
key_pressed :: proc(k: Key) -> bool {
|
||||||
return (_core.key_deltas[k] != 0) && key_down(k)
|
return (_core.key_deltas[k] != 0) && key_down(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
win32_perf_count_freq := win32.GetQueryPerformanceFrequency()
|
win32_perf_count_freq := win32.GetQueryPerformanceFrequency();
|
||||||
time_now :: proc() -> f64 {
|
time_now :: proc() -> f64 {
|
||||||
assert(win32_perf_count_freq != 0)
|
assert(win32_perf_count_freq != 0);
|
||||||
|
|
||||||
counter: i64
|
counter: i64;
|
||||||
win32.QueryPerformanceCounter(^counter)
|
win32.QueryPerformanceCounter(^counter);
|
||||||
result := counter as f64 / win32_perf_count_freq as f64
|
result := counter as f64 / win32_perf_count_freq as f64;
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
_core: Core
|
_core: Core;
|
||||||
|
|
||||||
run :: proc(user_init, user_step: proc(c: ^Core)) {
|
run :: proc(user_init, user_step: proc(c: ^Core)) {
|
||||||
using win32
|
using win32;
|
||||||
|
|
||||||
|
_core.running = true;
|
||||||
_core.running = true
|
|
||||||
|
|
||||||
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline #stdcall {
|
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline #stdcall {
|
||||||
win32_app_key_mods :: proc() -> u32 {
|
win32_app_key_mods :: proc() -> u32 {
|
||||||
mods: u32 = 0
|
mods: u32 = 0;
|
||||||
|
|
||||||
if is_key_down(Key_Code.SHIFT) {
|
if is_key_down(Key_Code.SHIFT) {
|
||||||
mods |= Key.MOD_SHIFT as u32;
|
mods |= Key.MOD_SHIFT as u32;
|
||||||
@@ -317,33 +316,33 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
|
|||||||
mods |= Key.MOD_SUPER as u32;
|
mods |= Key.MOD_SUPER as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mods
|
return mods;
|
||||||
}
|
}
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
case WM_KEYDOWN:
|
case WM_KEYDOWN:
|
||||||
_core.key_modifiers = win32_app_key_mods()
|
_core.key_modifiers = win32_app_key_mods();
|
||||||
if wparam < MAX_KEYS {
|
if wparam < MAX_KEYS {
|
||||||
_core.key_states[wparam] = 1
|
_core.key_states[wparam] = 1;
|
||||||
_core.key_deltas[wparam] = 1
|
_core.key_deltas[wparam] = 1;
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
|
|
||||||
case WM_KEYUP:
|
case WM_KEYUP:
|
||||||
_core.key_modifiers = win32_app_key_mods()
|
_core.key_modifiers = win32_app_key_mods();
|
||||||
if wparam < MAX_KEYS {
|
if wparam < MAX_KEYS {
|
||||||
_core.key_states[wparam] = 0
|
_core.key_states[wparam] = 0;
|
||||||
_core.key_deltas[wparam] = 1
|
_core.key_deltas[wparam] = 1;
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
|
|
||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
PostQuitMessage(0)
|
PostQuitMessage(0);
|
||||||
_core.running = false
|
_core.running = false;
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefWindowProcA(hwnd, msg, wparam, lparam)
|
return DefWindowProcA(hwnd, msg, wparam, lparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -351,30 +350,30 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
|
|||||||
class_name = ("Punity\x00" as string).data, // C-style string
|
class_name = ("Punity\x00" as string).data, // C-style string
|
||||||
size = size_of(WNDCLASSEXA) as u32,
|
size = size_of(WNDCLASSEXA) as u32,
|
||||||
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
||||||
instance = GetModuleHandleA(null) as HINSTANCE,
|
instance = GetModuleHandleA(nil) as HINSTANCE,
|
||||||
wnd_proc = win32_proc,
|
wnd_proc = win32_proc,
|
||||||
// wnd_proc = DefWindowProcA,
|
// wnd_proc = DefWindowProcA,
|
||||||
background = GetStockObject(BLACK_BRUSH) as HBRUSH,
|
background = GetStockObject(BLACK_BRUSH) as HBRUSH,
|
||||||
}
|
};
|
||||||
|
|
||||||
if RegisterClassExA(^window_class) == 0 {
|
if RegisterClassExA(^window_class) == 0 {
|
||||||
fmt.fprintln(os.stderr, "RegisterClassExA failed")
|
fmt.fprintln(os.stderr, "RegisterClassExA failed");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
screen_width := GetSystemMetrics(SM_CXSCREEN)
|
screen_width := GetSystemMetrics(SM_CXSCREEN);
|
||||||
screen_height := GetSystemMetrics(SM_CYSCREEN)
|
screen_height := GetSystemMetrics(SM_CYSCREEN);
|
||||||
|
|
||||||
rc: RECT
|
rc: RECT;
|
||||||
rc.left = (screen_width - WINDOW_WIDTH) / 2
|
rc.left = (screen_width - WINDOW_WIDTH) / 2;
|
||||||
rc.top = (screen_height - WINDOW_HEIGHT) / 2
|
rc.top = (screen_height - WINDOW_HEIGHT) / 2;
|
||||||
rc.right = rc.left + WINDOW_WIDTH
|
rc.right = rc.left + WINDOW_WIDTH;
|
||||||
rc.bottom = rc.top + WINDOW_HEIGHT
|
rc.bottom = rc.top + WINDOW_HEIGHT;
|
||||||
|
|
||||||
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
|
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
|
||||||
assert(AdjustWindowRect(^rc, style, 0) != 0)
|
assert(AdjustWindowRect(^rc, style, 0) != 0);
|
||||||
|
|
||||||
wt := WINDOW_TITLE
|
wt := WINDOW_TITLE;
|
||||||
|
|
||||||
win32_window := CreateWindowExA(0,
|
win32_window := CreateWindowExA(0,
|
||||||
window_class.class_name,
|
window_class.class_name,
|
||||||
@@ -382,83 +381,82 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
|
|||||||
style,
|
style,
|
||||||
rc.left, rc.top,
|
rc.left, rc.top,
|
||||||
rc.right-rc.left, rc.bottom-rc.top,
|
rc.right-rc.left, rc.bottom-rc.top,
|
||||||
null, null, window_class.instance,
|
nil, nil, window_class.instance,
|
||||||
null);
|
nil);
|
||||||
|
|
||||||
if win32_window == null {
|
if win32_window == nil {
|
||||||
fmt.fprintln(os.stderr, "CreateWindowExA failed")
|
fmt.fprintln(os.stderr, "CreateWindowExA failed");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
window_bmi: BITMAPINFO;
|
window_bmi: BITMAPINFO;
|
||||||
window_bmi.size = size_of(BITMAPINFO.HEADER) as u32
|
window_bmi.size = size_of(BITMAPINFO.HEADER) as u32;
|
||||||
window_bmi.width = CANVAS_WIDTH
|
window_bmi.width = CANVAS_WIDTH;
|
||||||
window_bmi.height = CANVAS_HEIGHT
|
window_bmi.height = CANVAS_HEIGHT;
|
||||||
window_bmi.planes = 1
|
window_bmi.planes = 1;
|
||||||
window_bmi.bit_count = 32
|
window_bmi.bit_count = 32;
|
||||||
window_bmi.compression = BI_RGB
|
window_bmi.compression = BI_RGB;
|
||||||
|
|
||||||
|
|
||||||
user_init(^_core)
|
user_init(^_core);
|
||||||
|
|
||||||
|
|
||||||
ShowWindow(win32_window, SW_SHOW)
|
ShowWindow(win32_window, SW_SHOW);
|
||||||
|
|
||||||
window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT);
|
window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT);
|
||||||
assert(window_buffer.data != null)
|
assert(window_buffer.data != nil);
|
||||||
defer free(window_buffer.data)
|
defer free(window_buffer.data);
|
||||||
|
|
||||||
for i := 0; i < window_buffer.count; i++ {
|
for i := 0; i < window_buffer.count; i++ {
|
||||||
window_buffer[i] = 0xff00ff
|
window_buffer[i] = 0xff00ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
prev_time, curr_time,dt: f64
|
prev_time, curr_time,dt: f64;
|
||||||
prev_time = time_now()
|
prev_time = time_now();
|
||||||
curr_time = time_now()
|
curr_time = time_now();
|
||||||
total_time : f64 = 0
|
total_time : f64 = 0;
|
||||||
offset_x := 0;
|
offset_x := 0;
|
||||||
offset_y := 0;
|
offset_y := 0;
|
||||||
|
|
||||||
message: MSG
|
message: MSG;
|
||||||
for _core.running {
|
for _core.running {
|
||||||
curr_time = time_now()
|
curr_time = time_now();
|
||||||
dt = curr_time - prev_time
|
dt = curr_time - prev_time;
|
||||||
prev_time = curr_time
|
prev_time = curr_time;
|
||||||
total_time += dt
|
total_time += dt;
|
||||||
|
|
||||||
offset_x += 1
|
offset_x += 1;
|
||||||
offset_y += 2
|
offset_y += 2;
|
||||||
|
|
||||||
{
|
{
|
||||||
data: [128]byte
|
data: [128]byte;
|
||||||
buf := data[:0]
|
buf := data[:0];
|
||||||
fmt.bprintf(^buf, "Punity: % ms\x00", dt*1000)
|
fmt.bprintf(^buf, "Punity: % ms\x00", dt*1000);
|
||||||
win32.SetWindowTextA(win32_window, buf.data)
|
win32.SetWindowTextA(win32_window, buf.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for y := 0; y < CANVAS_HEIGHT; y++ {
|
for y := 0; y < CANVAS_HEIGHT; y++ {
|
||||||
for x := 0; x < CANVAS_WIDTH; x++ {
|
for x := 0; x < CANVAS_WIDTH; x++ {
|
||||||
g := (x % 32) * 8
|
g := (x % 32) * 8;
|
||||||
b := (y % 32) * 8
|
b := (y % 32) * 8;
|
||||||
window_buffer[x + y*CANVAS_WIDTH] = (g << 8 | b) as u32
|
window_buffer[x + y*CANVAS_WIDTH] = (g << 8 | b) as u32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_zero(^_core.key_deltas[0], size_of_val(_core.key_deltas[0]))
|
_core.key_deltas = nil;
|
||||||
|
|
||||||
|
for PeekMessageA(^message, nil, 0, 0, PM_REMOVE) != 0 {
|
||||||
for PeekMessageA(^message, null, 0, 0, PM_REMOVE) != 0 {
|
|
||||||
if message.message == WM_QUIT {
|
if message.message == WM_QUIT {
|
||||||
_core.running = false
|
_core.running = false;
|
||||||
}
|
}
|
||||||
TranslateMessage(^message)
|
TranslateMessage(^message);
|
||||||
DispatchMessageA(^message)
|
DispatchMessageA(^message);
|
||||||
}
|
}
|
||||||
|
|
||||||
user_step(^_core)
|
user_step(^_core);
|
||||||
|
|
||||||
dc := GetDC(win32_window);
|
dc := GetDC(win32_window);
|
||||||
StretchDIBits(dc,
|
StretchDIBits(dc,
|
||||||
@@ -467,18 +465,18 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
|
|||||||
window_buffer.data,
|
window_buffer.data,
|
||||||
^window_bmi,
|
^window_bmi,
|
||||||
DIB_RGB_COLORS,
|
DIB_RGB_COLORS,
|
||||||
SRCCOPY)
|
SRCCOPY);
|
||||||
ReleaseDC(win32_window, dc)
|
ReleaseDC(win32_window, dc);
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
delta := time_now() - prev_time
|
delta := time_now() - prev_time;
|
||||||
ms := ((FRAME_TIME - delta) * 1000) as i32
|
ms := ((FRAME_TIME - delta) * 1000) as i32;
|
||||||
if ms > 0 {
|
if ms > 0 {
|
||||||
win32.Sleep(ms)
|
win32.Sleep(ms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_core.frame++
|
_core.frame++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ thing :: proc() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#load "fmt.odin"
|
#include "fmt.odin"
|
||||||
|
|
||||||
thing :: proc() {
|
thing :: proc() {
|
||||||
println("Hello5!")
|
println("Hello5!")
|
||||||
|
|||||||
+147
-169
@@ -1,109 +1,86 @@
|
|||||||
#shared_global_scope
|
#shared_global_scope;
|
||||||
|
|
||||||
#import "os.odin"
|
#import "os.odin";
|
||||||
#import "fmt.odin"
|
#import "fmt.odin";
|
||||||
#import "mem.odin"
|
#import "mem.odin";
|
||||||
|
|
||||||
/*
|
|
||||||
Optimization_Level :: enum {
|
|
||||||
DEBUG,
|
|
||||||
RELEASE,
|
|
||||||
}
|
|
||||||
|
|
||||||
Bounds_Check_Mode :: enum {
|
|
||||||
ON,
|
|
||||||
OFF,
|
|
||||||
}
|
|
||||||
|
|
||||||
Build_Options :: struct {
|
|
||||||
optimization_level: Optimization_Level
|
|
||||||
|
|
||||||
bounds_check: Bounds_Check_Mode
|
|
||||||
|
|
||||||
output_name: string
|
|
||||||
output_path: string
|
|
||||||
}
|
|
||||||
|
|
||||||
build_options: Build_Options
|
|
||||||
*/
|
|
||||||
|
|
||||||
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
||||||
// The compiler relies upon this _exact_ order
|
// The compiler relies upon this _exact_ order
|
||||||
Type_Info :: union {
|
Type_Info :: union {
|
||||||
Member :: struct #ordered {
|
Member :: struct #ordered {
|
||||||
name: string // can be empty if tuple
|
name: string; // can be empty if tuple
|
||||||
type_info: ^Type_Info
|
type_info: ^Type_Info;
|
||||||
offset: int // offsets are not used in tuples
|
offset: int; // offsets are not used in tuples
|
||||||
}
|
}
|
||||||
Record :: struct #ordered {
|
Record :: struct #ordered {
|
||||||
fields: []Member
|
fields: []Member;
|
||||||
size: int // in bytes
|
size: int; // in bytes
|
||||||
align: int // in bytes
|
align: int; // in bytes
|
||||||
packed: bool
|
packed: bool;
|
||||||
ordered: bool
|
ordered: bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
Named: struct #ordered {
|
Named: struct #ordered {
|
||||||
name: string
|
name: string;
|
||||||
base: ^Type_Info // This will _not_ be a Type_Info.Named
|
base: ^Type_Info; // This will _not_ be a Type_Info.Named
|
||||||
}
|
};
|
||||||
Integer: struct #ordered {
|
Integer: struct #ordered {
|
||||||
size: int // in bytes
|
size: int; // in bytes
|
||||||
signed: bool
|
signed: bool;
|
||||||
}
|
};
|
||||||
Float: struct #ordered {
|
Float: struct #ordered {
|
||||||
size: int // in bytes
|
size: int; // in bytes
|
||||||
}
|
};
|
||||||
Any: struct #ordered {}
|
Any: struct #ordered {};
|
||||||
String: struct #ordered {}
|
String: struct #ordered {};
|
||||||
Boolean: struct #ordered {}
|
Boolean: struct #ordered {};
|
||||||
Pointer: struct #ordered {
|
Pointer: struct #ordered {
|
||||||
elem: ^Type_Info // nil -> rawptr
|
elem: ^Type_Info; // nil -> rawptr
|
||||||
}
|
};
|
||||||
Maybe: struct #ordered {
|
Maybe: struct #ordered {
|
||||||
elem: ^Type_Info
|
elem: ^Type_Info;
|
||||||
}
|
};
|
||||||
Procedure: struct #ordered {
|
Procedure: struct #ordered {
|
||||||
params: ^Type_Info // Type_Info.Tuple
|
params: ^Type_Info; // Type_Info.Tuple
|
||||||
results: ^Type_Info // Type_Info.Tuple
|
results: ^Type_Info; // Type_Info.Tuple
|
||||||
variadic: bool
|
variadic: bool;
|
||||||
}
|
};
|
||||||
Array: struct #ordered {
|
Array: struct #ordered {
|
||||||
elem: ^Type_Info
|
elem: ^Type_Info;
|
||||||
elem_size: int
|
elem_size: int;
|
||||||
count: int
|
count: int;
|
||||||
}
|
};
|
||||||
Slice: struct #ordered {
|
Slice: struct #ordered {
|
||||||
elem: ^Type_Info
|
elem: ^Type_Info;
|
||||||
elem_size: int
|
elem_size: int;
|
||||||
}
|
};
|
||||||
Vector: struct #ordered {
|
Vector: struct #ordered {
|
||||||
elem: ^Type_Info
|
elem: ^Type_Info;
|
||||||
elem_size: int
|
elem_size: int;
|
||||||
count: int
|
count: int;
|
||||||
align: int
|
align: int;
|
||||||
}
|
};
|
||||||
Tuple: Record
|
Tuple: Record;
|
||||||
Struct: Record
|
Struct: Record;
|
||||||
Union: Record
|
Union: Record;
|
||||||
Raw_Union: Record
|
Raw_Union: Record;
|
||||||
Enum: struct #ordered {
|
Enum: struct #ordered {
|
||||||
base: ^Type_Info
|
base: ^Type_Info;
|
||||||
values: []i64
|
values: []i64;
|
||||||
names: []string
|
names: []string;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
||||||
if info == nil {
|
if info == nil {
|
||||||
return nil
|
return nil;
|
||||||
}
|
}
|
||||||
base := info
|
base := info;
|
||||||
match type i : base {
|
match type i : base {
|
||||||
case Type_Info.Named:
|
case Type_Info.Named:
|
||||||
base = i.base
|
base = i.base;
|
||||||
}
|
}
|
||||||
return base
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -144,145 +121,146 @@ Allocator :: struct #ordered {
|
|||||||
|
|
||||||
|
|
||||||
procedure: Proc;
|
procedure: Proc;
|
||||||
data: rawptr
|
data: rawptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Context :: struct #ordered {
|
Context :: struct #ordered {
|
||||||
thread_id: int
|
thread_id: int;
|
||||||
|
|
||||||
allocator: Allocator
|
allocator: Allocator;
|
||||||
|
|
||||||
user_data: rawptr
|
user_data: rawptr;
|
||||||
user_index: int
|
user_index: int;
|
||||||
}
|
}
|
||||||
|
|
||||||
#thread_local __context: Context
|
#thread_local __context: Context;
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_ALIGNMENT :: align_of([vector 4]f32)
|
DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
|
||||||
|
|
||||||
|
|
||||||
__check_context :: proc() {
|
__check_context :: proc() {
|
||||||
c := ^__context
|
c := ^__context;
|
||||||
|
|
||||||
if c.allocator.procedure == nil {
|
if c.allocator.procedure == nil {
|
||||||
c.allocator = default_allocator()
|
c.allocator = default_allocator();
|
||||||
}
|
}
|
||||||
if c.thread_id == 0 {
|
if c.thread_id == 0 {
|
||||||
c.thread_id = os.current_thread_id()
|
c.thread_id = os.current_thread_id();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT) }
|
alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT); }
|
||||||
|
|
||||||
alloc_align :: proc(size, alignment: int) -> rawptr #inline {
|
alloc_align :: proc(size, alignment: int) -> rawptr #inline {
|
||||||
__check_context()
|
__check_context();
|
||||||
a := context.allocator
|
a := context.allocator;
|
||||||
return a.procedure(a.data, Allocator.Mode.ALLOC, size, alignment, nil, 0, 0)
|
return a.procedure(a.data, Allocator.Mode.ALLOC, size, alignment, nil, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
free :: proc(ptr: rawptr) #inline {
|
free :: proc(ptr: rawptr) #inline {
|
||||||
__check_context()
|
__check_context();
|
||||||
a := context.allocator
|
a := context.allocator;
|
||||||
if ptr != nil {
|
if ptr != nil {
|
||||||
a.procedure(a.data, Allocator.Mode.FREE, 0, 0, ptr, 0, 0)
|
a.procedure(a.data, Allocator.Mode.FREE, 0, 0, ptr, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free_all :: proc() #inline {
|
free_all :: proc() #inline {
|
||||||
__check_context()
|
__check_context();
|
||||||
a := context.allocator
|
a := context.allocator;
|
||||||
a.procedure(a.data, Allocator.Mode.FREE_ALL, 0, 0, nil, 0, 0)
|
a.procedure(a.data, Allocator.Mode.FREE_ALL, 0, 0, nil, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) }
|
resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT); }
|
||||||
resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
|
resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
|
||||||
__check_context()
|
__check_context();
|
||||||
a := context.allocator
|
a := context.allocator;
|
||||||
return a.procedure(a.data, Allocator.Mode.RESIZE, new_size, alignment, ptr, old_size, 0)
|
return a.procedure(a.data, Allocator.Mode.RESIZE, new_size, alignment, ptr, old_size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
|
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
|
||||||
if old_memory == nil {
|
if old_memory == nil {
|
||||||
return alloc_align(new_size, alignment)
|
return alloc_align(new_size, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_size == 0 {
|
if new_size == 0 {
|
||||||
free(old_memory)
|
free(old_memory);
|
||||||
return nil
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_size == old_size {
|
if new_size == old_size {
|
||||||
return old_memory
|
return old_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_memory := alloc_align(new_size, alignment)
|
new_memory := alloc_align(new_size, alignment);
|
||||||
if new_memory == nil {
|
if new_memory == nil {
|
||||||
return nil
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
mem.copy(new_memory, old_memory, min(old_size, new_size));
|
mem.copy(new_memory, old_memory, min(old_size, new_size));;
|
||||||
free(old_memory)
|
free(old_memory);
|
||||||
return new_memory
|
return new_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||||
using Allocator.Mode
|
using Allocator.Mode;
|
||||||
/*
|
when false {
|
||||||
match mode {
|
match mode {
|
||||||
case ALLOC:
|
case ALLOC:
|
||||||
total_size := size + alignment + size_of(mem.AllocationHeader)
|
total_size := size + alignment + size_of(mem.AllocationHeader);
|
||||||
ptr := os.heap_alloc(total_size)
|
ptr := os.heap_alloc(total_size);
|
||||||
header := ptr as ^mem.AllocationHeader
|
header := ptr as ^mem.AllocationHeader;
|
||||||
ptr = mem.align_forward(header+1, alignment)
|
ptr = mem.align_forward(header+1, alignment);
|
||||||
mem.allocation_header_fill(header, ptr, size)
|
mem.allocation_header_fill(header, ptr, size);
|
||||||
return mem.zero(ptr, size)
|
return mem.zero(ptr, size);
|
||||||
|
|
||||||
case FREE:
|
case FREE:
|
||||||
os.heap_free(mem.allocation_header(old_memory))
|
os.heap_free(mem.allocation_header(old_memory));
|
||||||
return nil
|
return nil;
|
||||||
|
|
||||||
case FREE_ALL:
|
case FREE_ALL:
|
||||||
// NOTE(bill): Does nothing
|
// NOTE(bill): Does nothing
|
||||||
|
|
||||||
case RESIZE:
|
case RESIZE:
|
||||||
total_size := size + alignment + size_of(mem.AllocationHeader)
|
total_size := size + alignment + size_of(mem.AllocationHeader);
|
||||||
ptr := os.heap_resize(mem.allocation_header(old_memory), total_size)
|
ptr := os.heap_resize(mem.allocation_header(old_memory), total_size);
|
||||||
header := ptr as ^mem.AllocationHeader
|
header := ptr as ^mem.AllocationHeader;
|
||||||
ptr = mem.align_forward(header+1, alignment)
|
ptr = mem.align_forward(header+1, alignment);
|
||||||
mem.allocation_header_fill(header, ptr, size)
|
mem.allocation_header_fill(header, ptr, size);
|
||||||
return mem.zero(ptr, size)
|
return mem.zero(ptr, size);
|
||||||
}
|
}
|
||||||
*/
|
} else {
|
||||||
match mode {
|
match mode {
|
||||||
case ALLOC:
|
case ALLOC:
|
||||||
return os.heap_alloc(size)
|
return os.heap_alloc(size);
|
||||||
|
|
||||||
case FREE:
|
case FREE:
|
||||||
os.heap_free(old_memory)
|
os.heap_free(old_memory);
|
||||||
return nil
|
return nil;
|
||||||
|
|
||||||
case FREE_ALL:
|
case FREE_ALL:
|
||||||
// NOTE(bill): Does nothing
|
// NOTE(bill): Does nothing
|
||||||
|
|
||||||
case RESIZE:
|
case RESIZE:
|
||||||
return os.heap_resize(old_memory, size)
|
return os.heap_resize(old_memory, size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
default_allocator :: proc() -> Allocator {
|
default_allocator :: proc() -> Allocator {
|
||||||
return Allocator{
|
return Allocator{
|
||||||
procedure = default_allocator_proc,
|
procedure = default_allocator_proc,
|
||||||
data = nil,
|
data = nil,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -297,58 +275,58 @@ default_allocator :: proc() -> Allocator {
|
|||||||
|
|
||||||
__string_eq :: proc(a, b: string) -> bool {
|
__string_eq :: proc(a, b: string) -> bool {
|
||||||
if a.count != b.count {
|
if a.count != b.count {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
if a.data == b.data {
|
if a.data == b.data {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
return mem.compare(a.data, b.data, a.count) == 0
|
return mem.compare(a.data, b.data, a.count) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__string_cmp :: proc(a, b : string) -> int {
|
__string_cmp :: proc(a, b : string) -> int {
|
||||||
return mem.compare(a.data, b.data, min(a.count, b.count))
|
return mem.compare(a.data, b.data, min(a.count, b.count));
|
||||||
}
|
}
|
||||||
|
|
||||||
__string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b) }
|
__string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); }
|
||||||
__string_lt :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) < 0 }
|
__string_lt :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) < 0; }
|
||||||
__string_gt :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) > 0 }
|
__string_gt :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) > 0; }
|
||||||
__string_le :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) <= 0 }
|
__string_le :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) <= 0; }
|
||||||
__string_ge :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) >= 0 }
|
__string_ge :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) >= 0; }
|
||||||
|
|
||||||
|
|
||||||
__assert :: proc(file: string, line, column: int, msg: string) #inline {
|
__assert :: proc(file: string, line, column: int, msg: string) #inline {
|
||||||
fmt.fprintf(os.stderr, "%(%:%) Runtime assertion: %\n",
|
fmt.fprintf(os.stderr, "%(%:%) Runtime assertion: %\n",
|
||||||
file, line, column, msg)
|
file, line, column, msg);
|
||||||
__debug_trap()
|
__debug_trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
__bounds_check_error :: proc(file: string, line, column: int,
|
__bounds_check_error :: proc(file: string, line, column: int,
|
||||||
index, count: int) {
|
index, count: int) {
|
||||||
if 0 <= index && index < count {
|
if 0 <= index && index < count {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
fmt.fprintf(os.stderr, "%(%:%) Index % is out of bounds range [0, %)\n",
|
fmt.fprintf(os.stderr, "%(%:%) Index % is out of bounds range [0, %)\n",
|
||||||
file, line, column, index, count)
|
file, line, column, index, count);
|
||||||
__debug_trap()
|
__debug_trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
__slice_expr_error :: proc(file: string, line, column: int,
|
__slice_expr_error :: proc(file: string, line, column: int,
|
||||||
low, high, max: int) {
|
low, high, max: int) {
|
||||||
if 0 <= low && low <= high && high <= max {
|
if 0 <= low && low <= high && high <= max {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
fmt.fprintf(os.stderr, "%(%:%) Invalid slice indices: [%:%:%]\n",
|
fmt.fprintf(os.stderr, "%(%:%) Invalid slice indices: [%:%:%]\n",
|
||||||
file, line, column, low, high, max)
|
file, line, column, low, high, max);
|
||||||
__debug_trap()
|
__debug_trap();
|
||||||
}
|
}
|
||||||
__substring_expr_error :: proc(file: string, line, column: int,
|
__substring_expr_error :: proc(file: string, line, column: int,
|
||||||
low, high: int) {
|
low, high: int) {
|
||||||
if 0 <= low && low <= high {
|
if 0 <= low && low <= high {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
fmt.fprintf(os.stderr, "%(%:%) Invalid substring indices: [%:%:%]\n",
|
fmt.fprintf(os.stderr, "%(%:%) Invalid substring indices: [%:%:%]\n",
|
||||||
file, line, column, low, high)
|
file, line, column, low, high);
|
||||||
__debug_trap()
|
__debug_trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
__enum_to_string :: proc(info: ^Type_Info, value: i64) -> string {
|
__enum_to_string :: proc(info: ^Type_Info, value: i64) -> string {
|
||||||
@@ -357,11 +335,11 @@ __enum_to_string :: proc(info: ^Type_Info, value: i64) -> string {
|
|||||||
// TODO(bill): Search faster than linearly
|
// TODO(bill): Search faster than linearly
|
||||||
for i := 0; i < ti.values.count; i++ {
|
for i := 0; i < ti.values.count; i++ {
|
||||||
if ti.values[i] == value {
|
if ti.values[i] == value {
|
||||||
return ti.names[i]
|
return ti.names[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+80
-81
@@ -1,157 +1,156 @@
|
|||||||
#shared_global_scope
|
#shared_global_scope;
|
||||||
|
|
||||||
#import "fmt.odin"
|
|
||||||
|
|
||||||
|
#import "fmt.odin";
|
||||||
|
|
||||||
__u128_mod :: proc(a, b: u128) -> u128 #link_name "__umodti3" {
|
__u128_mod :: proc(a, b: u128) -> u128 #link_name "__umodti3" {
|
||||||
_, r := __u128_quo_mod(a, b)
|
_, r := __u128_quo_mod(a, b);
|
||||||
return r
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
__u128_quo :: proc(a, b: u128) -> u128 #link_name "__udivti3" {
|
__u128_quo :: proc(a, b: u128) -> u128 #link_name "__udivti3" {
|
||||||
n, _ := __u128_quo_mod(a, b)
|
n, _ := __u128_quo_mod(a, b);
|
||||||
return n
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
__i128_mod :: proc(a, b: i128) -> i128 #link_name "__modti3" {
|
__i128_mod :: proc(a, b: i128) -> i128 #link_name "__modti3" {
|
||||||
_, r := __i128_quo_mod(a, b)
|
_, r := __i128_quo_mod(a, b);
|
||||||
return r
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
__i128_quo :: proc(a, b: i128) -> i128 #link_name "__divti3" {
|
__i128_quo :: proc(a, b: i128) -> i128 #link_name "__divti3" {
|
||||||
n, _ := __i128_quo_mod(a, b)
|
n, _ := __i128_quo_mod(a, b);
|
||||||
return n
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
__i128_quo_mod :: proc(a, b: i128) -> (i128, i128) #link_name "__divmodti4" {
|
__i128_quo_mod :: proc(a, b: i128) -> (i128, i128) #link_name "__divmodti4" {
|
||||||
s := b >> 127
|
s := b >> 127;
|
||||||
b = (b ~ s) - s
|
b = (b ~ s) - s;
|
||||||
s = a >> 127
|
s = a >> 127;
|
||||||
a = (a ~ s) - s
|
a = (a ~ s) - s;
|
||||||
|
|
||||||
n, r := __u128_quo_mod(a as u128, b as u128)
|
n, r := __u128_quo_mod(a as u128, b as u128);
|
||||||
return (n as i128 ~ s) - s, (r as i128 ~ s) - s
|
return (n as i128 ~ s) - s, (r as i128 ~ s) - s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__u128_quo_mod :: proc(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" {
|
__u128_quo_mod :: proc(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" {
|
||||||
clz :: proc(x: u64) -> u64 {
|
clz :: proc(x: u64) -> u64 {
|
||||||
clz_u64 :: proc(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.ctlz.i64"
|
clz_u64 :: proc(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.ctlz.i64"
|
||||||
return clz_u64(x, false)
|
return clz_u64(x, false);
|
||||||
}
|
}
|
||||||
ctz :: proc(x: u64) -> u64 {
|
ctz :: proc(x: u64) -> u64 {
|
||||||
ctz_u64 :: proc(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.cttz.i64"
|
ctz_u64 :: proc(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.cttz.i64"
|
||||||
return ctz_u64(x, false)
|
return ctz_u64(x, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
u128_lo_hi :: raw_union {
|
u128_lo_hi :: raw_union {
|
||||||
all: u128
|
all: u128;
|
||||||
using _lohi: struct {lo, hi: u64}
|
using _lohi: struct {lo, hi: u64;};
|
||||||
}
|
}
|
||||||
|
|
||||||
n, d, q, r: u128_lo_hi
|
n, d, q, r: u128_lo_hi;
|
||||||
sr: u64
|
sr: u64;
|
||||||
|
|
||||||
n.all = a
|
n.all = a;
|
||||||
d.all = b
|
d.all = b;
|
||||||
|
|
||||||
if n.hi == 0 {
|
if n.hi == 0 {
|
||||||
if d.hi == 0 {
|
if d.hi == 0 {
|
||||||
return (n.lo / d.lo) as u128, (n.lo % d.lo) as u128
|
return (n.lo / d.lo) as u128, (n.lo % d.lo) as u128;
|
||||||
}
|
}
|
||||||
return 0, n.lo as u128
|
return 0, n.lo as u128;
|
||||||
}
|
}
|
||||||
if d.lo == 0 {
|
if d.lo == 0 {
|
||||||
if d.hi == 0 {
|
if d.hi == 0 {
|
||||||
return (n.hi / d.lo) as u128, (n.hi % d.lo) as u128
|
return (n.hi / d.lo) as u128, (n.hi % d.lo) as u128;
|
||||||
}
|
}
|
||||||
if n.lo == 0 {
|
if n.lo == 0 {
|
||||||
r.hi = n.hi % d.hi
|
r.hi = n.hi % d.hi;
|
||||||
r.lo = 0
|
r.lo = 0;
|
||||||
return (n.hi / d.hi) as u128, r.all
|
return (n.hi / d.hi) as u128, r.all;
|
||||||
}
|
}
|
||||||
if (d.hi & (d.hi-1)) == 0 {
|
if (d.hi & (d.hi-1)) == 0 {
|
||||||
r.lo = n.lo
|
r.lo = n.lo;
|
||||||
r.hi = n.hi & (d.hi-1)
|
r.hi = n.hi & (d.hi-1);
|
||||||
return (n.hi >> ctz(d.hi)) as u128, r.all
|
return (n.hi >> ctz(d.hi)) as u128, r.all;
|
||||||
}
|
}
|
||||||
|
|
||||||
sr = clz(d.hi) - clz(n.hi)
|
sr = clz(d.hi) - clz(n.hi);
|
||||||
if sr > 64 - 2 {
|
if sr > 64 - 2 {
|
||||||
return 0, n.all
|
return 0, n.all;
|
||||||
}
|
}
|
||||||
sr++
|
sr++;
|
||||||
q.lo = 0
|
q.lo = 0;
|
||||||
q.hi = n.lo << (64-sr)
|
q.hi = n.lo << (64-sr);
|
||||||
r.hi = n.hi >> sr
|
r.hi = n.hi >> sr;
|
||||||
r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
|
r.lo = (n.hi << (64-sr)) | (n.lo >> sr);
|
||||||
} else {
|
} else {
|
||||||
if d.hi == 0 {
|
if d.hi == 0 {
|
||||||
if (d.lo & (d.lo - 1)) == 0 {
|
if (d.lo & (d.lo - 1)) == 0 {
|
||||||
rem := (n.lo % (d.lo - 1)) as u128
|
rem := (n.lo % (d.lo - 1)) as u128;
|
||||||
if d.lo == 1 {
|
if d.lo == 1 {
|
||||||
return n.all, rem
|
return n.all, rem;
|
||||||
}
|
}
|
||||||
sr = ctz(d.lo)
|
sr = ctz(d.lo);
|
||||||
q.hi = n.hi >> sr
|
q.hi = n.hi >> sr;
|
||||||
q.lo = (n.hi << (64-sr)) | (n.lo >> sr);
|
q.lo = (n.hi << (64-sr)) | (n.lo >> sr);
|
||||||
return q.all, rem
|
return q.all, rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
sr = 1 + 64 + clz(d.lo) - clz(n.hi)
|
sr = 1 + 64 + clz(d.lo) - clz(n.hi);
|
||||||
|
|
||||||
q.all = n.all << (128-sr)
|
q.all = n.all << (128-sr);
|
||||||
r.all = n.all >> sr
|
r.all = n.all >> sr;
|
||||||
if sr == 64 {
|
if sr == 64 {
|
||||||
q.lo = 0
|
q.lo = 0;
|
||||||
q.hi = n.lo
|
q.hi = n.lo;
|
||||||
r.hi = 0
|
r.hi = 0;
|
||||||
r.lo = n.hi
|
r.lo = n.hi;
|
||||||
} else if sr < 64 {
|
} else if sr < 64 {
|
||||||
q.lo = 0
|
q.lo = 0;
|
||||||
q.hi = n.lo << (64-sr)
|
q.hi = n.lo << (64-sr);
|
||||||
r.hi = n.hi >> sr
|
r.hi = n.hi >> sr;
|
||||||
r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
|
r.lo = (n.hi << (64-sr)) | (n.lo >> sr);
|
||||||
} else {
|
} else {
|
||||||
q.lo = n.lo << (128-sr)
|
q.lo = n.lo << (128-sr);
|
||||||
q.hi = (n.hi << (128-sr)) | (n.lo >> (sr-64))
|
q.hi = (n.hi << (128-sr)) | (n.lo >> (sr-64));
|
||||||
r.hi = 0
|
r.hi = 0;
|
||||||
r.lo = n.hi >> (sr-64)
|
r.lo = n.hi >> (sr-64);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sr = clz(d.hi) - clz(n.hi)
|
sr = clz(d.hi) - clz(n.hi);
|
||||||
if sr > 64-1 {
|
if sr > 64-1 {
|
||||||
return 0, n.all
|
return 0, n.all;
|
||||||
}
|
}
|
||||||
sr++
|
sr++;
|
||||||
q.lo = 0
|
q.lo = 0;
|
||||||
q.hi = n.lo << (64-sr)
|
q.hi = n.lo << (64-sr);
|
||||||
r.all = n.all >> sr
|
r.all = n.all >> sr;
|
||||||
if sr < 64 {
|
if sr < 64 {
|
||||||
r.hi = n.hi >> sr
|
r.hi = n.hi >> sr;
|
||||||
r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
|
r.lo = (n.hi << (64-sr)) | (n.lo >> sr);
|
||||||
} else {
|
} else {
|
||||||
r.hi = 0
|
r.hi = 0;
|
||||||
r.lo = n.hi
|
r.lo = n.hi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
carry: u64
|
carry: u64;
|
||||||
for ; sr > 0; sr-- {
|
for ; sr > 0; sr-- {
|
||||||
r.hi = (r.hi << 1) | (r.lo >> (64-1))
|
r.hi = (r.hi << 1) | (r.lo >> (64-1));
|
||||||
r.lo = (r.lo << 1) | (r.hi >> (64-1))
|
r.lo = (r.lo << 1) | (r.hi >> (64-1));
|
||||||
q.hi = (q.hi << 1) | (q.lo >> (64-1))
|
q.hi = (q.hi << 1) | (q.lo >> (64-1));
|
||||||
q.lo = (q.lo << 1) | carry
|
q.lo = (q.lo << 1) | carry;
|
||||||
|
|
||||||
carry = 0
|
carry = 0;
|
||||||
if r.all >= d.all {
|
if r.all >= d.all {
|
||||||
r.all -= d.all
|
r.all -= d.all;
|
||||||
carry = 1
|
carry = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
q.all = (q.all << 1) | (carry as u128)
|
q.all = (q.all << 1) | (carry as u128);
|
||||||
return q.all, r.all
|
return q.all, r.all;
|
||||||
}
|
}
|
||||||
|
|||||||
+278
-276
@@ -1,591 +1,593 @@
|
|||||||
#import "os.odin"
|
#import "os.odin";
|
||||||
#import "mem.odin"
|
#import "mem.odin";
|
||||||
#import "utf8.odin"
|
#import "utf8.odin";
|
||||||
|
|
||||||
PRINT_BUF_SIZE :: 1<<12
|
PRINT_BUF_SIZE :: 1<<12;
|
||||||
|
|
||||||
fprint :: proc(f: ^os.File, args: ..any) -> int {
|
fprint :: proc(f: ^os.File, args: ..any) -> int {
|
||||||
data: [PRINT_BUF_SIZE]byte
|
data: [PRINT_BUF_SIZE]byte;
|
||||||
buf := data[:0]
|
buf := data[:0];
|
||||||
bprint(^buf, ..args)
|
bprint(^buf, ..args);
|
||||||
os.write(f, buf)
|
os.write(f, buf);
|
||||||
return buf.count
|
return buf.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintln :: proc(f: ^os.File, args: ..any) -> int {
|
fprintln :: proc(f: ^os.File, args: ..any) -> int {
|
||||||
data: [PRINT_BUF_SIZE]byte
|
data: [PRINT_BUF_SIZE]byte;
|
||||||
buf := data[:0]
|
buf := data[:0];
|
||||||
bprintln(^buf, ..args)
|
bprintln(^buf, ..args);
|
||||||
os.write(f, buf)
|
os.write(f, buf);
|
||||||
return buf.count
|
return buf.count;
|
||||||
}
|
}
|
||||||
fprintf :: proc(f: ^os.File, fmt: string, args: ..any) -> int {
|
fprintf :: proc(f: ^os.File, fmt: string, args: ..any) -> int {
|
||||||
data: [PRINT_BUF_SIZE]byte
|
data: [PRINT_BUF_SIZE]byte;
|
||||||
buf := data[:0]
|
buf := data[:0];
|
||||||
bprintf(^buf, fmt, ..args)
|
bprintf(^buf, fmt, ..args);
|
||||||
os.write(f, buf)
|
os.write(f, buf);
|
||||||
return buf.count
|
return buf.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
print :: proc(args: ..any) -> int {
|
print :: proc(args: ..any) -> int {
|
||||||
return fprint(os.stdout, ..args)
|
return fprint(os.stdout, ..args);
|
||||||
}
|
}
|
||||||
println :: proc(args: ..any) -> int {
|
println :: proc(args: ..any) -> int {
|
||||||
return fprintln(os.stdout, ..args)
|
return fprintln(os.stdout, ..args);
|
||||||
}
|
}
|
||||||
printf :: proc(fmt: string, args: ..any) -> int {
|
printf :: proc(fmt: string, args: ..any) -> int {
|
||||||
return fprintf(os.stdout, fmt, ..args)
|
return fprintf(os.stdout, fmt, ..args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fprint_type :: proc(f: ^os.File, info: ^Type_Info) {
|
fprint_type :: proc(f: ^os.File, info: ^Type_Info) {
|
||||||
data: [PRINT_BUF_SIZE]byte
|
data: [PRINT_BUF_SIZE]byte;
|
||||||
buf := data[:0]
|
buf := data[:0];
|
||||||
print_type_to_buffer(^buf, info)
|
print_type_to_buffer(^buf, info);
|
||||||
os.write(f, buf)
|
os.write(f, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
|
print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
|
||||||
if buf.count < buf.capacity {
|
if buf.count < buf.capacity {
|
||||||
n := min(buf.capacity-buf.count, b.count)
|
n := min(buf.capacity-buf.count, b.count);
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
mem.copy(buf.data + buf.count, ^b[0], n)
|
mem.copy(buf.data + buf.count, b.data, n);
|
||||||
buf.count += n
|
buf.count += n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_string_to_buffer :: proc(buf: ^[]byte, s: string) {
|
print_string_to_buffer :: proc(buf: ^[]byte, s: string) {
|
||||||
print_byte_buffer(buf, s as []byte)
|
print_byte_buffer(buf, s as []byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
byte_reverse :: proc(b: []byte) {
|
byte_reverse :: proc(b: []byte) {
|
||||||
n := b.count
|
n := b.count;
|
||||||
for i := 0; i < n/2; i++ {
|
for i := 0; i < n/2; i++ {
|
||||||
b[i], b[n-1-i] = b[n-1-i], b[i]
|
b[i], b[n-1-i] = b[n-1-i], b[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_rune_to_buffer :: proc(buf: ^[]byte, r: rune) {
|
print_rune_to_buffer :: proc(buf: ^[]byte, r: rune) {
|
||||||
b, n := utf8.encode_rune(r)
|
b, n := utf8.encode_rune(r);
|
||||||
print_string_to_buffer(buf, b[:n] as string)
|
print_string_to_buffer(buf, b[:n] as string);
|
||||||
}
|
}
|
||||||
|
|
||||||
print_space_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, ' ') }
|
print_space_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, ' '); }
|
||||||
print_nl_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, '\n') }
|
print_nl_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, '\n'); }
|
||||||
|
|
||||||
__NUM_TO_CHAR_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"
|
__NUM_TO_CHAR_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$";
|
||||||
|
|
||||||
print_bool_to_buffer :: proc(buffer: ^[]byte, b : bool) {
|
print_bool_to_buffer :: proc(buffer: ^[]byte, b : bool) {
|
||||||
if b { print_string_to_buffer(buffer, "true") }
|
if b { print_string_to_buffer(buffer, "true"); }
|
||||||
else { print_string_to_buffer(buffer, "false") }
|
else { print_string_to_buffer(buffer, "false"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
print_pointer_to_buffer :: proc(buffer: ^[]byte, p: rawptr) #inline {
|
print_pointer_to_buffer :: proc(buffer: ^[]byte, p: rawptr) #inline {
|
||||||
print_string_to_buffer(buffer, "0x")
|
print_string_to_buffer(buffer, "0x");
|
||||||
print_u64_to_buffer(buffer, p as uint as u64)
|
print_u64_to_buffer(buffer, p as uint as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
print_f16_to_buffer :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 4) }
|
print_f16_to_buffer :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 4); }
|
||||||
print_f32_to_buffer :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7) }
|
print_f32_to_buffer :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7); }
|
||||||
print_f64_to_buffer :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f as f64, 16) }
|
print_f64_to_buffer :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f as f64, 16); }
|
||||||
print_u64_to_buffer :: proc(buffer: ^[]byte, value: u64) {
|
print_u64_to_buffer :: proc(buffer: ^[]byte, value: u64) {
|
||||||
i := value
|
i := value;
|
||||||
buf: [20]byte
|
buf: [20]byte;
|
||||||
len := 0
|
len := 0;
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
buf[len] = '0'
|
buf[len] = '0';
|
||||||
len++
|
len++;
|
||||||
}
|
}
|
||||||
for i > 0 {
|
for i > 0 {
|
||||||
buf[len] = __NUM_TO_CHAR_TABLE[i % 10]
|
buf[len] = __NUM_TO_CHAR_TABLE[i % 10];
|
||||||
len++
|
len++;
|
||||||
i /= 10
|
i /= 10;
|
||||||
}
|
}
|
||||||
byte_reverse(buf[:len])
|
byte_reverse(buf[:len]);
|
||||||
print_string_to_buffer(buffer, buf[:len] as string)
|
print_string_to_buffer(buffer, buf[:len] as string);
|
||||||
}
|
}
|
||||||
print_i64_to_buffer :: proc(buffer: ^[]byte, value: i64) {
|
print_i64_to_buffer :: proc(buffer: ^[]byte, value: i64) {
|
||||||
i := value
|
i := value;
|
||||||
neg := i < 0
|
neg := i < 0;
|
||||||
if neg {
|
if neg {
|
||||||
i = -i
|
i = -i;
|
||||||
print_rune_to_buffer(buffer, '-')
|
print_rune_to_buffer(buffer, '-');
|
||||||
}
|
}
|
||||||
print_u64_to_buffer(buffer, i as u64)
|
print_u64_to_buffer(buffer, i as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
print_u128_to_buffer :: proc(buffer: ^[]byte, value: u128) {
|
print_u128_to_buffer :: proc(buffer: ^[]byte, value: u128) {
|
||||||
a := value transmute [2]u64
|
a := value transmute [2]u64;
|
||||||
if a[1] != 0 {
|
if a[1] != 0 {
|
||||||
print_u64_to_buffer(buffer, a[1])
|
print_u64_to_buffer(buffer, a[1]);
|
||||||
}
|
}
|
||||||
print_u64_to_buffer(buffer, a[0])
|
print_u64_to_buffer(buffer, a[0]);
|
||||||
}
|
}
|
||||||
print_i128_to_buffer :: proc(buffer: ^[]byte, value: i128) {
|
print_i128_to_buffer :: proc(buffer: ^[]byte, value: i128) {
|
||||||
i := value
|
i := value;
|
||||||
neg := i < 0
|
neg := i < 0;
|
||||||
if neg {
|
if neg {
|
||||||
i = -i
|
i = -i;
|
||||||
print_rune_to_buffer(buffer, '-')
|
print_rune_to_buffer(buffer, '-');
|
||||||
}
|
}
|
||||||
print_u128_to_buffer(buffer, i as u128)
|
print_u128_to_buffer(buffer, i as u128);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
print__f64 :: proc(buffer: ^[]byte, value: f64, decimal_places: int) {
|
print__f64 :: proc(buffer: ^[]byte, value: f64, decimal_places: int) {
|
||||||
f := value
|
f := value;
|
||||||
if f == 0 {
|
if f == 0 {
|
||||||
print_rune_to_buffer(buffer, '0')
|
print_rune_to_buffer(buffer, '0');
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if f < 0 {
|
if f < 0 {
|
||||||
print_rune_to_buffer(buffer, '-')
|
print_rune_to_buffer(buffer, '-');
|
||||||
f = -f
|
f = -f;
|
||||||
}
|
}
|
||||||
|
|
||||||
i := f as u64
|
i := f as u64;
|
||||||
print_u64_to_buffer(buffer, i)
|
print_u64_to_buffer(buffer, i);
|
||||||
f -= i as f64
|
f -= i as f64;
|
||||||
|
|
||||||
print_rune_to_buffer(buffer, '.')
|
print_rune_to_buffer(buffer, '.');
|
||||||
|
|
||||||
mult: f64 = 10.0
|
mult: f64 = 10.0;
|
||||||
for ; decimal_places >= 0; decimal_places-- {
|
for ; decimal_places >= 0; decimal_places-- {
|
||||||
i = (f * mult) as u64
|
i = (f * mult) as u64;
|
||||||
print_u64_to_buffer(buffer, i as u64)
|
print_u64_to_buffer(buffer, i as u64);
|
||||||
f -= i as f64 / mult
|
f -= i as f64 / mult;
|
||||||
mult *= 10
|
mult *= 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_type_to_buffer :: proc(buf: ^[]byte, ti: ^Type_Info) {
|
print_type_to_buffer :: proc(buf: ^[]byte, ti: ^Type_Info) {
|
||||||
if ti == nil { return }
|
if ti == nil {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
using Type_Info
|
using Type_Info;
|
||||||
match type info : ti {
|
match type info : ti {
|
||||||
case Named:
|
case Named:
|
||||||
print_string_to_buffer(buf, info.name)
|
print_string_to_buffer(buf, info.name);
|
||||||
case Integer:
|
case Integer:
|
||||||
match {
|
match {
|
||||||
case ti == type_info(int):
|
case ti == type_info(int):
|
||||||
print_string_to_buffer(buf, "int")
|
print_string_to_buffer(buf, "int");
|
||||||
case ti == type_info(uint):
|
case ti == type_info(uint):
|
||||||
print_string_to_buffer(buf, "uint")
|
print_string_to_buffer(buf, "uint");
|
||||||
default:
|
default:
|
||||||
if info.signed {
|
if info.signed {
|
||||||
print_string_to_buffer(buf, "i")
|
print_string_to_buffer(buf, "i");
|
||||||
} else {
|
} else {
|
||||||
print_string_to_buffer(buf, "u")
|
print_string_to_buffer(buf, "u");
|
||||||
}
|
}
|
||||||
print_u64_to_buffer(buf, 8*info.size as u64)
|
print_u64_to_buffer(buf, 8*info.size as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Float:
|
case Float:
|
||||||
match info.size {
|
match info.size {
|
||||||
case 4: print_string_to_buffer(buf, "f32")
|
case 4: print_string_to_buffer(buf, "f32");
|
||||||
case 8: print_string_to_buffer(buf, "f64")
|
case 8: print_string_to_buffer(buf, "f64");
|
||||||
}
|
}
|
||||||
case String: print_string_to_buffer(buf, "string")
|
case String: print_string_to_buffer(buf, "string");
|
||||||
case Boolean: print_string_to_buffer(buf, "bool")
|
case Boolean: print_string_to_buffer(buf, "bool");
|
||||||
case Pointer:
|
case Pointer:
|
||||||
if info.elem == nil {
|
if info.elem == nil {
|
||||||
print_string_to_buffer(buf, "rawptr")
|
print_string_to_buffer(buf, "rawptr");
|
||||||
} else {
|
} else {
|
||||||
print_string_to_buffer(buf, "^")
|
print_string_to_buffer(buf, "^");
|
||||||
print_type_to_buffer(buf, info.elem)
|
print_type_to_buffer(buf, info.elem);
|
||||||
}
|
}
|
||||||
case Maybe:
|
case Maybe:
|
||||||
print_string_to_buffer(buf, "?")
|
print_string_to_buffer(buf, "?");
|
||||||
print_type_to_buffer(buf, info.elem)
|
print_type_to_buffer(buf, info.elem);
|
||||||
case Procedure:
|
case Procedure:
|
||||||
print_string_to_buffer(buf, "proc")
|
print_string_to_buffer(buf, "proc");
|
||||||
if info.params == nil {
|
if info.params == nil {
|
||||||
print_string_to_buffer(buf, "()")
|
print_string_to_buffer(buf, "()");
|
||||||
} else {
|
} else {
|
||||||
count := (info.params as ^Tuple).fields.count
|
count := (info.params as ^Tuple).fields.count;
|
||||||
if count == 1 { print_string_to_buffer(buf, "(") }
|
if count == 1 { print_string_to_buffer(buf, "("); }
|
||||||
print_type_to_buffer(buf, info.params)
|
print_type_to_buffer(buf, info.params);
|
||||||
if count == 1 { print_string_to_buffer(buf, ")") }
|
if count == 1 { print_string_to_buffer(buf, ")"); }
|
||||||
}
|
}
|
||||||
if info.results != nil {
|
if info.results != nil {
|
||||||
print_string_to_buffer(buf, " -> ")
|
print_string_to_buffer(buf, " -> ");
|
||||||
print_type_to_buffer(buf, info.results)
|
print_type_to_buffer(buf, info.results);
|
||||||
}
|
}
|
||||||
case Tuple:
|
case Tuple:
|
||||||
count := info.fields.count
|
count := info.fields.count;
|
||||||
if count != 1 { print_string_to_buffer(buf, "(") }
|
if count != 1 { print_string_to_buffer(buf, "("); }
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
if i > 0 { print_string_to_buffer(buf, ", ") }
|
if i > 0 { print_string_to_buffer(buf, ", "); }
|
||||||
|
|
||||||
f := info.fields[i]
|
f := info.fields[i];
|
||||||
|
|
||||||
if f.name.count > 0 {
|
if f.name.count > 0 {
|
||||||
print_string_to_buffer(buf, f.name)
|
print_string_to_buffer(buf, f.name);
|
||||||
print_string_to_buffer(buf, ": ")
|
print_string_to_buffer(buf, ": ");
|
||||||
}
|
}
|
||||||
print_type_to_buffer(buf, f.type_info)
|
print_type_to_buffer(buf, f.type_info);
|
||||||
}
|
}
|
||||||
if count != 1 { print_string_to_buffer(buf, ")") }
|
if count != 1 { print_string_to_buffer(buf, ")"); }
|
||||||
|
|
||||||
case Array:
|
case Array:
|
||||||
print_string_to_buffer(buf, "[")
|
print_string_to_buffer(buf, "[");
|
||||||
print_i64_to_buffer(buf, info.count as i64)
|
print_i64_to_buffer(buf, info.count as i64);
|
||||||
print_string_to_buffer(buf, "]")
|
print_string_to_buffer(buf, "]");
|
||||||
print_type_to_buffer(buf, info.elem)
|
print_type_to_buffer(buf, info.elem);
|
||||||
case Slice:
|
case Slice:
|
||||||
print_string_to_buffer(buf, "[")
|
print_string_to_buffer(buf, "[");
|
||||||
print_string_to_buffer(buf, "]")
|
print_string_to_buffer(buf, "]");
|
||||||
print_type_to_buffer(buf, info.elem)
|
print_type_to_buffer(buf, info.elem);
|
||||||
case Vector:
|
case Vector:
|
||||||
print_string_to_buffer(buf, "[vector ")
|
print_string_to_buffer(buf, "[vector ");
|
||||||
print_i64_to_buffer(buf, info.count as i64)
|
print_i64_to_buffer(buf, info.count as i64);
|
||||||
print_string_to_buffer(buf, "]")
|
print_string_to_buffer(buf, "]");
|
||||||
print_type_to_buffer(buf, info.elem)
|
print_type_to_buffer(buf, info.elem);
|
||||||
|
|
||||||
case Struct:
|
case Struct:
|
||||||
print_string_to_buffer(buf, "struct ")
|
print_string_to_buffer(buf, "struct ");
|
||||||
if info.packed { print_string_to_buffer(buf, "#packed ") }
|
if info.packed { print_string_to_buffer(buf, "#packed "); }
|
||||||
if info.ordered { print_string_to_buffer(buf, "#ordered ") }
|
if info.ordered { print_string_to_buffer(buf, "#ordered "); }
|
||||||
print_string_to_buffer(buf, "{")
|
print_string_to_buffer(buf, "{");
|
||||||
for i := 0; i < info.fields.count; i++ {
|
for i := 0; i < info.fields.count; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
print_string_to_buffer(buf, ", ")
|
print_string_to_buffer(buf, ", ");
|
||||||
}
|
}
|
||||||
print_any_to_buffer(buf, info.fields[i].name)
|
print_any_to_buffer(buf, info.fields[i].name);
|
||||||
print_string_to_buffer(buf, ": ")
|
print_string_to_buffer(buf, ": ");
|
||||||
print_type_to_buffer(buf, info.fields[i].type_info)
|
print_type_to_buffer(buf, info.fields[i].type_info);
|
||||||
}
|
}
|
||||||
print_string_to_buffer(buf, "}")
|
print_string_to_buffer(buf, "}");
|
||||||
|
|
||||||
case Union:
|
case Union:
|
||||||
print_string_to_buffer(buf, "union {")
|
print_string_to_buffer(buf, "union {");
|
||||||
for i := 0; i < info.fields.count; i++ {
|
for i := 0; i < info.fields.count; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
print_string_to_buffer(buf, ", ")
|
print_string_to_buffer(buf, ", ");
|
||||||
}
|
}
|
||||||
print_any_to_buffer(buf, info.fields[i].name)
|
print_any_to_buffer(buf, info.fields[i].name);
|
||||||
print_string_to_buffer(buf, ": ")
|
print_string_to_buffer(buf, ": ");
|
||||||
print_type_to_buffer(buf, info.fields[i].type_info)
|
print_type_to_buffer(buf, info.fields[i].type_info);
|
||||||
}
|
}
|
||||||
print_string_to_buffer(buf, "}")
|
print_string_to_buffer(buf, "}");
|
||||||
|
|
||||||
case Raw_Union:
|
case Raw_Union:
|
||||||
print_string_to_buffer(buf, "raw_union {")
|
print_string_to_buffer(buf, "raw_union {");
|
||||||
for i := 0; i < info.fields.count; i++ {
|
for i := 0; i < info.fields.count; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
print_string_to_buffer(buf, ", ")
|
print_string_to_buffer(buf, ", ");
|
||||||
}
|
}
|
||||||
print_any_to_buffer(buf, info.fields[i].name)
|
print_any_to_buffer(buf, info.fields[i].name);
|
||||||
print_string_to_buffer(buf, ": ")
|
print_string_to_buffer(buf, ": ");
|
||||||
print_type_to_buffer(buf, info.fields[i].type_info)
|
print_type_to_buffer(buf, info.fields[i].type_info);
|
||||||
}
|
}
|
||||||
print_string_to_buffer(buf, "}")
|
print_string_to_buffer(buf, "}");
|
||||||
|
|
||||||
case Enum:
|
case Enum:
|
||||||
print_string_to_buffer(buf, "enum ")
|
print_string_to_buffer(buf, "enum ");
|
||||||
print_type_to_buffer(buf, info.base)
|
print_type_to_buffer(buf, info.base);
|
||||||
print_string_to_buffer(buf, "{}")
|
print_string_to_buffer(buf, "{}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
make_any :: proc(type_info: ^Type_Info, data: rawptr) -> any {
|
make_any :: proc(type_info: ^Type_Info, data: rawptr) -> any {
|
||||||
a: any
|
a: any;
|
||||||
a.type_info = type_info
|
a.type_info = type_info;
|
||||||
a.data = data
|
a.data = data;
|
||||||
return a
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_any_to_buffer :: proc(buf: ^[]byte, arg: any) {
|
print_any_to_buffer :: proc(buf: ^[]byte, arg: any) {
|
||||||
if arg.type_info == nil {
|
if arg.type_info == nil {
|
||||||
print_string_to_buffer(buf, "<nil>")
|
print_string_to_buffer(buf, "<nil>");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if arg.data == nil {
|
if arg.data == nil {
|
||||||
print_string_to_buffer(buf, "<nil>")
|
print_string_to_buffer(buf, "<nil>");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using Type_Info
|
using Type_Info;
|
||||||
match type info : arg.type_info {
|
match type info : arg.type_info {
|
||||||
case Named:
|
case Named:
|
||||||
a := make_any(info.base, arg.data)
|
a := make_any(info.base, arg.data);
|
||||||
match type b : info.base {
|
match type b : info.base {
|
||||||
case Struct:
|
case Struct:
|
||||||
print_string_to_buffer(buf, info.name)
|
print_string_to_buffer(buf, info.name);
|
||||||
print_string_to_buffer(buf, "{")
|
print_string_to_buffer(buf, "{");
|
||||||
for i := 0; i < b.fields.count; i++ {
|
for i := 0; i < b.fields.count; i++ {
|
||||||
f := b.fields[i];
|
f := b.fields[i];
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
print_string_to_buffer(buf, ", ")
|
print_string_to_buffer(buf, ", ");
|
||||||
}
|
}
|
||||||
print_string_to_buffer(buf, f.name)
|
print_string_to_buffer(buf, f.name);
|
||||||
// print_any_to_buffer(buf, f.offset)
|
// print_any_to_buffer(buf, f.offset);
|
||||||
print_string_to_buffer(buf, " = ")
|
print_string_to_buffer(buf, " = ");
|
||||||
data := arg.data as ^byte + f.offset
|
data := arg.data as ^byte + f.offset;
|
||||||
print_any_to_buffer(buf, make_any(f.type_info, data))
|
print_any_to_buffer(buf, make_any(f.type_info, data));
|
||||||
}
|
}
|
||||||
print_string_to_buffer(buf, "}")
|
print_string_to_buffer(buf, "}");
|
||||||
|
|
||||||
default:
|
default:
|
||||||
print_any_to_buffer(buf, a)
|
print_any_to_buffer(buf, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Integer:
|
case Integer:
|
||||||
match type i : arg {
|
match type i : arg {
|
||||||
case i8: print_i64_to_buffer(buf, i as i64)
|
case i8: print_i64_to_buffer(buf, i as i64);
|
||||||
case u8: print_u64_to_buffer(buf, i as u64)
|
case u8: print_u64_to_buffer(buf, i as u64);
|
||||||
case i16: print_i64_to_buffer(buf, i as i64)
|
case i16: print_i64_to_buffer(buf, i as i64);
|
||||||
case u16: print_u64_to_buffer(buf, i as u64)
|
case u16: print_u64_to_buffer(buf, i as u64);
|
||||||
case i32: print_i64_to_buffer(buf, i as i64)
|
case i32: print_i64_to_buffer(buf, i as i64);
|
||||||
case u32: print_u64_to_buffer(buf, i as u64)
|
case u32: print_u64_to_buffer(buf, i as u64);
|
||||||
case i64: print_i64_to_buffer(buf, i as i64)
|
case i64: print_i64_to_buffer(buf, i as i64);
|
||||||
case u64: print_u64_to_buffer(buf, i as u64)
|
case u64: print_u64_to_buffer(buf, i as u64);
|
||||||
case i128: print_i128_to_buffer(buf, i)
|
case i128: print_i128_to_buffer(buf, i);
|
||||||
case u128: print_u128_to_buffer(buf, i)
|
case u128: print_u128_to_buffer(buf, i);
|
||||||
|
|
||||||
case int: print_u64_to_buffer(buf, i as u64)
|
case int: print_u64_to_buffer(buf, i as u64);
|
||||||
case uint: print_u64_to_buffer(buf, i as u64)
|
case uint: print_u64_to_buffer(buf, i as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Float:
|
case Float:
|
||||||
match type f : arg {
|
match type f : arg {
|
||||||
// case f16: print_f64_to_buffer(buf, f as f64)
|
// case f16: print_f64_to_buffer(buf, f as f64);
|
||||||
case f32: print_f32_to_buffer(buf, f)
|
case f32: print_f32_to_buffer(buf, f);
|
||||||
case f64: print_f64_to_buffer(buf, f)
|
case f64: print_f64_to_buffer(buf, f);
|
||||||
// case f128: print_f64_to_buffer(buf, f as f64)
|
// case f128: print_f64_to_buffer(buf, f as f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
case String:
|
case String:
|
||||||
match type s : arg {
|
match type s : arg {
|
||||||
case string: print_string_to_buffer(buf, s)
|
case string: print_string_to_buffer(buf, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Boolean:
|
case Boolean:
|
||||||
match type b : arg {
|
match type b : arg {
|
||||||
case bool: print_bool_to_buffer(buf, b)
|
case bool: print_bool_to_buffer(buf, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Pointer:
|
case Pointer:
|
||||||
match type p : arg {
|
match type p : arg {
|
||||||
case ^Type_Info: print_type_to_buffer(buf, p)
|
case ^Type_Info: print_type_to_buffer(buf, p);
|
||||||
default: print_pointer_to_buffer(buf, (arg.data as ^rawptr)^)
|
default: print_pointer_to_buffer(buf, (arg.data as ^rawptr)^);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Maybe:
|
case Maybe:
|
||||||
size := mem.size_of_type_info(info.elem)
|
size := mem.size_of_type_info(info.elem);
|
||||||
data := slice_ptr(arg.data as ^byte, size+1)
|
data := slice_ptr(arg.data as ^byte, size+1);
|
||||||
if data[size] != 0 {
|
if data[size] != 0 {
|
||||||
print_any_to_buffer(buf, make_any(info.elem, arg.data))
|
print_any_to_buffer(buf, make_any(info.elem, arg.data));
|
||||||
} else {
|
} else {
|
||||||
print_string_to_buffer(buf, "nil")
|
print_string_to_buffer(buf, "nil");
|
||||||
}
|
}
|
||||||
|
|
||||||
case Enum:
|
case Enum:
|
||||||
value: i64 = 0
|
value: i64 = 0;
|
||||||
|
|
||||||
match type i : make_any(info.base, arg.data) {
|
match type i : make_any(info.base, arg.data) {
|
||||||
case i8: value = i as i64
|
case i8: value = i as i64;
|
||||||
case i16: value = i as i64
|
case i16: value = i as i64;
|
||||||
case i32: value = i as i64
|
case i32: value = i as i64;
|
||||||
case i64: value = i as i64
|
case i64: value = i as i64;
|
||||||
case u8: value = i as i64
|
case u8: value = i as i64;
|
||||||
case u16: value = i as i64
|
case u16: value = i as i64;
|
||||||
case u32: value = i as i64
|
case u32: value = i as i64;
|
||||||
case u64: value = i as i64
|
case u64: value = i as i64;
|
||||||
}
|
}
|
||||||
print_string_to_buffer(buf, __enum_to_string(arg.type_info, value))
|
print_string_to_buffer(buf, __enum_to_string(arg.type_info, value));
|
||||||
|
|
||||||
case Array:
|
case Array:
|
||||||
bprintf(buf, "[%]%{", info.count, info.elem)
|
bprintf(buf, "[%]%{", info.count, info.elem);
|
||||||
defer print_string_to_buffer(buf, "}")
|
defer print_string_to_buffer(buf, "}");
|
||||||
|
|
||||||
for i := 0; i < info.count; i++ {
|
for i := 0; i < info.count; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
print_string_to_buffer(buf, ", ")
|
print_string_to_buffer(buf, ", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
data := arg.data as ^byte + i*info.elem_size
|
data := arg.data as ^byte + i*info.elem_size;
|
||||||
print_any_to_buffer(buf, make_any(info.elem, data))
|
print_any_to_buffer(buf, make_any(info.elem, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
case Slice:
|
case Slice:
|
||||||
slice := arg.data as ^[]byte
|
slice := arg.data as ^[]byte;
|
||||||
bprintf(buf, "[]%{", info.elem)
|
bprintf(buf, "[]%{", info.elem);
|
||||||
defer print_string_to_buffer(buf, "}")
|
defer print_string_to_buffer(buf, "}");
|
||||||
|
|
||||||
for i := 0; i < slice.count; i++ {
|
for i := 0; i < slice.count; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
print_string_to_buffer(buf, ", ")
|
print_string_to_buffer(buf, ", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
data := slice.data + i*info.elem_size
|
data := slice.data + i*info.elem_size;
|
||||||
print_any_to_buffer(buf, make_any(info.elem, data))
|
print_any_to_buffer(buf, make_any(info.elem, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
case Vector:
|
case Vector:
|
||||||
is_bool :: proc(type_info: ^Type_Info) -> bool {
|
is_bool :: proc(type_info: ^Type_Info) -> bool {
|
||||||
match type info : type_info {
|
match type info : type_info {
|
||||||
case Named:
|
case Named:
|
||||||
return is_bool(info.base)
|
return is_bool(info.base);
|
||||||
case Boolean:
|
case Boolean:
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bprintf(buf, "[vector %]%{", info.count, info.elem)
|
bprintf(buf, "[vector %]%{", info.count, info.elem);
|
||||||
defer print_string_to_buffer(buf, "}")
|
defer print_string_to_buffer(buf, "}");
|
||||||
|
|
||||||
if is_bool(info.elem) {
|
if is_bool(info.elem) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < info.count; i++ {
|
for i := 0; i < info.count; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
print_string_to_buffer(buf, ", ")
|
print_string_to_buffer(buf, ", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
data := arg.data as ^byte + i*info.elem_size
|
data := arg.data as ^byte + i*info.elem_size;
|
||||||
print_any_to_buffer(buf, make_any(info.elem, data))
|
print_any_to_buffer(buf, make_any(info.elem, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case Struct:
|
case Struct:
|
||||||
bprintf(buf, "%{", arg.type_info)
|
bprintf(buf, "%{", arg.type_info);
|
||||||
defer print_string_to_buffer(buf, "}")
|
defer print_string_to_buffer(buf, "}");
|
||||||
|
|
||||||
for i := 0; i < info.fields.count; i++ {
|
for i := 0; i < info.fields.count; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
print_string_to_buffer(buf, ", ")
|
print_string_to_buffer(buf, ", ");
|
||||||
}
|
}
|
||||||
print_string_to_buffer(buf, info.fields[i].name)
|
print_string_to_buffer(buf, info.fields[i].name);
|
||||||
print_string_to_buffer(buf, " = ")
|
print_string_to_buffer(buf, " = ");
|
||||||
data := arg.data as ^byte + info.fields[i].offset
|
data := arg.data as ^byte + info.fields[i].offset;
|
||||||
ti := info.fields[i].type_info
|
ti := info.fields[i].type_info;
|
||||||
print_any_to_buffer(buf, make_any(ti, data))
|
print_any_to_buffer(buf, make_any(ti, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
case Union:
|
case Union:
|
||||||
print_string_to_buffer(buf, "(union)")
|
print_string_to_buffer(buf, "(union)");
|
||||||
case Raw_Union:
|
case Raw_Union:
|
||||||
print_string_to_buffer(buf, "(raw_union)")
|
print_string_to_buffer(buf, "(raw_union)");
|
||||||
case Procedure:
|
case Procedure:
|
||||||
print_type_to_buffer(buf, arg.type_info)
|
print_type_to_buffer(buf, arg.type_info);
|
||||||
print_string_to_buffer(buf, " @ 0x")
|
print_string_to_buffer(buf, " @ 0x");
|
||||||
print_pointer_to_buffer(buf, (arg.data as ^rawptr)^)
|
print_pointer_to_buffer(buf, (arg.data as ^rawptr)^);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bprintf :: proc(buf: ^[]byte, fmt: string, args: ..any) -> int {
|
bprintf :: proc(buf: ^[]byte, fmt: string, args: ..any) -> int {
|
||||||
is_digit :: proc(r: rune) -> bool #inline {
|
is_digit :: proc(r: rune) -> bool #inline {
|
||||||
return '0' <= r && r <= '9'
|
return '0' <= r && r <= '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_int :: proc(s: string, offset: int) -> (int, int) {
|
parse_int :: proc(s: string, offset: int) -> (int, int) {
|
||||||
result := 0
|
result := 0;
|
||||||
|
|
||||||
for ; offset < s.count; offset++ {
|
for ; offset < s.count; offset++ {
|
||||||
c := s[offset] as rune
|
c := s[offset] as rune;
|
||||||
if !is_digit(c) {
|
if !is_digit(c) {
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
result *= 10
|
result *= 10;
|
||||||
result += (c - '0') as int
|
result += (c - '0') as int;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, offset
|
return result, offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev := 0
|
prev := 0;
|
||||||
implicit_index := 0
|
implicit_index := 0;
|
||||||
|
|
||||||
for i := 0; i < fmt.count; i++ {
|
for i := 0; i < fmt.count; i++ {
|
||||||
r := fmt[i] as rune
|
r := fmt[i] as rune;
|
||||||
index := implicit_index
|
index := implicit_index;
|
||||||
|
|
||||||
if r != '%' {
|
if r != '%' {
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_string_to_buffer(buf, fmt[prev:i])
|
print_string_to_buffer(buf, fmt[prev:i]);
|
||||||
i++ // Skip %
|
i++; // Skip %
|
||||||
if i < fmt.count {
|
if i < fmt.count {
|
||||||
next := fmt[i] as rune
|
next := fmt[i] as rune;
|
||||||
|
|
||||||
if next == '%' {
|
if next == '%' {
|
||||||
print_string_to_buffer(buf, "%")
|
print_string_to_buffer(buf, "%");
|
||||||
i++
|
i++;
|
||||||
prev = i
|
prev = i;
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_digit(next) {
|
if is_digit(next) {
|
||||||
index, i = parse_int(fmt, i)
|
index, i = parse_int(fmt, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if 0 <= index && index < args.count {
|
if 0 <= index && index < args.count {
|
||||||
print_any_to_buffer(buf, args[index])
|
print_any_to_buffer(buf, args[index]);
|
||||||
implicit_index = index+1
|
implicit_index = index+1;
|
||||||
} else {
|
} else {
|
||||||
// TODO(bill): Error check index out bounds
|
// TODO(bill): Error check index out bounds
|
||||||
print_string_to_buffer(buf, "<invalid>")
|
print_string_to_buffer(buf, "<invalid>");
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = i
|
prev = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_string_to_buffer(buf, fmt[prev:])
|
print_string_to_buffer(buf, fmt[prev:]);
|
||||||
return buf.count
|
return buf.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bprint :: proc(buf: ^[]byte, args: ..any) -> int {
|
bprint :: proc(buf: ^[]byte, args: ..any) -> int {
|
||||||
is_type_string :: proc(info: ^Type_Info) -> bool {
|
is_type_string :: proc(info: ^Type_Info) -> bool {
|
||||||
using Type_Info
|
using Type_Info;
|
||||||
if info == nil {
|
if info == nil {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
match type i : type_info_base(info) {
|
match type i : type_info_base(info) {
|
||||||
case String:
|
case String:
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
prev_string := false
|
prev_string := false;
|
||||||
for i := 0; i < args.count; i++ {
|
for i := 0; i < args.count; i++ {
|
||||||
arg := args[i]
|
arg := args[i];
|
||||||
is_string := arg.data != nil && is_type_string(arg.type_info)
|
is_string := arg.data != nil && is_type_string(arg.type_info);
|
||||||
if i > 0 && !is_string && !prev_string {
|
if i > 0 && !is_string && !prev_string {
|
||||||
print_space_to_buffer(buf)
|
print_space_to_buffer(buf);
|
||||||
}
|
}
|
||||||
print_any_to_buffer(buf, arg)
|
print_any_to_buffer(buf, arg);
|
||||||
prev_string = is_string;
|
prev_string = is_string;
|
||||||
}
|
}
|
||||||
return buf.count
|
return buf.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bprintln :: proc(buf: ^[]byte, args: ..any) -> int {
|
bprintln :: proc(buf: ^[]byte, args: ..any) -> int {
|
||||||
for i := 0; i < args.count; i++ {
|
for i := 0; i < args.count; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
append(buf, ' ')
|
append(buf, ' ');
|
||||||
}
|
}
|
||||||
print_any_to_buffer(buf, args[i])
|
print_any_to_buffer(buf, args[i]);
|
||||||
}
|
}
|
||||||
print_nl_to_buffer(buf)
|
print_nl_to_buffer(buf);
|
||||||
return buf.count
|
return buf.count;
|
||||||
}
|
}
|
||||||
|
|||||||
+96
-96
@@ -1,164 +1,164 @@
|
|||||||
crc32 :: proc(data: rawptr, len: int) -> u32 {
|
crc32 :: proc(data: rawptr, len: int) -> u32 {
|
||||||
result := ~(0 as u32)
|
result := ~(0 as u32);
|
||||||
s := slice_ptr(data as ^u8, len)
|
s := slice_ptr(data as ^u8, len);
|
||||||
for i := 0; i < len; i++ {
|
for i := 0; i < len; i++ {
|
||||||
b := s[i] as u32
|
b := s[i] as u32;
|
||||||
result = result>>8 ~ __CRC32_TABLE[(result ~ b) & 0xff]
|
result = result>>8 ~ __CRC32_TABLE[(result ~ b) & 0xff];
|
||||||
}
|
}
|
||||||
return ~result
|
return ~result;
|
||||||
}
|
}
|
||||||
crc64 :: proc(data: rawptr, len: int) -> u64 {
|
crc64 :: proc(data: rawptr, len: int) -> u64 {
|
||||||
result := ~(0 as u64)
|
result := ~(0 as u64);
|
||||||
s := slice_ptr(data as ^u8, len)
|
s := slice_ptr(data as ^u8, len);
|
||||||
for i := 0; i < len; i++ {
|
for i := 0; i < len; i++ {
|
||||||
b := s[i] as u64
|
b := s[i] as u64;
|
||||||
result = result>>8 ~ __CRC64_TABLE[(result ~ b) & 0xff]
|
result = result>>8 ~ __CRC64_TABLE[(result ~ b) & 0xff];
|
||||||
}
|
}
|
||||||
return ~result
|
return ~result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv32 :: proc(data: rawptr, len: int) -> u32 {
|
fnv32 :: proc(data: rawptr, len: int) -> u32 {
|
||||||
s := slice_ptr(data as ^u8, len)
|
s := slice_ptr(data as ^u8, len);
|
||||||
|
|
||||||
h: u32 = 0x811c9dc5
|
h: u32 = 0x811c9dc5;
|
||||||
for i := 0; i < len; i++ {
|
for i := 0; i < len; i++ {
|
||||||
h = (h * 0x01000193) ~ s[i] as u32
|
h = (h * 0x01000193) ~ s[i] as u32;
|
||||||
}
|
}
|
||||||
return h
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv64 :: proc(data: rawptr, len: int) -> u64 {
|
fnv64 :: proc(data: rawptr, len: int) -> u64 {
|
||||||
s := slice_ptr(data as ^u8, len)
|
s := slice_ptr(data as ^u8, len);
|
||||||
|
|
||||||
h: u64 = 0xcbf29ce484222325
|
h: u64 = 0xcbf29ce484222325;
|
||||||
for i := 0; i < len; i++ {
|
for i := 0; i < len; i++ {
|
||||||
h = (h * 0x100000001b3) ~ s[i] as u64
|
h = (h * 0x100000001b3) ~ s[i] as u64;
|
||||||
}
|
}
|
||||||
return h
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv32a :: proc(data: rawptr, len: int) -> u32 {
|
fnv32a :: proc(data: rawptr, len: int) -> u32 {
|
||||||
s := slice_ptr(data as ^u8, len)
|
s := slice_ptr(data as ^u8, len);
|
||||||
|
|
||||||
h: u32 = 0x811c9dc5
|
h: u32 = 0x811c9dc5;
|
||||||
for i := 0; i < len; i++ {
|
for i := 0; i < len; i++ {
|
||||||
h = (h ~ s[i] as u32) * 0x01000193
|
h = (h ~ s[i] as u32) * 0x01000193;
|
||||||
}
|
}
|
||||||
return h
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv64a :: proc(data: rawptr, len: int) -> u64 {
|
fnv64a :: proc(data: rawptr, len: int) -> u64 {
|
||||||
s := slice_ptr(data as ^u8, len)
|
s := slice_ptr(data as ^u8, len);
|
||||||
|
|
||||||
h: u64 = 0xcbf29ce484222325
|
h: u64 = 0xcbf29ce484222325;
|
||||||
for i := 0; i < len; i++ {
|
for i := 0; i < len; i++ {
|
||||||
h = (h ~ s[i] as u64) * 0x100000001b3
|
h = (h ~ s[i] as u64) * 0x100000001b3;
|
||||||
}
|
}
|
||||||
return h
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
||||||
SEED :: 0x9747b28c
|
SEED :: 0x9747b28c;
|
||||||
|
|
||||||
if size_of(int) == 8 {
|
if size_of(int) == 8 {
|
||||||
m :: 0xc6a4a7935bd1e995
|
m :: 0xc6a4a7935bd1e995;
|
||||||
r :: 47
|
r :: 47;
|
||||||
|
|
||||||
h: u64 = SEED ~ (len as u64 * m)
|
h: u64 = SEED ~ (len as u64 * m);
|
||||||
|
|
||||||
data := slice_ptr(data_ as ^u64, len/size_of(u64))
|
data := slice_ptr(data_ as ^u64, len/size_of(u64));
|
||||||
data2 := slice_ptr(data_ as ^u8, len)
|
data2 := slice_ptr(data_ as ^u8, len);
|
||||||
|
|
||||||
for i := 0; i < data.count; i++ {
|
for i := 0; i < data.count; i++ {
|
||||||
k := data[i]
|
k := data[i];
|
||||||
|
|
||||||
k *= m
|
k *= m;
|
||||||
k ~= k>>r
|
k ~= k>>r;
|
||||||
k *= m
|
k *= m;
|
||||||
|
|
||||||
h ~= k
|
h ~= k;
|
||||||
h *= m
|
h *= m;
|
||||||
}
|
}
|
||||||
|
|
||||||
match len & 7 {
|
match len & 7 {
|
||||||
case 7: h ~= data2[6] as u64 << 48; fallthrough
|
case 7: h ~= data2[6] as u64 << 48; fallthrough;
|
||||||
case 6: h ~= data2[5] as u64 << 40; fallthrough
|
case 6: h ~= data2[5] as u64 << 40; fallthrough;
|
||||||
case 5: h ~= data2[4] as u64 << 32; fallthrough
|
case 5: h ~= data2[4] as u64 << 32; fallthrough;
|
||||||
case 4: h ~= data2[3] as u64 << 24; fallthrough
|
case 4: h ~= data2[3] as u64 << 24; fallthrough;
|
||||||
case 3: h ~= data2[2] as u64 << 16; fallthrough
|
case 3: h ~= data2[2] as u64 << 16; fallthrough;
|
||||||
case 2: h ~= data2[1] as u64 << 8; fallthrough
|
case 2: h ~= data2[1] as u64 << 8; fallthrough;
|
||||||
case 1:
|
case 1:
|
||||||
h ~= data2[0] as u64
|
h ~= data2[0] as u64;
|
||||||
h *= m
|
h *= m;
|
||||||
}
|
}
|
||||||
|
|
||||||
h ~= h>>r
|
h ~= h>>r;
|
||||||
h *= m
|
h *= m;
|
||||||
h ~= h>>r
|
h ~= h>>r;
|
||||||
|
|
||||||
return h
|
return h;
|
||||||
} else {
|
} else {
|
||||||
m :: 0x5bd1e995
|
m :: 0x5bd1e995;
|
||||||
r :: 24
|
r :: 24;
|
||||||
|
|
||||||
h1: u32 = SEED as u32 ~ len as u32
|
h1: u32 = SEED as u32 ~ len as u32;
|
||||||
h2: u32 = SEED >> 32
|
h2: u32 = SEED >> 32;
|
||||||
|
|
||||||
data := slice_ptr(data_ as ^u32, len/size_of(u32))
|
data := slice_ptr(data_ as ^u32, len/size_of(u32));
|
||||||
|
|
||||||
i := 0
|
i := 0;
|
||||||
for len >= 8 {
|
for len >= 8 {
|
||||||
k1, k2: u32
|
k1, k2: u32;
|
||||||
k1 = data[i]; i++
|
k1 = data[i]; i++;
|
||||||
k1 *= m
|
k1 *= m;
|
||||||
k1 ~= k1>>r
|
k1 ~= k1>>r;
|
||||||
k1 *= m
|
k1 *= m;
|
||||||
h1 *= m
|
h1 *= m;
|
||||||
h1 ~= k1
|
h1 ~= k1;
|
||||||
len -= 4
|
len -= 4;
|
||||||
|
|
||||||
k2 = data[i]; i++
|
k2 = data[i]; i++;
|
||||||
k2 *= m
|
k2 *= m;
|
||||||
k2 ~= k2>>r
|
k2 ~= k2>>r;
|
||||||
k2 *= m
|
k2 *= m;
|
||||||
h2 *= m
|
h2 *= m;
|
||||||
h2 ~= k2
|
h2 ~= k2;
|
||||||
len -= 4
|
len -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len >= 4) {
|
if (len >= 4) {
|
||||||
k1: u32
|
k1: u32;
|
||||||
k1 = data[i]; i++
|
k1 = data[i]; i++;
|
||||||
k1 *= m
|
k1 *= m;
|
||||||
k1 ~= k1>>r
|
k1 ~= k1>>r;
|
||||||
k1 *= m
|
k1 *= m;
|
||||||
h1 *= m
|
h1 *= m;
|
||||||
h1 ~= k1
|
h1 ~= k1;
|
||||||
len -= 4
|
len -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
data8 := slice_ptr((data.data+i) as ^u8, 3) // NOTE(bill): This is unsafe
|
data8 := slice_ptr((data.data+i) as ^u8, 3); // NOTE(bill): This is unsafe
|
||||||
|
|
||||||
match len {
|
match len {
|
||||||
case 3: h2 ~= data8[2] as u32 << 16; fallthrough
|
case 3: h2 ~= data8[2] as u32 << 16; fallthrough;
|
||||||
case 2: h2 ~= data8[1] as u32 << 8; fallthrough
|
case 2: h2 ~= data8[1] as u32 << 8; fallthrough;
|
||||||
case 1:
|
case 1:
|
||||||
h2 ~= data8[0] as u32
|
h2 ~= data8[0] as u32;
|
||||||
h2 *= m
|
h2 *= m;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 ~= h2>>18
|
h1 ~= h2>>18;
|
||||||
h1 *= m
|
h1 *= m;
|
||||||
h2 ~= h1>>22
|
h2 ~= h1>>22;
|
||||||
h2 *= m
|
h2 *= m;
|
||||||
h1 ~= h2>>17
|
h1 ~= h2>>17;
|
||||||
h1 *= m
|
h1 *= m;
|
||||||
h2 ~= h1>>19
|
h2 ~= h1>>19;
|
||||||
h2 *= m
|
h2 *= m;
|
||||||
|
|
||||||
h := (h1 as u64)<<32 | h2 as u64
|
h := (h1 as u64)<<32 | h2 as u64;
|
||||||
return h
|
return h;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +229,7 @@ __CRC32_TABLE := [256]u32{
|
|||||||
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
|
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
|
||||||
}
|
};
|
||||||
__CRC64_TABLE := [256]u64{
|
__CRC64_TABLE := [256]u64{
|
||||||
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
|
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
|
||||||
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
|
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
|
||||||
@@ -295,4 +295,4 @@ __CRC64_TABLE := [256]u64{
|
|||||||
0xcf8b0890283e370c, 0x8d7be97b81d4019f, 0x4a6acb477bea5a2a, 0x089a2aacd2006cb9,
|
0xcf8b0890283e370c, 0x8d7be97b81d4019f, 0x4a6acb477bea5a2a, 0x089a2aacd2006cb9,
|
||||||
0x14dea25f3af9026d, 0x562e43b4931334fe, 0x913f6188692d6f4b, 0xd3cf8063c0c759d8,
|
0x14dea25f3af9026d, 0x562e43b4931334fe, 0x913f6188692d6f4b, 0xd3cf8063c0c759d8,
|
||||||
0x5dedc41a34bbeeb2, 0x1f1d25f19d51d821, 0xd80c07cd676f8394, 0x9afce626ce85b507,
|
0x5dedc41a34bbeeb2, 0x1f1d25f19d51d821, 0xd80c07cd676f8394, 0x9afce626ce85b507,
|
||||||
}
|
};
|
||||||
|
|||||||
+206
-209
@@ -1,29 +1,29 @@
|
|||||||
TAU :: 6.28318530717958647692528676655900576
|
TAU :: 6.28318530717958647692528676655900576;
|
||||||
PI :: 3.14159265358979323846264338327950288
|
PI :: 3.14159265358979323846264338327950288;
|
||||||
ONE_OVER_TAU :: 0.636619772367581343075535053490057448
|
ONE_OVER_TAU :: 0.636619772367581343075535053490057448;
|
||||||
ONE_OVER_PI :: 0.159154943091895335768883763372514362
|
ONE_OVER_PI :: 0.159154943091895335768883763372514362;
|
||||||
|
|
||||||
E :: 2.71828182845904523536
|
E :: 2.71828182845904523536;
|
||||||
SQRT_TWO :: 1.41421356237309504880168872420969808
|
SQRT_TWO :: 1.41421356237309504880168872420969808;
|
||||||
SQRT_THREE :: 1.73205080756887729352744634150587236
|
SQRT_THREE :: 1.73205080756887729352744634150587236;
|
||||||
SQRT_FIVE :: 2.23606797749978969640917366873127623
|
SQRT_FIVE :: 2.23606797749978969640917366873127623;
|
||||||
|
|
||||||
LOG_TWO :: 0.693147180559945309417232121458176568
|
LOG_TWO :: 0.693147180559945309417232121458176568;
|
||||||
LOG_TEN :: 2.30258509299404568401799145468436421
|
LOG_TEN :: 2.30258509299404568401799145468436421;
|
||||||
|
|
||||||
EPSILON :: 1.19209290e-7
|
EPSILON :: 1.19209290e-7;
|
||||||
|
|
||||||
τ :: TAU
|
τ :: TAU;
|
||||||
π :: PI
|
π :: PI;
|
||||||
|
|
||||||
|
|
||||||
Vec2 :: type {2}f32
|
Vec2 :: type [vector 2]f32;
|
||||||
Vec3 :: type {3}f32
|
Vec3 :: type [vector 3]f32;
|
||||||
Vec4 :: type {4}f32
|
Vec4 :: type [vector 4]f32;
|
||||||
|
|
||||||
Mat2 :: type [2]Vec2
|
Mat2 :: type [2]Vec2;
|
||||||
Mat3 :: type [3]Vec3
|
Mat3 :: type [3]Vec3;
|
||||||
Mat4 :: type [4]Vec4
|
Mat4 :: type [4]Vec4;
|
||||||
|
|
||||||
|
|
||||||
sqrt32 :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
|
sqrt32 :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
|
||||||
@@ -35,107 +35,104 @@ sin64 :: proc(x: f64) -> f64 #foreign "llvm.sin.f64"
|
|||||||
cos32 :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
|
cos32 :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
|
||||||
cos64 :: proc(x: f64) -> f64 #foreign "llvm.cos.f64"
|
cos64 :: proc(x: f64) -> f64 #foreign "llvm.cos.f64"
|
||||||
|
|
||||||
tan32 :: proc(x: f32) -> f32 #inline { return sin32(x)/cos32(x) }
|
tan32 :: proc(x: f32) -> f32 #inline { return sin32(x)/cos32(x); }
|
||||||
tan64 :: proc(x: f64) -> f64 #inline { return sin64(x)/cos64(x) }
|
tan64 :: proc(x: f64) -> f64 #inline { return sin64(x)/cos64(x); }
|
||||||
|
|
||||||
lerp32 :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t }
|
lerp32 :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; }
|
||||||
lerp64 :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t }
|
lerp64 :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; }
|
||||||
|
|
||||||
clamp32 :: proc(x, lower, upper: f32) -> f32 { return min(max(x, lower), upper) }
|
sign32 :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
|
||||||
clamp64 :: proc(x, lower, upper: f64) -> f64 { return min(max(x, lower), upper) }
|
sign64 :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
|
||||||
|
|
||||||
sign32 :: proc(x: f32) -> f32 { if x >= 0 { return +1 } return -1 }
|
|
||||||
sign64 :: proc(x: f64) -> f64 { if x >= 0 { return +1 } return -1 }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
copy_sign32 :: proc(x, y: f32) -> f32 {
|
copy_sign32 :: proc(x, y: f32) -> f32 {
|
||||||
ix := x transmute u32
|
ix := x transmute u32;
|
||||||
iy := y transmute u32
|
iy := y transmute u32;
|
||||||
ix &= 0x7fffffff
|
ix &= 0x7fffffff;
|
||||||
ix |= iy & 0x80000000
|
ix |= iy & 0x80000000;
|
||||||
return ix transmute f32
|
return ix transmute f32;
|
||||||
}
|
}
|
||||||
round32 :: proc(x: f32) -> f32 {
|
round32 :: proc(x: f32) -> f32 {
|
||||||
if x >= 0 {
|
if x >= 0 {
|
||||||
return floor32(x + 0.5)
|
return floor32(x + 0.5);
|
||||||
}
|
}
|
||||||
return ceil32(x - 0.5)
|
return ceil32(x - 0.5);
|
||||||
}
|
}
|
||||||
floor32 :: proc(x: f32) -> f32 {
|
floor32 :: proc(x: f32) -> f32 {
|
||||||
if x >= 0 {
|
if x >= 0 {
|
||||||
return x as int as f32
|
return x as int as f32;
|
||||||
}
|
}
|
||||||
return (x-0.5) as int as f32
|
return (x-0.5) as int as f32;
|
||||||
}
|
}
|
||||||
ceil32 :: proc(x: f32) -> f32 {
|
ceil32 :: proc(x: f32) -> f32 {
|
||||||
if x < 0 {
|
if x < 0 {
|
||||||
return x as int as f32
|
return x as int as f32;
|
||||||
}
|
}
|
||||||
return ((x as int)+1) as f32
|
return ((x as int)+1) as f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
remainder32 :: proc(x, y: f32) -> f32 {
|
remainder32 :: proc(x, y: f32) -> f32 {
|
||||||
return x - round32(x/y) * y
|
return x - round32(x/y) * y;
|
||||||
}
|
}
|
||||||
|
|
||||||
fmod32 :: proc(x, y: f32) -> f32 {
|
fmod32 :: proc(x, y: f32) -> f32 {
|
||||||
y = abs(y)
|
y = abs(y);
|
||||||
result := remainder32(abs(x), y)
|
result := remainder32(abs(x), y);
|
||||||
if sign32(result) < 0 {
|
if sign32(result) < 0 {
|
||||||
result += y
|
result += y;
|
||||||
}
|
}
|
||||||
return copy_sign32(result, x)
|
return copy_sign32(result, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
to_radians :: proc(degrees: f32) -> f32 { return degrees * TAU / 360 }
|
to_radians :: proc(degrees: f32) -> f32 { return degrees * TAU / 360; }
|
||||||
to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU }
|
to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dot2 :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y }
|
dot2 :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y; }
|
||||||
dot3 :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z }
|
dot3 :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
|
||||||
dot4 :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w }
|
dot4 :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
|
||||||
|
|
||||||
cross3 :: proc(x, y: Vec3) -> Vec3 {
|
cross3 :: proc(x, y: Vec3) -> Vec3 {
|
||||||
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1)
|
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
|
||||||
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0)
|
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
|
||||||
return a - b
|
return a - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vec2_mag :: proc(v: Vec2) -> f32 { return sqrt32(dot2(v, v)) }
|
vec2_mag :: proc(v: Vec2) -> f32 { return sqrt32(dot2(v, v)); }
|
||||||
vec3_mag :: proc(v: Vec3) -> f32 { return sqrt32(dot3(v, v)) }
|
vec3_mag :: proc(v: Vec3) -> f32 { return sqrt32(dot3(v, v)); }
|
||||||
vec4_mag :: proc(v: Vec4) -> f32 { return sqrt32(dot4(v, v)) }
|
vec4_mag :: proc(v: Vec4) -> f32 { return sqrt32(dot4(v, v)); }
|
||||||
|
|
||||||
vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)} }
|
vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)}; }
|
||||||
vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)} }
|
vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; }
|
||||||
vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)} }
|
vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)}; }
|
||||||
|
|
||||||
vec2_norm0 :: proc(v: Vec2) -> Vec2 {
|
vec2_norm0 :: proc(v: Vec2) -> Vec2 {
|
||||||
m := vec2_mag(v)
|
m := vec2_mag(v);
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
return Vec2{0}
|
return Vec2{0};
|
||||||
}
|
}
|
||||||
return v / Vec2{m}
|
return v / Vec2{m};
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3_norm0 :: proc(v: Vec3) -> Vec3 {
|
vec3_norm0 :: proc(v: Vec3) -> Vec3 {
|
||||||
m := vec3_mag(v)
|
m := vec3_mag(v);
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
return Vec3{0}
|
return Vec3{0};
|
||||||
}
|
}
|
||||||
return v / Vec3{m}
|
return v / Vec3{m};
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4_norm0 :: proc(v: Vec4) -> Vec4 {
|
vec4_norm0 :: proc(v: Vec4) -> Vec4 {
|
||||||
m := vec4_mag(v)
|
m := vec4_mag(v);
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
return Vec4{0}
|
return Vec4{0};
|
||||||
}
|
}
|
||||||
return v / Vec4{m}
|
return v / Vec4{m};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -146,29 +143,29 @@ mat4_identity :: proc() -> Mat4 {
|
|||||||
{0, 1, 0, 0},
|
{0, 1, 0, 0},
|
||||||
{0, 0, 1, 0},
|
{0, 0, 1, 0},
|
||||||
{0, 0, 0, 1},
|
{0, 0, 0, 1},
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
||||||
for j := 0; j < 4; j++ {
|
for j := 0; j < 4; j++ {
|
||||||
for i := 0; i < 4; i++ {
|
for i := 0; i < 4; i++ {
|
||||||
m[i][j], m[j][i] = m[j][i], m[i][j]
|
m[i][j], m[j][i] = m[j][i], m[i][j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
|
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
|
||||||
c: Mat4
|
c: Mat4;
|
||||||
for j := 0; j < 4; j++ {
|
for j := 0; j < 4; j++ {
|
||||||
for i := 0; i < 4; i++ {
|
for i := 0; i < 4; i++ {
|
||||||
c[j][i] = a[0][i]*b[j][0]
|
c[j][i] = a[0][i]*b[j][0]
|
||||||
+ a[1][i]*b[j][1]
|
+ a[1][i]*b[j][1]
|
||||||
+ a[2][i]*b[j][2]
|
+ a[2][i]*b[j][2]
|
||||||
+ a[3][i]*b[j][3]
|
+ a[3][i]*b[j][3];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||||
@@ -177,197 +174,197 @@ mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
|||||||
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
|
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
|
||||||
m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z + m[3][2]*v.w,
|
m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z + m[3][2]*v.w,
|
||||||
m[0][3]*v.x + m[1][3]*v.y + m[2][3]*v.z + m[3][3]*v.w,
|
m[0][3]*v.x + m[1][3]*v.y + m[2][3]*v.z + m[3][3]*v.w,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_inverse :: proc(m: Mat4) -> Mat4 {
|
mat4_inverse :: proc(m: Mat4) -> Mat4 {
|
||||||
o: Mat4
|
o: Mat4;
|
||||||
|
|
||||||
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3]
|
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
|
||||||
sf01 := m[2][1] * m[3][3] - m[3][1] * m[2][3]
|
sf01 := m[2][1] * m[3][3] - m[3][1] * m[2][3];
|
||||||
sf02 := m[2][1] * m[3][2] - m[3][1] * m[2][2]
|
sf02 := m[2][1] * m[3][2] - m[3][1] * m[2][2];
|
||||||
sf03 := m[2][0] * m[3][3] - m[3][0] * m[2][3]
|
sf03 := m[2][0] * m[3][3] - m[3][0] * m[2][3];
|
||||||
sf04 := m[2][0] * m[3][2] - m[3][0] * m[2][2]
|
sf04 := m[2][0] * m[3][2] - m[3][0] * m[2][2];
|
||||||
sf05 := m[2][0] * m[3][1] - m[3][0] * m[2][1]
|
sf05 := m[2][0] * m[3][1] - m[3][0] * m[2][1];
|
||||||
sf06 := m[1][2] * m[3][3] - m[3][2] * m[1][3]
|
sf06 := m[1][2] * m[3][3] - m[3][2] * m[1][3];
|
||||||
sf07 := m[1][1] * m[3][3] - m[3][1] * m[1][3]
|
sf07 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
|
||||||
sf08 := m[1][1] * m[3][2] - m[3][1] * m[1][2]
|
sf08 := m[1][1] * m[3][2] - m[3][1] * m[1][2];
|
||||||
sf09 := m[1][0] * m[3][3] - m[3][0] * m[1][3]
|
sf09 := m[1][0] * m[3][3] - m[3][0] * m[1][3];
|
||||||
sf10 := m[1][0] * m[3][2] - m[3][0] * m[1][2]
|
sf10 := m[1][0] * m[3][2] - m[3][0] * m[1][2];
|
||||||
sf11 := m[1][1] * m[3][3] - m[3][1] * m[1][3]
|
sf11 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
|
||||||
sf12 := m[1][0] * m[3][1] - m[3][0] * m[1][1]
|
sf12 := m[1][0] * m[3][1] - m[3][0] * m[1][1];
|
||||||
sf13 := m[1][2] * m[2][3] - m[2][2] * m[1][3]
|
sf13 := m[1][2] * m[2][3] - m[2][2] * m[1][3];
|
||||||
sf14 := m[1][1] * m[2][3] - m[2][1] * m[1][3]
|
sf14 := m[1][1] * m[2][3] - m[2][1] * m[1][3];
|
||||||
sf15 := m[1][1] * m[2][2] - m[2][1] * m[1][2]
|
sf15 := m[1][1] * m[2][2] - m[2][1] * m[1][2];
|
||||||
sf16 := m[1][0] * m[2][3] - m[2][0] * m[1][3]
|
sf16 := m[1][0] * m[2][3] - m[2][0] * m[1][3];
|
||||||
sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2]
|
sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2];
|
||||||
sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1]
|
sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1];
|
||||||
|
|
||||||
o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02)
|
o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02);
|
||||||
o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04)
|
o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04);
|
||||||
o[0][2] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05)
|
o[0][2] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05);
|
||||||
o[0][3] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05)
|
o[0][3] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05);
|
||||||
|
|
||||||
o[1][0] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02)
|
o[1][0] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02);
|
||||||
o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04)
|
o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04);
|
||||||
o[1][2] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05)
|
o[1][2] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05);
|
||||||
o[1][3] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05)
|
o[1][3] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05);
|
||||||
|
|
||||||
o[2][0] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08)
|
o[2][0] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08);
|
||||||
o[2][1] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10)
|
o[2][1] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10);
|
||||||
o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12)
|
o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12);
|
||||||
o[2][3] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12)
|
o[2][3] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12);
|
||||||
|
|
||||||
o[3][0] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15)
|
o[3][0] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15);
|
||||||
o[3][1] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17)
|
o[3][1] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17);
|
||||||
o[3][2] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18)
|
o[3][2] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18);
|
||||||
o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18)
|
o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18);
|
||||||
|
|
||||||
ood := 1.0 / (m[0][0] * o[0][0] +
|
ood := 1.0 / (m[0][0] * o[0][0] +
|
||||||
m[0][1] * o[0][1] +
|
m[0][1] * o[0][1] +
|
||||||
m[0][2] * o[0][2] +
|
m[0][2] * o[0][2] +
|
||||||
m[0][3] * o[0][3])
|
m[0][3] * o[0][3]);
|
||||||
|
|
||||||
o[0][0] *= ood
|
o[0][0] *= ood;
|
||||||
o[0][1] *= ood
|
o[0][1] *= ood;
|
||||||
o[0][2] *= ood
|
o[0][2] *= ood;
|
||||||
o[0][3] *= ood
|
o[0][3] *= ood;
|
||||||
o[1][0] *= ood
|
o[1][0] *= ood;
|
||||||
o[1][1] *= ood
|
o[1][1] *= ood;
|
||||||
o[1][2] *= ood
|
o[1][2] *= ood;
|
||||||
o[1][3] *= ood
|
o[1][3] *= ood;
|
||||||
o[2][0] *= ood
|
o[2][0] *= ood;
|
||||||
o[2][1] *= ood
|
o[2][1] *= ood;
|
||||||
o[2][2] *= ood
|
o[2][2] *= ood;
|
||||||
o[2][3] *= ood
|
o[2][3] *= ood;
|
||||||
o[3][0] *= ood
|
o[3][0] *= ood;
|
||||||
o[3][1] *= ood
|
o[3][1] *= ood;
|
||||||
o[3][2] *= ood
|
o[3][2] *= ood;
|
||||||
o[3][3] *= ood
|
o[3][3] *= ood;
|
||||||
|
|
||||||
return o
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mat4_translate :: proc(v: Vec3) -> Mat4 {
|
mat4_translate :: proc(v: Vec3) -> Mat4 {
|
||||||
m := mat4_identity()
|
m := mat4_identity();
|
||||||
m[3][0] = v.x
|
m[3][0] = v.x;
|
||||||
m[3][1] = v.y
|
m[3][1] = v.y;
|
||||||
m[3][2] = v.z
|
m[3][2] = v.z;
|
||||||
m[3][3] = 1
|
m[3][3] = 1;
|
||||||
return m
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
||||||
c := cos32(angle_radians)
|
c := cos32(angle_radians);
|
||||||
s := sin32(angle_radians)
|
s := sin32(angle_radians);
|
||||||
|
|
||||||
a := vec3_norm(v)
|
a := vec3_norm(v);
|
||||||
t := a * Vec3{1-c}
|
t := a * Vec3{1-c};
|
||||||
|
|
||||||
rot := mat4_identity()
|
rot := mat4_identity();
|
||||||
|
|
||||||
rot[0][0] = c + t.x*a.x
|
rot[0][0] = c + t.x*a.x;
|
||||||
rot[0][1] = 0 + t.x*a.y + s*a.z
|
rot[0][1] = 0 + t.x*a.y + s*a.z;
|
||||||
rot[0][2] = 0 + t.x*a.z - s*a.y
|
rot[0][2] = 0 + t.x*a.z - s*a.y;
|
||||||
rot[0][3] = 0
|
rot[0][3] = 0;
|
||||||
|
|
||||||
rot[1][0] = 0 + t.y*a.x - s*a.z
|
rot[1][0] = 0 + t.y*a.x - s*a.z;
|
||||||
rot[1][1] = c + t.y*a.y
|
rot[1][1] = c + t.y*a.y;
|
||||||
rot[1][2] = 0 + t.y*a.z + s*a.x
|
rot[1][2] = 0 + t.y*a.z + s*a.x;
|
||||||
rot[1][3] = 0
|
rot[1][3] = 0;
|
||||||
|
|
||||||
rot[2][0] = 0 + t.z*a.x + s*a.y
|
rot[2][0] = 0 + t.z*a.x + s*a.y;
|
||||||
rot[2][1] = 0 + t.z*a.y - s*a.x
|
rot[2][1] = 0 + t.z*a.y - s*a.x;
|
||||||
rot[2][2] = c + t.z*a.z
|
rot[2][2] = c + t.z*a.z;
|
||||||
rot[2][3] = 0
|
rot[2][3] = 0;
|
||||||
|
|
||||||
return rot
|
return rot;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
mat4_scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
||||||
m[0][0] = v.x
|
m[0][0] = v.x;
|
||||||
m[1][1] = v.y
|
m[1][1] = v.y;
|
||||||
m[2][2] = v.z
|
m[2][2] = v.z;
|
||||||
return m
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_scalef :: proc(m: Mat4, s: f32) -> Mat4 {
|
mat4_scalef :: proc(m: Mat4, s: f32) -> Mat4 {
|
||||||
m[0][0] = s
|
m[0][0] = s;
|
||||||
m[1][1] = s
|
m[1][1] = s;
|
||||||
m[2][2] = s
|
m[2][2] = s;
|
||||||
return m
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mat4_look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
mat4_look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
||||||
f := vec3_norm(centre - eye)
|
f := vec3_norm(centre - eye);
|
||||||
s := vec3_norm(cross3(f, up))
|
s := vec3_norm(cross3(f, up));
|
||||||
u := cross3(s, f)
|
u := cross3(s, f);
|
||||||
|
|
||||||
m: Mat4
|
m: Mat4;
|
||||||
|
|
||||||
m[0] = Vec4{+s.x, +s.y, +s.z, 0}
|
m[0] = Vec4{+s.x, +s.y, +s.z, 0};
|
||||||
m[1] = Vec4{+u.x, +u.y, +u.z, 0}
|
m[1] = Vec4{+u.x, +u.y, +u.z, 0};
|
||||||
m[2] = Vec4{-f.x, -f.y, -f.z, 0}
|
m[2] = Vec4{-f.x, -f.y, -f.z, 0};
|
||||||
m[3] = Vec4{dot3(s, eye), dot3(u, eye), dot3(f, eye), 1}
|
m[3] = Vec4{dot3(s, eye), dot3(u, eye), dot3(f, eye), 1};
|
||||||
|
|
||||||
return m
|
return m;
|
||||||
}
|
}
|
||||||
mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
|
mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
|
||||||
m: Mat4
|
m: Mat4;
|
||||||
tan_half_fovy := tan32(0.5 * fovy)
|
tan_half_fovy := tan32(0.5 * fovy);
|
||||||
m[0][0] = 1.0 / (aspect*tan_half_fovy)
|
m[0][0] = 1.0 / (aspect*tan_half_fovy);
|
||||||
m[1][1] = 1.0 / (tan_half_fovy)
|
m[1][1] = 1.0 / (tan_half_fovy);
|
||||||
m[2][2] = -(far + near) / (far - near)
|
m[2][2] = -(far + near) / (far - near);
|
||||||
m[2][3] = -1.0
|
m[2][3] = -1.0;
|
||||||
m[3][2] = -2.0*far*near / (far - near)
|
m[3][2] = -2.0*far*near / (far - near);
|
||||||
return m
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mat4_ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
|
mat4_ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
|
||||||
m := mat4_identity()
|
m := mat4_identity();
|
||||||
|
|
||||||
m[0][0] = +2.0 / (right - left)
|
m[0][0] = +2.0 / (right - left);
|
||||||
m[1][1] = +2.0 / (top - bottom)
|
m[1][1] = +2.0 / (top - bottom);
|
||||||
m[2][2] = -2.0 / (far - near)
|
m[2][2] = -2.0 / (far - near);
|
||||||
m[3][0] = -(right + left) / (right - left)
|
m[3][0] = -(right + left) / (right - left);
|
||||||
m[3][1] = -(top + bottom) / (top - bottom)
|
m[3][1] = -(top + bottom) / (top - bottom);
|
||||||
m[3][2] = -(far + near) / (far - near)
|
m[3][2] = -(far + near) / (far - near);
|
||||||
|
|
||||||
return m
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
F32_DIG :: 6
|
F32_DIG :: 6;
|
||||||
F32_EPSILON :: 1.192092896e-07
|
F32_EPSILON :: 1.192092896e-07;
|
||||||
F32_GUARD :: 0
|
F32_GUARD :: 0;
|
||||||
F32_MANT_DIG :: 24
|
F32_MANT_DIG :: 24;
|
||||||
F32_MAX :: 3.402823466e+38
|
F32_MAX :: 3.402823466e+38;
|
||||||
F32_MAX_10_EXP :: 38
|
F32_MAX_10_EXP :: 38;
|
||||||
F32_MAX_EXP :: 128
|
F32_MAX_EXP :: 128;
|
||||||
F32_MIN :: 1.175494351e-38
|
F32_MIN :: 1.175494351e-38;
|
||||||
F32_MIN_10_EXP :: -37
|
F32_MIN_10_EXP :: -37;
|
||||||
F32_MIN_EXP :: -125
|
F32_MIN_EXP :: -125;
|
||||||
F32_NORMALIZE :: 0
|
F32_NORMALIZE :: 0;
|
||||||
F32_RADIX :: 2
|
F32_RADIX :: 2;
|
||||||
F32_ROUNDS :: 1
|
F32_ROUNDS :: 1;
|
||||||
|
|
||||||
F64_DIG :: 15 // # of decimal digits of precision
|
F64_DIG :: 15; // # of decimal digits of precision
|
||||||
F64_EPSILON :: 2.2204460492503131e-016 // smallest such that 1.0+F64_EPSILON != 1.0
|
F64_EPSILON :: 2.2204460492503131e-016; // smallest such that 1.0+F64_EPSILON != 1.0
|
||||||
F64_MANT_DIG :: 53 // # of bits in mantissa
|
F64_MANT_DIG :: 53; // # of bits in mantissa
|
||||||
F64_MAX :: 1.7976931348623158e+308 // max value
|
F64_MAX :: 1.7976931348623158e+308; // max value
|
||||||
F64_MAX_10_EXP :: 308 // max decimal exponent
|
F64_MAX_10_EXP :: 308; // max decimal exponent
|
||||||
F64_MAX_EXP :: 1024 // max binary exponent
|
F64_MAX_EXP :: 1024; // max binary exponent
|
||||||
F64_MIN :: 2.2250738585072014e-308 // min positive value
|
F64_MIN :: 2.2250738585072014e-308; // min positive value
|
||||||
F64_MIN_10_EXP :: -307 // min decimal exponent
|
F64_MIN_10_EXP :: -307; // min decimal exponent
|
||||||
F64_MIN_EXP :: -1021 // min binary exponent
|
F64_MIN_EXP :: -1021; // min binary exponent
|
||||||
F64_RADIX :: 2 // exponent radix
|
F64_RADIX :: 2; // exponent radix
|
||||||
F64_ROUNDS :: 1 // addition rounding: near
|
F64_ROUNDS :: 1; // addition rounding: near
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+127
-127
@@ -1,51 +1,51 @@
|
|||||||
#import "fmt.odin"
|
#import "fmt.odin";
|
||||||
#import "os.odin"
|
#import "os.odin";
|
||||||
|
|
||||||
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
|
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
|
||||||
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
|
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
|
||||||
llvm_memset_64bit(data, value as byte, len, 1, false)
|
llvm_memset_64bit(data, value as byte, len, 1, false);
|
||||||
return data
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
zero :: proc(data: rawptr, len: int) -> rawptr {
|
zero :: proc(data: rawptr, len: int) -> rawptr {
|
||||||
return set(data, 0, len)
|
return set(data, 0, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
|
copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
|
||||||
// NOTE(bill): This _must_ implemented like C's memmove
|
// NOTE(bill): This _must_ implemented like C's memmove
|
||||||
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
|
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
|
||||||
llvm_memmove_64bit(dst, src, len, 1, false)
|
llvm_memmove_64bit(dst, src, len, 1, false);
|
||||||
return dst
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
|
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
|
||||||
// NOTE(bill): This _must_ implemented like C's memcpy
|
// NOTE(bill): This _must_ implemented like C's memcpy
|
||||||
llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
|
llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
|
||||||
llvm_memcpy_64bit(dst, src, len, 1, false)
|
llvm_memcpy_64bit(dst, src, len, 1, false);
|
||||||
return dst
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
|
compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
|
||||||
// Translation of http://mgronhol.github.io/fast-strcmp/
|
// Translation of http://mgronhol.github.io/fast-strcmp/
|
||||||
a := slice_ptr(dst as ^byte, n)
|
a := slice_ptr(dst as ^byte, n);
|
||||||
b := slice_ptr(src as ^byte, n)
|
b := slice_ptr(src as ^byte, n);
|
||||||
|
|
||||||
fast := n/size_of(int) + 1
|
fast := n/size_of(int) + 1;
|
||||||
offset := (fast-1)*size_of(int)
|
offset := (fast-1)*size_of(int);
|
||||||
curr_block := 0
|
curr_block := 0;
|
||||||
if n <= size_of(int) {
|
if n <= size_of(int) {
|
||||||
fast = 0
|
fast = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
la := slice_ptr(^a[0] as ^int, fast)
|
la := slice_ptr(^a[0] as ^int, fast);
|
||||||
lb := slice_ptr(^b[0] as ^int, fast)
|
lb := slice_ptr(^b[0] as ^int, fast);
|
||||||
|
|
||||||
for ; curr_block < fast; curr_block++ {
|
for ; curr_block < fast; curr_block++ {
|
||||||
if (la[curr_block] ~ lb[curr_block]) != 0 {
|
if (la[curr_block] ~ lb[curr_block]) != 0 {
|
||||||
for pos := curr_block*size_of(int); pos < n; pos++ {
|
for pos := curr_block*size_of(int); pos < n; pos++ {
|
||||||
if (a[pos] ~ b[pos]) != 0 {
|
if (a[pos] ~ b[pos]) != 0 {
|
||||||
return a[pos] as int - b[pos] as int
|
return a[pos] as int - b[pos] as int;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,58 +54,58 @@ compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
|
|||||||
|
|
||||||
for ; offset < n; offset++ {
|
for ; offset < n; offset++ {
|
||||||
if (a[offset] ~ b[offset]) != 0 {
|
if (a[offset] ~ b[offset]) != 0 {
|
||||||
return a[offset] as int - b[offset] as int
|
return a[offset] as int - b[offset] as int;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
kilobytes :: proc(x: int) -> int #inline { return (x) * 1024 }
|
kilobytes :: proc(x: int) -> int #inline { return (x) * 1024; }
|
||||||
megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024 }
|
megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024; }
|
||||||
gigabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024 }
|
gigabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; }
|
||||||
terabytes :: proc(x: int) -> int #inline { return terabytes(x) * 1024 }
|
terabytes :: proc(x: int) -> int #inline { return terabytes(x) * 1024; }
|
||||||
|
|
||||||
is_power_of_two :: proc(x: int) -> bool {
|
is_power_of_two :: proc(x: int) -> bool {
|
||||||
if x <= 0 {
|
if x <= 0 {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
return (x & (x-1)) == 0
|
return (x & (x-1)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
|
align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
|
||||||
assert(is_power_of_two(align))
|
assert(is_power_of_two(align));
|
||||||
|
|
||||||
a := align as uint
|
a := align as uint;
|
||||||
p := ptr as uint
|
p := ptr as uint;
|
||||||
modulo := p & (a-1)
|
modulo := p & (a-1);
|
||||||
if modulo != 0 {
|
if modulo != 0 {
|
||||||
p += a - modulo
|
p += a - modulo;
|
||||||
}
|
}
|
||||||
return p as rawptr
|
return p as rawptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AllocationHeader :: struct {
|
AllocationHeader :: struct {
|
||||||
size: int
|
size: int;
|
||||||
}
|
}
|
||||||
allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: int) {
|
allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: int) {
|
||||||
header.size = size
|
header.size = size;
|
||||||
ptr := (header+1) as ^int
|
ptr := (header+1) as ^int;
|
||||||
|
|
||||||
for i := 0; ptr as rawptr < data; i++ {
|
for i := 0; ptr as rawptr < data; i++ {
|
||||||
(ptr+i)^ = -1
|
(ptr+i)^ = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
|
allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
|
||||||
p := data as ^int
|
p := data as ^int;
|
||||||
for (p-1)^ == -1 {
|
for (p-1)^ == -1 {
|
||||||
p = (p-1)
|
p = (p-1);
|
||||||
}
|
}
|
||||||
return (p as ^AllocationHeader)-1
|
return (p as ^AllocationHeader)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -115,13 +115,13 @@ allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
|
|||||||
// Custom allocators
|
// Custom allocators
|
||||||
|
|
||||||
Arena :: struct {
|
Arena :: struct {
|
||||||
backing: Allocator
|
backing: Allocator;
|
||||||
memory: []byte
|
memory: []byte;
|
||||||
temp_count: int
|
temp_count: int;
|
||||||
|
|
||||||
Temp_Memory :: struct {
|
Temp_Memory :: struct {
|
||||||
arena: ^Arena
|
arena: ^Arena;
|
||||||
original_count: int
|
original_count: int;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,22 +130,22 @@ Arena :: struct {
|
|||||||
|
|
||||||
|
|
||||||
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
|
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
|
||||||
backing = Allocator{}
|
backing = Allocator{};
|
||||||
memory = data[:0]
|
memory = data[:0];
|
||||||
temp_count = 0
|
temp_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_arena_from_context :: proc(using a: ^Arena, size: int) {
|
init_arena_from_context :: proc(using a: ^Arena, size: int) {
|
||||||
backing = context.allocator
|
backing = context.allocator;
|
||||||
memory = new_slice(byte, 0, size)
|
memory = new_slice(byte, 0, size);
|
||||||
temp_count = 0
|
temp_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
free_arena :: proc(using a: ^Arena) {
|
free_arena :: proc(using a: ^Arena) {
|
||||||
if backing.procedure != nil {
|
if backing.procedure != nil {
|
||||||
push_allocator backing {
|
push_allocator backing {
|
||||||
free(memory.data)
|
free(memory.data);
|
||||||
memory = memory[0:0:0]
|
memory = memory[0:0:0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,57 +154,57 @@ arena_allocator :: proc(arena: ^Arena) -> Allocator {
|
|||||||
return Allocator{
|
return Allocator{
|
||||||
procedure = arena_allocator_proc,
|
procedure = arena_allocator_proc,
|
||||||
data = arena,
|
data = arena,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||||
arena := allocator_data as ^Arena
|
arena := allocator_data as ^Arena;
|
||||||
|
|
||||||
using Allocator.Mode
|
using Allocator.Mode;
|
||||||
match mode {
|
match mode {
|
||||||
case ALLOC:
|
case ALLOC:
|
||||||
total_size := size + alignment
|
total_size := size + alignment;
|
||||||
|
|
||||||
if arena.memory.count + total_size > arena.memory.capacity {
|
if arena.memory.count + total_size > arena.memory.capacity {
|
||||||
fmt.fprintln(os.stderr, "Arena out of memory")
|
fmt.fprintln(os.stderr, "Arena out of memory");
|
||||||
return nil
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
#no_bounds_check end := ^arena.memory[arena.memory.count]
|
#no_bounds_check end := ^arena.memory[arena.memory.count];
|
||||||
|
|
||||||
ptr := align_forward(end, alignment)
|
ptr := align_forward(end, alignment);
|
||||||
arena.memory.count += total_size
|
arena.memory.count += total_size;
|
||||||
return zero(ptr, size)
|
return zero(ptr, size);
|
||||||
|
|
||||||
case FREE:
|
case FREE:
|
||||||
// NOTE(bill): Free all at once
|
// NOTE(bill): Free all at once
|
||||||
// Use Arena.Temp_Memory if you want to free a block
|
// Use Arena.Temp_Memory if you want to free a block
|
||||||
|
|
||||||
case FREE_ALL:
|
case FREE_ALL:
|
||||||
arena.memory.count = 0
|
arena.memory.count = 0;
|
||||||
|
|
||||||
case RESIZE:
|
case RESIZE:
|
||||||
return default_resize_align(old_memory, old_size, size, alignment)
|
return default_resize_align(old_memory, old_size, size, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena.Temp_Memory {
|
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena.Temp_Memory {
|
||||||
tmp: Arena.Temp_Memory
|
tmp: Arena.Temp_Memory;
|
||||||
tmp.arena = a
|
tmp.arena = a;
|
||||||
tmp.original_count = a.memory.count
|
tmp.original_count = a.memory.count;
|
||||||
a.temp_count++
|
a.temp_count++;
|
||||||
return tmp
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
end_arena_temp_memory :: proc(using tmp: Arena.Temp_Memory) {
|
end_arena_temp_memory :: proc(using tmp: Arena.Temp_Memory) {
|
||||||
assert(arena.memory.count >= original_count)
|
assert(arena.memory.count >= original_count);
|
||||||
assert(arena.temp_count > 0)
|
assert(arena.temp_count > 0);
|
||||||
arena.memory.count = original_count
|
arena.memory.count = original_count;
|
||||||
arena.temp_count--
|
arena.temp_count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -214,119 +214,119 @@ end_arena_temp_memory :: proc(using tmp: Arena.Temp_Memory) {
|
|||||||
|
|
||||||
|
|
||||||
align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||||
WORD_SIZE :: size_of(int)
|
WORD_SIZE :: size_of(int);
|
||||||
using Type_Info
|
using Type_Info;
|
||||||
|
|
||||||
match type info : type_info {
|
match type info : type_info {
|
||||||
case Named:
|
case Named:
|
||||||
return align_of_type_info(info.base)
|
return align_of_type_info(info.base);
|
||||||
case Integer:
|
case Integer:
|
||||||
return info.size
|
return info.size;
|
||||||
case Float:
|
case Float:
|
||||||
return info.size
|
return info.size;
|
||||||
case String:
|
case String:
|
||||||
return WORD_SIZE
|
return WORD_SIZE;
|
||||||
case Boolean:
|
case Boolean:
|
||||||
return 1
|
return 1;
|
||||||
case Pointer:
|
case Pointer:
|
||||||
return WORD_SIZE
|
return WORD_SIZE;
|
||||||
case Maybe:
|
case Maybe:
|
||||||
return max(align_of_type_info(info.elem), 1)
|
return max(align_of_type_info(info.elem), 1);
|
||||||
case Procedure:
|
case Procedure:
|
||||||
return WORD_SIZE
|
return WORD_SIZE;
|
||||||
case Array:
|
case Array:
|
||||||
return align_of_type_info(info.elem)
|
return align_of_type_info(info.elem);
|
||||||
case Slice:
|
case Slice:
|
||||||
return WORD_SIZE
|
return WORD_SIZE;
|
||||||
case Vector:
|
case Vector:
|
||||||
return align_of_type_info(info.elem)
|
return align_of_type_info(info.elem);
|
||||||
case Struct:
|
case Struct:
|
||||||
return info.align
|
return info.align;
|
||||||
case Union:
|
case Union:
|
||||||
return info.align
|
return info.align;
|
||||||
case Raw_Union:
|
case Raw_Union:
|
||||||
return info.align
|
return info.align;
|
||||||
case Enum:
|
case Enum:
|
||||||
return align_of_type_info(info.base)
|
return align_of_type_info(info.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
align_formula :: proc(size, align: int) -> int {
|
align_formula :: proc(size, align: int) -> int {
|
||||||
result := size + align-1
|
result := size + align-1;
|
||||||
return result - result%align
|
return result - result%align;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
size_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||||
WORD_SIZE :: size_of(int)
|
WORD_SIZE :: size_of(int);
|
||||||
using Type_Info
|
using Type_Info;
|
||||||
|
|
||||||
match type info : type_info {
|
match type info : type_info {
|
||||||
case Named:
|
case Named:
|
||||||
return size_of_type_info(info.base)
|
return size_of_type_info(info.base);
|
||||||
case Integer:
|
case Integer:
|
||||||
return info.size
|
return info.size;
|
||||||
case Float:
|
case Float:
|
||||||
return info.size
|
return info.size;
|
||||||
case Any:
|
case Any:
|
||||||
return 2*WORD_SIZE
|
return 2*WORD_SIZE;
|
||||||
case String:
|
case String:
|
||||||
return 2*WORD_SIZE
|
return 2*WORD_SIZE;
|
||||||
case Boolean:
|
case Boolean:
|
||||||
return 1
|
return 1;
|
||||||
case Pointer:
|
case Pointer:
|
||||||
return WORD_SIZE
|
return WORD_SIZE;
|
||||||
case Maybe:
|
case Maybe:
|
||||||
return size_of_type_info(info.elem) + 1
|
return size_of_type_info(info.elem) + 1;
|
||||||
case Procedure:
|
case Procedure:
|
||||||
return WORD_SIZE
|
return WORD_SIZE;
|
||||||
case Array:
|
case Array:
|
||||||
count := info.count
|
count := info.count;
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
size := size_of_type_info(info.elem)
|
size := size_of_type_info(info.elem);
|
||||||
align := align_of_type_info(info.elem)
|
align := align_of_type_info(info.elem);
|
||||||
alignment := align_formula(size, align)
|
alignment := align_formula(size, align);
|
||||||
return alignment*(count-1) + size
|
return alignment*(count-1) + size;
|
||||||
case Slice:
|
case Slice:
|
||||||
return 3*WORD_SIZE
|
return 3*WORD_SIZE;
|
||||||
case Vector:
|
case Vector:
|
||||||
is_bool :: proc(type_info: ^Type_Info) -> bool {
|
is_bool :: proc(type_info: ^Type_Info) -> bool {
|
||||||
match type info : type_info {
|
match type info : type_info {
|
||||||
case Named:
|
case Named:
|
||||||
return is_bool(info.base)
|
return is_bool(info.base);
|
||||||
case Boolean:
|
case Boolean:
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
count := info.count
|
count := info.count;
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
bit_size := 8*size_of_type_info(info.elem)
|
bit_size := 8*size_of_type_info(info.elem);
|
||||||
if is_bool(info.elem) {
|
if is_bool(info.elem) {
|
||||||
// NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
|
// NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
|
||||||
// Silly LLVM spec
|
// Silly LLVM spec
|
||||||
bit_size = 1
|
bit_size = 1;
|
||||||
}
|
}
|
||||||
total_size_in_bits := bit_size * count
|
total_size_in_bits := bit_size * count;
|
||||||
total_size := (total_size_in_bits+7)/8
|
total_size := (total_size_in_bits+7)/8;
|
||||||
return total_size
|
return total_size;
|
||||||
|
|
||||||
case Struct:
|
case Struct:
|
||||||
return info.size
|
return info.size;
|
||||||
case Union:
|
case Union:
|
||||||
return info.size
|
return info.size;
|
||||||
case Raw_Union:
|
case Raw_Union:
|
||||||
return info.size
|
return info.size;
|
||||||
case Enum:
|
case Enum:
|
||||||
return size_of_type_info(info.base)
|
return size_of_type_info(info.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+93
-95
@@ -1,8 +1,6 @@
|
|||||||
when ODIN_OS == "windows" {
|
#foreign_system_library "opengl32" when ODIN_OS == "windows";
|
||||||
#foreign_system_library "opengl32"
|
#import "win32.odin" when ODIN_OS == "windows";
|
||||||
}
|
#include "opengl_constants.odin";
|
||||||
#import "win32.odin"
|
|
||||||
#load "opengl_constants.odin"
|
|
||||||
|
|
||||||
Clear :: proc(mask: u32) #foreign "glClear"
|
Clear :: proc(mask: u32) #foreign "glClear"
|
||||||
ClearColor :: proc(r, g, b, a: f32) #foreign "glClearColor"
|
ClearColor :: proc(r, g, b, a: f32) #foreign "glClearColor"
|
||||||
@@ -32,126 +30,126 @@ GetIntegerv :: proc(name: i32, v: ^i32) #foreign "glGetIntegerv"
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
_libgl := win32.LoadLibraryA(("opengl32.dll\x00" as string).data)
|
_libgl := win32.LoadLibraryA(("opengl32.dll\x00" as string).data);
|
||||||
|
|
||||||
GetProcAddress :: proc(name: string) -> proc() {
|
GetProcAddress :: proc(name: string) -> proc() {
|
||||||
assert(name[name.count-1] == 0)
|
assert(name[name.count-1] == 0);
|
||||||
res := win32.wglGetProcAddress(name.data)
|
res := win32.wglGetProcAddress(name.data);
|
||||||
if res == nil {
|
if res == nil {
|
||||||
res = win32.GetProcAddress(_libgl, name.data);
|
res = win32.GetProcAddress(_libgl, name.data);
|
||||||
}
|
}
|
||||||
return res
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GenBuffers: proc(count: i32, buffers: ^u32)
|
GenBuffers: proc(count: i32, buffers: ^u32);
|
||||||
GenVertexArrays: proc(count: i32, buffers: ^u32)
|
GenVertexArrays: proc(count: i32, buffers: ^u32);
|
||||||
GenSamplers: proc(count: i32, buffers: ^u32)
|
GenSamplers: proc(count: i32, buffers: ^u32);
|
||||||
BindBuffer: proc(target: i32, buffer: u32)
|
BindBuffer: proc(target: i32, buffer: u32);
|
||||||
BindVertexArray: proc(buffer: u32)
|
BindVertexArray: proc(buffer: u32);
|
||||||
BindSampler: proc(position: i32, sampler: u32)
|
BindSampler: proc(position: i32, sampler: u32);
|
||||||
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32)
|
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32);
|
||||||
BufferSubData: proc(target: i32, offset, size: int, data: rawptr)
|
BufferSubData: proc(target: i32, offset, size: int, data: rawptr);
|
||||||
|
|
||||||
DrawArrays: proc(mode, first: i32, count: u32)
|
DrawArrays: proc(mode, first: i32, count: u32);
|
||||||
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr)
|
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr);
|
||||||
|
|
||||||
MapBuffer: proc(target, access: i32) -> rawptr
|
MapBuffer: proc(target, access: i32) -> rawptr;
|
||||||
UnmapBuffer: proc(target: i32)
|
UnmapBuffer: proc(target: i32);
|
||||||
|
|
||||||
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr)
|
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr);
|
||||||
EnableVertexAttribArray: proc(index: u32)
|
EnableVertexAttribArray: proc(index: u32);
|
||||||
|
|
||||||
CreateShader: proc(shader_type: i32) -> u32
|
CreateShader: proc(shader_type: i32) -> u32;
|
||||||
ShaderSource: proc(shader: u32, count: u32, string: ^^byte, length: ^i32)
|
ShaderSource: proc(shader: u32, count: u32, string: ^^byte, length: ^i32);
|
||||||
CompileShader: proc(shader: u32)
|
CompileShader: proc(shader: u32);
|
||||||
CreateProgram: proc() -> u32
|
CreateProgram: proc() -> u32;
|
||||||
AttachShader: proc(program, shader: u32)
|
AttachShader: proc(program, shader: u32);
|
||||||
DetachShader: proc(program, shader: u32)
|
DetachShader: proc(program, shader: u32);
|
||||||
DeleteShader: proc(shader: u32)
|
DeleteShader: proc(shader: u32);
|
||||||
LinkProgram: proc(program: u32)
|
LinkProgram: proc(program: u32);
|
||||||
UseProgram: proc(program: u32)
|
UseProgram: proc(program: u32);
|
||||||
DeleteProgram: proc(program: u32)
|
DeleteProgram: proc(program: u32);
|
||||||
|
|
||||||
|
|
||||||
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32)
|
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32);
|
||||||
GetProgramiv: proc(program: u32, pname: i32, params: ^i32)
|
GetProgramiv: proc(program: u32, pname: i32, params: ^i32);
|
||||||
GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^byte)
|
GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^byte);
|
||||||
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte)
|
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte);
|
||||||
|
|
||||||
ActiveTexture: proc(texture: i32)
|
ActiveTexture: proc(texture: i32);
|
||||||
GenerateMipmap: proc(target: i32)
|
GenerateMipmap: proc(target: i32);
|
||||||
|
|
||||||
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32)
|
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32);
|
||||||
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32)
|
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32);
|
||||||
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32)
|
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32);
|
||||||
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32)
|
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32);
|
||||||
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32)
|
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32);
|
||||||
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32)
|
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32);
|
||||||
|
|
||||||
|
|
||||||
Uniform1i: proc(loc: i32, v0: i32)
|
Uniform1i: proc(loc: i32, v0: i32);
|
||||||
Uniform2i: proc(loc: i32, v0, v1: i32)
|
Uniform2i: proc(loc: i32, v0, v1: i32);
|
||||||
Uniform3i: proc(loc: i32, v0, v1, v2: i32)
|
Uniform3i: proc(loc: i32, v0, v1, v2: i32);
|
||||||
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32)
|
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32);
|
||||||
Uniform1f: proc(loc: i32, v0: f32)
|
Uniform1f: proc(loc: i32, v0: f32);
|
||||||
Uniform2f: proc(loc: i32, v0, v1: f32)
|
Uniform2f: proc(loc: i32, v0, v1: f32);
|
||||||
Uniform3f: proc(loc: i32, v0, v1, v2: f32)
|
Uniform3f: proc(loc: i32, v0, v1, v2: f32);
|
||||||
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32)
|
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32);
|
||||||
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32)
|
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32);
|
||||||
|
|
||||||
GetUniformLocation: proc(program: u32, name: ^byte) -> i32
|
GetUniformLocation: proc(program: u32, name: ^byte) -> i32;
|
||||||
|
|
||||||
init :: proc() {
|
init :: proc() {
|
||||||
set_proc_address :: proc(p: rawptr, name: string) #inline { (p as ^proc())^ = GetProcAddress(name) }
|
set_proc_address :: proc(p: rawptr, name: string) #inline { (p as ^proc())^ = GetProcAddress(name); }
|
||||||
|
|
||||||
set_proc_address(^GenBuffers, "glGenBuffers\x00")
|
set_proc_address(^GenBuffers, "glGenBuffers\x00");
|
||||||
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00")
|
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
|
||||||
set_proc_address(^GenSamplers, "glGenSamplers\x00")
|
set_proc_address(^GenSamplers, "glGenSamplers\x00");
|
||||||
set_proc_address(^BindBuffer, "glBindBuffer\x00")
|
set_proc_address(^BindBuffer, "glBindBuffer\x00");
|
||||||
set_proc_address(^BindSampler, "glBindSampler\x00")
|
set_proc_address(^BindSampler, "glBindSampler\x00");
|
||||||
set_proc_address(^BindVertexArray, "glBindVertexArray\x00")
|
set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
|
||||||
set_proc_address(^BufferData, "glBufferData\x00")
|
set_proc_address(^BufferData, "glBufferData\x00");
|
||||||
set_proc_address(^BufferSubData, "glBufferSubData\x00")
|
set_proc_address(^BufferSubData, "glBufferSubData\x00");
|
||||||
|
|
||||||
set_proc_address(^DrawArrays, "glDrawArrays\x00")
|
set_proc_address(^DrawArrays, "glDrawArrays\x00");
|
||||||
set_proc_address(^DrawElements, "glDrawElements\x00")
|
set_proc_address(^DrawElements, "glDrawElements\x00");
|
||||||
|
|
||||||
set_proc_address(^MapBuffer, "glMapBuffer\x00")
|
set_proc_address(^MapBuffer, "glMapBuffer\x00");
|
||||||
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00")
|
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00");
|
||||||
|
|
||||||
set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00")
|
set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00");
|
||||||
set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00")
|
set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00");
|
||||||
|
|
||||||
set_proc_address(^CreateShader, "glCreateShader\x00")
|
set_proc_address(^CreateShader, "glCreateShader\x00");
|
||||||
set_proc_address(^ShaderSource, "glShaderSource\x00")
|
set_proc_address(^ShaderSource, "glShaderSource\x00");
|
||||||
set_proc_address(^CompileShader, "glCompileShader\x00")
|
set_proc_address(^CompileShader, "glCompileShader\x00");
|
||||||
set_proc_address(^CreateProgram, "glCreateProgram\x00")
|
set_proc_address(^CreateProgram, "glCreateProgram\x00");
|
||||||
set_proc_address(^AttachShader, "glAttachShader\x00")
|
set_proc_address(^AttachShader, "glAttachShader\x00");
|
||||||
set_proc_address(^DetachShader, "glDetachShader\x00")
|
set_proc_address(^DetachShader, "glDetachShader\x00");
|
||||||
set_proc_address(^DeleteShader, "glDeleteShader\x00")
|
set_proc_address(^DeleteShader, "glDeleteShader\x00");
|
||||||
set_proc_address(^LinkProgram, "glLinkProgram\x00")
|
set_proc_address(^LinkProgram, "glLinkProgram\x00");
|
||||||
set_proc_address(^UseProgram, "glUseProgram\x00")
|
set_proc_address(^UseProgram, "glUseProgram\x00");
|
||||||
set_proc_address(^DeleteProgram, "glDeleteProgram\x00")
|
set_proc_address(^DeleteProgram, "glDeleteProgram\x00");
|
||||||
|
|
||||||
set_proc_address(^GetShaderiv, "glGetShaderiv\x00")
|
set_proc_address(^GetShaderiv, "glGetShaderiv\x00");
|
||||||
set_proc_address(^GetProgramiv, "glGetProgramiv\x00")
|
set_proc_address(^GetProgramiv, "glGetProgramiv\x00");
|
||||||
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00")
|
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00");
|
||||||
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00")
|
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00");
|
||||||
|
|
||||||
set_proc_address(^ActiveTexture, "glActiveTexture\x00")
|
set_proc_address(^ActiveTexture, "glActiveTexture\x00");
|
||||||
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00")
|
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00");
|
||||||
|
|
||||||
set_proc_address(^Uniform1i, "glUniform1i\x00")
|
set_proc_address(^Uniform1i, "glUniform1i\x00");
|
||||||
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00")
|
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00");
|
||||||
|
|
||||||
set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00")
|
set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00");
|
||||||
|
|
||||||
set_proc_address(^SamplerParameteri, "glSamplerParameteri\x00")
|
set_proc_address(^SamplerParameteri, "glSamplerParameteri\x00");
|
||||||
set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00")
|
set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00");
|
||||||
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00")
|
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00");
|
||||||
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00")
|
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00");
|
||||||
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00")
|
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00");
|
||||||
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00")
|
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1365
-1365
File diff suppressed because it is too large
Load Diff
+2
-3
@@ -1,3 +1,2 @@
|
|||||||
when ODIN_OS == "windows" {
|
#include "os_windows.odin" when ODIN_OS == "windows";
|
||||||
#load "os_windows.odin"
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
#import "win32.odin";
|
||||||
|
#import "fmt.odin";
|
||||||
|
|
||||||
|
File_Time :: type u64
|
||||||
|
|
||||||
|
File :: struct {
|
||||||
|
Handle :: raw_union {
|
||||||
|
p: rawptr;
|
||||||
|
i: int;
|
||||||
|
}
|
||||||
|
handle: Handle;
|
||||||
|
last_write_time: File_Time;
|
||||||
|
}
|
||||||
|
|
||||||
|
open :: proc(name: string) -> (File, bool) {
|
||||||
|
using win32;
|
||||||
|
buf: [300]byte;
|
||||||
|
copy(buf[:], name as []byte);
|
||||||
|
f: File;
|
||||||
|
f.handle.p = CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, nil) as rawptr;
|
||||||
|
success := f.handle.p != INVALID_HANDLE_VALUE;
|
||||||
|
f.last_write_time = last_write_time(^f);
|
||||||
|
return f, success;
|
||||||
|
}
|
||||||
|
|
||||||
|
create :: proc(name: string) -> (File, bool) {
|
||||||
|
using win32;
|
||||||
|
buf: [300]byte;
|
||||||
|
copy(buf[:], name as []byte);
|
||||||
|
f: File;
|
||||||
|
f.handle.p = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_ALWAYS, 0, nil) as rawptr;
|
||||||
|
success := f.handle.p != INVALID_HANDLE_VALUE;
|
||||||
|
f.last_write_time = last_write_time(^f);
|
||||||
|
return f, success;
|
||||||
|
}
|
||||||
|
|
||||||
|
close :: proc(using f: ^File) {
|
||||||
|
win32.CloseHandle(handle.p as win32.HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
write :: proc(using f: ^File, buf: []byte) -> bool {
|
||||||
|
bytes_written: i32;
|
||||||
|
return win32.WriteFile(handle.p as win32.HANDLE, buf.data, buf.count as i32, ^bytes_written, nil) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_has_changed :: proc(f: ^File) -> bool {
|
||||||
|
last_write_time := last_write_time(f);
|
||||||
|
if f.last_write_time != last_write_time {
|
||||||
|
f.last_write_time = last_write_time;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
last_write_time :: proc(f: ^File) -> File_Time {
|
||||||
|
file_info: win32.BY_HANDLE_FILE_INFORMATION;
|
||||||
|
win32.GetFileInformationByHandle(f.handle.p as win32.HANDLE, ^file_info);
|
||||||
|
l := file_info.last_write_time.low_date_time as File_Time;
|
||||||
|
h := file_info.last_write_time.high_date_time as File_Time;
|
||||||
|
return l | h << 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_write_time_by_name :: proc(name: string) -> File_Time {
|
||||||
|
last_write_time: win32.FILETIME;
|
||||||
|
data: win32.WIN32_FILE_ATTRIBUTE_DATA;
|
||||||
|
|
||||||
|
buf: [1024]byte;
|
||||||
|
path := buf[:0];
|
||||||
|
fmt.bprint(^path, name, "\x00");
|
||||||
|
|
||||||
|
if win32.GetFileAttributesExA(path.data, win32.GetFileExInfoStandard, ^data) != 0 {
|
||||||
|
last_write_time = data.last_write_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
l := last_write_time.low_date_time as File_Time;
|
||||||
|
h := last_write_time.high_date_time as File_Time;
|
||||||
|
return l | h << 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
File_Standard :: enum {
|
||||||
|
INPUT,
|
||||||
|
OUTPUT,
|
||||||
|
ERROR,
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): Uses startup to initialize it
|
||||||
|
__std_files := [File_Standard.count]File{
|
||||||
|
{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE) transmute File.Handle },
|
||||||
|
{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE) transmute File.Handle },
|
||||||
|
{handle = win32.GetStdHandle(win32.STD_ERROR_HANDLE) transmute File.Handle },
|
||||||
|
};
|
||||||
|
|
||||||
|
stdin := ^__std_files[File_Standard.INPUT];
|
||||||
|
stdout := ^__std_files[File_Standard.OUTPUT];
|
||||||
|
stderr := ^__std_files[File_Standard.ERROR];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||||
|
buf: [300]byte;
|
||||||
|
copy(buf[:], name as []byte);
|
||||||
|
|
||||||
|
f, file_ok := open(name);
|
||||||
|
if !file_ok {
|
||||||
|
return nil, false;
|
||||||
|
}
|
||||||
|
defer close(^f);
|
||||||
|
|
||||||
|
length: i64;
|
||||||
|
file_size_ok := win32.GetFileSizeEx(f.handle.p as win32.HANDLE, ^length) != 0;
|
||||||
|
if !file_size_ok {
|
||||||
|
return nil, false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data := new_slice(u8, length);
|
||||||
|
if data.data == nil {
|
||||||
|
return nil, false;
|
||||||
|
}
|
||||||
|
|
||||||
|
single_read_length: i32;
|
||||||
|
total_read: i64;
|
||||||
|
|
||||||
|
for total_read < length {
|
||||||
|
remaining := length - total_read;
|
||||||
|
to_read: u32;
|
||||||
|
MAX :: 1<<32-1;
|
||||||
|
if remaining <= MAX {
|
||||||
|
to_read = remaining as u32;
|
||||||
|
} else {
|
||||||
|
to_read = MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
win32.ReadFile(f.handle.p as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, nil);
|
||||||
|
if single_read_length <= 0 {
|
||||||
|
free(data.data);
|
||||||
|
return nil, false;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_read += single_read_length as i64;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
heap_alloc :: proc(size: int) -> rawptr {
|
||||||
|
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size);
|
||||||
|
}
|
||||||
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
|
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
|
||||||
|
}
|
||||||
|
heap_free :: proc(ptr: rawptr) {
|
||||||
|
win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
exit :: proc(code: int) {
|
||||||
|
win32.ExitProcess(code as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
current_thread_id :: proc() -> int {
|
||||||
|
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
|
||||||
|
return GetCurrentThreadId() as int;
|
||||||
|
}
|
||||||
|
|
||||||
+94
-94
@@ -1,17 +1,17 @@
|
|||||||
RUNE_ERROR :: '\ufffd'
|
RUNE_ERROR :: '\ufffd';
|
||||||
RUNE_SELF :: 0x80
|
RUNE_SELF :: 0x80;
|
||||||
RUNE_BOM :: 0xfeff
|
RUNE_BOM :: 0xfeff;
|
||||||
RUNE_EOF :: ~(0 as rune)
|
RUNE_EOF :: ~(0 as rune);
|
||||||
MAX_RUNE :: '\U0010ffff'
|
MAX_RUNE :: '\U0010ffff';
|
||||||
UTF_MAX :: 4
|
UTF_MAX :: 4;
|
||||||
|
|
||||||
|
|
||||||
SURROGATE_MIN :: 0xd800
|
SURROGATE_MIN :: 0xd800;
|
||||||
SURROGATE_MAX :: 0xdfff
|
SURROGATE_MAX :: 0xdfff;
|
||||||
|
|
||||||
|
|
||||||
Accept_Range :: struct {
|
Accept_Range :: struct {
|
||||||
lo, hi: u8
|
lo, hi: u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
accept_ranges := [5]Accept_Range{
|
accept_ranges := [5]Accept_Range{
|
||||||
@@ -20,7 +20,7 @@ accept_ranges := [5]Accept_Range{
|
|||||||
{0x80, 0x9f},
|
{0x80, 0x9f},
|
||||||
{0x90, 0xbf},
|
{0x90, 0xbf},
|
||||||
{0x80, 0x8f},
|
{0x80, 0x8f},
|
||||||
}
|
};
|
||||||
|
|
||||||
accept_sizes := [256]byte{
|
accept_sizes := [256]byte{
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
||||||
@@ -40,177 +40,177 @@ accept_sizes := [256]byte{
|
|||||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
|
||||||
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
|
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
|
||||||
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
|
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
|
||||||
}
|
};
|
||||||
|
|
||||||
encode_rune :: proc(r_: rune) -> ([4]byte, int) {
|
encode_rune :: proc(r_: rune) -> ([4]byte, int) {
|
||||||
r := r_
|
r := r_;
|
||||||
buf: [4]byte
|
buf: [4]byte;
|
||||||
i := r as u32
|
i := r as u32;
|
||||||
mask: byte : 0x3f
|
mask: byte : 0x3f;
|
||||||
if i <= 1<<7-1 {
|
if i <= 1<<7-1 {
|
||||||
buf[0] = r as byte
|
buf[0] = r as byte;
|
||||||
return buf, 1
|
return buf, 1;
|
||||||
}
|
}
|
||||||
if i <= 1<<11-1 {
|
if i <= 1<<11-1 {
|
||||||
buf[0] = 0xc0 | (r>>6) as byte
|
buf[0] = 0xc0 | (r>>6) as byte;
|
||||||
buf[1] = 0x80 | (r) as byte & mask
|
buf[1] = 0x80 | (r) as byte & mask;
|
||||||
return buf, 2
|
return buf, 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid or Surrogate range
|
// Invalid or Surrogate range
|
||||||
if i > 0x0010ffff ||
|
if i > 0x0010ffff ||
|
||||||
(0xd800 <= i && i <= 0xdfff) {
|
(0xd800 <= i && i <= 0xdfff) {
|
||||||
r = 0xfffd
|
r = 0xfffd;
|
||||||
}
|
}
|
||||||
|
|
||||||
if i <= 1<<16-1 {
|
if i <= 1<<16-1 {
|
||||||
buf[0] = 0xe0 | (r>>12) as byte
|
buf[0] = 0xe0 | (r>>12) as byte;
|
||||||
buf[1] = 0x80 | (r>>6) as byte & mask
|
buf[1] = 0x80 | (r>>6) as byte & mask;
|
||||||
buf[2] = 0x80 | (r) as byte & mask
|
buf[2] = 0x80 | (r) as byte & mask;
|
||||||
return buf, 3
|
return buf, 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[0] = 0xf0 | (r>>18) as byte
|
buf[0] = 0xf0 | (r>>18) as byte;
|
||||||
buf[1] = 0x80 | (r>>12) as byte & mask
|
buf[1] = 0x80 | (r>>12) as byte & mask;
|
||||||
buf[2] = 0x80 | (r>>6) as byte & mask
|
buf[2] = 0x80 | (r>>6) as byte & mask;
|
||||||
buf[3] = 0x80 | (r) as byte & mask
|
buf[3] = 0x80 | (r) as byte & mask;
|
||||||
return buf, 4
|
return buf, 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
decode_rune :: proc(s: string) -> (rune, int) {
|
decode_rune :: proc(s: string) -> (rune, int) {
|
||||||
n := s.count
|
n := s.count;
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
return RUNE_ERROR, 0
|
return RUNE_ERROR, 0;
|
||||||
}
|
}
|
||||||
b0 := s[0]
|
b0 := s[0];
|
||||||
x := accept_sizes[b0]
|
x := accept_sizes[b0];
|
||||||
if x >= 0xf0 {
|
if x >= 0xf0 {
|
||||||
mask := (x as rune << 31) >> 31 // all zeros or all ones
|
mask := (x as rune << 31) >> 31; // all zeros or all ones
|
||||||
return (b0 as rune) &~ mask | RUNE_ERROR&mask, 1
|
return (b0 as rune) &~ mask | RUNE_ERROR&mask, 1;
|
||||||
}
|
}
|
||||||
size := x & 7
|
size := x & 7;
|
||||||
ar := accept_ranges[x>>4]
|
ar := accept_ranges[x>>4];
|
||||||
if n < size as int {
|
if n < size as int {
|
||||||
return RUNE_ERROR, 1
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
b1 := s[1]
|
b1 := s[1];
|
||||||
if b1 < ar.lo || ar.hi < b1 {
|
if b1 < ar.lo || ar.hi < b1 {
|
||||||
return RUNE_ERROR, 1
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
MASK_X :: 0b00111111
|
MASK_X :: 0b00111111;
|
||||||
MASK_2 :: 0b00011111
|
MASK_2 :: 0b00011111;
|
||||||
MASK_3 :: 0b00001111
|
MASK_3 :: 0b00001111;
|
||||||
MASK_4 :: 0b00000111
|
MASK_4 :: 0b00000111;
|
||||||
|
|
||||||
if size == 2 {
|
if size == 2 {
|
||||||
return (b0&MASK_2) as rune <<6 | (b1&MASK_X) as rune, 2
|
return (b0&MASK_2) as rune <<6 | (b1&MASK_X) as rune, 2;
|
||||||
}
|
}
|
||||||
b2 := s[2]
|
b2 := s[2];
|
||||||
if b2 < 0x80 || 0xbf < b2 {
|
if b2 < 0x80 || 0xbf < b2 {
|
||||||
return RUNE_ERROR, 1
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
if size == 3 {
|
if size == 3 {
|
||||||
return (b0&MASK_3) as rune <<12 | (b1&MASK_X) as rune <<6 | (b2&MASK_X) as rune, 3
|
return (b0&MASK_3) as rune <<12 | (b1&MASK_X) as rune <<6 | (b2&MASK_X) as rune, 3;
|
||||||
}
|
}
|
||||||
b3 := s[3]
|
b3 := s[3];
|
||||||
if b3 < 0x80 || 0xbf < b3 {
|
if b3 < 0x80 || 0xbf < b3 {
|
||||||
return RUNE_ERROR, 1
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
return (b0&MASK_4) as rune <<18 | (b1&MASK_X) as rune <<12 | (b3&MASK_X) as rune <<6 | (b3&MASK_X) as rune, 4
|
return (b0&MASK_4) as rune <<18 | (b1&MASK_X) as rune <<12 | (b3&MASK_X) as rune <<6 | (b3&MASK_X) as rune, 4;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
valid_rune :: proc(r: rune) -> bool {
|
valid_rune :: proc(r: rune) -> bool {
|
||||||
if r < 0 {
|
if r < 0 {
|
||||||
return false
|
return false;
|
||||||
} else if SURROGATE_MIN <= r && r <= SURROGATE_MAX {
|
} else if SURROGATE_MIN <= r && r <= SURROGATE_MAX {
|
||||||
return false
|
return false;
|
||||||
} else if r > MAX_RUNE {
|
} else if r > MAX_RUNE {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
valid_string :: proc(s: string) -> bool {
|
valid_string :: proc(s: string) -> bool {
|
||||||
n := s.count
|
n := s.count;
|
||||||
for i := 0; i < n; {
|
for i := 0; i < n; {
|
||||||
si := s[i]
|
si := s[i];
|
||||||
if si < RUNE_SELF { // ascii
|
if si < RUNE_SELF { // ascii
|
||||||
i++
|
i++;
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
x := accept_sizes[si]
|
x := accept_sizes[si];
|
||||||
if x == 0xf1 {
|
if x == 0xf1 {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
size := (x & 7) as int
|
size := (x & 7) as int;
|
||||||
if i+size > n {
|
if i+size > n {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
ar := accept_ranges[x>>4]
|
ar := accept_ranges[x>>4];
|
||||||
if b := s[i+1]; b < ar.lo || ar.hi < b {
|
if b := s[i+1]; b < ar.lo || ar.hi < b {
|
||||||
return false
|
return false;
|
||||||
} else if size == 2 {
|
} else if size == 2 {
|
||||||
// Okay
|
// Okay
|
||||||
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
|
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
|
||||||
return false
|
return false;
|
||||||
} else if size == 3 {
|
} else if size == 3 {
|
||||||
// Okay
|
// Okay
|
||||||
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
|
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
i += size
|
i += size;
|
||||||
}
|
}
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rune_count :: proc(s: string) -> int {
|
rune_count :: proc(s: string) -> int {
|
||||||
count := 0
|
count := 0;
|
||||||
n := s.count
|
n := s.count;
|
||||||
for i := 0; i < n; count++ {
|
for i := 0; i < n; count++ {
|
||||||
si := s[i]
|
si := s[i];
|
||||||
if si < RUNE_SELF { // ascii
|
if si < RUNE_SELF { // ascii
|
||||||
i++
|
i++;
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
x := accept_sizes[si]
|
x := accept_sizes[si];
|
||||||
if x == 0xf1 {
|
if x == 0xf1 {
|
||||||
i++
|
i++;
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
size := (x & 7) as int
|
size := (x & 7) as int;
|
||||||
if i+size > n {
|
if i+size > n {
|
||||||
i++
|
i++;
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
ar := accept_ranges[x>>4]
|
ar := accept_ranges[x>>4];
|
||||||
if b := s[i+1]; b < ar.lo || ar.hi < b {
|
if b := s[i+1]; b < ar.lo || ar.hi < b {
|
||||||
size = 1
|
size = 1;
|
||||||
} else if size == 2 {
|
} else if size == 2 {
|
||||||
// Okay
|
// Okay
|
||||||
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
|
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
|
||||||
size = 1
|
size = 1;
|
||||||
} else if size == 3 {
|
} else if size == 3 {
|
||||||
// Okay
|
// Okay
|
||||||
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
|
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
|
||||||
size = 1
|
size = 1;
|
||||||
}
|
}
|
||||||
i += size
|
i += size;
|
||||||
}
|
}
|
||||||
return count
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rune_size :: proc(r: rune) -> int {
|
rune_size :: proc(r: rune) -> int {
|
||||||
match {
|
match {
|
||||||
case r < 0: return -1
|
case r < 0: return -1;
|
||||||
case r <= 1<<7 - 1: return 1
|
case r <= 1<<7 - 1: return 1;
|
||||||
case r <= 1<<11 - 1: return 2
|
case r <= 1<<11 - 1: return 2;
|
||||||
case SURROGATE_MIN <= r && r <= SURROGATE_MAX: return -1
|
case SURROGATE_MIN <= r && r <= SURROGATE_MAX: return -1;
|
||||||
case r <= 1<<16 - 1: return 3
|
case r <= 1<<16 - 1: return 3;
|
||||||
case r <= MAX_RUNE: return 4
|
case r <= MAX_RUNE: return 4;
|
||||||
}
|
}
|
||||||
return -1
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
+123
-125
@@ -1,7 +1,5 @@
|
|||||||
when ODIN_OS == "windows" {
|
#foreign_system_library "user32" when ODIN_OS == "windows";
|
||||||
#foreign_system_library "user32"
|
#foreign_system_library "gdi32" when ODIN_OS == "windows";
|
||||||
#foreign_system_library "gdi32"
|
|
||||||
}
|
|
||||||
|
|
||||||
HANDLE :: type rawptr
|
HANDLE :: type rawptr
|
||||||
HWND :: type HANDLE
|
HWND :: type HANDLE
|
||||||
@@ -20,100 +18,100 @@ ATOM :: type i16
|
|||||||
BOOL :: type i32
|
BOOL :: type i32
|
||||||
WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
|
WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
|
||||||
|
|
||||||
INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE
|
INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE;
|
||||||
|
|
||||||
CS_VREDRAW :: 0x0001
|
CS_VREDRAW :: 0x0001;
|
||||||
CS_HREDRAW :: 0x0002
|
CS_HREDRAW :: 0x0002;
|
||||||
CS_OWNDC :: 0x0020
|
CS_OWNDC :: 0x0020;
|
||||||
CW_USEDEFAULT :: -0x80000000
|
CW_USEDEFAULT :: -0x80000000;
|
||||||
|
|
||||||
WS_OVERLAPPED :: 0
|
WS_OVERLAPPED :: 0;
|
||||||
WS_MAXIMIZEBOX :: 0x00010000
|
WS_MAXIMIZEBOX :: 0x00010000;
|
||||||
WS_MINIMIZEBOX :: 0x00020000
|
WS_MINIMIZEBOX :: 0x00020000;
|
||||||
WS_THICKFRAME :: 0x00040000
|
WS_THICKFRAME :: 0x00040000;
|
||||||
WS_SYSMENU :: 0x00080000
|
WS_SYSMENU :: 0x00080000;
|
||||||
WS_CAPTION :: 0x00C00000
|
WS_CAPTION :: 0x00C00000;
|
||||||
WS_VISIBLE :: 0x10000000
|
WS_VISIBLE :: 0x10000000;
|
||||||
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX
|
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
|
||||||
|
|
||||||
WM_DESTROY :: 0x0002
|
WM_DESTROY :: 0x0002;
|
||||||
WM_CLOSE :: 0x0010
|
WM_CLOSE :: 0x0010;
|
||||||
WM_QUIT :: 0x0012
|
WM_QUIT :: 0x0012;
|
||||||
WM_KEYDOWN :: 0x0100
|
WM_KEYDOWN :: 0x0100;
|
||||||
WM_KEYUP :: 0x0101
|
WM_KEYUP :: 0x0101;
|
||||||
|
|
||||||
PM_REMOVE :: 1
|
PM_REMOVE :: 1;
|
||||||
|
|
||||||
COLOR_BACKGROUND :: 1 as HBRUSH
|
COLOR_BACKGROUND :: 1 as HBRUSH;
|
||||||
BLACK_BRUSH :: 4
|
BLACK_BRUSH :: 4;
|
||||||
|
|
||||||
SM_CXSCREEN :: 0
|
SM_CXSCREEN :: 0;
|
||||||
SM_CYSCREEN :: 1
|
SM_CYSCREEN :: 1;
|
||||||
|
|
||||||
SW_SHOW :: 5
|
SW_SHOW :: 5;
|
||||||
|
|
||||||
POINT :: struct #ordered {
|
POINT :: struct #ordered {
|
||||||
x, y: i32
|
x, y: i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
WNDCLASSEXA :: struct #ordered {
|
WNDCLASSEXA :: struct #ordered {
|
||||||
size, style: u32
|
size, style: u32;
|
||||||
wnd_proc: WNDPROC
|
wnd_proc: WNDPROC;
|
||||||
cls_extra, wnd_extra: i32
|
cls_extra, wnd_extra: i32;
|
||||||
instance: HINSTANCE
|
instance: HINSTANCE;
|
||||||
icon: HICON
|
icon: HICON;
|
||||||
cursor: HCURSOR
|
cursor: HCURSOR;
|
||||||
background: HBRUSH
|
background: HBRUSH;
|
||||||
menu_name, class_name: ^u8
|
menu_name, class_name: ^u8;
|
||||||
sm: HICON
|
sm: HICON;
|
||||||
}
|
}
|
||||||
|
|
||||||
MSG :: struct #ordered {
|
MSG :: struct #ordered {
|
||||||
hwnd: HWND
|
hwnd: HWND;
|
||||||
message: u32
|
message: u32;
|
||||||
wparam: WPARAM
|
wparam: WPARAM;
|
||||||
lparam: LPARAM
|
lparam: LPARAM;
|
||||||
time: u32
|
time: u32;
|
||||||
pt: POINT
|
pt: POINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
RECT :: struct #ordered {
|
RECT :: struct #ordered {
|
||||||
left: i32
|
left: i32;
|
||||||
top: i32
|
top: i32;
|
||||||
right: i32
|
right: i32;
|
||||||
bottom: i32
|
bottom: i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILETIME :: struct #ordered {
|
FILETIME :: struct #ordered {
|
||||||
low_date_time, high_date_time: u32
|
low_date_time, high_date_time: u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
BY_HANDLE_FILE_INFORMATION :: struct #ordered {
|
BY_HANDLE_FILE_INFORMATION :: struct #ordered {
|
||||||
file_attributes: u32
|
file_attributes: u32;
|
||||||
creation_time,
|
creation_time,
|
||||||
last_access_time,
|
last_access_time,
|
||||||
last_write_time: FILETIME
|
last_write_time: FILETIME;
|
||||||
volume_serial_number,
|
volume_serial_number,
|
||||||
file_size_high,
|
file_size_high,
|
||||||
file_size_low,
|
file_size_low,
|
||||||
number_of_links,
|
number_of_links,
|
||||||
file_index_high,
|
file_index_high,
|
||||||
file_index_low: u32
|
file_index_low: u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
WIN32_FILE_ATTRIBUTE_DATA :: struct #ordered {
|
WIN32_FILE_ATTRIBUTE_DATA :: struct #ordered {
|
||||||
file_attributes: u32
|
file_attributes: u32;
|
||||||
creation_time,
|
creation_time,
|
||||||
last_access_time,
|
last_access_time,
|
||||||
last_write_time: FILETIME
|
last_write_time: FILETIME;
|
||||||
file_size_high,
|
file_size_high,
|
||||||
file_size_low: u32
|
file_size_low: u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
GET_FILEEX_INFO_LEVELS :: type i32
|
GET_FILEEX_INFO_LEVELS :: type i32;
|
||||||
GetFileExInfoStandard : GET_FILEEX_INFO_LEVELS : 0
|
GetFileExInfoStandard : GET_FILEEX_INFO_LEVELS : 0;
|
||||||
GetFileExMaxInfoLevel : GET_FILEEX_INFO_LEVELS : 1
|
GetFileExMaxInfoLevel : GET_FILEEX_INFO_LEVELS : 1;
|
||||||
|
|
||||||
GetLastError :: proc() -> i32 #foreign #dll_import
|
GetLastError :: proc() -> i32 #foreign #dll_import
|
||||||
ExitProcess :: proc(exit_code: u32) #foreign #dll_import
|
ExitProcess :: proc(exit_code: u32) #foreign #dll_import
|
||||||
@@ -154,9 +152,9 @@ AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign #
|
|||||||
|
|
||||||
|
|
||||||
GetQueryPerformanceFrequency :: proc() -> i64 {
|
GetQueryPerformanceFrequency :: proc() -> i64 {
|
||||||
r: i64
|
r: i64;
|
||||||
QueryPerformanceFrequency(^r)
|
QueryPerformanceFrequency(^r);
|
||||||
return r
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
GetCommandLineA :: proc() -> ^u8 #foreign #dll_import
|
GetCommandLineA :: proc() -> ^u8 #foreign #dll_import
|
||||||
@@ -177,35 +175,35 @@ GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL
|
|||||||
GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> BOOL #foreign #dll_import
|
GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> BOOL #foreign #dll_import
|
||||||
GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign #dll_import
|
GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign #dll_import
|
||||||
|
|
||||||
FILE_SHARE_READ :: 0x00000001
|
FILE_SHARE_READ :: 0x00000001;
|
||||||
FILE_SHARE_WRITE :: 0x00000002
|
FILE_SHARE_WRITE :: 0x00000002;
|
||||||
FILE_SHARE_DELETE :: 0x00000004
|
FILE_SHARE_DELETE :: 0x00000004;
|
||||||
FILE_GENERIC_ALL :: 0x10000000
|
FILE_GENERIC_ALL :: 0x10000000;
|
||||||
FILE_GENERIC_EXECUTE :: 0x20000000
|
FILE_GENERIC_EXECUTE :: 0x20000000;
|
||||||
FILE_GENERIC_WRITE :: 0x40000000
|
FILE_GENERIC_WRITE :: 0x40000000;
|
||||||
FILE_GENERIC_READ :: 0x80000000
|
FILE_GENERIC_READ :: 0x80000000;
|
||||||
|
|
||||||
STD_INPUT_HANDLE :: -10
|
STD_INPUT_HANDLE :: -10;
|
||||||
STD_OUTPUT_HANDLE :: -11
|
STD_OUTPUT_HANDLE :: -11;
|
||||||
STD_ERROR_HANDLE :: -12
|
STD_ERROR_HANDLE :: -12;
|
||||||
|
|
||||||
CREATE_NEW :: 1
|
CREATE_NEW :: 1;
|
||||||
CREATE_ALWAYS :: 2
|
CREATE_ALWAYS :: 2;
|
||||||
OPEN_EXISTING :: 3
|
OPEN_EXISTING :: 3;
|
||||||
OPEN_ALWAYS :: 4
|
OPEN_ALWAYS :: 4;
|
||||||
TRUNCATE_EXISTING :: 5
|
TRUNCATE_EXISTING :: 5;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
HeapAlloc :: proc(h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign #dll_import
|
HeapAlloc :: proc(h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign #dll_import
|
||||||
HeapReAlloc :: proc(h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign #dll_import
|
HeapReAlloc :: proc(h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign #dll_import
|
||||||
HeapFree :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign #dll_import
|
HeapFree :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign #dll_import
|
||||||
GetProcessHeap :: proc() -> HANDLE #foreign #dll_import
|
GetProcessHeap :: proc() -> HANDLE #foreign #dll_import
|
||||||
|
|
||||||
|
|
||||||
HEAP_ZERO_MEMORY :: 0x00000008
|
HEAP_ZERO_MEMORY :: 0x00000008;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -213,28 +211,28 @@ HEAP_ZERO_MEMORY :: 0x00000008
|
|||||||
|
|
||||||
BITMAPINFO :: struct #ordered {
|
BITMAPINFO :: struct #ordered {
|
||||||
HEADER :: struct #ordered {
|
HEADER :: struct #ordered {
|
||||||
size: u32
|
size: u32;
|
||||||
width, height: i32
|
width, height: i32;
|
||||||
planes, bit_count: i16
|
planes, bit_count: i16;
|
||||||
compression: u32
|
compression: u32;
|
||||||
size_image: u32
|
size_image: u32;
|
||||||
x_pels_per_meter: i32
|
x_pels_per_meter: i32;
|
||||||
y_pels_per_meter: i32
|
y_pels_per_meter: i32;
|
||||||
clr_used: u32
|
clr_used: u32;
|
||||||
clr_important: u32
|
clr_important: u32;
|
||||||
}
|
}
|
||||||
using header: HEADER
|
using header: HEADER;
|
||||||
colors: [1]RGBQUAD
|
colors: [1]RGBQUAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RGBQUAD :: struct #ordered {
|
RGBQUAD :: struct #ordered {
|
||||||
blue, green, red, reserved: byte
|
blue, green, red, reserved: byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
BI_RGB :: 0
|
BI_RGB :: 0;
|
||||||
DIB_RGB_COLORS :: 0x00
|
DIB_RGB_COLORS :: 0x00;
|
||||||
SRCCOPY : u32 : 0x00cc0020
|
SRCCOPY : u32 : 0x00cc0020;
|
||||||
|
|
||||||
StretchDIBits :: proc(hdc: HDC,
|
StretchDIBits :: proc(hdc: HDC,
|
||||||
x_dst, y_dst, width_dst, height_dst: i32,
|
x_dst, y_dst, width_dst, height_dst: i32,
|
||||||
@@ -255,27 +253,27 @@ GetClientRect :: proc(hwnd: HWND, rect: ^RECT) -> BOOL #foreign
|
|||||||
|
|
||||||
// Windows OpenGL
|
// Windows OpenGL
|
||||||
|
|
||||||
PFD_TYPE_RGBA :: 0
|
PFD_TYPE_RGBA :: 0;
|
||||||
PFD_TYPE_COLORINDEX :: 1
|
PFD_TYPE_COLORINDEX :: 1;
|
||||||
PFD_MAIN_PLANE :: 0
|
PFD_MAIN_PLANE :: 0;
|
||||||
PFD_OVERLAY_PLANE :: 1
|
PFD_OVERLAY_PLANE :: 1;
|
||||||
PFD_UNDERLAY_PLANE :: -1
|
PFD_UNDERLAY_PLANE :: -1;
|
||||||
PFD_DOUBLEBUFFER :: 1
|
PFD_DOUBLEBUFFER :: 1;
|
||||||
PFD_STEREO :: 2
|
PFD_STEREO :: 2;
|
||||||
PFD_DRAW_TO_WINDOW :: 4
|
PFD_DRAW_TO_WINDOW :: 4;
|
||||||
PFD_DRAW_TO_BITMAP :: 8
|
PFD_DRAW_TO_BITMAP :: 8;
|
||||||
PFD_SUPPORT_GDI :: 16
|
PFD_SUPPORT_GDI :: 16;
|
||||||
PFD_SUPPORT_OPENGL :: 32
|
PFD_SUPPORT_OPENGL :: 32;
|
||||||
PFD_GENERIC_FORMAT :: 64
|
PFD_GENERIC_FORMAT :: 64;
|
||||||
PFD_NEED_PALETTE :: 128
|
PFD_NEED_PALETTE :: 128;
|
||||||
PFD_NEED_SYSTEM_PALETTE :: 0x00000100
|
PFD_NEED_SYSTEM_PALETTE :: 0x00000100;
|
||||||
PFD_SWAP_EXCHANGE :: 0x00000200
|
PFD_SWAP_EXCHANGE :: 0x00000200;
|
||||||
PFD_SWAP_COPY :: 0x00000400
|
PFD_SWAP_COPY :: 0x00000400;
|
||||||
PFD_SWAP_LAYER_BUFFERS :: 0x00000800
|
PFD_SWAP_LAYER_BUFFERS :: 0x00000800;
|
||||||
PFD_GENERIC_ACCELERATED :: 0x00001000
|
PFD_GENERIC_ACCELERATED :: 0x00001000;
|
||||||
PFD_DEPTH_DONTCARE :: 0x20000000
|
PFD_DEPTH_DONTCARE :: 0x20000000;
|
||||||
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000
|
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
|
||||||
PFD_STEREO_DONTCARE :: 0x80000000
|
PFD_STEREO_DONTCARE :: 0x80000000;
|
||||||
|
|
||||||
HGLRC :: type HANDLE
|
HGLRC :: type HANDLE
|
||||||
PROC :: type proc()
|
PROC :: type proc()
|
||||||
@@ -285,7 +283,7 @@ wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, att
|
|||||||
PIXELFORMATDESCRIPTOR :: struct #ordered {
|
PIXELFORMATDESCRIPTOR :: struct #ordered {
|
||||||
size,
|
size,
|
||||||
version,
|
version,
|
||||||
flags: u32
|
flags: u32;
|
||||||
|
|
||||||
pixel_type,
|
pixel_type,
|
||||||
color_bits,
|
color_bits,
|
||||||
@@ -306,11 +304,11 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
|
|||||||
stencil_bits,
|
stencil_bits,
|
||||||
aux_buffers,
|
aux_buffers,
|
||||||
layer_type,
|
layer_type,
|
||||||
reserved: byte
|
reserved: byte;
|
||||||
|
|
||||||
layer_mask,
|
layer_mask,
|
||||||
visible_mask,
|
visible_mask,
|
||||||
damage_mask: u32
|
damage_mask: u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
GetDC :: proc(h: HANDLE) -> HDC #foreign
|
GetDC :: proc(h: HANDLE) -> HDC #foreign
|
||||||
@@ -319,11 +317,11 @@ ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign
|
|||||||
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign #dll_import
|
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign #dll_import
|
||||||
ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign #dll_import
|
ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign #dll_import
|
||||||
|
|
||||||
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091
|
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
|
||||||
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092
|
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092;
|
||||||
WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126
|
WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126;
|
||||||
WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001
|
WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001;
|
||||||
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002
|
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002;
|
||||||
|
|
||||||
wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign #dll_import
|
wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign #dll_import
|
||||||
wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign #dll_import
|
wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign #dll_import
|
||||||
@@ -336,7 +334,7 @@ GetKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
|||||||
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
||||||
|
|
||||||
is_key_down :: proc(key: Key_Code) -> bool {
|
is_key_down :: proc(key: Key_Code) -> bool {
|
||||||
return GetAsyncKeyState(key as i32) < 0
|
return GetAsyncKeyState(key as i32) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Key_Code :: enum i32 {
|
Key_Code :: enum i32 {
|
||||||
|
|||||||
+52
-73
@@ -223,10 +223,10 @@ typedef struct CheckerContext {
|
|||||||
#define MAP_NAME MapExprInfo
|
#define MAP_NAME MapExprInfo
|
||||||
#include "../map.c"
|
#include "../map.c"
|
||||||
|
|
||||||
typedef struct DelayedImport {
|
typedef struct DelayedDecl {
|
||||||
Scope * parent;
|
Scope * parent;
|
||||||
AstNodeImportDecl *decl;
|
AstNode *decl;
|
||||||
} DelayedImport;
|
} DelayedDecl;
|
||||||
|
|
||||||
|
|
||||||
// NOTE(bill): Symbol tables
|
// NOTE(bill): Symbol tables
|
||||||
@@ -253,7 +253,8 @@ typedef struct Checker {
|
|||||||
BaseTypeSizes sizes;
|
BaseTypeSizes sizes;
|
||||||
Scope * global_scope;
|
Scope * global_scope;
|
||||||
Array(ProcedureInfo) procs; // NOTE(bill): Procedures to check
|
Array(ProcedureInfo) procs; // NOTE(bill): Procedures to check
|
||||||
Array(DelayedImport) delayed_imports;
|
Array(DelayedDecl) delayed_imports;
|
||||||
|
Array(DelayedDecl) delayed_foreign_libraries;
|
||||||
|
|
||||||
|
|
||||||
gbArena arena;
|
gbArena arena;
|
||||||
@@ -427,7 +428,7 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (e->scope != shared) {
|
if (e->scope != shared) {
|
||||||
// Do not return imported entities even #load ones
|
// Do not return imported entities even #include ones
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -616,6 +617,7 @@ void init_checker(Checker *c, Parser *parser, BaseTypeSizes sizes) {
|
|||||||
array_init(&c->proc_stack, a);
|
array_init(&c->proc_stack, a);
|
||||||
array_init(&c->procs, a);
|
array_init(&c->procs, a);
|
||||||
array_init(&c->delayed_imports, a);
|
array_init(&c->delayed_imports, a);
|
||||||
|
array_init(&c->delayed_foreign_libraries, a);
|
||||||
|
|
||||||
// NOTE(bill): Is this big enough or too small?
|
// NOTE(bill): Is this big enough or too small?
|
||||||
isize item_size = gb_max3(gb_size_of(Entity), gb_size_of(Type), gb_size_of(Scope));
|
isize item_size = gb_max3(gb_size_of(Entity), gb_size_of(Type), gb_size_of(Scope));
|
||||||
@@ -642,6 +644,7 @@ void destroy_checker(Checker *c) {
|
|||||||
array_free(&c->proc_stack);
|
array_free(&c->proc_stack);
|
||||||
array_free(&c->procs);
|
array_free(&c->procs);
|
||||||
array_free(&c->delayed_imports);
|
array_free(&c->delayed_imports);
|
||||||
|
array_free(&c->delayed_foreign_libraries);
|
||||||
|
|
||||||
gb_arena_free(&c->arena);
|
gb_arena_free(&c->arena);
|
||||||
}
|
}
|
||||||
@@ -1083,39 +1086,6 @@ void check_global_entities_by_kind(Checker *c, EntityKind kind) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray nodes, MapScope *file_scopes);
|
|
||||||
|
|
||||||
void check_global_when_stmt(Checker *c, Scope *parent_scope, AstNodeWhenStmt *ws, MapScope *file_scopes) {
|
|
||||||
Operand operand = {Addressing_Invalid};
|
|
||||||
check_expr(c, &operand, ws->cond);
|
|
||||||
if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
|
|
||||||
error_node(ws->cond, "Non-boolean condition in `when` statement");
|
|
||||||
}
|
|
||||||
if (operand.mode != Addressing_Constant) {
|
|
||||||
error_node(ws->cond, "Non-constant condition in `when` statement");
|
|
||||||
}
|
|
||||||
if (ws->body == NULL || ws->body->kind != AstNode_BlockStmt) {
|
|
||||||
error_node(ws->cond, "Invalid body for `when` statement");
|
|
||||||
} else {
|
|
||||||
if (operand.value.kind == ExactValue_Bool &&
|
|
||||||
operand.value.value_bool == true) {
|
|
||||||
ast_node(body, BlockStmt, ws->body);
|
|
||||||
check_global_collect_entities(c, parent_scope, body->stmts, file_scopes);
|
|
||||||
} else if (ws->else_stmt) {
|
|
||||||
switch (ws->else_stmt->kind) {
|
|
||||||
case AstNode_BlockStmt:
|
|
||||||
check_global_collect_entities(c, parent_scope, ws->else_stmt->BlockStmt.stmts, file_scopes);
|
|
||||||
break;
|
|
||||||
case AstNode_WhenStmt:
|
|
||||||
check_global_when_stmt(c, parent_scope, &ws->else_stmt->WhenStmt, file_scopes);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
error_node(ws->else_stmt, "Invalid `else` statement in `when` statement");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray nodes, MapScope *file_scopes) {
|
void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray nodes, MapScope *file_scopes) {
|
||||||
for_array(decl_index, nodes) {
|
for_array(decl_index, nodes) {
|
||||||
AstNode *decl = nodes.e[decl_index];
|
AstNode *decl = nodes.e[decl_index];
|
||||||
@@ -1126,16 +1096,13 @@ void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray
|
|||||||
switch (decl->kind) {
|
switch (decl->kind) {
|
||||||
case_ast_node(bd, BadDecl, decl);
|
case_ast_node(bd, BadDecl, decl);
|
||||||
case_end;
|
case_end;
|
||||||
case_ast_node(ws, WhenStmt, decl);
|
|
||||||
// Will be handled later
|
|
||||||
case_end;
|
|
||||||
case_ast_node(id, ImportDecl, decl);
|
case_ast_node(id, ImportDecl, decl);
|
||||||
if (!parent_scope->is_file) {
|
if (!parent_scope->is_file) {
|
||||||
// NOTE(bill): _Should_ be caught by the parser
|
// NOTE(bill): _Should_ be caught by the parser
|
||||||
// TODO(bill): Better error handling if it isn't
|
// TODO(bill): Better error handling if it isn't
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
DelayedImport di = {parent_scope, id};
|
DelayedDecl di = {parent_scope, decl};
|
||||||
array_add(&c->delayed_imports, di);
|
array_add(&c->delayed_imports, di);
|
||||||
case_end;
|
case_end;
|
||||||
case_ast_node(fl, ForeignLibrary, decl);
|
case_ast_node(fl, ForeignLibrary, decl);
|
||||||
@@ -1145,24 +1112,8 @@ void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String file_str = fl->filepath.string;
|
DelayedDecl di = {parent_scope, decl};
|
||||||
String base_dir = fl->base_dir;
|
array_add(&c->delayed_foreign_libraries, di);
|
||||||
|
|
||||||
if (!fl->is_system) {
|
|
||||||
gbAllocator a = heap_allocator(); // TODO(bill): Change this allocator
|
|
||||||
|
|
||||||
String rel_path = get_fullpath_relative(a, base_dir, file_str);
|
|
||||||
String import_file = rel_path;
|
|
||||||
if (!gb_file_exists(cast(char *)rel_path.text)) { // NOTE(bill): This should be null terminated
|
|
||||||
String abs_path = get_fullpath_core(a, file_str);
|
|
||||||
if (gb_file_exists(cast(char *)abs_path.text)) {
|
|
||||||
import_file = abs_path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_str = import_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
try_add_foreign_library_path(c, file_str);
|
|
||||||
case_end;
|
case_end;
|
||||||
case_ast_node(cd, ConstDecl, decl);
|
case_ast_node(cd, ConstDecl, decl);
|
||||||
for_array(i, cd->values) {
|
for_array(i, cd->values) {
|
||||||
@@ -1251,23 +1202,13 @@ void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): `when` stmts need to be handled after the other as the condition may refer to something
|
|
||||||
// declared after this stmt in source
|
|
||||||
for_array(decl_index, nodes) {
|
|
||||||
AstNode *decl = nodes.e[decl_index];
|
|
||||||
switch (decl->kind) {
|
|
||||||
case_ast_node(ws, WhenStmt, decl);
|
|
||||||
check_global_when_stmt(c, parent_scope, ws, file_scopes);
|
|
||||||
case_end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_import_entities(Checker *c, MapScope *file_scopes) {
|
void check_import_entities(Checker *c, MapScope *file_scopes) {
|
||||||
for_array(i, c->delayed_imports) {
|
for_array(i, c->delayed_imports) {
|
||||||
AstNodeImportDecl *id = c->delayed_imports.e[i].decl;
|
|
||||||
Scope *parent_scope = c->delayed_imports.e[i].parent;
|
Scope *parent_scope = c->delayed_imports.e[i].parent;
|
||||||
|
AstNode *decl = c->delayed_imports.e[i].decl;
|
||||||
|
ast_node(id, ImportDecl, decl);
|
||||||
|
|
||||||
HashKey key = hash_string(id->fullpath);
|
HashKey key = hash_string(id->fullpath);
|
||||||
Scope **found = map_scope_get(file_scopes, key);
|
Scope **found = map_scope_get(file_scopes, key);
|
||||||
@@ -1286,6 +1227,19 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (id->cond != NULL) {
|
||||||
|
Operand operand = {Addressing_Invalid};
|
||||||
|
check_expr(c, &operand, id->cond);
|
||||||
|
if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) {
|
||||||
|
error_node(id->cond, "Non-constant boolean `when` condition");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (operand.value.kind == ExactValue_Bool &&
|
||||||
|
!operand.value.value_bool) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool previously_added = false;
|
bool previously_added = false;
|
||||||
for_array(import_index, parent_scope->imported) {
|
for_array(import_index, parent_scope->imported) {
|
||||||
Scope *prev = parent_scope->imported.e[import_index];
|
Scope *prev = parent_scope->imported.e[import_index];
|
||||||
@@ -1366,6 +1320,31 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for_array(i, c->delayed_foreign_libraries) {
|
||||||
|
Scope *parent_scope = c->delayed_foreign_libraries.e[i].parent;
|
||||||
|
AstNode *decl = c->delayed_foreign_libraries.e[i].decl;
|
||||||
|
ast_node(fl, ForeignLibrary, decl);
|
||||||
|
|
||||||
|
String file_str = fl->filepath.string;
|
||||||
|
String base_dir = fl->base_dir;
|
||||||
|
|
||||||
|
if (!fl->is_system) {
|
||||||
|
gbAllocator a = heap_allocator(); // TODO(bill): Change this allocator
|
||||||
|
|
||||||
|
String rel_path = get_fullpath_relative(a, base_dir, file_str);
|
||||||
|
String import_file = rel_path;
|
||||||
|
if (!gb_file_exists(cast(char *)rel_path.text)) { // NOTE(bill): This should be null terminated
|
||||||
|
String abs_path = get_fullpath_core(a, file_str);
|
||||||
|
if (gb_file_exists(cast(char *)abs_path.text)) {
|
||||||
|
import_file = abs_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_str = import_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
try_add_foreign_library_path(c, file_str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+23
-26
@@ -1,10 +1,10 @@
|
|||||||
bool check_is_terminating(AstNode *node);
|
bool check_is_terminating(AstNode *node);
|
||||||
void check_stmt (Checker *c, AstNode *node, u32 flags);
|
void check_stmt (Checker *c, AstNode *node, u32 flags);
|
||||||
void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags);
|
void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags);
|
||||||
void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker);
|
void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker);
|
||||||
void check_const_decl (Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr);
|
void check_const_decl (Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr);
|
||||||
void check_proc_decl (Checker *c, Entity *e, DeclInfo *d);
|
void check_proc_decl (Checker *c, Entity *e, DeclInfo *d);
|
||||||
void check_var_decl (Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr);
|
void check_var_decl (Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr);
|
||||||
|
|
||||||
// NOTE(bill): `content_name` is for debugging and error messages
|
// NOTE(bill): `content_name` is for debugging and error messages
|
||||||
Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) {
|
Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) {
|
||||||
@@ -227,23 +227,21 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
|||||||
|
|
||||||
if (operand->mode != Addressing_Constant) {
|
if (operand->mode != Addressing_Constant) {
|
||||||
// TODO(bill): better error
|
// TODO(bill): better error
|
||||||
error_node(operand->expr,
|
error_node(operand->expr, "`%.*s` is not a constant", LIT(ast_node_token(operand->expr).string));
|
||||||
"`%.*s` is not a constant", LIT(ast_node_token(operand->expr).string));
|
if (e->type == NULL) {
|
||||||
|
e->type = t_invalid;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!is_type_constant_type(operand->type)) {
|
||||||
|
gbString type_str = type_to_string(operand->type);
|
||||||
|
error_node(operand->expr, "Invalid constant type: `%s`", type_str);
|
||||||
|
gb_string_free(type_str);
|
||||||
if (e->type == NULL) {
|
if (e->type == NULL) {
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// if (!is_type_constant_type(operand->type)) {
|
|
||||||
// gbString type_str = type_to_string(operand->type);
|
|
||||||
// defer (gb_string_free(type_str));
|
|
||||||
// error_node(operand->expr,
|
|
||||||
// "Invalid constant type: `%s`", type_str);
|
|
||||||
// if (e->type == NULL) {
|
|
||||||
// e->type = t_invalid;
|
|
||||||
// }
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (e->type == NULL) { // NOTE(bill): type inference
|
if (e->type == NULL) { // NOTE(bill): type inference
|
||||||
e->type = operand->type;
|
e->type = operand->type;
|
||||||
@@ -269,14 +267,13 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e
|
|||||||
|
|
||||||
if (type_expr) {
|
if (type_expr) {
|
||||||
Type *t = check_type(c, type_expr);
|
Type *t = check_type(c, type_expr);
|
||||||
// if (!is_type_constant_type(t)) {
|
if (!is_type_constant_type(t)) {
|
||||||
// gbString str = type_to_string(t);
|
gbString str = type_to_string(t);
|
||||||
// defer (gb_string_free(str));
|
error_node(type_expr, "Invalid constant type `%s`", str);
|
||||||
// error_node(type_expr),
|
gb_string_free(str);
|
||||||
// "Invalid constant type `%s`", str);
|
e->type = t_invalid;
|
||||||
// e->type = t_invalid;
|
return;
|
||||||
// return;
|
}
|
||||||
// }
|
|
||||||
e->type = t;
|
e->type = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
|
|||||||
gb_temp_arena_memory_end(tmp);
|
gb_temp_arena_memory_end(tmp);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
#if 0
|
||||||
case_ast_node(pd, ProcDecl, node);
|
case_ast_node(pd, ProcDecl, node);
|
||||||
if (!ast_node_expect(pd->name, AstNode_Ident)) {
|
if (!ast_node_expect(pd->name, AstNode_Ident)) {
|
||||||
break;
|
break;
|
||||||
@@ -163,6 +164,7 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
|
|||||||
add_entity_and_decl_info(c, pd->name, e, d);
|
add_entity_and_decl_info(c, pd->name, e, d);
|
||||||
check_entity_decl(c, e, d, NULL, NULL);
|
check_entity_decl(c, e, d, NULL, NULL);
|
||||||
case_end;
|
case_end;
|
||||||
|
#endif
|
||||||
|
|
||||||
case_ast_node(td, TypeDecl, node);
|
case_ast_node(td, TypeDecl, node);
|
||||||
if (!ast_node_expect(td->name, AstNode_Ident)) {
|
if (!ast_node_expect(td->name, AstNode_Ident)) {
|
||||||
|
|||||||
+29
-22
@@ -111,6 +111,15 @@ bool check_is_terminating(AstNode *node) {
|
|||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(ws, WhenStmt, node);
|
||||||
|
if (ws->else_stmt != NULL) {
|
||||||
|
if (check_is_terminating(ws->body) &&
|
||||||
|
check_is_terminating(ws->else_stmt)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(fs, ForStmt, node);
|
case_ast_node(fs, ForStmt, node);
|
||||||
if (fs->cond == NULL && !check_has_break(fs->body, true)) {
|
if (fs->cond == NULL && !check_has_break(fs->body, true)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -283,30 +292,28 @@ typedef struct TypeAndToken {
|
|||||||
void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
|
void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
|
||||||
Operand operand = {Addressing_Invalid};
|
Operand operand = {Addressing_Invalid};
|
||||||
check_expr(c, &operand, ws->cond);
|
check_expr(c, &operand, ws->cond);
|
||||||
if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
|
if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) {
|
||||||
error_node(ws->cond, "Non-boolean condition in `when` statement");
|
error_node(ws->cond, "Non-constant boolean `when` condition");
|
||||||
}
|
return;
|
||||||
if (operand.mode != Addressing_Constant) {
|
|
||||||
error_node(ws->cond, "Non-constant condition in `when` statement");
|
|
||||||
}
|
}
|
||||||
if (ws->body == NULL || ws->body->kind != AstNode_BlockStmt) {
|
if (ws->body == NULL || ws->body->kind != AstNode_BlockStmt) {
|
||||||
error_node(ws->cond, "Invalid body for `when` statement");
|
error_node(ws->cond, "Invalid body for `when` statement");
|
||||||
} else {
|
return;
|
||||||
if (operand.value.kind == ExactValue_Bool &&
|
}
|
||||||
operand.value.value_bool) {
|
if (operand.value.kind == ExactValue_Bool &&
|
||||||
check_stmt_list(c, ws->body->BlockStmt.stmts, flags);
|
operand.value.value_bool) {
|
||||||
} else if (ws->else_stmt) {
|
check_stmt_list(c, ws->body->BlockStmt.stmts, flags);
|
||||||
switch (ws->else_stmt->kind) {
|
} else if (ws->else_stmt) {
|
||||||
case AstNode_BlockStmt:
|
switch (ws->else_stmt->kind) {
|
||||||
check_stmt_list(c, ws->else_stmt->BlockStmt.stmts, flags);
|
case AstNode_BlockStmt:
|
||||||
break;
|
check_stmt_list(c, ws->else_stmt->BlockStmt.stmts, flags);
|
||||||
case AstNode_WhenStmt:
|
break;
|
||||||
check_when_stmt(c, &ws->else_stmt->WhenStmt, flags);
|
case AstNode_WhenStmt:
|
||||||
break;
|
check_when_stmt(c, &ws->else_stmt->WhenStmt, flags);
|
||||||
default:
|
break;
|
||||||
error_node(ws->else_stmt, "Invalid `else` statement in `when` statement");
|
default:
|
||||||
break;
|
error_node(ws->else_stmt, "Invalid `else` statement in `when` statement");
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1085,7 +1092,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
|
|
||||||
case_ast_node(pd, ProcDecl, node);
|
case_ast_node(pd, ProcDecl, node);
|
||||||
// NOTE(bill): Handled elsewhere
|
// NOTE(bill): Handled elsewhere
|
||||||
#if 0
|
#if 1
|
||||||
// NOTE(bill): This must be handled here so it has access to the parent scope stuff
|
// NOTE(bill): This must be handled here so it has access to the parent scope stuff
|
||||||
// e.g. using
|
// e.g. using
|
||||||
Entity *e = make_entity_procedure(c->allocator, c->context.scope, pd->name->Ident, NULL);
|
Entity *e = make_entity_procedure(c->allocator, c->context.scope, pd->name->Ident, NULL);
|
||||||
|
|||||||
+3
-4
@@ -233,8 +233,8 @@ int main(int argc, char **argv) {
|
|||||||
gbString lib_str = gb_string_make(heap_allocator(), "Kernel32.lib");
|
gbString lib_str = gb_string_make(heap_allocator(), "Kernel32.lib");
|
||||||
// defer (gb_string_free(lib_str));
|
// defer (gb_string_free(lib_str));
|
||||||
char lib_str_buf[1024] = {0};
|
char lib_str_buf[1024] = {0};
|
||||||
for_array(i, parser.foreign_libraries) {
|
for_array(i, checker.info.foreign_libraries) {
|
||||||
String lib = parser.foreign_libraries.e[i];
|
String lib = checker.info.foreign_libraries.e[i];
|
||||||
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
|
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
|
||||||
" %.*s.lib", LIT(lib));
|
" %.*s.lib", LIT(lib));
|
||||||
lib_str = gb_string_appendc(lib_str, lib_str_buf);
|
lib_str = gb_string_appendc(lib_str, lib_str_buf);
|
||||||
@@ -255,8 +255,7 @@ int main(int argc, char **argv) {
|
|||||||
// timings_print_all(&timings);
|
// timings_print_all(&timings);
|
||||||
|
|
||||||
if (run_output) {
|
if (run_output) {
|
||||||
win32_exec_command_line_app("odin run",
|
win32_exec_command_line_app("odin run", "%.*s.exe", cast(int)base_name_len, output_name);
|
||||||
"%.*s.exe", cast(int)base_name_len, output_name);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+122
-119
@@ -56,7 +56,6 @@ typedef struct Parser {
|
|||||||
Array(AstFile) files;
|
Array(AstFile) files;
|
||||||
Array(ImportedFile) imports;
|
Array(ImportedFile) imports;
|
||||||
gbAtomic32 import_index;
|
gbAtomic32 import_index;
|
||||||
Array(String) foreign_libraries;
|
|
||||||
isize total_token_count;
|
isize total_token_count;
|
||||||
gbMutex mutex;
|
gbMutex mutex;
|
||||||
} Parser;
|
} Parser;
|
||||||
@@ -88,7 +87,8 @@ typedef enum StmtStateFlag {
|
|||||||
|
|
||||||
AstNodeArray make_ast_node_array(AstFile *f) {
|
AstNodeArray make_ast_node_array(AstFile *f) {
|
||||||
AstNodeArray a;
|
AstNodeArray a;
|
||||||
array_init(&a, gb_arena_allocator(&f->arena));
|
// array_init(&a, gb_arena_allocator(&f->arena));
|
||||||
|
array_init(&a, heap_allocator());
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,16 +254,17 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
|
|||||||
}) \
|
}) \
|
||||||
AST_NODE_KIND(ImportDecl, "import declaration", struct { \
|
AST_NODE_KIND(ImportDecl, "import declaration", struct { \
|
||||||
Token token, relpath; \
|
Token token, relpath; \
|
||||||
String os, arch; \
|
|
||||||
String fullpath; \
|
String fullpath; \
|
||||||
Token import_name; \
|
Token import_name; \
|
||||||
bool is_load; \
|
bool is_load; \
|
||||||
|
AstNode *cond; \
|
||||||
AstNode *note; \
|
AstNode *note; \
|
||||||
}) \
|
}) \
|
||||||
AST_NODE_KIND(ForeignLibrary, "foreign library", struct { \
|
AST_NODE_KIND(ForeignLibrary, "foreign library", struct { \
|
||||||
Token token, filepath; \
|
Token token, filepath; \
|
||||||
String base_dir; \
|
String base_dir; \
|
||||||
bool is_system; \
|
AstNode *cond; \
|
||||||
|
bool is_system; \
|
||||||
}) \
|
}) \
|
||||||
AST_NODE_KIND(_DeclEnd, "", i32) \
|
AST_NODE_KIND(_DeclEnd, "", i32) \
|
||||||
AST_NODE_KIND(_TypeBegin, "", i32) \
|
AST_NODE_KIND(_TypeBegin, "", i32) \
|
||||||
@@ -1005,22 +1006,22 @@ AstNode *make_type_decl(AstFile *f, Token token, AstNode *name, AstNode *type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AstNode *make_import_decl(AstFile *f, Token token, Token relpath, Token import_name,
|
AstNode *make_import_decl(AstFile *f, Token token, Token relpath, Token import_name,
|
||||||
String os, String arch,
|
AstNode *cond,
|
||||||
bool is_load) {
|
bool is_load) {
|
||||||
AstNode *result = make_node(f, AstNode_ImportDecl);
|
AstNode *result = make_node(f, AstNode_ImportDecl);
|
||||||
result->ImportDecl.token = token;
|
result->ImportDecl.token = token;
|
||||||
result->ImportDecl.relpath = relpath;
|
result->ImportDecl.relpath = relpath;
|
||||||
result->ImportDecl.import_name = import_name;
|
result->ImportDecl.import_name = import_name;
|
||||||
result->ImportDecl.os = os;
|
result->ImportDecl.cond = cond;
|
||||||
result->ImportDecl.arch = arch;
|
|
||||||
result->ImportDecl.is_load = is_load;
|
result->ImportDecl.is_load = is_load;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode *make_foreign_library(AstFile *f, Token token, Token filepath, bool is_system) {
|
AstNode *make_foreign_library(AstFile *f, Token token, Token filepath, AstNode *cond, bool is_system) {
|
||||||
AstNode *result = make_node(f, AstNode_ForeignLibrary);
|
AstNode *result = make_node(f, AstNode_ForeignLibrary);
|
||||||
result->ForeignLibrary.token = token;
|
result->ForeignLibrary.token = token;
|
||||||
result->ForeignLibrary.filepath = filepath;
|
result->ForeignLibrary.filepath = filepath;
|
||||||
|
result->ForeignLibrary.cond = cond;
|
||||||
result->ForeignLibrary.is_system = is_system;
|
result->ForeignLibrary.is_system = is_system;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1156,19 +1157,30 @@ bool expect_semicolon_after_stmt(AstFile *f, AstNode *s) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->curr_token.pos.line != f->prev_token.pos.line) {
|
if (s != NULL) {
|
||||||
return true;
|
switch (s->kind) {
|
||||||
|
case AstNode_ProcDecl:
|
||||||
|
case AstNode_TypeDecl:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (f->curr_token.kind) {
|
// if (f->curr_token.pos.line != f->prev_token.pos.line) {
|
||||||
case Token_EOF:
|
// return true;
|
||||||
case Token_CloseBrace:
|
// }
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
syntax_error(f->curr_token,
|
// switch (f->curr_token.kind) {
|
||||||
"Expected `;` after %.*s, got `%.*s`",
|
// case Token_EOF:
|
||||||
LIT(ast_node_strings[s->kind]), LIT(token_strings[f->curr_token.kind]));
|
// case Token_CloseBrace:
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (s != NULL) {
|
||||||
|
syntax_error(f->prev_token, "Expected `;` after %.*s, got `%.*s`",
|
||||||
|
LIT(ast_node_strings[s->kind]), LIT(token_strings[f->prev_token.kind]));
|
||||||
|
} else {
|
||||||
|
syntax_error(f->prev_token, "Expected `;`");
|
||||||
|
}
|
||||||
fix_advance_to_next_stmt(f);
|
fix_advance_to_next_stmt(f);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1197,12 +1209,6 @@ AstNode *parse_tag_expr(AstFile *f, AstNode *expression) {
|
|||||||
return make_tag_expr(f, token, name, expression);
|
return make_tag_expr(f, token, name, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode *parse_tag_stmt(AstFile *f, AstNode *statement) {
|
|
||||||
Token token = expect_token(f, Token_Hash);
|
|
||||||
Token name = expect_token(f, Token_Identifier);
|
|
||||||
return make_tag_stmt(f, token, name, statement);
|
|
||||||
}
|
|
||||||
|
|
||||||
AstNode *unparen_expr(AstNode *node) {
|
AstNode *unparen_expr(AstNode *node) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (node->kind != AstNode_ParenExpr)
|
if (node->kind != AstNode_ParenExpr)
|
||||||
@@ -2518,10 +2524,8 @@ AstNode *parse_return_stmt(AstFile *f) {
|
|||||||
f->curr_token.pos.line == token.pos.line) {
|
f->curr_token.pos.line == token.pos.line) {
|
||||||
results = parse_rhs_expr_list(f);
|
results = parse_rhs_expr_list(f);
|
||||||
}
|
}
|
||||||
if (f->curr_token.kind != Token_CloseBrace) {
|
|
||||||
expect_semicolon_after_stmt(f, results.e[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
expect_semicolon_after_stmt(f, results.e[0]);
|
||||||
return make_return_stmt(f, token, results);
|
return make_return_stmt(f, token, results);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2751,11 +2755,11 @@ AstNode *parse_stmt(AstFile *f) {
|
|||||||
// TODO(bill): other keywords
|
// TODO(bill): other keywords
|
||||||
case Token_if: return parse_if_stmt(f);
|
case Token_if: return parse_if_stmt(f);
|
||||||
case Token_when: return parse_when_stmt(f);
|
case Token_when: return parse_when_stmt(f);
|
||||||
case Token_return: return parse_return_stmt(f);
|
|
||||||
case Token_for: return parse_for_stmt(f);
|
case Token_for: return parse_for_stmt(f);
|
||||||
case Token_match: return parse_match_stmt(f);
|
case Token_match: return parse_match_stmt(f);
|
||||||
case Token_defer: return parse_defer_stmt(f);
|
case Token_defer: return parse_defer_stmt(f);
|
||||||
case Token_asm: return parse_asm_stmt(f);
|
case Token_asm: return parse_asm_stmt(f);
|
||||||
|
case Token_return: return parse_return_stmt(f);
|
||||||
|
|
||||||
case Token_break:
|
case Token_break:
|
||||||
case Token_continue:
|
case Token_continue:
|
||||||
@@ -2821,29 +2825,103 @@ AstNode *parse_stmt(AstFile *f) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Token_Hash: {
|
case Token_Hash: {
|
||||||
s = parse_tag_stmt(f, NULL);
|
AstNode *s = NULL;
|
||||||
String tag = s->TagStmt.name.string;
|
Token hash_token = expect_token(f, Token_Hash);
|
||||||
|
Token name = expect_token(f, Token_Identifier);
|
||||||
|
String tag = name.string;
|
||||||
if (str_eq(tag, str_lit("shared_global_scope"))) {
|
if (str_eq(tag, str_lit("shared_global_scope"))) {
|
||||||
if (f->curr_proc == NULL) {
|
if (f->curr_proc == NULL) {
|
||||||
f->is_global_scope = true;
|
f->is_global_scope = true;
|
||||||
return make_empty_stmt(f, f->curr_token);
|
s = make_empty_stmt(f, f->curr_token);
|
||||||
|
} else {
|
||||||
|
syntax_error(token, "You cannot use #shared_global_scope within a procedure. This must be done at the file scope");
|
||||||
|
s = make_bad_decl(f, token, f->curr_token);
|
||||||
}
|
}
|
||||||
syntax_error(token, "You cannot use #shared_global_scope within a procedure. This must be done at the file scope");
|
expect_semicolon_after_stmt(f, s);
|
||||||
return make_bad_decl(f, token, f->curr_token);
|
return s;
|
||||||
} else if (str_eq(tag, str_lit("foreign_system_library"))) {
|
} else if (str_eq(tag, str_lit("foreign_system_library"))) {
|
||||||
|
AstNode *cond = NULL;
|
||||||
Token file_path = expect_token(f, Token_String);
|
Token file_path = expect_token(f, Token_String);
|
||||||
if (f->curr_proc == NULL) {
|
|
||||||
return make_foreign_library(f, s->TagStmt.token, file_path, true);
|
if (allow_token(f, Token_when)) {
|
||||||
|
cond = parse_expr(f, false);
|
||||||
}
|
}
|
||||||
syntax_error(token, "You cannot use #foreign_system_library within a procedure. This must be done at the file scope");
|
|
||||||
return make_bad_decl(f, token, file_path);
|
if (f->curr_proc == NULL) {
|
||||||
|
s = make_foreign_library(f, hash_token, file_path, cond, true);
|
||||||
|
} else {
|
||||||
|
syntax_error(token, "You cannot use #foreign_system_library within a procedure. This must be done at the file scope");
|
||||||
|
s = make_bad_decl(f, token, file_path);
|
||||||
|
}
|
||||||
|
expect_semicolon_after_stmt(f, s);
|
||||||
|
return s;
|
||||||
} else if (str_eq(tag, str_lit("foreign_library"))) {
|
} else if (str_eq(tag, str_lit("foreign_library"))) {
|
||||||
|
AstNode *cond = NULL;
|
||||||
Token file_path = expect_token(f, Token_String);
|
Token file_path = expect_token(f, Token_String);
|
||||||
if (f->curr_proc == NULL) {
|
|
||||||
return make_foreign_library(f, s->TagStmt.token, file_path, false);
|
if (allow_token(f, Token_when)) {
|
||||||
|
cond = parse_expr(f, false);
|
||||||
}
|
}
|
||||||
syntax_error(token, "You cannot use #foreign_library within a procedure. This must be done at the file scope");
|
|
||||||
return make_bad_decl(f, token, file_path);
|
if (f->curr_proc == NULL) {
|
||||||
|
s = make_foreign_library(f, hash_token, file_path, cond, false);
|
||||||
|
} else {
|
||||||
|
syntax_error(token, "You cannot use #foreign_library within a procedure. This must be done at the file scope");
|
||||||
|
s = make_bad_decl(f, token, file_path);
|
||||||
|
}
|
||||||
|
expect_semicolon_after_stmt(f, s);
|
||||||
|
return s;
|
||||||
|
} else if (str_eq(tag, str_lit("import"))) {
|
||||||
|
AstNode *cond = NULL;
|
||||||
|
Token import_name = {0};
|
||||||
|
|
||||||
|
switch (f->curr_token.kind) {
|
||||||
|
case Token_Period:
|
||||||
|
import_name = f->curr_token;
|
||||||
|
import_name.kind = Token_Identifier;
|
||||||
|
next_token(f);
|
||||||
|
break;
|
||||||
|
case Token_Identifier:
|
||||||
|
import_name = f->curr_token;
|
||||||
|
next_token(f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_eq(import_name.string, str_lit("_"))) {
|
||||||
|
syntax_error(token, "Illegal import name: `_`");
|
||||||
|
}
|
||||||
|
|
||||||
|
Token file_path = expect_token_after(f, Token_String, "#import");
|
||||||
|
if (allow_token(f, Token_when)) {
|
||||||
|
cond = parse_expr(f, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->curr_proc != NULL) {
|
||||||
|
syntax_error(token, "You cannot use #import within a procedure. This must be done at the file scope");
|
||||||
|
s = make_bad_decl(f, token, file_path);
|
||||||
|
} else {
|
||||||
|
s = make_import_decl(f, hash_token, file_path, import_name, cond, false);
|
||||||
|
expect_semicolon_after_stmt(f, s);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
} else if (str_eq(tag, str_lit("include"))) {
|
||||||
|
AstNode *cond = NULL;
|
||||||
|
Token file_path = expect_token(f, Token_String);
|
||||||
|
Token import_name = file_path;
|
||||||
|
import_name.string = str_lit(".");
|
||||||
|
|
||||||
|
if (allow_token(f, Token_when)) {
|
||||||
|
cond = parse_expr(f, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->curr_proc == NULL) {
|
||||||
|
s = make_import_decl(f, hash_token, file_path, import_name, cond, true);
|
||||||
|
} else {
|
||||||
|
syntax_error(token, "You cannot use #include within a procedure. This must be done at the file scope");
|
||||||
|
s = make_bad_decl(f, token, file_path);
|
||||||
|
}
|
||||||
|
expect_semicolon_after_stmt(f, s);
|
||||||
|
return s;
|
||||||
} else if (str_eq(tag, str_lit("thread_local"))) {
|
} else if (str_eq(tag, str_lit("thread_local"))) {
|
||||||
AstNode *var_decl = parse_simple_stmt(f);
|
AstNode *var_decl = parse_simple_stmt(f);
|
||||||
if (var_decl->kind != AstNode_VarDecl) {
|
if (var_decl->kind != AstNode_VarDecl) {
|
||||||
@@ -2870,60 +2948,9 @@ AstNode *parse_stmt(AstFile *f) {
|
|||||||
syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together");
|
syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together");
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
} else if (str_eq(tag, str_lit("import"))) {
|
|
||||||
String os = {0};
|
|
||||||
String arch = {0};
|
|
||||||
|
|
||||||
// if (tag.len > 6) {
|
|
||||||
// String sub = make_string(tag.text+6, tag.len-6);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(bill): better error messages
|
|
||||||
Token import_name = {0};
|
|
||||||
Token file_path = expect_token_after(f, Token_String, "#import");
|
|
||||||
if (allow_token(f, Token_as)) {
|
|
||||||
// NOTE(bill): Custom import name
|
|
||||||
if (f->curr_token.kind == Token_Period) {
|
|
||||||
import_name = f->curr_token;
|
|
||||||
import_name.kind = Token_Identifier;
|
|
||||||
next_token(f);
|
|
||||||
} else {
|
|
||||||
import_name = expect_token_after(f, Token_Identifier, "`as` for import declaration");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (str_eq(import_name.string, str_lit("_"))) {
|
|
||||||
syntax_error(token, "Illegal import name: `_`");
|
|
||||||
return make_bad_decl(f, token, f->curr_token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f->curr_proc != NULL) {
|
|
||||||
syntax_error(token, "You cannot use #import within a procedure. This must be done at the file scope");
|
|
||||||
return make_bad_decl(f, token, file_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return make_import_decl(f, s->TagStmt.token, file_path, import_name, os, arch, false);
|
|
||||||
} else if (str_eq(tag, str_lit("load"))) {
|
|
||||||
String os = {0};
|
|
||||||
String arch = {0};
|
|
||||||
// TODO(bill): better error messages
|
|
||||||
Token file_path = expect_token(f, Token_String);
|
|
||||||
Token import_name = file_path;
|
|
||||||
import_name.string = str_lit(".");
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (f->curr_proc == NULL) {
|
|
||||||
return make_import_decl(f, s->TagStmt.token, file_path, import_name, os, arch, true);
|
|
||||||
}
|
|
||||||
syntax_error(token, "You cannot use #load within a procedure. This must be done at the file scope");
|
|
||||||
return make_bad_decl(f, token, file_path);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s->TagStmt.stmt = parse_stmt(f); // TODO(bill): Find out why this doesn't work as an argument
|
return make_tag_stmt(f, hash_token, name, parse_stmt(f));
|
||||||
return s;
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Token_OpenBrace:
|
case Token_OpenBrace:
|
||||||
@@ -3016,7 +3043,6 @@ void destroy_ast_file(AstFile *f) {
|
|||||||
bool init_parser(Parser *p) {
|
bool init_parser(Parser *p) {
|
||||||
array_init(&p->files, heap_allocator());
|
array_init(&p->files, heap_allocator());
|
||||||
array_init(&p->imports, heap_allocator());
|
array_init(&p->imports, heap_allocator());
|
||||||
array_init(&p->foreign_libraries, heap_allocator());
|
|
||||||
gb_mutex_init(&p->mutex);
|
gb_mutex_init(&p->mutex);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -3033,7 +3059,6 @@ void destroy_parser(Parser *p) {
|
|||||||
#endif
|
#endif
|
||||||
array_free(&p->files);
|
array_free(&p->files);
|
||||||
array_free(&p->imports);
|
array_free(&p->imports);
|
||||||
array_free(&p->foreign_libraries);
|
|
||||||
gb_mutex_destroy(&p->mutex);
|
gb_mutex_destroy(&p->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3169,43 +3194,21 @@ String get_filepath_extension(String path) {
|
|||||||
return make_string(path.text, dot);
|
return make_string(path.text, dot);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray decls);
|
|
||||||
|
|
||||||
void parse_setup_file_when_stmt(Parser *p, AstFile *f, String base_dir, AstNodeWhenStmt *ws) {
|
|
||||||
if (ws->body != NULL && ws->body->kind == AstNode_BlockStmt) {
|
|
||||||
parse_setup_file_decls(p, f, base_dir, ws->body->BlockStmt.stmts);
|
|
||||||
}
|
|
||||||
if (ws->else_stmt) {
|
|
||||||
switch (ws->else_stmt->kind) {
|
|
||||||
case AstNode_BlockStmt:
|
|
||||||
parse_setup_file_decls(p, f, base_dir, ws->else_stmt->BlockStmt.stmts);
|
|
||||||
break;
|
|
||||||
case AstNode_WhenStmt:
|
|
||||||
parse_setup_file_when_stmt(p, f, base_dir, &ws->else_stmt->WhenStmt);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray decls) {
|
void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray decls) {
|
||||||
for_array(i, decls) {
|
for_array(i, decls) {
|
||||||
AstNode *node = decls.e[i];
|
AstNode *node = decls.e[i];
|
||||||
|
|
||||||
if (!is_ast_node_decl(node) &&
|
if (!is_ast_node_decl(node) &&
|
||||||
!is_ast_node_when_stmt(node) &&
|
|
||||||
node->kind != AstNode_BadStmt &&
|
node->kind != AstNode_BadStmt &&
|
||||||
node->kind != AstNode_EmptyStmt) {
|
node->kind != AstNode_EmptyStmt) {
|
||||||
// NOTE(bill): Sanity check
|
// NOTE(bill): Sanity check
|
||||||
syntax_error_node(node, "Only declarations are allowed at file scope %.*s", LIT(ast_node_strings[node->kind]));
|
syntax_error_node(node, "Only declarations are allowed at file scope %.*s", LIT(ast_node_strings[node->kind]));
|
||||||
} else if (node->kind == AstNode_WhenStmt) {
|
|
||||||
parse_setup_file_when_stmt(p, f, base_dir, &node->WhenStmt);
|
|
||||||
} else if (node->kind == AstNode_ImportDecl) {
|
} else if (node->kind == AstNode_ImportDecl) {
|
||||||
AstNodeImportDecl *id = &node->ImportDecl;
|
AstNodeImportDecl *id = &node->ImportDecl;
|
||||||
String file_str = id->relpath.string;
|
String file_str = id->relpath.string;
|
||||||
|
|
||||||
if (!is_import_path_valid(file_str)) {
|
if (!is_import_path_valid(file_str)) {
|
||||||
if (id->is_load) {
|
if (id->is_load) {
|
||||||
syntax_error_node(node, "Invalid #load path: `%.*s`", LIT(file_str));
|
syntax_error_node(node, "Invalid #include path: `%.*s`", LIT(file_str));
|
||||||
} else {
|
} else {
|
||||||
syntax_error_node(node, "Invalid #import path: `%.*s`", LIT(file_str));
|
syntax_error_node(node, "Invalid #import path: `%.*s`", LIT(file_str));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ typedef struct ssaModule {
|
|||||||
String layout;
|
String layout;
|
||||||
// String triple;
|
// String triple;
|
||||||
|
|
||||||
|
|
||||||
MapEntity min_dep_map; // Key: Entity *
|
MapEntity min_dep_map; // Key: Entity *
|
||||||
MapSsaValue values; // Key: Entity *
|
MapSsaValue values; // Key: Entity *
|
||||||
MapSsaValue members; // Key: String
|
MapSsaValue members; // Key: String
|
||||||
@@ -192,6 +191,11 @@ struct ssaProcedure {
|
|||||||
}) \
|
}) \
|
||||||
SSA_INSTR_KIND(Phi, struct { ssaValueArray edges; Type *type; }) \
|
SSA_INSTR_KIND(Phi, struct { ssaValueArray edges; Type *type; }) \
|
||||||
SSA_INSTR_KIND(Unreachable, i32) \
|
SSA_INSTR_KIND(Unreachable, i32) \
|
||||||
|
SSA_INSTR_KIND(UnaryOp, struct { \
|
||||||
|
Type * type; \
|
||||||
|
TokenKind op; \
|
||||||
|
ssaValue *expr; \
|
||||||
|
}) \
|
||||||
SSA_INSTR_KIND(BinaryOp, struct { \
|
SSA_INSTR_KIND(BinaryOp, struct { \
|
||||||
Type * type; \
|
Type * type; \
|
||||||
TokenKind op; \
|
TokenKind op; \
|
||||||
@@ -560,6 +564,8 @@ Type *ssa_instr_type(ssaInstr *instr) {
|
|||||||
return instr->UnionTagPtr.type;
|
return instr->UnionTagPtr.type;
|
||||||
case ssaInstr_UnionTagValue:
|
case ssaInstr_UnionTagValue:
|
||||||
return instr->UnionTagValue.type;
|
return instr->UnionTagValue.type;
|
||||||
|
case ssaInstr_UnaryOp:
|
||||||
|
return instr->UnaryOp.type;
|
||||||
case ssaInstr_BinaryOp:
|
case ssaInstr_BinaryOp:
|
||||||
return instr->BinaryOp.type;
|
return instr->BinaryOp.type;
|
||||||
case ssaInstr_Conv:
|
case ssaInstr_Conv:
|
||||||
@@ -887,6 +893,15 @@ ssaValue *ssa_make_instr_union_tag_value(ssaProcedure *p, ssaValue *address) {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssaValue *ssa_make_instr_unary_op(ssaProcedure *p, TokenKind op, ssaValue *expr, Type *type) {
|
||||||
|
ssaValue *v = ssa_alloc_instr(p, ssaInstr_UnaryOp);
|
||||||
|
ssaInstr *i = &v->Instr;
|
||||||
|
i->UnaryOp.op = op;
|
||||||
|
i->UnaryOp.expr = expr;
|
||||||
|
i->UnaryOp.type = type;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ssaValue *ssa_make_instr_binary_op(ssaProcedure *p, TokenKind op, ssaValue *left, ssaValue *right, Type *type) {
|
ssaValue *ssa_make_instr_binary_op(ssaProcedure *p, TokenKind op, ssaValue *left, ssaValue *right, Type *type) {
|
||||||
ssaValue *v = ssa_alloc_instr(p, ssaInstr_BinaryOp);
|
ssaValue *v = ssa_alloc_instr(p, ssaInstr_BinaryOp);
|
||||||
@@ -2619,18 +2634,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
|||||||
case Token_Add:
|
case Token_Add:
|
||||||
return ssa_build_expr(proc, ue->expr);
|
return ssa_build_expr(proc, ue->expr);
|
||||||
|
|
||||||
case Token_Sub: // NOTE(bill): -`x` == 0 - `x`
|
case Token_Not: // Boolean not
|
||||||
return ssa_emit_arith(proc, ue->op.kind, v_zero, ssa_build_expr(proc, ue->expr), tv->type);
|
case Token_Xor: // Bitwise not
|
||||||
|
case Token_Sub: // Bitwise not
|
||||||
case Token_Not: // Boolean not
|
return ssa_emit(proc, ssa_make_instr_unary_op(proc, ue->op.kind, ssa_build_expr(proc, ue->expr), tv->type));
|
||||||
case Token_Xor: { // Bitwise not
|
|
||||||
// NOTE(bill): "not" `x` == `x` "xor" `-1`
|
|
||||||
ssaValue *left = ssa_build_expr(proc, ue->expr);
|
|
||||||
ssaValue *right = ssa_add_module_constant(proc->module, tv->type, make_exact_value_integer(-1));
|
|
||||||
return ssa_emit_arith(proc, ue->op.kind,
|
|
||||||
left, right,
|
|
||||||
tv->type);
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
|||||||
+49
-1
@@ -866,6 +866,55 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
|
|||||||
ssa_fprintf(f, "unreachable\n");
|
ssa_fprintf(f, "unreachable\n");
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case ssaInstr_UnaryOp: {
|
||||||
|
ssaInstrUnaryOp *uo = &value->Instr.UnaryOp;
|
||||||
|
Type *type = base_type(ssa_type(uo->expr));
|
||||||
|
Type *elem_type = type;
|
||||||
|
while (elem_type->kind == Type_Vector) {
|
||||||
|
elem_type = base_type(elem_type->Vector.elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssa_fprintf(f, "%%%d = ", value->index);
|
||||||
|
switch (uo->op) {
|
||||||
|
case Token_Sub:
|
||||||
|
if (is_type_float(elem_type)) {
|
||||||
|
ssa_fprintf(f, "fsub");
|
||||||
|
} else {
|
||||||
|
ssa_fprintf(f, "sub");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Token_Xor:
|
||||||
|
case Token_Not:
|
||||||
|
GB_ASSERT(is_type_integer(type) || is_type_boolean(type));
|
||||||
|
ssa_fprintf(f, "xor");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GB_PANIC("Unknown unary operator");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssa_fprintf(f, " ");
|
||||||
|
ssa_print_type(f, m, type);
|
||||||
|
ssa_fprintf(f, " ");
|
||||||
|
switch (uo->op) {
|
||||||
|
case Token_Sub:
|
||||||
|
if (is_type_float(elem_type)) {
|
||||||
|
ssa_print_exact_value(f, m, make_exact_value_float(0), type);
|
||||||
|
} else {
|
||||||
|
ssa_fprintf(f, "0");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Token_Xor:
|
||||||
|
case Token_Not:
|
||||||
|
GB_ASSERT(is_type_integer(type) || is_type_boolean(type));
|
||||||
|
ssa_fprintf(f, "-1");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ssa_fprintf(f, ", ");
|
||||||
|
ssa_print_value(f, m, uo->expr, type);
|
||||||
|
ssa_fprintf(f, "\n");
|
||||||
|
} break;
|
||||||
|
|
||||||
case ssaInstr_BinaryOp: {
|
case ssaInstr_BinaryOp: {
|
||||||
ssaInstrBinaryOp *bo = &value->Instr.BinaryOp;
|
ssaInstrBinaryOp *bo = &value->Instr.BinaryOp;
|
||||||
Type *type = base_type(ssa_type(bo->left));
|
Type *type = base_type(ssa_type(bo->left));
|
||||||
@@ -971,7 +1020,6 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
|
|||||||
ssa_fprintf(f, ", ");
|
ssa_fprintf(f, ", ");
|
||||||
ssa_print_value(f, m, bo->right, type);
|
ssa_print_value(f, m, bo->right, type);
|
||||||
ssa_fprintf(f, "\n");
|
ssa_fprintf(f, "\n");
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case ssaInstr_Call: {
|
case ssaInstr_Call: {
|
||||||
|
|||||||
+2
-2
@@ -83,8 +83,8 @@ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
|
|||||||
\
|
\
|
||||||
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||||
TOKEN_KIND(Token_type, "type"), \
|
TOKEN_KIND(Token_type, "type"), \
|
||||||
/* TOKEN_KIND(Token_import, "import"), */ \
|
/* TOKEN_KIND(Token_import, "import"), */\
|
||||||
/* TOKEN_KIND(Token_include, "include"), */ \
|
/* TOKEN_KIND(Token_include, "include"), */\
|
||||||
TOKEN_KIND(Token_proc, "proc"), \
|
TOKEN_KIND(Token_proc, "proc"), \
|
||||||
TOKEN_KIND(Token_match, "match"), \
|
TOKEN_KIND(Token_match, "match"), \
|
||||||
TOKEN_KIND(Token_break, "break"), \
|
TOKEN_KIND(Token_break, "break"), \
|
||||||
|
|||||||
Reference in New Issue
Block a user