Semicolons are required; when condition for certain file scope declarations; #import syntax change

This commit is contained in:
Ginger Bill
2016-12-01 22:44:00 +00:00
parent be8b9bda2f
commit 4bb45700a5
29 changed files with 3400 additions and 3244 deletions
+2 -30
View File
@@ -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
View File
@@ -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
View File
@@ -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);
} }
+1 -1
View File
@@ -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
+3 -3
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -28,7 +28,7 @@ thing :: proc() {
*/ */
/* /*
#load "fmt.odin" #include "fmt.odin"
thing :: proc() { thing :: proc() {
println("Hello5!") println("Hello5!")
+147 -169
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+2 -3
View File
@@ -1,3 +1,2 @@
when ODIN_OS == "windows" { #include "os_windows.odin" when ODIN_OS == "windows";
#load "os_windows.odin"
}
+173
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
} }
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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));
} }
+20 -13
View File
@@ -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
View File
@@ -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
View File
@@ -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"), \