Go/BCPL style semicolon insertion during tokenizing stage

This commit is contained in:
Ginger Bill
2016-12-05 23:39:26 +00:00
parent 88aa74bbb9
commit a16bdb215a
18 changed files with 3025 additions and 2906 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ if %release_mode% EQU 0 ( rem Debug
) )
set compiler_warnings= ^ set compiler_warnings= ^
-we4002 -we4013 -we4020 -we4024 -we4029 -we4031 -we4047 -we4133 -we4706 ^ -we4002 -we4013 -we4020 -we4024 -we4029 -we4031 -we4047 -we4133 -we4706 -we4715 ^
-wd4100 -wd4101 -wd4127 -wd4189 ^ -wd4100 -wd4101 -wd4127 -wd4189 ^
-wd4201 -wd4204 -wd4244 ^ -wd4201 -wd4204 -wd4244 ^
-wd4306 ^ -wd4306 ^
+4 -14
View File
@@ -1,18 +1,8 @@
#import "fmt.odin"; #import "fmt.odin"
A :: type struct {
b: B;
};
B :: type struct {
c: C;
};
C :: type struct {
a: A;
};
main :: proc() { main :: proc() {
fmt.println(size_of(A)); if true {
fmt.println(size_of(B));
fmt.println(size_of(C)); }
} }
+73 -73
View File
@@ -1,10 +1,10 @@
#import "fmt.odin"; #import "fmt.odin"
#foreign_system_library "Ws2_32" when ODIN_OS == "windows"; #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 != nil); 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 = nil; 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(nil, 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, nil, 0); 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)
} }
+145 -145
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 :: "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,77 +272,77 @@ 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
} }
if is_key_down(Key_Code.CONTROL) { if is_key_down(Key_Code.CONTROL) {
mods |= Key.MOD_CONTROL as u32; mods |= Key.MOD_CONTROL as u32
} }
if is_key_down(Key_Code.MENU) { if is_key_down(Key_Code.MENU) {
mods |= Key.MOD_ALT as u32; mods |= Key.MOD_ALT as u32
} }
if is_key_down(Key_Code.LWIN) || is_key_down(Key_Code.RWIN) { if is_key_down(Key_Code.LWIN) || is_key_down(Key_Code.RWIN) {
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)
} }
@@ -354,26 +354,26 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
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 {
fmt.fprintln(os.stderr, "RegisterClassExA failed");
return;
} }
screen_width := GetSystemMetrics(SM_CXSCREEN); if RegisterClassExA(^window_class) == 0 {
screen_height := GetSystemMetrics(SM_CYSCREEN); fmt.fprintln(os.stderr, "RegisterClassExA failed")
return
}
rc: RECT; screen_width := GetSystemMetrics(SM_CXSCREEN)
rc.left = (screen_width - WINDOW_WIDTH) / 2; screen_height := GetSystemMetrics(SM_CYSCREEN)
rc.top = (screen_height - WINDOW_HEIGHT) / 2;
rc.right = rc.left + WINDOW_WIDTH;
rc.bottom = rc.top + WINDOW_HEIGHT;
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; rc: RECT
assert(AdjustWindowRect(^rc, style, 0) != 0); rc.left = (screen_width - WINDOW_WIDTH) / 2
rc.top = (screen_height - WINDOW_HEIGHT) / 2
rc.right = rc.left + WINDOW_WIDTH
rc.bottom = rc.top + WINDOW_HEIGHT
wt := WINDOW_TITLE; style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
assert(AdjustWindowRect(^rc, style, 0) != 0)
wt := WINDOW_TITLE
win32_window := CreateWindowExA(0, win32_window := CreateWindowExA(0,
window_class.class_name, window_class.class_name,
@@ -382,101 +382,101 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
rc.left, rc.top, rc.left, rc.top,
rc.right-rc.left, rc.bottom-rc.top, rc.right-rc.left, rc.bottom-rc.top,
nil, nil, window_class.instance, nil, nil, window_class.instance,
nil); nil)
if win32_window == nil { 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 != nil); 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
} }
} }
_core.key_deltas = nil; _core.key_deltas = nil
for PeekMessageA(^message, nil, 0, 0, PM_REMOVE) != 0 { for PeekMessageA(^message, nil, 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,
0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE, 0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
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++
} }
} }
+115 -115
View File
@@ -1,8 +1,8 @@
#shared_global_scope; #shared_global_scope
#import "os.odin"; #import "os.odin"
#import "fmt.odin"; #import "fmt.odin"
#import "mem.odin"; #import "mem.odin"
// IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a // IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a
// #shared_global_scope due to the internals of the compiler. // #shared_global_scope due to the internals of the compiler.
@@ -15,78 +15,78 @@
Type_Info :: union { Type_Info :: union {
Member :: type struct #ordered { Member :: type 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
} }
@@ -126,147 +126,147 @@ Allocator :: struct #ordered {
old_memory: rawptr, old_size: int, flags: u64) -> rawptr old_memory: rawptr, old_size: int, flags: u64) -> rawptr
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 { 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 { } 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,
}; }
} }
@@ -281,16 +281,16 @@ 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); }
@@ -302,37 +302,37 @@ __string_ge :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) >=
__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 {
@@ -341,11 +341,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 ""
} }
+81 -81
View File
@@ -1,156 +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
} }
+266 -263
View File
@@ -1,592 +1,595 @@
#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]
bprint_type(^buf, info); bprint_type(^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.data, n); mem.copy(buf.data + buf.count, b.data, n)
buf.count += n; buf.count += n
} }
} }
} }
bprint_string :: proc(buf: ^[]byte, s: string) { bprint_string :: 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]
} }
} }
bprint_rune :: proc(buf: ^[]byte, r: rune) { bprint_rune :: proc(buf: ^[]byte, r: rune) {
b, n := utf8.encode_rune(r); b, n := utf8.encode_rune(r)
bprint_string(buf, b[:n] as string); bprint_string(buf, b[:n] as string)
} }
bprint_space :: proc(buf: ^[]byte) { bprint_rune(buf, ' '); } bprint_space :: proc(buf: ^[]byte) { bprint_rune(buf, ' '); }
bprint_nl :: proc(buf: ^[]byte) { bprint_rune(buf, '\n'); } bprint_nl :: proc(buf: ^[]byte) { bprint_rune(buf, '\n'); }
__NUM_TO_CHAR_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"; __NUM_TO_CHAR_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"
bprint_bool :: proc(buffer: ^[]byte, b : bool) { bprint_bool :: proc(buffer: ^[]byte, b : bool) {
if b { bprint_string(buffer, "true"); } if b {
else { bprint_string(buffer, "false"); } bprint_string(buffer, "true")
} else {
bprint_string(buffer, "false")
}
} }
bprint_pointer :: proc(buffer: ^[]byte, p: rawptr) #inline { bprint_pointer :: proc(buffer: ^[]byte, p: rawptr) #inline {
bprint_string(buffer, "0x"); bprint_string(buffer, "0x")
bprint_u64(buffer, p as uint as u64); bprint_u64(buffer, p as uint as u64)
} }
bprint_f16 :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 4); } bprint_f16 :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 4); }
bprint_f32 :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7); } bprint_f32 :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7); }
bprint_f64 :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f as f64, 16); } bprint_f64 :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f as f64, 16); }
bprint_u64 :: proc(buffer: ^[]byte, value: u64) { bprint_u64 :: 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])
bprint_string(buffer, buf[:len] as string); bprint_string(buffer, buf[:len] as string)
} }
bprint_i64 :: proc(buffer: ^[]byte, value: i64) { bprint_i64 :: proc(buffer: ^[]byte, value: i64) {
// TODO(bill): Cleanup printing // TODO(bill): Cleanup printing
i := value; i := value
if i < 0 { if i < 0 {
i = -i; i = -i
bprint_rune(buffer, '-'); bprint_rune(buffer, '-')
} }
bprint_u64(buffer, i as u64); bprint_u64(buffer, i as u64)
} }
bprint_u128 :: proc(buffer: ^[]byte, value: u128) { bprint_u128 :: proc(buffer: ^[]byte, value: u128) {
a := value transmute [2]u64; a := value transmute [2]u64
if a[1] != 0 { if a[1] != 0 {
bprint_u64(buffer, a[1]); bprint_u64(buffer, a[1])
} }
bprint_u64(buffer, a[0]); bprint_u64(buffer, a[0])
} }
bprint_i128 :: proc(buffer: ^[]byte, value: i128) { bprint_i128 :: proc(buffer: ^[]byte, value: i128) {
i := value; i := value
if i < 0 { if i < 0 {
i = -i; i = -i
bprint_rune(buffer, '-'); bprint_rune(buffer, '-')
} }
bprint_u128(buffer, i as u128); bprint_u128(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 {
bprint_rune(buffer, '0'); bprint_rune(buffer, '0')
return; return
} }
if f < 0 { if f < 0 {
bprint_rune(buffer, '-'); bprint_rune(buffer, '-')
f = -f; f = -f
} }
i := f as u64; i := f as u64
bprint_u64(buffer, i); bprint_u64(buffer, i)
f -= i as f64; f -= i as f64
bprint_rune(buffer, '.'); bprint_rune(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
bprint_u64(buffer, i as u64); bprint_u64(buffer, i as u64)
f -= i as f64 / mult; f -= i as f64 / mult
mult *= 10; mult *= 10
} }
} }
bprint_type :: proc(buf: ^[]byte, ti: ^Type_Info) { bprint_type :: proc(buf: ^[]byte, ti: ^Type_Info) {
if ti == nil { if ti == nil {
return; return
} }
using Type_Info; using Type_Info
match type info : ti { match type info : ti {
case Named: case Named:
bprint_string(buf, info.name); bprint_string(buf, info.name)
case Integer: case Integer:
match { match {
case ti == type_info(int): case ti == type_info(int):
bprint_string(buf, "int"); bprint_string(buf, "int")
case ti == type_info(uint): case ti == type_info(uint):
bprint_string(buf, "uint"); bprint_string(buf, "uint")
default: default:
if info.signed { if info.signed {
bprint_string(buf, "i"); bprint_string(buf, "i")
} else { } else {
bprint_string(buf, "u"); bprint_string(buf, "u")
} }
bprint_u64(buf, 8*info.size as u64); bprint_u64(buf, 8*info.size as u64)
} }
case Float: case Float:
match info.size { match info.size {
case 4: bprint_string(buf, "f32"); case 4: bprint_string(buf, "f32")
case 8: bprint_string(buf, "f64"); case 8: bprint_string(buf, "f64")
} }
case String: bprint_string(buf, "string"); case String: bprint_string(buf, "string")
case Boolean: bprint_string(buf, "bool"); case Boolean: bprint_string(buf, "bool")
case Pointer: case Pointer:
if info.elem == nil { if info.elem == nil {
bprint_string(buf, "rawptr"); bprint_string(buf, "rawptr")
} else { } else {
bprint_string(buf, "^"); bprint_string(buf, "^")
bprint_type(buf, info.elem); bprint_type(buf, info.elem)
} }
case Maybe: case Maybe:
bprint_string(buf, "?"); bprint_string(buf, "?")
bprint_type(buf, info.elem); bprint_type(buf, info.elem)
case Procedure: case Procedure:
bprint_string(buf, "proc"); bprint_string(buf, "proc")
if info.params == nil { if info.params == nil {
bprint_string(buf, "()"); bprint_string(buf, "()")
} else { } else {
count := (info.params as ^Tuple).fields.count; count := (info.params as ^Tuple).fields.count
if count == 1 { bprint_string(buf, "("); } if count == 1 { bprint_string(buf, "("); }
bprint_type(buf, info.params); bprint_type(buf, info.params)
if count == 1 { bprint_string(buf, ")"); } if count == 1 { bprint_string(buf, ")"); }
} }
if info.results != nil { if info.results != nil {
bprint_string(buf, " -> "); bprint_string(buf, " -> ")
bprint_type(buf, info.results); bprint_type(buf, info.results)
} }
case Tuple: case Tuple:
count := info.fields.count; count := info.fields.count
if count != 1 { bprint_string(buf, "("); } if count != 1 { bprint_string(buf, "("); }
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
if i > 0 { bprint_string(buf, ", "); } if i > 0 { bprint_string(buf, ", "); }
f := info.fields[i]; f := info.fields[i]
if f.name.count > 0 { if f.name.count > 0 {
bprint_string(buf, f.name); bprint_string(buf, f.name)
bprint_string(buf, ": "); bprint_string(buf, ": ")
} }
bprint_type(buf, f.type_info); bprint_type(buf, f.type_info)
} }
if count != 1 { bprint_string(buf, ")"); } if count != 1 { bprint_string(buf, ")"); }
case Array: case Array:
bprint_string(buf, "["); bprint_string(buf, "[")
bprint_i64(buf, info.count as i64); bprint_i64(buf, info.count as i64)
bprint_string(buf, "]"); bprint_string(buf, "]")
bprint_type(buf, info.elem); bprint_type(buf, info.elem)
case Slice: case Slice:
bprint_string(buf, "["); bprint_string(buf, "[")
bprint_string(buf, "]"); bprint_string(buf, "]")
bprint_type(buf, info.elem); bprint_type(buf, info.elem)
case Vector: case Vector:
bprint_string(buf, "[vector "); bprint_string(buf, "[vector ")
bprint_i64(buf, info.count as i64); bprint_i64(buf, info.count as i64)
bprint_string(buf, "]"); bprint_string(buf, "]")
bprint_type(buf, info.elem); bprint_type(buf, info.elem)
case Struct: case Struct:
bprint_string(buf, "struct "); bprint_string(buf, "struct ")
if info.packed { bprint_string(buf, "#packed "); } if info.packed { bprint_string(buf, "#packed "); }
if info.ordered { bprint_string(buf, "#ordered "); } if info.ordered { bprint_string(buf, "#ordered "); }
bprint_string(buf, "{"); bprint_string(buf, "{")
for i := 0; i < info.fields.count; i++ { for i := 0; i < info.fields.count; i++ {
if i > 0 { if i > 0 {
bprint_string(buf, ", "); bprint_string(buf, ", ")
} }
bprint_any(buf, info.fields[i].name); bprint_any(buf, info.fields[i].name)
bprint_string(buf, ": "); bprint_string(buf, ": ")
bprint_type(buf, info.fields[i].type_info); bprint_type(buf, info.fields[i].type_info)
} }
bprint_string(buf, "}"); bprint_string(buf, "}")
case Union: case Union:
bprint_string(buf, "union {"); bprint_string(buf, "union {")
for i := 0; i < info.fields.count; i++ { for i := 0; i < info.fields.count; i++ {
if i > 0 { if i > 0 {
bprint_string(buf, ", "); bprint_string(buf, ", ")
} }
bprint_any(buf, info.fields[i].name); bprint_any(buf, info.fields[i].name)
bprint_string(buf, ": "); bprint_string(buf, ": ")
bprint_type(buf, info.fields[i].type_info); bprint_type(buf, info.fields[i].type_info)
} }
bprint_string(buf, "}"); bprint_string(buf, "}")
case Raw_Union: case Raw_Union:
bprint_string(buf, "raw_union {"); bprint_string(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 {
bprint_string(buf, ", "); bprint_string(buf, ", ")
} }
bprint_any(buf, info.fields[i].name); bprint_any(buf, info.fields[i].name)
bprint_string(buf, ": "); bprint_string(buf, ": ")
bprint_type(buf, info.fields[i].type_info); bprint_type(buf, info.fields[i].type_info)
} }
bprint_string(buf, "}"); bprint_string(buf, "}")
case Enum: case Enum:
bprint_string(buf, "enum "); bprint_string(buf, "enum ")
bprint_type(buf, info.base); bprint_type(buf, info.base)
bprint_string(buf, "{}"); bprint_string(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
} }
bprint_any :: proc(buf: ^[]byte, arg: any) { bprint_any :: proc(buf: ^[]byte, arg: any) {
if arg.type_info == nil { if arg.type_info == nil {
bprint_string(buf, "<nil>"); bprint_string(buf, "<nil>")
return; return
} }
if arg.data == nil { if arg.data == nil {
bprint_string(buf, "<nil>"); bprint_string(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:
bprint_string(buf, info.name); bprint_string(buf, info.name)
bprint_string(buf, "{"); bprint_string(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 {
bprint_string(buf, ", "); bprint_string(buf, ", ")
} }
bprint_string(buf, f.name); bprint_string(buf, f.name)
// bprint_any(buf, f.offset); // bprint_any(buf, f.offset)
bprint_string(buf, " = "); bprint_string(buf, " = ")
data := arg.data as ^byte + f.offset; data := arg.data as ^byte + f.offset
bprint_any(buf, make_any(f.type_info, data)); bprint_any(buf, make_any(f.type_info, data))
} }
bprint_string(buf, "}"); bprint_string(buf, "}")
default: default:
bprint_any(buf, a); bprint_any(buf, a)
} }
case Integer: case Integer:
match type i : arg { match type i : arg {
case i8: bprint_i64(buf, i as i64); case i8: bprint_i64(buf, i as i64)
case u8: bprint_u64(buf, i as u64); case u8: bprint_u64(buf, i as u64)
case i16: bprint_i64(buf, i as i64); case i16: bprint_i64(buf, i as i64)
case u16: bprint_u64(buf, i as u64); case u16: bprint_u64(buf, i as u64)
case i32: bprint_i64(buf, i as i64); case i32: bprint_i64(buf, i as i64)
case u32: bprint_u64(buf, i as u64); case u32: bprint_u64(buf, i as u64)
case i64: bprint_i64(buf, i); case i64: bprint_i64(buf, i)
case u64: bprint_u64(buf, i); case u64: bprint_u64(buf, i)
case i128: bprint_i128(buf, i); case i128: bprint_i128(buf, i)
case u128: bprint_u128(buf, i); case u128: bprint_u128(buf, i)
case int: bprint_i64(buf, i as i64); case int: bprint_i64(buf, i as i64)
case uint: bprint_u64(buf, i as u64); case uint: bprint_u64(buf, i as u64)
} }
case Float: case Float:
match type f : arg { match type f : arg {
// case f16: bprint_f64(buf, f as f64); // case f16: bprint_f64(buf, f as f64)
case f32: bprint_f32(buf, f); case f32: bprint_f32(buf, f)
case f64: bprint_f64(buf, f); case f64: bprint_f64(buf, f)
// case f128: bprint_f64(buf, f as f64); // case f128: bprint_f64(buf, f as f64)
} }
case String: case String:
match type s : arg { match type s : arg {
case string: bprint_string(buf, s); case string: bprint_string(buf, s)
} }
case Boolean: case Boolean:
match type b : arg { match type b : arg {
case bool: bprint_bool(buf, b); case bool: bprint_bool(buf, b)
} }
case Pointer: case Pointer:
match type p : arg { match type p : arg {
case ^Type_Info: bprint_type(buf, p); case ^Type_Info: bprint_type(buf, p)
default: bprint_pointer(buf, (arg.data as ^rawptr)^); default: bprint_pointer(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 {
bprint_any(buf, make_any(info.elem, arg.data)); bprint_any(buf, make_any(info.elem, arg.data))
} else { } else {
bprint_string(buf, "nil"); bprint_string(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
} }
bprint_string(buf, __enum_to_string(arg.type_info, value)); bprint_string(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 bprint_string(buf, "}"); defer bprint_string(buf, "}")
for i := 0; i < info.count; i++ { for i := 0; i < info.count; i++ {
if i > 0 { if i > 0 {
bprint_string(buf, ", "); bprint_string(buf, ", ")
} }
data := arg.data as ^byte + i*info.elem_size; data := arg.data as ^byte + i*info.elem_size
bprint_any(buf, make_any(info.elem, data)); bprint_any(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 bprint_string(buf, "}"); defer bprint_string(buf, "}")
for i := 0; i < slice.count; i++ { for i := 0; i < slice.count; i++ {
if i > 0 { if i > 0 {
bprint_string(buf, ", "); bprint_string(buf, ", ")
} }
data := slice.data + i*info.elem_size; data := slice.data + i*info.elem_size
bprint_any(buf, make_any(info.elem, data)); bprint_any(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 bprint_string(buf, "}"); defer bprint_string(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 {
bprint_string(buf, ", "); bprint_string(buf, ", ")
} }
data := arg.data as ^byte + i*info.elem_size; data := arg.data as ^byte + i*info.elem_size
bprint_any(buf, make_any(info.elem, data)); bprint_any(buf, make_any(info.elem, data))
} }
case Struct: case Struct:
bprintf(buf, "%{", arg.type_info); bprintf(buf, "%{", arg.type_info)
defer bprint_string(buf, "}"); defer bprint_string(buf, "}")
for i := 0; i < info.fields.count; i++ { for i := 0; i < info.fields.count; i++ {
if i > 0 { if i > 0 {
bprint_string(buf, ", "); bprint_string(buf, ", ")
} }
bprint_string(buf, info.fields[i].name); bprint_string(buf, info.fields[i].name)
bprint_string(buf, " = "); bprint_string(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
bprint_any(buf, make_any(ti, data)); bprint_any(buf, make_any(ti, data))
} }
case Union: case Union:
bprint_string(buf, "(union)"); bprint_string(buf, "(union)")
case Raw_Union: case Raw_Union:
bprint_string(buf, "(raw_union)"); bprint_string(buf, "(raw_union)")
case Procedure: case Procedure:
bprint_type(buf, arg.type_info); bprint_type(buf, arg.type_info)
bprint_string(buf, " @ 0x"); bprint_string(buf, " @ 0x")
bprint_pointer(buf, (arg.data as ^rawptr)^); bprint_pointer(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
} }
bprint_string(buf, fmt[prev:i]); bprint_string(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 == '%' {
bprint_string(buf, "%"); bprint_string(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 {
bprint_any(buf, args[index]); bprint_any(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
bprint_string(buf, "<invalid>"); bprint_string(buf, "<invalid>")
} }
prev = i; prev = i
} }
bprint_string(buf, fmt[prev:]); bprint_string(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 {
bprint_space(buf); bprint_space(buf)
} }
bprint_any(buf, arg); bprint_any(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, ' ')
} }
bprint_any(buf, args[i]); bprint_any(buf, args[i])
} }
bprint_nl(buf); bprint_nl(buf)
return buf.count; return buf.count
} }
+95 -95
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,
}; }
+189 -189
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 [vector 2]f32; Vec2 :: type [vector 2]f32
Vec3 :: type [vector 3]f32; Vec3 :: type [vector 3]f32
Vec4 :: type [vector 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"
@@ -47,42 +47,42 @@ 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)
} }
@@ -97,9 +97,9 @@ 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
} }
@@ -112,27 +112,27 @@ 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}
} }
@@ -143,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 {
@@ -174,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
+123 -123
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,11 +54,11 @@ 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
} }
@@ -70,42 +70,42 @@ 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 -93
View File
@@ -1,6 +1,6 @@
#foreign_system_library "opengl32" when ODIN_OS == "windows"; #foreign_system_library "opengl32" when ODIN_OS == "windows"
#import "win32.odin" when ODIN_OS == "windows"; #import "win32.odin" when ODIN_OS == "windows"
#include "opengl_constants.odin"; #include "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"
@@ -30,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
+1 -1
View File
@@ -1,2 +1,2 @@
#include "os_windows.odin" when ODIN_OS == "windows"; #include "os_windows.odin" when ODIN_OS == "windows"
+74 -74
View File
@@ -1,82 +1,82 @@
#import "win32.odin"; #import "win32.odin"
#import "fmt.odin"; #import "fmt.odin"
File_Time :: type u64 File_Time :: type u64
File :: struct { File :: struct {
Handle :: raw_union { Handle :: raw_union {
p: rawptr; p: rawptr
i: int; i: int
} }
handle: Handle; handle: Handle
last_write_time: File_Time; last_write_time: File_Time
} }
open :: proc(name: string) -> (File, bool) { open :: proc(name: string) -> (File, bool) {
using win32; using win32
buf: [300]byte; buf: [300]byte
copy(buf[:], name as []byte); copy(buf[:], name as []byte)
f: File; f: File
f.handle.p = CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, nil) as rawptr; 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; success := f.handle.p != INVALID_HANDLE_VALUE
f.last_write_time = last_write_time(^f); f.last_write_time = last_write_time(^f)
return f, success; return f, success
} }
create :: proc(name: string) -> (File, bool) { create :: proc(name: string) -> (File, bool) {
using win32; using win32
buf: [300]byte; buf: [300]byte
copy(buf[:], name as []byte); copy(buf[:], name as []byte)
f: File; f: File
f.handle.p = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_ALWAYS, 0, nil) as rawptr; 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; success := f.handle.p != INVALID_HANDLE_VALUE
f.last_write_time = last_write_time(^f); f.last_write_time = last_write_time(^f)
return f, success; return f, success
} }
close :: proc(using f: ^File) { close :: proc(using f: ^File) {
win32.CloseHandle(handle.p as win32.HANDLE); win32.CloseHandle(handle.p as win32.HANDLE)
} }
write :: proc(using f: ^File, buf: []byte) -> bool { write :: proc(using f: ^File, buf: []byte) -> bool {
bytes_written: i32; bytes_written: i32
return win32.WriteFile(handle.p as win32.HANDLE, buf.data, buf.count as i32, ^bytes_written, nil) != 0; 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 { file_has_changed :: proc(f: ^File) -> bool {
last_write_time := last_write_time(f); last_write_time := last_write_time(f)
if f.last_write_time != last_write_time { if f.last_write_time != last_write_time {
f.last_write_time = last_write_time; f.last_write_time = last_write_time
return true; return true
} }
return false; return false
} }
last_write_time :: proc(f: ^File) -> File_Time { last_write_time :: proc(f: ^File) -> File_Time {
file_info: win32.BY_HANDLE_FILE_INFORMATION; file_info: win32.BY_HANDLE_FILE_INFORMATION
win32.GetFileInformationByHandle(f.handle.p as win32.HANDLE, ^file_info); win32.GetFileInformationByHandle(f.handle.p as win32.HANDLE, ^file_info)
l := file_info.last_write_time.low_date_time as File_Time; l := file_info.last_write_time.low_date_time as File_Time
h := file_info.last_write_time.high_date_time as File_Time; h := file_info.last_write_time.high_date_time as File_Time
return l | h << 32; return l | h << 32
} }
last_write_time_by_name :: proc(name: string) -> File_Time { last_write_time_by_name :: proc(name: string) -> File_Time {
last_write_time: win32.FILETIME; last_write_time: win32.FILETIME
data: win32.WIN32_FILE_ATTRIBUTE_DATA; data: win32.WIN32_FILE_ATTRIBUTE_DATA
buf: [1024]byte; buf: [1024]byte
path := buf[:0]; path := buf[:0]
fmt.bprint(^path, name, "\x00"); fmt.bprint(^path, name, "\x00")
if win32.GetFileAttributesExA(path.data, win32.GetFileExInfoStandard, ^data) != 0 { if win32.GetFileAttributesExA(path.data, win32.GetFileExInfoStandard, ^data) != 0 {
last_write_time = data.last_write_time; last_write_time = data.last_write_time
} }
l := last_write_time.low_date_time as File_Time; l := last_write_time.low_date_time as File_Time
h := last_write_time.high_date_time as File_Time; h := last_write_time.high_date_time as File_Time
return l | h << 32; return l | h << 32
} }
@@ -93,81 +93,81 @@ __std_files := [File_Standard.count]File{
{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE) transmute File.Handle }, {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_OUTPUT_HANDLE) transmute File.Handle },
{handle = win32.GetStdHandle(win32.STD_ERROR_HANDLE) transmute File.Handle }, {handle = win32.GetStdHandle(win32.STD_ERROR_HANDLE) transmute File.Handle },
}; }
stdin := ^__std_files[File_Standard.INPUT]; stdin := ^__std_files[File_Standard.INPUT]
stdout := ^__std_files[File_Standard.OUTPUT]; stdout := ^__std_files[File_Standard.OUTPUT]
stderr := ^__std_files[File_Standard.ERROR]; stderr := ^__std_files[File_Standard.ERROR]
read_entire_file :: proc(name: string) -> ([]byte, bool) { read_entire_file :: proc(name: string) -> ([]byte, bool) {
buf: [300]byte; buf: [300]byte
copy(buf[:], name as []byte); copy(buf[:], name as []byte)
f, file_ok := open(name); f, file_ok := open(name)
if !file_ok { if !file_ok {
return nil, false; return nil, false
} }
defer close(^f); defer close(^f)
length: i64; length: i64
file_size_ok := win32.GetFileSizeEx(f.handle.p as win32.HANDLE, ^length) != 0; file_size_ok := win32.GetFileSizeEx(f.handle.p as win32.HANDLE, ^length) != 0
if !file_size_ok { if !file_size_ok {
return nil, false; return nil, false
} }
data := new_slice(u8, length); data := new_slice(u8, length)
if data.data == nil { if data.data == nil {
return nil, false; return nil, false
} }
single_read_length: i32; single_read_length: i32
total_read: i64; total_read: i64
for total_read < length { for total_read < length {
remaining := length - total_read; remaining := length - total_read
to_read: u32; to_read: u32
MAX :: 1<<32-1; MAX :: 1<<32-1
if remaining <= MAX { if remaining <= MAX {
to_read = remaining as u32; to_read = remaining as u32
} else { } else {
to_read = MAX; to_read = MAX
} }
win32.ReadFile(f.handle.p as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, nil); win32.ReadFile(f.handle.p as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, nil)
if single_read_length <= 0 { if single_read_length <= 0 {
free(data.data); free(data.data)
return nil, false; return nil, false
} }
total_read += single_read_length as i64; total_read += single_read_length as i64
} }
return data, true; return data, true
} }
heap_alloc :: proc(size: int) -> rawptr { heap_alloc :: proc(size: int) -> rawptr {
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size); return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size)
} }
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size); return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size)
} }
heap_free :: proc(ptr: rawptr) { heap_free :: proc(ptr: rawptr) {
win32.HeapFree(win32.GetProcessHeap(), 0, ptr); win32.HeapFree(win32.GetProcessHeap(), 0, ptr)
} }
exit :: proc(code: int) { exit :: proc(code: int) {
win32.ExitProcess(code as u32); win32.ExitProcess(code as u32)
} }
current_thread_id :: proc() -> int { current_thread_id :: proc() -> int {
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
return GetCurrentThreadId() as int; return GetCurrentThreadId() as int
} }
+93 -93
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
} }
+120 -120
View File
@@ -1,5 +1,5 @@
#foreign_system_library "user32" when ODIN_OS == "windows"; #foreign_system_library "user32" when ODIN_OS == "windows"
#foreign_system_library "gdi32" when ODIN_OS == "windows"; #foreign_system_library "gdi32" when ODIN_OS == "windows"
HANDLE :: type rawptr HANDLE :: type rawptr
HWND :: type HANDLE HWND :: type HANDLE
@@ -18,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
@@ -152,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
@@ -175,23 +175,23 @@ 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
@@ -203,7 +203,7 @@ HeapFree :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL
GetProcessHeap :: proc() -> HANDLE #foreign #dll_import GetProcessHeap :: proc() -> HANDLE #foreign #dll_import
HEAP_ZERO_MEMORY :: 0x00000008; HEAP_ZERO_MEMORY :: 0x00000008
@@ -211,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,
@@ -253,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()
@@ -283,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,
@@ -304,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
@@ -317,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
@@ -334,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 {
+7 -23
View File
@@ -1157,26 +1157,6 @@ bool expect_semicolon_after_stmt(AstFile *f, AstNode *s) {
return true; return true;
} }
if (s != NULL) {
switch (s->kind) {
case AstNode_ProcDecl:
case AstNode_TypeDecl:
return true;
}
}
// if (f->curr_token.pos.line != f->prev_token.pos.line) {
// return true;
// }
if (f->curr_token.pos.line == f->prev_token.pos.line) {
switch (f->curr_token.kind) {
case Token_EOF:
case Token_CloseBrace:
return true;
}
}
if (s != NULL) { if (s != NULL) {
syntax_error(f->prev_token, "Expected `;` after %.*s, got `%.*s`", syntax_error(f->prev_token, "Expected `;` after %.*s, got `%.*s`",
LIT(ast_node_strings[s->kind]), LIT(token_strings[f->prev_token.kind])); LIT(ast_node_strings[s->kind]), LIT(token_strings[f->prev_token.kind]));
@@ -2222,10 +2202,14 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) {
break; break;
} }
// fallthrough // fallthrough
default: default: {
String prev = str_lit("newline");
if (str_ne(f->prev_token.string, str_lit("\n"))) {
prev = f->prev_token.string;
}
syntax_error(f->curr_token, syntax_error(f->curr_token,
"Expected a type or identifier after `%.*s`, got `%.*s`", LIT(f->prev_token.string), LIT(f->curr_token.string)); "Expected a type or identifier after %.*s, got %.*s", LIT(prev), LIT(f->curr_token.string));
break; } break;
} }
return NULL; return NULL;
+180 -38
View File
@@ -303,6 +303,8 @@ typedef struct Tokenizer {
u8 * line; // current line pos u8 * line; // current line pos
isize line_count; isize line_count;
bool insert_semicolon; // Inserts a semicolon before the next newline
isize error_count; isize error_count;
Array(String) allocated_strings; Array(String) allocated_strings;
} Tokenizer; } Tokenizer;
@@ -413,7 +415,10 @@ gb_inline void destroy_tokenizer(Tokenizer *t) {
} }
void tokenizer_skip_whitespace(Tokenizer *t) { void tokenizer_skip_whitespace(Tokenizer *t) {
while (rune_is_whitespace(t->curr_rune)) { while (t->curr_rune == ' ' ||
t->curr_rune == '\t' ||
(t->curr_rune == '\n' && !t->insert_semicolon) ||
t->curr_rune == '\r') {
advance_to_next_rune(t); advance_to_next_rune(t);
} }
} }
@@ -617,6 +622,51 @@ gb_inline TokenKind token_kind_dub_eq(Tokenizer *t, Rune sing_rune, TokenKind si
return sing; return sing;
} }
void tokenizer__fle_update(Tokenizer *t) {
t->curr_rune = '/';
t->curr = t->curr-1;
t->read_curr = t->curr+1;
advance_to_next_rune(t);
}
// NOTE(bill): needed if comment is straight after a "semicolon"
bool tokenizer_find_line_end(Tokenizer *t) {
while (t->curr_rune == '/' || t->curr_rune == '*') {
if (t->curr_rune == '/') {
tokenizer__fle_update(t);
return true;
}
advance_to_next_rune(t);
while (t->curr_rune >= 0) {
Rune r = t->curr_rune;
if (r == '\n') {
tokenizer__fle_update(t);
return true;
}
advance_to_next_rune(t);
if (r == '*' && t->curr_rune == '/') {
advance_to_next_rune(t);
break;
}
}
tokenizer_skip_whitespace(t);
if (t->curr_rune < 0 || t->curr_rune == '\n') {
tokenizer__fle_update(t);
return true;
}
if (t->curr_rune != '/') {
tokenizer__fle_update(t);
return false;
}
advance_to_next_rune(t);
}
tokenizer__fle_update(t);
return false;
}
Token tokenizer_get_token(Tokenizer *t) { Token tokenizer_get_token(Tokenizer *t) {
Token token = {0}; Token token = {0};
Rune curr_rune; Rune curr_rune;
@@ -627,6 +677,8 @@ Token tokenizer_get_token(Tokenizer *t) {
token.pos.line = t->line_count; token.pos.line = t->line_count;
token.pos.column = t->curr - t->line + 1; token.pos.column = t->curr - t->line + 1;
bool insert_semicolon = false;
curr_rune = t->curr_rune; curr_rune = t->curr_rune;
if (rune_is_letter(curr_rune)) { if (rune_is_letter(curr_rune)) {
token.kind = Token_Ident; token.kind = Token_Ident;
@@ -654,19 +706,48 @@ Token tokenizer_get_token(Tokenizer *t) {
} }
} }
} }
switch (token.kind) {
case Token_Ident:
case Token_return:
case Token_break:
case Token_continue:
case Token_fallthrough:
insert_semicolon = true;
break;
}
} else {
insert_semicolon = true;
} }
} else if (gb_is_between(curr_rune, '0', '9')) { } else if (gb_is_between(curr_rune, '0', '9')) {
insert_semicolon = true;
token = scan_number_to_token(t, false); token = scan_number_to_token(t, false);
} else { } else {
advance_to_next_rune(t); advance_to_next_rune(t);
switch (curr_rune) { switch (curr_rune) {
case GB_RUNE_EOF: case GB_RUNE_EOF:
if (t->insert_semicolon) {
t->insert_semicolon = false;
token.string = str_lit("\n");
token.kind = Token_Semicolon;
return token;
}
token.kind = Token_EOF; token.kind = Token_EOF;
break; break;
case '\n':
// NOTE(bill): This will be only be reached if t->insert_semicolom was set
// earlier and exited early from tokenizer_skip_whitespace()
t->insert_semicolon = false;
token.string = str_lit("\n");
token.kind = Token_Semicolon;
return token;
case '\'': // Rune Literal case '\'': // Rune Literal
{ {
insert_semicolon = true;
token.kind = Token_Rune; token.kind = Token_Rune;
Rune quote = curr_rune; Rune quote = curr_rune;
bool valid = true; bool valid = true;
@@ -699,6 +780,7 @@ Token tokenizer_get_token(Tokenizer *t) {
if (success == 2) { if (success == 2) {
array_add(&t->allocated_strings, token.string); array_add(&t->allocated_strings, token.string);
} }
t->insert_semicolon = true;
return token; return token;
} else { } else {
tokenizer_err(t, "Invalid rune literal"); tokenizer_err(t, "Invalid rune literal");
@@ -708,6 +790,8 @@ Token tokenizer_get_token(Tokenizer *t) {
case '`': // Raw String Literal case '`': // Raw String Literal
case '"': // String Literal case '"': // String Literal
{ {
insert_semicolon = true;
i32 success; i32 success;
Rune quote = curr_rune; Rune quote = curr_rune;
token.kind = Token_String; token.kind = Token_String;
@@ -745,6 +829,7 @@ Token tokenizer_get_token(Tokenizer *t) {
if (success == 2) { if (success == 2) {
array_add(&t->allocated_strings, token.string); array_add(&t->allocated_strings, token.string);
} }
t->insert_semicolon = true;
return token; return token;
} else { } else {
tokenizer_err(t, "Invalid string literal"); tokenizer_err(t, "Invalid string literal");
@@ -754,6 +839,7 @@ Token tokenizer_get_token(Tokenizer *t) {
case '.': case '.':
token.kind = Token_Period; // Default token.kind = Token_Period; // Default
if (gb_is_between(t->curr_rune, '0', '9')) { // Might be a number if (gb_is_between(t->curr_rune, '0', '9')) { // Might be a number
insert_semicolon = true;
token = scan_number_to_token(t, true); token = scan_number_to_token(t, true);
} else if (t->curr_rune == '.') { // Could be an ellipsis } else if (t->curr_rune == '.') { // Could be an ellipsis
advance_to_next_rune(t); advance_to_next_rune(t);
@@ -765,54 +851,107 @@ Token tokenizer_get_token(Tokenizer *t) {
} }
break; break;
case '#': token.kind = Token_Hash; break; case '#':
case '@': token.kind = Token_At; break; token.kind = Token_Hash;
case '^': token.kind = Token_Pointer; break; break;
case '?': token.kind = Token_Maybe; break; case '@':
case ';': token.kind = Token_Semicolon; break; token.kind = Token_At;
case ',': token.kind = Token_Comma; break; break;
case '(': token.kind = Token_OpenParen; break; case '^':
case ')': token.kind = Token_CloseParen; break; token.kind = Token_Pointer;
case '[': token.kind = Token_OpenBracket; break; break;
case ']': token.kind = Token_CloseBracket; break; case '?':
case '{': token.kind = Token_OpenBrace; break; token.kind = Token_Maybe;
case '}': token.kind = Token_CloseBrace; break; break;
case ':': token.kind = Token_Colon; break; case ';':
token.kind = Token_Semicolon;
token.string = str_lit(";");
break;
case ',':
token.kind = Token_Comma;
break;
case ':':
token.kind = Token_Colon;
break;
case '(':
token.kind = Token_OpenParen;
break;
case ')':
insert_semicolon = true;
token.kind = Token_CloseParen;
break;
case '[':
token.kind = Token_OpenBracket;
break;
case ']':
insert_semicolon = true;
token.kind = Token_CloseBracket;
break;
case '{':
token.kind = Token_OpenBrace;
break;
case '}':
insert_semicolon = true;
token.kind = Token_CloseBrace;
break;
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break; case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break; case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break;
case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break; case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break;
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break; case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break; case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Increment); break; case '+':
case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Decrement, '>', Token_ArrowRight); break; token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Increment);
if (token.kind == Token_Increment) {
insert_semicolon = true;
}
break;
case '-':
token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Decrement, '>', Token_ArrowRight);
if (token.kind == Token_Decrement) {
insert_semicolon = true;
}
break;
case '/': { case '/': {
if (t->curr_rune == '/') { if (t->curr_rune == '/' || t->curr_rune == '*') {
while (t->curr_rune != '\n') { if (t->insert_semicolon && tokenizer_find_line_end(t)) {
advance_to_next_rune(t); t->curr_rune = '/';
t->curr = token.string.text;
t->read_curr = t->curr+1;
t->insert_semicolon = false;
token.kind = Token_Semicolon;
token.string = str_lit("\n");
return token;
} }
token.kind = Token_Comment;
} else if (t->curr_rune == '*') { if (t->curr_rune == '/') {
isize comment_scope = 1; while (t->curr_rune != '\n') {
advance_to_next_rune(t);
while (comment_scope > 0) {
if (t->curr_rune == '/') {
advance_to_next_rune(t);
if (t->curr_rune == '*') {
advance_to_next_rune(t);
comment_scope++;
}
} else if (t->curr_rune == '*') {
advance_to_next_rune(t);
if (t->curr_rune == '/') {
advance_to_next_rune(t);
comment_scope--;
}
} else {
advance_to_next_rune(t); advance_to_next_rune(t);
} }
token.kind = Token_Comment;
} else if (t->curr_rune == '*') {
isize comment_scope = 1;
advance_to_next_rune(t);
while (comment_scope > 0) {
if (t->curr_rune == '/') {
advance_to_next_rune(t);
if (t->curr_rune == '*') {
advance_to_next_rune(t);
comment_scope++;
}
} else if (t->curr_rune == '*') {
advance_to_next_rune(t);
if (t->curr_rune == '/') {
advance_to_next_rune(t);
comment_scope--;
}
} else {
advance_to_next_rune(t);
}
}
token.kind = Token_Comment;
} }
token.kind = Token_Comment;
} else { } else {
token.kind = token_kind_variant2(t, Token_Quo, Token_QuoEq); token.kind = token_kind_variant2(t, Token_Quo, Token_QuoEq);
} }
@@ -851,11 +990,14 @@ Token tokenizer_get_token(Tokenizer *t) {
int len = cast(int)gb_utf8_encode_rune(str, curr_rune); int len = cast(int)gb_utf8_encode_rune(str, curr_rune);
tokenizer_err(t, "Illegal character: %.*s (%d) ", len, str, curr_rune); tokenizer_err(t, "Illegal character: %.*s (%d) ", len, str, curr_rune);
} }
insert_semicolon = t->insert_semicolon;
token.kind = Token_Invalid; token.kind = Token_Invalid;
break; break;
} }
} }
t->insert_semicolon = insert_semicolon;
token.string.len = t->curr - token.string.text; token.string.len = t->curr - token.string.text;
return token; return token;
} }