mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-12 06:11:26 -07:00
Compare commits
137 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 284a9cd4c3 | |||
| 5955c101d4 | |||
| f80b910ba3 | |||
| 2b0521347b | |||
| 0c06a8d154 | |||
| b0e3a4e276 | |||
| b651466630 | |||
| 24c09c9201 | |||
| e48346a9ee | |||
| 9bd8bdaa5a | |||
| a137699d95 | |||
| f6a56c2f82 | |||
| dffa791607 | |||
| 5ce6555721 | |||
| 53b3ad186f | |||
| 82c1c5b3fe | |||
| 6d880bc3bb | |||
| 40281d595d | |||
| 85fab55e57 | |||
| 1d2eb8055e | |||
| 9e0b69312b | |||
| bbddbba340 | |||
| 0d01a6f552 | |||
| ae3672608d | |||
| e5c39fb2a9 | |||
| eb4b3f5976 | |||
| dbb070524f | |||
| 36b0b50ba4 | |||
| ac46b2053d | |||
| 0ffcccdae5 | |||
| 4777bd607e | |||
| 39e9b50482 | |||
| 30adb9c770 | |||
| b1d1497f4b | |||
| 9df3a94d33 | |||
| d4f335d068 | |||
| 74341b9b74 | |||
| 66ee2cb6ed | |||
| 1d4881cbbe | |||
| 04b917a60a | |||
| e6c99cd289 | |||
| 6bc5584add | |||
| 121f0185d6 | |||
| e7999f8450 | |||
| 0b29e42adb | |||
| fcc8b89e6b | |||
| 529d1c78c7 | |||
| 414486829a | |||
| 3e05be8eb8 | |||
| ae24a8e5ae | |||
| d2588f9d1d | |||
| 1eb9994d88 | |||
| a43b89f36e | |||
| 0ed34af19d | |||
| 71729c2855 | |||
| 6c8c430c2a | |||
| 57b97ad0bd | |||
| 56f7a859df | |||
| e5e14b9947 | |||
| 3d8bf36a30 | |||
| 85f7c2d040 | |||
| 26ea8f6dcb | |||
| e05fe1837d | |||
| 94762b56f6 | |||
| b3b688fa50 | |||
| 5eaa8de8f9 | |||
| 26d3c54aff | |||
| 349a62121c | |||
| bbb0e14633 | |||
| 42312d9def | |||
| 065d0e4ee3 | |||
| b772ad7094 | |||
| 444d366c39 | |||
| 8e4233b86a | |||
| 6424966b7a | |||
| 4e42d7df43 | |||
| 580ee5cc4a | |||
| 56a98a483f | |||
| df7a4eda8a | |||
| 91cc0b282a | |||
| 01d8aea4df | |||
| ee904060c5 | |||
| afb5538e83 | |||
| 1f24f105cc | |||
| 8f39ebbe5a | |||
| c1e720a49b | |||
| f38c8875b2 | |||
| e7e51f53ce | |||
| 5259de5872 | |||
| e2b9c87aa8 | |||
| 8c7cf0dbb0 | |||
| e6e9375b09 | |||
| c6096f9205 | |||
| 11614c2649 | |||
| 793bc8c585 | |||
| 335e88b738 | |||
| b77ea94976 | |||
| ae17a51c0d | |||
| ee7a83f124 | |||
| 67ac551a2f | |||
| 572ac616c1 | |||
| 96bf6a5bcb | |||
| c43d66c286 | |||
| 95fb5fa46c | |||
| d614913c11 | |||
| 3bfaac0844 | |||
| 14d0cbf6d7 | |||
| 61a163d773 | |||
| 3a644dad78 | |||
| d2c1c719bd | |||
| 333db4dc94 | |||
| cbcf4b6071 | |||
| e6e0aba8c3 | |||
| 85097a9958 | |||
| 7791c343c4 | |||
| 3bd762591a | |||
| 8e3b77aba8 | |||
| 36e3a02f67 | |||
| 566a242ba3 | |||
| 1e3b3c107c | |||
| 2ac33285c1 | |||
| 7cb8016df3 | |||
| cf3c5a878a | |||
| 2d20bde495 | |||
| b9e347ef50 | |||
| 6707c8750e | |||
| e5502c13ee | |||
| f30d2e43ea | |||
| 6c73f9d3fd | |||
| 1161aa829d | |||
| 01519f2fd5 | |||
| 33aad3a8ce | |||
| 4262c125c5 | |||
| a09d5959ef | |||
| d7bd3f8402 | |||
| 0fff6a2b74 | |||
| f4c0405221 |
+10
@@ -257,7 +257,17 @@ paket-files/
|
|||||||
builds/
|
builds/
|
||||||
bin/
|
bin/
|
||||||
*.exe
|
*.exe
|
||||||
|
*.obj
|
||||||
|
*.pdb
|
||||||
|
|
||||||
# - Linux/MacOS
|
# - Linux/MacOS
|
||||||
odin
|
odin
|
||||||
odin.dSYM
|
odin.dSYM
|
||||||
|
|
||||||
|
|
||||||
|
# shared collection
|
||||||
|
shared/
|
||||||
|
|
||||||
|
# temp files
|
||||||
|
* .ll
|
||||||
|
*.bc
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
DISABLED_WARNINGS=-Wno-switch -Wno-writable-strings -Wno-tautological-compare -Wno-macro-redefined #-Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare
|
||||||
|
LDFLAGS=-pthread -ldl -lm -lstdc++
|
||||||
|
CFLAGS=-std=c++11
|
||||||
|
CC=clang
|
||||||
|
|
||||||
|
OS=$(shell uname)
|
||||||
|
|
||||||
|
ifeq ($(OS), DARWIN)
|
||||||
|
LDFLAGS=$(LDFLAGS) -liconv
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: debug demo
|
||||||
|
|
||||||
|
demo:
|
||||||
|
./odin run examples/demo.odin
|
||||||
|
|
||||||
|
debug:
|
||||||
|
$(CC) src/main.cpp $(DISABLED_WARNINGS) $(CFLAGS) -g $(LDFLAGS) -o odin
|
||||||
|
|
||||||
|
release:
|
||||||
|
$(CC) src/main.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 -march=native $(LDFLAGS) -o odin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
set exe_name=odin.exe
|
set exe_name=odin.exe
|
||||||
|
|
||||||
:: Debug = 0, Release = 1
|
:: Debug = 0, Release = 1
|
||||||
set release_mode=1
|
set release_mode=0
|
||||||
set compiler_flags= -nologo -Oi -TP -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
set compiler_flags= -nologo -Oi -TP -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
||||||
|
|
||||||
if %release_mode% EQU 0 ( rem Debug
|
if %release_mode% EQU 0 ( rem Debug
|
||||||
@@ -43,7 +43,7 @@ del *.ilk > NUL 2> NUL
|
|||||||
|
|
||||||
cl %compiler_settings% "src\main.cpp" ^
|
cl %compiler_settings% "src\main.cpp" ^
|
||||||
/link %linker_settings% -OUT:%exe_name% ^
|
/link %linker_settings% -OUT:%exe_name% ^
|
||||||
&& odin run code/demo.odin -opt=0
|
&& odin run examples/demo.odin -opt=0
|
||||||
rem && odin docs core/fmt.odin
|
rem && odin docs core/fmt.odin
|
||||||
|
|
||||||
del *.obj > NUL 2> NUL
|
del *.obj > NUL 2> NUL
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
release_mode=0
|
release_mode=$1
|
||||||
|
|
||||||
warnings_to_disable="-std=c++11 -g -Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined -Wno-writable-strings"
|
warnings_to_disable="-std=c++11 -Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined -Wno-writable-strings"
|
||||||
libraries="-pthread -ldl -lm -lstdc++"
|
libraries="-pthread -ldl -lm -lstdc++"
|
||||||
other_args=""
|
other_args=""
|
||||||
compiler="clang"
|
compiler="clang"
|
||||||
|
|
||||||
|
if [ -z "$release_mode" ]; then release_mode="0"; fi
|
||||||
|
|
||||||
if [ "$release_mode" -eq "0" ]; then
|
if [ "$release_mode" -eq "0" ]; then
|
||||||
other_args="${other_args} -g -fno-inline-functions"
|
other_args="${other_args} -g"
|
||||||
fi
|
fi
|
||||||
|
if [ "$release_mode" -eq "1" ]; then
|
||||||
|
other_args="${other_args} -O3 -march=native"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "$(uname)" == "Darwin" ]]; then
|
if [[ "$(uname)" == "Darwin" ]]; then
|
||||||
|
|
||||||
# Set compiler to clang on MacOS
|
# Set compiler to clang on MacOS
|
||||||
@@ -19,6 +25,4 @@ if [[ "$(uname)" == "Darwin" ]]; then
|
|||||||
other_args="${other_args} -liconv"
|
other_args="${other_args} -liconv"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
${compiler} src/main.cpp ${warnings_to_disable} ${libraries} ${other_args} -o odin
|
${compiler} src/main.cpp ${warnings_to_disable} ${libraries} ${other_args} -o odin && ./odin run examples/demo.odin
|
||||||
|
|
||||||
./odin run code/demo.odin
|
|
||||||
|
|||||||
@@ -1,184 +0,0 @@
|
|||||||
import "fmt.odin";
|
|
||||||
|
|
||||||
foreign_system_library ws2 "Ws2_32.lib" when ODIN_OS == "windows";
|
|
||||||
|
|
||||||
|
|
||||||
type SOCKET uint;
|
|
||||||
const INVALID_SOCKET = ~SOCKET(0);
|
|
||||||
|
|
||||||
type AF enum i32 {
|
|
||||||
UNSPEC = 0, // unspecified
|
|
||||||
UNIX = 1, // local to host (pipes, portals)
|
|
||||||
INET = 2, // internetwork: UDP, TCP, etc.
|
|
||||||
IMPLINK = 3, // arpanet imp addresses
|
|
||||||
PUP = 4, // pup protocols: e.g. BSP
|
|
||||||
CHAOS = 5, // mit CHAOS protocols
|
|
||||||
NS = 6, // XEROX NS protocols
|
|
||||||
ISO = 7, // ISO protocols
|
|
||||||
OSI = ISO, // OSI is ISO
|
|
||||||
ECMA = 8, // european computer manufacturers
|
|
||||||
DATAKIT = 9, // datakit protocols
|
|
||||||
CCITT = 10, // CCITT protocols, X.25 etc
|
|
||||||
SNA = 11, // IBM SNA
|
|
||||||
DECnet = 12, // DECnet
|
|
||||||
DLI = 13, // Direct data link interface
|
|
||||||
LAT = 14, // LAT
|
|
||||||
HYLINK = 15, // NSC Hyperchannel
|
|
||||||
APPLETALK = 16, // AppleTalk
|
|
||||||
ROUTE = 17, // Internal Routing Protocol
|
|
||||||
LINK = 18, // Link layer interface
|
|
||||||
XTP = 19, // eXpress Transfer Protocol (no AF)
|
|
||||||
COIP = 20, // connection-oriented IP, aka ST II
|
|
||||||
CNT = 21, // Computer Network Technology
|
|
||||||
RTIP = 22, // Help Identify RTIP packets
|
|
||||||
IPX = 23, // Novell Internet Protocol
|
|
||||||
SIP = 24, // Simple Internet Protocol
|
|
||||||
PIP = 25, // Help Identify PIP packets
|
|
||||||
MAX = 26,
|
|
||||||
};
|
|
||||||
|
|
||||||
const (
|
|
||||||
SOCK_STREAM = 1;
|
|
||||||
SOCKET_ERROR = -1;
|
|
||||||
IPPROTO_TCP = 6;
|
|
||||||
AI_PASSIVE = 0x0020;
|
|
||||||
SOMAXCONN = 128;
|
|
||||||
)
|
|
||||||
const (
|
|
||||||
SD_RECEIVE = 0;
|
|
||||||
SD_SEND = 1;
|
|
||||||
SD_BOTH = 2;
|
|
||||||
)
|
|
||||||
|
|
||||||
const WSADESCRIPTION_LEN = 256;
|
|
||||||
const WSASYS_STATUS_LEN = 128;
|
|
||||||
type WSADATA struct #ordered {
|
|
||||||
version: i16,
|
|
||||||
high_version: i16,
|
|
||||||
|
|
||||||
|
|
||||||
// NOTE(bill): This is x64 ordering
|
|
||||||
max_sockets: u16,
|
|
||||||
max_udp_dg: u16,
|
|
||||||
vendor_info: ^u8,
|
|
||||||
description: [WSADESCRIPTION_LEN+1]u8,
|
|
||||||
system_status: [WSASYS_STATUS_LEN+1]u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
type addrinfo struct #ordered {
|
|
||||||
flags: i32,
|
|
||||||
family: i32,
|
|
||||||
socktype: i32,
|
|
||||||
protocol: i32,
|
|
||||||
addrlen: uint,
|
|
||||||
canonname: ^u8,
|
|
||||||
addr: ^sockaddr,
|
|
||||||
next: ^addrinfo,
|
|
||||||
}
|
|
||||||
|
|
||||||
type sockaddr struct #ordered {
|
|
||||||
family: u16,
|
|
||||||
data: [14]u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
foreign ws2 {
|
|
||||||
proc WSAStartup (version_requested: i16, data: ^WSADATA) -> i32;
|
|
||||||
proc WSACleanup () -> i32;
|
|
||||||
proc getaddrinfo (node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32;
|
|
||||||
proc freeaddrinfo (ai: ^addrinfo);
|
|
||||||
proc socket (af, type_, protocol: i32) -> SOCKET;
|
|
||||||
proc closesocket (s: SOCKET) -> i32;
|
|
||||||
proc bind (s: SOCKET, name: ^sockaddr, name_len: i32) -> i32;
|
|
||||||
proc listen (s: SOCKET, back_log: i32) -> i32;
|
|
||||||
proc accept (s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET;
|
|
||||||
proc recv (s: SOCKET, buf: ^u8, len: i32, flags: i32) -> i32;
|
|
||||||
proc send (s: SOCKET, buf: ^u8, len: i32, flags: i32) -> i32;
|
|
||||||
proc shutdown (s: SOCKET, how: i32) -> i32;
|
|
||||||
proc WSAGetLastError() -> i32;
|
|
||||||
}
|
|
||||||
proc to_c_string(s: string) -> ^u8 {
|
|
||||||
var c_str = make([]u8, len(s)+1);
|
|
||||||
copy(c_str, []u8(s));
|
|
||||||
c_str[len(s)] = 0;
|
|
||||||
return &c_str[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
proc run() {
|
|
||||||
var (
|
|
||||||
wsa: WSADATA;
|
|
||||||
res: ^addrinfo = nil;
|
|
||||||
hints: addrinfo;
|
|
||||||
s, client: SOCKET;
|
|
||||||
)
|
|
||||||
|
|
||||||
if WSAStartup(2 | (2 << 8), &wsa) != 0 {
|
|
||||||
fmt.println("WSAStartup failed: ", WSAGetLastError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
defer WSACleanup();
|
|
||||||
|
|
||||||
hints.family = i32(AF.INET);
|
|
||||||
hints.socktype = SOCK_STREAM;
|
|
||||||
hints.protocol = IPPROTO_TCP;
|
|
||||||
hints.flags = AI_PASSIVE;
|
|
||||||
|
|
||||||
if getaddrinfo(nil, to_c_string("8080"), &hints, &res) != 0 {
|
|
||||||
fmt.println("getaddrinfo failed: ", WSAGetLastError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
defer freeaddrinfo(res);
|
|
||||||
|
|
||||||
s = socket(res.family, res.socktype, res.protocol);
|
|
||||||
if s == INVALID_SOCKET {
|
|
||||||
fmt.println("socket failed: ", WSAGetLastError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
defer closesocket(s);
|
|
||||||
|
|
||||||
bind(s, res.addr, i32(res.addrlen));
|
|
||||||
listen(s, SOMAXCONN);
|
|
||||||
|
|
||||||
client = accept(s, nil, 0);
|
|
||||||
if client == INVALID_SOCKET {
|
|
||||||
fmt.println("socket failed: ", WSAGetLastError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
defer closesocket(client);
|
|
||||||
|
|
||||||
var html =
|
|
||||||
`HTTP/1.1 200 OK
|
|
||||||
Connection: close
|
|
||||||
Content-type: text/html
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Demo Title</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1 style="color: orange;">Odin Server Demo</h1>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
`;
|
|
||||||
|
|
||||||
var buf: [1024]u8;
|
|
||||||
for {
|
|
||||||
var bytes = recv(client, &buf[0], i32(len(buf)), 0);
|
|
||||||
if bytes > 0 {
|
|
||||||
// fmt.println(string(buf[0..<bytes]))
|
|
||||||
var bytes_sent = send(client, &html[0], i32(len(html)-1), 0);
|
|
||||||
if bytes_sent == SOCKET_ERROR {
|
|
||||||
fmt.println("send failed: ", WSAGetLastError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} else if bytes == 0 {
|
|
||||||
fmt.println("Connection closing...");
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
fmt.println("recv failed: ", WSAGetLastError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shutdown(client, SD_SEND);
|
|
||||||
}
|
|
||||||
+352
-339
File diff suppressed because it is too large
Load Diff
+27
-143
@@ -1,20 +1,22 @@
|
|||||||
#shared_global_scope;
|
#shared_global_scope
|
||||||
|
|
||||||
__multi3 :: proc(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
|
@(link_name="__multi3")
|
||||||
|
__multi3 :: proc "c" (a, b: u128) -> u128 {
|
||||||
bits_in_dword_2 :: size_of(i64) * 4;
|
bits_in_dword_2 :: size_of(i64) * 4;
|
||||||
lower_mask :: u128(~u64(0) >> bits_in_dword_2);
|
lower_mask :: u128(~u64(0) >> bits_in_dword_2);
|
||||||
|
|
||||||
|
|
||||||
TWords :: struct #raw_union {
|
when ODIN_ENDIAN == "big" {
|
||||||
all: u128;
|
TWords :: struct #raw_union {
|
||||||
using _: struct {
|
all: u128,
|
||||||
when ODIN_ENDIAN == "big" {
|
using _: struct {lo, hi: u64},
|
||||||
lo, hi: u64;
|
|
||||||
} else {
|
|
||||||
hi, lo: u64;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
} else {
|
||||||
|
TWords :: struct #raw_union {
|
||||||
|
all: u128,
|
||||||
|
using _: struct {hi, lo: u64},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
r: TWords;
|
r: TWords;
|
||||||
t: u64;
|
t: u64;
|
||||||
@@ -34,27 +36,32 @@ __multi3 :: proc(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
|
|||||||
return r.all;
|
return r.all;
|
||||||
}
|
}
|
||||||
|
|
||||||
__u128_mod :: proc(a, b: u128) -> u128 #cc_c #link_name "__umodti3" {
|
@(link_name="__umodti3")
|
||||||
|
__u128_mod :: proc "c" (a, b: u128) -> u128 {
|
||||||
r: u128;
|
r: u128;
|
||||||
__u128_quo_mod(a, b, &r);
|
__u128_quo_mod(a, b, &r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
__u128_quo :: proc(a, b: u128) -> u128 #cc_c #link_name "__udivti3" {
|
@(link_name="__udivti3")
|
||||||
|
__u128_quo :: proc "c" (a, b: u128) -> u128 {
|
||||||
return __u128_quo_mod(a, b, nil);
|
return __u128_quo_mod(a, b, nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
__i128_mod :: proc(a, b: i128) -> i128 #cc_c #link_name "__modti3" {
|
@(link_name="__modti3")
|
||||||
|
__i128_mod :: proc "c" (a, b: i128) -> i128 {
|
||||||
r: i128;
|
r: i128;
|
||||||
__i128_quo_mod(a, b, &r);
|
__i128_quo_mod(a, b, &r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
__i128_quo :: proc(a, b: i128) -> i128 #cc_c #link_name "__divti3" {
|
@(link_name="__divti3")
|
||||||
|
__i128_quo :: proc "c" (a, b: i128) -> i128 {
|
||||||
return __i128_quo_mod(a, b, nil);
|
return __i128_quo_mod(a, b, nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
__i128_quo_mod :: proc(a, b: i128, rem: ^i128) -> (quo: i128) #cc_c #link_name "__divmodti4" {
|
@(link_name="__divmodti4")
|
||||||
|
__i128_quo_mod :: proc "c" (a, b: i128, rem: ^i128) -> (quo: i128) {
|
||||||
s: i128;
|
s: i128;
|
||||||
s = b >> 127;
|
s = b >> 127;
|
||||||
b = (b~s) - s;
|
b = (b~s) - s;
|
||||||
@@ -73,9 +80,10 @@ __i128_quo_mod :: proc(a, b: i128, rem: ^i128) -> (quo: i128) #cc_c #link_name "
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__u128_quo_mod :: proc(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "__udivmodti4" {
|
@(link_name="__udivmodti4")
|
||||||
alo, ahi := u64(a), u64(a>>64);
|
__u128_quo_mod :: proc "c" (a, b: u128, rem: ^u128) -> (quo: u128) {
|
||||||
blo, bhi := u64(b), u64(b>>64);
|
alo := u64(a);
|
||||||
|
blo := u64(b);
|
||||||
if b == 0 {
|
if b == 0 {
|
||||||
if rem != nil do rem^ = 0;
|
if rem != nil do rem^ = 0;
|
||||||
return u128(alo/blo);
|
return u128(alo/blo);
|
||||||
@@ -100,127 +108,3 @@ __u128_quo_mod :: proc(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "
|
|||||||
if rem != nil do rem^ = r;
|
if rem != nil do rem^ = r;
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
__f16_to_f32 :: proc(f: f16) -> f32 #cc_c #no_inline #link_name "__gnu_h2f_ieee" {
|
|
||||||
when true {
|
|
||||||
// Source: https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
|
|
||||||
FP32 :: struct #raw_union {u: u32, f: f32};
|
|
||||||
|
|
||||||
magic, was_infnan: FP32;
|
|
||||||
magic.u = (254-15) << 23;
|
|
||||||
was_infnan.u = (127+16) << 23;
|
|
||||||
|
|
||||||
hu := transmute(u16, f);
|
|
||||||
|
|
||||||
o := FP32{};
|
|
||||||
|
|
||||||
o.u = u32(hu & 0x7fff) << 13);
|
|
||||||
o.f *= magic.f;
|
|
||||||
if o.f >= was_infnan.f {
|
|
||||||
o.u |= 255 << 23;
|
|
||||||
}
|
|
||||||
o.u |= u32(hu & 0x8000) << 16;
|
|
||||||
return o.f;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
__f32_to_f16 :: proc(f_: f32) -> f16 #cc_c #no_inline #link_name "__gnu_f2h_ieee" {
|
|
||||||
when false {
|
|
||||||
// Source: https://gist.github.com/rygorous/2156668
|
|
||||||
FP16 :: struct #raw_union {u: u16, f: f16};
|
|
||||||
FP32 :: struct #raw_union {u: u32, f: f32};
|
|
||||||
|
|
||||||
f32infty, f16infty, magic: FP32;
|
|
||||||
f32infty.u = 255<<23;
|
|
||||||
f16infty.u = 31<<23;
|
|
||||||
magic.u = 15<<23;
|
|
||||||
|
|
||||||
sign_mask :: u32(0x80000000);
|
|
||||||
round_mask :: ~u32(0x0fff);
|
|
||||||
|
|
||||||
f := transmute(FP32, f_);
|
|
||||||
|
|
||||||
o: FP16;
|
|
||||||
sign := f.u & sign_mask;
|
|
||||||
f.u ~= sign;
|
|
||||||
|
|
||||||
// NOTE all the integer compares in this function can be safely
|
|
||||||
// compiled into signed compares since all operands are below
|
|
||||||
// 0x80000000. Important if you want fast straight SSE2 code
|
|
||||||
// (since there's no unsigned PCMPGTD).
|
|
||||||
|
|
||||||
if f.u >= f32infty.u { // Inf or NaN (all exponent bits set)
|
|
||||||
o.u = f.u > f32infty.u ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf
|
|
||||||
} else { // (De)normalized number or zero
|
|
||||||
f.u &= round_mask;
|
|
||||||
f.f *= magic.f;
|
|
||||||
f.u -= round_mask;
|
|
||||||
if f.u > f16infty.u {
|
|
||||||
f.u = f16infty.u; // Clamp to signed infinity if overflowed
|
|
||||||
}
|
|
||||||
|
|
||||||
o.u = u16(f.u >> 13); // Take the bits!
|
|
||||||
}
|
|
||||||
|
|
||||||
o.u |= u16(sign >> 16);
|
|
||||||
return o.f;
|
|
||||||
} else {
|
|
||||||
f := transmute(u32, f_);
|
|
||||||
h: u16;
|
|
||||||
hs, he, hf: u16;
|
|
||||||
|
|
||||||
fs := (f >> 31) & 1;
|
|
||||||
fe := (f >> 23) & 0b1111_1111;
|
|
||||||
ff := (f >> 0) & 0b0111_1111_1111_1111_1111_1111;
|
|
||||||
|
|
||||||
add_one := false;
|
|
||||||
|
|
||||||
if (fe == 0) {
|
|
||||||
he = 0;
|
|
||||||
} else if (fe == 255) {
|
|
||||||
he = 31;
|
|
||||||
hf = ff != 0 ? 0x200 : 0;
|
|
||||||
} else {
|
|
||||||
ne := fe - 127 + 15;
|
|
||||||
if ne >= 31 {
|
|
||||||
he = 31;
|
|
||||||
} else if ne <= 0 {
|
|
||||||
if (14-ne) <= 24 {
|
|
||||||
mant := ff | 0x800000;
|
|
||||||
hf = u16(mant >> (14-ne));
|
|
||||||
|
|
||||||
if (mant >> (13-ne)) & 1 != 0 {
|
|
||||||
add_one = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
he = u16(ne);
|
|
||||||
hf = u16(ff >> 13);
|
|
||||||
if ff&0x1000 != 0 {
|
|
||||||
add_one = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
hs = u16(hs);
|
|
||||||
h |= (he&0b0001_1111)<<10;
|
|
||||||
h |= (hf&0b0011_1111_1111);
|
|
||||||
if add_one {
|
|
||||||
h++;
|
|
||||||
}
|
|
||||||
h |= (hs&1) << 15;
|
|
||||||
return transmute(f16, h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__f64_to_f16 :: proc(f: f64) -> f16 #cc_c #no_inline #link_name "__truncdfhf2" {
|
|
||||||
return __f32_to_f16(f32(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
__f16_to_f64 :: proc(f: f16) -> f64 #cc_c #no_inline {
|
|
||||||
return f64(__f16_to_f32(f));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|||||||
+4
-2
@@ -1,8 +1,10 @@
|
|||||||
// TODO(bill): Use assembly instead here to implement atomics
|
// TODO(bill): Use assembly instead here to implement atomics
|
||||||
// Inline vs external file?
|
// Inline vs external file?
|
||||||
|
|
||||||
import win32 "sys/windows.odin" when ODIN_OS == "windows";
|
when ODIN_OS == "windows" {
|
||||||
_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
|
import win32 "core:sys/windows.odin"
|
||||||
|
}
|
||||||
|
_ :: compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
|
||||||
|
|
||||||
|
|
||||||
yield_thread :: proc() { win32.mm_pause(); }
|
yield_thread :: proc() { win32.mm_pause(); }
|
||||||
|
|||||||
+138
-95
@@ -4,34 +4,91 @@ U32_MIN :: u32(0);
|
|||||||
U64_MIN :: u64(0);
|
U64_MIN :: u64(0);
|
||||||
U128_MIN :: u128(0);
|
U128_MIN :: u128(0);
|
||||||
|
|
||||||
I8_MIN :: i8(-0x80);
|
|
||||||
I16_MIN :: i16(-0x8000);
|
|
||||||
I32_MIN :: i32(-0x8000_0000);
|
|
||||||
I64_MIN :: i64(-0x8000_0000_0000_0000);
|
|
||||||
I128_MIN :: i128(-0x8000_0000_0000_0000_0000_0000_0000_0000);
|
|
||||||
|
|
||||||
U8_MAX :: ~u8(0);
|
U8_MAX :: ~u8(0);
|
||||||
U16_MAX :: ~u16(0);
|
U16_MAX :: ~u16(0);
|
||||||
U32_MAX :: ~u32(0);
|
U32_MAX :: ~u32(0);
|
||||||
U64_MAX :: ~u64(0);
|
U64_MAX :: ~u64(0);
|
||||||
U128_MAX :: ~u128(0);
|
U128_MAX :: ~u128(0);
|
||||||
|
|
||||||
I8_MAX :: i8(0x7f);
|
I8_MIN :: i8( ~u8(0) >> 1);
|
||||||
I16_MAX :: i16(0x7fff);
|
I16_MIN :: i16( ~u16(0) >> 1);
|
||||||
I32_MAX :: i32(0x7fff_ffff);
|
I32_MIN :: i32( ~u32(0) >> 1);
|
||||||
I64_MAX :: i64(0x7fff_ffff_ffff_ffff);
|
I64_MIN :: i64( ~u64(0) >> 1);
|
||||||
I128_MAX :: i128(0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ffff);
|
I128_MIN :: i128(~u128(0) >> 1);
|
||||||
|
|
||||||
count_ones :: proc(i: u8) -> u8 { foreign __llvm_core __llvm_ctpop :: proc(u8) -> u8 #link_name "llvm.ctpop.i8" ---; return __llvm_ctpop(i); }
|
I8_MAX :: -I8_MIN - 1;
|
||||||
count_ones :: proc(i: i8) -> i8 { foreign __llvm_core __llvm_ctpop :: proc(i8) -> i8 #link_name "llvm.ctpop.i8" ---; return __llvm_ctpop(i); }
|
I16_MAX :: -I16_MIN - 1;
|
||||||
count_ones :: proc(i: u16) -> u16 { foreign __llvm_core __llvm_ctpop :: proc(u16) -> u16 #link_name "llvm.ctpop.i16" ---; return __llvm_ctpop(i); }
|
I32_MAX :: -I32_MIN - 1;
|
||||||
count_ones :: proc(i: i16) -> i16 { foreign __llvm_core __llvm_ctpop :: proc(i16) -> i16 #link_name "llvm.ctpop.i16" ---; return __llvm_ctpop(i); }
|
I64_MAX :: -I64_MIN - 1;
|
||||||
count_ones :: proc(i: u32) -> u32 { foreign __llvm_core __llvm_ctpop :: proc(u32) -> u32 #link_name "llvm.ctpop.i32" ---; return __llvm_ctpop(i); }
|
I128_MAX :: -I128_MIN - 1;
|
||||||
count_ones :: proc(i: i32) -> i32 { foreign __llvm_core __llvm_ctpop :: proc(i32) -> i32 #link_name "llvm.ctpop.i32" ---; return __llvm_ctpop(i); }
|
|
||||||
count_ones :: proc(i: u64) -> u64 { foreign __llvm_core __llvm_ctpop :: proc(u64) -> u64 #link_name "llvm.ctpop.i64" ---; return __llvm_ctpop(i); }
|
foreign __llvm_core {
|
||||||
count_ones :: proc(i: i64) -> i64 { foreign __llvm_core __llvm_ctpop :: proc(i64) -> i64 #link_name "llvm.ctpop.i64" ---; return __llvm_ctpop(i); }
|
@(link_name="llvm.ctpop.i8") __llvm_ctpop :: proc(u8) -> u8 ---;
|
||||||
count_ones :: proc(i: u128) -> u128 { foreign __llvm_core __llvm_ctpop :: proc(u128) -> u128 #link_name "llvm.ctpop.i128" ---;return __llvm_ctpop(i); }
|
@(link_name="llvm.ctpop.i8") __llvm_ctpop :: proc(i8) -> i8 ---;
|
||||||
count_ones :: proc(i: i128) -> i128 { foreign __llvm_core __llvm_ctpop :: proc(i128) -> i128 #link_name "llvm.ctpop.i128" ---;return __llvm_ctpop(i); }
|
@(link_name="llvm.ctpop.i16") __llvm_ctpop :: proc(u16) -> u16 ---;
|
||||||
|
@(link_name="llvm.ctpop.i16") __llvm_ctpop :: proc(i16) -> i16 ---;
|
||||||
|
@(link_name="llvm.ctpop.i32") __llvm_ctpop :: proc(u32) -> u32 ---;
|
||||||
|
@(link_name="llvm.ctpop.i32") __llvm_ctpop :: proc(i32) -> i32 ---;
|
||||||
|
@(link_name="llvm.ctpop.i64") __llvm_ctpop :: proc(u64) -> u64 ---;
|
||||||
|
@(link_name="llvm.ctpop.i64") __llvm_ctpop :: proc(i64) -> i64 ---;
|
||||||
|
@(link_name="llvm.ctpop.i128") __llvm_ctpop :: proc(u128) -> u128 ---;
|
||||||
|
@(link_name="llvm.ctpop.i128") __llvm_ctpop :: proc(i128) -> i128 ---;
|
||||||
|
|
||||||
|
@(link_name="llvm.ctlz.i8") __llvm_ctlz :: proc(u8, bool) -> u8 ---;
|
||||||
|
@(link_name="llvm.ctlz.i8") __llvm_ctlz :: proc(i8, bool) -> i8 ---;
|
||||||
|
@(link_name="llvm.ctlz.i16") __llvm_ctlz :: proc(u16, bool) -> u16 ---;
|
||||||
|
@(link_name="llvm.ctlz.i16") __llvm_ctlz :: proc(i16, bool) -> i16 ---;
|
||||||
|
@(link_name="llvm.ctlz.i32") __llvm_ctlz :: proc(u32, bool) -> u32 ---;
|
||||||
|
@(link_name="llvm.ctlz.i32") __llvm_ctlz :: proc(i32, bool) -> i32 ---;
|
||||||
|
@(link_name="llvm.ctlz.i64") __llvm_ctlz :: proc(u64, bool) -> u64 ---;
|
||||||
|
@(link_name="llvm.ctlz.i64") __llvm_ctlz :: proc(i64, bool) -> i64 ---;
|
||||||
|
@(link_name="llvm.ctlz.i128") __llvm_ctlz :: proc(u128, bool) -> u128 ---;
|
||||||
|
@(link_name="llvm.ctlz.i128") __llvm_ctlz :: proc(i128, bool) -> i128 ---;
|
||||||
|
|
||||||
|
@(link_name="llvm.cttz.i8") __llvm_cttz :: proc(u8, bool) -> u8 ---;
|
||||||
|
@(link_name="llvm.cttz.i8") __llvm_cttz :: proc(i8, bool) -> i8 ---;
|
||||||
|
@(link_name="llvm.cttz.i16") __llvm_cttz :: proc(u16, bool) -> u16 ---;
|
||||||
|
@(link_name="llvm.cttz.i16") __llvm_cttz :: proc(i16, bool) -> i16 ---;
|
||||||
|
@(link_name="llvm.cttz.i32") __llvm_cttz :: proc(u32, bool) -> u32 ---;
|
||||||
|
@(link_name="llvm.cttz.i32") __llvm_cttz :: proc(i32, bool) -> i32 ---;
|
||||||
|
@(link_name="llvm.cttz.i64") __llvm_cttz :: proc(u64, bool) -> u64 ---;
|
||||||
|
@(link_name="llvm.cttz.i64") __llvm_cttz :: proc(i64, bool) -> i64 ---;
|
||||||
|
@(link_name="llvm.cttz.i128") __llvm_cttz :: proc(u128, bool) -> u128 ---;
|
||||||
|
@(link_name="llvm.cttz.i128") __llvm_cttz :: proc(i128, bool) -> i128 ---;
|
||||||
|
|
||||||
|
@(link_name="llvm.bitreverse.i8") __llvm_bitreverse :: proc(u8) -> u8 ---;
|
||||||
|
@(link_name="llvm.bitreverse.i8") __llvm_bitreverse :: proc(i8) -> i8 ---;
|
||||||
|
@(link_name="llvm.bitreverse.i16") __llvm_bitreverse :: proc(u16) -> u16 ---;
|
||||||
|
@(link_name="llvm.bitreverse.i16") __llvm_bitreverse :: proc(i16) -> i16 ---;
|
||||||
|
@(link_name="llvm.bitreverse.i32") __llvm_bitreverse :: proc(u32) -> u32 ---;
|
||||||
|
@(link_name="llvm.bitreverse.i32") __llvm_bitreverse :: proc(i32) -> i32 ---;
|
||||||
|
@(link_name="llvm.bitreverse.i64") __llvm_bitreverse :: proc(u64) -> u64 ---;
|
||||||
|
@(link_name="llvm.bitreverse.i64") __llvm_bitreverse :: proc(i64) -> i64 ---;
|
||||||
|
@(link_name="llvm.bitreverse.i128") __llvm_bitreverse :: proc(u128) -> u128 ---;
|
||||||
|
@(link_name="llvm.bitreverse.i128") __llvm_bitreverse :: proc(i128) -> i128 ---;
|
||||||
|
|
||||||
|
@(link_name="llvm.bswap.i16") byte_swap :: proc(u16) -> u16 ---;
|
||||||
|
@(link_name="llvm.bswap.i16") byte_swap :: proc(i16) -> i16 ---;
|
||||||
|
@(link_name="llvm.bswap.i32") byte_swap :: proc(u32) -> u32 ---;
|
||||||
|
@(link_name="llvm.bswap.i32") byte_swap :: proc(i32) -> i32 ---;
|
||||||
|
@(link_name="llvm.bswap.i64") byte_swap :: proc(u64) -> u64 ---;
|
||||||
|
@(link_name="llvm.bswap.i64") byte_swap :: proc(i64) -> i64 ---;
|
||||||
|
@(link_name="llvm.bswap.i128") byte_swap :: proc(u128) -> u128 ---;
|
||||||
|
@(link_name="llvm.bswap.i128") byte_swap :: proc(i128) -> i128 ---;
|
||||||
|
}
|
||||||
|
byte_swap :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(byte_swap(u32(i))); } else { return uint(byte_swap(u64(i))); } }
|
||||||
|
byte_swap :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(byte_swap(i32(i))); } else { return int(byte_swap(i64(i))); } }
|
||||||
|
|
||||||
|
count_ones :: proc(i: u8) -> u8 { return __llvm_ctpop(i); }
|
||||||
|
count_ones :: proc(i: i8) -> i8 { return __llvm_ctpop(i); }
|
||||||
|
count_ones :: proc(i: u16) -> u16 { return __llvm_ctpop(i); }
|
||||||
|
count_ones :: proc(i: i16) -> i16 { return __llvm_ctpop(i); }
|
||||||
|
count_ones :: proc(i: u32) -> u32 { return __llvm_ctpop(i); }
|
||||||
|
count_ones :: proc(i: i32) -> i32 { return __llvm_ctpop(i); }
|
||||||
|
count_ones :: proc(i: u64) -> u64 { return __llvm_ctpop(i); }
|
||||||
|
count_ones :: proc(i: i64) -> i64 { return __llvm_ctpop(i); }
|
||||||
|
count_ones :: proc(i: u128) -> u128 { return __llvm_ctpop(i); }
|
||||||
|
count_ones :: proc(i: i128) -> i128 { return __llvm_ctpop(i); }
|
||||||
count_ones :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(count_ones(u32(i))); } else { return uint(count_ones(u64(i))); } }
|
count_ones :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(count_ones(u32(i))); } else { return uint(count_ones(u64(i))); } }
|
||||||
count_ones :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(count_ones(i32(i))); } else { return int(count_ones(i64(i))); } }
|
count_ones :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(count_ones(i32(i))); } else { return int(count_ones(i64(i))); } }
|
||||||
|
|
||||||
@@ -76,60 +133,46 @@ rotate_right :: proc(i: i128, s: uint) -> i128 { return (i >> s)|(i << (8*size_o
|
|||||||
rotate_right :: proc(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_right(u32(i), s)); } else { return uint(rotate_right(u64(i), s)); } }
|
rotate_right :: proc(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_right(u32(i), s)); } else { return uint(rotate_right(u64(i), s)); } }
|
||||||
rotate_right :: proc(i: int, s: uint) -> int { when size_of(int) == size_of(i32) { return int(rotate_right(i32(i), s)); } else { return int(rotate_right(i64(i), s)); } }
|
rotate_right :: proc(i: int, s: uint) -> int { when size_of(int) == size_of(i32) { return int(rotate_right(i32(i), s)); } else { return int(rotate_right(i64(i), s)); } }
|
||||||
|
|
||||||
|
leading_zeros :: proc(i: u8) -> u8 { return __llvm_ctlz(i, false); }
|
||||||
leading_zeros :: proc(i: u8) -> u8 { foreign __llvm_core __llvm_ctlz :: proc(u8, bool) -> u8 #link_name "llvm.ctlz.i8" ---; return __llvm_ctlz(i, false); }
|
leading_zeros :: proc(i: i8) -> i8 { return __llvm_ctlz(i, false); }
|
||||||
leading_zeros :: proc(i: i8) -> i8 { foreign __llvm_core __llvm_ctlz :: proc(i8, bool) -> i8 #link_name "llvm.ctlz.i8" ---; return __llvm_ctlz(i, false); }
|
leading_zeros :: proc(i: u16) -> u16 { return __llvm_ctlz(i, false); }
|
||||||
leading_zeros :: proc(i: u16) -> u16 { foreign __llvm_core __llvm_ctlz :: proc(u16, bool) -> u16 #link_name "llvm.ctlz.i16" ---; return __llvm_ctlz(i, false); }
|
leading_zeros :: proc(i: i16) -> i16 { return __llvm_ctlz(i, false); }
|
||||||
leading_zeros :: proc(i: i16) -> i16 { foreign __llvm_core __llvm_ctlz :: proc(i16, bool) -> i16 #link_name "llvm.ctlz.i16" ---; return __llvm_ctlz(i, false); }
|
leading_zeros :: proc(i: u32) -> u32 { return __llvm_ctlz(i, false); }
|
||||||
leading_zeros :: proc(i: u32) -> u32 { foreign __llvm_core __llvm_ctlz :: proc(u32, bool) -> u32 #link_name "llvm.ctlz.i32" ---; return __llvm_ctlz(i, false); }
|
leading_zeros :: proc(i: i32) -> i32 { return __llvm_ctlz(i, false); }
|
||||||
leading_zeros :: proc(i: i32) -> i32 { foreign __llvm_core __llvm_ctlz :: proc(i32, bool) -> i32 #link_name "llvm.ctlz.i32" ---; return __llvm_ctlz(i, false); }
|
leading_zeros :: proc(i: u64) -> u64 { return __llvm_ctlz(i, false); }
|
||||||
leading_zeros :: proc(i: u64) -> u64 { foreign __llvm_core __llvm_ctlz :: proc(u64, bool) -> u64 #link_name "llvm.ctlz.i64" ---; return __llvm_ctlz(i, false); }
|
leading_zeros :: proc(i: i64) -> i64 { return __llvm_ctlz(i, false); }
|
||||||
leading_zeros :: proc(i: i64) -> i64 { foreign __llvm_core __llvm_ctlz :: proc(i64, bool) -> i64 #link_name "llvm.ctlz.i64" ---; return __llvm_ctlz(i, false); }
|
leading_zeros :: proc(i: u128) -> u128 { return __llvm_ctlz(i, false); }
|
||||||
leading_zeros :: proc(i: u128) -> u128 { foreign __llvm_core __llvm_ctlz :: proc(u128, bool) -> u128 #link_name "llvm.ctlz.i128" ---;return __llvm_ctlz(i, false); }
|
leading_zeros :: proc(i: i128) -> i128 { return __llvm_ctlz(i, false); }
|
||||||
leading_zeros :: proc(i: i128) -> i128 { foreign __llvm_core __llvm_ctlz :: proc(i128, bool) -> i128 #link_name "llvm.ctlz.i128" ---;return __llvm_ctlz(i, false); }
|
|
||||||
leading_zeros :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(leading_zeros(u32(i))); } else { return uint(leading_zeros(u64(i))); } }
|
leading_zeros :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(leading_zeros(u32(i))); } else { return uint(leading_zeros(u64(i))); } }
|
||||||
leading_zeros :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(leading_zeros(i32(i))); } else { return int(leading_zeros(i64(i))); } }
|
leading_zeros :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(leading_zeros(i32(i))); } else { return int(leading_zeros(i64(i))); } }
|
||||||
|
|
||||||
trailing_zeros :: proc(i: u8) -> u8 { foreign __llvm_core __llvm_cttz :: proc(u8, bool) -> u8 #link_name "llvm.cttz.i8" ---; return __llvm_cttz(i, false); }
|
trailing_zeros :: proc(i: u8) -> u8 { return __llvm_cttz(i, false); }
|
||||||
trailing_zeros :: proc(i: i8) -> i8 { foreign __llvm_core __llvm_cttz :: proc(i8, bool) -> i8 #link_name "llvm.cttz.i8" ---; return __llvm_cttz(i, false); }
|
trailing_zeros :: proc(i: i8) -> i8 { return __llvm_cttz(i, false); }
|
||||||
trailing_zeros :: proc(i: u16) -> u16 { foreign __llvm_core __llvm_cttz :: proc(u16, bool) -> u16 #link_name "llvm.cttz.i16" ---; return __llvm_cttz(i, false); }
|
trailing_zeros :: proc(i: u16) -> u16 { return __llvm_cttz(i, false); }
|
||||||
trailing_zeros :: proc(i: i16) -> i16 { foreign __llvm_core __llvm_cttz :: proc(i16, bool) -> i16 #link_name "llvm.cttz.i16" ---; return __llvm_cttz(i, false); }
|
trailing_zeros :: proc(i: i16) -> i16 { return __llvm_cttz(i, false); }
|
||||||
trailing_zeros :: proc(i: u32) -> u32 { foreign __llvm_core __llvm_cttz :: proc(u32, bool) -> u32 #link_name "llvm.cttz.i32" ---; return __llvm_cttz(i, false); }
|
trailing_zeros :: proc(i: u32) -> u32 { return __llvm_cttz(i, false); }
|
||||||
trailing_zeros :: proc(i: i32) -> i32 { foreign __llvm_core __llvm_cttz :: proc(i32, bool) -> i32 #link_name "llvm.cttz.i32" ---; return __llvm_cttz(i, false); }
|
trailing_zeros :: proc(i: i32) -> i32 { return __llvm_cttz(i, false); }
|
||||||
trailing_zeros :: proc(i: u64) -> u64 { foreign __llvm_core __llvm_cttz :: proc(u64, bool) -> u64 #link_name "llvm.cttz.i64" ---; return __llvm_cttz(i, false); }
|
trailing_zeros :: proc(i: u64) -> u64 { return __llvm_cttz(i, false); }
|
||||||
trailing_zeros :: proc(i: i64) -> i64 { foreign __llvm_core __llvm_cttz :: proc(i64, bool) -> i64 #link_name "llvm.cttz.i64" ---; return __llvm_cttz(i, false); }
|
trailing_zeros :: proc(i: i64) -> i64 { return __llvm_cttz(i, false); }
|
||||||
trailing_zeros :: proc(i: u128) -> u128 { foreign __llvm_core __llvm_cttz :: proc(u128, bool) -> u128 #link_name "llvm.cttz.i128" ---;return __llvm_cttz(i, false); }
|
trailing_zeros :: proc(i: u128) -> u128 { return __llvm_cttz(i, false); }
|
||||||
trailing_zeros :: proc(i: i128) -> i128 { foreign __llvm_core __llvm_cttz :: proc(i128, bool) -> i128 #link_name "llvm.cttz.i128" ---;return __llvm_cttz(i, false); }
|
trailing_zeros :: proc(i: i128) -> i128 { return __llvm_cttz(i, false); }
|
||||||
trailing_zeros :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(trailing_zeros(u32(i))); } else { return uint(trailing_zeros(u64(i))); } }
|
trailing_zeros :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(trailing_zeros(u32(i))); } else { return uint(trailing_zeros(u64(i))); } }
|
||||||
trailing_zeros :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(trailing_zeros(i32(i))); } else { return int(trailing_zeros(i64(i))); } }
|
trailing_zeros :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(trailing_zeros(i32(i))); } else { return int(trailing_zeros(i64(i))); } }
|
||||||
|
|
||||||
|
|
||||||
reverse_bits :: proc(i: u8) -> u8 { foreign __llvm_core __llvm_bitreverse :: proc(u8) -> u8 #link_name "llvm.bitreverse.i8" ---; return __llvm_bitreverse(i); }
|
reverse_bits :: proc(i: u8) -> u8 { return __llvm_bitreverse(i); }
|
||||||
reverse_bits :: proc(i: i8) -> i8 { foreign __llvm_core __llvm_bitreverse :: proc(i8) -> i8 #link_name "llvm.bitreverse.i8" ---; return __llvm_bitreverse(i); }
|
reverse_bits :: proc(i: i8) -> i8 { return __llvm_bitreverse(i); }
|
||||||
reverse_bits :: proc(i: u16) -> u16 { foreign __llvm_core __llvm_bitreverse :: proc(u16) -> u16 #link_name "llvm.bitreverse.i16" ---; return __llvm_bitreverse(i); }
|
reverse_bits :: proc(i: u16) -> u16 { return __llvm_bitreverse(i); }
|
||||||
reverse_bits :: proc(i: i16) -> i16 { foreign __llvm_core __llvm_bitreverse :: proc(i16) -> i16 #link_name "llvm.bitreverse.i16" ---; return __llvm_bitreverse(i); }
|
reverse_bits :: proc(i: i16) -> i16 { return __llvm_bitreverse(i); }
|
||||||
reverse_bits :: proc(i: u32) -> u32 { foreign __llvm_core __llvm_bitreverse :: proc(u32) -> u32 #link_name "llvm.bitreverse.i32" ---; return __llvm_bitreverse(i); }
|
reverse_bits :: proc(i: u32) -> u32 { return __llvm_bitreverse(i); }
|
||||||
reverse_bits :: proc(i: i32) -> i32 { foreign __llvm_core __llvm_bitreverse :: proc(i32) -> i32 #link_name "llvm.bitreverse.i32" ---; return __llvm_bitreverse(i); }
|
reverse_bits :: proc(i: i32) -> i32 { return __llvm_bitreverse(i); }
|
||||||
reverse_bits :: proc(i: u64) -> u64 { foreign __llvm_core __llvm_bitreverse :: proc(u64) -> u64 #link_name "llvm.bitreverse.i64" ---; return __llvm_bitreverse(i); }
|
reverse_bits :: proc(i: u64) -> u64 { return __llvm_bitreverse(i); }
|
||||||
reverse_bits :: proc(i: i64) -> i64 { foreign __llvm_core __llvm_bitreverse :: proc(i64) -> i64 #link_name "llvm.bitreverse.i64" ---; return __llvm_bitreverse(i); }
|
reverse_bits :: proc(i: i64) -> i64 { return __llvm_bitreverse(i); }
|
||||||
reverse_bits :: proc(i: u128) -> u128 { foreign __llvm_core __llvm_bitreverse :: proc(u128) -> u128 #link_name "llvm.bitreverse.i128" ---;return __llvm_bitreverse(i); }
|
reverse_bits :: proc(i: u128) -> u128 { return __llvm_bitreverse(i); }
|
||||||
reverse_bits :: proc(i: i128) -> i128 { foreign __llvm_core __llvm_bitreverse :: proc(i128) -> i128 #link_name "llvm.bitreverse.i128" ---;return __llvm_bitreverse(i); }
|
reverse_bits :: proc(i: i128) -> i128 { return __llvm_bitreverse(i); }
|
||||||
reverse_bits :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(reverse_bits(u32(i))); } else { return uint(reverse_bits(u64(i))); } }
|
reverse_bits :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(reverse_bits(u32(i))); } else { return uint(reverse_bits(u64(i))); } }
|
||||||
reverse_bits :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(reverse_bits(i32(i))); } else { return int(reverse_bits(i64(i))); } }
|
reverse_bits :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(reverse_bits(i32(i))); } else { return int(reverse_bits(i64(i))); } }
|
||||||
|
|
||||||
foreign __llvm_core {
|
|
||||||
byte_swap :: proc(u16) -> u16 #link_name "llvm.bswap.i16" ---;
|
|
||||||
byte_swap :: proc(i16) -> i16 #link_name "llvm.bswap.i16" ---;
|
|
||||||
byte_swap :: proc(u32) -> u32 #link_name "llvm.bswap.i32" ---;
|
|
||||||
byte_swap :: proc(i32) -> i32 #link_name "llvm.bswap.i32" ---;
|
|
||||||
byte_swap :: proc(u64) -> u64 #link_name "llvm.bswap.i64" ---;
|
|
||||||
byte_swap :: proc(i64) -> i64 #link_name "llvm.bswap.i64" ---;
|
|
||||||
byte_swap :: proc(u128) -> u128 #link_name "llvm.bswap.i128" ---;
|
|
||||||
byte_swap :: proc(i128) -> i128 #link_name "llvm.bswap.i128" ---;
|
|
||||||
}
|
|
||||||
byte_swap :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(byte_swap(u32(i))); } else { return uint(byte_swap(u64(i))); } }
|
|
||||||
byte_swap :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(byte_swap(i32(i))); } else { return int(byte_swap(i64(i))); } }
|
|
||||||
|
|
||||||
from_be :: proc(i: u8) -> u8 { return i; }
|
from_be :: proc(i: u8) -> u8 { return i; }
|
||||||
from_be :: proc(i: i8) -> i8 { return i; }
|
from_be :: proc(i: i8) -> i8 { return i; }
|
||||||
from_be :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
from_be :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||||
@@ -184,16 +227,16 @@ to_le :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else
|
|||||||
to_le :: proc(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
to_le :: proc(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||||
|
|
||||||
|
|
||||||
overflowing_add :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core op :: proc(u8, u8) -> (u8, bool) #link_name "llvm.uadd.with.overflow.i8" ---; return op(lhs, rhs); }
|
overflowing_add :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_add :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core op :: proc(i8, i8) -> (i8, bool) #link_name "llvm.sadd.with.overflow.i8" ---; return op(lhs, rhs); }
|
overflowing_add :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_add :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core op :: proc(u16, u16) -> (u16, bool) #link_name "llvm.uadd.with.overflow.i16" ---; return op(lhs, rhs); }
|
overflowing_add :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_add :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core op :: proc(i16, i16) -> (i16, bool) #link_name "llvm.sadd.with.overflow.i16" ---; return op(lhs, rhs); }
|
overflowing_add :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_add :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core op :: proc(u32, u32) -> (u32, bool) #link_name "llvm.uadd.with.overflow.i32" ---; return op(lhs, rhs); }
|
overflowing_add :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_add :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core op :: proc(i32, i32) -> (i32, bool) #link_name "llvm.sadd.with.overflow.i32" ---; return op(lhs, rhs); }
|
overflowing_add :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_add :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core op :: proc(u64, u64) -> (u64, bool) #link_name "llvm.uadd.with.overflow.i64" ---; return op(lhs, rhs); }
|
overflowing_add :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_add :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core op :: proc(i64, i64) -> (i64, bool) #link_name "llvm.sadd.with.overflow.i64" ---; return op(lhs, rhs); }
|
overflowing_add :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_add :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core op :: proc(u128, u128) -> (u128, bool) #link_name "llvm.uadd.with.overflow.i128" ---; return op(lhs, rhs); }
|
overflowing_add :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i128") op :: proc(u128, u128) -> (u128, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_add :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core op :: proc(i128, i128) -> (i128, bool) #link_name "llvm.sadd.with.overflow.i128" ---; return op(lhs, rhs); }
|
overflowing_add :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i128") op :: proc(i128, i128) -> (i128, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_add :: proc(lhs, rhs: uint) -> (uint, bool) {
|
overflowing_add :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||||
when size_of(uint) == size_of(u32) {
|
when size_of(uint) == size_of(u32) {
|
||||||
x, ok := overflowing_add(u32(lhs), u32(rhs));
|
x, ok := overflowing_add(u32(lhs), u32(rhs));
|
||||||
@@ -213,16 +256,16 @@ overflowing_add :: proc(lhs, rhs: int) -> (int, bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
overflowing_sub :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core op :: proc(u8, u8) -> (u8, bool) #link_name "llvm.usub.with.overflow.i8" ---; return op(lhs, rhs); }
|
overflowing_sub :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_sub :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core op :: proc(i8, i8) -> (i8, bool) #link_name "llvm.ssub.with.overflow.i8" ---; return op(lhs, rhs); }
|
overflowing_sub :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_sub :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core op :: proc(u16, u16) -> (u16, bool) #link_name "llvm.usub.with.overflow.i16" ---; return op(lhs, rhs); }
|
overflowing_sub :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_sub :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core op :: proc(i16, i16) -> (i16, bool) #link_name "llvm.ssub.with.overflow.i16" ---; return op(lhs, rhs); }
|
overflowing_sub :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_sub :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core op :: proc(u32, u32) -> (u32, bool) #link_name "llvm.usub.with.overflow.i32" ---; return op(lhs, rhs); }
|
overflowing_sub :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_sub :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core op :: proc(i32, i32) -> (i32, bool) #link_name "llvm.ssub.with.overflow.i32" ---; return op(lhs, rhs); }
|
overflowing_sub :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_sub :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core op :: proc(u64, u64) -> (u64, bool) #link_name "llvm.usub.with.overflow.i64" ---; return op(lhs, rhs); }
|
overflowing_sub :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_sub :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core op :: proc(i64, i64) -> (i64, bool) #link_name "llvm.ssub.with.overflow.i64" ---; return op(lhs, rhs); }
|
overflowing_sub :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_sub :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core op :: proc(u128, u128) -> (u128, bool) #link_name "llvm.usub.with.overflow.i128" ---; return op(lhs, rhs); }
|
overflowing_sub :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i128") op :: proc(u128, u128) -> (u128, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_sub :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core op :: proc(i128, i128) -> (i128, bool) #link_name "llvm.ssub.with.overflow.i128" ---; return op(lhs, rhs); }
|
overflowing_sub :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i128") op :: proc(i128, i128) -> (i128, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_sub :: proc(lhs, rhs: uint) -> (uint, bool) {
|
overflowing_sub :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||||
when size_of(uint) == size_of(u32) {
|
when size_of(uint) == size_of(u32) {
|
||||||
x, ok := overflowing_sub(u32(lhs), u32(rhs));
|
x, ok := overflowing_sub(u32(lhs), u32(rhs));
|
||||||
@@ -242,16 +285,16 @@ overflowing_sub :: proc(lhs, rhs: int) -> (int, bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
overflowing_mul :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core op :: proc(u8, u8) -> (u8, bool) #link_name "llvm.umul.with.overflow.i8" ---; return op(lhs, rhs); }
|
overflowing_mul :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_mul :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core op :: proc(i8, i8) -> (i8, bool) #link_name "llvm.smul.with.overflow.i8" ---; return op(lhs, rhs); }
|
overflowing_mul :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_mul :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core op :: proc(u16, u16) -> (u16, bool) #link_name "llvm.umul.with.overflow.i16" ---; return op(lhs, rhs); }
|
overflowing_mul :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_mul :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core op :: proc(i16, i16) -> (i16, bool) #link_name "llvm.smul.with.overflow.i16" ---; return op(lhs, rhs); }
|
overflowing_mul :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_mul :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core op :: proc(u32, u32) -> (u32, bool) #link_name "llvm.umul.with.overflow.i32" ---; return op(lhs, rhs); }
|
overflowing_mul :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_mul :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core op :: proc(i32, i32) -> (i32, bool) #link_name "llvm.smul.with.overflow.i32" ---; return op(lhs, rhs); }
|
overflowing_mul :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_mul :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core op :: proc(u64, u64) -> (u64, bool) #link_name "llvm.umul.with.overflow.i64" ---; return op(lhs, rhs); }
|
overflowing_mul :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_mul :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core op :: proc(i64, i64) -> (i64, bool) #link_name "llvm.smul.with.overflow.i64" ---; return op(lhs, rhs); }
|
overflowing_mul :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_mul :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core op :: proc(u128, u128) -> (u128, bool) #link_name "llvm.umul.with.overflow.i128" ---; return op(lhs, rhs); }
|
overflowing_mul :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i128") op :: proc(u128, u128) -> (u128, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_mul :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core op :: proc(i128, i128) -> (i128, bool) #link_name "llvm.smul.with.overflow.i128" ---; return op(lhs, rhs); }
|
overflowing_mul :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i128") op :: proc(i128, i128) -> (i128, bool) ---; return op(lhs, rhs); }
|
||||||
overflowing_mul :: proc(lhs, rhs: uint) -> (uint, bool) {
|
overflowing_mul :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||||
when size_of(uint) == size_of(u32) {
|
when size_of(uint) == size_of(u32) {
|
||||||
x, ok := overflowing_mul(u32(lhs), u32(rhs));
|
x, ok := overflowing_mul(u32(lhs), u32(rhs));
|
||||||
|
|||||||
+31
-34
@@ -1,41 +1,38 @@
|
|||||||
CHAR_BIT :: 8;
|
CHAR_BIT :: 8;
|
||||||
|
|
||||||
c_bool :: bool;
|
c_bool :: #alias bool;
|
||||||
|
c_char :: #alias u8;
|
||||||
|
c_byte :: #alias u8;
|
||||||
|
c_schar :: #alias i8;
|
||||||
|
c_uchar :: #alias u8;
|
||||||
|
c_short :: #alias i16;
|
||||||
|
c_ushort :: #alias u16;
|
||||||
|
c_int :: #alias i32;
|
||||||
|
c_uint :: #alias u32;
|
||||||
|
|
||||||
c_char :: u8;
|
when ODIN_OS == "windows" || size_of(rawptr) == 4 {
|
||||||
|
c_long :: #alias i32;
|
||||||
|
} else {
|
||||||
|
c_long :: #alias i64;
|
||||||
|
}
|
||||||
|
|
||||||
c_schar :: i8;
|
when ODIN_OS == "windows" || size_of(rawptr) == 4 {
|
||||||
c_uchar :: i8;
|
c_ulong :: #alias u32;
|
||||||
|
} else {
|
||||||
|
c_ulong :: #alias u64;
|
||||||
|
}
|
||||||
|
|
||||||
c_short :: i16;
|
c_longlong :: #alias i64;
|
||||||
c_ushort :: i16;
|
c_ulonglong :: #alias u64;
|
||||||
|
c_float :: #alias f32;
|
||||||
|
c_double :: #alias f64;
|
||||||
|
c_complex_float :: #alias complex64;
|
||||||
|
c_complex_double :: #alias complex128;
|
||||||
|
|
||||||
c_int :: i32;
|
_ :: compile_assert(size_of(uintptr) == size_of(int));
|
||||||
c_uint :: u32;
|
|
||||||
|
|
||||||
c_long :: ODIN_OS == "windows" ?
|
c_size_t :: #alias uint;
|
||||||
i32 :
|
c_ssize_t :: #alias int;
|
||||||
(size_of(int) == 4) ?
|
c_ptrdiff_t :: #alias int;
|
||||||
i32 :
|
c_uintptr_t :: #alias uintptr;
|
||||||
i64;
|
c_intptr_t :: #alias int;
|
||||||
|
|
||||||
c_ulong :: ODIN_OS == "windows" ?
|
|
||||||
u32 :
|
|
||||||
(size_of(int) == 4) ?
|
|
||||||
u32 :
|
|
||||||
u64;
|
|
||||||
|
|
||||||
c_longlong :: i64;
|
|
||||||
c_ulonglong :: u64;
|
|
||||||
|
|
||||||
c_float :: f32;
|
|
||||||
c_double :: f64;
|
|
||||||
|
|
||||||
c_complex_float :: complex64;
|
|
||||||
c_complex_double :: complex128;
|
|
||||||
|
|
||||||
c_size_t :: uint;
|
|
||||||
c_ssize_t :: int;
|
|
||||||
c_ptrdiff_t :: int;
|
|
||||||
c_uintptr_t :: uint;
|
|
||||||
c_intptr_t :: int;
|
|
||||||
|
|||||||
+19
-20
@@ -1,12 +1,11 @@
|
|||||||
// #import "fmt.odin";
|
|
||||||
// Multiple precision decimal numbers
|
// Multiple precision decimal numbers
|
||||||
// NOTE: This is only for floating point printing and nothing else
|
// NOTE: This is only for floating point printing and nothing else
|
||||||
|
|
||||||
Decimal :: struct {
|
Decimal :: struct {
|
||||||
digits: [384]u8; // big-endian digits
|
digits: [384]u8, // big-endian digits
|
||||||
count: int;
|
count: int,
|
||||||
decimal_point: int;
|
decimal_point: int,
|
||||||
neg, trunc: bool;
|
neg, trunc: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
decimal_to_string :: proc(buf: []u8, a: ^Decimal) -> string {
|
decimal_to_string :: proc(buf: []u8, a: ^Decimal) -> string {
|
||||||
@@ -29,13 +28,13 @@ decimal_to_string :: proc(buf: []u8, a: ^Decimal) -> string {
|
|||||||
|
|
||||||
w := 0;
|
w := 0;
|
||||||
if a.decimal_point <= 0 {
|
if a.decimal_point <= 0 {
|
||||||
buf[w] = '0'; w+=1;
|
buf[w] = '0'; w += 1;
|
||||||
buf[w] = '.'; w+=1;
|
buf[w] = '.'; w += 1;
|
||||||
w += digit_zero(buf[w .. w-a.decimal_point]);
|
w += digit_zero(buf[w .. w-a.decimal_point]);
|
||||||
w += copy(buf[w..], a.digits[0..a.count]);
|
w += copy(buf[w..], a.digits[0..a.count]);
|
||||||
} else if a.decimal_point < a.count {
|
} else if a.decimal_point < a.count {
|
||||||
w += copy(buf[w..], a.digits[0..a.decimal_point]);
|
w += copy(buf[w..], a.digits[0..a.decimal_point]);
|
||||||
buf[w] = '.'; w+=1;
|
buf[w] = '.'; w += 1;
|
||||||
w += copy(buf[w..], a.digits[a.decimal_point .. a.count]);
|
w += copy(buf[w..], a.digits[a.decimal_point .. a.count]);
|
||||||
} else {
|
} else {
|
||||||
w += copy(buf[w..], a.digits[0..a.count]);
|
w += copy(buf[w..], a.digits[0..a.count]);
|
||||||
@@ -57,20 +56,20 @@ trim :: proc(a: ^Decimal) {
|
|||||||
|
|
||||||
|
|
||||||
assign :: proc(a: ^Decimal, i: u64) {
|
assign :: proc(a: ^Decimal, i: u64) {
|
||||||
buf: [32]u8;
|
buf: [64]u8;
|
||||||
n := 0;
|
n := 0;
|
||||||
for i > 0 {
|
for i > 0 {
|
||||||
j := i/10;
|
j := i/10;
|
||||||
i -= 10*j;
|
i -= 10*j;
|
||||||
buf[n] = u8('0'+i);
|
buf[n] = u8('0'+i);
|
||||||
n+=1;
|
n += 1;
|
||||||
i = j;
|
i = j;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.count = 0;
|
a.count = 0;
|
||||||
for n -= 1; n >= 0; n -= 1 {
|
for n -= 1; n >= 0; n -= 1 {
|
||||||
a.digits[a.count] = buf[n];
|
a.digits[a.count] = buf[n];
|
||||||
a.count+=1;
|
a.count += 1;
|
||||||
}
|
}
|
||||||
a.decimal_point = a.count;
|
a.decimal_point = a.count;
|
||||||
trim(a);
|
trim(a);
|
||||||
@@ -83,7 +82,7 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
|||||||
w := 0; // write index
|
w := 0; // write index
|
||||||
|
|
||||||
n: uint;
|
n: uint;
|
||||||
for ; n>>k == 0; r+=1 {
|
for ; n>>k == 0; r += 1 {
|
||||||
if r >= a.count {
|
if r >= a.count {
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
// Just in case
|
// Just in case
|
||||||
@@ -92,7 +91,7 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
|||||||
}
|
}
|
||||||
for n>>k == 0 {
|
for n>>k == 0 {
|
||||||
n = n * 10;
|
n = n * 10;
|
||||||
r+=1;
|
r += 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -103,12 +102,12 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
|||||||
|
|
||||||
mask: uint = (1<<k) - 1;
|
mask: uint = (1<<k) - 1;
|
||||||
|
|
||||||
for ; r < a.count; r+=1 {
|
for ; r < a.count; r += 1 {
|
||||||
c := uint(a.digits[r]);
|
c := uint(a.digits[r]);
|
||||||
dig := n>>k;
|
dig := n>>k;
|
||||||
n &= mask;
|
n &= mask;
|
||||||
a.digits[w] = u8('0' + dig);
|
a.digits[w] = u8('0' + dig);
|
||||||
w+=1;
|
w += 1;
|
||||||
n = n*10 + c - '0';
|
n = n*10 + c - '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +116,7 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
|||||||
n &= mask;
|
n &= mask;
|
||||||
if w < len(a.digits) {
|
if w < len(a.digits) {
|
||||||
a.digits[w] = u8('0' + dig);
|
a.digits[w] = u8('0' + dig);
|
||||||
w+=1;
|
w += 1;
|
||||||
} else if dig > 0 {
|
} else if dig > 0 {
|
||||||
a.trunc = true;
|
a.trunc = true;
|
||||||
}
|
}
|
||||||
@@ -171,7 +170,7 @@ shift :: proc(a: ^Decimal, k: int) {
|
|||||||
uint_size :: 8*size_of(uint);
|
uint_size :: 8*size_of(uint);
|
||||||
max_shift :: uint_size-4;
|
max_shift :: uint_size-4;
|
||||||
|
|
||||||
match {
|
switch {
|
||||||
case a.count == 0:
|
case a.count == 0:
|
||||||
// no need to update
|
// no need to update
|
||||||
case k > 0:
|
case k > 0:
|
||||||
@@ -215,7 +214,7 @@ round_up :: proc(a: ^Decimal, nd: int) {
|
|||||||
|
|
||||||
for i := nd-1; i >= 0; i -= 1 {
|
for i := nd-1; i >= 0; i -= 1 {
|
||||||
if c := a.digits[i]; c < '9' {
|
if c := a.digits[i]; c < '9' {
|
||||||
a.digits[i]+=1;
|
a.digits[i] += 1;
|
||||||
a.count = i+1;
|
a.count = i+1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -224,7 +223,7 @@ round_up :: proc(a: ^Decimal, nd: int) {
|
|||||||
// Number is just 9s
|
// Number is just 9s
|
||||||
a.digits[0] = '1';
|
a.digits[0] = '1';
|
||||||
a.count = 1;
|
a.count = 1;
|
||||||
a.decimal_point+=1;
|
a.decimal_point += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
round_down :: proc(a: ^Decimal, nd: int) {
|
round_down :: proc(a: ^Decimal, nd: int) {
|
||||||
@@ -249,7 +248,7 @@ rounded_integer :: proc(a: ^Decimal) -> u64 {
|
|||||||
n *= 10;
|
n *= 10;
|
||||||
}
|
}
|
||||||
if can_round_up(a, a.decimal_point) {
|
if can_round_up(a, a.decimal_point) {
|
||||||
n+=1;
|
n += 1;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|||||||
+143
-130
@@ -1,11 +1,9 @@
|
|||||||
import (
|
import "core:os.odin"
|
||||||
"os.odin";
|
import "core:mem.odin"
|
||||||
"mem.odin";
|
import "core:utf8.odin"
|
||||||
"utf8.odin";
|
import "core:types.odin"
|
||||||
"types.odin";
|
import "core:strconv.odin"
|
||||||
"strconv.odin";
|
import "core:raw.odin"
|
||||||
"raw.odin";
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
_BUFFER_SIZE :: 1<<12;
|
_BUFFER_SIZE :: 1<<12;
|
||||||
@@ -16,36 +14,36 @@ String_Buffer :: union {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Fmt_Info :: struct {
|
Fmt_Info :: struct {
|
||||||
minus: bool;
|
minus: bool,
|
||||||
plus: bool;
|
plus: bool,
|
||||||
space: bool;
|
space: bool,
|
||||||
zero: bool;
|
zero: bool,
|
||||||
hash: bool;
|
hash: bool,
|
||||||
width_set: bool;
|
width_set: bool,
|
||||||
prec_set: bool;
|
prec_set: bool,
|
||||||
|
|
||||||
width: int;
|
width: int,
|
||||||
prec: int;
|
prec: int,
|
||||||
indent: int;
|
indent: int,
|
||||||
|
|
||||||
reordered: bool;
|
reordered: bool,
|
||||||
good_arg_index: bool;
|
good_arg_index: bool,
|
||||||
|
|
||||||
buf: ^String_Buffer;
|
buf: ^String_Buffer,
|
||||||
arg: any; // Temporary
|
arg: any, // Temporary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
string_buffer_data :: proc(buf: ^String_Buffer) -> []u8 {
|
string_buffer_data :: proc(buf: ^String_Buffer) -> []u8 {
|
||||||
match b in buf {
|
switch b in buf {
|
||||||
case []u8: return b[..];
|
case []u8: return b[..];
|
||||||
case [dynamic]u8: return b[..];
|
case [dynamic]u8: return b[..];
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
string_buffer_data :: proc(buf: String_Buffer) -> []u8 {
|
string_buffer_data :: proc(buf: String_Buffer) -> []u8 {
|
||||||
match b in buf {
|
switch b in buf {
|
||||||
case []u8: return b[..];
|
case []u8: return b[..];
|
||||||
case [dynamic]u8: return b[..];
|
case [dynamic]u8: return b[..];
|
||||||
}
|
}
|
||||||
@@ -60,13 +58,13 @@ write_string :: proc(buf: ^String_Buffer, s: string) {
|
|||||||
write_bytes(buf, cast([]u8)s);
|
write_bytes(buf, cast([]u8)s);
|
||||||
}
|
}
|
||||||
write_bytes :: proc(buf: ^String_Buffer, data: []u8) {
|
write_bytes :: proc(buf: ^String_Buffer, data: []u8) {
|
||||||
match b in buf {
|
switch b in buf {
|
||||||
case []u8: append(b, ...data);
|
case []u8: append(b, ...data);
|
||||||
case [dynamic]u8: append(b, ...data);
|
case [dynamic]u8: append(b, ...data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write_byte :: proc(buf: ^String_Buffer, data: u8) {
|
write_byte :: proc(buf: ^String_Buffer, data: u8) {
|
||||||
match b in buf {
|
switch b in buf {
|
||||||
case []u8: append(b, data);
|
case []u8: append(b, data);
|
||||||
case [dynamic]u8: append(b, data);
|
case [dynamic]u8: append(b, data);
|
||||||
}
|
}
|
||||||
@@ -176,53 +174,56 @@ fprint_type :: proc(fd: os.Handle, info: ^Type_Info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||||
if ti == nil do return;
|
if ti == nil {
|
||||||
|
write_string(buf, "nil");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
using Type_Info;
|
switch info in ti.variant {
|
||||||
match info in ti.variant {
|
case Type_Info_Named:
|
||||||
case Named:
|
|
||||||
write_string(buf, info.name);
|
write_string(buf, info.name);
|
||||||
case Integer:
|
case Type_Info_Integer:
|
||||||
match {
|
switch {
|
||||||
case ti == type_info_of(int): write_string(buf, "int");
|
case ti == type_info_of(int): write_string(buf, "int");
|
||||||
case ti == type_info_of(uint): write_string(buf, "uint");
|
case ti == type_info_of(uint): write_string(buf, "uint");
|
||||||
|
case ti == type_info_of(uintptr): write_string(buf, "uintptr");
|
||||||
case:
|
case:
|
||||||
if info.signed do write_byte(buf, 'i');
|
if info.signed do write_byte(buf, 'i');
|
||||||
else do write_byte(buf, 'u');
|
else do write_byte(buf, 'u');
|
||||||
write_int(buf, i64(8*ti.size), 10);
|
write_int(buf, i64(8*ti.size), 10);
|
||||||
}
|
}
|
||||||
case Rune:
|
case Type_Info_Rune:
|
||||||
write_string(buf, "rune");
|
write_string(buf, "rune");
|
||||||
case Float:
|
case Type_Info_Float:
|
||||||
match ti.size {
|
switch ti.size {
|
||||||
case 2: write_string(buf, "f16");
|
case 2: write_string(buf, "f16");
|
||||||
case 4: write_string(buf, "f32");
|
case 4: write_string(buf, "f32");
|
||||||
case 8: write_string(buf, "f64");
|
case 8: write_string(buf, "f64");
|
||||||
}
|
}
|
||||||
case Complex:
|
case Type_Info_Complex:
|
||||||
match ti.size {
|
switch ti.size {
|
||||||
case 4: write_string(buf, "complex32");
|
case 4: write_string(buf, "complex32");
|
||||||
case 8: write_string(buf, "complex64");
|
case 8: write_string(buf, "complex64");
|
||||||
case 16: write_string(buf, "complex128");
|
case 16: write_string(buf, "complex128");
|
||||||
}
|
}
|
||||||
case String: write_string(buf, "string");
|
case Type_Info_String: write_string(buf, "string");
|
||||||
case Boolean: write_string(buf, "bool");
|
case Type_Info_Boolean: write_string(buf, "bool");
|
||||||
case Any:
|
case Type_Info_Any:
|
||||||
write_string(buf, "any");
|
write_string(buf, "any");
|
||||||
|
|
||||||
case Pointer:
|
case Type_Info_Pointer:
|
||||||
if info.elem == nil {
|
if info.elem == nil {
|
||||||
write_string(buf, "rawptr");
|
write_string(buf, "rawptr");
|
||||||
} else {
|
} else {
|
||||||
write_string(buf, "^");
|
write_string(buf, "^");
|
||||||
write_type(buf, info.elem);
|
write_type(buf, info.elem);
|
||||||
}
|
}
|
||||||
case Procedure:
|
case Type_Info_Procedure:
|
||||||
write_string(buf, "proc");
|
write_string(buf, "proc");
|
||||||
if info.params == nil {
|
if info.params == nil {
|
||||||
write_string(buf, "()");
|
write_string(buf, "()");
|
||||||
} else {
|
} else {
|
||||||
t := info.params.variant.(Tuple);
|
t := info.params.variant.(Type_Info_Tuple);
|
||||||
write_string(buf, "(");
|
write_string(buf, "(");
|
||||||
for t, i in t.types {
|
for t, i in t.types {
|
||||||
if i > 0 do write_string(buf, ", ");
|
if i > 0 do write_string(buf, ", ");
|
||||||
@@ -234,7 +235,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
|||||||
write_string(buf, " -> ");
|
write_string(buf, " -> ");
|
||||||
write_type(buf, info.results);
|
write_type(buf, info.results);
|
||||||
}
|
}
|
||||||
case Tuple:
|
case Type_Info_Tuple:
|
||||||
count := len(info.names);
|
count := len(info.names);
|
||||||
if count != 1 do write_string(buf, "(");
|
if count != 1 do write_string(buf, "(");
|
||||||
for name, i in info.names {
|
for name, i in info.names {
|
||||||
@@ -250,31 +251,31 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
|||||||
}
|
}
|
||||||
if count != 1 do write_string(buf, ")");
|
if count != 1 do write_string(buf, ")");
|
||||||
|
|
||||||
case Array:
|
case Type_Info_Array:
|
||||||
write_string(buf, "[");
|
write_string(buf, "[");
|
||||||
fi := Fmt_Info{buf = buf};
|
fi := Fmt_Info{buf = buf};
|
||||||
write_int(buf, i64(info.count), 10);
|
write_int(buf, i64(info.count), 10);
|
||||||
write_string(buf, "]");
|
write_string(buf, "]");
|
||||||
write_type(buf, info.elem);
|
write_type(buf, info.elem);
|
||||||
case Dynamic_Array:
|
case Type_Info_Dynamic_Array:
|
||||||
write_string(buf, "[dynamic]");
|
write_string(buf, "[dynamic]");
|
||||||
write_type(buf, info.elem);
|
write_type(buf, info.elem);
|
||||||
case Slice:
|
case Type_Info_Slice:
|
||||||
write_string(buf, "[]");
|
write_string(buf, "[]");
|
||||||
write_type(buf, info.elem);
|
write_type(buf, info.elem);
|
||||||
case Vector:
|
case Type_Info_Vector:
|
||||||
write_string(buf, "[vector ");
|
write_string(buf, "[vector ");
|
||||||
write_int(buf, i64(info.count), 10);
|
write_int(buf, i64(info.count), 10);
|
||||||
write_string(buf, "]");
|
write_string(buf, "]");
|
||||||
write_type(buf, info.elem);
|
write_type(buf, info.elem);
|
||||||
|
|
||||||
case Map:
|
case Type_Info_Map:
|
||||||
write_string(buf, "map[");
|
write_string(buf, "map[");
|
||||||
write_type(buf, info.key);
|
write_type(buf, info.key);
|
||||||
write_byte(buf, ']');
|
write_byte(buf, ']');
|
||||||
write_type(buf, info.value);
|
write_type(buf, info.value);
|
||||||
|
|
||||||
case Struct:
|
case Type_Info_Struct:
|
||||||
write_string(buf, "struct ");
|
write_string(buf, "struct ");
|
||||||
if info.is_packed do write_string(buf, "#packed ");
|
if info.is_packed do write_string(buf, "#packed ");
|
||||||
if info.is_ordered do write_string(buf, "#ordered ");
|
if info.is_ordered do write_string(buf, "#ordered ");
|
||||||
@@ -293,7 +294,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
|||||||
}
|
}
|
||||||
write_byte(buf, '}');
|
write_byte(buf, '}');
|
||||||
|
|
||||||
case Union:
|
case Type_Info_Union:
|
||||||
write_string(buf, "union {");
|
write_string(buf, "union {");
|
||||||
for variant, i in info.variants {
|
for variant, i in info.variants {
|
||||||
if i > 0 do write_string(buf, ", ");
|
if i > 0 do write_string(buf, ", ");
|
||||||
@@ -301,7 +302,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
|||||||
}
|
}
|
||||||
write_string(buf, "}");
|
write_string(buf, "}");
|
||||||
|
|
||||||
case Enum:
|
case Type_Info_Enum:
|
||||||
write_string(buf, "enum ");
|
write_string(buf, "enum ");
|
||||||
write_type(buf, info.base);
|
write_type(buf, info.base);
|
||||||
write_string(buf, " {");
|
write_string(buf, " {");
|
||||||
@@ -311,7 +312,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
|||||||
}
|
}
|
||||||
write_string(buf, "}");
|
write_string(buf, "}");
|
||||||
|
|
||||||
case Bit_Field:
|
case Type_Info_Bit_Field:
|
||||||
write_string(buf, "bit_field ");
|
write_string(buf, "bit_field ");
|
||||||
if ti.align != 1 {
|
if ti.align != 1 {
|
||||||
write_string(buf, "#align ");
|
write_string(buf, "#align ");
|
||||||
@@ -326,13 +327,12 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
|||||||
write_int(buf, i64(info.bits[i]), 10);
|
write_int(buf, i64(info.bits[i]), 10);
|
||||||
}
|
}
|
||||||
write_string(buf, "}");
|
write_string(buf, "}");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: bool) {
|
_parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: bool) {
|
||||||
is_digit :: proc(r: rune) -> bool #inline {
|
is_digit :: inline proc(r: rune) -> bool{
|
||||||
return '0' <= r && r <= '9';
|
return '0' <= r && r <= '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,7 +389,7 @@ int_from_arg :: proc(args: []any, arg_index: int) -> (int, int, bool) {
|
|||||||
if arg_index < len(args) {
|
if arg_index < len(args) {
|
||||||
arg := args[arg_index];
|
arg := args[arg_index];
|
||||||
arg.type_info = type_info_base(arg.type_info);
|
arg.type_info = type_info_base(arg.type_info);
|
||||||
match i in arg {
|
switch i in arg {
|
||||||
case int: num = i;
|
case int: num = i;
|
||||||
case i8: num = int(i);
|
case i8: num = int(i);
|
||||||
case i16: num = int(i);
|
case i16: num = int(i);
|
||||||
@@ -424,7 +424,7 @@ fmt_bad_verb :: proc(using fi: ^Fmt_Info, verb: rune) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt_bool :: proc(using fi: ^Fmt_Info, b: bool, verb: rune) {
|
fmt_bool :: proc(using fi: ^Fmt_Info, b: bool, verb: rune) {
|
||||||
match verb {
|
switch verb {
|
||||||
case 't', 'v':
|
case 't', 'v':
|
||||||
s := "false";
|
s := "false";
|
||||||
if b do s = "true";
|
if b do s = "true";
|
||||||
@@ -476,7 +476,7 @@ _fmt_int :: proc(fi: ^Fmt_Info, u: u128, base: int, is_signed: bool, bit_size: i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match base {
|
switch base {
|
||||||
case 2, 8, 10, 12, 16:
|
case 2, 8, 10, 12, 16:
|
||||||
break;
|
break;
|
||||||
case:
|
case:
|
||||||
@@ -494,10 +494,10 @@ _fmt_int :: proc(fi: ^Fmt_Info, u: u128, base: int, is_signed: bool, bit_size: i
|
|||||||
|
|
||||||
if fi.hash && fi.zero {
|
if fi.hash && fi.zero {
|
||||||
c: u8;
|
c: u8;
|
||||||
match base {
|
switch base {
|
||||||
case 2: c = 'b';
|
case 2: c = 'b';
|
||||||
case 8: c = 'o';
|
case 8: c = 'o';
|
||||||
case 10: c = 'd';
|
// case 10: c = 'd';
|
||||||
case 12: c = 'z';
|
case 12: c = 'z';
|
||||||
case 16: c = 'x';
|
case 16: c = 'x';
|
||||||
}
|
}
|
||||||
@@ -518,7 +518,7 @@ __DIGITS_LOWER := "0123456789abcdefx";
|
|||||||
__DIGITS_UPPER := "0123456789ABCDEFX";
|
__DIGITS_UPPER := "0123456789ABCDEFX";
|
||||||
|
|
||||||
fmt_rune :: proc(fi: ^Fmt_Info, r: rune, verb: rune) {
|
fmt_rune :: proc(fi: ^Fmt_Info, r: rune, verb: rune) {
|
||||||
match verb {
|
switch verb {
|
||||||
case 'c', 'r', 'v':
|
case 'c', 'r', 'v':
|
||||||
write_rune(fi.buf, r);
|
write_rune(fi.buf, r);
|
||||||
case:
|
case:
|
||||||
@@ -527,7 +527,7 @@ fmt_rune :: proc(fi: ^Fmt_Info, r: rune, verb: rune) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt_int :: proc(fi: ^Fmt_Info, u: u128, is_signed: bool, bit_size: int, verb: rune) {
|
fmt_int :: proc(fi: ^Fmt_Info, u: u128, is_signed: bool, bit_size: int, verb: rune) {
|
||||||
match verb {
|
switch verb {
|
||||||
case 'v': _fmt_int(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER);
|
case 'v': _fmt_int(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER);
|
||||||
case 'b': _fmt_int(fi, u, 2, is_signed, bit_size, __DIGITS_LOWER);
|
case 'b': _fmt_int(fi, u, 2, is_signed, bit_size, __DIGITS_LOWER);
|
||||||
case 'o': _fmt_int(fi, u, 8, is_signed, bit_size, __DIGITS_LOWER);
|
case 'o': _fmt_int(fi, u, 8, is_signed, bit_size, __DIGITS_LOWER);
|
||||||
@@ -569,7 +569,7 @@ _pad :: proc(fi: ^Fmt_Info, s: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) {
|
fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) {
|
||||||
match verb {
|
switch verb {
|
||||||
// case 'e', 'E', 'f', 'F', 'g', 'G', 'v':
|
// case 'e', 'E', 'f', 'F', 'g', 'G', 'v':
|
||||||
// case 'f', 'F', 'v':
|
// case 'f', 'F', 'v':
|
||||||
|
|
||||||
@@ -612,7 +612,7 @@ fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt_string :: proc(fi: ^Fmt_Info, s: string, verb: rune) {
|
fmt_string :: proc(fi: ^Fmt_Info, s: string, verb: rune) {
|
||||||
match verb {
|
switch verb {
|
||||||
case 's', 'v':
|
case 's', 'v':
|
||||||
write_string(fi.buf, s);
|
write_string(fi.buf, s);
|
||||||
|
|
||||||
@@ -634,14 +634,14 @@ fmt_string :: proc(fi: ^Fmt_Info, s: string, verb: rune) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) {
|
fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) {
|
||||||
match verb {
|
switch verb {
|
||||||
case 'p', 'v':
|
case 'p', 'v':
|
||||||
// Okay
|
// Okay
|
||||||
case:
|
case:
|
||||||
fmt_bad_verb(fi, verb);
|
fmt_bad_verb(fi, verb);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
u := u128(uint(p));
|
u := u128(uintptr(p));
|
||||||
if !fi.hash || verb == 'v' {
|
if !fi.hash || verb == 'v' {
|
||||||
write_string(fi.buf, "0x");
|
write_string(fi.buf, "0x");
|
||||||
}
|
}
|
||||||
@@ -651,11 +651,10 @@ fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) {
|
|||||||
enum_value_to_string :: proc(v: any) -> (string, bool) {
|
enum_value_to_string :: proc(v: any) -> (string, bool) {
|
||||||
v.type_info = type_info_base(v.type_info);
|
v.type_info = type_info_base(v.type_info);
|
||||||
|
|
||||||
using Type_Info;
|
switch e in v.type_info.variant {
|
||||||
match e in v.type_info.variant {
|
|
||||||
case: return "", false;
|
case: return "", false;
|
||||||
case Enum:
|
case Type_Info_Enum:
|
||||||
get_str :: proc(i: $T, e: Enum) -> (string, bool) {
|
get_str :: proc(i: $T, e: Type_Info_Enum) -> (string, bool) {
|
||||||
if types.is_string(e.base) {
|
if types.is_string(e.base) {
|
||||||
for val, idx in e.values {
|
for val, idx in e.values {
|
||||||
if v, ok := val.(T); ok && v == i {
|
if v, ok := val.(T); ok && v == i {
|
||||||
@@ -675,20 +674,21 @@ enum_value_to_string :: proc(v: any) -> (string, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a := any{v.data, type_info_base(e.base)};
|
a := any{v.data, type_info_base(e.base)};
|
||||||
match v in a {
|
switch v in a {
|
||||||
case rune: return get_str(v, e);
|
case rune: return get_str(v, e);
|
||||||
case i8: return get_str(v, e);
|
case i8: return get_str(v, e);
|
||||||
case i16: return get_str(v, e);
|
case i16: return get_str(v, e);
|
||||||
case i32: return get_str(v, e);
|
case i32: return get_str(v, e);
|
||||||
case i64: return get_str(v, e);
|
case i64: return get_str(v, e);
|
||||||
case i128: return get_str(v, e);
|
case i128: return get_str(v, e);
|
||||||
case int: return get_str(v, e);
|
case int: return get_str(v, e);
|
||||||
case u8: return get_str(v, e);
|
case u8: return get_str(v, e);
|
||||||
case u16: return get_str(v, e);
|
case u16: return get_str(v, e);
|
||||||
case u32: return get_str(v, e);
|
case u32: return get_str(v, e);
|
||||||
case u64: return get_str(v, e);
|
case u64: return get_str(v, e);
|
||||||
case u128: return get_str(v, e);
|
case u128: return get_str(v, e);
|
||||||
case uint: return get_str(v, e);
|
case uint: return get_str(v, e);
|
||||||
|
case uintptr: return get_str(v, e);
|
||||||
|
|
||||||
case f32: return get_str(v, e);
|
case f32: return get_str(v, e);
|
||||||
case f64: return get_str(v, e);
|
case f64: return get_str(v, e);
|
||||||
@@ -700,7 +700,7 @@ enum_value_to_string :: proc(v: any) -> (string, bool) {
|
|||||||
|
|
||||||
string_to_enum_value :: proc(T: type, s: string) -> (T, bool) {
|
string_to_enum_value :: proc(T: type, s: string) -> (T, bool) {
|
||||||
ti := type_info_base(type_info_of(T));
|
ti := type_info_base(type_info_of(T));
|
||||||
if e, ok := ti.variant.(Type_Info.Enum); ok {
|
if e, ok := ti.variant.(Type_Info_Enum); ok {
|
||||||
for str, idx in e.names {
|
for str, idx in e.names {
|
||||||
if s == str {
|
if s == str {
|
||||||
// NOTE(bill): Unsafe cast
|
// NOTE(bill): Unsafe cast
|
||||||
@@ -718,11 +718,10 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using Type_Info;
|
switch e in v.type_info.variant {
|
||||||
match e in v.type_info.variant {
|
|
||||||
case: fmt_bad_verb(fi, verb);
|
case: fmt_bad_verb(fi, verb);
|
||||||
case Enum:
|
case Type_Info_Enum:
|
||||||
match verb {
|
switch verb {
|
||||||
case: fmt_bad_verb(fi, verb);
|
case: fmt_bad_verb(fi, verb);
|
||||||
case 'd', 'f':
|
case 'd', 'f':
|
||||||
fmt_arg(fi, any{v.data, type_info_base(e.base)}, verb);
|
fmt_arg(fi, any{v.data, type_info_base(e.base)}, verb);
|
||||||
@@ -741,11 +740,10 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using Type_Info;
|
switch info in v.type_info.variant {
|
||||||
match info in v.type_info.variant {
|
case Type_Info_Named:
|
||||||
case Named:
|
switch b in info.base.variant {
|
||||||
match b in info.base.variant {
|
case Type_Info_Struct:
|
||||||
case Struct:
|
|
||||||
if verb != 'v' {
|
if verb != 'v' {
|
||||||
fmt_bad_verb(fi, verb);
|
fmt_bad_verb(fi, verb);
|
||||||
return;
|
return;
|
||||||
@@ -757,7 +755,6 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
}
|
}
|
||||||
write_string(fi.buf, info.name);
|
write_string(fi.buf, info.name);
|
||||||
write_byte(fi.buf, '{');
|
write_byte(fi.buf, '{');
|
||||||
defer write_byte(fi.buf, '}');
|
|
||||||
|
|
||||||
hash := fi.hash; defer fi.hash = hash;
|
hash := fi.hash; defer fi.hash = hash;
|
||||||
indent := fi.indent; defer fi.indent -= 1;
|
indent := fi.indent; defer fi.indent -= 1;
|
||||||
@@ -769,11 +766,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
|
|
||||||
for _, i in b.names {
|
for _, i in b.names {
|
||||||
if !hash && i > 0 do write_string(fi.buf, ", ");
|
if !hash && i > 0 do write_string(fi.buf, ", ");
|
||||||
if hash {
|
if hash do for in 0..fi.indent do write_byte(fi.buf, '\t');
|
||||||
for in 0..fi.indent {
|
|
||||||
write_byte(fi.buf, '\t');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
write_string(fi.buf, b.names[i]);
|
write_string(fi.buf, b.names[i]);
|
||||||
write_string(fi.buf, " = ");
|
write_string(fi.buf, " = ");
|
||||||
@@ -788,25 +781,28 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
if hash do write_string(fi.buf, ",\n");
|
if hash do write_string(fi.buf, ",\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if hash do for in 0..indent do write_byte(fi.buf, '\t');
|
||||||
|
write_byte(fi.buf, '}');
|
||||||
|
|
||||||
case:
|
case:
|
||||||
fmt_value(fi, any{v.data, info.base}, verb);
|
fmt_value(fi, any{v.data, info.base}, verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Boolean: fmt_arg(fi, v, verb);
|
case Type_Info_Boolean: fmt_arg(fi, v, verb);
|
||||||
case Integer: fmt_arg(fi, v, verb);
|
case Type_Info_Integer: fmt_arg(fi, v, verb);
|
||||||
case Rune: fmt_arg(fi, v, verb);
|
case Type_Info_Rune: fmt_arg(fi, v, verb);
|
||||||
case Float: fmt_arg(fi, v, verb);
|
case Type_Info_Float: fmt_arg(fi, v, verb);
|
||||||
case Complex: fmt_arg(fi, v, verb);
|
case Type_Info_Complex: fmt_arg(fi, v, verb);
|
||||||
case String: fmt_arg(fi, v, verb);
|
case Type_Info_String: fmt_arg(fi, v, verb);
|
||||||
|
|
||||||
case Pointer:
|
case Type_Info_Pointer:
|
||||||
if v.type_info == type_info_of(^Type_Info) {
|
if v.type_info == type_info_of(^Type_Info) {
|
||||||
write_type(fi.buf, (cast(^^Type_Info)v.data)^);
|
write_type(fi.buf, (cast(^^Type_Info)v.data)^);
|
||||||
} else {
|
} else {
|
||||||
fmt_pointer(fi, (cast(^rawptr)v.data)^, verb);
|
fmt_pointer(fi, (cast(^rawptr)v.data)^, verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Array:
|
case Type_Info_Array:
|
||||||
write_byte(fi.buf, '[');
|
write_byte(fi.buf, '[');
|
||||||
defer write_byte(fi.buf, ']');
|
defer write_byte(fi.buf, ']');
|
||||||
for i in 0..info.count {
|
for i in 0..info.count {
|
||||||
@@ -816,7 +812,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Dynamic_Array:
|
case Type_Info_Dynamic_Array:
|
||||||
write_byte(fi.buf, '[');
|
write_byte(fi.buf, '[');
|
||||||
defer write_byte(fi.buf, ']');
|
defer write_byte(fi.buf, ']');
|
||||||
array := cast(^raw.Dynamic_Array)v.data;
|
array := cast(^raw.Dynamic_Array)v.data;
|
||||||
@@ -827,7 +823,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Slice:
|
case Type_Info_Slice:
|
||||||
write_byte(fi.buf, '[');
|
write_byte(fi.buf, '[');
|
||||||
defer write_byte(fi.buf, ']');
|
defer write_byte(fi.buf, ']');
|
||||||
slice := cast(^[]u8)v.data;
|
slice := cast(^[]u8)v.data;
|
||||||
@@ -838,7 +834,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Vector:
|
case Type_Info_Vector:
|
||||||
write_byte(fi.buf, '<');
|
write_byte(fi.buf, '<');
|
||||||
defer write_byte(fi.buf, '>');
|
defer write_byte(fi.buf, '>');
|
||||||
|
|
||||||
@@ -849,7 +845,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
fmt_value(fi, any{rawptr(data), info.elem}, verb);
|
fmt_value(fi, any{rawptr(data), info.elem}, verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Map:
|
case Type_Info_Map:
|
||||||
if verb != 'v' {
|
if verb != 'v' {
|
||||||
fmt_bad_verb(fi, verb);
|
fmt_bad_verb(fi, verb);
|
||||||
return;
|
return;
|
||||||
@@ -859,9 +855,9 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
defer write_byte(fi.buf, ']');
|
defer write_byte(fi.buf, ']');
|
||||||
|
|
||||||
entries := &((cast(^raw.Map)v.data).entries);
|
entries := &((cast(^raw.Map)v.data).entries);
|
||||||
gs := type_info_base(info.generated_struct).variant.(Struct);
|
gs := type_info_base(info.generated_struct).variant.(Type_Info_Struct);
|
||||||
ed := type_info_base(gs.types[1]).variant.(Dynamic_Array);
|
ed := type_info_base(gs.types[1]).variant.(Type_Info_Dynamic_Array);
|
||||||
entry_type := ed.elem.variant.(Struct);
|
entry_type := ed.elem.variant.(Type_Info_Struct);
|
||||||
entry_size := ed.elem_size;
|
entry_size := ed.elem_size;
|
||||||
|
|
||||||
for i in 0..entries.len {
|
for i in 0..entries.len {
|
||||||
@@ -885,7 +881,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
case Struct:
|
case Type_Info_Struct:
|
||||||
if info.is_raw_union {
|
if info.is_raw_union {
|
||||||
write_string(fi.buf, "(raw_union)");
|
write_string(fi.buf, "(raw_union)");
|
||||||
return;
|
return;
|
||||||
@@ -922,20 +918,37 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
if hash do write_string(fi.buf, ",\n");
|
if hash do write_string(fi.buf, ",\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
case Union:
|
case Type_Info_Union:
|
||||||
data := cast(^u8)v.data;
|
data := cast(^u8)v.data;
|
||||||
tipp := cast(^^Type_Info)(data + info.tag_offset);
|
tag_ptr := rawptr(data + info.tag_offset);
|
||||||
if data == nil || tipp == nil {
|
tag_any := any{tag_ptr, info.tag_type};
|
||||||
|
|
||||||
|
tag: i64 = -1;
|
||||||
|
switch i in tag_any {
|
||||||
|
case u8: tag = i64(i);
|
||||||
|
case i8: tag = i64(i);
|
||||||
|
case u16: tag = i64(i);
|
||||||
|
case i16: tag = i64(i);
|
||||||
|
case u32: tag = i64(i);
|
||||||
|
case i32: tag = i64(i);
|
||||||
|
case u64: tag = i64(i);
|
||||||
|
case i64: tag = i64(i);
|
||||||
|
case u128: tag = i64(i);
|
||||||
|
case i128: tag = i64(i);
|
||||||
|
case: panic("Invalid union tag type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if data == nil || tag <= 0 {
|
||||||
write_string(fi.buf, "(union)");
|
write_string(fi.buf, "(union)");
|
||||||
} else {
|
} else {
|
||||||
ti := tipp^;
|
ti := info.variants[tag-1];
|
||||||
fmt_arg(fi, any{data, ti}, verb);
|
fmt_arg(fi, any{data, ti}, verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Enum:
|
case Type_Info_Enum:
|
||||||
fmt_enum(fi, v, verb);
|
fmt_enum(fi, v, verb);
|
||||||
|
|
||||||
case Procedure:
|
case Type_Info_Procedure:
|
||||||
write_type(fi.buf, v.type_info);
|
write_type(fi.buf, v.type_info);
|
||||||
write_string(fi.buf, " @ ");
|
write_string(fi.buf, " @ ");
|
||||||
fmt_pointer(fi, (cast(^rawptr)v.data)^, 'p');
|
fmt_pointer(fi, (cast(^rawptr)v.data)^, 'p');
|
||||||
@@ -943,7 +956,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt_complex :: proc(fi: ^Fmt_Info, c: complex128, bits: int, verb: rune) {
|
fmt_complex :: proc(fi: ^Fmt_Info, c: complex128, bits: int, verb: rune) {
|
||||||
match verb {
|
switch verb {
|
||||||
case 'f', 'F', 'v':
|
case 'f', 'F', 'v':
|
||||||
r, i := real(c), imag(c);
|
r, i := real(c), imag(c);
|
||||||
fmt_float(fi, r, bits/2, verb);
|
fmt_float(fi, r, bits/2, verb);
|
||||||
@@ -976,7 +989,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
|
|||||||
|
|
||||||
if verb == 'T' {
|
if verb == 'T' {
|
||||||
ti := arg.type_info;
|
ti := arg.type_info;
|
||||||
match a in arg {
|
switch a in arg {
|
||||||
case ^Type_Info: ti = a;
|
case ^Type_Info: ti = a;
|
||||||
}
|
}
|
||||||
write_type(fi.buf, ti);
|
write_type(fi.buf, ti);
|
||||||
@@ -986,7 +999,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
|
|||||||
|
|
||||||
base_arg := arg;
|
base_arg := arg;
|
||||||
base_arg.type_info = type_info_base(base_arg.type_info);
|
base_arg.type_info = type_info_base(base_arg.type_info);
|
||||||
match a in base_arg {
|
switch a in base_arg {
|
||||||
case any: fmt_arg(fi, a, verb);
|
case any: fmt_arg(fi, a, verb);
|
||||||
case bool: fmt_bool(fi, a, verb);
|
case bool: fmt_bool(fi, a, verb);
|
||||||
case rune: fmt_rune(fi, a, verb);
|
case rune: fmt_rune(fi, a, verb);
|
||||||
@@ -1004,6 +1017,8 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
|
|||||||
case i64: fmt_int(fi, u128(a), true, 64, verb);
|
case i64: fmt_int(fi, u128(a), true, 64, verb);
|
||||||
case i128: fmt_int(fi, u128(a), true, 128, verb);
|
case i128: fmt_int(fi, u128(a), true, 128, verb);
|
||||||
|
|
||||||
|
case uintptr: fmt_int(fi, u128(a), false, 8*size_of(uintptr), verb);
|
||||||
|
|
||||||
case uint: fmt_int(fi, u128(a), false, 8*size_of(uint), verb);
|
case uint: fmt_int(fi, u128(a), false, 8*size_of(uint), verb);
|
||||||
case u8: fmt_int(fi, u128(a), false, 8, verb);
|
case u8: fmt_int(fi, u128(a), false, 8, verb);
|
||||||
case u16: fmt_int(fi, u128(a), false, 16, verb);
|
case u16: fmt_int(fi, u128(a), false, 16, verb);
|
||||||
@@ -1011,10 +1026,8 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
|
|||||||
case u64: fmt_int(fi, u128(a), false, 64, verb);
|
case u64: fmt_int(fi, u128(a), false, 64, verb);
|
||||||
case u128: fmt_int(fi, u128(a), false, 128, verb);
|
case u128: fmt_int(fi, u128(a), false, 128, verb);
|
||||||
|
|
||||||
|
|
||||||
case string: fmt_string(fi, a, verb);
|
case string: fmt_string(fi, a, verb);
|
||||||
|
|
||||||
|
|
||||||
case: fmt_value(fi, arg, verb);
|
case: fmt_value(fi, arg, verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1077,7 +1090,7 @@ sbprintf :: proc(b: ^String_Buffer, fmt: string, args: ...any) -> string {
|
|||||||
i += 1;
|
i += 1;
|
||||||
|
|
||||||
prefix_loop: for ; i < end; i += 1 {
|
prefix_loop: for ; i < end; i += 1 {
|
||||||
match fmt[i] {
|
switch fmt[i] {
|
||||||
case '+':
|
case '+':
|
||||||
fi.plus = true;
|
fi.plus = true;
|
||||||
case '-':
|
case '-':
|
||||||
|
|||||||
+14
-4
@@ -1,4 +1,14 @@
|
|||||||
import "mem.odin";
|
import "core:mem.odin"
|
||||||
|
|
||||||
|
adler32 :: proc(data: []u8) -> u32 {
|
||||||
|
ADLER_CONST :: 65521;
|
||||||
|
a, b: u32 = 1, 0;
|
||||||
|
for x in data {
|
||||||
|
a = (a + u32(x)) % ADLER_CONST;
|
||||||
|
b = (b + a) % ADLER_CONST;
|
||||||
|
}
|
||||||
|
return (b << 16) | a;
|
||||||
|
}
|
||||||
|
|
||||||
crc32 :: proc(data: []u8) -> u32 {
|
crc32 :: proc(data: []u8) -> u32 {
|
||||||
result := ~u32(0);
|
result := ~u32(0);
|
||||||
@@ -70,7 +80,7 @@ murmur32 :: proc(data: []u8) -> u32 {
|
|||||||
|
|
||||||
tail := data[nblocks*4 ..];
|
tail := data[nblocks*4 ..];
|
||||||
k1: u32;
|
k1: u32;
|
||||||
match len(tail)&3 {
|
switch len(tail)&3 {
|
||||||
case 3:
|
case 3:
|
||||||
k1 ~= u32(tail[2]) << 16;
|
k1 ~= u32(tail[2]) << 16;
|
||||||
fallthrough;
|
fallthrough;
|
||||||
@@ -117,7 +127,7 @@ murmur64 :: proc(data: []u8) -> u64 {
|
|||||||
h *= m;
|
h *= m;
|
||||||
}
|
}
|
||||||
|
|
||||||
match len(data)&7 {
|
switch len(data)&7 {
|
||||||
case 7: h ~= u64(data[6]) << 48; fallthrough;
|
case 7: h ~= u64(data[6]) << 48; fallthrough;
|
||||||
case 6: h ~= u64(data[5]) << 40; fallthrough;
|
case 6: h ~= u64(data[5]) << 40; fallthrough;
|
||||||
case 5: h ~= u64(data[4]) << 32; fallthrough;
|
case 5: h ~= u64(data[4]) << 32; fallthrough;
|
||||||
@@ -176,7 +186,7 @@ murmur64 :: proc(data: []u8) -> u64 {
|
|||||||
|
|
||||||
// TODO(bill): Fix this
|
// TODO(bill): Fix this
|
||||||
#no_bounds_check data8 := slice_to_bytes(data32[i..])[..3];
|
#no_bounds_check data8 := slice_to_bytes(data32[i..])[..3];
|
||||||
match len {
|
switch len {
|
||||||
case 3:
|
case 3:
|
||||||
h2 ~= u32(data8[2]) << 16;
|
h2 ~= u32(data8[2]) << 16;
|
||||||
fallthrough;
|
fallthrough;
|
||||||
|
|||||||
+67
-72
@@ -16,9 +16,9 @@ EPSILON :: 1.19209290e-7;
|
|||||||
τ :: TAU;
|
τ :: TAU;
|
||||||
π :: PI;
|
π :: PI;
|
||||||
|
|
||||||
Vec2 :: [vector 2]f32;
|
Vec2 :: [2]f32;
|
||||||
Vec3 :: [vector 3]f32;
|
Vec3 :: [3]f32;
|
||||||
Vec4 :: [vector 4]f32;
|
Vec4 :: [4]f32;
|
||||||
|
|
||||||
// Column major
|
// Column major
|
||||||
Mat2 :: [2][2]f32;
|
Mat2 :: [2][2]f32;
|
||||||
@@ -27,35 +27,45 @@ Mat4 :: [4][4]f32;
|
|||||||
|
|
||||||
Complex :: complex64;
|
Complex :: complex64;
|
||||||
|
|
||||||
|
@(default_calling_convention="c")
|
||||||
foreign __llvm_core {
|
foreign __llvm_core {
|
||||||
sqrt :: proc(x: f32) -> f32 #link_name "llvm.sqrt.f32" ---;
|
@(link_name="llvm.sqrt.f32")
|
||||||
sqrt :: proc(x: f64) -> f64 #link_name "llvm.sqrt.f64" ---;
|
sqrt :: proc(x: f32) -> f32 ---;
|
||||||
|
@(link_name="llvm.sqrt.f64")
|
||||||
|
sqrt :: proc(x: f64) -> f64 ---;
|
||||||
|
|
||||||
sin :: proc(θ: f32) -> f32 #link_name "llvm.sin.f32" ---;
|
@(link_name="llvm.sin.f32")
|
||||||
sin :: proc(θ: f64) -> f64 #link_name "llvm.sin.f64" ---;
|
sin :: proc(θ: f32) -> f32 ---;
|
||||||
|
@(link_name="llvm.sin.f64")
|
||||||
|
sin :: proc(θ: f64) -> f64 ---;
|
||||||
|
|
||||||
cos :: proc(θ: f32) -> f32 #link_name "llvm.cos.f32" ---;
|
@(link_name="llvm.cos.f32")
|
||||||
cos :: proc(θ: f64) -> f64 #link_name "llvm.cos.f64" ---;
|
cos :: proc(θ: f32) -> f32 ---;
|
||||||
|
@(link_name="llvm.cos.f64")
|
||||||
|
cos :: proc(θ: f64) -> f64 ---;
|
||||||
|
|
||||||
pow :: proc(x, power: f32) -> f32 #link_name "llvm.pow.f32" ---;
|
@(link_name="llvm.pow.f32")
|
||||||
pow :: proc(x, power: f64) -> f64 #link_name "llvm.pow.f64" ---;
|
pow :: proc(x, power: f32) -> f32 ---;
|
||||||
|
@(link_name="llvm.pow.f64")
|
||||||
|
pow :: proc(x, power: f64) -> f64 ---;
|
||||||
|
|
||||||
fmuladd :: proc(a, b, c: f32) -> f32 #link_name "llvm.fmuladd.f32" ---;
|
@(link_name="llvm.fmuladd.f32")
|
||||||
fmuladd :: proc(a, b, c: f64) -> f64 #link_name "llvm.fmuladd.f64" ---;
|
fmuladd :: proc(a, b, c: f32) -> f32 ---;
|
||||||
|
@(link_name="llvm.fmuladd.f64")
|
||||||
|
fmuladd :: proc(a, b, c: f64) -> f64 ---;
|
||||||
}
|
}
|
||||||
|
|
||||||
tan :: proc(θ: f32) -> f32 #inline do return sin(θ)/cos(θ);
|
tan :: proc "c" (θ: f32) -> f32 do return sin(θ)/cos(θ);
|
||||||
tan :: proc(θ: f64) -> f64 #inline do return sin(θ)/cos(θ);
|
tan :: proc "c" (θ: f64) -> f64 do return sin(θ)/cos(θ);
|
||||||
|
|
||||||
|
lerp :: proc(a, b: $T, t: $E) -> (x: T) do return a*(1-t) + b*t;
|
||||||
|
|
||||||
lerp :: proc(a, b, t: f32) -> (x: f32) do return a*(1-t) + b*t;
|
|
||||||
lerp :: proc(a, b, t: f64) -> (x: f64) do return a*(1-t) + b*t;
|
|
||||||
unlerp :: proc(a, b, x: f32) -> (t: f32) do return (x-a)/(b-a);
|
unlerp :: proc(a, b, x: f32) -> (t: f32) do return (x-a)/(b-a);
|
||||||
unlerp :: proc(a, b, x: f64) -> (t: f64) do return (x-a)/(b-a);
|
unlerp :: proc(a, b, x: f64) -> (t: f64) do return (x-a)/(b-a);
|
||||||
|
|
||||||
|
|
||||||
sign :: proc(x: f32) -> f32 { if x >= 0 do return +1; return -1; }
|
sign :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
|
||||||
sign :: proc(x: f64) -> f64 { if x >= 0 do return +1; return -1; }
|
sign :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -75,14 +85,14 @@ copy_sign :: proc(x, y: f64) -> f64 {
|
|||||||
return transmute(f64)ix;
|
return transmute(f64)ix;
|
||||||
}
|
}
|
||||||
|
|
||||||
round :: proc(x: f32) -> f32 { if x >= 0 do return floor(x + 0.5); return ceil(x - 0.5); }
|
round :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
||||||
round :: proc(x: f64) -> f64 { if x >= 0 do return floor(x + 0.5); return ceil(x - 0.5); }
|
round :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
||||||
|
|
||||||
floor :: proc(x: f32) -> f32 { if x >= 0 do return f32(i64(x)); return f32(i64(x-0.5)); } // TODO: Get accurate versions
|
floor :: proc(x: f32) -> f32 { return x >= 0 ? f32(i64(x)) : f32(i64(x-0.5)); } // TODO: Get accurate versions
|
||||||
floor :: proc(x: f64) -> f64 { if x >= 0 do return f64(i64(x)); return f64(i64(x-0.5)); } // TODO: Get accurate versions
|
floor :: proc(x: f64) -> f64 { return x >= 0 ? f64(i64(x)) : f64(i64(x-0.5)); } // TODO: Get accurate versions
|
||||||
|
|
||||||
ceil :: proc(x: f32) -> f32 { if x < 0 do return f32(i64(x)); return f32(i64(x+1)); }// TODO: Get accurate versions
|
ceil :: proc(x: f32) -> f32 { return x < 0 ? f32(i64(x)) : f32(i64(x+1)); }// TODO: Get accurate versions
|
||||||
ceil :: proc(x: f64) -> f64 { if x < 0 do return f64(i64(x)); return f64(i64(x+1)); }// TODO: Get accurate versions
|
ceil :: proc(x: f64) -> f64 { return x < 0 ? f64(i64(x)) : f64(i64(x+1)); }// TODO: Get accurate versions
|
||||||
|
|
||||||
remainder :: proc(x, y: f32) -> f32 do return x - round(x/y) * y;
|
remainder :: proc(x, y: f32) -> f32 do return x - round(x/y) * y;
|
||||||
remainder :: proc(x, y: f64) -> f64 do return x - round(x/y) * y;
|
remainder :: proc(x, y: f64) -> f64 do return x - round(x/y) * y;
|
||||||
@@ -112,41 +122,26 @@ to_degrees :: proc(radians: f32) -> f32 do return radians * 360 / TAU;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
dot :: proc(a, b: $T/[vector 2]$E) -> E { c := a*b; return c.x + c.y; }
|
dot :: proc(a, b: $T/[$N]$E) -> E {
|
||||||
dot :: proc(a, b: $T/[vector 3]$E) -> E { c := a*b; return c.x + c.y + c.z; }
|
res: E;
|
||||||
dot :: proc(a, b: $T/[vector 4]$E) -> E { c := a*b; return c.x + c.y + c.z + c.w; }
|
for i in 0..N do res += a[i] * b[i];
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
cross :: proc(x, y: $T/[vector 3]$E) -> T {
|
cross :: proc(x, y: $T/[3]$E) -> T {
|
||||||
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 T(a - b);
|
return T(a - b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mag :: proc(v: $T/[vector 2]$E) -> E do return sqrt(dot(v, v));
|
mag :: proc(v: $T/[$N]$E) -> E do return sqrt(dot(v, v));
|
||||||
mag :: proc(v: $T/[vector 3]$E) -> E do return sqrt(dot(v, v));
|
|
||||||
mag :: proc(v: $T/[vector 4]$E) -> E do return sqrt(dot(v, v));
|
|
||||||
|
|
||||||
norm :: proc(v: $T/[vector 2]$E) -> T do return v / mag(v);
|
norm :: proc(v: $T/[$N]$E) -> T do return v / mag(v);
|
||||||
norm :: proc(v: $T/[vector 3]$E) -> T do return v / mag(v);
|
|
||||||
norm :: proc(v: $T/[vector 4]$E) -> T do return v / mag(v);
|
|
||||||
|
|
||||||
norm0 :: proc(v: $T/[vector 2]$E) -> T {
|
norm0 :: proc(v: $T/[$N]$E) -> T {
|
||||||
m := mag(v);
|
m := mag(v);
|
||||||
if m == 0 do return 0;
|
return m == 0 ? 0 : v/m;
|
||||||
return v/m;
|
|
||||||
}
|
|
||||||
|
|
||||||
norm0 :: proc(v: $T/[vector 3]$E) -> T {
|
|
||||||
m := mag(v);
|
|
||||||
if m == 0 do return 0;
|
|
||||||
return v/m;
|
|
||||||
}
|
|
||||||
|
|
||||||
norm0 :: proc(v: $T/[vector 4]$E) -> T {
|
|
||||||
m := mag(v);
|
|
||||||
if m == 0 do return 0;
|
|
||||||
return v/m;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -184,10 +179,10 @@ mul :: proc(a, b: Mat4) -> Mat4 {
|
|||||||
|
|
||||||
mul :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
mul :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||||
return Vec4{
|
return Vec4{
|
||||||
m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w,
|
m[0][0]*v[0] + m[1][0]*v[1] + m[2][0]*v[2] + m[3][0]*v[3],
|
||||||
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
|
m[0][1]*v[0] + m[1][1]*v[1] + m[2][1]*v[2] + m[3][1]*v[3],
|
||||||
m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z + m[3][2]*v.w,
|
m[0][2]*v[0] + m[1][2]*v[1] + m[2][2]*v[2] + m[3][2]*v[3],
|
||||||
m[0][3]*v.x + m[1][3]*v.y + m[2][3]*v.z + m[3][3]*v.w,
|
m[0][3]*v[0] + m[1][3]*v[1] + m[2][3]*v[2] + m[3][3]*v[3],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,9 +258,9 @@ inverse :: proc(m: Mat4) -> Mat4 {
|
|||||||
|
|
||||||
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[0];
|
||||||
m[3][1] = v.y;
|
m[3][1] = v[1];
|
||||||
m[3][2] = v.z;
|
m[3][2] = v[2];
|
||||||
m[3][3] = 1;
|
m[3][3] = 1;
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
@@ -279,28 +274,28 @@ mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
|||||||
|
|
||||||
rot := mat4_identity();
|
rot := mat4_identity();
|
||||||
|
|
||||||
rot[0][0] = c + t.x*a.x;
|
rot[0][0] = c + t[0]*a[0];
|
||||||
rot[0][1] = 0 + t.x*a.y + s*a.z;
|
rot[0][1] = 0 + t[0]*a[1] + s*a[2];
|
||||||
rot[0][2] = 0 + t.x*a.z - s*a.y;
|
rot[0][2] = 0 + t[0]*a[2] - s*a[1];
|
||||||
rot[0][3] = 0;
|
rot[0][3] = 0;
|
||||||
|
|
||||||
rot[1][0] = 0 + t.y*a.x - s*a.z;
|
rot[1][0] = 0 + t[1]*a[0] - s*a[2];
|
||||||
rot[1][1] = c + t.y*a.y;
|
rot[1][1] = c + t[1]*a[1];
|
||||||
rot[1][2] = 0 + t.y*a.z + s*a.x;
|
rot[1][2] = 0 + t[1]*a[2] + s*a[0];
|
||||||
rot[1][3] = 0;
|
rot[1][3] = 0;
|
||||||
|
|
||||||
rot[2][0] = 0 + t.z*a.x + s*a.y;
|
rot[2][0] = 0 + t[2]*a[0] + s*a[1];
|
||||||
rot[2][1] = 0 + t.z*a.y - s*a.x;
|
rot[2][1] = 0 + t[2]*a[1] - s*a[0];
|
||||||
rot[2][2] = c + t.z*a.z;
|
rot[2][2] = c + t[2]*a[2];
|
||||||
rot[2][3] = 0;
|
rot[2][3] = 0;
|
||||||
|
|
||||||
return rot;
|
return rot;
|
||||||
}
|
}
|
||||||
|
|
||||||
scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
||||||
m[0][0] *= v.x;
|
m[0][0] *= v[0];
|
||||||
m[1][1] *= v.y;
|
m[1][1] *= v[1];
|
||||||
m[2][2] *= v.z;
|
m[2][2] *= v[2];
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,9 +313,9 @@ look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
|||||||
u := cross(s, f);
|
u := cross(s, f);
|
||||||
|
|
||||||
return Mat4{
|
return Mat4{
|
||||||
{+s.x, +u.x, -f.x, 0},
|
{+s[0], +u[0], -f[0], 0},
|
||||||
{+s.y, +u.y, -f.y, 0},
|
{+s[1], +u[1], -f[1], 0},
|
||||||
{+s.z, +u.z, -f.z, 0},
|
{+s[2], +u[2], -f[2], 0},
|
||||||
{-dot(s, eye), -dot(u, eye), dot(f, eye), 1},
|
{-dot(s, eye), -dot(u, eye), dot(f, eye), 1},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+97
-89
@@ -1,65 +1,72 @@
|
|||||||
import (
|
import "core:raw.odin"
|
||||||
"fmt.odin";
|
|
||||||
"os.odin";
|
|
||||||
"raw.odin";
|
|
||||||
)
|
|
||||||
foreign __llvm_core {
|
foreign __llvm_core {
|
||||||
swap :: proc(b: u16) -> u16 #link_name "llvm.bswap.i16" ---;
|
@(link_name = "llvm.bswap.i16") swap :: proc(b: u16) -> u16 ---;
|
||||||
swap :: proc(b: u32) -> u32 #link_name "llvm.bswap.i32" ---;
|
@(link_name = "llvm.bswap.i32") swap :: proc(b: u32) -> u32 ---;
|
||||||
swap :: proc(b: u64) -> u64 #link_name "llvm.bswap.i64" ---;
|
@(link_name = "llvm.bswap.i64") swap :: proc(b: u64) -> u64 ---;
|
||||||
}
|
}
|
||||||
|
|
||||||
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #cc_contextless {
|
set :: proc "contextless" (data: rawptr, value: i32, len: int) -> rawptr {
|
||||||
return __mem_set(data, value, len);
|
return __mem_set(data, value, len);
|
||||||
}
|
}
|
||||||
zero :: proc(data: rawptr, len: int) -> rawptr #cc_contextless {
|
zero :: proc "contextless" (data: rawptr, len: int) -> rawptr {
|
||||||
return __mem_zero(data, len);
|
return __mem_zero(data, len);
|
||||||
}
|
}
|
||||||
copy :: proc(dst, src: rawptr, len: int) -> rawptr #cc_contextless {
|
copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||||
return __mem_copy(dst, src, len);
|
return __mem_copy(dst, src, len);
|
||||||
}
|
}
|
||||||
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #cc_contextless {
|
copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||||
return __mem_copy_non_overlapping(dst, src, len);
|
return __mem_copy_non_overlapping(dst, src, len);
|
||||||
}
|
}
|
||||||
compare :: proc(a, b: []u8) -> int #cc_contextless {
|
compare :: proc "contextless" (a, b: []u8) -> int {
|
||||||
return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
|
return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
slice_ptr :: proc(ptr: ^$T, len: int) -> []T #cc_contextless {
|
slice_ptr :: proc "contextless" (ptr: ^$T, len: int) -> []T {
|
||||||
assert(len >= 0);
|
assert(len >= 0);
|
||||||
slice := raw.Slice{data = ptr, len = len, cap = len};
|
slice := raw.Slice{data = ptr, len = len, cap = len};
|
||||||
return (cast(^[]T)&slice)^;
|
return transmute([]T)slice;
|
||||||
}
|
}
|
||||||
slice_ptr :: proc(ptr: ^$T, len, cap: int) -> []T #cc_contextless {
|
slice_ptr :: proc "contextless" (ptr: ^$T, len, cap: int) -> []T {
|
||||||
assert(0 <= len && len <= cap);
|
assert(0 <= len && len <= cap);
|
||||||
slice := raw.Slice{data = ptr, len = len, cap = cap};
|
slice := raw.Slice{data = ptr, len = len, cap = cap};
|
||||||
return (cast(^[]T)&slice)^;
|
return transmute([]T)slice;
|
||||||
}
|
}
|
||||||
|
|
||||||
slice_to_bytes :: proc(slice: []$T) -> []u8 #cc_contextless {
|
slice_to_bytes :: proc "contextless" (slice: $E/[]$T) -> []u8 {
|
||||||
s := cast(^raw.Slice)&slice;
|
s := transmute(raw.Slice)slice;
|
||||||
s.len *= size_of(T);
|
s.len *= size_of(T);
|
||||||
s.cap *= size_of(T);
|
s.cap *= size_of(T);
|
||||||
return (cast(^[]u8)s)^;
|
return transmute([]u8)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []u8 {
|
||||||
|
assert(len >= 0);
|
||||||
|
return transmute([]u8)raw.Slice{ptr, len*size_of(T), len*size_of(T)};
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr_to_bytes :: proc "contextless" (ptr: ^$T, len, cap: int) -> []u8 {
|
||||||
|
assert(0 <= len && len <= cap);
|
||||||
|
return transmute([]u8)raw.Slice{ptr, len*size_of(T), cap*size_of(T)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
kilobytes :: proc(x: int) -> int #inline #cc_contextless { return (x) * 1024; }
|
kilobytes :: inline proc "contextless" (x: int) -> int do return (x) * 1024;
|
||||||
megabytes :: proc(x: int) -> int #inline #cc_contextless { return kilobytes(x) * 1024; }
|
megabytes :: inline proc "contextless" (x: int) -> int do return kilobytes(x) * 1024;
|
||||||
gigabytes :: proc(x: int) -> int #inline #cc_contextless { return megabytes(x) * 1024; }
|
gigabytes :: inline proc "contextless" (x: int) -> int do return megabytes(x) * 1024;
|
||||||
terabytes :: proc(x: int) -> int #inline #cc_contextless { return gigabytes(x) * 1024; }
|
terabytes :: inline proc "contextless" (x: int) -> int do return gigabytes(x) * 1024;
|
||||||
|
|
||||||
is_power_of_two :: proc(x: int) -> bool {
|
is_power_of_two :: proc(x: uintptr) -> bool {
|
||||||
if x <= 0 do return false;
|
if x <= 0 do 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: uintptr) -> rawptr {
|
||||||
assert(is_power_of_two(align));
|
assert(is_power_of_two(align));
|
||||||
|
|
||||||
a := uint(align);
|
a := uintptr(align);
|
||||||
p := uint(ptr);
|
p := uintptr(ptr);
|
||||||
modulo := p & (a-1);
|
modulo := p & (a-1);
|
||||||
if modulo != 0 do p += a - modulo;
|
if modulo != 0 do p += a - modulo;
|
||||||
return rawptr(p);
|
return rawptr(p);
|
||||||
@@ -67,9 +74,7 @@ align_forward :: proc(ptr: rawptr, align: int) -> 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;
|
||||||
@@ -94,15 +99,14 @@ allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
|
|||||||
// Custom allocators
|
// Custom allocators
|
||||||
|
|
||||||
Arena :: struct {
|
Arena :: struct {
|
||||||
backing: Allocator;
|
backing: Allocator,
|
||||||
offset: int;
|
memory: []u8,
|
||||||
memory: []u8;
|
temp_count: int,
|
||||||
temp_count: int;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ArenaTempMemory :: struct {
|
ArenaTempMemory :: struct {
|
||||||
arena: ^Arena;
|
arena: ^Arena,
|
||||||
original_count: int;
|
original_count: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -117,16 +121,22 @@ init_arena_from_memory :: proc(using a: ^Arena, data: []u8) {
|
|||||||
|
|
||||||
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 = make([]u8, size);
|
memory = make([]u8, 0, size);
|
||||||
temp_count = 0;
|
temp_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
context_from_allocator :: proc(a: Allocator) -> Context {
|
||||||
|
c := context;
|
||||||
|
c.allocator = a;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
destroy_arena :: proc(using a: ^Arena) {
|
destroy_arena :: proc(using a: ^Arena) {
|
||||||
if backing.procedure != nil {
|
if backing.procedure != nil {
|
||||||
push_allocator backing {
|
context <- context_from_allocator(backing) {
|
||||||
free(memory);
|
free(memory);
|
||||||
memory = nil;
|
memory = nil;
|
||||||
offset = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,25 +148,25 @@ arena_allocator :: proc(arena: ^Arena) -> Allocator {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
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, location := #caller_location) -> rawptr {
|
||||||
using Allocator.Mode;
|
using Allocator_Mode;
|
||||||
arena := cast(^Arena)allocator_data;
|
arena := cast(^Arena)allocator_data;
|
||||||
|
|
||||||
match mode {
|
|
||||||
|
switch mode {
|
||||||
case Alloc:
|
case Alloc:
|
||||||
total_size := size + alignment;
|
total_size := size + alignment;
|
||||||
|
|
||||||
if arena.offset + total_size > len(arena.memory) {
|
if len(arena.memory) + total_size > cap(arena.memory) {
|
||||||
fmt.fprintln(os.stderr, "Arena out of memory");
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
#no_bounds_check end := &arena.memory[arena.offset];
|
#no_bounds_check end := &arena.memory[len(arena.memory)];
|
||||||
|
|
||||||
ptr := align_forward(end, alignment);
|
ptr := align_forward(end, uintptr(alignment));
|
||||||
arena.offset += total_size;
|
(^raw.Slice)(&arena.memory).len += total_size;
|
||||||
return zero(ptr, size);
|
return zero(ptr, size);
|
||||||
|
|
||||||
case Free:
|
case Free:
|
||||||
@@ -164,7 +174,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
|||||||
// Use ArenaTempMemory if you want to free a block
|
// Use ArenaTempMemory if you want to free a block
|
||||||
|
|
||||||
case FreeAll:
|
case FreeAll:
|
||||||
arena.offset = 0;
|
(^raw.Slice)(&arena.memory).len = 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);
|
||||||
@@ -208,46 +218,45 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
|||||||
|
|
||||||
WORD_SIZE :: size_of(int);
|
WORD_SIZE :: size_of(int);
|
||||||
MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
|
MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
|
||||||
using Type_Info;
|
switch info in type_info.variant {
|
||||||
match info in type_info.variant {
|
case Type_Info_Named:
|
||||||
case Named:
|
|
||||||
return align_of_type_info(info.base);
|
return align_of_type_info(info.base);
|
||||||
case Integer:
|
case Type_Info_Integer:
|
||||||
return type_info.align;
|
return type_info.align;
|
||||||
case Rune:
|
case Type_Info_Rune:
|
||||||
return type_info.align;
|
return type_info.align;
|
||||||
case Float:
|
case Type_Info_Float:
|
||||||
return type_info.align;
|
return type_info.align;
|
||||||
case String:
|
case Type_Info_String:
|
||||||
return WORD_SIZE;
|
return WORD_SIZE;
|
||||||
case Boolean:
|
case Type_Info_Boolean:
|
||||||
return 1;
|
return 1;
|
||||||
case Any:
|
case Type_Info_Any:
|
||||||
return WORD_SIZE;
|
return WORD_SIZE;
|
||||||
case Pointer:
|
case Type_Info_Pointer:
|
||||||
return WORD_SIZE;
|
return WORD_SIZE;
|
||||||
case Procedure:
|
case Type_Info_Procedure:
|
||||||
return WORD_SIZE;
|
return WORD_SIZE;
|
||||||
case Array:
|
case Type_Info_Array:
|
||||||
return align_of_type_info(info.elem);
|
return align_of_type_info(info.elem);
|
||||||
case Dynamic_Array:
|
case Type_Info_Dynamic_Array:
|
||||||
return WORD_SIZE;
|
return WORD_SIZE;
|
||||||
case Slice:
|
case Type_Info_Slice:
|
||||||
return WORD_SIZE;
|
return WORD_SIZE;
|
||||||
case Vector:
|
case Type_Info_Vector:
|
||||||
size := size_of_type_info(info.elem);
|
size := size_of_type_info(info.elem);
|
||||||
count := int(max(prev_pow2(i64(info.count)), 1));
|
count := int(max(prev_pow2(i64(info.count)), 1));
|
||||||
total := size * count;
|
total := size * count;
|
||||||
return clamp(total, 1, MAX_ALIGN);
|
return clamp(total, 1, MAX_ALIGN);
|
||||||
case Tuple:
|
case Type_Info_Tuple:
|
||||||
return type_info.align;
|
return type_info.align;
|
||||||
case Struct:
|
case Type_Info_Struct:
|
||||||
return type_info.align;
|
return type_info.align;
|
||||||
case Union:
|
case Type_Info_Union:
|
||||||
return type_info.align;
|
return type_info.align;
|
||||||
case Enum:
|
case Type_Info_Enum:
|
||||||
return align_of_type_info(info.base);
|
return align_of_type_info(info.base);
|
||||||
case Map:
|
case Type_Info_Map:
|
||||||
return align_of_type_info(info.generated_struct);
|
return align_of_type_info(info.generated_struct);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,51 +270,50 @@ align_formula :: proc(size, align: int) -> int {
|
|||||||
|
|
||||||
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;
|
switch info in type_info.variant {
|
||||||
match info in type_info.variant {
|
case Type_Info_Named:
|
||||||
case Named:
|
|
||||||
return size_of_type_info(info.base);
|
return size_of_type_info(info.base);
|
||||||
case Integer:
|
case Type_Info_Integer:
|
||||||
return type_info.size;
|
return type_info.size;
|
||||||
case Rune:
|
case Type_Info_Rune:
|
||||||
return type_info.size;
|
return type_info.size;
|
||||||
case Float:
|
case Type_Info_Float:
|
||||||
return type_info.size;
|
return type_info.size;
|
||||||
case String:
|
case Type_Info_String:
|
||||||
return 2*WORD_SIZE;
|
return 2*WORD_SIZE;
|
||||||
case Boolean:
|
case Type_Info_Boolean:
|
||||||
return 1;
|
return 1;
|
||||||
case Any:
|
case Type_Info_Any:
|
||||||
return 2*WORD_SIZE;
|
return 2*WORD_SIZE;
|
||||||
case Pointer:
|
case Type_Info_Pointer:
|
||||||
return WORD_SIZE;
|
return WORD_SIZE;
|
||||||
case Procedure:
|
case Type_Info_Procedure:
|
||||||
return WORD_SIZE;
|
return WORD_SIZE;
|
||||||
case Array:
|
case Type_Info_Array:
|
||||||
count := info.count;
|
count := info.count;
|
||||||
if count == 0 do return 0;
|
if count == 0 do 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 Dynamic_Array:
|
case Type_Info_Dynamic_Array:
|
||||||
return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
|
return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
|
||||||
case Slice:
|
case Type_Info_Slice:
|
||||||
return 2*WORD_SIZE;
|
return 2*WORD_SIZE;
|
||||||
case Vector:
|
case Type_Info_Vector:
|
||||||
count := info.count;
|
count := info.count;
|
||||||
if count == 0 do return 0;
|
if count == 0 do 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 Struct:
|
case Type_Info_Struct:
|
||||||
return type_info.size;
|
return type_info.size;
|
||||||
case Union:
|
case Type_Info_Union:
|
||||||
return type_info.size;
|
return type_info.size;
|
||||||
case Enum:
|
case Type_Info_Enum:
|
||||||
return size_of_type_info(info.base);
|
return size_of_type_info(info.base);
|
||||||
case Map:
|
case Type_Info_Map:
|
||||||
return size_of_type_info(info.generated_struct);
|
return size_of_type_info(info.generated_struct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+85
-84
@@ -1,45 +1,46 @@
|
|||||||
foreign_system_library (
|
when ODIN_OS == "windows" {
|
||||||
lib "opengl32.lib" when ODIN_OS == "windows";
|
foreign import lib "system:opengl32.lib"
|
||||||
lib "gl" when ODIN_OS == "linux";
|
import win32 "core:sys/windows.odin"
|
||||||
)
|
import "core:sys/wgl.odin"
|
||||||
import (
|
} else when ODIN_OS == "linux" {
|
||||||
win32 "sys/windows.odin" when ODIN_OS == "windows";
|
foreign import lib "system:gl"
|
||||||
"sys/wgl.odin" when ODIN_OS == "windows";
|
}
|
||||||
)
|
|
||||||
import_load "opengl_constants.odin";
|
export "core:opengl_constants.odin"
|
||||||
|
|
||||||
_ := compile_assert(ODIN_OS != "osx");
|
_ := compile_assert(ODIN_OS != "osx");
|
||||||
|
|
||||||
|
@(default_calling_convention="c", link_prefix="gl")
|
||||||
foreign lib {
|
foreign lib {
|
||||||
Clear :: proc(mask: u32) #link_name "glClear" ---;
|
Clear :: proc(mask: u32) ---;
|
||||||
ClearColor :: proc(r, g, b, a: f32) #link_name "glClearColor" ---;
|
ClearColor :: proc(r, g, b, a: f32) ---;
|
||||||
Begin :: proc(mode: i32) #link_name "glBegin" ---;
|
Begin :: proc(mode: i32) ---;
|
||||||
End :: proc() #link_name "glEnd" ---;
|
End :: proc() ---;
|
||||||
Finish :: proc() #link_name "glFinish" ---;
|
Finish :: proc() ---;
|
||||||
BlendFunc :: proc(sfactor, dfactor: i32) #link_name "glBlendFunc" ---;
|
BlendFunc :: proc(sfactor, dfactor: i32) ---;
|
||||||
Enable :: proc(cap: i32) #link_name "glEnable" ---;
|
Enable :: proc(cap: i32) ---;
|
||||||
Disable :: proc(cap: i32) #link_name "glDisable" ---;
|
Disable :: proc(cap: i32) ---;
|
||||||
GenTextures :: proc(count: i32, result: ^u32) #link_name "glGenTextures" ---;
|
GenTextures :: proc(count: i32, result: ^u32) ---;
|
||||||
DeleteTextures :: proc(count: i32, result: ^u32) #link_name "glDeleteTextures"---;
|
DeleteTextures :: proc(count: i32, result: ^u32) ---;
|
||||||
TexParameteri :: proc(target, pname, param: i32) #link_name "glTexParameteri" ---;
|
TexParameteri :: proc(target, pname, param: i32) ---;
|
||||||
TexParameterf :: proc(target: i32, pname: i32, param: f32) #link_name "glTexParameterf" ---;
|
TexParameterf :: proc(target: i32, pname: i32, param: f32) ---;
|
||||||
BindTexture :: proc(target: i32, texture: u32) #link_name "glBindTexture" ---;
|
BindTexture :: proc(target: i32, texture: u32) ---;
|
||||||
LoadIdentity :: proc() #link_name "glLoadIdentity" ---;
|
LoadIdentity :: proc() ---;
|
||||||
Viewport :: proc(x, y, width, height: i32) #link_name "glViewport" ---;
|
Viewport :: proc(x, y, width, height: i32) ---;
|
||||||
Ortho :: proc(left, right, bottom, top, near, far: f64) #link_name "glOrtho" ---;
|
Ortho :: proc(left, right, bottom, top, near, far: f64) ---;
|
||||||
Color3f :: proc(r, g, b: f32) #link_name "glColor3f" ---;
|
Color3f :: proc(r, g, b: f32) ---;
|
||||||
Vertex3f :: proc(x, y, z: f32) #link_name "glVertex3f" ---;
|
Vertex3f :: proc(x, y, z: f32) ---;
|
||||||
GetError :: proc() -> i32 #link_name "glGetError" ---;
|
GetError :: proc() -> i32 ---;
|
||||||
GetString :: proc(name: i32) -> ^u8 #link_name "glGetString" ---;
|
GetString :: proc(name: i32) -> ^u8 ---;
|
||||||
GetIntegerv :: proc(name: i32, v: ^i32) #link_name "glGetIntegerv" ---;
|
GetIntegerv :: proc(name: i32, v: ^i32) ---;
|
||||||
TexCoord2f :: proc(x, y: f32) #link_name "glTexCoord2f" ---;
|
TexCoord2f :: proc(x, y: f32) ---;
|
||||||
TexImage2D :: proc(target, level, internal_format,
|
TexImage2D :: proc(target, level, internal_format: i32,
|
||||||
width, height, border,
|
width, height, border: i32,
|
||||||
format, type_: i32, pixels: rawptr) #link_name "glTexImage2D" ---;
|
format, type_: i32, pixels: rawptr) ---;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_string_data :: proc(s: string) -> ^u8 #inline { return &s[0]; }
|
_string_data :: inline proc(s: string) -> ^u8 do return &s[0];
|
||||||
|
|
||||||
_libgl := win32.load_library_a(_string_data("opengl32.dll\x00"));
|
_libgl := win32.load_library_a(_string_data("opengl32.dll\x00"));
|
||||||
|
|
||||||
@@ -57,69 +58,69 @@ get_proc_address :: proc(name: string) -> rawptr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Procedures
|
// Procedures
|
||||||
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
|
GenBuffers: proc "c" (count: i32, buffers: ^u32);
|
||||||
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
|
GenVertexArrays: proc "c" (count: i32, buffers: ^u32);
|
||||||
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
|
GenSamplers: proc "c" (count: i32, buffers: ^u32);
|
||||||
DeleteBuffers: proc(count: i32, buffers: ^u32) #cc_c;
|
DeleteBuffers: proc "c" (count: i32, buffers: ^u32);
|
||||||
BindBuffer: proc(target: i32, buffer: u32) #cc_c;
|
BindBuffer: proc "c" (target: i32, buffer: u32);
|
||||||
BindVertexArray: proc(buffer: u32) #cc_c;
|
BindVertexArray: proc "c" (buffer: u32);
|
||||||
DeleteVertexArrays: proc(count: i32, arrays: ^u32) #cc_c;
|
DeleteVertexArrays: proc "c" (count: i32, arrays: ^u32);
|
||||||
BindSampler: proc(position: i32, sampler: u32) #cc_c;
|
BindSampler: proc "c" (position: i32, sampler: u32);
|
||||||
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32) #cc_c;
|
BufferData: proc "c" (target: i32, size: int, data: rawptr, usage: i32);
|
||||||
BufferSubData: proc(target: i32, offset, size: int, data: rawptr) #cc_c;
|
BufferSubData: proc "c" (target: i32, offset, size: int, data: rawptr);
|
||||||
|
|
||||||
DrawArrays: proc(mode, first: i32, count: u32) #cc_c;
|
DrawArrays: proc "c" (mode, first: i32, count: u32);
|
||||||
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
|
DrawElements: proc "c" (mode: i32, count: u32, type_: i32, indices: rawptr);
|
||||||
|
|
||||||
MapBuffer: proc(target, access: i32) -> rawptr #cc_c;
|
MapBuffer: proc "c" (target, access: i32) -> rawptr;
|
||||||
UnmapBuffer: proc(target: i32) #cc_c;
|
UnmapBuffer: proc "c" (target: i32);
|
||||||
|
|
||||||
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr) #cc_c;
|
VertexAttribPointer: proc "c" (index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr);
|
||||||
EnableVertexAttribArray: proc(index: u32) #cc_c;
|
EnableVertexAttribArray: proc "c" (index: u32);
|
||||||
|
|
||||||
CreateShader: proc(shader_type: i32) -> u32 #cc_c;
|
CreateShader: proc "c" (shader_type: i32) -> u32;
|
||||||
ShaderSource: proc(shader: u32, count: u32, str: ^^u8, length: ^i32) #cc_c;
|
ShaderSource: proc "c" (shader: u32, count: u32, str: ^^u8, length: ^i32);
|
||||||
CompileShader: proc(shader: u32) #cc_c;
|
CompileShader: proc "c" (shader: u32);
|
||||||
CreateProgram: proc() -> u32 #cc_c;
|
CreateProgram: proc "c" () -> u32;
|
||||||
AttachShader: proc(program, shader: u32) #cc_c;
|
AttachShader: proc "c" (program, shader: u32);
|
||||||
DetachShader: proc(program, shader: u32) #cc_c;
|
DetachShader: proc "c" (program, shader: u32);
|
||||||
DeleteShader: proc(shader: u32) #cc_c;
|
DeleteShader: proc "c" (shader: u32);
|
||||||
LinkProgram: proc(program: u32) #cc_c;
|
LinkProgram: proc "c" (program: u32);
|
||||||
UseProgram: proc(program: u32) #cc_c;
|
UseProgram: proc "c" (program: u32);
|
||||||
DeleteProgram: proc(program: u32) #cc_c;
|
DeleteProgram: proc "c" (program: u32);
|
||||||
|
|
||||||
|
|
||||||
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c;
|
GetShaderiv: proc "c" (shader: u32, pname: i32, params: ^i32);
|
||||||
GetProgramiv: proc(program: u32, pname: i32, params: ^i32) #cc_c;
|
GetProgramiv: proc "c" (program: u32, pname: i32, params: ^i32);
|
||||||
GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^u8) #cc_c;
|
GetShaderInfoLog: proc "c" (shader: u32, max_length: u32, length: ^u32, info_long: ^u8);
|
||||||
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^u8) #cc_c;
|
GetProgramInfoLog: proc "c" (program: u32, max_length: u32, length: ^u32, info_long: ^u8);
|
||||||
|
|
||||||
ActiveTexture: proc(texture: i32) #cc_c;
|
ActiveTexture: proc "c" (texture: i32);
|
||||||
GenerateMipmap: proc(target: i32) #cc_c;
|
GenerateMipmap: proc "c" (target: i32);
|
||||||
|
|
||||||
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c;
|
SamplerParameteri: proc "c" (sampler: u32, pname: i32, param: i32);
|
||||||
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c;
|
SamplerParameterf: proc "c" (sampler: u32, pname: i32, param: f32);
|
||||||
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
|
SamplerParameteriv: proc "c" (sampler: u32, pname: i32, params: ^i32);
|
||||||
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
|
SamplerParameterfv: proc "c" (sampler: u32, pname: i32, params: ^f32);
|
||||||
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
|
SamplerParameterIiv: proc "c" (sampler: u32, pname: i32, params: ^i32);
|
||||||
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c;
|
SamplerParameterIuiv: proc "c" (sampler: u32, pname: i32, params: ^u32);
|
||||||
|
|
||||||
|
|
||||||
Uniform1i: proc(loc: i32, v0: i32) #cc_c;
|
Uniform1i: proc "c" (loc: i32, v0: i32);
|
||||||
Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c;
|
Uniform2i: proc "c" (loc: i32, v0, v1: i32);
|
||||||
Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c;
|
Uniform3i: proc "c" (loc: i32, v0, v1, v2: i32);
|
||||||
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
|
Uniform4i: proc "c" (loc: i32, v0, v1, v2, v3: i32);
|
||||||
Uniform1f: proc(loc: i32, v0: f32) #cc_c;
|
Uniform1f: proc "c" (loc: i32, v0: f32);
|
||||||
Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c;
|
Uniform2f: proc "c" (loc: i32, v0, v1: f32);
|
||||||
Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c;
|
Uniform3f: proc "c" (loc: i32, v0, v1, v2: f32);
|
||||||
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32) #cc_c;
|
Uniform4f: proc "c" (loc: i32, v0, v1, v2, v3: f32);
|
||||||
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;
|
UniformMatrix4fv: proc "c" (loc: i32, count: u32, transpose: i32, value: ^f32);
|
||||||
|
|
||||||
GetUniformLocation: proc(program: u32, name: ^u8) -> i32 #cc_c;
|
GetUniformLocation: proc "c" (program: u32, name: ^u8) -> i32;
|
||||||
|
|
||||||
|
|
||||||
init :: proc() {
|
init :: proc() {
|
||||||
set_proc_address :: proc(p: rawptr, name: string) #inline {
|
set_proc_address :: proc(p: rawptr, name: string) {
|
||||||
x := cast(^rawptr)p;
|
x := cast(^rawptr)p;
|
||||||
x^ = get_proc_address(name);
|
x^ = get_proc_address(name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1381,3 +1381,27 @@ DEBUG_LOGGED_MESSAGES_ARB :: 0x9145;
|
|||||||
DEBUG_SEVERITY_HIGH_ARB :: 0x9146;
|
DEBUG_SEVERITY_HIGH_ARB :: 0x9146;
|
||||||
DEBUG_SEVERITY_MEDIUM_ARB :: 0x9147;
|
DEBUG_SEVERITY_MEDIUM_ARB :: 0x9147;
|
||||||
DEBUG_SEVERITY_LOW_ARB :: 0x9148;
|
DEBUG_SEVERITY_LOW_ARB :: 0x9148;
|
||||||
|
|
||||||
|
|
||||||
|
SHADER_BINARY_FORMAT_SPIR_V :: 0x9551;
|
||||||
|
SPIR_V_BINARY :: 0x9552;
|
||||||
|
PARAMETER_BUFFER :: 0x80EE;
|
||||||
|
PARAMETER_BUFFER_BINDING :: 0x80EF;
|
||||||
|
CONTEXT_FLAG_NO_ERROR_BIT :: 0x00000008;
|
||||||
|
VERTICES_SUBMITTED :: 0x82EE;
|
||||||
|
PRIMITIVES_SUBMITTED :: 0x82EF;
|
||||||
|
VERTEX_SHADER_INVOCATIONS :: 0x82F0;
|
||||||
|
TESS_CONTROL_SHADER_PATCHES :: 0x82F1;
|
||||||
|
TESS_EVALUATION_SHADER_INVOCATIONS :: 0x82F2;
|
||||||
|
GEOMETRY_SHADER_PRIMITIVES_EMITTED :: 0x82F3;
|
||||||
|
FRAGMENT_SHADER_INVOCATIONS :: 0x82F4;
|
||||||
|
COMPUTE_SHADER_INVOCATIONS :: 0x82F5;
|
||||||
|
CLIPPING_INPUT_PRIMITIVES :: 0x82F6;
|
||||||
|
CLIPPING_OUTPUT_PRIMITIVES :: 0x82F7;
|
||||||
|
POLYGON_OFFSET_CLAMP :: 0x8E1B;
|
||||||
|
SPIR_V_EXTENSIONS :: 0x9553;
|
||||||
|
NUM_SPIR_V_EXTENSIONS :: 0x9554;
|
||||||
|
TEXTURE_MAX_ANISOTROPY :: 0x84FE;
|
||||||
|
MAX_TEXTURE_MAX_ANISOTROPY :: 0x84FF;
|
||||||
|
TRANSFORM_FEEDBACK_OVERFLOW :: 0x82EC;
|
||||||
|
TRANSFORM_FEEDBACK_STREAM_OVERFLOW :: 0x82ED;
|
||||||
|
|||||||
+19
-7
@@ -1,8 +1,8 @@
|
|||||||
import_load (
|
when ODIN_OS == "windows" do export "core:os_windows.odin";
|
||||||
"os_windows.odin" when ODIN_OS == "windows";
|
when ODIN_OS == "osx" do export "core:os_x.odin";
|
||||||
"os_x.odin" when ODIN_OS == "osx";
|
when ODIN_OS == "linux" do export "core:os_linux.odin";
|
||||||
"os_linux.odin" when ODIN_OS == "linux";
|
|
||||||
)
|
import "mem.odin";
|
||||||
|
|
||||||
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
|
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
|
||||||
return write(fd, cast([]u8)str);
|
return write(fd, cast([]u8)str);
|
||||||
@@ -37,8 +37,12 @@ read_entire_file :: proc(name: string) -> (data: []u8, success: bool) {
|
|||||||
return data[0..bytes_read], true;
|
return data[0..bytes_read], true;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_entire_file :: proc(name: string, data: []u8) -> (sucess: bool) {
|
write_entire_file :: proc(name: string, data: []u8, truncate := true) -> (success: bool) {
|
||||||
fd, err := open(name, O_WRONLY, 0);
|
flags: int = O_WRONLY|O_CREATE;
|
||||||
|
if truncate {
|
||||||
|
flags |= O_TRUNC;
|
||||||
|
}
|
||||||
|
fd, err := open(name, flags, 0);
|
||||||
if err != 0 {
|
if err != 0 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -47,3 +51,11 @@ write_entire_file :: proc(name: string, data: []u8) -> (sucess: bool) {
|
|||||||
bytes_written, write_err := write(fd, data);
|
bytes_written, write_err := write(fd, data);
|
||||||
return write_err != 0;
|
return write_err != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
|
||||||
|
return write(fd, mem.slice_ptr(cast(^u8)data, len));
|
||||||
|
}
|
||||||
|
|
||||||
|
read :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
|
||||||
|
return read(fd, mem.slice_ptr(cast(^u8)data, len));
|
||||||
|
}
|
||||||
|
|||||||
+64
-60
@@ -1,18 +1,18 @@
|
|||||||
foreign_system_library (
|
foreign import dl "system:dl"
|
||||||
dl "dl";
|
foreign import libc "system:c"
|
||||||
libc "c";
|
|
||||||
)
|
|
||||||
import "strings.odin";
|
|
||||||
|
|
||||||
Handle :: i32;
|
import "core:strings.odin"
|
||||||
|
import "core:mem.odin"
|
||||||
|
|
||||||
|
Handle :: i32;
|
||||||
File_Time :: u64;
|
File_Time :: u64;
|
||||||
Errno :: i32;
|
Errno :: i32;
|
||||||
|
|
||||||
|
|
||||||
O_RDONLY :: 0x00000;
|
O_RDONLY :: 0x00000;
|
||||||
O_WRONLY :: 0x00001;
|
O_WRONLY :: 0x00001;
|
||||||
O_RDWR :: 0x00002;
|
O_RDWR :: 0x00002;
|
||||||
O_CREAT :: 0x00040;
|
O_CREATE :: 0x00040;
|
||||||
O_EXCL :: 0x00080;
|
O_EXCL :: 0x00080;
|
||||||
O_NOCTTY :: 0x00100;
|
O_NOCTTY :: 0x00100;
|
||||||
O_TRUNC :: 0x00200;
|
O_TRUNC :: 0x00200;
|
||||||
@@ -41,9 +41,9 @@ RTLD_GLOBAL :: 0x100;
|
|||||||
args := _alloc_command_line_arguments();
|
args := _alloc_command_line_arguments();
|
||||||
|
|
||||||
_File_Time :: struct #ordered {
|
_File_Time :: struct #ordered {
|
||||||
seconds: i64;
|
seconds: i64,
|
||||||
nanoseconds: i32;
|
nanoseconds: i32,
|
||||||
reserved: i32;
|
reserved: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translated from
|
// Translated from
|
||||||
@@ -51,27 +51,27 @@ _File_Time :: struct #ordered {
|
|||||||
// Validity is not guaranteed.
|
// Validity is not guaranteed.
|
||||||
|
|
||||||
Stat :: struct #ordered {
|
Stat :: struct #ordered {
|
||||||
device_id: u64; // ID of device containing file
|
device_id: u64, // ID of device containing file
|
||||||
serial: u64; // File serial number
|
serial: u64, // File serial number
|
||||||
nlink: u32; // Number of hard links
|
nlink: u32, // Number of hard links
|
||||||
mode: u32; // Mode of the file
|
mode: u32, // Mode of the file
|
||||||
uid: u32; // User ID of the file's owner
|
uid: u32, // User ID of the file's owner
|
||||||
gid: u32; // Group ID of the file's group
|
gid: u32, // Group ID of the file's group
|
||||||
_padding: i32; // 32 bits of padding
|
_padding: i32, // 32 bits of padding
|
||||||
rdev: u64; // Device ID, if device
|
rdev: u64, // Device ID, if device
|
||||||
size: i64; // Size of the file, in bytes
|
size: i64, // Size of the file, in bytes
|
||||||
block_size: i64; // Optimal bllocksize for I/O
|
block_size: i64, // Optimal bllocksize for I/O
|
||||||
blocks: i64; // Number of 512-byte blocks allocated
|
blocks: i64, // Number of 512-byte blocks allocated
|
||||||
|
|
||||||
last_access: _File_Time; // Time of last access
|
last_access: _File_Time, // Time of last access
|
||||||
modified: _File_Time; // Time of last modification
|
modified: _File_Time, // Time of last modification
|
||||||
status_change: _File_Time; // Time of last status change
|
status_change: _File_Time, // Time of last status change
|
||||||
|
|
||||||
_reserve1,
|
_reserve1,
|
||||||
_reserve2,
|
_reserve2,
|
||||||
_reserve3: i64;
|
_reserve3: i64,
|
||||||
serial_numbe: u64; // File serial number...? Maybe.
|
serial_numbe: u64, // File serial number...? Maybe.
|
||||||
_reserve4: i64;
|
_reserve4: i64,
|
||||||
};
|
};
|
||||||
|
|
||||||
// File type
|
// File type
|
||||||
@@ -108,13 +108,13 @@ S_ISGID :: 0002000; // Set group id on execution
|
|||||||
S_ISVTX :: 0001000; // Directory restrcted delete
|
S_ISVTX :: 0001000; // Directory restrcted delete
|
||||||
|
|
||||||
|
|
||||||
S_ISLNK :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFLNK; }
|
S_ISLNK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK;
|
||||||
S_ISREG :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFREG; }
|
S_ISREG :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG;
|
||||||
S_ISDIR :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFDIR; }
|
S_ISDIR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR;
|
||||||
S_ISCHR :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFCHR; }
|
S_ISCHR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR;
|
||||||
S_ISBLK :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFBLK; }
|
S_ISBLK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK;
|
||||||
S_ISFIFO :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFIFO; }
|
S_ISFIFO :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO;
|
||||||
S_ISSOCK :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFSOCK;}
|
S_ISSOCK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK;
|
||||||
|
|
||||||
F_OK :: 0; // Test for file existance
|
F_OK :: 0; // Test for file existance
|
||||||
X_OK :: 1; // Test for execute permission
|
X_OK :: 1; // Test for execute permission
|
||||||
@@ -122,27 +122,28 @@ W_OK :: 2; // Test for write permission
|
|||||||
R_OK :: 4; // Test for read permission
|
R_OK :: 4; // Test for read permission
|
||||||
|
|
||||||
foreign libc {
|
foreign libc {
|
||||||
_unix_open :: proc(path: ^u8, mode: int) -> Handle #link_name "open" ---;
|
@(link_name="open") _unix_open :: proc(path: ^u8, mode: int) -> Handle ---;
|
||||||
_unix_close :: proc(fd: Handle) -> i32 #link_name "close" ---;
|
@(link_name="close") _unix_close :: proc(fd: Handle) -> i32 ---;
|
||||||
_unix_read :: proc(fd: Handle, buf: rawptr, size: int) -> int #link_name "read" ---;
|
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
|
||||||
_unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int #link_name "write" ---;
|
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
|
||||||
_unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 #link_name "lseek64" ---;
|
@(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 ---;
|
||||||
_unix_gettid :: proc() -> u64 #link_name "gettid" ---;
|
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---;
|
||||||
_unix_stat :: proc(path: ^u8, stat: ^Stat) -> i32 #link_name "stat" ---;
|
@(link_name="stat") _unix_stat :: proc(path: ^u8, stat: ^Stat) -> i32 ---;
|
||||||
_unix_access :: proc(path: ^u8, mask: int) -> i32 #link_name "access" ---;
|
@(link_name="access") _unix_access :: proc(path: ^u8, mask: int) -> i32 ---;
|
||||||
|
|
||||||
_unix_malloc :: proc(size: int) -> rawptr #link_name "malloc" ---;
|
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---;
|
||||||
_unix_free :: proc(ptr: rawptr) #link_name "free" ---;
|
@(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---;
|
||||||
_unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #link_name "realloc" ---;
|
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---;
|
||||||
_unix_getenv :: proc(^u8) -> ^u8 #link_name "getenv" ---;
|
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
|
||||||
|
@(link_name="getenv") _unix_getenv :: proc(^u8) -> ^u8 ---;
|
||||||
|
|
||||||
_unix_exit :: proc(status: int) #link_name "exit" ---;
|
@(link_name="exit") _unix_exit :: proc(status: int) ---;
|
||||||
}
|
}
|
||||||
foreign dl {
|
foreign dl {
|
||||||
_unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #link_name "dlopen" ---;
|
@(link_name="dlopen") _unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr ---;
|
||||||
_unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym" ---;
|
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> rawptr ---;
|
||||||
_unix_dlclose :: proc(handle: rawptr) -> int #link_name "dlclose" ---;
|
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---;
|
||||||
_unix_dlerror :: proc() -> ^u8 #link_name "dlerror" ---;
|
@(link_name="dlerror") _unix_dlerror :: proc() -> ^u8 ---;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
|
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
|
||||||
@@ -199,7 +200,7 @@ last_write_time :: proc(fd: Handle) -> File_Time {}
|
|||||||
last_write_time_by_name :: proc(name: string) -> File_Time {}
|
last_write_time_by_name :: proc(name: string) -> File_Time {}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
stat :: proc(path: string) -> (Stat, int) #inline {
|
stat :: inline proc(path: string) -> (Stat, int) {
|
||||||
s: Stat;
|
s: Stat;
|
||||||
cstr := strings.new_c_string(path);
|
cstr := strings.new_c_string(path);
|
||||||
defer free(cstr);
|
defer free(cstr);
|
||||||
@@ -207,7 +208,7 @@ stat :: proc(path: string) -> (Stat, int) #inline {
|
|||||||
return s, int(ret_int);
|
return s, int(ret_int);
|
||||||
}
|
}
|
||||||
|
|
||||||
access :: proc(path: string, mask: int) -> bool #inline {
|
access :: inline proc(path: string, mask: int) -> bool {
|
||||||
cstr := strings.new_c_string(path);
|
cstr := strings.new_c_string(path);
|
||||||
defer free(cstr);
|
defer free(cstr);
|
||||||
return _unix_access(cstr, mask) == 0;
|
return _unix_access(cstr, mask) == 0;
|
||||||
@@ -215,7 +216,7 @@ access :: proc(path: string, mask: int) -> bool #inline {
|
|||||||
|
|
||||||
heap_alloc :: proc(size: int) -> rawptr {
|
heap_alloc :: proc(size: int) -> rawptr {
|
||||||
assert(size > 0);
|
assert(size > 0);
|
||||||
return _unix_malloc(size);
|
return _unix_calloc(1, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
@@ -245,20 +246,20 @@ current_thread_id :: proc() -> int {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dlopen :: proc(filename: string, flags: int) -> rawptr #inline {
|
dlopen :: inline proc(filename: string, flags: int) -> rawptr {
|
||||||
cstr := strings.new_c_string(filename);
|
cstr := strings.new_c_string(filename);
|
||||||
handle := _unix_dlopen(cstr, flags);
|
handle := _unix_dlopen(cstr, flags);
|
||||||
free(cstr);
|
free(cstr);
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
dlsym :: proc(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
|
dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {
|
||||||
assert(handle != nil);
|
assert(handle != nil);
|
||||||
cstr := strings.new_c_string(symbol);
|
cstr := strings.new_c_string(symbol);
|
||||||
proc_handle := _unix_dlsym(handle, cstr);
|
proc_handle := _unix_dlsym(handle, cstr);
|
||||||
free(cstr);
|
free(cstr);
|
||||||
return proc_handle;
|
return proc_handle;
|
||||||
}
|
}
|
||||||
dlclose :: proc(handle: rawptr) -> bool #inline {
|
dlclose :: inline proc(handle: rawptr) -> bool {
|
||||||
assert(handle != nil);
|
assert(handle != nil);
|
||||||
return _unix_dlclose(handle) == 0;
|
return _unix_dlclose(handle) == 0;
|
||||||
}
|
}
|
||||||
@@ -268,6 +269,9 @@ dlerror :: proc() -> string {
|
|||||||
|
|
||||||
|
|
||||||
_alloc_command_line_arguments :: proc() -> []string {
|
_alloc_command_line_arguments :: proc() -> []string {
|
||||||
// TODO(bill):
|
args := make([]string, __argc__);
|
||||||
return nil;
|
for i in 0..__argc__ {
|
||||||
|
args[i] = strings.to_odin_string((__argv__+i)^);
|
||||||
|
}
|
||||||
|
return args;
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-13
@@ -1,18 +1,18 @@
|
|||||||
import win32 "sys/windows.odin";
|
import win32 "core:sys/windows.odin"
|
||||||
import "mem.odin";
|
import "core:mem.odin"
|
||||||
|
|
||||||
Handle :: int;
|
Handle :: uintptr;
|
||||||
File_Time :: u64;
|
File_Time :: u64;
|
||||||
|
|
||||||
|
|
||||||
INVALID_HANDLE: Handle : -1;
|
INVALID_HANDLE :: ~Handle(0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
O_RDONLY :: 0x00000;
|
O_RDONLY :: 0x00000;
|
||||||
O_WRONLY :: 0x00001;
|
O_WRONLY :: 0x00001;
|
||||||
O_RDWR :: 0x00002;
|
O_RDWR :: 0x00002;
|
||||||
O_CREAT :: 0x00040;
|
O_CREATE :: 0x00040;
|
||||||
O_EXCL :: 0x00080;
|
O_EXCL :: 0x00080;
|
||||||
O_NOCTTY :: 0x00100;
|
O_NOCTTY :: 0x00100;
|
||||||
O_TRUNC :: 0x00200;
|
O_TRUNC :: 0x00200;
|
||||||
@@ -60,13 +60,13 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errn
|
|||||||
if len(path) == 0 do return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
|
if len(path) == 0 do return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
|
||||||
|
|
||||||
access: u32;
|
access: u32;
|
||||||
match mode & (O_RDONLY|O_WRONLY|O_RDWR) {
|
switch mode & (O_RDONLY|O_WRONLY|O_RDWR) {
|
||||||
case O_RDONLY: access = win32.FILE_GENERIC_READ;
|
case O_RDONLY: access = win32.FILE_GENERIC_READ;
|
||||||
case O_WRONLY: access = win32.FILE_GENERIC_WRITE;
|
case O_WRONLY: access = win32.FILE_GENERIC_WRITE;
|
||||||
case O_RDWR: access = win32.FILE_GENERIC_READ | win32.FILE_GENERIC_WRITE;
|
case O_RDWR: access = win32.FILE_GENERIC_READ | win32.FILE_GENERIC_WRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode&O_CREAT != 0 {
|
if mode&O_CREATE != 0 {
|
||||||
access |= win32.FILE_GENERIC_WRITE;
|
access |= win32.FILE_GENERIC_WRITE;
|
||||||
}
|
}
|
||||||
if mode&O_APPEND != 0 {
|
if mode&O_APPEND != 0 {
|
||||||
@@ -82,12 +82,12 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errn
|
|||||||
}
|
}
|
||||||
|
|
||||||
create_mode: u32;
|
create_mode: u32;
|
||||||
match {
|
switch {
|
||||||
case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
|
case mode&(O_CREATE|O_EXCL) == (O_CREATE | O_EXCL):
|
||||||
create_mode = win32.CREATE_NEW;
|
create_mode = win32.CREATE_NEW;
|
||||||
case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC):
|
case mode&(O_CREATE|O_TRUNC) == (O_CREATE | O_TRUNC):
|
||||||
create_mode = win32.CREATE_ALWAYS;
|
create_mode = win32.CREATE_ALWAYS;
|
||||||
case mode&O_CREAT == O_CREAT:
|
case mode&O_CREATE == O_CREATE:
|
||||||
create_mode = win32.OPEN_ALWAYS;
|
create_mode = win32.OPEN_ALWAYS;
|
||||||
case mode&O_TRUNC == O_TRUNC:
|
case mode&O_TRUNC == O_TRUNC:
|
||||||
create_mode = win32.TRUNCATE_EXISTING;
|
create_mode = win32.TRUNCATE_EXISTING;
|
||||||
@@ -156,7 +156,7 @@ read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
|||||||
|
|
||||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||||
w: u32;
|
w: u32;
|
||||||
match whence {
|
switch whence {
|
||||||
case 0: w = win32.FILE_BEGIN;
|
case 0: w = win32.FILE_BEGIN;
|
||||||
case 1: w = win32.FILE_CURRENT;
|
case 1: w = win32.FILE_CURRENT;
|
||||||
case 2: w = win32.FILE_END;
|
case 2: w = win32.FILE_END;
|
||||||
@@ -272,7 +272,7 @@ _alloc_command_line_arguments :: proc() -> []string {
|
|||||||
|
|
||||||
i, j := 0, 0;
|
i, j := 0, 0;
|
||||||
for str[j] != 0 {
|
for str[j] != 0 {
|
||||||
match {
|
switch {
|
||||||
case str[j] < 0x80:
|
case str[j] < 0x80:
|
||||||
if i+1 > len do return "";
|
if i+1 > len do return "";
|
||||||
buf[i] = u8(str[j]); i += 1;
|
buf[i] = u8(str[j]); i += 1;
|
||||||
|
|||||||
+90
-80
@@ -1,19 +1,18 @@
|
|||||||
foreign_system_library (
|
foreign import dl "system:dl"
|
||||||
dl "dl";
|
foreign import libc "system:c"
|
||||||
libc "c";
|
|
||||||
)
|
|
||||||
|
|
||||||
import "strings.odin";
|
import "core:strings.odin"
|
||||||
|
import "core:mem.odin"
|
||||||
|
|
||||||
Handle :: i32;
|
Handle :: i32;
|
||||||
File_Time :: u64;
|
File_Time :: u64;
|
||||||
Errno :: int;
|
Errno :: int;
|
||||||
|
|
||||||
|
|
||||||
O_RDONLY :: 0x00000;
|
O_RDONLY :: 0x00000;
|
||||||
O_WRONLY :: 0x00001;
|
O_WRONLY :: 0x00001;
|
||||||
O_RDWR :: 0x00002;
|
O_RDWR :: 0x00002;
|
||||||
O_CREAT :: 0x00040;
|
O_CREATE :: 0x00040;
|
||||||
O_EXCL :: 0x00080;
|
O_EXCL :: 0x00080;
|
||||||
O_NOCTTY :: 0x00100;
|
O_NOCTTY :: 0x00100;
|
||||||
O_TRUNC :: 0x00200;
|
O_TRUNC :: 0x00200;
|
||||||
@@ -44,35 +43,36 @@ RTLD_NOLOAD :: 0x10;
|
|||||||
RTLD_FIRST :: 0x100;
|
RTLD_FIRST :: 0x100;
|
||||||
|
|
||||||
|
|
||||||
args: [dynamic]string;
|
// "Argv" arguments converted to Odin strings
|
||||||
|
args := _alloc_command_line_arguments();
|
||||||
|
|
||||||
_File_Time :: struct #ordered {
|
_File_Time :: struct #ordered {
|
||||||
seconds: i64;
|
seconds: i64,
|
||||||
nanoseconds: i64;
|
nanoseconds: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
Stat :: struct #ordered {
|
Stat :: struct #ordered {
|
||||||
device_id: i32; // ID of device containing file
|
device_id: i32, // ID of device containing file
|
||||||
mode: u16; // Mode of the file
|
mode: u16, // Mode of the file
|
||||||
nlink: u16; // Number of hard links
|
nlink: u16, // Number of hard links
|
||||||
serial: u64; // File serial number
|
serial: u64, // File serial number
|
||||||
uid: u32; // User ID of the file's owner
|
uid: u32, // User ID of the file's owner
|
||||||
gid: u32; // Group ID of the file's group
|
gid: u32, // Group ID of the file's group
|
||||||
rdev: i32; // Device ID, if device
|
rdev: i32, // Device ID, if device
|
||||||
|
|
||||||
last_access: File_Time; // Time of last access
|
last_access: File_Time, // Time of last access
|
||||||
modified: File_Time; // Time of last modification
|
modified: File_Time, // Time of last modification
|
||||||
status_change: File_Time; // Time of last status change
|
status_change: File_Time, // Time of last status change
|
||||||
created: File_Time; // Time of creation
|
created: File_Time, // Time of creation
|
||||||
|
|
||||||
size: i64; // Size of the file, in bytes
|
size: i64, // Size of the file, in bytes
|
||||||
blocks: i64; // Number of blocks allocated for the file
|
blocks: i64, // Number of blocks allocated for the file
|
||||||
block_size: i32; // Optimal blocksize for I/O
|
block_size: i32, // Optimal blocksize for I/O
|
||||||
flags: u32; // User-defined flags for the file
|
flags: u32, // User-defined flags for the file
|
||||||
gen_num: u32; // File generation number ...?
|
gen_num: u32, // File generation number ...?
|
||||||
_spare: i32; // RESERVED
|
_spare: i32, // RESERVED
|
||||||
_reserve1,
|
_reserve1,
|
||||||
_reserve2: i64; // RESERVED
|
_reserve2: i64, // RESERVED
|
||||||
};
|
};
|
||||||
|
|
||||||
// File type
|
// File type
|
||||||
@@ -108,13 +108,13 @@ S_ISUID :: 0004000; // Set user id on execution
|
|||||||
S_ISGID :: 0002000; // Set group id on execution
|
S_ISGID :: 0002000; // Set group id on execution
|
||||||
S_ISVTX :: 0001000; // Directory restrcted delete
|
S_ISVTX :: 0001000; // Directory restrcted delete
|
||||||
|
|
||||||
S_ISLNK :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFLNK;
|
S_ISLNK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK;
|
||||||
S_ISREG :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFREG;
|
S_ISREG :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG;
|
||||||
S_ISDIR :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFDIR;
|
S_ISDIR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR;
|
||||||
S_ISCHR :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFCHR;
|
S_ISCHR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR;
|
||||||
S_ISBLK :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFBLK;
|
S_ISBLK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK;
|
||||||
S_ISFIFO :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFIFO;
|
S_ISFIFO :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO;
|
||||||
S_ISSOCK :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFSOCK;
|
S_ISSOCK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK;
|
||||||
|
|
||||||
R_OK :: 4; // Test for read permission
|
R_OK :: 4; // Test for read permission
|
||||||
W_OK :: 2; // Test for write permission
|
W_OK :: 2; // Test for write permission
|
||||||
@@ -122,35 +122,36 @@ X_OK :: 1; // Test for execute permission
|
|||||||
F_OK :: 0; // Test for file existance
|
F_OK :: 0; // Test for file existance
|
||||||
|
|
||||||
foreign libc {
|
foreign libc {
|
||||||
unix_open :: proc(path: ^u8, mode: int) -> Handle #link_name "open" ---;
|
@(link_name="open") _unix_open :: proc(path: ^u8, mode: int) -> Handle ---;
|
||||||
unix_close :: proc(handle: Handle) #link_name "close" ---;
|
@(link_name="close") _unix_close :: proc(handle: Handle) ---;
|
||||||
unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int #link_name "read" ---;
|
@(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---;
|
||||||
unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int #link_name "write" ---;
|
@(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---;
|
||||||
unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int #link_name "lseek" ---;
|
@(link_name="lseek") _unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int ---;
|
||||||
unix_gettid :: proc() -> u64 #link_name "gettid" ---;
|
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---;
|
||||||
unix_stat :: proc(path: ^u8, stat: ^Stat) -> int #link_name "stat" ---;
|
@(link_name="stat") _unix_stat :: proc(path: ^u8, stat: ^Stat) -> int ---;
|
||||||
unix_access :: proc(path: ^u8, mask: int) -> int #link_name "access" ---;
|
@(link_name="access") _unix_access :: proc(path: ^u8, mask: int) -> int ---;
|
||||||
|
|
||||||
unix_malloc :: proc(size: int) -> rawptr #link_name "malloc" ---;
|
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---;
|
||||||
unix_free :: proc(ptr: rawptr) #link_name "free" ---;
|
@(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---;
|
||||||
unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #link_name "realloc" ---;
|
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---;
|
||||||
unix_getenv :: proc(^u8) -> ^u8 #link_name "getenv" ---;
|
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
|
||||||
|
@(link_name="getenv") _unix_getenv :: proc(^u8) -> ^u8 ---;
|
||||||
|
|
||||||
unix_exit :: proc(status: int) #link_name "exit" ---;
|
@(link_name="exit") _unix_exit :: proc(status: int) ---;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreign dl {
|
foreign dl {
|
||||||
unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #link_name "dlopen" ---;
|
@(link_name="dlopen") _unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr ---;
|
||||||
unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym" ---;
|
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> rawptr ---;
|
||||||
unix_dlclose :: proc(handle: rawptr) -> int #link_name "dlclose" ---;
|
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---;
|
||||||
unix_dlerror :: proc() -> ^u8 #link_name "dlerror" ---;
|
@(link_name="dlerror") _unix_dlerror :: proc() -> ^u8 ---;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
|
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
|
||||||
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
|
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
|
||||||
|
|
||||||
cstr := strings.new_c_string(path);
|
cstr := strings.new_c_string(path);
|
||||||
handle := unix_open(cstr, mode);
|
handle := _unix_open(cstr, mode);
|
||||||
free(cstr);
|
free(cstr);
|
||||||
if(handle == -1) {
|
if(handle == -1) {
|
||||||
return 0, 1;
|
return 0, 1;
|
||||||
@@ -164,13 +165,13 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errn
|
|||||||
}
|
}
|
||||||
|
|
||||||
close :: proc(fd: Handle) {
|
close :: proc(fd: Handle) {
|
||||||
unix_close(fd);
|
_unix_close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||||
assert(fd != -1);
|
assert(fd != -1);
|
||||||
|
|
||||||
bytes_written := unix_write(fd, &data[0], len(data));
|
bytes_written := _unix_write(fd, &data[0], len(data));
|
||||||
if(bytes_written == -1) {
|
if(bytes_written == -1) {
|
||||||
return 0, 1;
|
return 0, 1;
|
||||||
}
|
}
|
||||||
@@ -180,7 +181,7 @@ write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
|||||||
read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||||
assert(fd != -1);
|
assert(fd != -1);
|
||||||
|
|
||||||
bytes_read := unix_read(fd, &data[0], len(data));
|
bytes_read := _unix_read(fd, &data[0], len(data));
|
||||||
if(bytes_read == -1) {
|
if(bytes_read == -1) {
|
||||||
return 0, 1;
|
return 0, 1;
|
||||||
}
|
}
|
||||||
@@ -190,7 +191,7 @@ read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
|||||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||||
assert(fd != -1);
|
assert(fd != -1);
|
||||||
|
|
||||||
final_offset := i64(unix_lseek(fd, offset, whence));
|
final_offset := i64(_unix_lseek(fd, int(offset), whence));
|
||||||
if(final_offset == -1) {
|
if(final_offset == -1) {
|
||||||
return 0, 1;
|
return 0, 1;
|
||||||
}
|
}
|
||||||
@@ -216,34 +217,34 @@ last_write_time :: proc(fd: Handle) -> File_Time {}
|
|||||||
last_write_time_by_name :: proc(name: string) -> File_Time {}
|
last_write_time_by_name :: proc(name: string) -> File_Time {}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
stat :: proc(path: string) -> (Stat, bool) #inline {
|
stat :: inline proc(path: string) -> (Stat, bool) {
|
||||||
s: Stat;
|
s: Stat;
|
||||||
cstr := strings.new_c_string(path);
|
cstr := strings.new_c_string(path);
|
||||||
defer free(cstr);
|
defer free(cstr);
|
||||||
ret_int := unix_stat(cstr, &s);
|
ret_int := _unix_stat(cstr, &s);
|
||||||
return s, ret_int==0;
|
return s, ret_int==0;
|
||||||
}
|
}
|
||||||
|
|
||||||
access :: proc(path: string, mask: int) -> bool #inline {
|
access :: inline proc(path: string, mask: int) -> bool {
|
||||||
cstr := strings.new_c_string(path);
|
cstr := strings.new_c_string(path);
|
||||||
defer free(cstr);
|
defer free(cstr);
|
||||||
return unix_access(cstr, mask) == 0;
|
return _unix_access(cstr, mask) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_alloc :: proc(size: int) -> rawptr #inline {
|
heap_alloc :: inline proc(size: int) -> rawptr {
|
||||||
assert(size > 0);
|
assert(size > 0);
|
||||||
return unix_malloc(size);
|
return _unix_calloc(1, size);
|
||||||
}
|
}
|
||||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr #inline {
|
heap_resize :: inline proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
return unix_realloc(ptr, new_size);
|
return _unix_realloc(ptr, new_size);
|
||||||
}
|
}
|
||||||
heap_free :: proc(ptr: rawptr) #inline {
|
heap_free :: inline proc(ptr: rawptr) {
|
||||||
unix_free(ptr);
|
_unix_free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
getenv :: proc(name: string) -> (string, bool) {
|
getenv :: proc(name: string) -> (string, bool) {
|
||||||
path_str := strings.new_c_string(name);
|
path_str := strings.new_c_string(name);
|
||||||
cstr: ^u8 = unix_getenv(path_str);
|
cstr: ^u8 = _unix_getenv(path_str);
|
||||||
free(path_str);
|
free(path_str);
|
||||||
if(cstr == nil) {
|
if(cstr == nil) {
|
||||||
return "", false;
|
return "", false;
|
||||||
@@ -251,33 +252,42 @@ getenv :: proc(name: string) -> (string, bool) {
|
|||||||
return strings.to_odin_string(cstr), true;
|
return strings.to_odin_string(cstr), true;
|
||||||
}
|
}
|
||||||
|
|
||||||
exit :: proc(code: int) #inline {
|
exit :: inline proc(code: int) {
|
||||||
unix_exit(code);
|
_unix_exit(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
current_thread_id :: proc() -> int {
|
current_thread_id :: proc() -> int {
|
||||||
// return cast(int) unix_gettid();
|
// return cast(int) _unix_gettid();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dlopen :: proc(filename: string, flags: int) -> rawptr #inline {
|
dlopen :: inline proc(filename: string, flags: int) -> rawptr {
|
||||||
cstr := strings.new_c_string(filename);
|
cstr := strings.new_c_string(filename);
|
||||||
handle := unix_dlopen(cstr, flags);
|
handle := _unix_dlopen(cstr, flags);
|
||||||
free(cstr);
|
free(cstr);
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
dlsym :: proc(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
|
dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {
|
||||||
assert(handle != nil);
|
assert(handle != nil);
|
||||||
cstr := strings.new_c_string(symbol);
|
cstr := strings.new_c_string(symbol);
|
||||||
proc_handle := unix_dlsym(handle, cstr);
|
proc_handle := _unix_dlsym(handle, cstr);
|
||||||
free(cstr);
|
free(cstr);
|
||||||
return proc_handle;
|
return proc_handle;
|
||||||
}
|
}
|
||||||
dlclose :: proc(handle: rawptr) -> bool #inline {
|
dlclose :: inline proc(handle: rawptr) -> bool {
|
||||||
assert(handle != nil);
|
assert(handle != nil);
|
||||||
return unix_dlclose(handle) == 0;
|
return _unix_dlclose(handle) == 0;
|
||||||
}
|
}
|
||||||
dlerror :: proc() -> string {
|
dlerror :: proc() -> string {
|
||||||
return strings.to_odin_string(unix_dlerror());
|
return strings.to_odin_string(_unix_dlerror());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_alloc_command_line_arguments :: proc() -> []string {
|
||||||
|
args := make([]string, __argc__);
|
||||||
|
for i in 0..__argc__ {
|
||||||
|
args[i] = strings.to_odin_string((__argv__+i)^);
|
||||||
|
}
|
||||||
|
return args;
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-18
@@ -1,28 +1,28 @@
|
|||||||
Any :: struct #ordered {
|
Any :: struct #ordered {
|
||||||
data: rawptr;
|
data: rawptr,
|
||||||
type_info: ^Type_Info;
|
type_info: ^Type_Info,
|
||||||
};
|
}
|
||||||
|
|
||||||
String :: struct #ordered {
|
String :: struct #ordered {
|
||||||
data: ^u8;
|
data: ^u8,
|
||||||
len: int;
|
len: int,
|
||||||
};
|
}
|
||||||
|
|
||||||
Slice :: struct #ordered {
|
Slice :: struct #ordered {
|
||||||
data: rawptr;
|
data: rawptr,
|
||||||
len: int;
|
len: int,
|
||||||
cap: int;
|
cap: int,
|
||||||
};
|
}
|
||||||
|
|
||||||
Dynamic_Array :: struct #ordered {
|
Dynamic_Array :: struct #ordered {
|
||||||
data: rawptr;
|
data: rawptr,
|
||||||
len: int;
|
len: int,
|
||||||
cap: int;
|
cap: int,
|
||||||
allocator: Allocator;
|
allocator: Allocator,
|
||||||
};
|
}
|
||||||
|
|
||||||
Map :: struct #ordered {
|
Map :: struct #ordered {
|
||||||
hashes: [dynamic]int;
|
hashes: [dynamic]int,
|
||||||
entries: Dynamic_Array;
|
entries: Dynamic_Array,
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -187,7 +187,7 @@ merge_sort :: proc(array: $A/[]$T) {
|
|||||||
|
|
||||||
|
|
||||||
compare_ints :: proc(a, b: int) -> int {
|
compare_ints :: proc(a, b: int) -> int {
|
||||||
match delta := a - b; {
|
switch delta := a - b; {
|
||||||
case delta < 0: return -1;
|
case delta < 0: return -1;
|
||||||
case delta > 0: return +1;
|
case delta > 0: return +1;
|
||||||
}
|
}
|
||||||
@@ -195,14 +195,14 @@ compare_ints :: proc(a, b: int) -> int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compare_f32s :: proc(a, b: f32) -> int {
|
compare_f32s :: proc(a, b: f32) -> int {
|
||||||
match delta := a - b; {
|
switch delta := a - b; {
|
||||||
case delta < 0: return -1;
|
case delta < 0: return -1;
|
||||||
case delta > 0: return +1;
|
case delta > 0: return +1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
compare_f64s :: proc(a, b: f64) -> int {
|
compare_f64s :: proc(a, b: f64) -> int {
|
||||||
match delta := a - b; {
|
switch delta := a - b; {
|
||||||
case delta < 0: return -1;
|
case delta < 0: return -1;
|
||||||
case delta > 0: return +1;
|
case delta > 0: return +1;
|
||||||
}
|
}
|
||||||
|
|||||||
+60
-67
@@ -1,4 +1,4 @@
|
|||||||
import . "decimal.odin";
|
using import "core:decimal.odin"
|
||||||
|
|
||||||
Int_Flag :: enum {
|
Int_Flag :: enum {
|
||||||
Prefix = 1<<0,
|
Prefix = 1<<0,
|
||||||
@@ -7,23 +7,23 @@ Int_Flag :: enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
parse_bool :: proc(s: string) -> (result: bool, ok: bool) {
|
parse_bool :: proc(s: string) -> (result: bool = false, ok: bool) {
|
||||||
match s {
|
switch s {
|
||||||
case "1", "t", "T", "true", "TRUE", "True":
|
case "1", "t", "T", "true", "TRUE", "True":
|
||||||
return true, true;
|
return true, true;
|
||||||
case "0", "f", "F", "false", "FALSE", "False":
|
case "0", "f", "F", "false", "FALSE", "False":
|
||||||
return false, true;
|
return false, true;
|
||||||
}
|
}
|
||||||
return false, false;
|
return ok = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_digit_value :: proc(r: rune) -> int {
|
_digit_value :: proc(r: rune) -> int {
|
||||||
ri := int(r);
|
ri := int(r);
|
||||||
v: int = 16;
|
v: int = 16;
|
||||||
match r {
|
switch r {
|
||||||
case '0'..'9': v = ri-'0';
|
case '0'...'9': v = ri-'0';
|
||||||
case 'a'..'z': v = ri-'a'+10;
|
case 'a'...'z': v = ri-'a'+10;
|
||||||
case 'A'..'Z': v = ri-'A'+10;
|
case 'A'...'Z': v = ri-'A'+10;
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ _digit_value :: proc(r: rune) -> int {
|
|||||||
parse_i128 :: proc(s: string) -> i128 {
|
parse_i128 :: proc(s: string) -> i128 {
|
||||||
neg := false;
|
neg := false;
|
||||||
if len(s) > 1 {
|
if len(s) > 1 {
|
||||||
match s[0] {
|
switch s[0] {
|
||||||
case '-':
|
case '-':
|
||||||
neg = true;
|
neg = true;
|
||||||
s = s[1..];
|
s = s[1..];
|
||||||
@@ -43,7 +43,7 @@ parse_i128 :: proc(s: string) -> i128 {
|
|||||||
|
|
||||||
base: i128 = 10;
|
base: i128 = 10;
|
||||||
if len(s) > 2 && s[0] == '0' {
|
if len(s) > 2 && s[0] == '0' {
|
||||||
match s[1] {
|
switch s[1] {
|
||||||
case 'b': base = 2; s = s[2..];
|
case 'b': base = 2; s = s[2..];
|
||||||
case 'o': base = 8; s = s[2..];
|
case 'o': base = 8; s = s[2..];
|
||||||
case 'd': base = 10; s = s[2..];
|
case 'd': base = 10; s = s[2..];
|
||||||
@@ -80,7 +80,7 @@ parse_u128 :: proc(s: string) -> u128 {
|
|||||||
|
|
||||||
base := u128(10);
|
base := u128(10);
|
||||||
if len(s) > 2 && s[0] == '0' {
|
if len(s) > 2 && s[0] == '0' {
|
||||||
match s[1] {
|
switch s[1] {
|
||||||
case 'b': base = 2; s = s[2..];
|
case 'b': base = 2; s = s[2..];
|
||||||
case 'o': base = 8; s = s[2..];
|
case 'o': base = 8; s = s[2..];
|
||||||
case 'd': base = 10; s = s[2..];
|
case 'd': base = 10; s = s[2..];
|
||||||
@@ -115,7 +115,7 @@ parse_f64 :: proc(s: string) -> f64 {
|
|||||||
i := 0;
|
i := 0;
|
||||||
|
|
||||||
sign: f64 = 1;
|
sign: f64 = 1;
|
||||||
match s[i] {
|
switch s[i] {
|
||||||
case '-': i += 1; sign = -1;
|
case '-': i += 1; sign = -1;
|
||||||
case '+': i += 1;
|
case '+': i += 1;
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ parse_f64 :: proc(s: string) -> f64 {
|
|||||||
value += f64(v);
|
value += f64(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
if s[i] == '.' {
|
if i < len(s) && s[i] == '.' {
|
||||||
pow10: f64 = 10;
|
pow10: f64 = 10;
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
||||||
@@ -149,28 +149,30 @@ parse_f64 :: proc(s: string) -> f64 {
|
|||||||
frac := false;
|
frac := false;
|
||||||
scale: f64 = 1;
|
scale: f64 = 1;
|
||||||
|
|
||||||
if s[i] == 'e' || s[i] == 'E' {
|
if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
||||||
match s[i] {
|
if i < len(s) {
|
||||||
case '-': i += 1; frac = true;
|
switch s[i] {
|
||||||
case '+': i += 1;
|
case '-': i += 1; frac = true;
|
||||||
|
case '+': i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
exp: u32 = 0;
|
||||||
|
for ; i < len(s); i += 1 {
|
||||||
|
r := rune(s[i]);
|
||||||
|
if r == '_' do continue;
|
||||||
|
|
||||||
|
d := u32(_digit_value(r));
|
||||||
|
if d >= 10 do break;
|
||||||
|
exp = exp * 10 + d;
|
||||||
|
}
|
||||||
|
if exp > 308 { exp = 308; }
|
||||||
|
|
||||||
|
for exp >= 50 { scale *= 1e50; exp -= 50; }
|
||||||
|
for exp >= 8 { scale *= 1e8; exp -= 8; }
|
||||||
|
for exp > 0 { scale *= 10; exp -= 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
exp: u32 = 0;
|
|
||||||
for ; i < len(s); i += 1 {
|
|
||||||
r := rune(s[i]);
|
|
||||||
if r == '_' do continue;
|
|
||||||
|
|
||||||
d := u32(_digit_value(r));
|
|
||||||
if d >= 10 do break;
|
|
||||||
exp = exp * 10 + d;
|
|
||||||
}
|
|
||||||
if exp > 308 { exp = 308; }
|
|
||||||
|
|
||||||
for exp >= 50 { scale *= 1e50; exp -= 50; }
|
|
||||||
for exp >= 8 { scale *= 1e8; exp -= 8; }
|
|
||||||
for exp > 0 { scale *= 10; exp -= 1; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if frac do return sign * (value/scale);
|
if frac do return sign * (value/scale);
|
||||||
@@ -179,11 +181,8 @@ parse_f64 :: proc(s: string) -> f64 {
|
|||||||
|
|
||||||
|
|
||||||
append_bool :: proc(buf: []u8, b: bool) -> string {
|
append_bool :: proc(buf: []u8, b: bool) -> string {
|
||||||
if b {
|
if b do append(&buf, "true");
|
||||||
append(&buf, "true");
|
else do append(&buf, "false");
|
||||||
} else {
|
|
||||||
append(&buf, "false");
|
|
||||||
}
|
|
||||||
return string(buf);
|
return string(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +192,7 @@ append_uint :: proc(buf: []u8, u: u64, base: int) -> string {
|
|||||||
append_int :: proc(buf: []u8, i: i64, base: int) -> string {
|
append_int :: proc(buf: []u8, i: i64, base: int) -> string {
|
||||||
return append_bits(buf, u128(i), base, true, 8*size_of(int), digits, 0);
|
return append_bits(buf, u128(i), base, true, 8*size_of(int), digits, 0);
|
||||||
}
|
}
|
||||||
itoa :: proc(buf: []u8, i: int) -> string { return append_int(buf, i64(i), 10); }
|
itoa :: proc(buf: []u8, i: int) -> string do return append_int(buf, i64(i), 10);
|
||||||
|
|
||||||
append_float :: proc(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string {
|
append_float :: proc(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string {
|
||||||
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
|
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
|
||||||
@@ -203,16 +202,16 @@ append_float :: proc(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string
|
|||||||
|
|
||||||
|
|
||||||
DecimalSlice :: struct {
|
DecimalSlice :: struct {
|
||||||
digits: []u8;
|
digits: []u8,
|
||||||
count: int;
|
count: int,
|
||||||
decimal_point: int;
|
decimal_point: int,
|
||||||
neg: bool;
|
neg: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatInfo :: struct {
|
FloatInfo :: struct {
|
||||||
mantbits: uint;
|
mantbits: uint,
|
||||||
expbits: uint;
|
expbits: uint,
|
||||||
bias: int;
|
bias: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -224,7 +223,7 @@ _f64_info := FloatInfo{52, 11, -1023};
|
|||||||
generic_ftoa :: proc(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
|
generic_ftoa :: proc(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
|
||||||
bits: u64;
|
bits: u64;
|
||||||
flt: ^FloatInfo;
|
flt: ^FloatInfo;
|
||||||
match bit_size {
|
switch bit_size {
|
||||||
case 32:
|
case 32:
|
||||||
bits = u64(transmute(u32)f32(val));
|
bits = u64(transmute(u32)f32(val));
|
||||||
flt = &_f32_info;
|
flt = &_f32_info;
|
||||||
@@ -239,7 +238,7 @@ generic_ftoa :: proc(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8
|
|||||||
exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1);
|
exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1);
|
||||||
mant := bits & (u64(1) << flt.mantbits - 1);
|
mant := bits & (u64(1) << flt.mantbits - 1);
|
||||||
|
|
||||||
match exp {
|
switch exp {
|
||||||
case 1<<flt.expbits - 1:
|
case 1<<flt.expbits - 1:
|
||||||
s: string;
|
s: string;
|
||||||
if mant != 0 {
|
if mant != 0 {
|
||||||
@@ -270,13 +269,13 @@ generic_ftoa :: proc(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8
|
|||||||
if shortest {
|
if shortest {
|
||||||
round_shortest(d, mant, exp, flt);
|
round_shortest(d, mant, exp, flt);
|
||||||
digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
|
digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
|
||||||
match fmt {
|
switch fmt {
|
||||||
case 'e', 'E': prec = digs.count-1;
|
case 'e', 'E': prec = digs.count-1;
|
||||||
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
|
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
|
||||||
case 'g', 'G': prec = digs.count;
|
case 'g', 'G': prec = digs.count;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match fmt {
|
switch fmt {
|
||||||
case 'e', 'E': round(d, prec+1);
|
case 'e', 'E': round(d, prec+1);
|
||||||
case 'f', 'F': round(d, d.decimal_point+prec);
|
case 'f', 'F': round(d, d.decimal_point+prec);
|
||||||
case 'g', 'G':
|
case 'g', 'G':
|
||||||
@@ -294,14 +293,14 @@ generic_ftoa :: proc(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8
|
|||||||
|
|
||||||
|
|
||||||
format_digits :: proc(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: u8) -> []u8 {
|
format_digits :: proc(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: u8) -> []u8 {
|
||||||
match fmt {
|
switch fmt {
|
||||||
case 'f', 'F':
|
case 'f', 'F':
|
||||||
append(&buf, neg ? '-' : '+');
|
append(&buf, neg ? '-' : '+');
|
||||||
|
|
||||||
// integer, padded with zeros when needed
|
// integer, padded with zeros when needed
|
||||||
if digs.decimal_point > 0 {
|
if digs.decimal_point > 0 {
|
||||||
m := min(digs.count, digs.decimal_point);
|
m := min(digs.count, digs.decimal_point);
|
||||||
append(&buf, ...digs.digits[..m]);
|
append(&buf, ...digs.digits[0..m]);
|
||||||
for ; m < digs.decimal_point; m += 1 {
|
for ; m < digs.decimal_point; m += 1 {
|
||||||
append(&buf, '0');
|
append(&buf, '0');
|
||||||
}
|
}
|
||||||
@@ -321,7 +320,6 @@ format_digits :: proc(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice,
|
|||||||
append(&buf, c);
|
append(&buf, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
|
|
||||||
case 'e', 'E':
|
case 'e', 'E':
|
||||||
@@ -389,15 +387,15 @@ round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^FloatInfo) {
|
|||||||
ok_round_down := l != m || inclusive && i+1 == lower.count;
|
ok_round_down := l != m || inclusive && i+1 == lower.count;
|
||||||
ok_round_up := m != u && (inclusive || m+1 < u || i+1 < upper.count);
|
ok_round_up := m != u && (inclusive || m+1 < u || i+1 < upper.count);
|
||||||
|
|
||||||
if (ok_round_down && ok_round_up) {
|
if ok_round_down && ok_round_up {
|
||||||
round(d, i+1);
|
round(d, i+1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ok_round_down) {
|
if ok_round_down {
|
||||||
round_down(d, i+1);
|
round_down(d, i+1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ok_round_up) {
|
if ok_round_up {
|
||||||
round_up(d, i+1);
|
round_up(d, i+1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -412,32 +410,27 @@ digits := "0123456789abcdefghijklmnopqrstuvwxyz";
|
|||||||
is_integer_negative :: proc(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
|
is_integer_negative :: proc(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
|
||||||
neg := false;
|
neg := false;
|
||||||
if is_signed {
|
if is_signed {
|
||||||
match bit_size {
|
switch bit_size {
|
||||||
case 8:
|
case 8:
|
||||||
i := i8(u);
|
i := i8(u);
|
||||||
neg = i < 0;
|
neg = i < 0;
|
||||||
if neg { i = -i; }
|
u = u128(abs(i));
|
||||||
u = u128(i);
|
|
||||||
case 16:
|
case 16:
|
||||||
i := i16(u);
|
i := i16(u);
|
||||||
neg = i < 0;
|
neg = i < 0;
|
||||||
if neg { i = -i; }
|
u = u128(abs(i));
|
||||||
u = u128(i);
|
|
||||||
case 32:
|
case 32:
|
||||||
i := i32(u);
|
i := i32(u);
|
||||||
neg = i < 0;
|
neg = i < 0;
|
||||||
if neg { i = -i; }
|
u = u128(abs(i));
|
||||||
u = u128(i);
|
|
||||||
case 64:
|
case 64:
|
||||||
i := i64(u);
|
i := i64(u);
|
||||||
neg = i < 0;
|
neg = i < 0;
|
||||||
if neg { i = -i; }
|
u = u128(abs(i));
|
||||||
u = u128(i);
|
|
||||||
case 128:
|
case 128:
|
||||||
i := i128(u);
|
i := i128(u);
|
||||||
neg = i < 0;
|
neg = i < 0;
|
||||||
if neg { i = -i; }
|
u = u128(abs(i));
|
||||||
u = u128(i);
|
|
||||||
case:
|
case:
|
||||||
panic("is_integer_negative: Unknown integer size");
|
panic("is_integer_negative: Unknown integer size");
|
||||||
}
|
}
|
||||||
@@ -463,7 +456,7 @@ append_bits :: proc(buf: []u8, u: u128, base: int, is_signed: bool, bit_size: in
|
|||||||
|
|
||||||
if flags&Int_Flag.Prefix != 0 {
|
if flags&Int_Flag.Prefix != 0 {
|
||||||
ok := true;
|
ok := true;
|
||||||
match base {
|
switch base {
|
||||||
case 2: i-=1; a[i] = 'b';
|
case 2: i-=1; a[i] = 'b';
|
||||||
case 8: i-=1; a[i] = 'o';
|
case 8: i-=1; a[i] = 'o';
|
||||||
case 10: i-=1; a[i] = 'd';
|
case 10: i-=1; a[i] = 'd';
|
||||||
|
|||||||
+6
-6
@@ -1,4 +1,4 @@
|
|||||||
import "mem.odin";
|
import "core:mem.odin"
|
||||||
|
|
||||||
new_string :: proc(s: string) -> string {
|
new_string :: proc(s: string) -> string {
|
||||||
c := make([]u8, len(s)+1);
|
c := make([]u8, len(s)+1);
|
||||||
@@ -14,9 +14,9 @@ new_c_string :: proc(s: string) -> ^u8 {
|
|||||||
return &c[0];
|
return &c[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
to_odin_string :: proc(c: ^u8) -> string {
|
to_odin_string :: proc(str: ^u8) -> string {
|
||||||
if c == nil do return "";
|
if str == nil do return "";
|
||||||
len := 0;
|
end := str;
|
||||||
for (c+len)^ != 0 do len+=1;
|
for end^ != 0 do end+=1;
|
||||||
return string(mem.slice_ptr(c, len));
|
return string(mem.slice_ptr(str, end-str));
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-4
@@ -1,4 +1,2 @@
|
|||||||
import_load (
|
when ODIN_OS == "windows" do export "core:sync_windows.odin";
|
||||||
"sync_windows.odin" when ODIN_OS == "windows";
|
when ODIN_OS == "linux" do export "core:sync_linux.odin";
|
||||||
"sync_linux.odin" when ODIN_OS == "linux";
|
|
||||||
)
|
|
||||||
|
|||||||
+8
-10
@@ -1,17 +1,15 @@
|
|||||||
import (
|
import "core:atomics.odin"
|
||||||
"atomics.odin";
|
import "core:os.odin"
|
||||||
"os.odin";
|
|
||||||
)
|
|
||||||
|
|
||||||
Semaphore :: struct {
|
Semaphore :: struct {
|
||||||
// _handle: win32.Handle;
|
// _handle: win32.Handle,
|
||||||
}
|
}
|
||||||
|
|
||||||
Mutex :: struct {
|
Mutex :: struct {
|
||||||
_semaphore: Semaphore;
|
_semaphore: Semaphore,
|
||||||
_counter: i32;
|
_counter: i32,
|
||||||
_owner: i32;
|
_owner: i32,
|
||||||
_recursion: i32;
|
_recursion: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
current_thread_id :: proc() -> i32 {
|
current_thread_id :: proc() -> i32 {
|
||||||
@@ -30,7 +28,7 @@ semaphore_post :: proc(s: ^Semaphore, count: int) {
|
|||||||
// win32.ReleaseSemaphore(s._handle, cast(i32)count, nil);
|
// win32.ReleaseSemaphore(s._handle, cast(i32)count, nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
semaphore_release :: proc(s: ^Semaphore) #inline {
|
semaphore_release :: inline proc(s: ^Semaphore) {
|
||||||
semaphore_post(s, 1);
|
semaphore_post(s, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-11
@@ -1,23 +1,23 @@
|
|||||||
import (
|
when ODIN_OS == "windows" {
|
||||||
win32 "sys/windows.odin" when ODIN_OS == "windows";
|
import win32 "core:sys/windows.odin";
|
||||||
"atomics.odin";
|
}
|
||||||
)
|
import "core:atomics.odin"
|
||||||
|
|
||||||
Semaphore :: struct {
|
Semaphore :: struct {
|
||||||
_handle: win32.Handle;
|
_handle: win32.Handle,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Mutex :: struct {
|
Mutex :: struct {
|
||||||
_semaphore: Semaphore;
|
_semaphore: Semaphore,
|
||||||
_counter: i32;
|
_counter: i32,
|
||||||
_owner: i32;
|
_owner: i32,
|
||||||
_recursion: i32;
|
_recursion: i32,
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Mutex :: struct {
|
Mutex :: struct {
|
||||||
_critical_section: win32.Critical_Section;
|
_critical_section: win32.Critical_Section,
|
||||||
}
|
}
|
||||||
|
|
||||||
current_thread_id :: proc() -> i32 {
|
current_thread_id :: proc() -> i32 {
|
||||||
@@ -36,7 +36,9 @@ semaphore_post :: proc(s: ^Semaphore, count: int) {
|
|||||||
win32.release_semaphore(s._handle, i32(count), nil);
|
win32.release_semaphore(s._handle, i32(count), nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
|
semaphore_release :: inline proc(s: ^Semaphore) {
|
||||||
|
semaphore_post(s, 1);
|
||||||
|
}
|
||||||
|
|
||||||
semaphore_wait :: proc(s: ^Semaphore) {
|
semaphore_wait :: proc(s: ^Semaphore) {
|
||||||
win32.wait_for_single_object(s._handle, win32.INFINITE);
|
win32.wait_for_single_object(s._handle, win32.INFINITE);
|
||||||
|
|||||||
+85
-53
@@ -1,5 +1,7 @@
|
|||||||
foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
|
when ODIN_OS == "windows" {
|
||||||
import . "windows.odin";
|
foreign import "system:opengl32.lib"
|
||||||
|
using import "core:sys/windows.odin"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
|
CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
|
||||||
@@ -10,50 +12,50 @@ CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002;
|
|||||||
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001;
|
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001;
|
||||||
CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x00000002;
|
CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x00000002;
|
||||||
|
|
||||||
Hglrc :: Handle;
|
Hglrc :: Handle;
|
||||||
Color_Ref :: u32;
|
Color_Ref :: u32;
|
||||||
|
|
||||||
Layer_Plane_Descriptor :: struct {
|
Layer_Plane_Descriptor :: struct {
|
||||||
size: u16;
|
size: u16,
|
||||||
version: u16;
|
version: u16,
|
||||||
flags: u32;
|
flags: u32,
|
||||||
pixel_type: u8;
|
pixel_type: u8,
|
||||||
color_bits: u8;
|
color_bits: u8,
|
||||||
red_bits: u8;
|
red_bits: u8,
|
||||||
red_shift: u8;
|
red_shift: u8,
|
||||||
green_bits: u8;
|
green_bits: u8,
|
||||||
green_shift: u8;
|
green_shift: u8,
|
||||||
blue_bits: u8;
|
blue_bits: u8,
|
||||||
blue_shift: u8;
|
blue_shift: u8,
|
||||||
alpha_bits: u8;
|
alpha_bits: u8,
|
||||||
alpha_shift: u8;
|
alpha_shift: u8,
|
||||||
accum_bits: u8;
|
accum_bits: u8,
|
||||||
accum_red_bits: u8;
|
accum_red_bits: u8,
|
||||||
accum_green_bits: u8;
|
accum_green_bits: u8,
|
||||||
accum_blue_bits: u8;
|
accum_blue_bits: u8,
|
||||||
accum_alpha_bits: u8;
|
accum_alpha_bits: u8,
|
||||||
depth_bits: u8;
|
depth_bits: u8,
|
||||||
stencil_bits: u8;
|
stencil_bits: u8,
|
||||||
aux_buffers: u8;
|
aux_buffers: u8,
|
||||||
layer_type: u8;
|
layer_type: u8,
|
||||||
reserved: u8;
|
reserved: u8,
|
||||||
transparent: Color_Ref;
|
transparent: Color_Ref,
|
||||||
}
|
}
|
||||||
|
|
||||||
Point_Float :: struct {x, y: f32};
|
Point_Float :: struct {x, y: f32};
|
||||||
|
|
||||||
Glyph_Metrics_Float :: struct {
|
Glyph_Metrics_Float :: struct {
|
||||||
black_box_x: f32;
|
black_box_x: f32,
|
||||||
black_box_y: f32;
|
black_box_y: f32,
|
||||||
glyph_origin: Point_Float;
|
glyph_origin: Point_Float,
|
||||||
cell_inc_x: f32;
|
cell_inc_x: f32,
|
||||||
cell_inc_y: f32;
|
cell_inc_y: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Create_Context_Attribs_ARB_Type :: #type proc(hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
|
Create_Context_Attribs_ARB_Type :: #type proc "c" (hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
|
||||||
Choose_Pixel_Format_ARB_Type :: #type proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c;
|
Choose_Pixel_Format_ARB_Type :: #type proc "c" (hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool;
|
||||||
Swap_Interval_EXT_Type :: #type proc(interval: i32) -> bool #cc_c;
|
Swap_Interval_EXT_Type :: #type proc "c" (interval: i32) -> bool;
|
||||||
Get_Extensions_String_ARB_Type :: #type proc(Hdc) -> ^u8 #cc_c;
|
Get_Extensions_String_ARB_Type :: #type proc "c" (Hdc) -> ^u8;
|
||||||
|
|
||||||
// Procedures
|
// Procedures
|
||||||
create_context_attribs_arb: Create_Context_Attribs_ARB_Type;
|
create_context_attribs_arb: Create_Context_Attribs_ARB_Type;
|
||||||
@@ -62,22 +64,52 @@ Get_Extensions_String_ARB_Type :: #type proc(Hdc) -> ^u8 #cc_c;
|
|||||||
get_extensions_string_arb: Get_Extensions_String_ARB_Type;
|
get_extensions_string_arb: Get_Extensions_String_ARB_Type;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
foreign opengl32 {
|
foreign opengl32 {
|
||||||
create_context :: proc(hdc: Hdc) -> Hglrc #link_name "wglCreateContext" ---;
|
@(link_name="wglCreateContext")
|
||||||
make_current :: proc(hdc: Hdc, hglrc: Hglrc) -> Bool #link_name "wglMakeCurrent" ---;
|
create_context :: proc(hdc: Hdc) -> Hglrc ---;
|
||||||
get_proc_address :: proc(c_str: ^u8) -> rawptr #link_name "wglGetProcAddress" ---;
|
|
||||||
delete_context :: proc(hglrc: Hglrc) -> Bool #link_name "wglDeleteContext" ---;
|
@(link_name="wglMakeCurrent")
|
||||||
copy_context :: proc(src, dst: Hglrc, mask: u32) -> Bool #link_name "wglCopyContext" ---;
|
make_current :: proc(hdc: Hdc, hglrc: Hglrc) -> Bool ---;
|
||||||
create_layer_context :: proc(hdc: Hdc, layer_plane: i32) -> Hglrc #link_name "wglCreateLayerContext" ---;
|
|
||||||
describe_layer_plane :: proc(hdc: Hdc, pixel_format, layer_plane: i32, bytes: u32, pd: ^Layer_Plane_Descriptor) -> Bool #link_name "wglDescribeLayerPlane" ---;
|
@(link_name="wglGetProcAddress")
|
||||||
get_current_context :: proc() -> Hglrc #link_name "wglGetCurrentContext" ---;
|
get_proc_address :: proc(c_str: ^u8) -> rawptr ---;
|
||||||
get_current_dc :: proc() -> Hdc #link_name "wglGetCurrentDC" ---;
|
|
||||||
get_layer_palette_entries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #link_name "wglGetLayerPaletteEntries" ---;
|
@(link_name="wglDeleteContext")
|
||||||
realize_layer_palette :: proc(hdc: Hdc, layer_plane: i32, realize: Bool) -> Bool #link_name "wglRealizeLayerPalette" ---;
|
delete_context :: proc(hglrc: Hglrc) -> Bool ---;
|
||||||
set_layer_palette_entries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #link_name "wglSetLayerPaletteEntries" ---;
|
|
||||||
share_lists :: proc(hglrc1, hglrc2: Hglrc) -> Bool #link_name "wglShareLists" ---;
|
@(link_name="wglCopyContext")
|
||||||
swap_layer_buffers :: proc(hdc: Hdc, planes: u32) -> Bool #link_name "wglSwapLayerBuffers" ---;
|
copy_context :: proc(src, dst: Hglrc, mask: u32) -> Bool ---;
|
||||||
use_font_bitmaps :: proc(hdc: Hdc, first, count, list_base: u32) -> Bool #link_name "wglUseFontBitmaps" ---;
|
|
||||||
use_font_outlines :: proc(hdc: Hdc, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^Glyph_Metrics_Float) -> Bool #link_name "wglUseFontOutlines" ---;
|
@(link_name="wglCreateLayerContext")
|
||||||
|
create_layer_context :: proc(hdc: Hdc, layer_plane: i32) -> Hglrc ---;
|
||||||
|
|
||||||
|
@(link_name="wglDescribeLayerPlane")
|
||||||
|
describe_layer_plane :: proc(hdc: Hdc, pixel_format, layer_plane: i32, bytes: u32, pd: ^Layer_Plane_Descriptor) -> Bool ---;
|
||||||
|
|
||||||
|
@(link_name="wglGetCurrentContext")
|
||||||
|
get_current_context :: proc() -> Hglrc ---;
|
||||||
|
|
||||||
|
@(link_name="wglGetCurrentDC")
|
||||||
|
get_current_dc :: proc() -> Hdc ---;
|
||||||
|
|
||||||
|
@(link_name="wglGetLayerPaletteEntries")
|
||||||
|
get_layer_palette_entries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 ---;
|
||||||
|
|
||||||
|
@(link_name="wglRealizeLayerPalette")
|
||||||
|
realize_layer_palette :: proc(hdc: Hdc, layer_plane: i32, realize: Bool) -> Bool ---;
|
||||||
|
|
||||||
|
@(link_name="wglSetLayerPaletteEntries")
|
||||||
|
set_layer_palette_entries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 ---;
|
||||||
|
|
||||||
|
@(link_name="wglShareLists")
|
||||||
|
share_lists :: proc(hglrc1, hglrc2: Hglrc) -> Bool ---;
|
||||||
|
|
||||||
|
@(link_name="wglSwapLayerBuffers")
|
||||||
|
swap_layer_buffers :: proc(hdc: Hdc, planes: u32) -> Bool ---;
|
||||||
|
|
||||||
|
@(link_name="wglUseFontBitmaps")
|
||||||
|
use_font_bitmaps :: proc(hdc: Hdc, first, count, list_base: u32) -> Bool ---;
|
||||||
|
|
||||||
|
@(link_name="wglUseFontOutlines")
|
||||||
|
use_font_outlines :: proc(hdc: Hdc, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^Glyph_Metrics_Float) -> Bool ---;
|
||||||
}
|
}
|
||||||
|
|||||||
+414
-231
@@ -1,10 +1,10 @@
|
|||||||
foreign_system_library (
|
when ODIN_OS == "windows" {
|
||||||
"kernel32.lib" when ODIN_OS == "windows";
|
foreign import "system:kernel32.lib"
|
||||||
"user32.lib" when ODIN_OS == "windows";
|
foreign import "system:user32.lib"
|
||||||
"gdi32.lib" when ODIN_OS == "windows";
|
foreign import "system:gdi32.lib"
|
||||||
"winmm.lib" when ODIN_OS == "windows";
|
foreign import "system:winmm.lib"
|
||||||
"shell32.lib" when ODIN_OS == "windows";
|
foreign import "system:shell32.lib"
|
||||||
)
|
}
|
||||||
|
|
||||||
Handle :: rawptr;
|
Handle :: rawptr;
|
||||||
Hwnd :: Handle;
|
Hwnd :: Handle;
|
||||||
@@ -17,96 +17,113 @@ Hbrush :: Handle;
|
|||||||
Hgdiobj :: Handle;
|
Hgdiobj :: Handle;
|
||||||
Hmodule :: Handle;
|
Hmodule :: Handle;
|
||||||
Hmonitor :: Handle;
|
Hmonitor :: Handle;
|
||||||
|
Hrawinput :: Handle;
|
||||||
|
HKL :: Handle;
|
||||||
Wparam :: uint;
|
Wparam :: uint;
|
||||||
Lparam :: int;
|
Lparam :: int;
|
||||||
Lresult :: int;
|
Lresult :: int;
|
||||||
Wnd_Proc :: proc(Hwnd, u32, Wparam, Lparam) -> Lresult #cc_c;
|
Wnd_Proc :: #type proc "c" (Hwnd, u32, Wparam, Lparam) -> Lresult;
|
||||||
|
|
||||||
|
Long_Ptr :: int;
|
||||||
|
|
||||||
Bool :: i32;
|
Bool :: i32;
|
||||||
FALSE: Bool : 0;
|
FALSE: Bool : 0;
|
||||||
TRUE: Bool : 1;
|
TRUE: Bool : 1;
|
||||||
|
|
||||||
Point :: struct #ordered {
|
Point :: struct #ordered {
|
||||||
x, y: i32;
|
x, y: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Wnd_Class_Ex_A :: struct #ordered {
|
Wnd_Class_Ex_A :: struct #ordered {
|
||||||
size, style: u32;
|
size, style: u32,
|
||||||
wnd_proc: Wnd_Proc;
|
wnd_proc: Wnd_Proc,
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Wnd_Class_Ex_W :: struct #ordered {
|
||||||
|
size, style: u32,
|
||||||
|
wnd_proc: Wnd_Proc,
|
||||||
|
cls_extra, wnd_extra: i32,
|
||||||
|
instance: Hinstance,
|
||||||
|
icon: Hicon,
|
||||||
|
cursor: Hcursor,
|
||||||
|
background: Hbrush,
|
||||||
|
menu_name, class_name: ^u16,
|
||||||
|
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 {
|
||||||
lo, hi: u32;
|
lo, hi: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Systemtime :: struct #ordered {
|
Systemtime :: struct #ordered {
|
||||||
year, month: u16;
|
year, month: u16,
|
||||||
day_of_week, day: u16;
|
day_of_week, day: u16,
|
||||||
hour, minute, second, millisecond: u16;
|
hour, minute, second, millisecond: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
File_Attribute_Data :: struct #ordered {
|
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
Find_Data :: struct #ordered{
|
Find_Data :: struct #ordered{
|
||||||
file_attributes: u32;
|
file_attributes: u32,
|
||||||
creation_time: Filetime;
|
creation_time: Filetime,
|
||||||
last_access_time: Filetime;
|
last_access_time: Filetime,
|
||||||
last_write_time: Filetime;
|
last_write_time: Filetime,
|
||||||
file_size_high: u32;
|
file_size_high: u32,
|
||||||
file_size_low: u32;
|
file_size_low: u32,
|
||||||
reserved0: u32;
|
reserved0: u32,
|
||||||
reserved1: u32;
|
reserved1: u32,
|
||||||
file_name: [MAX_PATH]u8;
|
file_name: [MAX_PATH]u8,
|
||||||
alternate_file_name: [14]u8;
|
alternate_file_name: [14]u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
Security_Attributes :: struct #ordered {
|
Security_Attributes :: struct #ordered {
|
||||||
length: u32;
|
length: u32,
|
||||||
security_descriptor: rawptr;
|
security_descriptor: rawptr,
|
||||||
inherit_handle: Bool;
|
inherit_handle: Bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -114,7 +131,7 @@ Security_Attributes :: struct #ordered {
|
|||||||
Pixel_Format_Descriptor :: struct #ordered {
|
Pixel_Format_Descriptor :: struct #ordered {
|
||||||
size,
|
size,
|
||||||
version,
|
version,
|
||||||
flags: u32;
|
flags: u32,
|
||||||
|
|
||||||
pixel_type,
|
pixel_type,
|
||||||
color_bits,
|
color_bits,
|
||||||
@@ -135,38 +152,91 @@ Pixel_Format_Descriptor :: struct #ordered {
|
|||||||
stencil_bits,
|
stencil_bits,
|
||||||
aux_buffers,
|
aux_buffers,
|
||||||
layer_type,
|
layer_type,
|
||||||
reserved: u8;
|
reserved: u8,
|
||||||
|
|
||||||
layer_mask,
|
layer_mask,
|
||||||
visible_mask,
|
visible_mask,
|
||||||
damage_mask: u32;
|
damage_mask: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Critical_Section :: struct #ordered {
|
Critical_Section :: struct #ordered {
|
||||||
debug_info: ^Critical_Section_Debug;
|
debug_info: ^Critical_Section_Debug,
|
||||||
|
|
||||||
lock_count: i32;
|
lock_count: i32,
|
||||||
recursion_count: i32;
|
recursion_count: i32,
|
||||||
owning_thread: Handle;
|
owning_thread: Handle,
|
||||||
lock_semaphore: Handle;
|
lock_semaphore: Handle,
|
||||||
spin_count: ^u32;
|
spin_count: ^u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Critical_Section_Debug :: struct #ordered {
|
Critical_Section_Debug :: struct #ordered {
|
||||||
typ: u16;
|
typ: u16,
|
||||||
creator_back_trace_index: u16;
|
creator_back_trace_index: u16,
|
||||||
critical_section: ^Critical_Section;
|
critical_section: ^Critical_Section,
|
||||||
process_locks_list: ^List_Entry;
|
process_locks_list: ^List_Entry,
|
||||||
entry_count: u32;
|
entry_count: u32,
|
||||||
contention_count: u32;
|
contention_count: u32,
|
||||||
flags: u32;
|
flags: u32,
|
||||||
creator_back_trace_index_high: u16;
|
creator_back_trace_index_high: u16,
|
||||||
spare_word: u16;
|
spare_word: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
List_Entry :: struct #ordered {flink, blink: ^List_Entry};
|
List_Entry :: struct #ordered {flink, blink: ^List_Entry};
|
||||||
|
|
||||||
|
|
||||||
|
Raw_Input_Device :: struct #ordered {
|
||||||
|
usage_page: u16,
|
||||||
|
usage: u16,
|
||||||
|
flags: u32,
|
||||||
|
wnd_target: Hwnd,
|
||||||
|
}
|
||||||
|
|
||||||
|
Raw_Input_Header :: struct #ordered {
|
||||||
|
kind: u32,
|
||||||
|
size: u32,
|
||||||
|
device: Handle,
|
||||||
|
wparam: Wparam,
|
||||||
|
}
|
||||||
|
|
||||||
|
Raw_HID :: struct #ordered {
|
||||||
|
size_hid: u32,
|
||||||
|
count: u32,
|
||||||
|
raw_data: [1]u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
Raw_Keyboard :: struct #ordered {
|
||||||
|
make_code: u16,
|
||||||
|
flags: u16,
|
||||||
|
reserved: u16,
|
||||||
|
vkey: u16,
|
||||||
|
message: u32,
|
||||||
|
extra_information: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
Raw_Mouse :: struct #ordered {
|
||||||
|
flags: u16,
|
||||||
|
using data: struct #raw_union {
|
||||||
|
buttons: u32,
|
||||||
|
using _: struct #ordered {
|
||||||
|
button_flags: u16,
|
||||||
|
button_data: u16,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
raw_buttons: u32,
|
||||||
|
last_x: i32,
|
||||||
|
last_y: i32,
|
||||||
|
extra_information: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
Raw_Input :: struct #ordered {
|
||||||
|
using header: Raw_Input_Header,
|
||||||
|
data: struct #raw_union {
|
||||||
|
mouse: Raw_Mouse,
|
||||||
|
keyboard: Raw_Keyboard,
|
||||||
|
hid: Raw_HID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MAPVK_VK_TO_VSC :: 0;
|
MAPVK_VK_TO_VSC :: 0;
|
||||||
MAPVK_VSC_TO_VK :: 1;
|
MAPVK_VSC_TO_VK :: 1;
|
||||||
@@ -176,7 +246,7 @@ MAPVK_VSC_TO_VK_EX :: 3;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
INVALID_HANDLE :: Handle(~int(0));
|
INVALID_HANDLE :: Handle(~uintptr(0));
|
||||||
|
|
||||||
CREATE_SUSPENDED :: 0x00000004;
|
CREATE_SUSPENDED :: 0x00000004;
|
||||||
STACK_SIZE_PARAM_IS_A_RESERVATION :: 0x00010000;
|
STACK_SIZE_PARAM_IS_A_RESERVATION :: 0x00010000;
|
||||||
@@ -199,26 +269,30 @@ WS_BORDER :: 0x00800000;
|
|||||||
WS_CAPTION :: 0x00C00000;
|
WS_CAPTION :: 0x00C00000;
|
||||||
WS_VISIBLE :: 0x10000000;
|
WS_VISIBLE :: 0x10000000;
|
||||||
WS_POPUP :: 0x80000000;
|
WS_POPUP :: 0x80000000;
|
||||||
|
WS_MAXIMIZE :: 0x01000000;
|
||||||
|
WS_MINIMIZE :: 0x20000000;
|
||||||
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;
|
||||||
WS_POPUPWINDOW :: WS_POPUP | WS_BORDER | WS_SYSMENU;
|
WS_POPUPWINDOW :: WS_POPUP | WS_BORDER | WS_SYSMENU;
|
||||||
|
|
||||||
WM_DESTROY :: 0x0002;
|
WM_ACTIVATE :: 0x0006;
|
||||||
WM_SIZE :: 0x0005;
|
|
||||||
WM_CLOSE :: 0x0010;
|
|
||||||
WM_ACTIVATEAPP :: 0x001C;
|
WM_ACTIVATEAPP :: 0x001C;
|
||||||
WM_QUIT :: 0x0012;
|
WM_CHAR :: 0x0102;
|
||||||
|
WM_CLOSE :: 0x0010;
|
||||||
|
WM_CREATE :: 0x0001;
|
||||||
|
WM_DESTROY :: 0x0002;
|
||||||
|
WM_INPUT :: 0x00ff;
|
||||||
WM_KEYDOWN :: 0x0100;
|
WM_KEYDOWN :: 0x0100;
|
||||||
WM_KEYUP :: 0x0101;
|
WM_KEYUP :: 0x0101;
|
||||||
|
WM_KILLFOCUS :: 0x0008;
|
||||||
|
WM_QUIT :: 0x0012;
|
||||||
|
WM_SETCURSOR :: 0x0020;
|
||||||
|
WM_SETFOCUS :: 0x0007;
|
||||||
|
WM_SIZE :: 0x0005;
|
||||||
WM_SIZING :: 0x0214;
|
WM_SIZING :: 0x0214;
|
||||||
WM_SYSKEYDOWN :: 0x0104;
|
WM_SYSKEYDOWN :: 0x0104;
|
||||||
WM_SYSKEYUP :: 0x0105;
|
WM_SYSKEYUP :: 0x0105;
|
||||||
WM_WINDOWPOSCHANGED :: 0x0047;
|
|
||||||
WM_SETCURSOR :: 0x0020;
|
|
||||||
WM_CHAR :: 0x0102;
|
|
||||||
WM_ACTIVATE :: 0x0006;
|
|
||||||
WM_SETFOCUS :: 0x0007;
|
|
||||||
WM_KILLFOCUS :: 0x0008;
|
|
||||||
WM_USER :: 0x0400;
|
WM_USER :: 0x0400;
|
||||||
|
WM_WINDOWPOSCHANGED :: 0x0047;
|
||||||
|
|
||||||
WM_MOUSEWHEEL :: 0x020A;
|
WM_MOUSEWHEEL :: 0x020A;
|
||||||
WM_MOUSEMOVE :: 0x0200;
|
WM_MOUSEMOVE :: 0x0200;
|
||||||
@@ -243,13 +317,18 @@ SM_CYSCREEN :: 1;
|
|||||||
|
|
||||||
SW_SHOW :: 5;
|
SW_SHOW :: 5;
|
||||||
|
|
||||||
COLOR_BACKGROUND :: Hbrush(int(1));
|
COLOR_BACKGROUND :: Hbrush(uintptr(1));
|
||||||
|
|
||||||
INVALID_SET_FILE_POINTER :: ~u32(0);
|
INVALID_SET_FILE_POINTER :: ~u32(0);
|
||||||
HEAP_ZERO_MEMORY :: 0x00000008;
|
HEAP_ZERO_MEMORY :: 0x00000008;
|
||||||
INFINITE :: 0xffffffff;
|
INFINITE :: 0xffffffff;
|
||||||
|
GWL_EXSTYLE :: -20;
|
||||||
|
GWLP_HINSTANCE :: -6;
|
||||||
|
GWLP_ID :: -12;
|
||||||
GWL_STYLE :: -16;
|
GWL_STYLE :: -16;
|
||||||
Hwnd_TOP :: Hwnd(uint(0));
|
GWLP_USERDATA :: -21;
|
||||||
|
GWLP_WNDPROC :: -4;
|
||||||
|
Hwnd_TOP :: Hwnd(uintptr(0));
|
||||||
|
|
||||||
BI_RGB :: 0;
|
BI_RGB :: 0;
|
||||||
DIB_RGB_COLORS :: 0x00;
|
DIB_RGB_COLORS :: 0x00;
|
||||||
@@ -267,8 +346,63 @@ SWP_NOSIZE :: 0x0001;
|
|||||||
SWP_NOMOVE :: 0x0002;
|
SWP_NOMOVE :: 0x0002;
|
||||||
|
|
||||||
|
|
||||||
|
// Raw Input
|
||||||
|
|
||||||
|
|
||||||
|
RID_HEADER :: 0x10000005;
|
||||||
|
RID_INPUT :: 0x10000003;
|
||||||
|
|
||||||
|
|
||||||
|
RIDEV_APPKEYS :: 0x00000400;
|
||||||
|
RIDEV_CAPTUREMOUSE :: 0x00000200;
|
||||||
|
RIDEV_DEVNOTIFY :: 0x00002000;
|
||||||
|
RIDEV_EXCLUDE :: 0x00000010;
|
||||||
|
RIDEV_EXINPUTSINK :: 0x00001000;
|
||||||
|
RIDEV_INPUTSINK :: 0x00000100;
|
||||||
|
RIDEV_NOHOTKEYS :: 0x00000200;
|
||||||
|
RIDEV_NOLEGACY :: 0x00000030;
|
||||||
|
RIDEV_PAGEONLY :: 0x00000020;
|
||||||
|
RIDEV_REMOVE :: 0x00000001;
|
||||||
|
|
||||||
|
|
||||||
|
RIM_TYPEMOUSE :: 0;
|
||||||
|
RIM_TYPEKEYBOARD :: 1;
|
||||||
|
RIM_TYPEHID :: 2;
|
||||||
|
|
||||||
|
|
||||||
|
MOUSE_ATTRIBUTES_CHANGED :: 0x04;
|
||||||
|
MOUSE_MOVE_RELATIVE :: 0;
|
||||||
|
MOUSE_MOVE_ABSOLUTE :: 1;
|
||||||
|
MOUSE_VIRTUAL_DESKTOP :: 0x02;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RI_MOUSE_BUTTON_1_DOWN :: 0x0001;
|
||||||
|
RI_MOUSE_BUTTON_1_UP :: 0x0002;
|
||||||
|
RI_MOUSE_BUTTON_2_DOWN :: 0x0004;
|
||||||
|
RI_MOUSE_BUTTON_2_UP :: 0x0008;
|
||||||
|
RI_MOUSE_BUTTON_3_DOWN :: 0x0010;
|
||||||
|
RI_MOUSE_BUTTON_3_UP :: 0x0020;
|
||||||
|
RI_MOUSE_BUTTON_4_DOWN :: 0x0040;
|
||||||
|
RI_MOUSE_BUTTON_4_UP :: 0x0080;
|
||||||
|
RI_MOUSE_BUTTON_5_DOWN :: 0x0100;
|
||||||
|
RI_MOUSE_BUTTON_5_UP :: 0x0200;
|
||||||
|
RI_MOUSE_LEFT_BUTTON_DOWN :: 0x0001;
|
||||||
|
RI_MOUSE_LEFT_BUTTON_UP :: 0x0002;
|
||||||
|
RI_MOUSE_MIDDLE_BUTTON_DOWN :: 0x0010;
|
||||||
|
RI_MOUSE_MIDDLE_BUTTON_UP :: 0x0020;
|
||||||
|
RI_MOUSE_RIGHT_BUTTON_DOWN :: 0x0004;
|
||||||
|
RI_MOUSE_RIGHT_BUTTON_UP :: 0x0008;
|
||||||
|
RI_MOUSE_WHEEL :: 0x0400;
|
||||||
|
|
||||||
|
|
||||||
|
RI_KEY_MAKE :: 0x00;
|
||||||
|
RI_KEY_BREAK :: 0x01;
|
||||||
|
RI_KEY_E0 :: 0x02;
|
||||||
|
RI_KEY_E1 :: 0x04;
|
||||||
|
RI_KEY_TERMSRV_SET_LED :: 0x08;
|
||||||
|
RI_KEY_TERMSRV_SHADOW :: 0x10;
|
||||||
|
|
||||||
// Windows OpenGL
|
// Windows OpenGL
|
||||||
|
|
||||||
PFD_TYPE_RGBA :: 0;
|
PFD_TYPE_RGBA :: 0;
|
||||||
@@ -297,182 +431,228 @@ GET_FILEEX_INFO_LEVELS :: 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;
|
||||||
|
|
||||||
|
@(default_calling_convention = "std")
|
||||||
foreign kernel32 {
|
foreign kernel32 {
|
||||||
get_last_error :: proc() -> i32 #cc_std #link_name "GetLastError" ---;
|
@(link_name="GetLastError") get_last_error :: proc() -> i32 ---;
|
||||||
exit_process :: proc(exit_code: u32) #cc_std #link_name "ExitProcess" ---;
|
@(link_name="ExitProcess") exit_process :: proc(exit_code: u32) ---;
|
||||||
get_module_handle_a :: proc(module_name: ^u8) -> Hinstance #cc_std #link_name "GetModuleHandleA" ---;
|
@(link_name="GetModuleHandleA") get_module_handle_a :: proc(module_name: ^u8) -> Hinstance ---;
|
||||||
sleep :: proc(ms: i32) -> i32 #cc_std #link_name "Sleep" ---;
|
@(link_name="GetModuleHandleW") get_module_handle_w :: proc(module_name: ^u16) -> Hinstance ---;
|
||||||
query_performance_frequency :: proc(result: ^i64) -> i32 #cc_std #link_name "QueryPerformanceFrequency" ---;
|
@(link_name="Sleep") sleep :: proc(ms: i32) -> i32 ---;
|
||||||
query_performance_counter :: proc(result: ^i64) -> i32 #cc_std #link_name "QueryPerformanceCounter" ---;
|
@(link_name="QueryPerformanceFrequency") query_performance_frequency :: proc(result: ^i64) -> i32 ---;
|
||||||
output_debug_string_a :: proc(c_str: ^u8) #cc_std #link_name "OutputDebugStringA" ---;
|
@(link_name="QueryPerformanceCounter") query_performance_counter :: proc(result: ^i64) -> i32 ---;
|
||||||
|
@(link_name="OutputDebugStringA") output_debug_string_a :: proc(c_str: ^u8) ---;
|
||||||
|
|
||||||
get_command_line_a :: proc() -> ^u8 #cc_std #link_name "GetCommandLineA" ---;
|
@(link_name="GetCommandLineA") get_command_line_a :: proc() -> ^u8 ---;
|
||||||
get_command_line_w :: proc() -> ^u16 #cc_std #link_name "GetCommandLineW" ---;
|
@(link_name="GetCommandLineW") get_command_line_w :: proc() -> ^u16 ---;
|
||||||
get_system_metrics :: proc(index: i32) -> i32 #cc_std #link_name "GetSystemMetrics" ---;
|
@(link_name="GetSystemMetrics") get_system_metrics :: proc(index: i32) -> i32 ---;
|
||||||
get_current_thread_id :: proc() -> u32 #cc_std #link_name "GetCurrentThreadId" ---;
|
@(link_name="GetCurrentThreadId") get_current_thread_id :: proc() -> u32 ---;
|
||||||
|
|
||||||
get_system_time_as_file_time :: proc(system_time_as_file_time: ^Filetime) #cc_std #link_name "GetSystemTimeAsFileTime" ---;
|
@(link_name="GetSystemTimeAsFileTime") get_system_time_as_file_time :: proc(system_time_as_file_time: ^Filetime) ---;
|
||||||
file_time_to_local_file_time :: proc(file_time: ^Filetime, local_file_time: ^Filetime) -> Bool #cc_std #link_name "FileTimeToLocalFileTime" ---;
|
@(link_name="FileTimeToLocalFileTime") file_time_to_local_file_time :: proc(file_time: ^Filetime, local_file_time: ^Filetime) -> Bool ---;
|
||||||
file_time_to_system_time :: proc(file_time: ^Filetime, system_time: ^Systemtime) -> Bool #cc_std #link_name "FileTimeToSystemTime" ---;
|
@(link_name="FileTimeToSystemTime") file_time_to_system_time :: proc(file_time: ^Filetime, system_time: ^Systemtime) -> Bool ---;
|
||||||
system_time_to_file_time :: proc(system_time: ^Systemtime, file_time: ^Filetime) -> Bool #cc_std #link_name "SystemTimeToFileTime" ---;
|
@(link_name="SystemTimeToFileTime") system_time_to_file_time :: proc(system_time: ^Systemtime, file_time: ^Filetime) -> Bool ---;
|
||||||
|
|
||||||
close_handle :: proc(h: Handle) -> i32 #cc_std #link_name "CloseHandle" ---;
|
@(link_name="CloseHandle") close_handle :: proc(h: Handle) -> i32 ---;
|
||||||
get_std_handle :: proc(h: i32) -> Handle #cc_std #link_name "GetStdHandle" ---;
|
@(link_name="GetStdHandle") get_std_handle :: proc(h: i32) -> Handle ---;
|
||||||
create_file_a :: proc(filename: ^u8, desired_access, share_mode: u32,
|
|
||||||
security: rawptr,
|
|
||||||
creation, flags_and_attribs: u32, template_file: Handle) -> Handle #cc_std #link_name "CreateFileA" ---;
|
|
||||||
read_file :: proc(h: Handle, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> Bool #cc_std #link_name "ReadFile" ---;
|
|
||||||
write_file :: proc(h: Handle, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> Bool #cc_std #link_name "WriteFile" ---;
|
|
||||||
|
|
||||||
get_file_size_ex :: proc(file_handle: Handle, file_size: ^i64) -> Bool #cc_std #link_name "GetFileSizeEx" ---;
|
@(link_name="CreateFileA")
|
||||||
get_file_attributes_a :: proc(filename: ^u8) -> u32 #cc_std #link_name "GetFileAttributesA" ---;
|
create_file_a :: proc(filename: ^u8, desired_access, share_module: u32,
|
||||||
get_file_attributes_ex_a :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool #cc_std #link_name "GetFileAttributesExA" ---;
|
security: rawptr,
|
||||||
get_file_information_by_handle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool #cc_std #link_name "GetFileInformationByHandle" ---;
|
creation, flags_and_attribs: u32, template_file: Handle) -> Handle ---;
|
||||||
|
|
||||||
get_file_type :: proc(file_handle: Handle) -> u32 #cc_std #link_name "GetFileType" ---;
|
@(link_name="ReadFile") read_file :: proc(h: Handle, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> Bool ---;
|
||||||
set_file_pointer :: proc(file_handle: Handle, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #cc_std #link_name "SetFilePointer" ---;
|
@(link_name="WriteFile") write_file :: proc(h: Handle, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> Bool ---;
|
||||||
|
|
||||||
set_handle_information :: proc(obj: Handle, mask, flags: u32) -> Bool #cc_std #link_name "SetHandleInformation" ---;
|
@(link_name="GetFileSizeEx") get_file_size_ex :: proc(file_handle: Handle, file_size: ^i64) -> Bool ---;
|
||||||
|
@(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: ^u8) -> u32 ---;
|
||||||
|
@(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool ---;
|
||||||
|
@(link_name="GetFileInformationByHandle") get_file_information_by_handle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool ---;
|
||||||
|
|
||||||
find_first_file_a :: proc(file_name : ^u8, data : ^Find_Data) -> Handle #cc_std #link_name "FindFirstFileA" ---;
|
@(link_name="GetFileType") get_file_type :: proc(file_handle: Handle) -> u32 ---;
|
||||||
find_next_file_a :: proc(file : Handle, data : ^Find_Data) -> Bool #cc_std #link_name "FindNextFileA" ---;
|
@(link_name="SetFilePointer") set_file_pointer :: proc(file_handle: Handle, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 ---;
|
||||||
find_close :: proc(file : Handle) -> Bool #cc_std #link_name "FindClose" ---;
|
|
||||||
|
@(link_name="SetHandleInformation") set_handle_information :: proc(obj: Handle, mask, flags: u32) -> Bool ---;
|
||||||
|
|
||||||
|
@(link_name="FindFirstFileA") find_first_file_a :: proc(file_name : ^u8, data : ^Find_Data) -> Handle ---;
|
||||||
|
@(link_name="FindNextFileA") find_next_file_a :: proc(file : Handle, data : ^Find_Data) -> Bool ---;
|
||||||
|
@(link_name="FindClose") find_close :: proc(file : Handle) -> Bool ---;
|
||||||
|
|
||||||
|
|
||||||
heap_alloc :: proc(h: Handle, flags: u32, bytes: int) -> rawptr #cc_std #link_name "HeapAlloc" ---;
|
@(link_name="HeapAlloc") heap_alloc :: proc(h: Handle, flags: u32, bytes: int) -> rawptr ---;
|
||||||
heap_realloc :: proc(h: Handle, flags: u32, memory: rawptr, bytes: int) -> rawptr #cc_std #link_name "HeapReAlloc" ---;
|
@(link_name="HeapReAlloc") heap_realloc :: proc(h: Handle, flags: u32, memory: rawptr, bytes: int) -> rawptr ---;
|
||||||
heap_free :: proc(h: Handle, flags: u32, memory: rawptr) -> Bool #cc_std #link_name "HeapFree" ---;
|
@(link_name="HeapFree") heap_free :: proc(h: Handle, flags: u32, memory: rawptr) -> Bool ---;
|
||||||
get_process_heap :: proc() -> Handle #cc_std #link_name "GetProcessHeap" ---;
|
@(link_name="GetProcessHeap") get_process_heap :: proc() -> Handle ---;
|
||||||
|
|
||||||
|
|
||||||
create_semaphore_a :: proc(attributes: ^Security_Attributes, initial_count, maximum_count: i32, name: ^u8) -> Handle #cc_std #link_name "CreateSemaphoreA" ---;
|
@(link_name="CreateSemaphoreA") create_semaphore_a :: proc(attributes: ^Security_Attributes, initial_count, maximum_count: i32, name: ^u8) -> Handle ---;
|
||||||
release_semaphore :: proc(semaphore: Handle, release_count: i32, previous_count: ^i32) -> Bool #cc_std #link_name "ReleaseSemaphore" ---;
|
@(link_name="ReleaseSemaphore") release_semaphore :: proc(semaphore: Handle, release_count: i32, previous_count: ^i32) -> Bool ---;
|
||||||
wait_for_single_object :: proc(handle: Handle, milliseconds: u32) -> u32 #cc_std #link_name "WaitForSingleObject" ---;
|
@(link_name="WaitForSingleObject") wait_for_single_object :: proc(handle: Handle, milliseconds: u32) -> u32 ---;
|
||||||
|
}
|
||||||
|
|
||||||
|
@(default_calling_convention = "c")
|
||||||
|
foreign kernel32 {
|
||||||
|
@(link_name="InterlockedCompareExchange") interlocked_compare_exchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 ---;
|
||||||
|
@(link_name="InterlockedExchange") interlocked_exchange :: proc(dst: ^i32, desired: i32) -> i32 ---;
|
||||||
|
@(link_name="InterlockedExchangeAdd") interlocked_exchange_add :: proc(dst: ^i32, desired: i32) -> i32 ---;
|
||||||
|
@(link_name="InterlockedAnd") interlocked_and :: proc(dst: ^i32, desired: i32) -> i32 ---;
|
||||||
|
@(link_name="InterlockedOr") interlocked_or :: proc(dst: ^i32, desired: i32) -> i32 ---;
|
||||||
|
|
||||||
interlocked_compare_exchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #cc_c #link_name "InterlockedCompareExchange" ---;
|
@(link_name="InterlockedCompareExchange64") interlocked_compare_exchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 ---;
|
||||||
interlocked_exchange :: proc(dst: ^i32, desired: i32) -> i32 #cc_c #link_name "InterlockedExchange" ---;
|
@(link_name="InterlockedExchange64") interlocked_exchange64 :: proc(dst: ^i64, desired: i64) -> i64 ---;
|
||||||
interlocked_exchange_add :: proc(dst: ^i32, desired: i32) -> i32 #cc_c #link_name "InterlockedExchangeAdd" ---;
|
@(link_name="InterlockedExchangeAdd64") interlocked_exchange_add64 :: proc(dst: ^i64, desired: i64) -> i64 ---;
|
||||||
interlocked_and :: proc(dst: ^i32, desired: i32) -> i32 #cc_c #link_name "InterlockedAnd" ---;
|
@(link_name="InterlockedAnd64") interlocked_and64 :: proc(dst: ^i64, desired: i64) -> i64 ---;
|
||||||
interlocked_or :: proc(dst: ^i32, desired: i32) -> i32 #cc_c #link_name "InterlockedOr" ---;
|
@(link_name="InterlockedOr64") interlocked_or64 :: proc(dst: ^i64, desired: i64) -> i64 ---;
|
||||||
|
}
|
||||||
|
|
||||||
interlocked_compare_exchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 #cc_c #link_name "InterlockedCompareExchange64" ---;
|
@(default_calling_convention = "std")
|
||||||
interlocked_exchange64 :: proc(dst: ^i64, desired: i64) -> i64 #cc_c #link_name "InterlockedExchange64" ---;
|
foreign kernel32 {
|
||||||
interlocked_exchange_add64 :: proc(dst: ^i64, desired: i64) -> i64 #cc_c #link_name "InterlockedExchangeAdd64" ---;
|
@(link_name="_mm_pause") mm_pause :: proc() ---;
|
||||||
interlocked_and64 :: proc(dst: ^i64, desired: i64) -> i64 #cc_c #link_name "InterlockedAnd64" ---;
|
@(link_name="ReadWriteBarrier") read_write_barrier :: proc() ---;
|
||||||
interlocked_or64 :: proc(dst: ^i64, desired: i64) -> i64 #cc_c #link_name "InterlockedOr64" ---;
|
@(link_name="WriteBarrier") write_barrier :: proc() ---;
|
||||||
|
@(link_name="ReadBarrier") read_barrier :: proc() ---;
|
||||||
|
|
||||||
mm_pause :: proc() #cc_std #link_name "_mm_pause" ---;
|
@(link_name="CreateThread")
|
||||||
read_write_barrier :: proc() #cc_std #link_name "ReadWriteBarrier" ---;
|
create_thread :: proc(thread_attributes: ^Security_Attributes, stack_size: int, start_routine: rawptr,
|
||||||
write_barrier :: proc() #cc_std #link_name "WriteBarrier" ---;
|
parameter: rawptr, creation_flags: u32, thread_id: ^u32) -> Handle ---;
|
||||||
read_barrier :: proc() #cc_std #link_name "ReadBarrier" ---;
|
@(link_name="ResumeThread") resume_thread :: proc(thread: Handle) -> u32 ---;
|
||||||
|
@(link_name="GetThreadPriority") get_thread_priority :: proc(thread: Handle) -> i32 ---;
|
||||||
|
@(link_name="SetThreadPriority") set_thread_priority :: proc(thread: Handle, priority: i32) -> Bool ---;
|
||||||
|
@(link_name="GetExitCodeThread") get_exit_code_thread :: proc(thread: Handle, exit_code: ^u32) -> Bool ---;
|
||||||
|
|
||||||
create_thread :: proc(thread_attributes: ^Security_Attributes, stack_size: int, start_routine: rawptr,
|
@(link_name="InitializeCriticalSection") initialize_critical_section :: proc(critical_section: ^Critical_Section) ---;
|
||||||
parameter: rawptr, creation_flags: u32, thread_id: ^u32) -> Handle #cc_std #link_name "CreateThread" ---;
|
@(link_name="InitializeCriticalSectionAndSpinCount") initialize_critical_section_and_spin_count :: proc(critical_section: ^Critical_Section, spin_count: u32) ---;
|
||||||
resume_thread :: proc(thread: Handle) -> u32 #cc_std #link_name "ResumeThread" ---;
|
@(link_name="DeleteCriticalSection") delete_critical_section :: proc(critical_section: ^Critical_Section) ---;
|
||||||
get_thread_priority :: proc(thread: Handle) -> i32 #cc_std #link_name "GetThreadPriority" ---;
|
@(link_name="SetCriticalSectionSpinCount") set_critical_section_spin_count :: proc(critical_section: ^Critical_Section, spin_count: u32) -> u32 ---;
|
||||||
set_thread_priority :: proc(thread: Handle, priority: i32) -> Bool #cc_std #link_name "SetThreadPriority" ---;
|
@(link_name="TryEnterCriticalSection") try_enter_critical_section :: proc(critical_section: ^Critical_Section) -> Bool ---;
|
||||||
get_exit_code_thread :: proc(thread: Handle, exit_code: ^u32) -> Bool #cc_std #link_name "GetExitCodeThread" ---;
|
@(link_name="EnterCriticalSection") enter_critical_section :: proc(critical_section: ^Critical_Section) ---;
|
||||||
|
@(link_name="LeaveCriticalSection") leave_critical_section :: proc(critical_section: ^Critical_Section) ---;
|
||||||
|
|
||||||
initialize_critical_section :: proc(critical_section: ^Critical_Section) #cc_std #link_name "InitializeCriticalSection" ---;
|
@(link_name="CreateEventA") create_event_a :: proc(event_attributes: ^Security_Attributes, manual_reset, initial_state: Bool, name: ^u8) -> Handle ---;
|
||||||
initialize_critical_section_and_spin_count :: proc(critical_section: ^Critical_Section, spin_count: u32) #cc_std #link_name "InitializeCriticalSectionAndSpinCount" ---;
|
|
||||||
delete_critical_section :: proc(critical_section: ^Critical_Section) #cc_std #link_name "DeleteCriticalSection" ---;
|
|
||||||
set_critical_section_spin_count :: proc(critical_section: ^Critical_Section, spin_count: u32) -> u32 #cc_std #link_name "SetCriticalSectionSpinCount" ---;
|
|
||||||
try_enter_critical_section :: proc(critical_section: ^Critical_Section) -> Bool #cc_std #link_name "TryEnterCriticalSection" ---;
|
|
||||||
enter_critical_section :: proc(critical_section: ^Critical_Section) #cc_std #link_name "EnterCriticalSection" ---;
|
|
||||||
leave_critical_section :: proc(critical_section: ^Critical_Section) #cc_std #link_name "LeaveCriticalSection" ---;
|
|
||||||
|
|
||||||
create_event_a :: proc(event_attributes: ^Security_Attributes, manual_reset, initial_state: Bool, name: ^u8) -> Handle #cc_std #link_name "CreateEventA" ---;
|
@(link_name="LoadLibraryA") load_library_a :: proc(c_str: ^u8) -> Hmodule ---;
|
||||||
|
@(link_name="LoadLibraryW") load_library_a :: proc(c_str: ^u16) -> Hmodule ---;
|
||||||
load_library_a :: proc(c_str: ^u8) -> Hmodule #cc_std #link_name "LoadLibraryA" ---;
|
@(link_name="FreeLibrary") free_library :: proc(h: Hmodule) ---;
|
||||||
free_library :: proc(h: Hmodule) #cc_std #link_name "FreeLibrary" ---;
|
@(link_name="GetProcAddress") get_proc_address :: proc(h: Hmodule, c_str: ^u8) -> rawptr ---;
|
||||||
get_proc_address :: proc(h: Hmodule, c_str: ^u8) -> rawptr #cc_std #link_name "GetProcAddress" ---;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(default_calling_convention = "std")
|
||||||
foreign user32 {
|
foreign user32 {
|
||||||
get_desktop_window :: proc() -> Hwnd #cc_std #link_name "GetDesktopWindow" ---;
|
@(link_name="GetDesktopWindow") get_desktop_window :: proc() -> Hwnd ---;
|
||||||
show_cursor :: proc(show : Bool) #cc_std #link_name "ShowCursor" ---;
|
@(link_name="ShowCursor") show_cursor :: proc(show : Bool) ---;
|
||||||
get_cursor_pos :: proc(p: ^Point) -> i32 #cc_std #link_name "GetCursorPos" ---;
|
@(link_name="GetCursorPos") get_cursor_pos :: proc(p: ^Point) -> Bool ---;
|
||||||
screen_to_client :: proc(h: Hwnd, p: ^Point) -> i32 #cc_std #link_name "ScreenToClient" ---;
|
@(link_name="SetCursorPos") set_cursor_pos :: proc(x, y: i32) -> Bool ---;
|
||||||
post_quit_message :: proc(exit_code: i32) #cc_std #link_name "PostQuitMessage" ---;
|
@(link_name="ScreenToClient") screen_to_client :: proc(h: Hwnd, p: ^Point) -> Bool ---;
|
||||||
set_window_text_a :: proc(hwnd: Hwnd, c_string: ^u8) -> Bool #cc_std #link_name "SetWindowTextA" ---;
|
@(link_name="ClientToScreen") client_to_screen :: proc(h: Hwnd, p: ^Point) -> Bool ---;
|
||||||
register_class_ex_a :: proc(wc: ^Wnd_Class_Ex_A) -> i16 #cc_std #link_name "RegisterClassExA" ---;
|
@(link_name="PostQuitMessage") post_quit_message :: proc(exit_code: i32) ---;
|
||||||
|
@(link_name="SetWindowTextA") set_window_text_a :: proc(hwnd: Hwnd, c_string: ^u8) -> Bool ---;
|
||||||
|
@(link_name="RegisterClassExA") register_class_ex_a :: proc(wc: ^Wnd_Class_Ex_A) -> i16 ---;
|
||||||
|
@(link_name="RegisterClassExW") register_class_ex_w :: proc(wc: ^Wnd_Class_Ex_W) -> i16 ---;
|
||||||
|
|
||||||
create_window_ex_a :: proc(ex_style: u32,
|
@(link_name="CreateWindowExA")
|
||||||
class_name, title: ^u8,
|
create_window_ex_a :: proc(ex_style: u32,
|
||||||
style: u32,
|
class_name, title: ^u8,
|
||||||
x, y, w, h: i32,
|
style: u32,
|
||||||
parent: Hwnd, menu: Hmenu, instance: Hinstance,
|
x, y, w, h: i32,
|
||||||
param: rawptr) -> Hwnd #cc_std #link_name "CreateWindowExA" ---;
|
parent: Hwnd, menu: Hmenu, instance: Hinstance,
|
||||||
|
param: rawptr) -> Hwnd ---;
|
||||||
|
|
||||||
show_window :: proc(hwnd: Hwnd, cmd_show: i32) -> Bool #cc_std #link_name "ShowWindow" ---;
|
@(link_name="CreateWindowExW")
|
||||||
translate_message :: proc(msg: ^Msg) -> Bool #cc_std #link_name "TranslateMessage" ---;
|
create_window_ex_w :: proc(ex_style: u32,
|
||||||
dispatch_message_a :: proc(msg: ^Msg) -> Lresult #cc_std #link_name "DispatchMessageA" ---;
|
class_name, title: ^u16,
|
||||||
update_window :: proc(hwnd: Hwnd) -> Bool #cc_std #link_name "UpdateWindow" ---;
|
style: u32,
|
||||||
get_message_a :: proc(msg: ^Msg, hwnd: Hwnd, msg_filter_min, msg_filter_max : u32) -> Bool #cc_std #link_name "GetMessageA" ---;
|
x, y, w, h: i32,
|
||||||
peek_message_a :: proc(msg: ^Msg, hwnd: Hwnd,
|
parent: Hwnd, menu: Hmenu, instance: Hinstance,
|
||||||
msg_filter_min, msg_filter_max, remove_msg: u32) -> Bool #cc_std #link_name "PeekMessageA" ---;
|
param: rawptr) -> Hwnd ---;
|
||||||
|
|
||||||
|
@(link_name="ShowWindow") show_window :: proc(hwnd: Hwnd, cmd_show: i32) -> Bool ---;
|
||||||
|
@(link_name="TranslateMessage") translate_message :: proc(msg: ^Msg) -> Bool ---;
|
||||||
|
@(link_name="DispatchMessageA") dispatch_message_a :: proc(msg: ^Msg) -> Lresult ---;
|
||||||
|
@(link_name="DispatchMessageW") dispatch_message_w :: proc(msg: ^Msg) -> Lresult ---;
|
||||||
|
@(link_name="UpdateWindow") update_window :: proc(hwnd: Hwnd) -> Bool ---;
|
||||||
|
@(link_name="GetMessageA") get_message_a :: proc(msg: ^Msg, hwnd: Hwnd, msg_filter_min, msg_filter_max : u32) -> Bool ---;
|
||||||
|
@(link_name="GetMessageW") get_message_w :: proc(msg: ^Msg, hwnd: Hwnd, msg_filter_min, msg_filter_max : u32) -> Bool ---;
|
||||||
|
|
||||||
|
@(link_name="PeekMessageA") peek_message_a :: proc(msg: ^Msg, hwnd: Hwnd, msg_filter_min, msg_filter_max, remove_msg: u32) -> Bool ---;
|
||||||
|
@(link_name="PeekMessageW") peek_message_w :: proc(msg: ^Msg, hwnd: Hwnd, msg_filter_min, msg_filter_max, remove_msg: u32) -> Bool ---;
|
||||||
|
|
||||||
|
|
||||||
post_message :: proc(hwnd: Hwnd, msg, wparam, lparam : u32) -> Bool #cc_std #link_name "PostMessageA" ---;
|
@(link_name="PostMessageA") post_message :: proc(hwnd: Hwnd, msg, wparam, lparam : u32) -> Bool ---;
|
||||||
|
|
||||||
def_window_proc_a :: proc(hwnd: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Lresult #cc_std #link_name "DefWindowProcA" ---;
|
@(link_name="DefWindowProcA") def_window_proc_a :: proc(hwnd: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Lresult ---;
|
||||||
|
|
||||||
adjust_window_rect :: proc(rect: ^Rect, style: u32, menu: Bool) -> Bool #cc_std #link_name "AdjustWindowRect" ---;
|
@(link_name="AdjustWindowRect") adjust_window_rect :: proc(rect: ^Rect, style: u32, menu: Bool) -> Bool ---;
|
||||||
get_active_window :: proc() -> Hwnd #cc_std #link_name "GetActiveWindow" ---;
|
@(link_name="GetActiveWindow") get_active_window :: proc() -> Hwnd ---;
|
||||||
|
|
||||||
destroy_window :: proc(wnd: Hwnd) -> Bool #cc_std #link_name "DestroyWindow" ---;
|
@(link_name="DestroyWindow") destroy_window :: proc(wnd: Hwnd) -> Bool ---;
|
||||||
describe_pixel_format :: proc(dc: Hdc, pixel_format: i32, bytes: u32, pfd: ^Pixel_Format_Descriptor) -> i32 #cc_std #link_name "DescribePixelFormat" ---;
|
@(link_name="DescribePixelFormat") describe_pixel_format :: proc(dc: Hdc, pixel_format: i32, bytes: u32, pfd: ^Pixel_Format_Descriptor) -> i32 ---;
|
||||||
|
|
||||||
get_monitor_info_a :: proc(monitor: Hmonitor, mi: ^Monitor_Info) -> Bool #cc_std #link_name "GetMonitor_InfoA" ---;
|
@(link_name="GetMonitor_InfoA") get_monitor_info_a :: proc(monitor: Hmonitor, mi: ^Monitor_Info) -> Bool ---;
|
||||||
monitor_from_window :: proc(wnd: Hwnd, flags : u32) -> Hmonitor #cc_std #link_name "MonitorFromWindow" ---;
|
@(link_name="MonitorFromWindow") monitor_from_window :: proc(wnd: Hwnd, flags : u32) -> Hmonitor ---;
|
||||||
|
|
||||||
set_window_pos :: proc(wnd: Hwnd, wndInsertAfter: Hwnd, x, y, width, height: i32, flags: u32) #cc_std #link_name "SetWindowPos" ---;
|
@(link_name="SetWindowPos") set_window_pos :: proc(wnd: Hwnd, wndInsertAfter: Hwnd, x, y, width, height: i32, flags: u32) ---;
|
||||||
|
|
||||||
get_window_placement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> Bool #cc_std #link_name "GetWindowPlacement" ---;
|
@(link_name="GetWindowPlacement") get_window_placement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> Bool ---;
|
||||||
set_window_placement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> Bool #cc_std #link_name "SetWindowPlacement" ---;
|
@(link_name="SetWindowPlacement") set_window_placement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> Bool ---;
|
||||||
get_window_rect :: proc(wnd: Hwnd, rect: ^Rect) -> Bool #cc_std #link_name "GetWindowRect" ---;
|
@(link_name="GetWindowRect") get_window_rect :: proc(wnd: Hwnd, rect: ^Rect) -> Bool ---;
|
||||||
|
|
||||||
get_window_long_ptr_a :: proc(wnd: Hwnd, index: i32) -> i64 #cc_std #link_name "GetWindowLongPtrA" ---;
|
@(link_name="GetWindowLongPtrA") get_window_long_ptr_a :: proc(wnd: Hwnd, index: i32) -> Long_Ptr ---;
|
||||||
set_window_long_ptr_a :: proc(wnd: Hwnd, index: i32, new: i64) -> i64 #cc_std #link_name "SetWindowLongPtrA" ---;
|
@(link_name="SetWindowLongPtrA") set_window_long_ptr_a :: proc(wnd: Hwnd, index: i32, new: Long_Ptr) -> Long_Ptr ---;
|
||||||
|
@(link_name="GetWindowLongPtrW") get_window_long_ptr_w :: proc(wnd: Hwnd, index: i32) -> Long_Ptr ---;
|
||||||
|
@(link_name="SetWindowLongPtrW") set_window_long_ptr_w :: proc(wnd: Hwnd, index: i32, new: Long_Ptr) -> Long_Ptr ---;
|
||||||
|
|
||||||
get_window_text :: proc(wnd: Hwnd, str: ^u8, maxCount: i32) -> i32 #cc_std #link_name "GetWindowText" ---;
|
@(link_name="GetWindowText") get_window_text :: proc(wnd: Hwnd, str: ^u8, maxCount: i32) -> i32 ---;
|
||||||
|
|
||||||
get_client_rect :: proc(hwnd: Hwnd, rect: ^Rect) -> Bool #cc_std #link_name "GetClientRect" ---;
|
@(link_name="GetClientRect") get_client_rect :: proc(hwnd: Hwnd, rect: ^Rect) -> Bool ---;
|
||||||
|
|
||||||
get_dc :: proc(h: Hwnd) -> Hdc #cc_std #link_name "GetDC" ---;
|
@(link_name="GetDC") get_dc :: proc(h: Hwnd) -> Hdc ---;
|
||||||
release_dc :: proc(wnd: Hwnd, hdc: Hdc) -> i32 #cc_std #link_name "ReleaseDC" ---;
|
@(link_name="ReleaseDC") release_dc :: proc(wnd: Hwnd, hdc: Hdc) -> i32 ---;
|
||||||
|
|
||||||
map_virtual_key :: proc(scancode : u32, map_type : u32) -> u32 #cc_std #link_name "MapVirtualKeyA" ---;
|
@(link_name="MapVirtualKeyA") map_virtual_key_a :: proc(scancode : u32, map_type : u32) -> u32 ---;
|
||||||
|
@(link_name="MapVirtualKeyW") map_virtual_key_w :: proc(scancode : u32, map_type : u32) -> u32 ---;
|
||||||
|
|
||||||
get_key_state :: proc(v_key: i32) -> i16 #cc_std #link_name "GetKeyState" ---;
|
@(link_name="GetKeyState") get_key_state :: proc(v_key: i32) -> i16 ---;
|
||||||
get_async_key_state :: proc(v_key: i32) -> i16 #cc_std #link_name "GetAsyncKeyState" ---;
|
@(link_name="GetAsyncKeyState") get_async_key_state :: proc(v_key: i32) -> i16 ---;
|
||||||
|
|
||||||
|
@(link_name="SetForegroundWindow") set_foreground_window :: proc(h: Hwnd) -> Bool ---;
|
||||||
|
@(link_name="SetFocus") set_focus :: proc(h: Hwnd) -> Hwnd ---;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@(link_name="RegisterRawInputDevices") register_raw_input_devices :: proc(raw_input_device: ^Raw_Input_Device, num_devices, size: u32) -> Bool ---;
|
||||||
|
|
||||||
|
@(link_name="GetRawInputData") get_raw_input_data :: proc(raw_input: Hrawinput, command: u32, data: rawptr, size: ^u32, size_header: u32) -> u32 ---;
|
||||||
|
|
||||||
|
@(link_name="MapVirtualKeyExW") map_virtual_key_ex_w :: proc(code, map_type: u32, hkl: HKL) ---;
|
||||||
|
@(link_name="MapVirtualKeyExA") map_virtual_key_ex_a :: proc(code, map_type: u32, hkl: HKL) ---;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(default_calling_convention = "std")
|
||||||
foreign gdi32 {
|
foreign gdi32 {
|
||||||
get_stock_object :: proc(fn_object: i32) -> Hgdiobj #cc_std #link_name "GetStockObject" ---;
|
@(link_name="GetStockObject") get_stock_object :: proc(fn_object: i32) -> Hgdiobj ---;
|
||||||
|
|
||||||
stretch_dibits :: proc(hdc: Hdc,
|
@(link_name="StretchDIBits")
|
||||||
x_dst, y_dst, width_dst, height_dst: i32,
|
stretch_dibits :: proc(hdc: Hdc,
|
||||||
x_src, y_src, width_src, header_src: i32,
|
x_dst, y_dst, width_dst, height_dst: i32,
|
||||||
bits: rawptr, bits_info: ^BitmapInfo,
|
x_src, y_src, width_src, header_src: i32,
|
||||||
usage: u32,
|
bits: rawptr, bits_info: ^Bitmap_Info,
|
||||||
rop: u32) -> i32 #cc_std #link_name "StretchDIBits" ---;
|
usage: u32,
|
||||||
|
rop: u32) -> i32 ---;
|
||||||
|
|
||||||
set_pixel_format :: proc(hdc: Hdc, pixel_format: i32, pfd: ^Pixel_Format_Descriptor) -> Bool #cc_std #link_name "SetPixelFormat" ---;
|
@(link_name="SetPixelFormat") set_pixel_format :: proc(hdc: Hdc, pixel_format: i32, pfd: ^Pixel_Format_Descriptor) -> Bool ---;
|
||||||
choose_pixel_format :: proc(hdc: Hdc, pfd: ^Pixel_Format_Descriptor) -> i32 #cc_std #link_name "ChoosePixelFormat" ---;
|
@(link_name="ChoosePixelFormat") choose_pixel_format :: proc(hdc: Hdc, pfd: ^Pixel_Format_Descriptor) -> i32 ---;
|
||||||
swap_buffers :: proc(hdc: Hdc) -> Bool #cc_std #link_name "SwapBuffers" ---;
|
@(link_name="SwapBuffers") swap_buffers :: proc(hdc: Hdc) -> Bool ---;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(default_calling_convention = "std")
|
||||||
foreign shell32 {
|
foreign shell32 {
|
||||||
command_line_to_argv_w :: proc(cmd_list: ^u16, num_args: ^i32) -> ^^u16 #cc_std #link_name "CommandLineToArgvW" ---;
|
@(link_name="CommandLineToArgvW") command_line_to_argv_w :: proc(cmd_list: ^u16, num_args: ^i32) -> ^^u16 ---;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(default_calling_convention = "std")
|
||||||
foreign winmm {
|
foreign winmm {
|
||||||
time_get_time :: proc() -> u32 #cc_std #link_name "timeGetTime" ---;
|
@(link_name="timeGetTime") time_get_time :: proc() -> u32 ---;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -488,8 +668,7 @@ HIWORD :: proc(lParam: Lparam) -> u16 { return u16((u32(lParam) >> 16) & 0xffff)
|
|||||||
LOWORD :: proc(wParam: Wparam) -> u16 { return u16(wParam); }
|
LOWORD :: proc(wParam: Wparam) -> u16 { return u16(wParam); }
|
||||||
LOWORD :: proc(lParam: Lparam) -> u16 { return u16(lParam); }
|
LOWORD :: proc(lParam: Lparam) -> u16 { return u16(lParam); }
|
||||||
|
|
||||||
is_key_down :: proc(key: Key_Code) -> bool #inline { return get_async_key_state(i32(key)) < 0; }
|
is_key_down :: inline proc(key: Key_Code) -> bool do return get_async_key_state(i32(key)) < 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -546,35 +725,35 @@ FILE_TYPE_PIPE :: 0x0003;
|
|||||||
|
|
||||||
|
|
||||||
Monitor_Info :: struct #ordered {
|
Monitor_Info :: struct #ordered {
|
||||||
size: u32;
|
size: u32,
|
||||||
monitor: Rect;
|
monitor: Rect,
|
||||||
work: Rect;
|
work: Rect,
|
||||||
flags: u32;
|
flags: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Window_Placement :: struct #ordered {
|
Window_Placement :: struct #ordered {
|
||||||
length: u32;
|
length: u32,
|
||||||
flags: u32;
|
flags: u32,
|
||||||
show_cmd: u32;
|
show_cmd: u32,
|
||||||
min_pos: Point;
|
min_pos: Point,
|
||||||
max_pos: Point;
|
max_pos: Point,
|
||||||
normal_pos: Rect;
|
normal_pos: Rect,
|
||||||
}
|
}
|
||||||
|
|
||||||
Bitmap_Info_Header :: struct #ordered {
|
Bitmap_Info_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,
|
||||||
}
|
}
|
||||||
BitmapInfo :: struct #ordered {
|
Bitmap_Info :: struct #ordered {
|
||||||
using header: Bitmap_Info_Header;
|
using header: Bitmap_Info_Header,
|
||||||
colors: [1]Rgb_Quad;
|
colors: [1]Rgb_Quad,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -582,10 +761,14 @@ Rgb_Quad :: struct #ordered {blue, green, red, reserved: u8}
|
|||||||
|
|
||||||
|
|
||||||
Key_Code :: enum i32 {
|
Key_Code :: enum i32 {
|
||||||
|
Unknown = 0x00,
|
||||||
|
|
||||||
Lbutton = 0x01,
|
Lbutton = 0x01,
|
||||||
Rbutton = 0x02,
|
Rbutton = 0x02,
|
||||||
Cancel = 0x03,
|
Cancel = 0x03,
|
||||||
Mbutton = 0x04,
|
Mbutton = 0x04,
|
||||||
|
Xbutton1 = 0x05,
|
||||||
|
Xbutton2 = 0x06,
|
||||||
Back = 0x08,
|
Back = 0x08,
|
||||||
Tab = 0x09,
|
Tab = 0x09,
|
||||||
Clear = 0x0C,
|
Clear = 0x0C,
|
||||||
|
|||||||
+21
-22
@@ -1,47 +1,46 @@
|
|||||||
_ :: compile_assert(ODIN_OS == "windows");
|
_ :: compile_assert(ODIN_OS == "windows");
|
||||||
|
|
||||||
import win32 "sys/windows.odin";
|
when ODIN_OS == "windows" {
|
||||||
|
import win32 "core:sys/windows.odin"
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread_Proc :: #type proc(^Thread) -> int;
|
||||||
|
|
||||||
|
Thread_Os_Specific :: struct {
|
||||||
|
win32_thread: win32.Handle,
|
||||||
|
win32_thread_id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
Thread :: struct {
|
Thread :: struct {
|
||||||
using specific: Os_Specific;
|
using specific: Thread_Os_Specific,
|
||||||
procedure: Proc;
|
procedure: Thread_Proc,
|
||||||
data: any;
|
data: any,
|
||||||
user_index: int;
|
user_index: int,
|
||||||
|
|
||||||
init_context: Context;
|
init_context: Context,
|
||||||
use_init_context: bool;
|
use_init_context: bool,
|
||||||
|
|
||||||
Proc :: #type proc(^Thread) -> int;
|
|
||||||
Os_Specific :: struct {
|
|
||||||
win32_thread: win32.Handle;
|
|
||||||
win32_thread_id: u32;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
create :: proc(procedure: Thread.Proc) -> ^Thread {
|
create :: proc(procedure: Thread_Proc) -> ^Thread {
|
||||||
win32_thread_id: u32;
|
win32_thread_id: u32;
|
||||||
|
|
||||||
__windows_thread_entry_proc :: proc(data: rawptr) -> i32 #cc_c {
|
__windows_thread_entry_proc :: proc "c" (t: ^Thread) -> i32 {
|
||||||
if data == nil do return 0;
|
|
||||||
|
|
||||||
t := cast(^Thread)data;
|
|
||||||
|
|
||||||
c := context;
|
c := context;
|
||||||
if t.use_init_context {
|
if t.use_init_context {
|
||||||
c = t.init_context;
|
c = t.init_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
exit := 0;
|
exit := 0;
|
||||||
push_context c {
|
context <- c {
|
||||||
exit = t.procedure(t);
|
exit = t.procedure(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cast(i32)exit;
|
return i32(exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
win32_thread_proc := cast(rawptr)__windows_thread_entry_proc;
|
win32_thread_proc := rawptr(__windows_thread_entry_proc);
|
||||||
thread := new(Thread);
|
thread := new(Thread);
|
||||||
|
|
||||||
win32_thread := win32.create_thread(nil, 0, win32_thread_proc, thread, win32.CREATE_SUSPENDED, &win32_thread_id);
|
win32_thread := win32.create_thread(nil, 0, win32_thread_proc, thread, win32.CREATE_SUSPENDED, &win32_thread_id);
|
||||||
|
|||||||
+182
-22
@@ -1,103 +1,263 @@
|
|||||||
|
are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||||
|
if a == b do return true;
|
||||||
|
|
||||||
|
if (a == nil && b != nil) ||
|
||||||
|
(a != nil && b == nil) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case a.size != b.size, a.align != b.align:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch x in a.variant {
|
||||||
|
case Type_Info_Named:
|
||||||
|
y, ok := b.variant.(Type_Info_Named);
|
||||||
|
if !ok do return false;
|
||||||
|
return x.base == y.base;
|
||||||
|
|
||||||
|
case Type_Info_Integer:
|
||||||
|
y, ok := b.variant.(Type_Info_Integer);
|
||||||
|
if !ok do return false;
|
||||||
|
return x.signed == y.signed;
|
||||||
|
|
||||||
|
case Type_Info_Rune:
|
||||||
|
_, ok := b.variant.(Type_Info_Rune);
|
||||||
|
return ok;
|
||||||
|
|
||||||
|
case Type_Info_Float:
|
||||||
|
_, ok := b.variant.(Type_Info_Float);
|
||||||
|
return ok;
|
||||||
|
|
||||||
|
case Type_Info_Complex:
|
||||||
|
_, ok := b.variant.(Type_Info_Complex);
|
||||||
|
return ok;
|
||||||
|
|
||||||
|
case Type_Info_String:
|
||||||
|
_, ok := b.variant.(Type_Info_String);
|
||||||
|
return ok;
|
||||||
|
|
||||||
|
case Type_Info_Boolean:
|
||||||
|
_, ok := b.variant.(Type_Info_Boolean);
|
||||||
|
return ok;
|
||||||
|
|
||||||
|
case Type_Info_Any:
|
||||||
|
_, ok := b.variant.(Type_Info_Any);
|
||||||
|
return ok;
|
||||||
|
|
||||||
|
case Type_Info_Pointer:
|
||||||
|
y, ok := b.variant.(Type_Info_Pointer);
|
||||||
|
return are_types_identical(x.elem, y.elem);
|
||||||
|
|
||||||
|
case Type_Info_Procedure:
|
||||||
|
y, ok := b.variant.(Type_Info_Procedure);
|
||||||
|
if !ok do return false;
|
||||||
|
switch {
|
||||||
|
case x.variadic != y.variadic,
|
||||||
|
x.convention != y.convention:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return are_types_identical(x.params, y.params) && are_types_identical(x.results, y.results);
|
||||||
|
|
||||||
|
case Type_Info_Array:
|
||||||
|
y, ok := b.variant.(Type_Info_Array);
|
||||||
|
if !ok do return false;
|
||||||
|
if x.count != y.count do return false;
|
||||||
|
return are_types_identical(x.elem, y.elem);
|
||||||
|
|
||||||
|
case Type_Info_Dynamic_Array:
|
||||||
|
y, ok := b.variant.(Type_Info_Dynamic_Array);
|
||||||
|
if !ok do return false;
|
||||||
|
return are_types_identical(x.elem, y.elem);
|
||||||
|
|
||||||
|
case Type_Info_Slice:
|
||||||
|
y, ok := b.variant.(Type_Info_Slice);
|
||||||
|
if !ok do return false;
|
||||||
|
return are_types_identical(x.elem, y.elem);
|
||||||
|
|
||||||
|
case Type_Info_Vector:
|
||||||
|
y, ok := b.variant.(Type_Info_Vector);
|
||||||
|
if !ok do return false;
|
||||||
|
if x.count != y.count do return false;
|
||||||
|
return are_types_identical(x.elem, y.elem);
|
||||||
|
|
||||||
|
case Type_Info_Tuple:
|
||||||
|
y, ok := b.variant.(Type_Info_Tuple);
|
||||||
|
if !ok do return false;
|
||||||
|
if len(x.types) != len(y.types) do return false;
|
||||||
|
for _, i in x.types {
|
||||||
|
xt, yt := x.types[i], y.types[i];
|
||||||
|
if !are_types_identical(xt, yt) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Type_Info_Struct:
|
||||||
|
y, ok := b.variant.(Type_Info_Struct);
|
||||||
|
if !ok do return false;
|
||||||
|
switch {
|
||||||
|
case len(x.types) != len(y.types),
|
||||||
|
x.is_packed != y.is_packed,
|
||||||
|
x.is_ordered != y.is_ordered,
|
||||||
|
x.is_raw_union != y.is_raw_union,
|
||||||
|
x.custom_align != y.custom_align:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for _, i in x.types {
|
||||||
|
xn, yn := x.names[i], y.names[i];
|
||||||
|
xt, yt := x.types[i], y.types[i];
|
||||||
|
|
||||||
|
if xn != yn do return false;
|
||||||
|
if !are_types_identical(xt, yt) do return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Type_Info_Union:
|
||||||
|
y, ok := b.variant.(Type_Info_Union);
|
||||||
|
if !ok do return false;
|
||||||
|
if len(x.variants) != len(y.variants) do return false;
|
||||||
|
|
||||||
|
for _, i in x.variants {
|
||||||
|
xv, yv := x.variants[i], y.variants[i];
|
||||||
|
if !are_types_identical(xv, yv) do return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Type_Info_Enum:
|
||||||
|
// NOTE(bill): Should be handled above
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case Type_Info_Map:
|
||||||
|
y, ok := b.variant.(Type_Info_Map);
|
||||||
|
if !ok do return false;
|
||||||
|
return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value);
|
||||||
|
|
||||||
|
case Type_Info_Bit_Field:
|
||||||
|
y, ok := b.variant.(Type_Info_Bit_Field);
|
||||||
|
if !ok do return false;
|
||||||
|
if len(x.names) != len(y.names) do return false;
|
||||||
|
|
||||||
|
for _, i in x.names {
|
||||||
|
xb, yb := x.bits[i], y.bits[i];
|
||||||
|
xo, yo := x.offsets[i], y.offsets[i];
|
||||||
|
xn, yn := x.names[i], y.names[i];
|
||||||
|
|
||||||
|
if xb != yb do return false;
|
||||||
|
if xo != yo do return false;
|
||||||
|
if xn != yn do return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
is_signed :: proc(info: ^Type_Info) -> bool {
|
is_signed :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
match i in type_info_base(info).variant {
|
switch i in type_info_base(info).variant {
|
||||||
case Type_Info.Integer: return i.signed;
|
case Type_Info_Integer: return i.signed;
|
||||||
case Type_Info.Float: return true;
|
case Type_Info_Float: return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
is_integer :: proc(info: ^Type_Info) -> bool {
|
is_integer :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Integer);
|
_, ok := type_info_base(info).variant.(Type_Info_Integer);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_rune :: proc(info: ^Type_Info) -> bool {
|
is_rune :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Rune);
|
_, ok := type_info_base(info).variant.(Type_Info_Rune);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_float :: proc(info: ^Type_Info) -> bool {
|
is_float :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Float);
|
_, ok := type_info_base(info).variant.(Type_Info_Float);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_complex :: proc(info: ^Type_Info) -> bool {
|
is_complex :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Complex);
|
_, ok := type_info_base(info).variant.(Type_Info_Complex);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_any :: proc(info: ^Type_Info) -> bool {
|
is_any :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Any);
|
_, ok := type_info_base(info).variant.(Type_Info_Any);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_string :: proc(info: ^Type_Info) -> bool {
|
is_string :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.String);
|
_, ok := type_info_base(info).variant.(Type_Info_String);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_boolean :: proc(info: ^Type_Info) -> bool {
|
is_boolean :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Boolean);
|
_, ok := type_info_base(info).variant.(Type_Info_Boolean);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_pointer :: proc(info: ^Type_Info) -> bool {
|
is_pointer :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Pointer);
|
_, ok := type_info_base(info).variant.(Type_Info_Pointer);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_procedure :: proc(info: ^Type_Info) -> bool {
|
is_procedure :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Procedure);
|
_, ok := type_info_base(info).variant.(Type_Info_Procedure);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_array :: proc(info: ^Type_Info) -> bool {
|
is_array :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Array);
|
_, ok := type_info_base(info).variant.(Type_Info_Array);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
|
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Dynamic_Array);
|
_, ok := type_info_base(info).variant.(Type_Info_Dynamic_Array);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
|
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Map);
|
_, ok := type_info_base(info).variant.(Type_Info_Map);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_slice :: proc(info: ^Type_Info) -> bool {
|
is_slice :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Slice);
|
_, ok := type_info_base(info).variant.(Type_Info_Slice);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_vector :: proc(info: ^Type_Info) -> bool {
|
is_vector :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Vector);
|
_, ok := type_info_base(info).variant.(Type_Info_Vector);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_tuple :: proc(info: ^Type_Info) -> bool {
|
is_tuple :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Tuple);
|
_, ok := type_info_base(info).variant.(Type_Info_Tuple);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_struct :: proc(info: ^Type_Info) -> bool {
|
is_struct :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
s, ok := type_info_base(info).variant.(Type_Info.Struct);
|
s, ok := type_info_base(info).variant.(Type_Info_Struct);
|
||||||
return ok && !s.is_raw_union;
|
return ok && !s.is_raw_union;
|
||||||
}
|
}
|
||||||
is_raw_union :: proc(info: ^Type_Info) -> bool {
|
is_raw_union :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
s, ok := type_info_base(info).variant.(Type_Info.Struct);
|
s, ok := type_info_base(info).variant.(Type_Info_Struct);
|
||||||
return ok && s.is_raw_union;
|
return ok && s.is_raw_union;
|
||||||
}
|
}
|
||||||
is_union :: proc(info: ^Type_Info) -> bool {
|
is_union :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Union);
|
_, ok := type_info_base(info).variant.(Type_Info_Union);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
is_enum :: proc(info: ^Type_Info) -> bool {
|
is_enum :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil do return false;
|
if info == nil do return false;
|
||||||
_, ok := type_info_base(info).variant.(Type_Info.Enum);
|
_, ok := type_info_base(info).variant.(Type_Info_Enum);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-2
@@ -1,3 +1,5 @@
|
|||||||
|
import "utf8.odin"
|
||||||
|
|
||||||
REPLACEMENT_CHAR :: '\uFFFD';
|
REPLACEMENT_CHAR :: '\uFFFD';
|
||||||
MAX_RUNE :: '\U0010FFFF';
|
MAX_RUNE :: '\U0010FFFF';
|
||||||
|
|
||||||
@@ -27,7 +29,7 @@ encode_surrogate_pair :: proc(r: rune) -> (r1, r2: rune) {
|
|||||||
return _surr1 + (r>>10)&0x3ff, _surr2 + r&0x3ff;
|
return _surr1 + (r>>10)&0x3ff, _surr2 + r&0x3ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
encode :: proc(d: []u16, s: []rune) {
|
encode :: proc(d: []u16, s: []rune) -> int {
|
||||||
n := len(s);
|
n := len(s);
|
||||||
for r in s do if r >= _surr_self do n += 1;
|
for r in s do if r >= _surr_self do n += 1;
|
||||||
|
|
||||||
@@ -35,7 +37,7 @@ encode :: proc(d: []u16, s: []rune) {
|
|||||||
n = 0;
|
n = 0;
|
||||||
|
|
||||||
for r in s {
|
for r in s {
|
||||||
match r {
|
switch r {
|
||||||
case 0.._surr1, _surr3.._surr_self:
|
case 0.._surr1, _surr3.._surr_self:
|
||||||
d[n] = u16(r);
|
d[n] = u16(r);
|
||||||
n += 1;
|
n += 1;
|
||||||
@@ -51,4 +53,33 @@ encode :: proc(d: []u16, s: []rune) {
|
|||||||
n += 1;
|
n += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
encode :: proc(d: []u16, s: string) -> int {
|
||||||
|
n := utf8.rune_count(s);
|
||||||
|
for r in s do if r >= _surr_self do n += 1;
|
||||||
|
|
||||||
|
max_n := min(len(d), n);
|
||||||
|
n = 0;
|
||||||
|
|
||||||
|
for r in s {
|
||||||
|
switch r {
|
||||||
|
case 0.._surr1, _surr3.._surr_self:
|
||||||
|
d[n] = u16(r);
|
||||||
|
n += 1;
|
||||||
|
|
||||||
|
case _surr_self..MAX_RUNE:
|
||||||
|
r1, r2 := encode_surrogate_pair(r);
|
||||||
|
d[n] = u16(r1);
|
||||||
|
d[n+1] = u16(r2);
|
||||||
|
n += 2;
|
||||||
|
|
||||||
|
case:
|
||||||
|
d[n] = u16(REPLACEMENT_CHAR);
|
||||||
|
n += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -61,7 +61,7 @@ accept_sizes := [256]u8{
|
|||||||
encode_rune :: proc(r: rune) -> ([4]u8, int) {
|
encode_rune :: proc(r: rune) -> ([4]u8, int) {
|
||||||
buf: [4]u8;
|
buf: [4]u8;
|
||||||
i := u32(r);
|
i := u32(r);
|
||||||
mask: u8 : 0x3f;
|
mask :: u8(0x3f);
|
||||||
if i <= 1<<7-1 {
|
if i <= 1<<7-1 {
|
||||||
buf[0] = u8(r);
|
buf[0] = u8(r);
|
||||||
return buf, 1;
|
return buf, 1;
|
||||||
@@ -92,7 +92,7 @@ encode_rune :: proc(r: rune) -> ([4]u8, int) {
|
|||||||
return buf, 4;
|
return buf, 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune(cast([]u8)s); }
|
decode_rune :: inline proc(s: string) -> (rune, int) do return decode_rune(cast([]u8)s);
|
||||||
decode_rune :: proc(s: []u8) -> (rune, int) {
|
decode_rune :: proc(s: []u8) -> (rune, int) {
|
||||||
n := len(s);
|
n := len(s);
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
@@ -132,7 +132,7 @@ decode_rune :: proc(s: []u8) -> (rune, int) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
decode_last_rune :: proc(s: string) -> (rune, int) #inline { return decode_last_rune(cast([]u8)s); }
|
decode_last_rune :: inline proc(s: string) -> (rune, int) do return decode_last_rune(cast([]u8)s);
|
||||||
decode_last_rune :: proc(s: []u8) -> (rune, int) {
|
decode_last_rune :: proc(s: []u8) -> (rune, int) {
|
||||||
r: rune;
|
r: rune;
|
||||||
size: int;
|
size: int;
|
||||||
@@ -211,9 +211,9 @@ valid_string :: proc(s: string) -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rune_start :: proc(b: u8) -> bool #inline { return b&0xc0 != 0x80; }
|
rune_start :: inline proc(b: u8) -> bool do return b&0xc0 != 0x80;
|
||||||
|
|
||||||
rune_count :: proc(s: string) -> int #inline { return rune_count(cast([]u8)s); }
|
rune_count :: inline proc(s: string) -> int do return rune_count(cast([]u8)s);
|
||||||
rune_count :: proc(s: []u8) -> int {
|
rune_count :: proc(s: []u8) -> int {
|
||||||
count := 0;
|
count := 0;
|
||||||
n := len(s);
|
n := len(s);
|
||||||
@@ -254,7 +254,7 @@ rune_count :: proc(s: []u8) -> int {
|
|||||||
|
|
||||||
|
|
||||||
rune_size :: proc(r: rune) -> int {
|
rune_size :: proc(r: rune) -> int {
|
||||||
match {
|
switch {
|
||||||
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;
|
||||||
|
|||||||
@@ -1,27 +1,23 @@
|
|||||||
|
import "core:fmt.odin"
|
||||||
|
import "core:strconv.odin"
|
||||||
|
import "core:mem.odin"
|
||||||
|
import "core:bits.odin"
|
||||||
|
import "core:hash.odin"
|
||||||
|
import "core:math.odin"
|
||||||
|
import "core:os.odin"
|
||||||
|
import "core:raw.odin"
|
||||||
|
import "core:sort.odin"
|
||||||
|
import "core:strings.odin"
|
||||||
|
import "core:types.odin"
|
||||||
|
import "core:utf16.odin"
|
||||||
|
import "core:utf8.odin"
|
||||||
|
|
||||||
import (
|
when ODIN_OS == "windows" {
|
||||||
"fmt.odin";
|
import "core:atomics.odin"
|
||||||
"strconv.odin";
|
import "core:opengl.odin"
|
||||||
"mem.odin";
|
import "core:thread.odin"
|
||||||
"thread.odin" when ODIN_OS == "windows";
|
import win32 "core:sys/windows.odin"
|
||||||
win32 "sys/windows.odin" when ODIN_OS == "windows";
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
"atomics.odin";
|
|
||||||
"bits.odin";
|
|
||||||
"hash.odin";
|
|
||||||
"math.odin";
|
|
||||||
"opengl.odin";
|
|
||||||
"os.odin";
|
|
||||||
"raw.odin";
|
|
||||||
"sort.odin";
|
|
||||||
"strings.odin";
|
|
||||||
"sync.odin";
|
|
||||||
"types.odin";
|
|
||||||
"utf8.odin";
|
|
||||||
"utf16.odin";
|
|
||||||
*/
|
|
||||||
)
|
|
||||||
|
|
||||||
general_stuff :: proc() {
|
general_stuff :: proc() {
|
||||||
{ // `do` for inline statmes rather than block
|
{ // `do` for inline statmes rather than block
|
||||||
@@ -61,8 +57,8 @@ general_stuff :: proc() {
|
|||||||
|
|
||||||
{ // `expand_to_tuple` built-in procedure
|
{ // `expand_to_tuple` built-in procedure
|
||||||
Foo :: struct {
|
Foo :: struct {
|
||||||
x: int;
|
x: int,
|
||||||
b: bool;
|
b: bool,
|
||||||
}
|
}
|
||||||
f := Foo{137, true};
|
f := Foo{137, true};
|
||||||
x, b := expand_to_tuple(f);
|
x, b := expand_to_tuple(f);
|
||||||
@@ -80,31 +76,12 @@ general_stuff :: proc() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nested_struct_declarations :: proc() {
|
|
||||||
{
|
|
||||||
FooInteger :: int;
|
|
||||||
Foo :: struct {
|
|
||||||
i: FooInteger;
|
|
||||||
};
|
|
||||||
f := Foo{FooInteger(137)};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Foo :: struct {
|
|
||||||
Integer :: int;
|
|
||||||
|
|
||||||
i: Integer;
|
|
||||||
}
|
|
||||||
f := Foo{Foo.Integer(137)};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default_struct_values :: proc() {
|
default_struct_values :: proc() {
|
||||||
{
|
{
|
||||||
Vector3 :: struct {
|
Vector3 :: struct {
|
||||||
x: f32;
|
x: f32,
|
||||||
y: f32;
|
y: f32,
|
||||||
z: f32;
|
z: f32,
|
||||||
}
|
}
|
||||||
v: Vector3;
|
v: Vector3;
|
||||||
fmt.println(v);
|
fmt.println(v);
|
||||||
@@ -112,9 +89,9 @@ default_struct_values :: proc() {
|
|||||||
{
|
{
|
||||||
// Default values must be constants
|
// Default values must be constants
|
||||||
Vector3 :: struct {
|
Vector3 :: struct {
|
||||||
x: f32 = 1;
|
x: f32 = 1,
|
||||||
y: f32 = 4;
|
y: f32 = 4,
|
||||||
z: f32 = 9;
|
z: f32 = 9,
|
||||||
}
|
}
|
||||||
v: Vector3;
|
v: Vector3;
|
||||||
fmt.println(v);
|
fmt.println(v);
|
||||||
@@ -132,9 +109,9 @@ default_struct_values :: proc() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
Vector3 :: struct {
|
Vector3 :: struct {
|
||||||
x := 1.0;
|
x := 1.0,
|
||||||
y := 4.0;
|
y := 4.0,
|
||||||
z := 9.0;
|
z := 9.0,
|
||||||
}
|
}
|
||||||
stack_default: Vector3;
|
stack_default: Vector3;
|
||||||
stack_literal := Vector3{};
|
stack_literal := Vector3{};
|
||||||
@@ -172,7 +149,7 @@ union_type :: proc() {
|
|||||||
|
|
||||||
val = nil;
|
val = nil;
|
||||||
|
|
||||||
match v in val {
|
switch v in val {
|
||||||
case int: fmt.println("int", v);
|
case int: fmt.println("int", v);
|
||||||
case bool: fmt.println("bool", v);
|
case bool: fmt.println("bool", v);
|
||||||
case: fmt.println("nil");
|
case: fmt.println("nil");
|
||||||
@@ -193,20 +170,15 @@ union_type :: proc() {
|
|||||||
|
|
||||||
val = nil;
|
val = nil;
|
||||||
|
|
||||||
match v in val {
|
switch v in val {
|
||||||
case int: fmt.println("int", v);
|
case int: fmt.println("int", v);
|
||||||
case bool: fmt.println("bool", v);
|
case bool: fmt.println("bool", v);
|
||||||
case: fmt.println("nil");
|
case: fmt.println("nil");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 :: struct {
|
Vector3 :: struct {x, y, z: f32};
|
||||||
x, y, z: f32;
|
Quaternion :: struct {x, y, z: f32, w: f32 = 1};
|
||||||
};
|
|
||||||
Quaternion :: struct {
|
|
||||||
x, y, z: f32;
|
|
||||||
w: f32 = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// More realistic examples
|
// More realistic examples
|
||||||
{
|
{
|
||||||
@@ -217,23 +189,23 @@ union_type :: proc() {
|
|||||||
// an example of this for a basic game Entity.
|
// an example of this for a basic game Entity.
|
||||||
|
|
||||||
Entity :: struct {
|
Entity :: struct {
|
||||||
id: u64;
|
id: u64,
|
||||||
name: string;
|
name: string,
|
||||||
position: Vector3;
|
position: Vector3,
|
||||||
orientation: Quaternion;
|
orientation: Quaternion,
|
||||||
|
|
||||||
derived: any;
|
derived: any,
|
||||||
}
|
}
|
||||||
|
|
||||||
Frog :: struct {
|
Frog :: struct {
|
||||||
using entity: Entity;
|
using entity: Entity,
|
||||||
jump_height: f32;
|
jump_height: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Monster :: struct {
|
Monster :: struct {
|
||||||
using entity: Entity;
|
using entity: Entity,
|
||||||
is_robot: bool;
|
is_robot: bool,
|
||||||
is_zombie: bool;
|
is_zombie: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// See `parametric_polymorphism` procedure for details
|
// See `parametric_polymorphism` procedure for details
|
||||||
@@ -245,7 +217,7 @@ union_type :: proc() {
|
|||||||
|
|
||||||
entity := new_entity(Monster);
|
entity := new_entity(Monster);
|
||||||
|
|
||||||
match e in entity.derived {
|
switch e in entity.derived {
|
||||||
case Frog:
|
case Frog:
|
||||||
fmt.println("Ribbit");
|
fmt.println("Ribbit");
|
||||||
case Monster:
|
case Monster:
|
||||||
@@ -261,23 +233,23 @@ union_type :: proc() {
|
|||||||
// basic game Entity but using an union.
|
// basic game Entity but using an union.
|
||||||
|
|
||||||
Entity :: struct {
|
Entity :: struct {
|
||||||
id: u64;
|
id: u64,
|
||||||
name: string;
|
name: string,
|
||||||
position: Vector3;
|
position: Vector3,
|
||||||
orientation: Quaternion;
|
orientation: Quaternion,
|
||||||
|
|
||||||
derived: union {Frog, Monster};
|
derived: union {Frog, Monster},
|
||||||
}
|
}
|
||||||
|
|
||||||
Frog :: struct {
|
Frog :: struct {
|
||||||
using entity: ^Entity;
|
using entity: ^Entity,
|
||||||
jump_height: f32;
|
jump_height: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Monster :: struct {
|
Monster :: struct {
|
||||||
using entity: ^Entity;
|
using entity: ^Entity,
|
||||||
is_robot: bool;
|
is_robot: bool,
|
||||||
is_zombie: bool;
|
is_zombie: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// See `parametric_polymorphism` procedure for details
|
// See `parametric_polymorphism` procedure for details
|
||||||
@@ -289,7 +261,7 @@ union_type :: proc() {
|
|||||||
|
|
||||||
entity := new_entity(Monster);
|
entity := new_entity(Monster);
|
||||||
|
|
||||||
match e in entity.derived {
|
switch e in entity.derived {
|
||||||
case Frog:
|
case Frog:
|
||||||
fmt.println("Ribbit");
|
fmt.println("Ribbit");
|
||||||
case Monster:
|
case Monster:
|
||||||
@@ -389,18 +361,17 @@ parametric_polymorphism :: proc() {
|
|||||||
|
|
||||||
|
|
||||||
{ // Polymorphic Types and Type Specialization
|
{ // Polymorphic Types and Type Specialization
|
||||||
|
Table_Slot :: struct(Key, Value: type) {
|
||||||
|
occupied: bool,
|
||||||
|
hash: u32,
|
||||||
|
key: Key,
|
||||||
|
value: Value,
|
||||||
|
}
|
||||||
|
TABLE_SIZE_MIN :: 32;
|
||||||
Table :: struct(Key, Value: type) {
|
Table :: struct(Key, Value: type) {
|
||||||
Slot :: struct {
|
count: int,
|
||||||
occupied: bool;
|
allocator: Allocator,
|
||||||
hash: u32;
|
slots: []Table_Slot(Key, Value),
|
||||||
key: Key;
|
|
||||||
value: Value;
|
|
||||||
}
|
|
||||||
SIZE_MIN :: 32;
|
|
||||||
|
|
||||||
count: int;
|
|
||||||
allocator: Allocator;
|
|
||||||
slots: []Slot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only allow types that are specializations of a (polymorphic) slice
|
// Only allow types that are specializations of a (polymorphic) slice
|
||||||
@@ -414,8 +385,8 @@ parametric_polymorphism :: proc() {
|
|||||||
c := context;
|
c := context;
|
||||||
if table.allocator.procedure != nil do c.allocator = table.allocator;
|
if table.allocator.procedure != nil do c.allocator = table.allocator;
|
||||||
|
|
||||||
push_context c {
|
context <- c {
|
||||||
table.slots = make_slice([]T.Slot, max(capacity, T.SIZE_MIN));
|
table.slots = make_slice(type_of(table.slots), max(capacity, TABLE_SIZE_MIN));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,10 +394,10 @@ parametric_polymorphism :: proc() {
|
|||||||
c := context;
|
c := context;
|
||||||
if table.allocator.procedure != nil do c.allocator = table.allocator;
|
if table.allocator.procedure != nil do c.allocator = table.allocator;
|
||||||
|
|
||||||
push_context c {
|
context <- c {
|
||||||
old_slots := table.slots;
|
old_slots := table.slots;
|
||||||
|
|
||||||
cap := max(2*cap(table.slots), T.SIZE_MIN);
|
cap := max(2*cap(table.slots), TABLE_SIZE_MIN);
|
||||||
allocate(table, cap);
|
allocate(table, cap);
|
||||||
|
|
||||||
for s in old_slots do if s.occupied {
|
for s in old_slots do if s.occupied {
|
||||||
@@ -573,7 +544,7 @@ threading_example :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for len(threads) > 0 {
|
for len(threads) > 0 {
|
||||||
for i := 0; i < len(threads); {
|
for i := 0; i < len(threads); /**/ {
|
||||||
if t := threads[i]; thread.is_done(t) {
|
if t := threads[i]; thread.is_done(t) {
|
||||||
fmt.printf("Thread %d is done\n", t.user_index);
|
fmt.printf("Thread %d is done\n", t.user_index);
|
||||||
thread.destroy(t);
|
thread.destroy(t);
|
||||||
@@ -587,11 +558,9 @@ threading_example :: proc() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
when true {
|
when false {
|
||||||
fmt.println("\n# general_stuff"); general_stuff();
|
fmt.println("\n# general_stuff"); general_stuff();
|
||||||
fmt.println("\n# nested_struct_declarations"); nested_struct_declarations();
|
|
||||||
fmt.println("\n# default_struct_values"); default_struct_values();
|
fmt.println("\n# default_struct_values"); default_struct_values();
|
||||||
fmt.println("\n# union_type"); union_type();
|
fmt.println("\n# union_type"); union_type();
|
||||||
fmt.println("\n# parametric_polymorphism"); parametric_polymorphism();
|
fmt.println("\n# parametric_polymorphism"); parametric_polymorphism();
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import "core:fmt.odin";
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
recursive_factorial :: proc(i: u64) -> u64 {
|
||||||
|
if i < 2 do return 1;
|
||||||
|
return i * recursive_factorial(i-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop_factorial :: proc(i: u64) -> u64 {
|
||||||
|
result: u64 = 1;
|
||||||
|
for n in 2..i {
|
||||||
|
result *= n;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fmt.println(recursive_factorial(12));
|
||||||
|
fmt.println(loop_factorial(12));
|
||||||
|
}
|
||||||
@@ -1,63 +1,63 @@
|
|||||||
import win32 "sys/windows.odin" when ODIN_OS == "windows";
|
import win32 "core:sys/windows.odin" when ODIN_OS == "windows";
|
||||||
import wgl "sys/wgl.odin" when ODIN_OS == "windows";
|
import wgl "core:sys/wgl.odin" when ODIN_OS == "windows";
|
||||||
import "fmt.odin";
|
import "core:fmt.odin";
|
||||||
import "math.odin";
|
import "core:math.odin";
|
||||||
import "os.odin";
|
import "core:os.odin";
|
||||||
import gl "opengl.odin";
|
import gl "core:opengl.odin";
|
||||||
|
|
||||||
const TWO_HEARTS = '💕';
|
TWO_HEARTS :: '💕';
|
||||||
|
|
||||||
var win32_perf_count_freq = win32.get_query_performance_frequency();
|
win32_perf_count_freq := win32.get_query_performance_frequency();
|
||||||
proc time_now() -> f64 {
|
time_now :: proc() -> f64 {
|
||||||
assert(win32_perf_count_freq != 0);
|
assert(win32_perf_count_freq != 0);
|
||||||
|
|
||||||
var counter: i64;
|
counter: i64;
|
||||||
win32.query_performance_counter(&counter);
|
win32.query_performance_counter(&counter);
|
||||||
return f64(counter) / f64(win32_perf_count_freq);
|
return f64(counter) / f64(win32_perf_count_freq);
|
||||||
}
|
}
|
||||||
proc win32_print_last_error() {
|
win32_print_last_error :: proc() {
|
||||||
var err_code = win32.get_last_error();
|
err_code := win32.get_last_error();
|
||||||
if err_code != 0 {
|
if err_code != 0 {
|
||||||
fmt.println("get_last_error: ", err_code);
|
fmt.println("get_last_error: ", err_code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yuk!
|
// Yuk!
|
||||||
proc to_c_string(s: string) -> []u8 {
|
to_c_string :: proc(s: string) -> []u8 {
|
||||||
var c_str = make([]u8, len(s)+1);
|
c_str := make([]u8, len(s)+1);
|
||||||
copy(c_str, []u8(s));
|
copy(c_str, cast([]u8)s);
|
||||||
c_str[len(s)] = 0;
|
c_str[len(s)] = 0;
|
||||||
return c_str;
|
return c_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Window struct {
|
Window :: struct {
|
||||||
width, height: int,
|
width, height: int,
|
||||||
wc: win32.WndClassExA,
|
wc: win32.Wnd_Class_Ex_A,
|
||||||
dc: win32.Hdc,
|
dc: win32.Hdc,
|
||||||
hwnd: win32.Hwnd,
|
hwnd: win32.Hwnd,
|
||||||
opengl_context, rc: wgl.Hglrc,
|
opengl_context, rc: wgl.Hglrc,
|
||||||
c_title: []u8,
|
c_title: []u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
proc make_window(title: string, msg, height: int, window_proc: win32.WndProc) -> (Window, bool) {
|
make_window :: proc(title: string, msg, height: int, window_proc: win32.Wnd_Proc) -> (Window, bool) {
|
||||||
using win32;
|
using win32;
|
||||||
|
|
||||||
var w: Window;
|
w: Window;
|
||||||
w.width, w.height = msg, height;
|
w.width, w.height = msg, height;
|
||||||
|
|
||||||
var class_name = "Win32-Odin-Window\x00";
|
class_name := "Win32-Odin-Window\x00";
|
||||||
var c_class_name = &class_name[0];
|
c_class_name := &class_name[0];
|
||||||
if title[len(title)-1] != 0 {
|
if title[len(title)-1] != 0 {
|
||||||
w.c_title = to_c_string(title);
|
w.c_title = to_c_string(title);
|
||||||
} else {
|
} else {
|
||||||
w.c_title = []u8(title);
|
w.c_title = cast([]u8)title;
|
||||||
}
|
}
|
||||||
|
|
||||||
var instance = get_module_handle_a(nil);
|
instance := get_module_handle_a(nil);
|
||||||
|
|
||||||
w.wc = WndClassExA{
|
w.wc = Wnd_Class_Ex_A{
|
||||||
size = size_of(WndClassExA),
|
size = size_of(Wnd_Class_Ex_A),
|
||||||
style = CS_VREDRAW | CS_HREDRAW,
|
style = CS_VREDRAW | CS_HREDRAW,
|
||||||
instance = Hinstance(instance),
|
instance = Hinstance(instance),
|
||||||
class_name = c_class_name,
|
class_name = c_class_name,
|
||||||
@@ -84,8 +84,8 @@ proc make_window(title: string, msg, height: int, window_proc: win32.WndProc) ->
|
|||||||
w.dc = get_dc(w.hwnd);
|
w.dc = get_dc(w.hwnd);
|
||||||
|
|
||||||
{
|
{
|
||||||
var pfd = PixelFormatDescriptor{
|
pfd := Pixel_Format_Descriptor{
|
||||||
size = size_of(PixelFormatDescriptor),
|
size = size_of(Pixel_Format_Descriptor),
|
||||||
version = 1,
|
version = 1,
|
||||||
flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
|
flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
|
||||||
pixel_type = PFD_TYPE_RGBA,
|
pixel_type = PFD_TYPE_RGBA,
|
||||||
@@ -100,15 +100,15 @@ proc make_window(title: string, msg, height: int, window_proc: win32.WndProc) ->
|
|||||||
w.opengl_context = wgl.create_context(w.dc);
|
w.opengl_context = wgl.create_context(w.dc);
|
||||||
wgl.make_current(w.dc, w.opengl_context);
|
wgl.make_current(w.dc, w.opengl_context);
|
||||||
|
|
||||||
var attribs = [8]i32{
|
attribs := [8]i32{
|
||||||
wgl.CONTEXT_MAJOR_VERSION_ARB, 2,
|
wgl.CONTEXT_MAJOR_VERSION_ARB, 2,
|
||||||
wgl.CONTEXT_MINOR_VERSION_ARB, 1,
|
wgl.CONTEXT_MINOR_VERSION_ARB, 1,
|
||||||
wgl.CONTEXT_PROFILE_MASK_ARB, wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
wgl.CONTEXT_PROFILE_MASK_ARB, wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
||||||
0, // NOTE(bill): tells the proc that this is the end of attribs
|
0, // NOTE(bill): tells the that :: proc this is the end of attribs
|
||||||
};
|
};
|
||||||
|
|
||||||
var wgl_str = "wglCreateContextAttribsARB\x00";
|
wgl_str := "wglCreateContextAttribsARB\x00";
|
||||||
var wglCreateContextAttribsARB = wgl.CreateContextAttribsARBType(wgl.get_proc_address(&wgl_str[0]));
|
wglCreateContextAttribsARB := cast(wgl.Create_Context_Attribs_ARB_Type)wgl.get_proc_address(&wgl_str[0]);
|
||||||
w.rc = wglCreateContextAttribsARB(w.dc, nil, &attribs[0]);
|
w.rc = wglCreateContextAttribsARB(w.dc, nil, &attribs[0]);
|
||||||
wgl.make_current(w.dc, w.rc);
|
wgl.make_current(w.dc, w.rc);
|
||||||
swap_buffers(w.dc);
|
swap_buffers(w.dc);
|
||||||
@@ -117,19 +117,19 @@ proc make_window(title: string, msg, height: int, window_proc: win32.WndProc) ->
|
|||||||
return w, true;
|
return w, true;
|
||||||
}
|
}
|
||||||
|
|
||||||
proc destroy_window(w: ^Window) {
|
destroy_window :: proc(w: ^Window) {
|
||||||
free(w.c_title);
|
free(w.c_title);
|
||||||
}
|
}
|
||||||
|
|
||||||
proc display_window(w: ^Window) {
|
display_window :: proc(w: ^Window) {
|
||||||
win32.swap_buffers(w.dc);
|
win32.swap_buffers(w.dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
proc run() {
|
run :: proc() {
|
||||||
using math;
|
using math;
|
||||||
|
|
||||||
proc win32_proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline {
|
win32_proc :: proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline {
|
||||||
using win32;
|
using win32;
|
||||||
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
|
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
|
||||||
os.exit(0);
|
os.exit(0);
|
||||||
@@ -138,7 +138,7 @@ proc run() {
|
|||||||
return def_window_proc_a(hwnd, msg, wparam, lparam);
|
return def_window_proc_a(hwnd, msg, wparam, lparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
var window, window_success = make_window("Odin Language Demo", 854, 480, win32.WndProc(win32_proc));
|
window, window_success := make_window("Odin Language Demo", 854, 480, cast(win32.Wnd_Proc)win32_proc);
|
||||||
if !window_success {
|
if !window_success {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -148,17 +148,17 @@ proc run() {
|
|||||||
|
|
||||||
using win32;
|
using win32;
|
||||||
|
|
||||||
var prev_time = time_now();
|
prev_time := time_now();
|
||||||
var running = true;
|
running := true;
|
||||||
|
|
||||||
var pos = Vec2{100, 100};
|
pos := Vec2{100, 100};
|
||||||
|
|
||||||
for running {
|
for running {
|
||||||
var curr_time = time_now();
|
curr_time := time_now();
|
||||||
var dt = f32(curr_time - prev_time);
|
dt := f32(curr_time - prev_time);
|
||||||
prev_time = curr_time;
|
prev_time = curr_time;
|
||||||
|
|
||||||
var msg: Msg;
|
msg: Msg;
|
||||||
for peek_message_a(&msg, nil, 0, 0, PM_REMOVE) > 0 {
|
for peek_message_a(&msg, nil, 0, 0, PM_REMOVE) > 0 {
|
||||||
if msg.message == WM_QUIT {
|
if msg.message == WM_QUIT {
|
||||||
running = false;
|
running = false;
|
||||||
@@ -167,18 +167,18 @@ proc run() {
|
|||||||
dispatch_message_a(&msg);
|
dispatch_message_a(&msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_key_down(KeyCode.Escape) {
|
if is_key_down(Key_Code.Escape) {
|
||||||
running = false;
|
running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const SPEED = 500;
|
SPEED :: 500;
|
||||||
var v: Vec2;
|
v: Vec2;
|
||||||
|
|
||||||
if is_key_down(KeyCode.Right) { v[0] += 1; }
|
if is_key_down(Key_Code.Right) do v[0] += 1;
|
||||||
if is_key_down(KeyCode.Left) { v[0] -= 1; }
|
if is_key_down(Key_Code.Left) do v[0] -= 1;
|
||||||
if is_key_down(KeyCode.Up) { v[1] += 1; }
|
if is_key_down(Key_Code.Up) do v[1] += 1;
|
||||||
if is_key_down(KeyCode.Down) { v[1] -= 1; }
|
if is_key_down(Key_Code.Down) do v[1] -= 1;
|
||||||
|
|
||||||
v = norm(v);
|
v = norm(v);
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ proc run() {
|
|||||||
gl.Ortho(0, f64(window.width),
|
gl.Ortho(0, f64(window.width),
|
||||||
0, f64(window.height), 0, 1);
|
0, f64(window.height), 0, 1);
|
||||||
|
|
||||||
proc draw_rect(x, y, w, h: f32) {
|
draw_rect :: proc(x, y, w, h: f32) {
|
||||||
gl.Begin(gl.TRIANGLES);
|
gl.Begin(gl.TRIANGLES);
|
||||||
defer gl.End();
|
defer gl.End();
|
||||||
|
|
||||||
@@ -209,14 +209,13 @@ proc run() {
|
|||||||
draw_rect(pos.x, pos.y, 50, 50);
|
draw_rect(pos.x, pos.y, 50, 50);
|
||||||
|
|
||||||
display_window(&window);
|
display_window(&window);
|
||||||
var ms_to_sleep = i32(16 - 1000*dt);
|
if ms_to_sleep := i32(16 - 1000*dt); ms_to_sleep > 0 {
|
||||||
if ms_to_sleep > 0 {
|
|
||||||
win32.sleep(ms_to_sleep);
|
win32.sleep(ms_to_sleep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
proc main() {
|
main :: proc() {
|
||||||
run();
|
run();
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import "core:fmt.odin";
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
fmt.println("Hellope, world!");
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
#import "fmt.odin";
|
import "core:fmt.odin";
|
||||||
#import "os.odin";
|
import "core:os.odin";
|
||||||
#import "mem.odin";
|
import "core:mem.odin";
|
||||||
// #import "http_test.odin" as ht;
|
// import "http_test.odin" as ht;
|
||||||
// #import "game.odin" as game;
|
// import "game.odin" as game;
|
||||||
// #import "punity.odin" as pn;
|
// import "punity.odin" as pn;
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
struct_padding();
|
struct_padding();
|
||||||
@@ -160,21 +160,21 @@ type_introspection :: proc() {
|
|||||||
info: ^Type_Info;
|
info: ^Type_Info;
|
||||||
x: int;
|
x: int;
|
||||||
|
|
||||||
info = type_info(int); // by type
|
info = type_info_of(int); // by type
|
||||||
info = type_info_of_val(x); // by value
|
info = type_info_of(x); // by value
|
||||||
// See: runtime.odin
|
// See: runtime.odin
|
||||||
|
|
||||||
match i in info {
|
match i in info.variant {
|
||||||
case Type_Info.Integer:
|
case Type_Info_Integer:
|
||||||
fmt.println("integer!");
|
fmt.println("integer!");
|
||||||
case Type_Info.Float:
|
case Type_Info_Float:
|
||||||
fmt.println("float!");
|
fmt.println("float!");
|
||||||
default:
|
case:
|
||||||
fmt.println("potato!");
|
fmt.println("potato!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsafe cast
|
// Unsafe cast
|
||||||
integer_info := cast(^Type_Info.Integer)cast(rawptr)info;
|
integer_info := cast(^Type_Info_Integer)cast(rawptr)info;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -185,9 +185,9 @@ type_introspection :: proc() {
|
|||||||
v2: Vector3;
|
v2: Vector3;
|
||||||
v3: Vector3;
|
v3: Vector3;
|
||||||
|
|
||||||
t1 := type_info_of_val(v1);
|
t1 := type_info_of(v1);
|
||||||
t2 := type_info_of_val(v2);
|
t2 := type_info_of(v2);
|
||||||
t3 := type_info_of_val(v3);
|
t3 := type_info_of(v3);
|
||||||
|
|
||||||
fmt.println();
|
fmt.println();
|
||||||
fmt.print("Type of v1 is:\n\t", t1);
|
fmt.print("Type of v1 is:\n\t", t1);
|
||||||
@@ -262,12 +262,12 @@ crazy_introspection :: proc() {
|
|||||||
TOMATO,
|
TOMATO,
|
||||||
}
|
}
|
||||||
|
|
||||||
fruit_ti := type_info(Fruit);
|
fruit_ti := type_info_of(Fruit);
|
||||||
name := (union_cast(^Type_Info.Named)fruit_ti).name; // Unsafe casts
|
name := fruit_ti.variant.(Type_Info_Named).name;
|
||||||
info, _ := union_cast(^Type_Info.Enum)type_info_base(fruit_ti); // Unsafe casts
|
info, _ := type_info_base(fruit_ti).variant.(Type_Info_Enum);
|
||||||
|
|
||||||
fmt.printf("%s :: enum %T {\n", name, info.base);
|
fmt.printf("%s :: enum %T {\n", name, info.base);
|
||||||
for i := 0; i < len(info.values); i++ {
|
for _, i in info.values {
|
||||||
fmt.printf("\t%s\t= %v,\n", info.names[i], info.values[i]);
|
fmt.printf("\t%s\t= %v,\n", info.names[i], info.values[i]);
|
||||||
}
|
}
|
||||||
fmt.printf("}\n");
|
fmt.printf("}\n");
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
// Demo 002
|
// Demo 002
|
||||||
#load "fmt.odin";
|
export "core:fmt.odin";
|
||||||
#load "math.odin";
|
export "core:math.odin";
|
||||||
// #load "game.odin"
|
export "core:mem.odin";
|
||||||
|
// export "game.odin"
|
||||||
|
|
||||||
#thread_local tls_int: int;
|
#thread_local tls_int: int;
|
||||||
|
|
||||||
@@ -94,11 +95,9 @@ enumerations :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
variadic_procedures :: proc() {
|
variadic_procedures :: proc() {
|
||||||
print_ints :: proc(args: ..int) {
|
print_ints :: proc(args: ...int) {
|
||||||
for arg, i in args {
|
for arg, i in args {
|
||||||
if i > 0 {
|
if i > 0 do print(", ");
|
||||||
print(", ");
|
|
||||||
}
|
|
||||||
print(arg);
|
print(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,13 +106,11 @@ variadic_procedures :: proc() {
|
|||||||
print_ints(1); nl();
|
print_ints(1); nl();
|
||||||
print_ints(1, 2, 3); nl();
|
print_ints(1, 2, 3); nl();
|
||||||
|
|
||||||
print_prefix_f32s :: proc(prefix: string, args: ..f32) {
|
print_prefix_f32s :: proc(prefix: string, args: ...f32) {
|
||||||
print(prefix);
|
print(prefix);
|
||||||
print(": ");
|
print(": ");
|
||||||
for arg, i in args {
|
for arg, i in args {
|
||||||
if i > 0 {
|
if i > 0 do print(", ");
|
||||||
print(", ");
|
|
||||||
}
|
|
||||||
print(arg);
|
print(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,13 +144,7 @@ new_builtins :: proc() {
|
|||||||
|
|
||||||
// Q: Should this be `free` rather than `free` and should I overload it for slices too?
|
// Q: Should this be `free` rather than `free` and should I overload it for slices too?
|
||||||
|
|
||||||
{
|
push_allocator default_allocator() {
|
||||||
prev_context := context;
|
|
||||||
defer __context = prev_context;
|
|
||||||
// Q: Should I add a `push_context` feature to the language?
|
|
||||||
|
|
||||||
__context.allocator = default_allocator();
|
|
||||||
|
|
||||||
a := new(int);
|
a := new(int);
|
||||||
defer free(a);
|
defer free(a);
|
||||||
|
|
||||||
@@ -164,7 +155,7 @@ new_builtins :: proc() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
a: int = 123;
|
a: int = 123;
|
||||||
b: type_of_val(a) = 321;
|
b: type_of(a) = 321;
|
||||||
|
|
||||||
// NOTE(bill): This matches the current naming scheme
|
// NOTE(bill): This matches the current naming scheme
|
||||||
// size_of
|
// size_of
|
||||||
@@ -205,7 +196,7 @@ new_builtins :: proc() {
|
|||||||
|
|
||||||
a: [16]int;
|
a: [16]int;
|
||||||
a[1] = 1;
|
a[1] = 1;
|
||||||
b := ^a;
|
b := &a;
|
||||||
// Auto pointer deref
|
// Auto pointer deref
|
||||||
// consistent with record members
|
// consistent with record members
|
||||||
assert(b[1] == 1);
|
assert(b[1] == 1);
|
||||||
@@ -255,7 +246,7 @@ match_statement :: proc() {
|
|||||||
print("5!\n");
|
print("5!\n");
|
||||||
fallthrough; // explicit fallthrough
|
fallthrough; // explicit fallthrough
|
||||||
|
|
||||||
default:
|
case:
|
||||||
print("default!\n");
|
print("default!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,7 +258,7 @@ match_statement :: proc() {
|
|||||||
// break by default
|
// break by default
|
||||||
case TAU:
|
case TAU:
|
||||||
print("τ!\n");
|
print("τ!\n");
|
||||||
default:
|
case:
|
||||||
print("default!\n");
|
print("default!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +270,7 @@ match_statement :: proc() {
|
|||||||
// break by default
|
// break by default
|
||||||
case "Goodbye":
|
case "Goodbye":
|
||||||
print("farewell\n");
|
print("farewell\n");
|
||||||
default:
|
case:
|
||||||
print("???\n");
|
print("???\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,7 +293,7 @@ match_statement :: proc() {
|
|||||||
print("dozens\n");
|
print("dozens\n");
|
||||||
case a >= 100 && a < 1000:
|
case a >= 100 && a < 1000:
|
||||||
print("hundreds\n");
|
print("hundreds\n");
|
||||||
default:
|
case:
|
||||||
print("a fuck ton\n");
|
print("a fuck ton\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,11 +323,9 @@ match_statement :: proc() {
|
|||||||
|
|
||||||
Vector3 :: struct {x, y, z: f32}
|
Vector3 :: struct {x, y, z: f32}
|
||||||
|
|
||||||
print_floats :: proc(args: ..f32) {
|
print_floats :: proc(args: ...f32) {
|
||||||
for arg, i in args {
|
for arg, i in args {
|
||||||
if i > 0 {
|
if i > 0 do print(", ");
|
||||||
print(", ");
|
|
||||||
}
|
|
||||||
print(arg);
|
print(arg);
|
||||||
}
|
}
|
||||||
println();
|
println();
|
||||||
@@ -355,7 +344,7 @@ namespacing :: proc() {
|
|||||||
Thing :: #type struct {
|
Thing :: #type struct {
|
||||||
y: int,
|
y: int,
|
||||||
test: bool,
|
test: bool,
|
||||||
}
|
};
|
||||||
|
|
||||||
b: Thing; // Uses this scope's Thing
|
b: Thing; // Uses this scope's Thing
|
||||||
b.test = true;
|
b.test = true;
|
||||||
@@ -473,10 +462,10 @@ namespacing :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e := Entity{position = Vector3{1, 2, 3}};
|
e := Entity{position = Vector3{1, 2, 3}};
|
||||||
print_pos_1(^e);
|
print_pos_1(&e);
|
||||||
print_pos_2(^e);
|
print_pos_2(&e);
|
||||||
print_pos_3(^e);
|
print_pos_3(&e);
|
||||||
print_pos_4(^e);
|
print_pos_4(&e);
|
||||||
|
|
||||||
// This is similar to C++'s `this` pointer that is implicit and only available in methods
|
// This is similar to C++'s `this` pointer that is implicit and only available in methods
|
||||||
}
|
}
|
||||||
@@ -574,20 +563,20 @@ subtyping :: proc() {
|
|||||||
entity_count := 0;
|
entity_count := 0;
|
||||||
|
|
||||||
next_entity :: proc(entities: []Entity, entity_count: ^int) -> ^Entity {
|
next_entity :: proc(entities: []Entity, entity_count: ^int) -> ^Entity {
|
||||||
e := ^entities[entity_count^];
|
e := &entities[entity_count^];
|
||||||
entity_count^++;
|
entity_count^ += 1;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
f: Frog;
|
f: Frog;
|
||||||
f.entity = next_entity(entities[..], ^entity_count);
|
f.entity = next_entity(entities[..], &entity_count);
|
||||||
f.position = Vector3{3, 4, 6};
|
f.position = Vector3{3, 4, 6};
|
||||||
|
|
||||||
using f.position;
|
using f.position;
|
||||||
print_floats(x, y, z);
|
print_floats(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
/*{
|
||||||
// Down casting
|
// Down casting
|
||||||
|
|
||||||
Entity :: struct {
|
Entity :: struct {
|
||||||
@@ -609,7 +598,7 @@ subtyping :: proc() {
|
|||||||
|
|
||||||
// NOTE(bill): `down_cast` is unsafe and there are not check are compile time or run time
|
// NOTE(bill): `down_cast` is unsafe and there are not check are compile time or run time
|
||||||
// Q: Should I completely remove `down_cast` as I added it in about 30 minutes
|
// Q: Should I completely remove `down_cast` as I added it in about 30 minutes
|
||||||
}
|
}*/
|
||||||
|
|
||||||
{
|
{
|
||||||
// Multiple "inheritance"/subclassing
|
// Multiple "inheritance"/subclassing
|
||||||
@@ -630,7 +619,7 @@ subtyping :: proc() {
|
|||||||
|
|
||||||
tagged_unions :: proc() {
|
tagged_unions :: proc() {
|
||||||
{
|
{
|
||||||
EntityKind :: enum {
|
Entity_Kind :: enum {
|
||||||
INVALID,
|
INVALID,
|
||||||
FROG,
|
FROG,
|
||||||
GIRAFFE,
|
GIRAFFE,
|
||||||
@@ -638,8 +627,8 @@ tagged_unions :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Entity :: struct {
|
Entity :: struct {
|
||||||
kind: EntityKind
|
kind: Entity_Kind
|
||||||
using data: raw_union {
|
using data: struct #raw_union {
|
||||||
frog: struct {
|
frog: struct {
|
||||||
jump_height: f32,
|
jump_height: f32,
|
||||||
colour: u32,
|
colour: u32,
|
||||||
@@ -657,33 +646,31 @@ tagged_unions :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e: Entity;
|
e: Entity;
|
||||||
e.kind = EntityKind.FROG;
|
e.kind = Entity_Kind.FROG;
|
||||||
e.frog.jump_height = 12;
|
e.frog.jump_height = 12;
|
||||||
|
|
||||||
f: type_of_val(e.frog);
|
f: type_of(e.frog);
|
||||||
|
|
||||||
// But this is very unsafe and extremely cumbersome to write
|
// But this is very unsafe and extremely cumbersome to write
|
||||||
// In C++, I use macros to alleviate this but it's not a solution
|
// In C++, I use macros to alleviate this but it's not a solution
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Entity :: union {
|
Frog :: struct {
|
||||||
Frog{
|
jump_height: f32,
|
||||||
jump_height: f32,
|
colour: u32,
|
||||||
colour: u32,
|
|
||||||
},
|
|
||||||
Giraffe{
|
|
||||||
neck_length: f32,
|
|
||||||
spot_count: int,
|
|
||||||
},
|
|
||||||
Helicopter{
|
|
||||||
blade_count: int,
|
|
||||||
weight: f32,
|
|
||||||
pilot_name: string,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
Giraffe :: struct {
|
||||||
|
neck_length: f32,
|
||||||
|
spot_count: int,
|
||||||
|
}
|
||||||
|
Helicopter :: struct {
|
||||||
|
blade_count: int,
|
||||||
|
weight: f32,
|
||||||
|
pilot_name: string,
|
||||||
|
}
|
||||||
|
Entity :: union {Frog, Giraffe, Helicopter};
|
||||||
|
|
||||||
using Entity;
|
|
||||||
f1: Frog = Frog{12, 0xff9900};
|
f1: Frog = Frog{12, 0xff9900};
|
||||||
f2: Entity = Frog{12, 0xff9900}; // Implicit cast
|
f2: Entity = Frog{12, 0xff9900}; // Implicit cast
|
||||||
f3 := cast(Entity)Frog{12, 0xff9900}; // Explicit cast
|
f3 := cast(Entity)Frog{12, 0xff9900}; // Explicit cast
|
||||||
@@ -703,7 +690,7 @@ tagged_unions :: proc() {
|
|||||||
// Requires a pointer to the union
|
// Requires a pointer to the union
|
||||||
// `x` will be a pointer to type of the case
|
// `x` will be a pointer to type of the case
|
||||||
|
|
||||||
match x in ^f {
|
match x in &f {
|
||||||
case Frog:
|
case Frog:
|
||||||
print("Frog!\n");
|
print("Frog!\n");
|
||||||
print(x.jump_height); nl();
|
print(x.jump_height); nl();
|
||||||
@@ -713,7 +700,7 @@ tagged_unions :: proc() {
|
|||||||
print("Giraffe!\n");
|
print("Giraffe!\n");
|
||||||
case Helicopter:
|
case Helicopter:
|
||||||
print("ROFLCOPTER!\n");
|
print("ROFLCOPTER!\n");
|
||||||
default:
|
case:
|
||||||
print("invalid entity\n");
|
print("invalid entity\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,11 +742,11 @@ tagged_unions :: proc() {
|
|||||||
AstNode :: struct {};
|
AstNode :: struct {};
|
||||||
ExactValue :: struct {};
|
ExactValue :: struct {};
|
||||||
|
|
||||||
EntityKind :: enum {
|
Entity_Kind :: enum {
|
||||||
Invalid,
|
Invalid,
|
||||||
Constant,
|
Constant,
|
||||||
Variable,
|
Variable,
|
||||||
UsingVariable,
|
Using_Variable,
|
||||||
TypeName,
|
TypeName,
|
||||||
Procedure,
|
Procedure,
|
||||||
Builtin,
|
Builtin,
|
||||||
@@ -769,14 +756,14 @@ tagged_unions :: proc() {
|
|||||||
Guid :: i64;
|
Guid :: i64;
|
||||||
Entity :: struct {
|
Entity :: struct {
|
||||||
|
|
||||||
kind: EntityKind,
|
kind: Entity_Kind,
|
||||||
guid: Guid,
|
guid: Guid,
|
||||||
|
|
||||||
scope: ^Scope,
|
scope: ^Scope,
|
||||||
token: Token,
|
token: Token,
|
||||||
type_: ^Type,
|
type_: ^Type,
|
||||||
|
|
||||||
using data: raw_union {
|
using data: struct #raw_union {
|
||||||
Constant: struct {
|
Constant: struct {
|
||||||
value: ExactValue,
|
value: ExactValue,
|
||||||
},
|
},
|
||||||
@@ -786,7 +773,7 @@ tagged_unions :: proc() {
|
|||||||
is_field: bool, // Is struct field
|
is_field: bool, // Is struct field
|
||||||
anonymous: bool, // Variable is an anonymous
|
anonymous: bool, // Variable is an anonymous
|
||||||
},
|
},
|
||||||
UsingVariable: struct {
|
Using_Variable: struct {
|
||||||
},
|
},
|
||||||
TypeName: struct {
|
TypeName: struct {
|
||||||
},
|
},
|
||||||
@@ -813,44 +800,44 @@ tagged_unions :: proc() {
|
|||||||
|
|
||||||
Guid :: i64;
|
Guid :: i64;
|
||||||
Entity_Base :: struct {
|
Entity_Base :: struct {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity :: union {
|
|
||||||
|
Constant :: struct {
|
||||||
|
value: ExactValue,
|
||||||
|
}
|
||||||
|
Variable :: struct {
|
||||||
|
visited: bool, // Cycle detection
|
||||||
|
used: bool, // Variable is used
|
||||||
|
is_field: bool, // Is struct field
|
||||||
|
anonymous: bool, // Variable is an anonymous
|
||||||
|
}
|
||||||
|
Using_Variable :: struct {
|
||||||
|
}
|
||||||
|
TypeName :: struct {
|
||||||
|
}
|
||||||
|
Procedure :: struct {
|
||||||
|
used: bool,
|
||||||
|
}
|
||||||
|
Builtin :: struct {
|
||||||
|
id: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity :: struct {
|
||||||
guid: Guid,
|
guid: Guid,
|
||||||
|
|
||||||
scope: ^Scope,
|
scope: ^Scope,
|
||||||
token: Token,
|
token: Token,
|
||||||
type_: ^Type,
|
type_: ^Type,
|
||||||
|
|
||||||
Constant{
|
variant: union {Constant, Variable, Using_Variable, TypeName, Procedure, Builtin},
|
||||||
value: ExactValue,
|
|
||||||
},
|
|
||||||
Variable{
|
|
||||||
visited: bool, // Cycle detection
|
|
||||||
used: bool, // Variable is used
|
|
||||||
is_field: bool, // Is struct field
|
|
||||||
anonymous: bool, // Variable is an anonymous
|
|
||||||
},
|
|
||||||
UsingVariable{
|
|
||||||
},
|
|
||||||
TypeName{
|
|
||||||
},
|
|
||||||
Procedure{
|
|
||||||
used: bool,
|
|
||||||
},
|
|
||||||
Builtin{
|
|
||||||
id: int,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using Entity;
|
e := Entity{
|
||||||
|
variant = Variable{
|
||||||
e: Entity;
|
used = true,
|
||||||
|
anonymous = false,
|
||||||
e = Variable{
|
},
|
||||||
used = true,
|
|
||||||
anonymous = false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -863,13 +850,13 @@ tagged_unions :: proc() {
|
|||||||
{
|
{
|
||||||
// `Raw` unions still have uses, especially for mathematic types
|
// `Raw` unions still have uses, especially for mathematic types
|
||||||
|
|
||||||
Vector2 :: raw_union {
|
Vector2 :: struct #raw_union {
|
||||||
using xy_: struct { x, y: f32 },
|
using xy_: struct { x, y: f32 },
|
||||||
e: [2]f32,
|
e: [2]f32,
|
||||||
v: [vector 2]f32,
|
v: [vector 2]f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 :: raw_union {
|
Vector3 :: struct #raw_union {
|
||||||
using xyz_: struct { x, y, z: f32 },
|
using xyz_: struct { x, y, z: f32 },
|
||||||
xy: Vector2,
|
xy: Vector2,
|
||||||
e: [3]f32,
|
e: [3]f32,
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
#import "fmt.odin";
|
import "core:fmt.odin";
|
||||||
#import "utf8.odin";
|
import "core:utf8.odin";
|
||||||
#import "hash.odin";
|
import "core:hash.odin";
|
||||||
#import "mem.odin";
|
import "core:mem.odin";
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
{ // New Standard Library stuff
|
{ // New Standard Library stuff
|
||||||
s := "Hello";
|
s := "Hello";
|
||||||
fmt.println(s,
|
fmt.println(s,
|
||||||
utf8.valid_string(s),
|
utf8.valid_string(s),
|
||||||
hash.murmur64(cast([]byte)s));
|
hash.murmur64(cast([]u8)s));
|
||||||
|
|
||||||
// utf8.odin
|
// utf8.odin
|
||||||
// hash.odin
|
// hash.odin
|
||||||
@@ -20,10 +20,10 @@ main :: proc() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
arena: mem.Arena;
|
arena: mem.Arena;
|
||||||
mem.init_arena_from_context(^arena, mem.megabytes(16)); // Uses default allocator
|
mem.init_arena_from_context(&arena, mem.megabytes(16)); // Uses default allocator
|
||||||
defer mem.free_arena(^arena);
|
defer mem.destroy_arena(&arena);
|
||||||
|
|
||||||
push_allocator mem.arena_allocator(^arena) {
|
push_allocator mem.arena_allocator(&arena) {
|
||||||
x := new(int);
|
x := new(int);
|
||||||
x^ = 1337;
|
x^ = 1337;
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ main :: proc() {
|
|||||||
// You can also "push" a context
|
// You can also "push" a context
|
||||||
|
|
||||||
c := context; // Create copy of the allocator
|
c := context; // Create copy of the allocator
|
||||||
c.allocator = mem.arena_allocator(^arena);
|
c.allocator = mem.arena_allocator(&arena);
|
||||||
|
|
||||||
push_context c {
|
push_context c {
|
||||||
x := new(int);
|
x := new(int);
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
#import "fmt.odin";
|
import "core:fmt.odin";
|
||||||
#import "utf8.odin";
|
import "core:utf8.odin";
|
||||||
// #import "atomic.odin";
|
// import "core:atomic.odin";
|
||||||
// #import "hash.odin";
|
// import "core:hash.odin";
|
||||||
// #import "math.odin";
|
// import "core:math.odin";
|
||||||
// #import "mem.odin";
|
// import "core:mem.odin";
|
||||||
// #import "opengl.odin";
|
// import "core:opengl.odin";
|
||||||
// #import "os.odin";
|
// import "core:os.odin";
|
||||||
// #import "sync.odin";
|
// import "core:sync.odin";
|
||||||
// #import win32 "sys/windows.odin";
|
// import win32 "core:sys/windows.odin";
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
// syntax();
|
// syntax();
|
||||||
@@ -43,7 +43,7 @@ syntax :: proc() {
|
|||||||
Thing2 :: struct {x: f32, y: int, z: ^[]int};
|
Thing2 :: struct {x: f32, y: int, z: ^[]int};
|
||||||
|
|
||||||
// Slice interals are now just a `ptr+len+cap`
|
// Slice interals are now just a `ptr+len+cap`
|
||||||
slice: []int; compile_assert(size_of_val(slice) == 3*size_of(int));
|
slice: []int; compile_assert(size_of(slice) == 3*size_of(int));
|
||||||
|
|
||||||
// Helper type - Help the reader understand what it is quicker
|
// Helper type - Help the reader understand what it is quicker
|
||||||
My_Int :: #type int;
|
My_Int :: #type int;
|
||||||
@@ -90,22 +90,17 @@ Prefix_Type :: struct {x: int, y: f32, z: rawptr};
|
|||||||
|
|
||||||
prefixes :: proc() {
|
prefixes :: proc() {
|
||||||
using var: Prefix_Type;
|
using var: Prefix_Type;
|
||||||
immutable const := Prefix_Type{1, 2, nil};
|
|
||||||
var.x = 123;
|
var.x = 123;
|
||||||
x = 123;
|
x = 123;
|
||||||
// const.x = 123; // const is immutable
|
|
||||||
|
|
||||||
|
|
||||||
|
foo :: proc(using pt: Prefix_Type) {
|
||||||
foo :: proc(using immutable pt: Prefix_Type, immutable int_ptr: ^int) {
|
|
||||||
// int_ptr = nil; // Not valid
|
|
||||||
// int_ptr^ = 123; // Not valid
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Same as C99's `restrict`
|
// Same as C99's `restrict`
|
||||||
bar :: proc(no_alias a, b: ^int) {
|
bar :: proc(#no_alias a, b: ^int) {
|
||||||
// Assumes a never equals b so it can perform optimizations with that fact
|
// Assumes a never equals b so it can perform optimizations with that fact
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,14 +133,18 @@ when_statements :: proc() {
|
|||||||
foreign_procedures();
|
foreign_procedures();
|
||||||
}
|
}
|
||||||
|
|
||||||
#foreign_system_library win32_user "user32.lib" when ODIN_OS == "windows";
|
when ODIN_OS == "windows" {
|
||||||
|
foreign_system_library win32_user "user32.lib";
|
||||||
|
}
|
||||||
// NOTE: This is done on purpose for two reasons:
|
// NOTE: This is done on purpose for two reasons:
|
||||||
// * Makes it clear where the platform specific stuff is
|
// * Makes it clear where the platform specific stuff is
|
||||||
// * Removes the need to solve the travelling salesman problem when importing files :P
|
// * Removes the need to solve the travelling salesman problem when importing files :P
|
||||||
|
|
||||||
foreign_procedures :: proc() {
|
foreign_procedures :: proc() {
|
||||||
ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user;
|
foreign win32_user {
|
||||||
show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user "ShowWindow";
|
ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 ---;
|
||||||
|
show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #link_name "ShowWindow" ---;
|
||||||
|
}
|
||||||
// NOTE: If that library doesn't get used, it doesn't get linked with
|
// NOTE: If that library doesn't get used, it doesn't get linked with
|
||||||
// NOTE: There is not link checking yet to see if that procedure does come from that library
|
// NOTE: There is not link checking yet to see if that procedure does come from that library
|
||||||
|
|
||||||
@@ -203,14 +202,14 @@ loops :: proc() {
|
|||||||
fmt.println(val, idx);
|
fmt.println(val, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
primes := [..]int{2, 3, 5, 7, 11, 13, 17, 19};
|
primes := [...]int{2, 3, 5, 7, 11, 13, 17, 19};
|
||||||
|
|
||||||
for p in primes {
|
for p in primes {
|
||||||
fmt.println(p);
|
fmt.println(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pointers to arrays, slices, or strings are allowed
|
// Pointers to arrays, slices, or strings are allowed
|
||||||
for _ in ^primes {
|
for _ in &primes {
|
||||||
// ignore the value and just iterate across it
|
// ignore the value and just iterate across it
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +218,7 @@ loops :: proc() {
|
|||||||
name := "你好,世界";
|
name := "你好,世界";
|
||||||
fmt.println(name);
|
fmt.println(name);
|
||||||
for r in name {
|
for r in name {
|
||||||
compile_assert(type_of_val(r) == rune);
|
compile_assert(type_of(r) == rune);
|
||||||
fmt.printf("%r\n", r);
|
fmt.printf("%r\n", r);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,8 +269,8 @@ procedure_overloading :: proc() {
|
|||||||
a: i32 = 123;
|
a: i32 = 123;
|
||||||
b: f32;
|
b: f32;
|
||||||
c: rawptr;
|
c: rawptr;
|
||||||
fmt.println(foo(^a));
|
fmt.println(foo(&a));
|
||||||
foo(^b);
|
foo(&b);
|
||||||
foo(c);
|
foo(c);
|
||||||
// foo(nil); // nil could go to numerous types thus the ambiguity
|
// foo(nil); // nil could go to numerous types thus the ambiguity
|
||||||
|
|
||||||
@@ -0,0 +1,310 @@
|
|||||||
|
// import "core:atomic.odin";
|
||||||
|
import "core:hash.odin";
|
||||||
|
import "core:mem.odin";
|
||||||
|
import "core:opengl.odin";
|
||||||
|
import "core:strconv.odin";
|
||||||
|
import "core:sync.odin";
|
||||||
|
import win32 "core:sys/windows.odin";
|
||||||
|
|
||||||
|
import "core:fmt.odin";
|
||||||
|
import "core:os.odin";
|
||||||
|
import "core:math.odin";
|
||||||
|
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
when true {
|
||||||
|
/*
|
||||||
|
Added:
|
||||||
|
* Unexported entities and fields using an underscore prefix
|
||||||
|
- See `sync.odin` and explain
|
||||||
|
|
||||||
|
Removed:
|
||||||
|
* Maybe/option types
|
||||||
|
* Remove `type` keyword and other "reserved" keywords
|
||||||
|
* ..< and ... removed and replace with .. (half-closed range)
|
||||||
|
|
||||||
|
Changed:
|
||||||
|
* `compile_assert` and `assert` return the value of the condition for semantic reasons
|
||||||
|
* thread_local -> #thread_local
|
||||||
|
* #include -> #load
|
||||||
|
* Files only get checked if they are actually used
|
||||||
|
* match x in y {} // For type match statements
|
||||||
|
* Version numbering now starts from 0.1.0 and uses the convention:
|
||||||
|
- major.minor.patch
|
||||||
|
* Core library additions to Windows specific stuff
|
||||||
|
*/
|
||||||
|
|
||||||
|
{
|
||||||
|
Fruit :: enum {
|
||||||
|
APPLE,
|
||||||
|
BANANA,
|
||||||
|
COCONUT,
|
||||||
|
}
|
||||||
|
fmt.println(Fruit.names);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
A :: struct {x, y: f32};
|
||||||
|
B :: struct #align 16 {x, y: f32};
|
||||||
|
fmt.println("align_of(A) =", align_of(A));
|
||||||
|
fmt.println("align_of(B) =", align_of(B));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Removal of ..< and ...
|
||||||
|
for i in 0..16 {
|
||||||
|
}
|
||||||
|
// Is similar to
|
||||||
|
for i := 0; i < 16; i += 1 {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
thing: for i in 0..10 {
|
||||||
|
for j in i+1..10 {
|
||||||
|
if j == 2 {
|
||||||
|
fmt.println(i, j);
|
||||||
|
continue thing;
|
||||||
|
}
|
||||||
|
if j == 3 {
|
||||||
|
break thing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Works with, `for`, `for in`, `match`, `match in`
|
||||||
|
// NOTE(bill): This solves most of the problems I need `goto` for
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
t := type_info_of(int);
|
||||||
|
match i in t.variant {
|
||||||
|
case Type_Info_Integer, Type_Info_Float:
|
||||||
|
fmt.println("It's a number");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
x: any = 123;
|
||||||
|
foo: match i in x {
|
||||||
|
case int, f32:
|
||||||
|
fmt.println("It's an int or f32");
|
||||||
|
break foo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
cond := true;
|
||||||
|
x: int;
|
||||||
|
if cond {
|
||||||
|
x = 3;
|
||||||
|
} else {
|
||||||
|
x = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Ternary operator
|
||||||
|
y := cond ? 3 : 4;
|
||||||
|
|
||||||
|
FOO :: true ? 123 : 432; // Constant ternary expression
|
||||||
|
fmt.println("Ternary values:", y, FOO);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Slices now store a capacity
|
||||||
|
buf: [256]u8;
|
||||||
|
s: []u8;
|
||||||
|
s = buf[..0]; // == buf[0..0];
|
||||||
|
fmt.println("count =", len(s));
|
||||||
|
fmt.println("capacity =", cap(s));
|
||||||
|
append(&s, 1, 2, 3);
|
||||||
|
fmt.println(s);
|
||||||
|
|
||||||
|
s = buf[1..2..3];
|
||||||
|
fmt.println("count =", len(s));
|
||||||
|
fmt.println("capacity =", cap(s));
|
||||||
|
fmt.println(s);
|
||||||
|
|
||||||
|
clear(&s); // Sets count to zero
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Foo :: struct {
|
||||||
|
x, y, z: f32,
|
||||||
|
ok: bool,
|
||||||
|
flags: u32,
|
||||||
|
}
|
||||||
|
foo_array: [256]Foo;
|
||||||
|
foo_as_bytes: []u8 = mem.slice_to_bytes(foo_array[..]);
|
||||||
|
// Useful for things like
|
||||||
|
// os.write(handle, foo_as_bytes);
|
||||||
|
|
||||||
|
foo_slice := mem.slice_ptr(cast(^Foo)&foo_as_bytes[0], len(foo_as_bytes)/size_of(Foo), cap(foo_as_bytes)/size_of(Foo));
|
||||||
|
// Question: Should there be a bytes_to_slice procedure or is it clearer to do this even if it is error prone?
|
||||||
|
// And if so what would the syntax be?
|
||||||
|
// slice_transmute([]Foo, foo_as_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Vec3 :: [vector 3]f32;
|
||||||
|
|
||||||
|
x := Vec3{1, 2, 3};
|
||||||
|
y := Vec3{4, 5, 6};
|
||||||
|
fmt.println(x < y);
|
||||||
|
fmt.println(x + y);
|
||||||
|
fmt.println(x - y);
|
||||||
|
fmt.println(x * y);
|
||||||
|
fmt.println(x / y);
|
||||||
|
|
||||||
|
for i in x {
|
||||||
|
fmt.println(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
compile_assert(size_of([vector 7]bool) >= size_of([7]bool));
|
||||||
|
compile_assert(size_of([vector 7]i32) >= size_of([7]i32));
|
||||||
|
// align_of([vector 7]i32) != align_of([7]i32) // this may be the case
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// fmt.* changes
|
||||||
|
// bprint* returns `string`
|
||||||
|
|
||||||
|
data: [256]u8;
|
||||||
|
str := fmt.bprintf(data[..], "Hellope %d %s %c", 123, "others", '!');
|
||||||
|
fmt.println(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
x: [dynamic]f64;
|
||||||
|
reserve(&x, 16);
|
||||||
|
defer free(x); // `free` is overloaded for numerous types
|
||||||
|
// Number literals can have underscores in them for readability
|
||||||
|
append(&x, 2_000_000.500_000, 123, 5, 7); // variadic append
|
||||||
|
|
||||||
|
for p, i in x {
|
||||||
|
if i > 0 { fmt.print(", "); }
|
||||||
|
fmt.print(p);
|
||||||
|
}
|
||||||
|
fmt.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Dynamic array "literals"
|
||||||
|
x := [dynamic]f64{2_000_000.500_000, 3, 5, 7};
|
||||||
|
defer free(x);
|
||||||
|
fmt.println(x); // fmt.print* supports printing of dynamic types
|
||||||
|
clear(&x);
|
||||||
|
fmt.println(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
m: map[f32]int;
|
||||||
|
reserve(&m, 16);
|
||||||
|
defer free(m);
|
||||||
|
|
||||||
|
m[1.0] = 1278;
|
||||||
|
m[2.0] = 7643;
|
||||||
|
m[3.0] = 564;
|
||||||
|
_, ok := m[3.0];
|
||||||
|
c := m[3.0];
|
||||||
|
assert(ok && c == 564);
|
||||||
|
|
||||||
|
fmt.print("map[");
|
||||||
|
i := 0;
|
||||||
|
for val, key in m {
|
||||||
|
if i > 0 {
|
||||||
|
fmt.print(", ");
|
||||||
|
}
|
||||||
|
fmt.printf("%v=%v", key, val);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
fmt.println("]");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
m := map[string]u32{
|
||||||
|
"a" = 56,
|
||||||
|
"b" = 13453,
|
||||||
|
"c" = 7654,
|
||||||
|
};
|
||||||
|
defer free(m);
|
||||||
|
|
||||||
|
c := m["c"];
|
||||||
|
_, ok := m["c"];
|
||||||
|
assert(ok && c == 7654);
|
||||||
|
fmt.println(m);
|
||||||
|
|
||||||
|
delete(&m, "c"); // deletes entry with key "c"
|
||||||
|
_, found := m["c"];
|
||||||
|
assert(!found);
|
||||||
|
|
||||||
|
fmt.println(m);
|
||||||
|
clear(&m);
|
||||||
|
fmt.println(m);
|
||||||
|
|
||||||
|
// NOTE: Fixed size maps are planned but we have not yet implemented
|
||||||
|
// them as we have had no need for them as of yet
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Vector3 :: struct{x, y, z: f32};
|
||||||
|
Quaternion :: struct{x, y, z, w: f32};
|
||||||
|
|
||||||
|
// Variants
|
||||||
|
Frog :: struct {
|
||||||
|
ribbit_volume: f32,
|
||||||
|
jump_height: f32,
|
||||||
|
}
|
||||||
|
Door :: struct {
|
||||||
|
openness: f32,
|
||||||
|
}
|
||||||
|
Map :: struct {
|
||||||
|
width, height: f32,
|
||||||
|
place_positions: []Vector3,
|
||||||
|
place_names: []string,
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity :: struct {
|
||||||
|
// Common Fields
|
||||||
|
id: u64,
|
||||||
|
name: string,
|
||||||
|
using position: Vector3,
|
||||||
|
orientation: Quaternion,
|
||||||
|
flags: u32,
|
||||||
|
|
||||||
|
variant: union { Frog, Door, Map },
|
||||||
|
}
|
||||||
|
|
||||||
|
entity: Entity;
|
||||||
|
entity.id = 1337;
|
||||||
|
// implicit conversion from variant to base type
|
||||||
|
entity.variant = Frog{
|
||||||
|
ribbit_volume = 0.5,
|
||||||
|
jump_height = 2.1,
|
||||||
|
/*other data */
|
||||||
|
};
|
||||||
|
|
||||||
|
entity.name = "Frank";
|
||||||
|
entity.position = Vector3{1, 4, 9};
|
||||||
|
|
||||||
|
match e in entity.variant {
|
||||||
|
case Frog:
|
||||||
|
fmt.println("Ribbit");
|
||||||
|
case Door:
|
||||||
|
fmt.println("Creak");
|
||||||
|
case Map:
|
||||||
|
fmt.println("Rustle");
|
||||||
|
case:
|
||||||
|
fmt.println("Just a normal entity");
|
||||||
|
}
|
||||||
|
|
||||||
|
if frog, ok := entity.variant.(Frog); ok {
|
||||||
|
fmt.printf("The frog jumps %f feet high at %v\n", frog.jump_height, entity.position);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panics if not the correct type
|
||||||
|
frog: Frog;
|
||||||
|
frog = entity.variant.(Frog);
|
||||||
|
frog, _ = entity.variant.(Frog); // ignore error and force cast
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,35 +1,30 @@
|
|||||||
import (
|
import win32 "core:sys/windows.odin";
|
||||||
win32 "sys/windows.odin";
|
import "core:fmt.odin";
|
||||||
"fmt.odin";
|
import "core:os.odin";
|
||||||
"os.odin";
|
import "core:mem.odin";
|
||||||
"mem.odin";
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
CANVAS_WIDTH = 128;
|
|
||||||
CANVAS_HEIGHT = 128;
|
|
||||||
CANVAS_SCALE = 3;
|
|
||||||
FRAME_TIME = 1.0/30.0;
|
|
||||||
WINDOW_TITLE = "Punity\x00";
|
|
||||||
)
|
|
||||||
|
|
||||||
const _ = compile_assert(CANVAS_WIDTH % 16 == 0);
|
CANVAS_WIDTH :: 128;
|
||||||
|
CANVAS_HEIGHT :: 128;
|
||||||
|
CANVAS_SCALE :: 3;
|
||||||
|
FRAME_TIME :: 1.0/30.0;
|
||||||
|
WINDOW_TITLE :: "Punity\x00";
|
||||||
|
|
||||||
const (
|
_ :: compile_assert(CANVAS_WIDTH % 16 == 0);
|
||||||
WINDOW_WIDTH = CANVAS_WIDTH * CANVAS_SCALE;
|
|
||||||
WINDOW_HEIGHT = CANVAS_HEIGHT * CANVAS_SCALE;
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
STACK_CAPACITY = 1<<20;
|
|
||||||
STORAGE_CAPACITY = 1<<20;
|
|
||||||
|
|
||||||
DRAW_LIST_RESERVE = 128;
|
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE;
|
||||||
|
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE;
|
||||||
|
|
||||||
MAX_KEYS = 256;
|
|
||||||
)
|
|
||||||
|
|
||||||
type Core struct {
|
STACK_CAPACITY :: 1<<20;
|
||||||
|
STORAGE_CAPACITY :: 1<<20;
|
||||||
|
|
||||||
|
DRAW_LIST_RESERVE :: 128;
|
||||||
|
|
||||||
|
MAX_KEYS :: 256;
|
||||||
|
|
||||||
|
Core :: struct {
|
||||||
stack: ^Bank,
|
stack: ^Bank,
|
||||||
storage: ^Bank,
|
storage: ^Bank,
|
||||||
|
|
||||||
@@ -52,52 +47,52 @@ type Core struct {
|
|||||||
draw_list: ^Draw_List,
|
draw_list: ^Draw_List,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Perf_Span struct {
|
Perf_Span :: struct {
|
||||||
stamp: f64,
|
stamp: f64,
|
||||||
delta: f32,
|
delta: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Bank struct {
|
Bank :: struct {
|
||||||
memory: []u8,
|
memory: []u8,
|
||||||
cursor: int,
|
cursor: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Bank_State struct {
|
Bank_State :: struct {
|
||||||
state: Bank,
|
state: Bank,
|
||||||
bank: ^Bank,
|
bank: ^Bank,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Color raw_union {
|
Color :: struct #raw_union {
|
||||||
using channels: struct{a, b, g, r: u8},
|
using channels: struct{a, b, g, r: u8},
|
||||||
rgba: u32,
|
rgba: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Palette struct {
|
Palette :: struct {
|
||||||
colors: [256]Color,
|
colors: [256]Color,
|
||||||
colors_count: u8,
|
colors_count: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Rect raw_union {
|
Rect :: struct #raw_union {
|
||||||
using minmax: struct {min_x, min_y, max_x, max_y: int},
|
using minmax: struct {min_x, min_y, max_x, max_y: int},
|
||||||
using pos: struct {left, top, right, bottom: int},
|
using pos: struct {left, top, right, bottom: int},
|
||||||
e: [4]int,
|
e: [4]int,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Bitmap struct {
|
Bitmap :: struct {
|
||||||
pixels: []u8,
|
pixels: []u8,
|
||||||
width: int,
|
width: int,
|
||||||
height: int,
|
height: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Font struct {
|
Font :: struct {
|
||||||
using bitmap: Bitmap,
|
using bitmap: Bitmap,
|
||||||
char_width: int,
|
char_width: int,
|
||||||
char_height: int,
|
char_height: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Canvas struct {
|
Canvas :: struct {
|
||||||
using bitmap: ^Bitmap,
|
using bitmap: ^Bitmap,
|
||||||
palette: Palette,
|
palette: Palette,
|
||||||
translate_x: int,
|
translate_x: int,
|
||||||
@@ -106,23 +101,23 @@ type Canvas struct {
|
|||||||
font: ^Font,
|
font: ^Font,
|
||||||
}
|
}
|
||||||
|
|
||||||
type DrawFlag enum {
|
DrawFlag :: enum {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
FLIP_H = 1<<0,
|
FLIP_H = 1<<0,
|
||||||
FLIP_V = 1<<1,
|
FLIP_V = 1<<1,
|
||||||
MASK = 1<<2,
|
MASK = 1<<2,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Draw_Item struct {}
|
Draw_Item :: struct {}
|
||||||
type Draw_List struct {
|
Draw_List :: struct {
|
||||||
items: []Draw_Item,
|
items: []Draw_Item,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Key enum {
|
Key :: enum {
|
||||||
ModShift = 0x0001,
|
Mod_Shift = 0x0001,
|
||||||
ModControl = 0x0002,
|
Mod_Control = 0x0002,
|
||||||
ModAlt = 0x0004,
|
Mod_Alt = 0x0004,
|
||||||
ModSuper = 0x0008,
|
Mod_Super = 0x0008,
|
||||||
|
|
||||||
|
|
||||||
Unknown =-1,
|
Unknown =-1,
|
||||||
@@ -153,9 +148,9 @@ type Key enum {
|
|||||||
Kanji = 0x19,
|
Kanji = 0x19,
|
||||||
Escape = 0x1B,
|
Escape = 0x1B,
|
||||||
Convert = 0x1C,
|
Convert = 0x1C,
|
||||||
NonConvert = 0x1D,
|
Non_Convert = 0x1D,
|
||||||
Accept = 0x1E,
|
Accept = 0x1E,
|
||||||
ModeChange = 0x1F,
|
Mode_Change = 0x1F,
|
||||||
Space = 32,
|
Space = 32,
|
||||||
Prior = 33,
|
Prior = 33,
|
||||||
Next = 34,
|
Next = 34,
|
||||||
@@ -269,56 +264,49 @@ type Key enum {
|
|||||||
X = 88,
|
X = 88,
|
||||||
Y = 89,
|
Y = 89,
|
||||||
Z = 90,
|
Z = 90,
|
||||||
LeftBracket = 91, /* [ */
|
Left_Bracket = 91, /* [ */
|
||||||
Backslash = 92, /* \ */
|
Backslash = 92, /* \ */
|
||||||
RightBracket = 93, /* ] */
|
Right_Bracket = 93, /* ] */
|
||||||
GraveAccent = 96, /* ` */
|
Grave_Accent = 96, /* ` */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
proc key_down(k: Key) -> bool {
|
key_down :: proc(k: Key) -> bool {
|
||||||
return _core.key_states[k] != 0;
|
return _core.key_states[k] != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
proc key_pressed(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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let win32_perf_count_freq = win32.get_query_performance_frequency();
|
win32_perf_count_freq := win32.get_query_performance_frequency();
|
||||||
proc time_now() -> f64 {
|
time_now :: proc() -> f64 {
|
||||||
assert(win32_perf_count_freq != 0);
|
assert(win32_perf_count_freq != 0);
|
||||||
|
|
||||||
var counter: i64;
|
counter: i64;
|
||||||
win32.query_performance_counter(&counter);
|
win32.query_performance_counter(&counter);
|
||||||
return f64(counter) / f64(win32_perf_count_freq);
|
return f64(counter) / f64(win32_perf_count_freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
var _core: Core;
|
_core: Core;
|
||||||
|
|
||||||
proc run(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;
|
||||||
|
|
||||||
proc win32_proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline #cc_c {
|
win32_proc :: proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline #cc_c {
|
||||||
proc win32_app_key_mods() -> u32 {
|
win32_app_key_mods :: proc() -> u32 {
|
||||||
var mods: u32 = 0;
|
mods: u32 = 0;
|
||||||
|
|
||||||
if is_key_down(KeyCode.Shift) {
|
if is_key_down(Key_Code.Shift) do mods |= u32(Key.Mod_Shift);
|
||||||
mods |= u32(Key.ModShift);
|
if is_key_down(Key_Code.Control) do mods |= u32(Key.Mod_Control);
|
||||||
}
|
if is_key_down(Key_Code.Menu) do mods |= u32(Key.Mod_Alt);
|
||||||
if is_key_down(KeyCode.Control) {
|
if is_key_down(Key_Code.Lwin) do mods |= u32(Key.Mod_Super);
|
||||||
mods |= u32(Key.ModControl);
|
if is_key_down(Key_Code.Rwin) do mods |= u32(Key.Mod_Super);
|
||||||
}
|
|
||||||
if is_key_down(KeyCode.Menu) {
|
|
||||||
mods |= u32(Key.ModAlt);
|
|
||||||
}
|
|
||||||
if is_key_down(KeyCode.Lwin) || is_key_down(KeyCode.Rwin) {
|
|
||||||
mods |= u32(Key.ModSuper);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mods;
|
return mods;
|
||||||
}
|
}
|
||||||
@@ -350,14 +338,13 @@ proc run(user_init, user_step: proc(c: ^Core)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var class_name = "Punity\x00";
|
class_name := "Punity\x00";
|
||||||
var window_class = WndClassExA{
|
window_class := Wnd_Class_Ex_A{
|
||||||
class_name = &class_name[0],
|
class_name = &class_name[0],
|
||||||
size = size_of(WndClassExA),
|
size = size_of(Wnd_Class_Ex_A),
|
||||||
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
||||||
instance = Hinstance(get_module_handle_a(nil)),
|
instance = Hinstance(get_module_handle_a(nil)),
|
||||||
wnd_proc = win32_proc,
|
wnd_proc = win32_proc,
|
||||||
// wnd_proc = DefWindowProcA,
|
|
||||||
background = Hbrush(get_stock_object(BLACK_BRUSH)),
|
background = Hbrush(get_stock_object(BLACK_BRUSH)),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -366,28 +353,28 @@ proc run(user_init, user_step: proc(c: ^Core)) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var screen_width = get_system_metrics(SM_CXSCREEN);
|
screen_width := get_system_metrics(SM_CXSCREEN);
|
||||||
var screen_height = get_system_metrics(SM_CYSCREEN);
|
screen_height := get_system_metrics(SM_CYSCREEN);
|
||||||
|
|
||||||
var rc: Rect;
|
rc: Rect;
|
||||||
rc.left = (screen_width - WINDOW_WIDTH) / 2;
|
rc.left = (screen_width - WINDOW_WIDTH) / 2;
|
||||||
rc.top = (screen_height - WINDOW_HEIGHT) / 2;
|
rc.top = (screen_height - WINDOW_HEIGHT) / 2;
|
||||||
rc.right = rc.left + WINDOW_WIDTH;
|
rc.right = rc.left + WINDOW_WIDTH;
|
||||||
rc.bottom = rc.top + WINDOW_HEIGHT;
|
rc.bottom = rc.top + WINDOW_HEIGHT;
|
||||||
|
|
||||||
var style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
|
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
|
||||||
assert(adjust_window_rect(&rc, style, 0) != 0);
|
assert(adjust_window_rect(&rc, style, 0) != 0);
|
||||||
|
|
||||||
var wt = WINDOW_TITLE;
|
wt := WINDOW_TITLE;
|
||||||
|
|
||||||
var win32_window = create_window_ex_a(0,
|
win32_window := create_window_ex_a(0,
|
||||||
window_class.class_name,
|
window_class.class_name,
|
||||||
&wt[0],
|
&wt[0],
|
||||||
style,
|
style,
|
||||||
rc.left, rc.top,
|
rc.left, rc.top,
|
||||||
rc.right-rc.left, rc.bottom-rc.top,
|
rc.right-rc.left, rc.bottom-rc.top,
|
||||||
nil, nil, window_class.instance,
|
nil, nil, window_class.instance,
|
||||||
nil);
|
nil);
|
||||||
|
|
||||||
if win32_window == nil {
|
if win32_window == nil {
|
||||||
fmt.fprintln(os.stderr, "create_window_ex_a failed");
|
fmt.fprintln(os.stderr, "create_window_ex_a failed");
|
||||||
@@ -395,8 +382,8 @@ proc run(user_init, user_step: proc(c: ^Core)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var window_bmi: BitmapInfo;
|
window_bmi: Bitmap_Info;
|
||||||
window_bmi.size = size_of(BitmapInfoHeader);
|
window_bmi.size = size_of(Bitmap_Info_Header);
|
||||||
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;
|
||||||
@@ -408,23 +395,19 @@ proc run(user_init, user_step: proc(c: ^Core)) {
|
|||||||
|
|
||||||
show_window(win32_window, SW_SHOW);
|
show_window(win32_window, SW_SHOW);
|
||||||
|
|
||||||
var window_buffer = make([]u32, CANVAS_WIDTH * CANVAS_HEIGHT);
|
window_buffer := make([]u32, CANVAS_WIDTH * CANVAS_HEIGHT);
|
||||||
defer free(window_buffer);
|
defer free(window_buffer);
|
||||||
|
|
||||||
for _, i in window_buffer {
|
for _, i in window_buffer do window_buffer[i] = 0xff00ff;
|
||||||
window_buffer[i] = 0xff00ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
dt: f64;
|
||||||
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;
|
|
||||||
)
|
|
||||||
|
|
||||||
var 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;
|
||||||
@@ -435,16 +418,16 @@ proc run(user_init, user_step: proc(c: ^Core)) {
|
|||||||
offset_y += 2;
|
offset_y += 2;
|
||||||
|
|
||||||
{
|
{
|
||||||
var buf: [128]u8;
|
buf: [128]u8;
|
||||||
var s = fmt.bprintf(buf[..], "Punity: %.4f ms\x00", dt*1000);
|
s := fmt.bprintf(buf[..], "Punity: %.4f ms\x00", dt*1000);
|
||||||
win32.set_window_text_a(win32_window, &s[0]);
|
win32.set_window_text_a(win32_window, &s[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for var y = 0; y < CANVAS_HEIGHT; y++ {
|
for y in 0..CANVAS_HEIGHT {
|
||||||
for var x = 0; x < CANVAS_WIDTH; x++ {
|
for x in 0..CANVAS_WIDTH {
|
||||||
var g = (x % 32) * 8;
|
g := (x % 32) * 8;
|
||||||
var b = (y % 32) * 8;
|
b := (y % 32) * 8;
|
||||||
window_buffer[x + y*CANVAS_WIDTH] = u32(g << 8 | b);
|
window_buffer[x + y*CANVAS_WIDTH] = u32(g << 8 | b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -461,7 +444,7 @@ proc run(user_init, user_step: proc(c: ^Core)) {
|
|||||||
|
|
||||||
user_step(&_core);
|
user_step(&_core);
|
||||||
|
|
||||||
var dc = get_dc(win32_window);
|
dc := get_dc(win32_window);
|
||||||
stretch_dibits(dc,
|
stretch_dibits(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,
|
||||||
@@ -472,25 +455,23 @@ proc run(user_init, user_step: proc(c: ^Core)) {
|
|||||||
release_dc(win32_window, dc);
|
release_dc(win32_window, dc);
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
var delta = time_now() - prev_time;
|
delta := time_now() - prev_time;
|
||||||
var ms = i32((FRAME_TIME - delta) * 1000);
|
if ms := i32((FRAME_TIME - delta) * 1000); ms > 0 {
|
||||||
if ms > 0 {
|
win32.sleep(ms);
|
||||||
win32.sleep(ms);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_core.frame++;
|
_core.frame += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
proc main() {
|
main :: proc() {
|
||||||
proc user_init(c: ^Core) {
|
user_init :: proc(c: ^Core) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
proc user_step(c: ^Core) {
|
user_step :: proc(c: ^Core) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
@echo off
|
@echo off
|
||||||
|
|
||||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
|
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
|
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
|
||||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
|
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
|
||||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
|
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
|
||||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
|
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
|
||||||
set _NO_DEBUG_HEAP=1
|
set _NO_DEBUG_HEAP=1
|
||||||
|
|||||||
+46
-22
@@ -12,6 +12,8 @@ struct BuildContext {
|
|||||||
i64 word_size; // Size of a pointer, must be >= 4
|
i64 word_size; // Size of a pointer, must be >= 4
|
||||||
i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
|
i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
|
||||||
|
|
||||||
|
String command;
|
||||||
|
|
||||||
String opt_flags;
|
String opt_flags;
|
||||||
String llc_flags;
|
String llc_flags;
|
||||||
String link_flags;
|
String link_flags;
|
||||||
@@ -29,7 +31,28 @@ struct BuildContext {
|
|||||||
gb_global BuildContext build_context = {0};
|
gb_global BuildContext build_context = {0};
|
||||||
|
|
||||||
|
|
||||||
|
struct LibraryCollections {
|
||||||
|
String name;
|
||||||
|
String path;
|
||||||
|
};
|
||||||
|
|
||||||
|
gb_global Array<LibraryCollections> library_collections = {0};
|
||||||
|
|
||||||
|
void add_library_collection(String name, String path) {
|
||||||
|
// TODO(bill): Check the path is valid and a directory
|
||||||
|
LibraryCollections lc = {name, string_trim_whitespace(path)};
|
||||||
|
array_add(&library_collections, lc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool find_library_collection_path(String name, String *path) {
|
||||||
|
for_array(i, library_collections) {
|
||||||
|
if (library_collections[i].name == name) {
|
||||||
|
if (path) *path = library_collections[i].path;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO(bill): OS dependent versions for the BuildContext
|
// TODO(bill): OS dependent versions for the BuildContext
|
||||||
@@ -248,42 +271,43 @@ String path_to_fullpath(gbAllocator a, String s) {
|
|||||||
|
|
||||||
|
|
||||||
String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
|
String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
|
||||||
String res = {0};
|
u8 *str = gb_alloc_array(heap_allocator(), u8, base_dir.len+1+path.len+1);
|
||||||
isize str_len = base_dir.len+path.len;
|
defer (gb_free(heap_allocator(), str));
|
||||||
|
|
||||||
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
|
|
||||||
|
|
||||||
isize i = 0;
|
isize i = 0;
|
||||||
gb_memmove(str+i, &base_dir[0], base_dir.len); i += base_dir.len;
|
gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len;
|
||||||
gb_memmove(str+i, &path[0], path.len);
|
gb_memmove(str+i, "/", 1); i += 1;
|
||||||
str[str_len] = '\0';
|
gb_memmove(str+i, path.text, path.len); i += path.len;
|
||||||
res = path_to_fullpath(a, make_string(str, str_len));
|
str[i] = 0;
|
||||||
gb_free(heap_allocator(), str);
|
|
||||||
return res;
|
String res = make_string(str, i);
|
||||||
|
res = string_trim_whitespace(res);
|
||||||
|
return path_to_fullpath(a, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String get_fullpath_core(gbAllocator a, String path) {
|
String get_fullpath_core(gbAllocator a, String path) {
|
||||||
String module_dir = odin_root_dir();
|
String module_dir = odin_root_dir();
|
||||||
String res = {0};
|
|
||||||
|
|
||||||
char core[] = "core/";
|
String core = str_lit("core/");
|
||||||
isize core_len = gb_size_of(core)-1;
|
|
||||||
|
|
||||||
isize str_len = module_dir.len + core_len + path.len;
|
isize str_len = module_dir.len + core.len + path.len;
|
||||||
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
|
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
|
||||||
|
defer (gb_free(heap_allocator(), str));
|
||||||
|
|
||||||
gb_memmove(str, &module_dir[0], module_dir.len);
|
isize i = 0;
|
||||||
gb_memmove(str+module_dir.len, core, core_len);
|
gb_memmove(str+i, module_dir.text, module_dir.len); i += module_dir.len;
|
||||||
gb_memmove(str+module_dir.len+core_len, &path[0], path.len);
|
gb_memmove(str+i, core.text, core.len); i += core.len;
|
||||||
str[str_len] = '\0';
|
gb_memmove(str+i, path.text, path.len); i += path.len;
|
||||||
|
str[i] = 0;
|
||||||
|
|
||||||
res = path_to_fullpath(a, make_string(str, str_len));
|
String res = make_string(str, i);
|
||||||
gb_free(heap_allocator(), str);
|
res = string_trim_whitespace(res);
|
||||||
return res;
|
return path_to_fullpath(a, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String const ODIN_VERSION = str_lit("0.6.2");
|
String const ODIN_VERSION = str_lit("0.7.1");
|
||||||
|
|
||||||
void init_build_context(void) {
|
void init_build_context(void) {
|
||||||
BuildContext *bc = &build_context;
|
BuildContext *bc = &build_context;
|
||||||
|
|||||||
+158
-82
@@ -1,7 +1,7 @@
|
|||||||
bool check_is_terminating(AstNode *node);
|
bool check_is_terminating(AstNode *node);
|
||||||
void check_stmt (Checker *c, AstNode *node, u32 flags);
|
void check_stmt (Checker *c, AstNode *node, u32 flags);
|
||||||
|
|
||||||
// NOTE(bill): `content_name` is for debugging and error messages
|
// NOTE(bill): 'content_name' is for debugging and error messages
|
||||||
Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) {
|
Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) {
|
||||||
if (operand->mode == Addressing_Invalid ||
|
if (operand->mode == Addressing_Invalid ||
|
||||||
operand->type == t_invalid ||
|
operand->type == t_invalid ||
|
||||||
@@ -13,7 +13,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
|||||||
// TODO(bill): is this a good enough error message?
|
// TODO(bill): is this a good enough error message?
|
||||||
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
|
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
|
||||||
error(operand->expr,
|
error(operand->expr,
|
||||||
"Cannot assign built-in procedure `%s` in %.*s",
|
"Cannot assign built-in procedure '%s' in %.*s",
|
||||||
expr_str,
|
expr_str,
|
||||||
LIT(context_name));
|
LIT(context_name));
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
|||||||
|
|
||||||
if (operand->mode == Addressing_Overload) {
|
if (operand->mode == Addressing_Overload) {
|
||||||
if (e->type == nullptr) {
|
if (e->type == nullptr) {
|
||||||
error(operand->expr, "Cannot determine type from overloaded procedure `%.*s`", LIT(operand->overload_entities[0]->token.string));
|
error(operand->expr, "Cannot determine type from overloaded procedure '%.*s'", LIT(operand->overload_entities[0]->token.string));
|
||||||
} else {
|
} else {
|
||||||
check_assignment(c, operand, e->type, str_lit("variable assignment"));
|
check_assignment(c, operand, e->type, str_lit("variable assignment"));
|
||||||
if (operand->mode != Addressing_Type) {
|
if (operand->mode != Addressing_Type) {
|
||||||
@@ -62,13 +62,13 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
|||||||
if (is_type_polymorphic(t)) {
|
if (is_type_polymorphic(t)) {
|
||||||
gbString str = type_to_string(t);
|
gbString str = type_to_string(t);
|
||||||
defer (gb_string_free(str));
|
defer (gb_string_free(str));
|
||||||
error(e->token, "Invalid use of a polymorphic type `%s` in %.*s", str, LIT(context_name));
|
error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name));
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else if (is_type_empty_union(t)) {
|
} else if (is_type_empty_union(t)) {
|
||||||
gbString str = type_to_string(t);
|
gbString str = type_to_string(t);
|
||||||
defer (gb_string_free(str));
|
defer (gb_string_free(str));
|
||||||
error(e->token, "An empty union `%s` cannot be instantiated in %.*s", str, LIT(context_name));
|
error(e->token, "An empty union '%s' cannot be instantiated in %.*s", str, LIT(context_name));
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -102,7 +102,7 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNo
|
|||||||
// an extra allocation
|
// an extra allocation
|
||||||
Array<Operand> operands = {};
|
Array<Operand> operands = {};
|
||||||
array_init(&operands, c->tmp_allocator, 2*lhs_count);
|
array_init(&operands, c->tmp_allocator, 2*lhs_count);
|
||||||
check_unpack_arguments(c, lhs_count, &operands, inits, true);
|
check_unpack_arguments(c, lhs, lhs_count, &operands, inits, true);
|
||||||
|
|
||||||
isize rhs_count = operands.count;
|
isize rhs_count = operands.count;
|
||||||
for_array(i, operands) {
|
for_array(i, operands) {
|
||||||
@@ -113,10 +113,16 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNo
|
|||||||
|
|
||||||
isize max = gb_min(lhs_count, rhs_count);
|
isize max = gb_min(lhs_count, rhs_count);
|
||||||
for (isize i = 0; i < max; i++) {
|
for (isize i = 0; i < max; i++) {
|
||||||
check_init_variable(c, lhs[i], &operands[i], context_name);
|
Entity *e = lhs[i];
|
||||||
|
DeclInfo *d = decl_info_of_entity(&c->info, e);
|
||||||
|
Operand *o = &operands[i];
|
||||||
|
check_init_variable(c, e, o, context_name);
|
||||||
|
if (d != nullptr) {
|
||||||
|
d->init_expr = o->expr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (rhs_count > 0 && lhs_count != rhs_count) {
|
if (rhs_count > 0 && lhs_count != rhs_count) {
|
||||||
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
error(lhs[0]->token, "Assignment count mismatch '%td' = '%td'", lhs_count, rhs_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +139,7 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
|||||||
if (operand->mode != Addressing_Constant) {
|
if (operand->mode != Addressing_Constant) {
|
||||||
// TODO(bill): better error
|
// TODO(bill): better error
|
||||||
gbString str = expr_to_string(operand->expr);
|
gbString str = expr_to_string(operand->expr);
|
||||||
error(operand->expr, "`%s` is not a constant", str);
|
error(operand->expr, "'%s' is not a constant", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
if (e->type == nullptr) {
|
if (e->type == nullptr) {
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
@@ -142,7 +148,7 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
|||||||
}
|
}
|
||||||
if (!is_type_constant_type(operand->type)) {
|
if (!is_type_constant_type(operand->type)) {
|
||||||
gbString type_str = type_to_string(operand->type);
|
gbString type_str = type_to_string(operand->type);
|
||||||
error(operand->expr, "Invalid constant type: `%s`", type_str);
|
error(operand->expr, "Invalid constant type: '%s'", type_str);
|
||||||
gb_string_free(type_str);
|
gb_string_free(type_str);
|
||||||
if (e->type == nullptr) {
|
if (e->type == nullptr) {
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
@@ -164,8 +170,31 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
|||||||
e->Constant.value = operand->value;
|
e->Constant.value = operand->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
|
AstNode *remove_type_alias(AstNode *node) {
|
||||||
|
for (;;) {
|
||||||
|
if (node == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (node->kind == AstNode_ParenExpr) {
|
||||||
|
node = node->ParenExpr.expr;
|
||||||
|
} else if (node->kind == AstNode_AliasType) {
|
||||||
|
node = node->AliasType.type;
|
||||||
|
} else {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, bool is_alias) {
|
||||||
GB_ASSERT(e->type == nullptr);
|
GB_ASSERT(e->type == nullptr);
|
||||||
|
|
||||||
|
DeclInfo *decl = decl_info_of_entity(&c->info, e);
|
||||||
|
if (decl != nullptr && decl->attributes.count > 0) {
|
||||||
|
error(decl->attributes[0], "Attributes are not allowed on type declarations");
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNode *te = remove_type_alias(type_expr);
|
||||||
|
e->type = t_invalid;
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
Type *named = make_type_named(c->allocator, name, nullptr, e);
|
Type *named = make_type_named(c->allocator, name, nullptr, e);
|
||||||
named->Named.type_name = e;
|
named->Named.type_name = e;
|
||||||
@@ -174,12 +203,17 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
|
|||||||
}
|
}
|
||||||
e->type = named;
|
e->type = named;
|
||||||
|
|
||||||
// gb_printf_err("%.*s %p\n", LIT(e->token.string), e);
|
Type *bt = check_type(c, te, named);
|
||||||
|
|
||||||
Type *bt = check_type(c, type_expr, named);
|
|
||||||
named->Named.base = base_type(bt);
|
named->Named.base = base_type(bt);
|
||||||
if (named->Named.base == t_invalid) {
|
if (is_alias) {
|
||||||
// gb_printf("check_type_decl: %s\n", type_to_string(named));
|
if (is_type_named(bt)) {
|
||||||
|
e->type = bt;
|
||||||
|
e->TypeName.is_type_alias = true;
|
||||||
|
} else {
|
||||||
|
gbString str = type_to_string(bt);
|
||||||
|
error(type_expr, "Type alias declaration with a non-named type '%s'", str);
|
||||||
|
gb_string_free(str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,7 +231,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
|||||||
Type *t = check_type(c, type_expr);
|
Type *t = check_type(c, type_expr);
|
||||||
if (!is_type_constant_type(t)) {
|
if (!is_type_constant_type(t)) {
|
||||||
gbString str = type_to_string(t);
|
gbString str = type_to_string(t);
|
||||||
error(type_expr, "Invalid constant type `%s`", str);
|
error(type_expr, "Invalid constant type '%s'", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
return;
|
return;
|
||||||
@@ -226,9 +260,9 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
|||||||
error(e->token, "A type declaration cannot have an type parameter");
|
error(e->token, "A type declaration cannot have an type parameter");
|
||||||
}
|
}
|
||||||
d->type_expr = d->init_expr;
|
d->type_expr = d->init_expr;
|
||||||
check_type_decl(c, e, d->type_expr, named_type);
|
check_type_decl(c, e, d->type_expr, named_type, false);
|
||||||
return;
|
return;
|
||||||
} break;
|
}
|
||||||
|
|
||||||
// NOTE(bill): Check to see if the expression it to be aliases
|
// NOTE(bill): Check to see if the expression it to be aliases
|
||||||
#if 1
|
#if 1
|
||||||
@@ -290,9 +324,15 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
|||||||
if (operand.mode == Addressing_Invalid ||
|
if (operand.mode == Addressing_Invalid ||
|
||||||
base_type(operand.type) == t_invalid) {
|
base_type(operand.type) == t_invalid) {
|
||||||
gbString str = expr_to_string(init);
|
gbString str = expr_to_string(init);
|
||||||
error(e->token, "Invalid declaration type `%s`", str);
|
error(e->token, "Invalid declaration type '%s'", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DeclInfo *decl = decl_info_of_entity(&c->info, e);
|
||||||
|
if (decl != nullptr && decl->attributes.count > 0) {
|
||||||
|
error(decl->attributes[0], "Attributes are not allowed on constant value declarations");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -375,12 +415,12 @@ void init_entity_foreign_library(Checker *c, Entity *e) {
|
|||||||
Entity *found = scope_lookup_entity(c->context.scope, name);
|
Entity *found = scope_lookup_entity(c->context.scope, name);
|
||||||
if (found == nullptr) {
|
if (found == nullptr) {
|
||||||
if (is_blank_ident(name)) {
|
if (is_blank_ident(name)) {
|
||||||
error(ident, "`_` cannot be used as a value type");
|
error(ident, "'_' cannot be used as a value type");
|
||||||
} else {
|
} else {
|
||||||
error(ident, "Undeclared name: %.*s", LIT(name));
|
error(ident, "Undeclared name: %.*s", LIT(name));
|
||||||
}
|
}
|
||||||
} else if (found->kind != Entity_LibraryName) {
|
} else if (found->kind != Entity_LibraryName) {
|
||||||
error(ident, "`%.*s` cannot be used as a library name", LIT(name));
|
error(ident, "'%.*s' cannot be used as a library name", LIT(name));
|
||||||
} else {
|
} else {
|
||||||
// TODO(bill): Extra stuff to do with library names?
|
// TODO(bill): Extra stuff to do with library names?
|
||||||
*foreign_library = found;
|
*foreign_library = found;
|
||||||
@@ -389,6 +429,23 @@ void init_entity_foreign_library(Checker *c, Entity *e) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String handle_link_name(Checker *c, Token token, String link_name, String link_prefix) {
|
||||||
|
if (link_prefix.len > 0) {
|
||||||
|
if (link_name.len > 0) {
|
||||||
|
error(token, "'link_name' and 'link_prefix' cannot be used together");
|
||||||
|
} else {
|
||||||
|
isize len = link_prefix.len + token.string.len;
|
||||||
|
u8 *name = gb_alloc_array(c->allocator, u8, len+1);
|
||||||
|
gb_memmove(name, &link_prefix[0], link_prefix.len);
|
||||||
|
gb_memmove(name+link_prefix.len, &token.string[0], token.string.len);
|
||||||
|
name[len] = 0;
|
||||||
|
|
||||||
|
link_name = make_string(name, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return link_name;
|
||||||
|
}
|
||||||
|
|
||||||
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||||
GB_ASSERT(e->type == nullptr);
|
GB_ASSERT(e->type == nullptr);
|
||||||
if (d->proc_lit->kind != AstNode_ProcLit) {
|
if (d->proc_lit->kind != AstNode_ProcLit) {
|
||||||
@@ -410,8 +467,6 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
defer (check_close_scope(c));
|
defer (check_close_scope(c));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
auto prev_context = c->context;
|
auto prev_context = c->context;
|
||||||
c->context.allow_polymorphic_types = true;
|
c->context.allow_polymorphic_types = true;
|
||||||
check_procedure_type(c, proc_type, pl->type);
|
check_procedure_type(c, proc_type, pl->type);
|
||||||
@@ -419,35 +474,42 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
|
|
||||||
TypeProc *pt = &proc_type->Proc;
|
TypeProc *pt = &proc_type->Proc;
|
||||||
|
|
||||||
bool is_foreign = (pl->tags & ProcTag_foreign) != 0;
|
bool is_foreign = e->Procedure.is_foreign;
|
||||||
bool is_link_name = (pl->tags & ProcTag_link_name) != 0;
|
bool is_export = e->Procedure.is_export;
|
||||||
bool is_export = (pl->tags & ProcTag_export) != 0;
|
|
||||||
bool is_inline = (pl->tags & ProcTag_inline) != 0;
|
|
||||||
bool is_no_inline = (pl->tags & ProcTag_no_inline) != 0;
|
|
||||||
bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
|
bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
|
||||||
|
|
||||||
|
AttributeContext ac = make_attribute_context(e->Procedure.link_prefix);
|
||||||
|
|
||||||
|
if (d != nullptr) {
|
||||||
|
check_decl_attributes(c, d->attributes, proc_decl_attribute, &ac);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (d->scope->is_file && e->token.string == "main") {
|
ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix);
|
||||||
|
|
||||||
|
if (d->scope->file != nullptr && e->token.string == "main") {
|
||||||
if (pt->param_count != 0 ||
|
if (pt->param_count != 0 ||
|
||||||
pt->result_count != 0) {
|
pt->result_count != 0) {
|
||||||
gbString str = type_to_string(proc_type);
|
gbString str = type_to_string(proc_type);
|
||||||
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
|
error(e->token, "Procedure type of 'main' was expected to be 'proc()', got %s", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
}
|
}
|
||||||
if (pt->calling_convention != ProcCC_Odin &&
|
if (pt->calling_convention != ProcCC_Odin &&
|
||||||
pt->calling_convention != ProcCC_Contextless) {
|
pt->calling_convention != ProcCC_Contextless) {
|
||||||
error(e->token, "Procedure `main` cannot have a custom calling convention");
|
error(e->token, "Procedure 'main' cannot have a custom calling convention");
|
||||||
}
|
}
|
||||||
pt->calling_convention = ProcCC_Contextless;
|
pt->calling_convention = ProcCC_Contextless;
|
||||||
}
|
if (d->scope->is_init) {
|
||||||
|
if (c->info.entry_point != nullptr) {
|
||||||
if (is_inline && is_no_inline) {
|
error(e->token, "Redeclaration of the entry pointer procedure 'main'");
|
||||||
error(pl->type, "You cannot apply both `inline` and `no_inline` to a procedure");
|
} else {
|
||||||
|
c->info.entry_point = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_foreign && is_export) {
|
if (is_foreign && is_export) {
|
||||||
error(pl->type, "A foreign procedure cannot have an `export` tag");
|
error(pl->type, "A foreign procedure cannot have an 'export' tag");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pt->is_polymorphic) {
|
if (pt->is_polymorphic) {
|
||||||
@@ -466,7 +528,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
error(pl->body, "A foreign procedure cannot have a body");
|
error(pl->body, "A foreign procedure cannot have a body");
|
||||||
}
|
}
|
||||||
if (proc_type->Proc.c_vararg) {
|
if (proc_type->Proc.c_vararg) {
|
||||||
error(pl->body, "A procedure with a `#c_vararg` field cannot have a body and must be foreign");
|
error(pl->body, "A procedure with a '#c_vararg' field cannot have a body and must be foreign");
|
||||||
}
|
}
|
||||||
|
|
||||||
d->scope = c->context.scope;
|
d->scope = c->context.scope;
|
||||||
@@ -476,28 +538,33 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pl->body, pl->tags);
|
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pl->body, pl->tags);
|
||||||
}
|
}
|
||||||
} else if (!is_foreign) {
|
} else if (!is_foreign) {
|
||||||
error(e->token, "Only a foreign procedure cannot have a body");
|
if (e->Procedure.is_export) {
|
||||||
|
error(e->token, "Foreign export procedures must have a body");
|
||||||
|
} else {
|
||||||
|
error(e->token, "Only a foreign procedure cannot have a body");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pt->result_count == 0 && is_require_results) {
|
if (pt->result_count == 0 && is_require_results) {
|
||||||
error(pl->type, "`#require_results` is not needed on a procedure with no results");
|
error(pl->type, "'#require_results' is not needed on a procedure with no results");
|
||||||
} else {
|
} else {
|
||||||
pt->require_results = is_require_results;
|
pt->require_results = is_require_results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ac.link_name.len > 0) {
|
||||||
|
e->Procedure.link_name = ac.link_name;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_foreign) {
|
if (is_foreign) {
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
if (pl->link_name.len > 0) {
|
if (e->Procedure.link_name.len > 0) {
|
||||||
name = pl->link_name;
|
name = e->Procedure.link_name;
|
||||||
}
|
}
|
||||||
e->Procedure.is_foreign = true;
|
e->Procedure.is_foreign = true;
|
||||||
e->Procedure.link_name = name;
|
e->Procedure.link_name = name;
|
||||||
|
|
||||||
init_entity_foreign_library(c, e);
|
init_entity_foreign_library(c, e);
|
||||||
|
|
||||||
|
|
||||||
auto *fp = &c->info.foreigns;
|
auto *fp = &c->info.foreigns;
|
||||||
HashKey key = hash_string(name);
|
HashKey key = hash_string(name);
|
||||||
Entity **found = map_get(fp, key);
|
Entity **found = map_get(fp, key);
|
||||||
@@ -509,30 +576,28 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
if (is_type_proc(this_type) && is_type_proc(other_type)) {
|
if (is_type_proc(this_type) && is_type_proc(other_type)) {
|
||||||
if (!are_signatures_similar_enough(this_type, other_type)) {
|
if (!are_signatures_similar_enough(this_type, other_type)) {
|
||||||
error(d->proc_lit,
|
error(d->proc_lit,
|
||||||
"Redeclaration of foreign procedure `%.*s` with different type signatures\n"
|
"Redeclaration of foreign procedure '%.*s' with different type signatures\n"
|
||||||
"\tat %.*s(%td:%td)",
|
"\tat %.*s(%td:%td)",
|
||||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||||
}
|
}
|
||||||
} else if (!are_types_identical(this_type, other_type)) {
|
} else if (!are_types_identical(this_type, other_type)) {
|
||||||
error(d->proc_lit,
|
error(d->proc_lit,
|
||||||
"Foreign entity `%.*s` previously declared elsewhere with a different type\n"
|
"Foreign entity '%.*s' previously declared elsewhere with a different type\n"
|
||||||
"\tat %.*s(%td:%td)",
|
"\tat %.*s(%td:%td)",
|
||||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||||
}
|
}
|
||||||
|
} else if (name == "main") {
|
||||||
|
error(d->proc_lit, "The link name 'main' is reserved for internal use");
|
||||||
} else {
|
} else {
|
||||||
map_set(fp, key, e);
|
map_set(fp, key, e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
if (is_link_name) {
|
if (e->Procedure.link_name.len > 0) {
|
||||||
name = pl->link_name;
|
name = e->Procedure.link_name;
|
||||||
}
|
}
|
||||||
|
if (e->Procedure.link_name.len > 0 || is_export) {
|
||||||
if (is_link_name || is_export) {
|
|
||||||
auto *fp = &c->info.foreigns;
|
auto *fp = &c->info.foreigns;
|
||||||
|
|
||||||
e->Procedure.link_name = name;
|
|
||||||
|
|
||||||
HashKey key = hash_string(name);
|
HashKey key = hash_string(name);
|
||||||
Entity **found = map_get(fp, key);
|
Entity **found = map_get(fp, key);
|
||||||
if (found) {
|
if (found) {
|
||||||
@@ -540,9 +605,11 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
TokenPos pos = f->token.pos;
|
TokenPos pos = f->token.pos;
|
||||||
// TODO(bill): Better error message?
|
// TODO(bill): Better error message?
|
||||||
error(d->proc_lit,
|
error(d->proc_lit,
|
||||||
"Non unique linking name for procedure `%.*s`\n"
|
"Non unique linking name for procedure '%.*s'\n"
|
||||||
"\tother at %.*s(%td:%td)",
|
"\tother at %.*s(%td:%td)",
|
||||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||||
|
} else if (name == "main") {
|
||||||
|
error(d->proc_lit, "The link name 'main' is reserved for internal use");
|
||||||
} else {
|
} else {
|
||||||
map_set(fp, key, e);
|
map_set(fp, key, e);
|
||||||
}
|
}
|
||||||
@@ -550,7 +617,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) {
|
void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, Array<AstNode *> init_expr_list) {
|
||||||
GB_ASSERT(e->type == nullptr);
|
GB_ASSERT(e->type == nullptr);
|
||||||
GB_ASSERT(e->kind == Entity_Variable);
|
GB_ASSERT(e->kind == Entity_Variable);
|
||||||
|
|
||||||
@@ -560,6 +627,17 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
|||||||
}
|
}
|
||||||
e->flags |= EntityFlag_Visited;
|
e->flags |= EntityFlag_Visited;
|
||||||
|
|
||||||
|
AttributeContext ac = make_attribute_context(e->Variable.link_prefix);
|
||||||
|
ac.init_expr_list_count = init_expr_list.count;
|
||||||
|
|
||||||
|
DeclInfo *decl = decl_info_of_entity(&c->info, e);
|
||||||
|
if (decl != nullptr) {
|
||||||
|
check_decl_attributes(c, decl->attributes, var_decl_attribute, &ac);
|
||||||
|
}
|
||||||
|
|
||||||
|
ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix);
|
||||||
|
e->Variable.thread_local_model = ac.thread_local_model;
|
||||||
|
|
||||||
String context_name = str_lit("variable declaration");
|
String context_name = str_lit("variable declaration");
|
||||||
|
|
||||||
if (type_expr != nullptr) {
|
if (type_expr != nullptr) {
|
||||||
@@ -569,24 +647,32 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
|||||||
if (is_type_polymorphic(base_type(e->type))) {
|
if (is_type_polymorphic(base_type(e->type))) {
|
||||||
gbString str = type_to_string(e->type);
|
gbString str = type_to_string(e->type);
|
||||||
defer (gb_string_free(str));
|
defer (gb_string_free(str));
|
||||||
error(e->token, "Invalid use of a polymorphic type `%s` in %.*s", str, LIT(context_name));
|
error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name));
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
} else if (is_type_empty_union(e->type)) {
|
} else if (is_type_empty_union(e->type)) {
|
||||||
gbString str = type_to_string(e->type);
|
gbString str = type_to_string(e->type);
|
||||||
defer (gb_string_free(str));
|
defer (gb_string_free(str));
|
||||||
error(e->token, "An empty union `%s` cannot be instantiated in %.*s", str, LIT(context_name));
|
error(e->token, "An empty union '%s' cannot be instantiated in %.*s", str, LIT(context_name));
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (e->Variable.is_foreign) {
|
if (e->Variable.is_foreign) {
|
||||||
if (init_expr != nullptr) {
|
if (init_expr_list.count > 0) {
|
||||||
error(e->token, "A foreign variable declaration cannot have a default value");
|
error(e->token, "A foreign variable declaration cannot have a default value");
|
||||||
}
|
}
|
||||||
init_entity_foreign_library(c, e);
|
init_entity_foreign_library(c, e);
|
||||||
|
}
|
||||||
|
if (ac.link_name.len > 0) {
|
||||||
|
e->Variable.link_name = ac.link_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e->Variable.is_foreign || e->Variable.is_export) {
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
|
if (e->Variable.link_name.len > 0) {
|
||||||
|
name = e->Variable.link_name;
|
||||||
|
}
|
||||||
auto *fp = &c->info.foreigns;
|
auto *fp = &c->info.foreigns;
|
||||||
HashKey key = hash_string(name);
|
HashKey key = hash_string(name);
|
||||||
Entity **found = map_get(fp, key);
|
Entity **found = map_get(fp, key);
|
||||||
@@ -597,7 +683,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
|||||||
Type *other_type = base_type(f->type);
|
Type *other_type = base_type(f->type);
|
||||||
if (!are_types_identical(this_type, other_type)) {
|
if (!are_types_identical(this_type, other_type)) {
|
||||||
error(e->token,
|
error(e->token,
|
||||||
"Foreign entity `%.*s` previously declared elsewhere with a different type\n"
|
"Foreign entity '%.*s' previously declared elsewhere with a different type\n"
|
||||||
"\tat %.*s(%td:%td)",
|
"\tat %.*s(%td:%td)",
|
||||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||||
}
|
}
|
||||||
@@ -606,31 +692,20 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init_expr == nullptr) {
|
if (init_expr_list.count == 0) {
|
||||||
if (type_expr == nullptr) {
|
if (type_expr == nullptr) {
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entities == nullptr || entity_count == 1) {
|
|
||||||
GB_ASSERT(entities == nullptr || entities[0] == e);
|
|
||||||
Operand operand = {};
|
|
||||||
check_expr(c, &operand, init_expr);
|
|
||||||
check_init_variable(c, e, &operand, context_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type_expr != nullptr) {
|
if (type_expr != nullptr) {
|
||||||
for (isize i = 0; i < entity_count; i++) {
|
for (isize i = 0; i < entity_count; i++) {
|
||||||
entities[i]->type = e->type;
|
entities[i]->type = e->type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_init_variables(c, entities, entity_count, init_expr_list, context_name);
|
||||||
Array<AstNode *> inits;
|
|
||||||
array_init(&inits, c->allocator, 1);
|
|
||||||
array_add(&inits, init_expr);
|
|
||||||
check_init_variables(c, entities, entity_count, inits, context_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||||
@@ -645,7 +720,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
|||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
set_base_type(named_type, t_invalid);
|
set_base_type(named_type, t_invalid);
|
||||||
return;
|
return;
|
||||||
// GB_PANIC("`%.*s` should been declared!", LIT(e->token.string));
|
// GB_PANIC("'%.*s' should been declared!", LIT(e->token.string));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -657,14 +732,16 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
|||||||
|
|
||||||
switch (e->kind) {
|
switch (e->kind) {
|
||||||
case Entity_Variable:
|
case Entity_Variable:
|
||||||
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr);
|
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr_list);
|
||||||
break;
|
break;
|
||||||
case Entity_Constant:
|
case Entity_Constant:
|
||||||
check_const_decl(c, e, d->type_expr, d->init_expr, named_type);
|
check_const_decl(c, e, d->type_expr, d->init_expr, named_type);
|
||||||
break;
|
break;
|
||||||
case Entity_TypeName:
|
case Entity_TypeName: {
|
||||||
check_type_decl(c, e, d->type_expr, named_type);
|
bool is_alias = unparen_expr(d->type_expr)->kind == AstNode_AliasType;
|
||||||
|
check_type_decl(c, e, d->type_expr, named_type, is_alias);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Entity_Procedure:
|
case Entity_Procedure:
|
||||||
check_proc_decl(c, e, d);
|
check_proc_decl(c, e, d);
|
||||||
break;
|
break;
|
||||||
@@ -724,13 +801,13 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
|||||||
uvar->Variable.is_immutable = is_immutable;
|
uvar->Variable.is_immutable = is_immutable;
|
||||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||||
if (prev != nullptr) {
|
if (prev != nullptr) {
|
||||||
error(e->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
|
error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error(e->token, "`using` can only be applied to variables of type struct");
|
error(e->token, "'using' can only be applied to variables of type struct");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -743,7 +820,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
|||||||
if (type->Proc.result_count > 0) {
|
if (type->Proc.result_count > 0) {
|
||||||
if (!check_is_terminating(body)) {
|
if (!check_is_terminating(body)) {
|
||||||
if (token.kind == Token_Ident) {
|
if (token.kind == Token_Ident) {
|
||||||
error(bs->close, "Missing return statement at the end of the procedure `%.*s`", LIT(token.string));
|
error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string));
|
||||||
} else {
|
} else {
|
||||||
error(bs->close, "Missing return statement at the end of the procedure");
|
error(bs->close, "Missing return statement at the end of the procedure");
|
||||||
}
|
}
|
||||||
@@ -757,9 +834,8 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
|||||||
if (decl->parent != nullptr) {
|
if (decl->parent != nullptr) {
|
||||||
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
|
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
|
||||||
for_array(i, decl->deps.entries) {
|
for_array(i, decl->deps.entries) {
|
||||||
HashKey key = decl->deps.entries[i].key;
|
Entity *e = decl->deps.entries[i].ptr;
|
||||||
Entity *e = cast(Entity *)key.ptr;
|
ptr_set_add(&decl->parent->deps, e);
|
||||||
map_set(&decl->parent->deps, key, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+665
-2588
File diff suppressed because it is too large
Load Diff
+232
-207
File diff suppressed because it is too large
Load Diff
+2436
File diff suppressed because it is too large
Load Diff
+1695
-662
File diff suppressed because it is too large
Load Diff
+105
-6
@@ -50,16 +50,19 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
|||||||
if (flags & gbAllocatorFlag_ClearToZero) {
|
if (flags & gbAllocatorFlag_ClearToZero) {
|
||||||
gb_zero_size(ptr, size);
|
gb_zero_size(ptr, size);
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case gbAllocation_Free: {
|
case gbAllocation_Free: {
|
||||||
free(old_memory);
|
free(old_memory);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case gbAllocation_Resize: {
|
case gbAllocation_Resize: {
|
||||||
// ptr = realloc(old_memory, size);
|
// ptr = realloc(old_memory, size);
|
||||||
ptr = gb_default_resize_align(heap_allocator(), old_memory, old_size, size, alignment);
|
ptr = gb_default_resize_align(heap_allocator(), old_memory, old_size, size, alignment);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
// TODO(bill): *nix version that's decent
|
// TODO(bill): *nix version that's decent
|
||||||
case gbAllocation_Alloc: {
|
case gbAllocation_Alloc: {
|
||||||
@@ -68,15 +71,18 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
|||||||
if (flags & gbAllocatorFlag_ClearToZero) {
|
if (flags & gbAllocatorFlag_ClearToZero) {
|
||||||
gb_zero_size(ptr, size);
|
gb_zero_size(ptr, size);
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case gbAllocation_Free: {
|
case gbAllocation_Free: {
|
||||||
free(old_memory);
|
free(old_memory);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case gbAllocation_Resize: {
|
case gbAllocation_Resize: {
|
||||||
ptr = gb_default_resize_align(heap_allocator(), old_memory, old_size, size, alignment);
|
ptr = gb_default_resize_align(heap_allocator(), old_memory, old_size, size, alignment);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case gbAllocation_FreeAll:
|
case gbAllocation_FreeAll:
|
||||||
@@ -107,6 +113,9 @@ u128 fnv128a(void const *data, isize len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include "map.cpp"
|
#include "map.cpp"
|
||||||
|
#include "ptr_set.cpp"
|
||||||
|
#include "string_set.cpp"
|
||||||
|
#include "priority_queue.cpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -296,6 +305,68 @@ i64 next_pow2(i64 n) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i32 bit_set_count(u32 x) {
|
||||||
|
x -= ((x >> 1) & 0x55555555);
|
||||||
|
x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
|
||||||
|
x = (((x >> 4) + x) & 0x0f0f0f0f);
|
||||||
|
x += (x >> 8);
|
||||||
|
x += (x >> 16);
|
||||||
|
|
||||||
|
return cast(i32)(x & 0x0000003f);
|
||||||
|
}
|
||||||
|
|
||||||
|
i64 bit_set_count(u64 x) {
|
||||||
|
u32 a = *(cast(u32 *)&x);
|
||||||
|
u32 b = *(cast(u32 *)&x + 1);
|
||||||
|
return bit_set_count(a) + bit_set_count(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 floor_log2(u32 x) {
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
x |= x >> 8;
|
||||||
|
x |= x >> 16;
|
||||||
|
return cast(u32)(bit_set_count(x) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 floor_log2(u64 x) {
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
x |= x >> 8;
|
||||||
|
x |= x >> 16;
|
||||||
|
x |= x >> 32;
|
||||||
|
return cast(u64)(bit_set_count(x) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u32 ceil_log2(u32 x) {
|
||||||
|
i32 y = cast(i32)(x & (x-1));
|
||||||
|
y |= -y;
|
||||||
|
y >>= 32-1;
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
x |= x >> 8;
|
||||||
|
x |= x >> 16;
|
||||||
|
return cast(u32)(bit_set_count(x) - 1 - y);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 ceil_log2(u64 x) {
|
||||||
|
i64 y = cast(i64)(x & (x-1));
|
||||||
|
y |= -y;
|
||||||
|
y >>= 64-1;
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
x |= x >> 8;
|
||||||
|
x |= x >> 16;
|
||||||
|
x |= x >> 32;
|
||||||
|
return cast(u64)(bit_set_count(x) - 1 - y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
i32 prev_pow2(i32 n) {
|
i32 prev_pow2(i32 n) {
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -461,3 +532,31 @@ wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
|
bool path_is_directory(String path) {
|
||||||
|
gbAllocator a = heap_allocator();
|
||||||
|
String16 wstr = string_to_string16(a, path);
|
||||||
|
defer (gb_free(a, wstr.text));
|
||||||
|
|
||||||
|
i32 attribs = GetFileAttributesW(wstr.text);
|
||||||
|
if (attribs < 0) return false;
|
||||||
|
|
||||||
|
return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
bool path_is_directory(String path) {
|
||||||
|
gbAllocator a = heap_allocator();
|
||||||
|
char *copy = cast(char *)copy_string(a, path).text;
|
||||||
|
defer (gb_free(a, copy));
|
||||||
|
|
||||||
|
struct stat s;
|
||||||
|
if (stat(copy, &s) == 0) {
|
||||||
|
return (s.st_mode & S_IFDIR) != 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+1
-24
@@ -90,34 +90,11 @@ void print_proc_decl(AstNodeProcDecl *pd) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
void print_declaration(AstNode *decl) {
|
void print_declaration(AstNode *decl) {
|
||||||
switch (decl->kind) {
|
|
||||||
case_ast_node(gd, GenDecl, decl);
|
|
||||||
for_array(spec_index, gd->specs) {
|
|
||||||
AstNode *spec = gd->specs[spec_index];
|
|
||||||
switch(gd->token.kind) {
|
|
||||||
case Token_import:
|
|
||||||
case Token_import_load:
|
|
||||||
break;
|
|
||||||
case Token_foreign_library:
|
|
||||||
case Token_foreign_system_library:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case_end;
|
|
||||||
|
|
||||||
// case_ast_node(pd, ProcDecl, decl);
|
|
||||||
// print_proc_decl(pd);
|
|
||||||
// case_end;
|
|
||||||
|
|
||||||
case_ast_node(fb, ForeignBlockDecl, decl);
|
|
||||||
// TODO(bill)
|
|
||||||
case_end;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_documentation(Parser *parser) {
|
void generate_documentation(Parser *parser) {
|
||||||
for_array(file_index, parser->files) {
|
for_array(file_index, parser->files) {
|
||||||
AstFile *file = &parser->files[file_index];
|
AstFile *file = parser->files[file_index];
|
||||||
Tokenizer *tokenizer = &file->tokenizer;
|
Tokenizer *tokenizer = &file->tokenizer;
|
||||||
String fullpath = tokenizer->fullpath;
|
String fullpath = tokenizer->fullpath;
|
||||||
gb_printf("%.*s\n", LIT(fullpath));
|
gb_printf("%.*s\n", LIT(fullpath));
|
||||||
|
|||||||
+25
-16
@@ -2,7 +2,6 @@ struct Scope;
|
|||||||
struct Checker;
|
struct Checker;
|
||||||
struct Type;
|
struct Type;
|
||||||
struct DeclInfo;
|
struct DeclInfo;
|
||||||
// typedef enum BuiltinProcId BuiltinProcId;
|
|
||||||
|
|
||||||
|
|
||||||
#define ENTITY_KINDS \
|
#define ENTITY_KINDS \
|
||||||
@@ -44,22 +43,16 @@ enum EntityFlag {
|
|||||||
EntityFlag_Value = 1<<9,
|
EntityFlag_Value = 1<<9,
|
||||||
EntityFlag_Sret = 1<<10,
|
EntityFlag_Sret = 1<<10,
|
||||||
EntityFlag_BitFieldValue = 1<<11,
|
EntityFlag_BitFieldValue = 1<<11,
|
||||||
|
EntityFlag_PolyConst = 1<<12,
|
||||||
|
|
||||||
EntityFlag_CVarArg = 1<<20,
|
EntityFlag_CVarArg = 1<<20,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Zero value means the overloading process is not yet done
|
// Zero value means the overloading process is not yet done
|
||||||
enum OverloadKind {
|
enum OverloadKind {
|
||||||
Overload_Unknown,
|
Overload_Unknown = 0,
|
||||||
Overload_No,
|
Overload_No = 1,
|
||||||
Overload_Yes,
|
Overload_Yes = 2,
|
||||||
};
|
|
||||||
|
|
||||||
enum EntityAliasKind {
|
|
||||||
EntityAlias_Invalid,
|
|
||||||
EntityAlias_Type,
|
|
||||||
EntityAlias_Entity,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -78,6 +71,8 @@ struct Entity {
|
|||||||
Entity * using_parent;
|
Entity * using_parent;
|
||||||
AstNode * using_expr;
|
AstNode * using_expr;
|
||||||
|
|
||||||
|
isize order_in_src;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
ExactValue value;
|
ExactValue value;
|
||||||
@@ -90,20 +85,24 @@ struct Entity {
|
|||||||
bool default_is_undef;
|
bool default_is_undef;
|
||||||
bool default_is_location;
|
bool default_is_location;
|
||||||
bool is_immutable;
|
bool is_immutable;
|
||||||
bool is_thread_local;
|
String thread_local_model;
|
||||||
bool is_foreign;
|
bool is_foreign;
|
||||||
|
bool is_export;
|
||||||
Entity * foreign_library;
|
Entity * foreign_library;
|
||||||
AstNode * foreign_library_ident;
|
AstNode * foreign_library_ident;
|
||||||
String link_name;
|
String link_name;
|
||||||
|
String link_prefix;
|
||||||
} Variable;
|
} Variable;
|
||||||
struct {
|
struct {
|
||||||
bool is_type_alias;
|
bool is_type_alias;
|
||||||
Type *type_parameter_specialization;
|
Type *type_parameter_specialization;
|
||||||
} TypeName;
|
} TypeName;
|
||||||
struct {
|
struct {
|
||||||
OverloadKind overload_kind;
|
OverloadKind overload_kind;
|
||||||
String link_name;
|
String link_name;
|
||||||
|
String link_prefix;
|
||||||
u64 tags;
|
u64 tags;
|
||||||
|
bool is_export;
|
||||||
bool is_foreign;
|
bool is_foreign;
|
||||||
Entity * foreign_library;
|
Entity * foreign_library;
|
||||||
AstNode * foreign_library_ident;
|
AstNode * foreign_library_ident;
|
||||||
@@ -127,7 +126,7 @@ struct Entity {
|
|||||||
} LibraryName;
|
} LibraryName;
|
||||||
i32 Nil;
|
i32 Nil;
|
||||||
struct {
|
struct {
|
||||||
String name;
|
String name;
|
||||||
AstNode *node;
|
AstNode *node;
|
||||||
} Label;
|
} Label;
|
||||||
};
|
};
|
||||||
@@ -160,6 +159,7 @@ bool is_entity_exported(Entity *e) {
|
|||||||
return name[0] != '_';
|
return name[0] != '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
gb_global u64 global_entity_id = 0;
|
gb_global u64 global_entity_id = 0;
|
||||||
|
|
||||||
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
|
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
|
||||||
@@ -208,6 +208,16 @@ Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type,
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Entity *make_entity_const_param(gbAllocator a, Scope *scope, Token token, Type *type, ExactValue value, bool poly_const) {
|
||||||
|
Entity *entity = make_entity_constant(a, scope, token, type, value);
|
||||||
|
entity->flags |= EntityFlag_Used;
|
||||||
|
if (poly_const) entity->flags |= EntityFlag_PolyConst;
|
||||||
|
entity->flags |= EntityFlag_Param;
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, i32 field_src_index) {
|
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, i32 field_src_index) {
|
||||||
Entity *entity = make_entity_variable(a, scope, token, type, false);
|
Entity *entity = make_entity_variable(a, scope, token, type, false);
|
||||||
entity->Variable.field_src_index = field_src_index;
|
entity->Variable.field_src_index = field_src_index;
|
||||||
@@ -266,8 +276,7 @@ Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type
|
|||||||
|
|
||||||
|
|
||||||
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
|
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
|
||||||
Token token = make_token_ident(name);
|
Entity *entity = alloc_entity(a, Entity_Nil, nullptr, make_token_ident(name), type);
|
||||||
Entity *entity = alloc_entity(a, Entity_Nil, nullptr, token, type);
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+38
-16
@@ -22,6 +22,7 @@ enum ExactValueKind {
|
|||||||
ExactValue_Complex,
|
ExactValue_Complex,
|
||||||
ExactValue_Pointer,
|
ExactValue_Pointer,
|
||||||
ExactValue_Compound, // TODO(bill): Is this good enough?
|
ExactValue_Compound, // TODO(bill): Is this good enough?
|
||||||
|
ExactValue_Procedure, // TODO(bill): Is this good enough?
|
||||||
ExactValue_Type,
|
ExactValue_Type,
|
||||||
|
|
||||||
ExactValue_Count,
|
ExactValue_Count,
|
||||||
@@ -37,6 +38,7 @@ struct ExactValue {
|
|||||||
i64 value_pointer;
|
i64 value_pointer;
|
||||||
Complex128 value_complex;
|
Complex128 value_complex;
|
||||||
AstNode * value_compound;
|
AstNode * value_compound;
|
||||||
|
AstNode * value_procedure;
|
||||||
Type * value_type;
|
Type * value_type;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -109,6 +111,12 @@ ExactValue exact_value_type(Type *type) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExactValue exact_value_procedure(AstNode *node) {
|
||||||
|
ExactValue result = {ExactValue_Procedure};
|
||||||
|
result.value_procedure = node;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ExactValue exact_value_integer_from_string(String string) {
|
ExactValue exact_value_integer_from_string(String string) {
|
||||||
return exact_value_u128(u128_from_string(string));
|
return exact_value_u128(u128_from_string(string));
|
||||||
@@ -238,7 +246,7 @@ ExactValue exact_value_from_basic_literal(Token token) {
|
|||||||
case Token_Imag: {
|
case Token_Imag: {
|
||||||
String str = token.string;
|
String str = token.string;
|
||||||
Rune last_rune = cast(Rune)str[str.len-1];
|
Rune last_rune = cast(Rune)str[str.len-1];
|
||||||
str.len--; // Ignore the `i|j|k`
|
str.len--; // Ignore the 'i|j|k'
|
||||||
f64 imag = float_from_string(str);
|
f64 imag = float_from_string(str);
|
||||||
|
|
||||||
if (last_rune == 'i') {
|
if (last_rune == 'i') {
|
||||||
@@ -270,7 +278,8 @@ ExactValue exact_value_to_integer(ExactValue v) {
|
|||||||
if (f == v.value_float) {
|
if (f == v.value_float) {
|
||||||
return exact_value_i128(i);
|
return exact_value_i128(i);
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ExactValue_Pointer:
|
case ExactValue_Pointer:
|
||||||
return exact_value_i64(cast(i64)cast(intptr)v.value_pointer);
|
return exact_value_i64(cast(i64)cast(intptr)v.value_pointer);
|
||||||
@@ -335,7 +344,7 @@ ExactValue exact_value_make_imag(ExactValue v) {
|
|||||||
case ExactValue_Float:
|
case ExactValue_Float:
|
||||||
return exact_value_complex(0, v.value_float);
|
return exact_value_complex(0, v.value_float);
|
||||||
default:
|
default:
|
||||||
GB_PANIC("Expected an integer or float type for `exact_value_make_imag`");
|
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
|
||||||
}
|
}
|
||||||
ExactValue r = {ExactValue_Invalid};
|
ExactValue r = {ExactValue_Invalid};
|
||||||
return r;
|
return r;
|
||||||
@@ -352,7 +361,8 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
|||||||
case ExactValue_Complex:
|
case ExactValue_Complex:
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Token_Sub: {
|
case Token_Sub: {
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
@@ -374,7 +384,8 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
|||||||
return exact_value_complex(-real, -imag);
|
return exact_value_complex(-real, -imag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Token_Xor: {
|
case Token_Xor: {
|
||||||
i128 i = I128_ZERO;
|
i128 i = I128_ZERO;
|
||||||
@@ -396,7 +407,8 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return exact_value_i128(i);
|
return exact_value_i128(i);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Token_Not: {
|
case Token_Not: {
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
@@ -404,7 +416,8 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
|||||||
case ExactValue_Bool:
|
case ExactValue_Bool:
|
||||||
return exact_value_bool(!v.value_bool);
|
return exact_value_bool(!v.value_bool);
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
failure:
|
failure:
|
||||||
@@ -521,7 +534,8 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return exact_value_i128(c);
|
return exact_value_i128(c);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ExactValue_Float: {
|
case ExactValue_Float: {
|
||||||
f64 a = x.value_float;
|
f64 a = x.value_float;
|
||||||
@@ -533,7 +547,8 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
|||||||
case Token_Quo: return exact_value_float(a / b);
|
case Token_Quo: return exact_value_float(a / b);
|
||||||
default: goto error;
|
default: goto error;
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ExactValue_Complex: {
|
case ExactValue_Complex: {
|
||||||
y = exact_value_to_complex(y);
|
y = exact_value_to_complex(y);
|
||||||
@@ -560,11 +575,13 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
|||||||
f64 s = c*c + d*d;
|
f64 s = c*c + d*d;
|
||||||
real = (a*c + b*d)/s;
|
real = (a*c + b*d)/s;
|
||||||
imag = (b*c - a*d)/s;
|
imag = (b*c - a*d)/s;
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
default: goto error;
|
default: goto error;
|
||||||
}
|
}
|
||||||
return exact_value_complex(real, imag);
|
return exact_value_complex(real, imag);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ExactValue_String: {
|
case ExactValue_String: {
|
||||||
if (op != Token_Add) goto error;
|
if (op != Token_Add) goto error;
|
||||||
@@ -577,7 +594,8 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
|||||||
gb_memmove(data, sx.text, sx.len);
|
gb_memmove(data, sx.text, sx.len);
|
||||||
gb_memmove(data+sx.len, sy.text, sy.len);
|
gb_memmove(data+sx.len, sy.text, sy.len);
|
||||||
return exact_value_string(make_string(data, len));
|
return exact_value_string(make_string(data, len));
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error:; // NOTE(bill): MSVC accepts this??? apparently you cannot declare variables immediately after labels...
|
error:; // NOTE(bill): MSVC accepts this??? apparently you cannot declare variables immediately after labels...
|
||||||
@@ -620,7 +638,8 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
|||||||
case Token_Gt: return a > b;
|
case Token_Gt: return a > b;
|
||||||
case Token_GtEq: return a >= b;
|
case Token_GtEq: return a >= b;
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ExactValue_Float: {
|
case ExactValue_Float: {
|
||||||
f64 a = x.value_float;
|
f64 a = x.value_float;
|
||||||
@@ -633,7 +652,8 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
|||||||
case Token_Gt: return cmp_f64(a, b) > 0;
|
case Token_Gt: return cmp_f64(a, b) > 0;
|
||||||
case Token_GtEq: return cmp_f64(a, b) >= 0;
|
case Token_GtEq: return cmp_f64(a, b) >= 0;
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ExactValue_Complex: {
|
case ExactValue_Complex: {
|
||||||
f64 a = x.value_complex.real;
|
f64 a = x.value_complex.real;
|
||||||
@@ -644,7 +664,8 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
|||||||
case Token_CmpEq: return cmp_f64(a, c) == 0 && cmp_f64(b, d) == 0;
|
case Token_CmpEq: return cmp_f64(a, c) == 0 && cmp_f64(b, d) == 0;
|
||||||
case Token_NotEq: return cmp_f64(a, c) != 0 || cmp_f64(b, d) != 0;
|
case Token_NotEq: return cmp_f64(a, c) != 0 || cmp_f64(b, d) != 0;
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ExactValue_String: {
|
case ExactValue_String: {
|
||||||
String a = x.value_string;
|
String a = x.value_string;
|
||||||
@@ -658,7 +679,8 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
|||||||
case Token_Gt: return a > b;
|
case Token_Gt: return a > b;
|
||||||
case Token_GtEq: return a >= b;
|
case Token_GtEq: return a >= b;
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ExactValue_Type:
|
case ExactValue_Type:
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
|||||||
+6
-4
@@ -7954,7 +7954,7 @@ gbFileTime gb_file_last_write_time(char const *filepath) {
|
|||||||
time_t result = 0;
|
time_t result = 0;
|
||||||
struct stat file_stat;
|
struct stat file_stat;
|
||||||
|
|
||||||
if (stat(filepath, &file_stat)) {
|
if (stat(filepath, &file_stat) == 0) {
|
||||||
result = file_stat.st_mtime;
|
result = file_stat.st_mtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7984,15 +7984,17 @@ gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filena
|
|||||||
|
|
||||||
gb_inline b32 gb_file_move(char const *existing_filename, char const *new_filename) {
|
gb_inline b32 gb_file_move(char const *existing_filename, char const *new_filename) {
|
||||||
if (link(existing_filename, new_filename) == 0) {
|
if (link(existing_filename, new_filename) == 0) {
|
||||||
if (unlink(existing_filename) != -1) {
|
return unlink(existing_filename) != -1;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 gb_file_remove(char const *filename) {
|
b32 gb_file_remove(char const *filename) {
|
||||||
|
#if defined(GB_SYSTEM_OSX)
|
||||||
|
return unlink(filename) != -1;
|
||||||
|
#else
|
||||||
return remove(filename) == 0;
|
return remove(filename) == 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+115
-102
@@ -95,48 +95,48 @@ void i128_divide (i128 num, i128 den, i128 *quo, i128 *rem);
|
|||||||
i128 i128_quo (i128 a, i128 b);
|
i128 i128_quo (i128 a, i128 b);
|
||||||
i128 i128_mod (i128 a, i128 b);
|
i128 i128_mod (i128 a, i128 b);
|
||||||
|
|
||||||
bool operator==(u128 a, u128 b) { return u128_eq(a, b); }
|
bool operator==(u128 const &a, u128 const &b) { return u128_eq(a, b); }
|
||||||
bool operator!=(u128 a, u128 b) { return u128_ne(a, b); }
|
bool operator!=(u128 const &a, u128 const &b) { return u128_ne(a, b); }
|
||||||
bool operator< (u128 a, u128 b) { return u128_lt(a, b); }
|
bool operator< (u128 const &a, u128 const &b) { return u128_lt(a, b); }
|
||||||
bool operator> (u128 a, u128 b) { return u128_gt(a, b); }
|
bool operator> (u128 const &a, u128 const &b) { return u128_gt(a, b); }
|
||||||
bool operator<=(u128 a, u128 b) { return u128_le(a, b); }
|
bool operator<=(u128 const &a, u128 const &b) { return u128_le(a, b); }
|
||||||
bool operator>=(u128 a, u128 b) { return u128_ge(a, b); }
|
bool operator>=(u128 const &a, u128 const &b) { return u128_ge(a, b); }
|
||||||
|
|
||||||
u128 operator+(u128 a, u128 b) { return u128_add(a, b); }
|
u128 operator+ (u128 const &a, u128 const &b) { return u128_add(a, b); }
|
||||||
u128 operator-(u128 a, u128 b) { return u128_sub(a, b); }
|
u128 operator- (u128 const &a, u128 const &b) { return u128_sub(a, b); }
|
||||||
u128 operator*(u128 a, u128 b) { return u128_mul(a, b); }
|
u128 operator* (u128 const &a, u128 const &b) { return u128_mul(a, b); }
|
||||||
u128 operator/(u128 a, u128 b) { return u128_quo(a, b); }
|
u128 operator/ (u128 const &a, u128 const &b) { return u128_quo(a, b); }
|
||||||
u128 operator%(u128 a, u128 b) { return u128_mod(a, b); }
|
u128 operator% (u128 const &a, u128 const &b) { return u128_mod(a, b); }
|
||||||
u128 operator&(u128 a, u128 b) { return u128_and(a, b); }
|
u128 operator& (u128 const &a, u128 const &b) { return u128_and(a, b); }
|
||||||
u128 operator|(u128 a, u128 b) { return u128_or (a, b); }
|
u128 operator| (u128 const &a, u128 const &b) { return u128_or (a, b); }
|
||||||
u128 operator^(u128 a, u128 b) { return u128_xor(a, b); }
|
u128 operator^ (u128 const &a, u128 const &b) { return u128_xor(a, b); }
|
||||||
u128 operator~(u128 a) { return u128_not(a); }
|
u128 operator~ (u128 const &a) { return u128_not(a); }
|
||||||
u128 operator+(u128 a) { return a; }
|
u128 operator+ (u128 const &a) { return a; }
|
||||||
u128 operator-(u128 a) { return u128_neg(a); }
|
u128 operator- (u128 const &a) { return u128_neg(a); }
|
||||||
u128 operator<<(u128 a, u32 b) { return u128_shl(a, b); }
|
u128 operator<<(u128 const &a, u32 const &b) { return u128_shl(a, b); }
|
||||||
u128 operator>>(u128 a, u32 b) { return u128_shr(a, b); }
|
u128 operator>>(u128 const &a, u32 const &b) { return u128_shr(a, b); }
|
||||||
|
|
||||||
|
|
||||||
bool operator==(i128 a, i128 b) { return i128_eq(a, b); }
|
bool operator==(i128 const &a, i128 const &b) { return i128_eq(a, b); }
|
||||||
bool operator!=(i128 a, i128 b) { return i128_ne(a, b); }
|
bool operator!=(i128 const &a, i128 const &b) { return i128_ne(a, b); }
|
||||||
bool operator< (i128 a, i128 b) { return i128_lt(a, b); }
|
bool operator< (i128 const &a, i128 const &b) { return i128_lt(a, b); }
|
||||||
bool operator> (i128 a, i128 b) { return i128_gt(a, b); }
|
bool operator> (i128 const &a, i128 const &b) { return i128_gt(a, b); }
|
||||||
bool operator<=(i128 a, i128 b) { return i128_le(a, b); }
|
bool operator<=(i128 const &a, i128 const &b) { return i128_le(a, b); }
|
||||||
bool operator>=(i128 a, i128 b) { return i128_ge(a, b); }
|
bool operator>=(i128 const &a, i128 const &b) { return i128_ge(a, b); }
|
||||||
|
|
||||||
i128 operator+(i128 a, i128 b) { return i128_add(a, b); }
|
i128 operator+ (i128 const &a, i128 const &b) { return i128_add(a, b); }
|
||||||
i128 operator-(i128 a, i128 b) { return i128_sub(a, b); }
|
i128 operator- (i128 const &a, i128 const &b) { return i128_sub(a, b); }
|
||||||
i128 operator*(i128 a, i128 b) { return i128_mul(a, b); }
|
i128 operator* (i128 const &a, i128 const &b) { return i128_mul(a, b); }
|
||||||
i128 operator/(i128 a, i128 b) { return i128_quo(a, b); }
|
i128 operator/ (i128 const &a, i128 const &b) { return i128_quo(a, b); }
|
||||||
i128 operator%(i128 a, i128 b) { return i128_mod(a, b); }
|
i128 operator% (i128 const &a, i128 const &b) { return i128_mod(a, b); }
|
||||||
i128 operator&(i128 a, i128 b) { return i128_and(a, b); }
|
i128 operator& (i128 const &a, i128 const &b) { return i128_and(a, b); }
|
||||||
i128 operator|(i128 a, i128 b) { return i128_or (a, b); }
|
i128 operator| (i128 const &a, i128 const &b) { return i128_or (a, b); }
|
||||||
i128 operator^(i128 a, i128 b) { return i128_xor(a, b); }
|
i128 operator^ (i128 const &a, i128 const &b) { return i128_xor(a, b); }
|
||||||
i128 operator~(i128 a) { return i128_not(a); }
|
i128 operator~ (i128 const &a) { return i128_not(a); }
|
||||||
i128 operator+(i128 a) { return a; }
|
i128 operator+ (i128 const &a) { return a; }
|
||||||
i128 operator-(i128 a) { return i128_neg(a); }
|
i128 operator- (i128 const &a) { return i128_neg(a); }
|
||||||
i128 operator<<(i128 a, u32 b) { return i128_shl(a, b); }
|
i128 operator<<(i128 const &a, u32 b) { return i128_shl(a, b); }
|
||||||
i128 operator>>(i128 a, u32 b) { return i128_shr(a, b); }
|
i128 operator>>(i128 const &a, u32 b) { return i128_shr(a, b); }
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -482,36 +482,37 @@ u128 u128_mul(u128 a, u128 b) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool u128_hibit(u128 *d) { return (d->hi & BIT128_U64_HIGHBIT) != 0; }
|
bool u128_hibit(u128 const &d) { return (d.hi & BIT128_U64_HIGHBIT) != 0; }
|
||||||
|
bool i128_hibit(i128 const &d) { return d.hi < 0; }
|
||||||
|
|
||||||
void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) {
|
void u128_divide(u128 a, u128 b, u128 *quo, u128 *rem) {
|
||||||
if (u128_eq(den, U128_ZERO)) {
|
if (u128_eq(b, U128_ZERO)) {
|
||||||
if (quo) *quo = u128_from_u64(num.lo/den.lo);
|
if (quo) *quo = u128_from_u64(a.lo/b.lo);
|
||||||
if (rem) *rem = U128_ZERO;
|
if (rem) *rem = U128_ZERO;
|
||||||
} else {
|
return;
|
||||||
u128 n = num;
|
|
||||||
u128 d = den;
|
|
||||||
u128 x = U128_ONE;
|
|
||||||
u128 r = U128_ZERO;
|
|
||||||
|
|
||||||
while (u128_ge(n, d) && !u128_hibit(&d)) {
|
|
||||||
x = u128_shl(x, 1);
|
|
||||||
d = u128_shl(d, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (u128_ne(x, U128_ZERO)) {
|
|
||||||
if (u128_ge(n, d)) {
|
|
||||||
n = u128_sub(n, d);
|
|
||||||
r = u128_or(r, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
x = u128_shr(x, 1);
|
|
||||||
d = u128_shr(d, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (quo) *quo = r;
|
|
||||||
if (rem) *rem = n;
|
|
||||||
}
|
}
|
||||||
|
u128 r = a;
|
||||||
|
u128 d = b;
|
||||||
|
u128 x = U128_ONE;
|
||||||
|
u128 q = U128_ZERO;
|
||||||
|
|
||||||
|
while (u128_ge(r, d) && !u128_hibit(d)) {
|
||||||
|
x = u128_shl(x, 1);
|
||||||
|
d = u128_shl(d, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (u128_ne(x, U128_ZERO)) {
|
||||||
|
if (u128_ge(r, d)) {
|
||||||
|
r = u128_sub(r, d);
|
||||||
|
q = u128_or(q, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
x = u128_shr(x, 1);
|
||||||
|
d = u128_shr(d, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quo) *quo = q;
|
||||||
|
if (rem) *rem = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
u128 u128_quo(u128 a, u128 b) {
|
u128 u128_quo(u128 a, u128 b) {
|
||||||
@@ -668,50 +669,62 @@ i128 i128_mul(i128 a, i128 b) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void i128_divide(i128 a, i128 b, i128 *quo, i128 *rem) {
|
void i128_divide(i128 a, i128 b, i128 *quo_, i128 *rem_) {
|
||||||
// TODO(bill): Which one is correct?!
|
// TODO(bill): Optimize this i128 division calculation
|
||||||
#if 1
|
i128 iquo = {0};
|
||||||
i128 s = i128_shr(b, 127);
|
i128 irem = {0};
|
||||||
b = i128_sub(i128_xor(b, s), s);
|
if (a.hi == 0 && b.hi == 0) {
|
||||||
s = i128_shr(a, 127);
|
u64 q = a.lo / b.lo;
|
||||||
b = i128_sub(i128_xor(a, s), s);
|
u64 r = a.lo % b.lo;
|
||||||
|
iquo = i128_from_u64(q);
|
||||||
u128 n, r = {0};
|
irem = i128_from_u64(r);
|
||||||
u128_divide(*cast(u128 *)&a, *cast(u128 *)&b, &n, &r);
|
} else if ((~a.hi) == 0 && (~b.hi) == 0) {
|
||||||
i128 ni = *cast(i128 *)&n;
|
i64 x = i128_to_i64(a);
|
||||||
i128 ri = *cast(i128 *)&r;
|
i64 y = i128_to_i64(b);
|
||||||
|
i64 q = x / y;
|
||||||
if (quo) *quo = i128_sub(i128_xor(ni, s), s);
|
i64 r = x % y;
|
||||||
if (rem) *rem = i128_sub(i128_xor(ri, s), s);
|
iquo = i128_from_i64(q);
|
||||||
#else
|
irem = i128_from_i64(r);
|
||||||
if (i128_eq(b, I128_ZERO)) {
|
} else if (a.hi > 0 || b.hi > 0) {
|
||||||
if (quo) *quo = i128_from_u64(a.lo/b.lo);
|
u128 q, r = {0};
|
||||||
if (rem) *rem = I128_ZERO;
|
u128_divide(*cast(u128 *)&a, *cast(u128 *)&b, &q, &r);
|
||||||
|
iquo = *cast(i128 *)&q;
|
||||||
|
irem = *cast(i128 *)&r;
|
||||||
|
} else if (i128_eq(b, I128_ZERO)) {
|
||||||
|
iquo = i128_from_u64(a.lo/b.lo);
|
||||||
} else {
|
} else {
|
||||||
i128 n = a;
|
i32 rem_sign = 1;
|
||||||
i128 d = b;
|
i32 quo_sign = 1;
|
||||||
i128 x = I128_ONE;
|
if (i128_lt(a, I128_ZERO)) {
|
||||||
i128 r = I128_ZERO;
|
a = i128_neg(a);
|
||||||
|
rem_sign = -1;
|
||||||
while (i128_ge(n, d) && ((i128_shr(d, 128-1).lo&1) == 0)) {
|
|
||||||
x = i128_shl(x, 1);
|
|
||||||
d = i128_shl(d, 1);
|
|
||||||
}
|
}
|
||||||
|
if (i128_lt(b, I128_ZERO)) {
|
||||||
|
b = i128_neg(b);
|
||||||
|
quo_sign = -1;
|
||||||
|
}
|
||||||
|
quo_sign *= rem_sign;
|
||||||
|
|
||||||
while (i128_ne(x, I128_ZERO)) {
|
iquo = a;
|
||||||
if (i128_ge(n, d)) {
|
|
||||||
n = i128_sub(n, d);
|
for (isize i = 0; i < 128; i++) {
|
||||||
r = i128_or(r, x);
|
irem = i128_shl(irem, 1);
|
||||||
|
if (i128_lt(iquo, I128_ZERO)) {
|
||||||
|
irem.lo |= 1;
|
||||||
|
}
|
||||||
|
iquo = i128_shl(iquo, 1);
|
||||||
|
if (i128_ge(irem, b)) {
|
||||||
|
irem = i128_sub(irem, b);
|
||||||
|
iquo = i128_add(iquo, I128_ONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
x = i128_shr(x, 1);
|
|
||||||
d = i128_shr(d, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quo) *quo = r;
|
if (quo_sign < 0) iquo = i128_neg(iquo);
|
||||||
if (rem) *rem = n;
|
if (rem_sign < 0) irem = i128_neg(irem);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
if (quo_) *quo_ = iquo;
|
||||||
|
if (rem_) *rem_ = irem;
|
||||||
}
|
}
|
||||||
|
|
||||||
i128 i128_quo(i128 a, i128 b) {
|
i128 i128_quo(i128 a, i128 b) {
|
||||||
|
|||||||
+1610
-1126
File diff suppressed because it is too large
Load Diff
+292
-167
@@ -139,6 +139,49 @@ void ir_print_escape_string(irFileBuffer *f, String name, bool print_quotes, boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ir_print_escape_path(irFileBuffer *f, String path) {
|
||||||
|
isize extra = 0;
|
||||||
|
for (isize i = 0; i < path.len; i++) {
|
||||||
|
u8 c = path[i];
|
||||||
|
if (!ir_valid_char(c)) {
|
||||||
|
extra += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extra == 0) {
|
||||||
|
ir_write_string(f, path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char hex_table[] = "0123456789ABCDEF";
|
||||||
|
isize buf_len = path.len + extra + 2 + 1;
|
||||||
|
|
||||||
|
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
|
||||||
|
|
||||||
|
u8 *buf = gb_alloc_array(string_buffer_allocator, u8, buf_len);
|
||||||
|
|
||||||
|
isize j = 0;
|
||||||
|
|
||||||
|
for (isize i = 0; i < path.len; i++) {
|
||||||
|
u8 c = path[i];
|
||||||
|
if (ir_valid_char(c) || c == ':') {
|
||||||
|
buf[j++] = c;
|
||||||
|
} else if (c == '\\') {
|
||||||
|
buf[j++] = '/';
|
||||||
|
} else {
|
||||||
|
buf[j] = '\\';
|
||||||
|
buf[j+1] = hex_table[c >> 4];
|
||||||
|
buf[j+2] = hex_table[c & 0x0f];
|
||||||
|
j += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ir_file_write(f, buf, j);
|
||||||
|
|
||||||
|
gb_temp_arena_memory_end(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ir_print_encoded_local(irFileBuffer *f, String name) {
|
void ir_print_encoded_local(irFileBuffer *f, String name) {
|
||||||
ir_write_byte(f, '%');
|
ir_write_byte(f, '%');
|
||||||
@@ -151,6 +194,8 @@ void ir_print_encoded_global(irFileBuffer *f, String name, bool remove_prefix) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ir_print_type(irFileBuffer *f, irModule *m, Type *t);
|
void ir_print_type(irFileBuffer *f, irModule *m, Type *t);
|
||||||
|
void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hint);
|
||||||
|
|
||||||
|
|
||||||
void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
|
void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
|
||||||
GB_ASSERT(is_type_proc(t));
|
GB_ASSERT(is_type_proc(t));
|
||||||
@@ -243,14 +288,15 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
case Basic_f64: ir_write_string(f, "double"); return;
|
case Basic_f64: ir_write_string(f, "double"); return;
|
||||||
|
|
||||||
// case Basic_complex32: ir_write_string(f, "%%..complex32"); return;
|
// case Basic_complex32: ir_write_string(f, "%%..complex32"); return;
|
||||||
case Basic_complex64: ir_write_string(f, "%..complex64"); return;
|
case Basic_complex64: ir_write_string(f, "%..complex64"); return;
|
||||||
case Basic_complex128: ir_write_string(f, "%..complex128"); return;
|
case Basic_complex128: ir_write_string(f, "%..complex128"); return;
|
||||||
|
|
||||||
case Basic_rawptr: ir_write_string(f, "%..rawptr"); return;
|
case Basic_rawptr: ir_write_string(f, "%..rawptr"); return;
|
||||||
case Basic_string: ir_write_string(f, "%..string"); return;
|
case Basic_string: ir_write_string(f, "%..string"); return;
|
||||||
case Basic_uint: ir_fprintf(f, "i%lld", word_bits); return;
|
case Basic_uint: ir_fprintf(f, "i%lld", word_bits); return;
|
||||||
case Basic_int: ir_fprintf(f, "i%lld", word_bits); return;
|
case Basic_int: ir_fprintf(f, "i%lld", word_bits); return;
|
||||||
case Basic_any: ir_write_string(f, "%..any"); return;
|
case Basic_uintptr: ir_fprintf(f, "i%lld", word_bits); return;
|
||||||
|
case Basic_any: ir_write_string(f, "%..any"); return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Type_Pointer: {
|
case Type_Pointer: {
|
||||||
@@ -303,7 +349,8 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
|
|
||||||
ir_fprintf(f, "{[0 x <%lld x i8>], ", align);
|
ir_fprintf(f, "{[0 x <%lld x i8>], ", align);
|
||||||
ir_fprintf(f, "[%lld x i8], ", block_size);
|
ir_fprintf(f, "[%lld x i8], ", block_size);
|
||||||
ir_print_type(f, m, t_type_info_ptr);
|
// ir_print_type(f, m, t_type_info_ptr);
|
||||||
|
ir_print_type(f, m, union_tag_type(t));
|
||||||
ir_write_byte(f, '}');
|
ir_write_byte(f, '}');
|
||||||
}
|
}
|
||||||
} return;
|
} return;
|
||||||
@@ -339,17 +386,26 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
case Type_Named:
|
case Type_Named:
|
||||||
switch (base_type(t)->kind) {
|
switch (base_type(t)->kind) {
|
||||||
case Type_Struct:
|
case Type_Struct:
|
||||||
case Type_Union: {
|
case Type_Union: {
|
||||||
String *name = map_get(&m->entity_names, hash_pointer(t->Named.type_name));
|
GB_ASSERT(t->Named.type_name != nullptr);
|
||||||
GB_ASSERT_MSG(name != nullptr, "%.*s %p", LIT(t->Named.name), t->Named.type_name);
|
String *found = map_get(&m->entity_names, hash_entity(t->Named.type_name));
|
||||||
ir_print_encoded_local(f, *name);
|
if (found) {
|
||||||
} break;
|
ir_print_encoded_local(f, *found);
|
||||||
|
} else {
|
||||||
|
// TODO(bill): Is this correct behaviour?!
|
||||||
|
GB_ASSERT_MSG(found != nullptr, "%.*s %p", LIT(t->Named.name), t->Named.type_name);
|
||||||
|
// gb_printf_err("%.*s %p\n", LIT(t->Named.name), t->Named.type_name);
|
||||||
|
ir_print_type(f, m, base_type(t));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
ir_print_type(f, m, base_type(t));
|
ir_print_type(f, m, base_type(t));
|
||||||
break;
|
break;
|
||||||
@@ -381,13 +437,15 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
generate_map_internal_types(m->allocator, t);
|
generate_map_internal_types(m->allocator, t);
|
||||||
GB_ASSERT(t->Map.generated_struct_type != nullptr);
|
GB_ASSERT(t->Map.generated_struct_type != nullptr);
|
||||||
ir_print_type(f, m, t->Map.generated_struct_type);
|
ir_print_type(f, m, t->Map.generated_struct_type);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Type_BitField: {
|
case Type_BitField: {
|
||||||
i64 align = type_align_of(heap_allocator(), t);
|
i64 align = type_align_of(heap_allocator(), t);
|
||||||
i64 size = type_size_of(heap_allocator(), t);
|
i64 size = type_size_of(heap_allocator(), t);
|
||||||
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align, size);
|
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align, size);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,7 +455,7 @@ void ir_print_compound_element(irFileBuffer *f, irModule *m, ExactValue v, Type
|
|||||||
ir_print_type(f, m, elem_type);
|
ir_print_type(f, m, elem_type);
|
||||||
ir_write_byte(f, ' ');
|
ir_write_byte(f, ' ');
|
||||||
|
|
||||||
if (v.kind == ExactValue_Invalid || base_type(elem_type) == t_any) {
|
if (v.kind == ExactValue_Invalid || !elem_type_can_be_constant(elem_type)) {
|
||||||
if (ir_type_has_default_values(elem_type)) {
|
if (ir_type_has_default_values(elem_type)) {
|
||||||
ir_print_exact_value(f, m, v, elem_type);
|
ir_print_exact_value(f, m, v, elem_type);
|
||||||
} else {
|
} else {
|
||||||
@@ -409,6 +467,7 @@ void ir_print_compound_element(irFileBuffer *f, irModule *m, ExactValue v, Type
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type) {
|
void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type) {
|
||||||
|
Type *original_type = type;
|
||||||
type = core_type(type);
|
type = core_type(type);
|
||||||
value = convert_exact_value_for_type(value, type);
|
value = convert_exact_value_for_type(value, type);
|
||||||
|
|
||||||
@@ -447,7 +506,8 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
ir_print_type(f, m, t_int);
|
ir_print_type(f, m, t_int);
|
||||||
ir_fprintf(f, " %lld}", cast(i64)str.len);
|
ir_fprintf(f, " %lld}", cast(i64)str.len);
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
case ExactValue_Integer: {
|
case ExactValue_Integer: {
|
||||||
if (is_type_pointer(type)) {
|
if (is_type_pointer(type)) {
|
||||||
if (i128_eq(value.value_integer, I128_ZERO)) {
|
if (i128_eq(value.value_integer, I128_ZERO)) {
|
||||||
@@ -464,7 +524,8 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
} else {
|
} else {
|
||||||
ir_write_i128(f, value.value_integer);
|
ir_write_i128(f, value.value_integer);
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
case ExactValue_Float: {
|
case ExactValue_Float: {
|
||||||
GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type));
|
GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type));
|
||||||
type = core_type(type);
|
type = core_type(type);
|
||||||
@@ -493,7 +554,8 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
ir_fprintf(f, "0x%016llx", u);
|
ir_fprintf(f, "0x%016llx", u);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ExactValue_Complex: {
|
case ExactValue_Complex: {
|
||||||
type = core_type(type);
|
type = core_type(type);
|
||||||
@@ -506,7 +568,8 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
ir_write_string(f, str_lit(", ")); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
|
ir_write_string(f, str_lit(", ")); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
|
||||||
ir_print_exact_value(f, m, exact_value_float(value.value_complex.imag), ft);
|
ir_print_exact_value(f, m, exact_value_float(value.value_complex.imag), ft);
|
||||||
ir_write_byte(f, '}');
|
ir_write_byte(f, '}');
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ExactValue_Pointer:
|
case ExactValue_Pointer:
|
||||||
if (value.value_pointer == 0) {
|
if (value.value_pointer == 0) {
|
||||||
@@ -522,7 +585,10 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
|
|
||||||
case ExactValue_Compound: {
|
case ExactValue_Compound: {
|
||||||
type = base_type(type);
|
type = base_type(type);
|
||||||
if (is_type_array(type)) {
|
if (is_type_slice(type)) {
|
||||||
|
irValue *s = ir_add_module_constant(m, type, value);
|
||||||
|
ir_print_value(f, m, s, type);
|
||||||
|
} else if (is_type_array(type)) {
|
||||||
ast_node(cl, CompoundLit, value.value_compound);
|
ast_node(cl, CompoundLit, value.value_compound);
|
||||||
|
|
||||||
Type *elem_type = type->Array.elem;
|
Type *elem_type = type->Array.elem;
|
||||||
@@ -591,6 +657,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
ir_write_string(f, "]}");
|
ir_write_string(f, "]}");
|
||||||
} else if (is_type_struct(type)) {
|
} else if (is_type_struct(type)) {
|
||||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
|
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
|
||||||
|
defer (gb_temp_arena_memory_end(tmp));
|
||||||
|
|
||||||
ast_node(cl, CompoundLit, value.value_compound);
|
ast_node(cl, CompoundLit, value.value_compound);
|
||||||
|
|
||||||
@@ -600,6 +667,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String tstr = make_string_c(type_to_string(original_type));
|
||||||
|
|
||||||
isize value_count = type->Struct.fields.count;
|
isize value_count = type->Struct.fields.count;
|
||||||
ExactValue *values = gb_alloc_array(m->tmp_allocator, ExactValue, value_count);
|
ExactValue *values = gb_alloc_array(m->tmp_allocator, ExactValue, value_count);
|
||||||
@@ -629,7 +697,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
if (tav.mode != Addressing_Invalid) {
|
if (tav.mode != Addressing_Invalid) {
|
||||||
val = tav.value;
|
val = tav.value;
|
||||||
}
|
}
|
||||||
values[f->Variable.field_index] = val;
|
values[f->Variable.field_index] = val;
|
||||||
visited[f->Variable.field_index] = true;
|
visited[f->Variable.field_index] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -672,13 +740,31 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
|
|
||||||
ir_write_byte(f, '}');
|
ir_write_byte(f, '}');
|
||||||
if (type->Struct.is_packed) ir_write_byte(f, '>');
|
if (type->Struct.is_packed) ir_write_byte(f, '>');
|
||||||
|
|
||||||
gb_temp_arena_memory_end(tmp);
|
|
||||||
} else {
|
} else {
|
||||||
ir_write_string(f, "zeroinitializer");
|
ir_write_string(f, "zeroinitializer");
|
||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ExactValue_Procedure: {
|
||||||
|
irValue **found = nullptr;
|
||||||
|
AstNode *expr = value.value_procedure;
|
||||||
|
GB_ASSERT(expr != nullptr);
|
||||||
|
|
||||||
|
if (expr->kind == AstNode_ProcLit) {
|
||||||
|
found = map_get(&m->anonymous_proc_lits, hash_pointer(expr));
|
||||||
|
} else {
|
||||||
|
GB_ASSERT(expr->kind == AstNode_Ident);
|
||||||
|
Entity *e = entity_of_ident(m->info, expr);
|
||||||
|
GB_ASSERT(e != nullptr);
|
||||||
|
found = map_get(&m->values, hash_entity(e));
|
||||||
|
}
|
||||||
|
GB_ASSERT(found != nullptr);
|
||||||
|
irValue *val = *found;
|
||||||
|
ir_print_value(f, m, val, type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
bool has_defaults = ir_type_has_default_values(type);
|
bool has_defaults = ir_type_has_default_values(type);
|
||||||
@@ -734,7 +820,8 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// GB_PANIC("Invalid ExactValue: %d", value.kind);
|
// GB_PANIC("Invalid ExactValue: %d", value.kind);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -759,7 +846,7 @@ bool ir_print_is_proc_global(irModule *m, irProcedure *proc) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (proc->tags & (ProcTag_foreign|ProcTag_export)) != 0;
|
return proc->is_foreign || proc->is_export;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hint) {
|
void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hint) {
|
||||||
@@ -797,7 +884,8 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
|
|||||||
ir_print_type(f, m, t_int);
|
ir_print_type(f, m, t_int);
|
||||||
ir_fprintf(f, " %lld}", cs->count);
|
ir_fprintf(f, " %lld}", cs->count);
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irValue_Nil:
|
case irValue_Nil:
|
||||||
ir_write_string(f, "zeroinitializer");
|
ir_write_string(f, "zeroinitializer");
|
||||||
@@ -819,7 +907,8 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
|
|||||||
in_global_scope = scope->is_global || scope->is_init;
|
in_global_scope = scope->is_global || scope->is_init;
|
||||||
}
|
}
|
||||||
ir_print_encoded_global(f, ir_get_global_name(m, value), in_global_scope);
|
ir_print_encoded_global(f, ir_get_global_name(m, value), in_global_scope);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
case irValue_Param:
|
case irValue_Param:
|
||||||
ir_print_encoded_local(f, value->Param.entity->token.string);
|
ir_print_encoded_local(f, value->Param.entity->token.string);
|
||||||
break;
|
break;
|
||||||
@@ -836,9 +925,9 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
|
|||||||
switch (cc) {
|
switch (cc) {
|
||||||
case ProcCC_Odin: ir_write_string(f, ""); break;
|
case ProcCC_Odin: ir_write_string(f, ""); break;
|
||||||
case ProcCC_Contextless: ir_write_string(f, ""); break;
|
case ProcCC_Contextless: ir_write_string(f, ""); break;
|
||||||
case ProcCC_C: ir_write_string(f, "ccc "); break;
|
case ProcCC_CDecl: ir_write_string(f, "ccc "); break;
|
||||||
case ProcCC_Std: ir_write_string(f, "cc 64 "); break;
|
case ProcCC_StdCall: ir_write_string(f, "cc 64 "); break;
|
||||||
case ProcCC_Fast: ir_write_string(f, "cc 65 "); break;
|
case ProcCC_FastCall: ir_write_string(f, "cc 65 "); break;
|
||||||
default: GB_PANIC("unknown calling convention: %d", cc);
|
default: GB_PANIC("unknown calling convention: %d", cc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -853,13 +942,15 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
default: {
|
default: {
|
||||||
GB_PANIC("<unknown instr> %d\n", instr->kind);
|
GB_PANIC("<unknown instr> %d\n", instr->kind);
|
||||||
ir_fprintf(f, "; <unknown instr> %d\n", instr->kind);
|
ir_fprintf(f, "; <unknown instr> %d\n", instr->kind);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_StartupRuntime: {
|
case irInstr_StartupRuntime: {
|
||||||
ir_write_string(f, "call void ");
|
ir_write_string(f, "call void ");
|
||||||
ir_print_encoded_global(f, str_lit(IR_STARTUP_RUNTIME_PROC_NAME), false);
|
ir_print_encoded_global(f, str_lit(IR_STARTUP_RUNTIME_PROC_NAME), false);
|
||||||
ir_write_string(f, "()\n");
|
ir_write_string(f, "()\n");
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_Comment:
|
case irInstr_Comment:
|
||||||
ir_write_string(f, "; ");
|
ir_write_string(f, "; ");
|
||||||
@@ -876,7 +967,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_fprintf(f, "%%%d = alloca ", value->index);
|
ir_fprintf(f, "%%%d = alloca ", value->index);
|
||||||
ir_print_type(f, m, type);
|
ir_print_type(f, m, type);
|
||||||
ir_fprintf(f, ", align %lld\n", align);
|
ir_fprintf(f, ", align %lld\n", align);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_ZeroInit: {
|
case irInstr_ZeroInit: {
|
||||||
Type *type = type_deref(ir_type(instr->ZeroInit.address));
|
Type *type = type_deref(ir_type(instr->ZeroInit.address));
|
||||||
@@ -887,7 +979,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_write_string(f, str_lit(", "));
|
ir_write_string(f, str_lit(", "));
|
||||||
ir_print_type(f, m, type);
|
ir_print_type(f, m, type);
|
||||||
ir_fprintf(f, "* %%%d\n", instr->ZeroInit.address->index);
|
ir_fprintf(f, "* %%%d\n", instr->ZeroInit.address->index);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_Store: {
|
case irInstr_Store: {
|
||||||
Type *type = type_deref(ir_type(instr->Store.address));
|
Type *type = type_deref(ir_type(instr->Store.address));
|
||||||
@@ -900,7 +993,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_write_string(f, "* ");
|
ir_write_string(f, "* ");
|
||||||
ir_print_value(f, m, instr->Store.address, type);
|
ir_print_value(f, m, instr->Store.address, type);
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_Load: {
|
case irInstr_Load: {
|
||||||
Type *type = instr->Load.type;
|
Type *type = instr->Load.type;
|
||||||
@@ -911,7 +1005,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_write_string(f, "* ");
|
ir_write_string(f, "* ");
|
||||||
ir_print_value(f, m, instr->Load.address, type);
|
ir_print_value(f, m, instr->Load.address, type);
|
||||||
ir_fprintf(f, ", align %lld\n", type_align_of(m->allocator, type));
|
ir_fprintf(f, ", align %lld\n", type_align_of(m->allocator, type));
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_ArrayElementPtr: {
|
case irInstr_ArrayElementPtr: {
|
||||||
Type *et = ir_type(instr->ArrayElementPtr.address);
|
Type *et = ir_type(instr->ArrayElementPtr.address);
|
||||||
@@ -936,7 +1031,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_write_byte(f, ' ');
|
ir_write_byte(f, ' ');
|
||||||
ir_print_value(f, m, index, t);
|
ir_print_value(f, m, index, t);
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_StructElementPtr: {
|
case irInstr_StructElementPtr: {
|
||||||
Type *et = ir_type(instr->StructElementPtr.address);
|
Type *et = ir_type(instr->StructElementPtr.address);
|
||||||
@@ -962,7 +1058,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_print_type(f, m, t_i32);
|
ir_print_type(f, m, t_i32);
|
||||||
ir_fprintf(f, " %d", index);
|
ir_fprintf(f, " %d", index);
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_PtrOffset: {
|
case irInstr_PtrOffset: {
|
||||||
Type *pt = ir_type(instr->PtrOffset.address);
|
Type *pt = ir_type(instr->PtrOffset.address);
|
||||||
@@ -980,7 +1077,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_write_byte(f, ' ');
|
ir_write_byte(f, ' ');
|
||||||
ir_print_value(f, m, offset, t);
|
ir_print_value(f, m, offset, t);
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_Phi: {
|
case irInstr_Phi: {
|
||||||
ir_fprintf(f, "%%%d = phi ", value->index);
|
ir_fprintf(f, "%%%d = phi ", value->index);
|
||||||
@@ -1007,7 +1105,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_write_string(f, " ]");
|
ir_write_string(f, " ]");
|
||||||
}
|
}
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_StructExtractValue: {
|
case irInstr_StructExtractValue: {
|
||||||
Type *et = ir_type(instr->StructExtractValue.address);
|
Type *et = ir_type(instr->StructExtractValue.address);
|
||||||
@@ -1027,7 +1126,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_write_byte(f, ' ');
|
ir_write_byte(f, ' ');
|
||||||
ir_print_value(f, m, instr->StructExtractValue.address, et);
|
ir_print_value(f, m, instr->StructExtractValue.address, et);
|
||||||
ir_fprintf(f, ", %d\n", index);
|
ir_fprintf(f, ", %d\n", index);
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_UnionTagPtr: {
|
case irInstr_UnionTagPtr: {
|
||||||
Type *et = ir_type(instr->UnionTagPtr.address);
|
Type *et = ir_type(instr->UnionTagPtr.address);
|
||||||
@@ -1045,13 +1145,14 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_write_string(f, " 0, ");
|
ir_write_string(f, " 0, ");
|
||||||
ir_print_type(f, m, t_i32);
|
ir_print_type(f, m, t_i32);
|
||||||
#if 1
|
#if 1
|
||||||
ir_fprintf(f, " %d", 2);
|
ir_fprintf(f, " 2");
|
||||||
#else
|
#else
|
||||||
ir_fprintf(f, " %d", 2);
|
ir_fprintf(f, " %d", 2);
|
||||||
#endif
|
#endif
|
||||||
ir_write_string(f, " ; UnionTagPtr");
|
ir_write_string(f, " ; UnionTagPtr");
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_UnionTagValue: {
|
case irInstr_UnionTagValue: {
|
||||||
Type *et = ir_type(instr->UnionTagValue.address);
|
Type *et = ir_type(instr->UnionTagValue.address);
|
||||||
@@ -1064,20 +1165,21 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_print_value(f, m, instr->UnionTagValue.address, et);
|
ir_print_value(f, m, instr->UnionTagValue.address, et);
|
||||||
ir_write_byte(f, ',');
|
ir_write_byte(f, ',');
|
||||||
#if 1
|
#if 1
|
||||||
ir_fprintf(f, " %d", 2);
|
ir_fprintf(f, " 2");
|
||||||
#else
|
#else
|
||||||
ir_fprintf(f, " %d", 2);
|
ir_fprintf(f, " %d", 2);
|
||||||
#endif
|
#endif
|
||||||
ir_fprintf(f, ", %d", 2);
|
|
||||||
ir_write_string(f, " ; UnionTagValue");
|
ir_write_string(f, " ; UnionTagValue");
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_Jump: {;
|
case irInstr_Jump: {;
|
||||||
ir_write_string(f, "br label %");
|
ir_write_string(f, "br label %");
|
||||||
ir_print_block_name(f, instr->Jump.block);
|
ir_print_block_name(f, instr->Jump.block);
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_If: {;
|
case irInstr_If: {;
|
||||||
ir_write_string(f, "br ");
|
ir_write_string(f, "br ");
|
||||||
@@ -1088,7 +1190,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_write_string(f, "label %"); ir_print_block_name(f, instr->If.true_block);
|
ir_write_string(f, "label %"); ir_print_block_name(f, instr->If.true_block);
|
||||||
ir_write_string(f, ", label %"); ir_print_block_name(f, instr->If.false_block);
|
ir_write_string(f, ", label %"); ir_print_block_name(f, instr->If.false_block);
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_Return: {
|
case irInstr_Return: {
|
||||||
irInstrReturn *ret = &instr->Return;
|
irInstrReturn *ret = &instr->Return;
|
||||||
@@ -1104,7 +1207,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
|
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
|
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_Conv: {
|
case irInstr_Conv: {
|
||||||
irInstrConv *c = &instr->Conv;
|
irInstrConv *c = &instr->Conv;
|
||||||
@@ -1116,11 +1220,13 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_print_type(f, m, c->to);
|
ir_print_type(f, m, c->to);
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
|
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_Unreachable: {
|
case irInstr_Unreachable: {
|
||||||
ir_fprintf(f, "unreachable\n");
|
ir_fprintf(f, "unreachable\n");
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_UnaryOp: {
|
case irInstr_UnaryOp: {
|
||||||
irInstrUnaryOp *uo = &value->Instr.UnaryOp;
|
irInstrUnaryOp *uo = &value->Instr.UnaryOp;
|
||||||
@@ -1169,7 +1275,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_write_string(f, str_lit(", "));
|
ir_write_string(f, str_lit(", "));
|
||||||
ir_print_value(f, m, uo->expr, type);
|
ir_print_value(f, m, uo->expr, type);
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_BinaryOp: {
|
case irInstr_BinaryOp: {
|
||||||
irInstrBinaryOp *bo = &value->Instr.BinaryOp;
|
irInstrBinaryOp *bo = &value->Instr.BinaryOp;
|
||||||
@@ -1181,32 +1288,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
|
|
||||||
if (gb_is_between(bo->op, Token__ComparisonBegin+1, Token__ComparisonEnd-1)) {
|
if (gb_is_between(bo->op, Token__ComparisonBegin+1, Token__ComparisonEnd-1)) {
|
||||||
if (is_type_string(elem_type)) {
|
if (is_type_string(elem_type)) {
|
||||||
ir_write_string(f, "call ");
|
GB_PANIC("Unhandled string type");
|
||||||
ir_print_calling_convention(f, m, ProcCC_Odin);
|
|
||||||
ir_print_type(f, m, t_bool);
|
|
||||||
char *runtime_proc = "";
|
|
||||||
switch (bo->op) {
|
|
||||||
case Token_CmpEq: runtime_proc = "__string_eq"; break;
|
|
||||||
case Token_NotEq: runtime_proc = "__string_ne"; break;
|
|
||||||
case Token_Lt: runtime_proc = "__string_lt"; break;
|
|
||||||
case Token_Gt: runtime_proc = "__string_gt"; break;
|
|
||||||
case Token_LtEq: runtime_proc = "__string_le"; break;
|
|
||||||
case Token_GtEq: runtime_proc = "__string_gt"; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ir_write_byte(f, ' ');
|
|
||||||
ir_print_encoded_global(f, make_string_c(runtime_proc), false);
|
|
||||||
ir_write_byte(f, '(');
|
|
||||||
ir_print_type(f, m, type);
|
|
||||||
ir_write_byte(f, ' ');
|
|
||||||
ir_print_value(f, m, bo->left, type);
|
|
||||||
ir_write_string(f, str_lit(", "));
|
|
||||||
ir_print_type(f, m, type);
|
|
||||||
ir_write_byte(f, ' ');
|
|
||||||
ir_print_value(f, m, bo->right, type);
|
|
||||||
ir_write_string(f, ")\n");
|
|
||||||
return;
|
|
||||||
|
|
||||||
} else if (is_type_float(elem_type)) {
|
} else if (is_type_float(elem_type)) {
|
||||||
ir_write_string(f, "fcmp ");
|
ir_write_string(f, "fcmp ");
|
||||||
switch (bo->op) {
|
switch (bo->op) {
|
||||||
@@ -1218,37 +1300,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
case Token_GtEq: ir_write_string(f, "oge"); break;
|
case Token_GtEq: ir_write_string(f, "oge"); break;
|
||||||
}
|
}
|
||||||
} else if (is_type_complex(elem_type)) {
|
} else if (is_type_complex(elem_type)) {
|
||||||
ir_write_string(f, "call ");
|
GB_PANIC("Unhandled complex type");
|
||||||
ir_print_calling_convention(f, m, ProcCC_Odin);
|
|
||||||
ir_print_type(f, m, t_bool);
|
|
||||||
char *runtime_proc = "";
|
|
||||||
i64 sz = 8*type_size_of(m->allocator, elem_type);
|
|
||||||
switch (sz) {
|
|
||||||
case 64:
|
|
||||||
switch (bo->op) {
|
|
||||||
case Token_CmpEq: runtime_proc = "__complex64_eq"; break;
|
|
||||||
case Token_NotEq: runtime_proc = "__complex64_ne"; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 128:
|
|
||||||
switch (bo->op) {
|
|
||||||
case Token_CmpEq: runtime_proc = "__complex128_eq"; break;
|
|
||||||
case Token_NotEq: runtime_proc = "__complex128_ne"; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ir_write_byte(f, ' ');
|
|
||||||
ir_print_encoded_global(f, make_string_c(runtime_proc), false);
|
|
||||||
ir_write_byte(f, '(');
|
|
||||||
ir_print_type(f, m, type);
|
|
||||||
ir_write_byte(f, ' ');
|
|
||||||
ir_print_value(f, m, bo->left, type);
|
|
||||||
ir_write_string(f, str_lit(", "));
|
|
||||||
ir_print_type(f, m, type);
|
|
||||||
ir_write_byte(f, ' ');
|
|
||||||
ir_print_value(f, m, bo->right, type);
|
|
||||||
ir_write_string(f, ")\n");
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
ir_write_string(f, "icmp ");
|
ir_write_string(f, "icmp ");
|
||||||
@@ -1301,7 +1353,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
case Token_Quo: ir_write_string(f, "div"); break;
|
case Token_Quo: ir_write_string(f, "div"); break;
|
||||||
case Token_Mod: ir_write_string(f, "rem"); break;
|
case Token_Mod: ir_write_string(f, "rem"); break;
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1312,7 +1365,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_write_string(f, str_lit(", "));
|
ir_write_string(f, str_lit(", "));
|
||||||
ir_print_value(f, m, bo->right, type);
|
ir_print_value(f, m, bo->right, type);
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_Call: {
|
case irInstr_Call: {
|
||||||
irInstrCall *call = &instr->Call;
|
irInstrCall *call = &instr->Call;
|
||||||
@@ -1409,9 +1463,16 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_write_string(f, " noalias nonnull ");
|
ir_write_string(f, " noalias nonnull ");
|
||||||
ir_print_value(f, m, call->context_ptr, t_context_ptr);
|
ir_print_value(f, m, call->context_ptr, t_context_ptr);
|
||||||
}
|
}
|
||||||
ir_write_string(f, ")\n");
|
ir_write_string(f, ")");
|
||||||
|
|
||||||
} break;
|
if (m->generate_debug_info && call->debug_location) {
|
||||||
|
ir_fprintf(f, ", !dbg !%d", call->debug_location->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ir_write_string(f, "\n");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_Select: {
|
case irInstr_Select: {
|
||||||
ir_fprintf(f, "%%%d = select i1 ", value->index);
|
ir_fprintf(f, "%%%d = select i1 ", value->index);
|
||||||
@@ -1425,7 +1486,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_write_byte(f, ' ');
|
ir_write_byte(f, ' ');
|
||||||
ir_print_value(f, m, instr->Select.false_value, ir_type(instr->Select.false_value));
|
ir_print_value(f, m, instr->Select.false_value, ir_type(instr->Select.false_value));
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// case irInstr_VectorExtractElement: {
|
// case irInstr_VectorExtractElement: {
|
||||||
// Type *vt = ir_type(instr->VectorExtractElement.vector);
|
// Type *vt = ir_type(instr->VectorExtractElement.vector);
|
||||||
@@ -1440,7 +1502,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
// ir_write_byte(f, ' ');
|
// ir_write_byte(f, ' ');
|
||||||
// ir_print_value(f, m, instr->VectorExtractElement.index, it);
|
// ir_print_value(f, m, instr->VectorExtractElement.index, it);
|
||||||
// ir_write_byte(f, '\n');
|
// ir_write_byte(f, '\n');
|
||||||
// } break;
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
// case irInstr_VectorInsertElement: {
|
// case irInstr_VectorInsertElement: {
|
||||||
// irInstrVectorInsertElement *ie = &instr->VectorInsertElement;
|
// irInstrVectorInsertElement *ie = &instr->VectorInsertElement;
|
||||||
@@ -1462,7 +1525,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
// ir_print_value(f, m, ie->index, ir_type(ie->index));
|
// ir_print_value(f, m, ie->index, ir_type(ie->index));
|
||||||
|
|
||||||
// ir_write_byte(f, '\n');
|
// ir_write_byte(f, '\n');
|
||||||
// } break;
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
// case irInstr_VectorShuffle: {
|
// case irInstr_VectorShuffle: {
|
||||||
// irInstrVectorShuffle *sv = &instr->VectorShuffle;
|
// irInstrVectorShuffle *sv = &instr->VectorShuffle;
|
||||||
@@ -1488,7 +1552,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
// }
|
// }
|
||||||
// ir_fprintf(f, ">");
|
// ir_fprintf(f, ">");
|
||||||
// ir_write_byte(f, '\n');
|
// ir_write_byte(f, '\n');
|
||||||
// } break;
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
case irInstr_BoundsCheck: {
|
case irInstr_BoundsCheck: {
|
||||||
@@ -1519,7 +1584,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_print_value(f, m, bc->len, t_int);
|
ir_print_value(f, m, bc->len, t_int);
|
||||||
|
|
||||||
ir_fprintf(f, ")\n");
|
ir_fprintf(f, ")\n");
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case irInstr_SliceBoundsCheck: {
|
case irInstr_SliceBoundsCheck: {
|
||||||
irInstrSliceBoundsCheck *bc = &instr->SliceBoundsCheck;
|
irInstrSliceBoundsCheck *bc = &instr->SliceBoundsCheck;
|
||||||
@@ -1561,7 +1627,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ir_fprintf(f, ")\n");
|
ir_fprintf(f, ")\n");
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case irInstr_DebugDeclare: {
|
case irInstr_DebugDeclare: {
|
||||||
@@ -1571,8 +1638,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
Entity *e = dd->entity;
|
Entity *e = dd->entity;
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
TokenPos pos = e->token.pos;
|
TokenPos pos = e->token.pos;
|
||||||
// gb_printf("debug_declare %.*s\n", LIT(dd->entity->token.string));
|
|
||||||
ir_write_string(f, "; ");
|
|
||||||
|
if (!m->generate_debug_info) {
|
||||||
|
ir_write_string(f, "; ");
|
||||||
|
}
|
||||||
ir_write_string(f, "call void @llvm.dbg.declare(");
|
ir_write_string(f, "call void @llvm.dbg.declare(");
|
||||||
ir_write_string(f, "metadata ");
|
ir_write_string(f, "metadata ");
|
||||||
ir_print_type(f, m, vt);
|
ir_print_type(f, m, vt);
|
||||||
@@ -1586,7 +1656,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_fprintf(f, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, di->id);
|
ir_fprintf(f, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, di->id);
|
||||||
|
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1601,11 +1672,13 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
|||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
ir_write_string(f, "define ");
|
ir_write_string(f, "define ");
|
||||||
if (build_context.is_dll) {
|
if (build_context.is_dll) {
|
||||||
// if (proc->tags & (ProcTag_export|ProcTag_dll_export)) {
|
if (proc->is_export) {
|
||||||
if (proc->tags & (ProcTag_export)) {
|
|
||||||
ir_write_string(f, "dllexport ");
|
ir_write_string(f, "dllexport ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if (!proc->is_export && !proc->is_foreign && !proc->is_entry_point) {
|
||||||
|
// ir_write_string(f, "internal ");
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeProc *proc_type = &proc->type->Proc;
|
TypeProc *proc_type = &proc->type->Proc;
|
||||||
@@ -1675,26 +1748,33 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
|||||||
|
|
||||||
ir_write_string(f, ") ");
|
ir_write_string(f, ") ");
|
||||||
|
|
||||||
if (proc->tags & ProcTag_inline) {
|
switch (proc->inlining) {
|
||||||
ir_write_string(f, "alwaysinline ");
|
default:
|
||||||
}
|
ir_fprintf(f, "#0 ");
|
||||||
if (proc->tags & ProcTag_no_inline) {
|
break;
|
||||||
|
case ProcInlining_no_inline:
|
||||||
ir_write_string(f, "noinline ");
|
ir_write_string(f, "noinline ");
|
||||||
|
ir_fprintf(f, "#0 ");
|
||||||
|
break;
|
||||||
|
case ProcInlining_inline:
|
||||||
|
ir_write_string(f, "alwaysinline ");
|
||||||
|
ir_fprintf(f, "#1 ");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (proc->entity != nullptr) {
|
if (proc->entity != nullptr) {
|
||||||
if (proc->body != nullptr) {
|
if (proc->body != nullptr) {
|
||||||
irDebugInfo **di_ = map_get(&proc->module->debug_info, hash_pointer(proc->entity));
|
irDebugInfo **di_ = map_get(&proc->module->debug_info, hash_pointer(proc->entity));
|
||||||
if (di_ != nullptr) {
|
if (di_ != nullptr) {
|
||||||
irDebugInfo *di = *di_;
|
irDebugInfo *di = *di_;
|
||||||
GB_ASSERT(di->kind == irDebugInfo_Proc);
|
GB_ASSERT(di->kind == irDebugInfo_Proc);
|
||||||
// ir_fprintf(f, "!dbg !%d ", di->id);
|
ir_fprintf(f, "!dbg !%d ", di->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (proc->body != nullptr) {
|
if (proc->body != nullptr) {
|
||||||
// ir_fprintf(f, "nounwind uwtable {\n");
|
// ir_fprintf(f, "nounwind uwtable {\n");
|
||||||
|
|
||||||
@@ -1724,6 +1804,7 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
|||||||
void ir_print_type_name(irFileBuffer *f, irModule *m, irValue *v) {
|
void ir_print_type_name(irFileBuffer *f, irModule *m, irValue *v) {
|
||||||
GB_ASSERT(v->kind == irValue_TypeName);
|
GB_ASSERT(v->kind == irValue_TypeName);
|
||||||
Type *t = base_type(v->TypeName.type);
|
Type *t = base_type(v->TypeName.type);
|
||||||
|
|
||||||
ir_print_encoded_local(f, v->TypeName.name);
|
ir_print_encoded_local(f, v->TypeName.name);
|
||||||
ir_write_string(f, str_lit(" = type "));
|
ir_write_string(f, str_lit(" = type "));
|
||||||
|
|
||||||
@@ -1766,6 +1847,13 @@ void print_llvm_ir(irGen *ir) {
|
|||||||
irFileBuffer buf = {}, *f = &buf;
|
irFileBuffer buf = {}, *f = &buf;
|
||||||
ir_file_buffer_init(f, &ir->output_file);
|
ir_file_buffer_init(f, &ir->output_file);
|
||||||
|
|
||||||
|
if (m->generate_debug_info) {
|
||||||
|
ir_write_string(f, "target datalayout = \"e-m:w-i64:64-f80:128-n8:16:32:64-S128\"\n");
|
||||||
|
ir_write_string(f, "target triple = \"x86_64-pc-windows-msvc19.11.25508\"\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ir_print_encoded_local(f, str_lit("..opaque"));
|
ir_print_encoded_local(f, str_lit("..opaque"));
|
||||||
ir_write_string(f, str_lit(" = type {};\n"));
|
ir_write_string(f, str_lit(" = type {};\n"));
|
||||||
ir_print_encoded_local(f, str_lit("..string"));
|
ir_print_encoded_local(f, str_lit("..string"));
|
||||||
@@ -1851,8 +1939,19 @@ void print_llvm_ir(irGen *ir) {
|
|||||||
if (g->is_foreign) {
|
if (g->is_foreign) {
|
||||||
ir_write_string(f, str_lit("external "));
|
ir_write_string(f, str_lit("external "));
|
||||||
}
|
}
|
||||||
if (g->is_thread_local) {
|
if (build_context.is_dll) {
|
||||||
ir_write_string(f, str_lit("thread_local "));
|
if (g->is_export) {
|
||||||
|
ir_write_string(f, str_lit("dllexport "));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (g->thread_local_model.len > 0) {
|
||||||
|
String model = g->thread_local_model;
|
||||||
|
if (model == "default") {
|
||||||
|
ir_write_string(f, str_lit("thread_local "));
|
||||||
|
} else {
|
||||||
|
ir_fprintf(f, "thread_local(%.*s) ", LIT(model));
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g->is_private) {
|
if (g->is_private) {
|
||||||
@@ -1881,23 +1980,28 @@ void print_llvm_ir(irGen *ir) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
if (m->generate_debug_info) {
|
||||||
// if (m->generate_debug_info) {
|
|
||||||
{
|
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
|
|
||||||
i32 diec = m->debug_info.entries.count;
|
i32 diec = m->debug_info.entries.count;
|
||||||
|
|
||||||
ir_fprintf(f, "!llvm.dbg.cu = !{!0}\n");
|
i32 di_version = diec+1;
|
||||||
ir_fprintf(f, "!llvm.ident = !{!%d}\n", diec+3);
|
i32 di_debug_info = diec+2;
|
||||||
ir_fprintf(f, "!%d = !{i32 2, !\"Dwarf Version\", i32 4}\n", diec+0);
|
i32 di_code_view = diec+3;
|
||||||
ir_fprintf(f, "!%d = !{i32 2, !\"Debug Info Version\", i32 3}\n", diec+1);
|
i32 di_wchar_size = diec+4;
|
||||||
ir_fprintf(f, "!%d = !{i32 1, !\"PIC Level\", i32 2}\n", diec+2);
|
|
||||||
ir_fprintf(f, "!%d = !{!\"clang version 3.9.0 (branches/release_39)\"}\n", diec+3);
|
ir_fprintf(f, "attributes #0 = {nounwind noinline optnone uwtable}\n");
|
||||||
|
ir_fprintf(f, "attributes #1 = {nounwind alwaysinline uwtable}\n");
|
||||||
|
|
||||||
|
|
||||||
|
ir_fprintf(f, "!llvm.dbg.cu = !{!%d}\n", m->debug_compile_unit->id);
|
||||||
|
ir_fprintf(f, "!llvm.ident = !{!%d}\n", di_version);
|
||||||
|
ir_fprintf(f, "!llvm.module.flags = !{!%d, !%d, !%d}\n", di_debug_info, di_code_view, di_wchar_size);
|
||||||
|
|
||||||
|
ir_fprintf(f, "!0 = !{}\n");
|
||||||
|
|
||||||
for_array(di_index, m->debug_info.entries) {
|
for_array(di_index, m->debug_info.entries) {
|
||||||
MapIrDebugInfoEntry *entry = &m->debug_info.entries[di_index];
|
irDebugInfo *di = m->debug_info.entries[di_index].value;
|
||||||
irDebugInfo *di = entry->value;
|
|
||||||
ir_fprintf(f, "!%d = ", di->id);
|
ir_fprintf(f, "!%d = ", di->id);
|
||||||
|
|
||||||
switch (di->kind) {
|
switch (di->kind) {
|
||||||
@@ -1905,37 +2009,42 @@ void print_llvm_ir(irGen *ir) {
|
|||||||
irDebugInfo *file = *map_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
|
irDebugInfo *file = *map_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
|
||||||
ir_fprintf(f,
|
ir_fprintf(f,
|
||||||
"distinct !DICompileUnit("
|
"distinct !DICompileUnit("
|
||||||
"language: DW_LANG_Go, " // Is this good enough?
|
"language: DW_LANG_C_plus_plus" // Is this good enough?
|
||||||
"file: !%d, "
|
", file: !%d"
|
||||||
"producer: \"clang version 3.9.0 (branches/release_39)\", "
|
", producer: \"Odin %.*s\""
|
||||||
"flags: \"\", "
|
", flags: \"\""
|
||||||
"runtimeVersion: 0, "
|
", runtimeVersion: 0"
|
||||||
"isOptimized: false, "
|
", isOptimized: false"
|
||||||
"emissionKind: FullDebug"
|
", emissionKind: FullDebug"
|
||||||
")",
|
")",
|
||||||
file->id);
|
file->id, LIT(build_context.ODIN_VERSION));
|
||||||
|
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
case irDebugInfo_File:
|
case irDebugInfo_File:
|
||||||
ir_fprintf(f, "!DIFile(filename: \"");
|
ir_fprintf(f, "!DIFile(filename: \"");
|
||||||
ir_print_escape_string(f, di->File.filename, false);
|
ir_print_escape_path(f, di->File.filename);
|
||||||
ir_fprintf(f, "\", directory: \"");
|
ir_fprintf(f, "\", directory: \"");
|
||||||
ir_print_escape_string(f, di->File.directory, false);
|
ir_print_escape_path(f, di->File.directory);
|
||||||
ir_fprintf(f, "\")");
|
ir_fprintf(f, "\"");
|
||||||
|
ir_fprintf(f, ")");
|
||||||
break;
|
break;
|
||||||
case irDebugInfo_Proc:
|
case irDebugInfo_Proc:
|
||||||
ir_fprintf(f, "distinct !DISubprogram("
|
ir_fprintf(f, "distinct !DISubprogram("
|
||||||
"name: \"%.*s\", "
|
"name: \"%.*s\""
|
||||||
// "linkageName: \"\", "
|
", linkageName: \"%.*s\""
|
||||||
"file: !%d, "
|
", file: !%d"
|
||||||
"line: %td, "
|
", line: %td"
|
||||||
"isDefinition: true, "
|
", isDefinition: true"
|
||||||
"isLocal: false, "
|
", isLocal: true"
|
||||||
"unit: !0"
|
", flags: DIFlagPrototyped"
|
||||||
|
", isOptimized: false"
|
||||||
|
", unit: !%d"
|
||||||
")",
|
")",
|
||||||
|
LIT(di->Proc.entity->token.string),
|
||||||
LIT(di->Proc.name),
|
LIT(di->Proc.name),
|
||||||
di->Proc.file->id,
|
di->Proc.file->id, di->Proc.pos.line,
|
||||||
di->Proc.pos.line);
|
m->debug_compile_unit->id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case irDebugInfo_AllProcs:
|
case irDebugInfo_AllProcs:
|
||||||
@@ -1947,11 +2056,27 @@ void print_llvm_ir(irGen *ir) {
|
|||||||
}
|
}
|
||||||
ir_write_byte(f, '}');
|
ir_write_byte(f, '}');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case irDebugInfo_Location:
|
||||||
|
GB_ASSERT(di->Location.scope != nullptr);
|
||||||
|
ir_fprintf(f, "!DILocation(line: %td, column: %td, scope: !%d)",
|
||||||
|
di->Location.pos.line, di->Location.pos.column, di->Location.scope->id);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
GB_PANIC("Unhandled irDebugInfo kind %d", di->kind);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ir_fprintf(f, "!%d = !{!\"Odin version %.*s \"}\n", di_version, LIT(build_context.ODIN_VERSION));
|
||||||
|
ir_fprintf(f, "!%d = !{i32 2, !\"Debug Info Version\", i32 3}\n", di_debug_info);
|
||||||
|
ir_fprintf(f, "!%d = !{i32 2, !\"CodeView\", i32 1}\n", di_code_view);
|
||||||
|
ir_fprintf(f, "!%d = !{i32 1, !\"wchar_size\", i32 2}\n", di_wchar_size);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
ir_file_buffer_destroy(f);
|
ir_file_buffer_destroy(f);
|
||||||
}
|
}
|
||||||
|
|||||||
+198
-39
@@ -1,3 +1,5 @@
|
|||||||
|
#define ALLOW_ARRAY_PROGRAMMING
|
||||||
|
|
||||||
#define USE_CUSTOM_BACKEND 0
|
#define USE_CUSTOM_BACKEND 0
|
||||||
// #define NO_ARRAY_BOUNDS_CHECK
|
// #define NO_ARRAY_BOUNDS_CHECK
|
||||||
#if !defined(USE_THREADED_PARSER)
|
#if !defined(USE_THREADED_PARSER)
|
||||||
@@ -17,7 +19,7 @@
|
|||||||
#include "ir_print.cpp"
|
#include "ir_print.cpp"
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
// NOTE(bill): `name` is used in debugging and profiling modes
|
// NOTE(bill): 'name' is used in debugging and profiling modes
|
||||||
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
||||||
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
|
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
|
||||||
PROCESS_INFORMATION pi = {0};
|
PROCESS_INFORMATION pi = {0};
|
||||||
@@ -161,14 +163,42 @@ void usage(String argv0) {
|
|||||||
print_usage_line(0, "Usage:");
|
print_usage_line(0, "Usage:");
|
||||||
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
|
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
|
||||||
print_usage_line(0, "Commands:");
|
print_usage_line(0, "Commands:");
|
||||||
print_usage_line(1, "build compile .odin file as executable");
|
print_usage_line(1, "build compile .odin file as executable");
|
||||||
print_usage_line(1, "build_dll compile .odin file as dll");
|
print_usage_line(1, "run compile and run .odin file");
|
||||||
print_usage_line(1, "run compile and run .odin file");
|
print_usage_line(1, "docs generate documentation for a .odin file");
|
||||||
print_usage_line(1, "docs generate documentation for a .odin file");
|
print_usage_line(1, "version print version");
|
||||||
print_usage_line(1, "version print version");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool string_is_valid_identifier(String str) {
|
||||||
|
if (str.len <= 0) return false;
|
||||||
|
|
||||||
|
isize rune_count = 0;
|
||||||
|
|
||||||
|
isize w = 0;
|
||||||
|
isize offset = 0;
|
||||||
|
while (offset < str.len) {
|
||||||
|
Rune r = 0;
|
||||||
|
w = gb_utf8_decode(str.text, str.len, &r);
|
||||||
|
if (r == GB_RUNE_INVALID) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rune_count == 0) {
|
||||||
|
if (!rune_is_letter(r)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!rune_is_letter(r) && !rune_is_digit(r)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rune_count += 1;
|
||||||
|
offset += w;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
enum BuildFlagKind {
|
enum BuildFlagKind {
|
||||||
BuildFlag_Invalid,
|
BuildFlag_Invalid,
|
||||||
@@ -177,6 +207,8 @@ enum BuildFlagKind {
|
|||||||
BuildFlag_ShowTimings,
|
BuildFlag_ShowTimings,
|
||||||
BuildFlag_ThreadCount,
|
BuildFlag_ThreadCount,
|
||||||
BuildFlag_KeepTempFiles,
|
BuildFlag_KeepTempFiles,
|
||||||
|
BuildFlag_Collection,
|
||||||
|
BuildFlag_BuildMode,
|
||||||
|
|
||||||
BuildFlag_COUNT,
|
BuildFlag_COUNT,
|
||||||
};
|
};
|
||||||
@@ -198,7 +230,6 @@ struct BuildFlag {
|
|||||||
BuildFlagParamKind param_kind;
|
BuildFlagParamKind param_kind;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind) {
|
void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind) {
|
||||||
BuildFlag flag = {kind, name, param_kind};
|
BuildFlag flag = {kind, name, param_kind};
|
||||||
array_add(build_flags, flag);
|
array_add(build_flags, flag);
|
||||||
@@ -211,6 +242,8 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None);
|
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None);
|
||||||
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
|
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
|
||||||
add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None);
|
add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None);
|
||||||
|
add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String);
|
||||||
|
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String);
|
||||||
|
|
||||||
|
|
||||||
Array<String> flag_args = args;
|
Array<String> flag_args = args;
|
||||||
@@ -241,7 +274,7 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
if (bf.name == name) {
|
if (bf.name == name) {
|
||||||
found = true;
|
found = true;
|
||||||
if (set_flags[bf.kind]) {
|
if (set_flags[bf.kind]) {
|
||||||
gb_printf_err("Previous flag set: `%.*s`\n", LIT(name));
|
gb_printf_err("Previous flag set: '%.*s'\n", LIT(name));
|
||||||
bad_flags = true;
|
bad_flags = true;
|
||||||
} else {
|
} else {
|
||||||
ExactValue value = {};
|
ExactValue value = {};
|
||||||
@@ -250,11 +283,11 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
if (param.len == 0) {
|
if (param.len == 0) {
|
||||||
ok = true;
|
ok = true;
|
||||||
} else {
|
} else {
|
||||||
gb_printf_err("Flag `%.*s` was not expecting a parameter `%.*s`\n", LIT(name), LIT(param));
|
gb_printf_err("Flag '%.*s' was not expecting a parameter '%.*s'\n", LIT(name), LIT(param));
|
||||||
bad_flags = true;
|
bad_flags = true;
|
||||||
}
|
}
|
||||||
} else if (param.len == 0) {
|
} else if (param.len == 0) {
|
||||||
gb_printf_err("Flag missing for `%.*s`\n", LIT(name));
|
gb_printf_err("Flag missing for '%.*s'\n", LIT(name));
|
||||||
bad_flags = true;
|
bad_flags = true;
|
||||||
} else {
|
} else {
|
||||||
ok = true;
|
ok = true;
|
||||||
@@ -269,6 +302,8 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
value = exact_value_bool(true);
|
value = exact_value_bool(true);
|
||||||
} else if (param == "TRUE") {
|
} else if (param == "TRUE") {
|
||||||
value = exact_value_bool(true);
|
value = exact_value_bool(true);
|
||||||
|
} else if (param == "True") {
|
||||||
|
value = exact_value_bool(true);
|
||||||
} else if (param == "1") {
|
} else if (param == "1") {
|
||||||
value = exact_value_bool(true);
|
value = exact_value_bool(true);
|
||||||
} else if (param == "f") {
|
} else if (param == "f") {
|
||||||
@@ -279,10 +314,12 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
value = exact_value_bool(false);
|
value = exact_value_bool(false);
|
||||||
} else if (param == "FALSE") {
|
} else if (param == "FALSE") {
|
||||||
value = exact_value_bool(false);
|
value = exact_value_bool(false);
|
||||||
|
} else if (param == "False") {
|
||||||
|
value = exact_value_bool(false);
|
||||||
} else if (param == "0") {
|
} else if (param == "0") {
|
||||||
value = exact_value_bool(false);
|
value = exact_value_bool(false);
|
||||||
} else {
|
} else {
|
||||||
gb_printf_err("Invalid flag parameter for `%.*s` = `%.*s`\n", LIT(name), LIT(param));
|
gb_printf_err("Invalid flag parameter for '%.*s' = '%.*s'\n", LIT(name), LIT(param));
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case BuildFlagParam_Integer:
|
case BuildFlagParam_Integer:
|
||||||
@@ -353,11 +390,99 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
} else {
|
} else {
|
||||||
build_context.thread_count = count;
|
build_context.thread_count = count;
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
case BuildFlag_KeepTempFiles:
|
case BuildFlag_KeepTempFiles:
|
||||||
GB_ASSERT(value.kind == ExactValue_Invalid);
|
GB_ASSERT(value.kind == ExactValue_Invalid);
|
||||||
build_context.keep_temp_files = true;
|
build_context.keep_temp_files = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BuildFlag_Collection: {
|
||||||
|
GB_ASSERT(value.kind == ExactValue_String);
|
||||||
|
String str = value.value_string;
|
||||||
|
isize eq_pos = -1;
|
||||||
|
for (isize i = 0; i < str.len; i++) {
|
||||||
|
if (str[i] == '=') {
|
||||||
|
eq_pos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (eq_pos < 0) {
|
||||||
|
gb_printf_err("Expected 'name=path', got '%.*s'\n", LIT(param));
|
||||||
|
bad_flags = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String name = substring(str, 0, eq_pos);
|
||||||
|
String path = substring(str, eq_pos+1, str.len);
|
||||||
|
if (name.len == 0 || path.len == 0) {
|
||||||
|
gb_printf_err("Expected 'name=path', got '%.*s'\n", LIT(param));
|
||||||
|
bad_flags = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string_is_valid_identifier(name)) {
|
||||||
|
gb_printf_err("Library collection name '%.*s' must be a valid identifier\n", LIT(name));
|
||||||
|
bad_flags = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name == "_") {
|
||||||
|
gb_printf_err("Library collection name cannot be an underscore\n");
|
||||||
|
bad_flags = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name == "system") {
|
||||||
|
gb_printf_err("Library collection name 'system' is reserved\n");
|
||||||
|
bad_flags = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
String prev_path = {};
|
||||||
|
bool found = find_library_collection_path(name, &prev_path);
|
||||||
|
if (found) {
|
||||||
|
gb_printf_err("Library collection '%.*s' already exists with path '%.*s'\n", LIT(name), LIT(prev_path));
|
||||||
|
bad_flags = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
gbAllocator a = heap_allocator();
|
||||||
|
String fullpath = path_to_fullpath(a, path);
|
||||||
|
if (!path_is_directory(fullpath)) {
|
||||||
|
gb_printf_err("Library collection '%.*s' path must be a directory, got '%.*s'\n", LIT(name), LIT(fullpath));
|
||||||
|
gb_free(a, fullpath.text);
|
||||||
|
bad_flags = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_library_collection(name, path);
|
||||||
|
|
||||||
|
// NOTE(bill): Allow for multiple library collections
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BuildFlag_BuildMode: {
|
||||||
|
GB_ASSERT(value.kind == ExactValue_String);
|
||||||
|
String str = value.value_string;
|
||||||
|
|
||||||
|
if (build_context.command != "build") {
|
||||||
|
gb_printf_err("'build-mode' can only be used with the 'build' command\n");
|
||||||
|
bad_flags = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str == "dll") {
|
||||||
|
build_context.is_dll = true;
|
||||||
|
} else if (str == "exe") {
|
||||||
|
build_context.is_dll = false;
|
||||||
|
} else {
|
||||||
|
gb_printf_err("Unknown build mode '%.*s'\n", LIT(str));
|
||||||
|
bad_flags = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,7 +493,7 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
gb_printf_err("Unknown flag: `%.*s`\n", LIT(name));
|
gb_printf_err("Unknown flag: '%.*s'\n", LIT(name));
|
||||||
bad_flags = true;
|
bad_flags = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -449,34 +574,32 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
init_scratch_memory(gb_megabytes(10));
|
init_scratch_memory(gb_megabytes(10));
|
||||||
init_global_error_collector();
|
init_global_error_collector();
|
||||||
|
|
||||||
Array<String> args = setup_args(arg_count, arg_ptr);
|
array_init(&library_collections, heap_allocator());
|
||||||
|
// NOTE(bill): 'core' cannot be (re)defined by the user
|
||||||
|
add_library_collection(str_lit("core"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("core")));
|
||||||
|
|
||||||
|
Array<String> args = setup_args(arg_count, arg_ptr);
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
|
|
||||||
|
String command = args[1];
|
||||||
|
|
||||||
String init_filename = {};
|
String init_filename = {};
|
||||||
bool run_output = false;
|
bool run_output = false;
|
||||||
if (args[1] == "run") {
|
if (command == "run") {
|
||||||
if (args.count < 3) {
|
if (args.count < 3) {
|
||||||
usage(args[0]);
|
usage(args[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
init_filename = args[2];
|
init_filename = args[2];
|
||||||
run_output = true;
|
run_output = true;
|
||||||
} else if (args[1] == "build_dll") {
|
} else if (command == "build") {
|
||||||
if (args.count < 3) {
|
if (args.count < 3) {
|
||||||
usage(args[0]);
|
usage(args[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
init_filename = args[2];
|
init_filename = args[2];
|
||||||
build_context.is_dll = true;
|
} else if (command == "docs") {
|
||||||
} else if (args[1] == "build") {
|
|
||||||
if (args.count < 3) {
|
|
||||||
usage(args[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
init_filename = args[2];
|
|
||||||
} else if (args[1] == "docs") {
|
|
||||||
if (args.count < 3) {
|
if (args.count < 3) {
|
||||||
usage(args[0]);
|
usage(args[0]);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -488,7 +611,7 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
print_usage_line(0, "Documentation generation is not yet supported");
|
print_usage_line(0, "Documentation generation is not yet supported");
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
} else if (args[1] == "version") {
|
} else if (command == "version") {
|
||||||
gb_printf("%.*s version %.*s\n", LIT(args[0]), LIT(ODIN_VERSION));
|
gb_printf("%.*s version %.*s\n", LIT(args[0]), LIT(ODIN_VERSION));
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -496,11 +619,21 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
build_context.command = command;
|
||||||
|
|
||||||
if (!parse_build_flags(args)) {
|
if (!parse_build_flags(args)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE(bill): add 'shared' directory if it is not already set
|
||||||
|
if (!find_library_collection_path(str_lit("shared"), nullptr)) {
|
||||||
|
add_library_collection(str_lit("shared"),
|
||||||
|
get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("shared")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
init_build_context();
|
init_build_context();
|
||||||
if (build_context.word_size == 4) {
|
if (build_context.word_size == 4) {
|
||||||
print_usage_line(0, "%s 32-bit is not yet supported", args[0]);
|
print_usage_line(0, "%s 32-bit is not yet supported", args[0]);
|
||||||
@@ -574,7 +707,6 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
|
|
||||||
String output_name = ir_gen.output_name;
|
String output_name = ir_gen.output_name;
|
||||||
String output_base = ir_gen.output_base;
|
String output_base = ir_gen.output_base;
|
||||||
int base_name_len = cast(int)output_base.len;
|
|
||||||
|
|
||||||
build_context.optimization_level = gb_clamp(build_context.optimization_level, 0, 3);
|
build_context.optimization_level = gb_clamp(build_context.optimization_level, 0, 3);
|
||||||
|
|
||||||
@@ -605,7 +737,7 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
#if defined(GB_SYSTEM_OSX)
|
#if defined(GB_SYSTEM_OSX)
|
||||||
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
|
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
|
||||||
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
|
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
|
||||||
// make sure to also change the `macosx_version_min` param passed to `llc`
|
// make sure to also change the 'macosx_version_min' param passed to 'llc'
|
||||||
"-mtriple=x86_64-apple-macosx10.8 "
|
"-mtriple=x86_64-apple-macosx10.8 "
|
||||||
#endif
|
#endif
|
||||||
"",
|
"",
|
||||||
@@ -655,9 +787,10 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exit_code = system_exec_command_line_app("msvc-link", true,
|
exit_code = system_exec_command_line_app("msvc-link", true,
|
||||||
"link \"%.*s\".obj -OUT:\"%.*s.%s\" %s "
|
"link \"%.*s.obj\" -OUT:\"%.*s.%s\" %s "
|
||||||
"/defaultlib:libcmt "
|
"/defaultlib:libcmt "
|
||||||
// "/nodefaultlib "
|
// "/nodefaultlib "
|
||||||
|
// "/debug "
|
||||||
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
|
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
|
||||||
" %.*s "
|
" %.*s "
|
||||||
" %s "
|
" %s "
|
||||||
@@ -699,9 +832,15 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
return exit_code;
|
return exit_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
timings_start_section(&timings, str_lit("ld-link"));
|
// NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe
|
||||||
|
char cwd[256];
|
||||||
|
getcwd(&cwd[0], 256);
|
||||||
|
//printf("%s\n", cwd);
|
||||||
|
|
||||||
|
// NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library
|
||||||
|
// files can be passed with -l:
|
||||||
|
gbString lib_str = gb_string_make(heap_allocator(), "-L/");
|
||||||
|
|
||||||
gbString lib_str = gb_string_make(heap_allocator(), "");
|
|
||||||
defer (gb_string_free(lib_str));
|
defer (gb_string_free(lib_str));
|
||||||
char lib_str_buf[1024] = {0};
|
char lib_str_buf[1024] = {0};
|
||||||
for_array(i, ir_gen.module.foreign_library_paths) {
|
for_array(i, ir_gen.module.foreign_library_paths) {
|
||||||
@@ -713,15 +852,36 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
#if defined(GB_SYSTEM_OSX)
|
#if defined(GB_SYSTEM_OSX)
|
||||||
isize len;
|
isize len;
|
||||||
if(lib.len > 2 && lib[0] == '-' && lib[1] == 'f') {
|
if(lib.len > 2 && lib[0] == '-' && lib[1] == 'f') {
|
||||||
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
|
// framework thingie
|
||||||
" -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
|
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
|
||||||
|
} else if (string_has_extension(lib, str_lit("a"))) {
|
||||||
|
// static libs, absolute full path relative to the file in which the lib was imported from
|
||||||
|
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " %.*s ", LIT(lib));
|
||||||
|
} else if (string_has_extension(lib, str_lit("dylib"))) {
|
||||||
|
// dynamic lib, relative path to executable
|
||||||
|
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%s/%.*s ", cwd, LIT(lib));
|
||||||
} else {
|
} else {
|
||||||
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
|
// dynamic or static system lib, just link regularly searching system library paths
|
||||||
" -l%.*s ", LIT(lib));
|
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l%.*s ", LIT(lib));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
|
// NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path,
|
||||||
" -l%.*s ", LIT(lib));
|
// since those are statically linked to at link time. shared libraries (.so) has to be
|
||||||
|
// available at runtime wherever the executable is run, so we make require those to be
|
||||||
|
// local to the executable (unless the system collection is used, in which case we search
|
||||||
|
// the system library paths for the library file).
|
||||||
|
if (string_has_extension(lib, str_lit("a"))) {
|
||||||
|
// static libs, absolute full path relative to the file in which the lib was imported from
|
||||||
|
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%.*s ", LIT(lib));
|
||||||
|
} else if (string_has_extension(lib, str_lit("so"))) {
|
||||||
|
// dynamic lib, relative path to executable
|
||||||
|
// NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible
|
||||||
|
// at runtimeto the executable
|
||||||
|
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%s/%.*s ", cwd, LIT(lib));
|
||||||
|
} else {
|
||||||
|
// dynamic or static system lib, just link regularly searching system library paths
|
||||||
|
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l%.*s ", LIT(lib));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
lib_str = gb_string_appendc(lib_str, lib_str_buf);
|
lib_str = gb_string_appendc(lib_str, lib_str_buf);
|
||||||
}
|
}
|
||||||
@@ -733,7 +893,6 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
char *linker;
|
char *linker;
|
||||||
if (build_context.is_dll) {
|
if (build_context.is_dll) {
|
||||||
// Shared libraries are .dylib on MacOS and .so on Linux.
|
// Shared libraries are .dylib on MacOS and .so on Linux.
|
||||||
// TODO(zangent): Is that statement entirely truthful?
|
|
||||||
#if defined(GB_SYSTEM_OSX)
|
#if defined(GB_SYSTEM_OSX)
|
||||||
output_ext = ".dylib";
|
output_ext = ".dylib";
|
||||||
#else
|
#else
|
||||||
@@ -757,14 +916,14 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
exit_code = system_exec_command_line_app("ld-link", true,
|
exit_code = system_exec_command_line_app("ld-link", true,
|
||||||
"%s \"%.*s\".o -o \"%.*s%s\" %s "
|
"%s \"%.*s.o\" -o \"%.*s%s\" %s "
|
||||||
"-lc -lm "
|
"-lc -lm "
|
||||||
" %.*s "
|
" %.*s "
|
||||||
" %s "
|
" %s "
|
||||||
#if defined(GB_SYSTEM_OSX)
|
#if defined(GB_SYSTEM_OSX)
|
||||||
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
|
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
|
||||||
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
|
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
|
||||||
// make sure to also change the `mtriple` param passed to `opt`
|
// make sure to also change the 'mtriple' param passed to 'opt'
|
||||||
" -macosx_version_min 10.8.0 "
|
" -macosx_version_min 10.8.0 "
|
||||||
// This points the linker to where the entry point is
|
// This points the linker to where the entry point is
|
||||||
" -e _main "
|
" -e _main "
|
||||||
|
|||||||
+2
-9
@@ -101,8 +101,7 @@ struct Map {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename T> void map_init (Map<T> *h, gbAllocator a);
|
template <typename T> void map_init (Map<T> *h, gbAllocator a, isize capacity = 16);
|
||||||
template <typename T> void map_init_with_reserve(Map<T> *h, gbAllocator a, isize capacity);
|
|
||||||
template <typename T> void map_destroy (Map<T> *h);
|
template <typename T> void map_destroy (Map<T> *h);
|
||||||
template <typename T> T * map_get (Map<T> *h, HashKey key);
|
template <typename T> T * map_get (Map<T> *h, HashKey key);
|
||||||
template <typename T> void map_set (Map<T> *h, HashKey key, T const &value);
|
template <typename T> void map_set (Map<T> *h, HashKey key, T const &value);
|
||||||
@@ -123,13 +122,7 @@ template <typename T> void multi_map_remove_all(Map<T> *h, HashKey key);
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
gb_inline void map_init(Map<T> *h, gbAllocator a) {
|
gb_inline void map_init(Map<T> *h, gbAllocator a, isize capacity) {
|
||||||
array_init(&h->hashes, a);
|
|
||||||
array_init(&h->entries, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
gb_inline void map_init_with_reserve(Map<T> *h, gbAllocator a, isize capacity) {
|
|
||||||
array_init(&h->hashes, a, capacity);
|
array_init(&h->hashes, a, capacity);
|
||||||
array_init(&h->entries, a, capacity);
|
array_init(&h->entries, a, capacity);
|
||||||
}
|
}
|
||||||
|
|||||||
+828
-786
File diff suppressed because it is too large
Load Diff
-221
@@ -1,221 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
gb_inline void print_indent(isize indent) {
|
|
||||||
while (indent --> 0)
|
|
||||||
gb_printf(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_ast(AstNode *node, isize indent) {
|
|
||||||
if (node == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (node->kind) {
|
|
||||||
case AstNode_BasicLit:
|
|
||||||
print_indent(indent);
|
|
||||||
print_token(node->BasicLit);
|
|
||||||
break;
|
|
||||||
case AstNode_Ident:
|
|
||||||
print_indent(indent);
|
|
||||||
print_token(node->Ident);
|
|
||||||
break;
|
|
||||||
case AstNode_ProcLit:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(proc lit)\n");
|
|
||||||
print_ast(node->ProcLit.type, indent+1);
|
|
||||||
print_ast(node->ProcLit.body, indent+1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AstNode_CompoundLit:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(compound lit)\n");
|
|
||||||
print_ast(node->CompoundLit.type, indent+1);
|
|
||||||
for_array(i, node->CompoundLit.elems) {
|
|
||||||
print_ast(node->CompoundLit.elems[i], indent+1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
case AstNode_TagExpr:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(tag)\n");
|
|
||||||
print_indent(indent+1);
|
|
||||||
print_token(node->TagExpr.name);
|
|
||||||
print_ast(node->TagExpr.expr, indent+1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AstNode_UnaryExpr:
|
|
||||||
print_indent(indent);
|
|
||||||
print_token(node->UnaryExpr.op);
|
|
||||||
print_ast(node->UnaryExpr.expr, indent+1);
|
|
||||||
break;
|
|
||||||
case AstNode_BinaryExpr:
|
|
||||||
print_indent(indent);
|
|
||||||
print_token(node->BinaryExpr.op);
|
|
||||||
print_ast(node->BinaryExpr.left, indent+1);
|
|
||||||
print_ast(node->BinaryExpr.right, indent+1);
|
|
||||||
break;
|
|
||||||
case AstNode_CallExpr:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(call)\n");
|
|
||||||
print_ast(node->CallExpr.proc, indent+1);
|
|
||||||
for_array(i, node->CallExpr.args) {
|
|
||||||
print_ast(node->CallExpr.args[i], indent+1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AstNode_SelectorExpr:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf(".\n");
|
|
||||||
print_ast(node->SelectorExpr.expr, indent+1);
|
|
||||||
print_ast(node->SelectorExpr.selector, indent+1);
|
|
||||||
break;
|
|
||||||
case AstNode_IndexExpr:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("([])\n");
|
|
||||||
print_ast(node->IndexExpr.expr, indent+1);
|
|
||||||
print_ast(node->IndexExpr.index, indent+1);
|
|
||||||
break;
|
|
||||||
case AstNode_DerefExpr:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(deref)\n");
|
|
||||||
print_ast(node->DerefExpr.expr, indent+1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
case AstNode_ExprStmt:
|
|
||||||
print_ast(node->ExprStmt.expr, indent);
|
|
||||||
break;
|
|
||||||
case AstNode_IncDecStmt:
|
|
||||||
print_indent(indent);
|
|
||||||
print_token(node->IncDecStmt.op);
|
|
||||||
print_ast(node->IncDecStmt.expr, indent+1);
|
|
||||||
break;
|
|
||||||
case AstNode_AssignStmt:
|
|
||||||
print_indent(indent);
|
|
||||||
print_token(node->AssignStmt.op);
|
|
||||||
for_array(i, node->AssignStmt.lhs) {
|
|
||||||
print_ast(node->AssignStmt.lhs[i], indent+1);
|
|
||||||
}
|
|
||||||
for_array(i, node->AssignStmt.rhs) {
|
|
||||||
print_ast(node->AssignStmt.rhs[i], indent+1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AstNode_BlockStmt:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(block)\n");
|
|
||||||
for_array(i, node->BlockStmt.stmts) {
|
|
||||||
print_ast(node->BlockStmt.stmts[i], indent+1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AstNode_IfStmt:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(if)\n");
|
|
||||||
print_ast(node->IfStmt.cond, indent+1);
|
|
||||||
print_ast(node->IfStmt.body, indent+1);
|
|
||||||
if (node->IfStmt.else_stmt) {
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(else)\n");
|
|
||||||
print_ast(node->IfStmt.else_stmt, indent+1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AstNode_ReturnStmt:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(return)\n");
|
|
||||||
for_array(i, node->ReturnStmt.results) {
|
|
||||||
print_ast(node->ReturnStmt.results[i], indent+1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AstNode_ForStmt:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(for)\n");
|
|
||||||
print_ast(node->ForStmt.init, indent+1);
|
|
||||||
print_ast(node->ForStmt.cond, indent+1);
|
|
||||||
print_ast(node->ForStmt.post, indent+1);
|
|
||||||
print_ast(node->ForStmt.body, indent+1);
|
|
||||||
break;
|
|
||||||
case AstNode_DeferStmt:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(defer)\n");
|
|
||||||
print_ast(node->DeferStmt.stmt, indent+1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
case AstNode_VarDecl:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(decl:var)\n");
|
|
||||||
for_array(i, node->VarDecl.names) {
|
|
||||||
print_ast(node->VarDecl.names[i], indent+1);
|
|
||||||
}
|
|
||||||
print_ast(node->VarDecl.type, indent+1);
|
|
||||||
for_array(i, node->VarDecl.values) {
|
|
||||||
print_ast(node->VarDecl.values[i], indent+1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AstNode_ConstDecl:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(decl:const)\n");
|
|
||||||
for_array(i, node->VarDecl.names) {
|
|
||||||
print_ast(node->VarDecl.names[i], indent+1);
|
|
||||||
}
|
|
||||||
print_ast(node->VarDecl.type, indent+1);
|
|
||||||
for_array(i, node->VarDecl.values) {
|
|
||||||
print_ast(node->VarDecl.values[i], indent+1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AstNode_ProcDecl:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(decl:proc)\n");
|
|
||||||
print_ast(node->ProcDecl.type, indent+1);
|
|
||||||
print_ast(node->ProcDecl.body, indent+1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AstNode_TypeDecl:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(type)\n");
|
|
||||||
print_ast(node->TypeDecl.name, indent+1);
|
|
||||||
print_ast(node->TypeDecl.type, indent+1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AstNode_ProcType:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(type:proc)(%td -> %td)\n", node->ProcType.params.count, node->ProcType.results.count);
|
|
||||||
for_array(i, node->ProcType.params) {
|
|
||||||
print_ast(node->ProcType.params[i], indent+1);
|
|
||||||
}
|
|
||||||
if (node->ProcType.results.count > 0) {
|
|
||||||
print_indent(indent+1);
|
|
||||||
gb_printf("->\n");
|
|
||||||
for_array(i, node->ProcType.results) {
|
|
||||||
print_ast(node->ProcType.results[i], indent+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AstNode_Parameter:
|
|
||||||
for_array(i, node->Parameter.names) {
|
|
||||||
print_ast(node->Parameter.names[i], indent+1);
|
|
||||||
}
|
|
||||||
print_ast(node->Parameter.type, indent);
|
|
||||||
break;
|
|
||||||
case AstNode_PointerType:
|
|
||||||
print_indent(indent);
|
|
||||||
print_token(node->PointerType.token);
|
|
||||||
print_ast(node->PointerType.type, indent+1);
|
|
||||||
break;
|
|
||||||
case AstNode_ArrayType:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("[]\n");
|
|
||||||
print_ast(node->ArrayType.count, indent+1);
|
|
||||||
print_ast(node->ArrayType.elem, indent+1);
|
|
||||||
break;
|
|
||||||
case AstNode_StructType:
|
|
||||||
print_indent(indent);
|
|
||||||
gb_printf("(struct)\n");
|
|
||||||
for_array(i, node->StructType.decls) {
|
|
||||||
print_ast(node->StructType.decls[i], indent+1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (node->next)
|
|
||||||
// print_ast(node->next, indent);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
template <typename T>
|
||||||
|
struct PriorityQueue {
|
||||||
|
Array<T> queue;
|
||||||
|
|
||||||
|
int (* cmp) (T *q, isize i, isize j);
|
||||||
|
void (* swap)(T *q, isize i, isize j);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool priority_queue_shift_down(PriorityQueue<T> *pq, isize i0, isize n) {
|
||||||
|
// O(n log n)
|
||||||
|
isize i = i0;
|
||||||
|
isize j, j1, j2;
|
||||||
|
if (0 > i || i > n) return false;
|
||||||
|
for (;;) {
|
||||||
|
j1 = 2*i + 1;
|
||||||
|
if (0 > j1 || j1 >= n) break;
|
||||||
|
j = j1;
|
||||||
|
j2 = j1 + 1;
|
||||||
|
if (j2 < n && pq->cmp(&pq->queue[0], j2, j1) < 0) {
|
||||||
|
j = j2;
|
||||||
|
}
|
||||||
|
if (pq->cmp(&pq->queue[0], i, j) < 0) break;
|
||||||
|
|
||||||
|
pq->swap(&pq->queue[0], i, j);
|
||||||
|
i = j;
|
||||||
|
}
|
||||||
|
return i > i0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
|
||||||
|
while (0 <= j && j < pq->queue.count) {
|
||||||
|
isize i = (j-1)/2;
|
||||||
|
if (i == j || pq->cmp(&pq->queue[0], i, j) < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pq->swap(&pq->queue[0], i, j);
|
||||||
|
j = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): When an element at index `i0` has changed its value, this will fix the
|
||||||
|
// the heap ordering. This using a basic "heapsort" with shift up and a shift down parts.
|
||||||
|
template <typename T>
|
||||||
|
void priority_queue_fix(PriorityQueue<T> *pq, isize i) {
|
||||||
|
if (!priority_queue_shift_down(pq, i, pq->queue.count)) {
|
||||||
|
priority_queue_shift_up(pq, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void priority_queue_push(PriorityQueue<T> *pq, T const &value) {
|
||||||
|
array_add(&pq->queue, value);
|
||||||
|
priority_queue_shift_up(pq, pq->queue.count-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T priority_queue_pop(PriorityQueue<T> *pq) {
|
||||||
|
GB_ASSERT(pq->queue.count > 0);
|
||||||
|
|
||||||
|
isize n = pq->queue.count - 1;
|
||||||
|
pq->swap(&pq->queue[0], 0, n);
|
||||||
|
priority_queue_shift_down(pq, 0, n);
|
||||||
|
return array_pop(&pq->queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T priority_queue_remove(PriorityQueue<T> *pq, isize i) {
|
||||||
|
GB_ASSERT(0 <= i && i < pq->queue.count);
|
||||||
|
isize n = pq->queue.count - 1;
|
||||||
|
if (n != i) {
|
||||||
|
pq->swap(&pq->queue[0], i, n);
|
||||||
|
priority_queue_shift_down(pq, i, n);
|
||||||
|
priority_queue_shift_up(pq, i);
|
||||||
|
}
|
||||||
|
return array_pop(&pq->queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
PriorityQueue<T> priority_queue_create(Array<T> queue,
|
||||||
|
int (* cmp) (T *q, isize i, isize j),
|
||||||
|
void (* swap)(T *q, isize i, isize j)) {
|
||||||
|
PriorityQueue<T> pq = {};
|
||||||
|
pq.queue = queue;
|
||||||
|
pq.cmp = cmp;
|
||||||
|
pq.swap = swap;
|
||||||
|
|
||||||
|
isize n = pq.queue.count;
|
||||||
|
for (isize i = n/2 - 1; i >= 0; i--) {
|
||||||
|
priority_queue_shift_down(&pq, i, n);
|
||||||
|
}
|
||||||
|
return pq;
|
||||||
|
}
|
||||||
+195
@@ -0,0 +1,195 @@
|
|||||||
|
struct PtrSetFindResult {
|
||||||
|
isize hash_index;
|
||||||
|
isize entry_prev;
|
||||||
|
isize entry_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct PtrSetEntry {
|
||||||
|
T ptr;
|
||||||
|
isize next;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct PtrSet {
|
||||||
|
Array<isize> hashes;
|
||||||
|
Array<PtrSetEntry<T>> entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> void ptr_set_init (PtrSet<T> *s, gbAllocator a, isize capacity = 16);
|
||||||
|
template <typename T> void ptr_set_destroy (PtrSet<T> *s);
|
||||||
|
template <typename T> void ptr_set_add (PtrSet<T> *s, T ptr);
|
||||||
|
template <typename T> bool ptr_set_exists (PtrSet<T> *s, T ptr);
|
||||||
|
template <typename T> void ptr_set_remove (PtrSet<T> *s, T ptr);
|
||||||
|
template <typename T> void ptr_set_clear (PtrSet<T> *s);
|
||||||
|
template <typename T> void ptr_set_grow (PtrSet<T> *s);
|
||||||
|
template <typename T> void ptr_set_rehash (PtrSet<T> *s, isize new_count);
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void ptr_set_init(PtrSet<T> *s, gbAllocator a, isize capacity) {
|
||||||
|
array_init(&s->hashes, a, capacity);
|
||||||
|
array_init(&s->entries, a, capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void ptr_set_destroy(PtrSet<T> *s) {
|
||||||
|
array_free(&s->hashes);
|
||||||
|
array_free(&s->entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
gb_internal isize ptr_set__add_entry(PtrSet<T> *s, T ptr) {
|
||||||
|
PtrSetEntry<T> e = {};
|
||||||
|
e.ptr = ptr;
|
||||||
|
e.next = -1;
|
||||||
|
array_add(&s->entries, e);
|
||||||
|
return s->entries.count-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
gb_internal PtrSetFindResult ptr_set__find(PtrSet<T> *s, T ptr) {
|
||||||
|
PtrSetFindResult fr = {-1, -1, -1};
|
||||||
|
if (s->hashes.count > 0) {
|
||||||
|
uintptr p = cast(uintptr)ptr;
|
||||||
|
uintptr n = cast(uintptr)s->hashes.count;
|
||||||
|
fr.hash_index = cast(isize)(p % n);
|
||||||
|
fr.entry_index = s->hashes[fr.hash_index];
|
||||||
|
while (fr.entry_index >= 0) {
|
||||||
|
if (s->entries[fr.entry_index].ptr == ptr) {
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
fr.entry_prev = fr.entry_index;
|
||||||
|
fr.entry_index = s->entries[fr.entry_index].next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
gb_internal PtrSetFindResult ptr_set__find_from_entry(PtrSet<T> *s, PtrSetEntry<T> *e) {
|
||||||
|
PtrSetFindResult fr = {-1, -1, -1};
|
||||||
|
if (s->hashes.count > 0) {
|
||||||
|
fr.hash_index = e->key.key % s->hashes.count;
|
||||||
|
fr.entry_index = s->hashes[fr.hash_index];
|
||||||
|
while (fr.entry_index >= 0) {
|
||||||
|
if (&s->entries[fr.entry_index] == e) {
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
fr.entry_prev = fr.entry_index;
|
||||||
|
fr.entry_index = s->entries[fr.entry_index].next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
gb_internal b32 ptr_set__full(PtrSet<T> *s) {
|
||||||
|
return 0.75f * s->hashes.count <= s->entries.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
gb_inline void ptr_set_grow(PtrSet<T> *s) {
|
||||||
|
isize new_count = ARRAY_GROW_FORMULA(s->entries.count);
|
||||||
|
ptr_set_rehash(s, new_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void ptr_set_rehash(PtrSet<T> *s, isize new_count) {
|
||||||
|
isize i, j;
|
||||||
|
PtrSet<T> ns = {};
|
||||||
|
ptr_set_init(&ns, s->hashes.allocator);
|
||||||
|
array_resize(&ns.hashes, new_count);
|
||||||
|
array_reserve(&ns.entries, s->entries.count);
|
||||||
|
for (i = 0; i < new_count; i++) {
|
||||||
|
ns.hashes[i] = -1;
|
||||||
|
}
|
||||||
|
for (i = 0; i < s->entries.count; i++) {
|
||||||
|
PtrSetEntry<T> *e = &s->entries[i];
|
||||||
|
PtrSetFindResult fr;
|
||||||
|
if (ns.hashes.count == 0) {
|
||||||
|
ptr_set_grow(&ns);
|
||||||
|
}
|
||||||
|
fr = ptr_set__find(&ns, e->ptr);
|
||||||
|
j = ptr_set__add_entry(&ns, e->ptr);
|
||||||
|
if (fr.entry_prev < 0) {
|
||||||
|
ns.hashes[fr.hash_index] = j;
|
||||||
|
} else {
|
||||||
|
ns.entries[fr.entry_prev].next = j;
|
||||||
|
}
|
||||||
|
ns.entries[j].next = fr.entry_index;
|
||||||
|
if (ptr_set__full(&ns)) {
|
||||||
|
ptr_set_grow(&ns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr_set_destroy(s);
|
||||||
|
*s = ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
gb_inline bool ptr_set_exists(PtrSet<T> *s, T ptr) {
|
||||||
|
isize index = ptr_set__find(s, ptr).entry_index;
|
||||||
|
return index >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if it already exists
|
||||||
|
template <typename T>
|
||||||
|
void ptr_set_add(PtrSet<T> *s, T ptr) {
|
||||||
|
isize index;
|
||||||
|
PtrSetFindResult fr;
|
||||||
|
if (s->hashes.count == 0) {
|
||||||
|
ptr_set_grow(s);
|
||||||
|
}
|
||||||
|
fr = ptr_set__find(s, ptr);
|
||||||
|
if (fr.entry_index >= 0) {
|
||||||
|
index = fr.entry_index;
|
||||||
|
} else {
|
||||||
|
index = ptr_set__add_entry(s, ptr);
|
||||||
|
if (fr.entry_prev >= 0) {
|
||||||
|
s->entries[fr.entry_prev].next = index;
|
||||||
|
} else {
|
||||||
|
s->hashes[fr.hash_index] = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ptr_set__full(s)) {
|
||||||
|
ptr_set_grow(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void ptr_set__erase(PtrSet<T> *s, PtrSetFindResult fr) {
|
||||||
|
PtrSetFindResult last;
|
||||||
|
if (fr.entry_prev < 0) {
|
||||||
|
s->hashes[fr.hash_index] = s->entries[fr.entry_index].next;
|
||||||
|
} else {
|
||||||
|
s->entries[fr.entry_prev].next = s->entries[fr.entry_index].next;
|
||||||
|
}
|
||||||
|
if (fr.entry_index == s->entries.count-1) {
|
||||||
|
array_pop(&s->entries);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s->entries[fr.entry_index] = s->entries[s->entries.count-1];
|
||||||
|
last = ptr_set__find(s, s->entries[fr.entry_index].ptr);
|
||||||
|
if (last.entry_prev >= 0) {
|
||||||
|
s->entries[last.entry_prev].next = fr.entry_index;
|
||||||
|
} else {
|
||||||
|
s->hashes[last.hash_index] = fr.entry_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void ptr_set_remove(PtrSet<T> *s, T ptr) {
|
||||||
|
PtrSetFindResult fr = ptr_set__find(s, ptr);
|
||||||
|
if (fr.entry_index >= 0) {
|
||||||
|
ptr_set__erase(s, fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
gb_inline void ptr_set_clear(PtrSet<T> *s) {
|
||||||
|
array_clear(&s->hashes);
|
||||||
|
array_clear(&s->entries);
|
||||||
|
}
|
||||||
+12
-20
@@ -159,7 +159,7 @@ struct ssaModule {
|
|||||||
gbAllocator tmp_allocator;
|
gbAllocator tmp_allocator;
|
||||||
gbArena tmp_arena;
|
gbArena tmp_arena;
|
||||||
|
|
||||||
Map<Entity *> min_dep_map; // Key: Entity *
|
PtrSet<Entity *> min_dep_map;
|
||||||
Map<ssaValue *> values; // Key: Entity *
|
Map<ssaValue *> values; // Key: Entity *
|
||||||
// List of registers for the specific architecture
|
// List of registers for the specific architecture
|
||||||
Array<ssaRegister> registers;
|
Array<ssaRegister> registers;
|
||||||
@@ -1935,12 +1935,6 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
|||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(us, UsingStmt, node);
|
case_ast_node(us, UsingStmt, node);
|
||||||
for_array(i, us->list) {
|
|
||||||
AstNode *decl = unparen_expr(us->list[i]);
|
|
||||||
if (decl->kind == AstNode_GenDecl) {
|
|
||||||
ssa_build_stmt(p, decl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ws, WhenStmt, node);
|
case_ast_node(ws, WhenStmt, node);
|
||||||
@@ -2144,12 +2138,12 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
|||||||
GB_PANIC("TODO: RangeStmt");
|
GB_PANIC("TODO: RangeStmt");
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(rs, MatchStmt, node);
|
case_ast_node(rs, SwitchStmt, node);
|
||||||
GB_PANIC("TODO: MatchStmt");
|
GB_PANIC("TODO: SwitchStmt");
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(rs, TypeMatchStmt, node);
|
case_ast_node(rs, TypeSwitchStmt, node);
|
||||||
GB_PANIC("TODO: TypeMatchStmt");
|
GB_PANIC("TODO: TypeSwitchStmt");
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(bs, BranchStmt, node);
|
case_ast_node(bs, BranchStmt, node);
|
||||||
@@ -2182,9 +2176,6 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
|||||||
ssa_emit_jump(p, b);
|
ssa_emit_jump(p, b);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(pa, PushAllocator, node);
|
|
||||||
GB_PANIC("TODO: PushAllocator");
|
|
||||||
case_end;
|
|
||||||
case_ast_node(pc, PushContext, node);
|
case_ast_node(pc, PushContext, node);
|
||||||
GB_PANIC("TODO: PushContext");
|
GB_PANIC("TODO: PushContext");
|
||||||
case_end;
|
case_end;
|
||||||
@@ -2437,7 +2428,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
|||||||
if (e->scope->is_init && name == "main") {
|
if (e->scope->is_init && name == "main") {
|
||||||
entry_point = e;
|
entry_point = e;
|
||||||
}
|
}
|
||||||
if ((e->Procedure.tags & ProcTag_export) != 0 ||
|
if (e->Procedure.is_export ||
|
||||||
(e->Procedure.link_name.len > 0) ||
|
(e->Procedure.link_name.len > 0) ||
|
||||||
(e->scope->is_file && e->Procedure.link_name.len > 0)) {
|
(e->scope->is_file && e->Procedure.link_name.len > 0)) {
|
||||||
if (!has_dll_main && name == "DllMain") {
|
if (!has_dll_main && name == "DllMain") {
|
||||||
@@ -2451,7 +2442,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
|||||||
|
|
||||||
|
|
||||||
m.entry_point_entity = entry_point;
|
m.entry_point_entity = entry_point;
|
||||||
m.min_dep_map = generate_minimum_dependency_map(info, entry_point);
|
m.min_dep_map = generate_minimum_dependency_set(info, entry_point);
|
||||||
|
|
||||||
for_array(i, info->entities.entries) {
|
for_array(i, info->entities.entries) {
|
||||||
auto *entry = &info->entities.entries[i];
|
auto *entry = &info->entities.entries[i];
|
||||||
@@ -2464,13 +2455,14 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (map_get(&m.min_dep_map, hash_pointer(e)) == nullptr) {
|
if (!ptr_set_exists(&m.min_dep_map, e)) {
|
||||||
// NOTE(bill): Nothing depends upon it so doesn't need to be built
|
// NOTE(bill): Nothing depends upon it so doesn't need to be built
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!scope->is_global) {
|
if (!scope->is_global) {
|
||||||
if (e->kind == Entity_Procedure && (e->Procedure.tags & ProcTag_export) != 0) {
|
if (e->kind == Entity_Procedure && e->Procedure.is_export) {
|
||||||
|
} else if (e->kind == Entity_Variable && e->Variable.is_export) {
|
||||||
} else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
|
} else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
|
||||||
// Handle later
|
// Handle later
|
||||||
} else if (scope->is_init && e->kind == Entity_Procedure && name == "main") {
|
} else if (scope->is_init && e->kind == Entity_Procedure && name == "main") {
|
||||||
@@ -2495,8 +2487,8 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
|||||||
if (e->Procedure.is_foreign) {
|
if (e->Procedure.is_foreign) {
|
||||||
name = e->token.string; // NOTE(bill): Don't use the mangled name
|
name = e->token.string; // NOTE(bill): Don't use the mangled name
|
||||||
}
|
}
|
||||||
if (pl->link_name.len > 0) {
|
if (e->Procedure.link_name.len > 0) {
|
||||||
name = pl->link_name;
|
name = e->Procedure.link_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e == entry_point) {
|
if (e == entry_point) {
|
||||||
|
|||||||
+34
-4
@@ -16,11 +16,11 @@ struct String {
|
|||||||
isize len;
|
isize len;
|
||||||
|
|
||||||
u8 &operator[](isize i) {
|
u8 &operator[](isize i) {
|
||||||
GB_ASSERT(0 <= i && i < len);
|
GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
|
||||||
return text[i];
|
return text[i];
|
||||||
}
|
}
|
||||||
u8 const &operator[](isize i) const {
|
u8 const &operator[](isize i) const {
|
||||||
GB_ASSERT(0 <= i && i < len);
|
GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
|
||||||
return text[i];
|
return text[i];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -38,11 +38,11 @@ struct String16 {
|
|||||||
wchar_t *text;
|
wchar_t *text;
|
||||||
isize len;
|
isize len;
|
||||||
wchar_t &operator[](isize i) {
|
wchar_t &operator[](isize i) {
|
||||||
GB_ASSERT(0 <= i && i < len);
|
GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
|
||||||
return text[i];
|
return text[i];
|
||||||
}
|
}
|
||||||
wchar_t const &operator[](isize i) const {
|
wchar_t const &operator[](isize i) const {
|
||||||
GB_ASSERT(0 <= i && i < len);
|
GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
|
||||||
return text[i];
|
return text[i];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -213,6 +213,10 @@ String string_trim_whitespace(String str) {
|
|||||||
str.len--;
|
str.len--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (str.len > 0 && str[str.len-1] == 0) {
|
||||||
|
str.len--;
|
||||||
|
}
|
||||||
|
|
||||||
while (str.len > 0 && rune_is_whitespace(str[0])) {
|
while (str.len > 0 && rune_is_whitespace(str[0])) {
|
||||||
str.text++;
|
str.text++;
|
||||||
str.len--;
|
str.len--;
|
||||||
@@ -267,8 +271,34 @@ String filename_from_path(String s) {
|
|||||||
return make_string(nullptr, 0);
|
return make_string(nullptr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String remove_directory_from_path(String s) {
|
||||||
|
isize len = 0;
|
||||||
|
for (isize i = s.len-1; i >= 0; i--) {
|
||||||
|
if (s[i] == '/' ||
|
||||||
|
s[i] == '\\') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
return substring(s, s.len-len, s.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String concatenate_strings(gbAllocator a, String x, String y) {
|
||||||
|
isize len = x.len+y.len;
|
||||||
|
u8 *data = gb_alloc_array(a, u8, len+1);
|
||||||
|
gb_memmove(data, x.text, x.len);
|
||||||
|
gb_memmove(data+x.len, y.text, y.len);
|
||||||
|
data[len] = 0;
|
||||||
|
return make_string(data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
String copy_string(gbAllocator a, String s) {
|
||||||
|
u8 *data = gb_alloc_array(a, u8, s.len+1);
|
||||||
|
gb_memmove(data, s.text, s.len);
|
||||||
|
data[s.len] = 0;
|
||||||
|
return make_string(data, s.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,184 @@
|
|||||||
|
struct StringSetFindResult {
|
||||||
|
isize hash_index;
|
||||||
|
isize entry_prev;
|
||||||
|
isize entry_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StringSetEntry {
|
||||||
|
HashKey key;
|
||||||
|
isize next;
|
||||||
|
String value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StringSet {
|
||||||
|
Array<isize> hashes;
|
||||||
|
Array<StringSetEntry> entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void string_set_init (StringSet *s, gbAllocator a, isize capacity = 16);
|
||||||
|
void string_set_destroy(StringSet *s);
|
||||||
|
void string_set_add (StringSet *s, String str);
|
||||||
|
bool string_set_exists (StringSet *s, String str);
|
||||||
|
void string_set_remove (StringSet *s, String str);
|
||||||
|
void string_set_clear (StringSet *s);
|
||||||
|
void string_set_grow (StringSet *s);
|
||||||
|
void string_set_rehash (StringSet *s, isize new_count);
|
||||||
|
|
||||||
|
|
||||||
|
gb_inline void string_set_init(StringSet *s, gbAllocator a, isize capacity) {
|
||||||
|
array_init(&s->hashes, a);
|
||||||
|
array_init(&s->entries, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_inline void string_set_destroy(StringSet *s) {
|
||||||
|
array_free(&s->entries);
|
||||||
|
array_free(&s->hashes);
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_internal isize string_set__add_entry(StringSet *s, HashKey key) {
|
||||||
|
StringSetEntry e = {};
|
||||||
|
e.key = key;
|
||||||
|
e.next = -1;
|
||||||
|
array_add(&s->entries, e);
|
||||||
|
return s->entries.count-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_internal StringSetFindResult string_set__find(StringSet *s, HashKey key) {
|
||||||
|
StringSetFindResult fr = {-1, -1, -1};
|
||||||
|
if (s->hashes.count > 0) {
|
||||||
|
// fr.hash_index = u128_to_i64(key.key % u128_from_i64(s->hashes.count));
|
||||||
|
fr.hash_index = key.key % s->hashes.count;
|
||||||
|
fr.entry_index = s->hashes[fr.hash_index];
|
||||||
|
while (fr.entry_index >= 0) {
|
||||||
|
if (hash_key_equal(s->entries[fr.entry_index].key, key)) {
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
fr.entry_prev = fr.entry_index;
|
||||||
|
fr.entry_index = s->entries[fr.entry_index].next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_internal StringSetFindResult string_set__find_from_entry(StringSet *s, StringSetEntry *e) {
|
||||||
|
StringSetFindResult fr = {-1, -1, -1};
|
||||||
|
if (s->hashes.count > 0) {
|
||||||
|
fr.hash_index = e->key.key % s->hashes.count;
|
||||||
|
fr.entry_index = s->hashes[fr.hash_index];
|
||||||
|
while (fr.entry_index >= 0) {
|
||||||
|
if (&s->entries[fr.entry_index] == e) {
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
fr.entry_prev = fr.entry_index;
|
||||||
|
fr.entry_index = s->entries[fr.entry_index].next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_internal b32 string_set__full(StringSet *s) {
|
||||||
|
return 0.75f * s->hashes.count <= s->entries.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_inline void string_set_grow(StringSet *s) {
|
||||||
|
isize new_count = ARRAY_GROW_FORMULA(s->entries.count);
|
||||||
|
string_set_rehash(s, new_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void string_set_rehash(StringSet *s, isize new_count) {
|
||||||
|
isize i, j;
|
||||||
|
StringSet ns = {};
|
||||||
|
string_set_init(&ns, s->hashes.allocator);
|
||||||
|
array_resize(&ns.hashes, new_count);
|
||||||
|
array_reserve(&ns.entries, s->entries.count);
|
||||||
|
for (i = 0; i < new_count; i++) {
|
||||||
|
ns.hashes[i] = -1;
|
||||||
|
}
|
||||||
|
for (i = 0; i < s->entries.count; i++) {
|
||||||
|
StringSetEntry *e = &s->entries[i];
|
||||||
|
StringSetFindResult fr;
|
||||||
|
if (ns.hashes.count == 0) {
|
||||||
|
string_set_grow(&ns);
|
||||||
|
}
|
||||||
|
fr = string_set__find(&ns, e->key);
|
||||||
|
j = string_set__add_entry(&ns, e->key);
|
||||||
|
if (fr.entry_prev < 0) {
|
||||||
|
ns.hashes[fr.hash_index] = j;
|
||||||
|
} else {
|
||||||
|
ns.entries[fr.entry_prev].next = j;
|
||||||
|
}
|
||||||
|
ns.entries[j].next = fr.entry_index;
|
||||||
|
ns.entries[j].value = e->value;
|
||||||
|
if (string_set__full(&ns)) {
|
||||||
|
string_set_grow(&ns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string_set_destroy(s);
|
||||||
|
*s = ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_inline bool string_set_exists(StringSet *s, String str) {
|
||||||
|
HashKey key = hash_string(str);
|
||||||
|
isize index = string_set__find(s, key).entry_index;
|
||||||
|
return index >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void string_set_add(StringSet *s, String str) {
|
||||||
|
isize index;
|
||||||
|
StringSetFindResult fr;
|
||||||
|
HashKey key = hash_string(str);
|
||||||
|
if (s->hashes.count == 0) {
|
||||||
|
string_set_grow(s);
|
||||||
|
}
|
||||||
|
fr = string_set__find(s, key);
|
||||||
|
if (fr.entry_index >= 0) {
|
||||||
|
index = fr.entry_index;
|
||||||
|
} else {
|
||||||
|
index = string_set__add_entry(s, key);
|
||||||
|
if (fr.entry_prev >= 0) {
|
||||||
|
s->entries[fr.entry_prev].next = index;
|
||||||
|
} else {
|
||||||
|
s->hashes[fr.hash_index] = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s->entries[index].value = str;
|
||||||
|
|
||||||
|
if (string_set__full(s)) {
|
||||||
|
string_set_grow(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void string_set__erase(StringSet *s, StringSetFindResult fr) {
|
||||||
|
StringSetFindResult last;
|
||||||
|
if (fr.entry_prev < 0) {
|
||||||
|
s->hashes[fr.hash_index] = s->entries[fr.entry_index].next;
|
||||||
|
} else {
|
||||||
|
s->entries[fr.entry_prev].next = s->entries[fr.entry_index].next;
|
||||||
|
}
|
||||||
|
if (fr.entry_index == s->entries.count-1) {
|
||||||
|
array_pop(&s->entries);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s->entries[fr.entry_index] = s->entries[s->entries.count-1];
|
||||||
|
last = string_set__find(s, s->entries[fr.entry_index].key);
|
||||||
|
if (last.entry_prev >= 0) {
|
||||||
|
s->entries[last.entry_prev].next = fr.entry_index;
|
||||||
|
} else {
|
||||||
|
s->hashes[last.hash_index] = fr.entry_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void string_set_remove(StringSet *s, String str) {
|
||||||
|
HashKey key = hash_string(str);
|
||||||
|
StringSetFindResult fr = string_set__find(s, key);
|
||||||
|
if (fr.entry_index >= 0) {
|
||||||
|
string_set__erase(s, fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_inline void string_set_clear(StringSet *s) {
|
||||||
|
array_clear(&s->hashes);
|
||||||
|
array_clear(&s->entries);
|
||||||
|
}
|
||||||
+32
-28
@@ -55,8 +55,6 @@ TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
|||||||
TOKEN_KIND(Token_ArrowRight, "->"), \
|
TOKEN_KIND(Token_ArrowRight, "->"), \
|
||||||
TOKEN_KIND(Token_ArrowLeft, "<-"), \
|
TOKEN_KIND(Token_ArrowLeft, "<-"), \
|
||||||
TOKEN_KIND(Token_DoubleArrowRight, "=>"), \
|
TOKEN_KIND(Token_DoubleArrowRight, "=>"), \
|
||||||
/* TOKEN_KIND(Token_Inc, "++"), */ \
|
|
||||||
/* TOKEN_KIND(Token_Dec, "--"), */ \
|
|
||||||
TOKEN_KIND(Token_Undef, "---"), \
|
TOKEN_KIND(Token_Undef, "---"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
|
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
|
||||||
@@ -85,16 +83,14 @@ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
|
|||||||
\
|
\
|
||||||
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||||
TOKEN_KIND(Token_import, "import"), \
|
TOKEN_KIND(Token_import, "import"), \
|
||||||
TOKEN_KIND(Token_import_load, "import_load"), \
|
TOKEN_KIND(Token_export, "export"), \
|
||||||
TOKEN_KIND(Token_foreign, "foreign"), \
|
TOKEN_KIND(Token_foreign, "foreign"), \
|
||||||
TOKEN_KIND(Token_foreign_library, "foreign_library"), \
|
|
||||||
TOKEN_KIND(Token_foreign_system_library, "foreign_system_library"), \
|
|
||||||
TOKEN_KIND(Token_type, "type"), \
|
TOKEN_KIND(Token_type, "type"), \
|
||||||
TOKEN_KIND(Token_when, "when"), \
|
TOKEN_KIND(Token_when, "when"), \
|
||||||
TOKEN_KIND(Token_if, "if"), \
|
TOKEN_KIND(Token_if, "if"), \
|
||||||
TOKEN_KIND(Token_else, "else"), \
|
TOKEN_KIND(Token_else, "else"), \
|
||||||
TOKEN_KIND(Token_for, "for"), \
|
TOKEN_KIND(Token_for, "for"), \
|
||||||
TOKEN_KIND(Token_match, "match"), \
|
TOKEN_KIND(Token_switch, "switch"), \
|
||||||
TOKEN_KIND(Token_in, "in"), \
|
TOKEN_KIND(Token_in, "in"), \
|
||||||
TOKEN_KIND(Token_do, "do"), \
|
TOKEN_KIND(Token_do, "do"), \
|
||||||
TOKEN_KIND(Token_case, "case"), \
|
TOKEN_KIND(Token_case, "case"), \
|
||||||
@@ -116,9 +112,9 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
|||||||
TOKEN_KIND(Token_cast, "cast"), \
|
TOKEN_KIND(Token_cast, "cast"), \
|
||||||
TOKEN_KIND(Token_transmute, "transmute"), \
|
TOKEN_KIND(Token_transmute, "transmute"), \
|
||||||
TOKEN_KIND(Token_using, "using"), \
|
TOKEN_KIND(Token_using, "using"), \
|
||||||
|
TOKEN_KIND(Token_inline, "inline"), \
|
||||||
|
TOKEN_KIND(Token_no_inline, "no_inline"), \
|
||||||
TOKEN_KIND(Token_context, "context"), \
|
TOKEN_KIND(Token_context, "context"), \
|
||||||
TOKEN_KIND(Token_push_context, "push_context"), \
|
|
||||||
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
|
|
||||||
TOKEN_KIND(Token_size_of, "size_of"), \
|
TOKEN_KIND(Token_size_of, "size_of"), \
|
||||||
TOKEN_KIND(Token_align_of, "align_of"), \
|
TOKEN_KIND(Token_align_of, "align_of"), \
|
||||||
TOKEN_KIND(Token_offset_of, "offset_of"), \
|
TOKEN_KIND(Token_offset_of, "offset_of"), \
|
||||||
@@ -149,21 +145,27 @@ struct TokenPos {
|
|||||||
isize column;
|
isize column;
|
||||||
};
|
};
|
||||||
|
|
||||||
i32 token_pos_cmp(TokenPos a, TokenPos b) {
|
TokenPos token_pos(String file, isize line, isize column) {
|
||||||
if (a.line == b.line) {
|
TokenPos pos = {file, line, column};
|
||||||
if (a.column == b.column) {
|
return pos;
|
||||||
isize min_len = gb_min(a.file.len, b.file.len);
|
}
|
||||||
return gb_memcompare(a.file.text, b.file.text, min_len);
|
|
||||||
}
|
i32 token_pos_cmp(TokenPos const &a, TokenPos const &b) {
|
||||||
|
if (a.line != b.line) {
|
||||||
|
return (a.line < b.line) ? -1 : +1;
|
||||||
|
}
|
||||||
|
if (a.column != b.column) {
|
||||||
return (a.column < b.column) ? -1 : +1;
|
return (a.column < b.column) ? -1 : +1;
|
||||||
}
|
}
|
||||||
|
return string_compare(a.file, b.file);
|
||||||
return (a.line < b.line) ? -1 : +1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool token_pos_eq(TokenPos a, TokenPos b) {
|
bool operator==(TokenPos const &a, TokenPos const &b) { return token_pos_cmp(a, b) == 0; }
|
||||||
return token_pos_cmp(a, b) == 0;
|
bool operator!=(TokenPos const &a, TokenPos const &b) { return token_pos_cmp(a, b) != 0; }
|
||||||
}
|
bool operator< (TokenPos const &a, TokenPos const &b) { return token_pos_cmp(a, b) < 0; }
|
||||||
|
bool operator<=(TokenPos const &a, TokenPos const &b) { return token_pos_cmp(a, b) <= 0; }
|
||||||
|
bool operator> (TokenPos const &a, TokenPos const &b) { return token_pos_cmp(a, b) > 0; }
|
||||||
|
bool operator>=(TokenPos const &a, TokenPos const &b) { return token_pos_cmp(a, b) >= 0; }
|
||||||
|
|
||||||
struct Token {
|
struct Token {
|
||||||
TokenKind kind;
|
TokenKind kind;
|
||||||
@@ -197,7 +199,7 @@ void warning_va(Token token, char *fmt, va_list va) {
|
|||||||
gb_mutex_lock(&global_error_collector.mutex);
|
gb_mutex_lock(&global_error_collector.mutex);
|
||||||
global_error_collector.warning_count++;
|
global_error_collector.warning_count++;
|
||||||
// NOTE(bill): Duplicate error, skip it
|
// NOTE(bill): Duplicate error, skip it
|
||||||
if (!token_pos_eq(global_error_collector.prev, token.pos)) {
|
if (global_error_collector.prev != token.pos) {
|
||||||
global_error_collector.prev = token.pos;
|
global_error_collector.prev = token.pos;
|
||||||
gb_printf_err("%.*s(%td:%td) Warning: %s\n",
|
gb_printf_err("%.*s(%td:%td) Warning: %s\n",
|
||||||
LIT(token.pos.file), token.pos.line, token.pos.column,
|
LIT(token.pos.file), token.pos.line, token.pos.column,
|
||||||
@@ -211,7 +213,7 @@ void error_va(Token token, char *fmt, va_list va) {
|
|||||||
gb_mutex_lock(&global_error_collector.mutex);
|
gb_mutex_lock(&global_error_collector.mutex);
|
||||||
global_error_collector.count++;
|
global_error_collector.count++;
|
||||||
// NOTE(bill): Duplicate error, skip it
|
// NOTE(bill): Duplicate error, skip it
|
||||||
if (!token_pos_eq(global_error_collector.prev, token.pos)) {
|
if (global_error_collector.prev != token.pos) {
|
||||||
global_error_collector.prev = token.pos;
|
global_error_collector.prev = token.pos;
|
||||||
gb_printf_err("%.*s(%td:%td) %s\n",
|
gb_printf_err("%.*s(%td:%td) %s\n",
|
||||||
LIT(token.pos.file), token.pos.line, token.pos.column,
|
LIT(token.pos.file), token.pos.line, token.pos.column,
|
||||||
@@ -227,7 +229,7 @@ void syntax_error_va(Token token, char *fmt, va_list va) {
|
|||||||
gb_mutex_lock(&global_error_collector.mutex);
|
gb_mutex_lock(&global_error_collector.mutex);
|
||||||
global_error_collector.count++;
|
global_error_collector.count++;
|
||||||
// NOTE(bill): Duplicate error, skip it
|
// NOTE(bill): Duplicate error, skip it
|
||||||
if (!token_pos_eq(global_error_collector.prev, token.pos)) {
|
if (global_error_collector.prev != token.pos) {
|
||||||
global_error_collector.prev = token.pos;
|
global_error_collector.prev = token.pos;
|
||||||
gb_printf_err("%.*s(%td:%td) Syntax Error: %s\n",
|
gb_printf_err("%.*s(%td:%td) Syntax Error: %s\n",
|
||||||
LIT(token.pos.file), token.pos.line, token.pos.column,
|
LIT(token.pos.file), token.pos.line, token.pos.column,
|
||||||
@@ -243,7 +245,7 @@ void syntax_warning_va(Token token, char *fmt, va_list va) {
|
|||||||
gb_mutex_lock(&global_error_collector.mutex);
|
gb_mutex_lock(&global_error_collector.mutex);
|
||||||
global_error_collector.warning_count++;
|
global_error_collector.warning_count++;
|
||||||
// NOTE(bill): Duplicate error, skip it
|
// NOTE(bill): Duplicate error, skip it
|
||||||
if (!token_pos_eq(global_error_collector.prev, token.pos)) {
|
if (global_error_collector.prev != token.pos) {
|
||||||
global_error_collector.prev = token.pos;
|
global_error_collector.prev = token.pos;
|
||||||
gb_printf_err("%.*s(%td:%td) Syntax Warning: %s\n",
|
gb_printf_err("%.*s(%td:%td) Syntax Warning: %s\n",
|
||||||
LIT(token.pos.file), token.pos.line, token.pos.column,
|
LIT(token.pos.file), token.pos.line, token.pos.column,
|
||||||
@@ -428,18 +430,22 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
|
|||||||
TokenizerInitError err = TokenizerInit_None;
|
TokenizerInitError err = TokenizerInit_None;
|
||||||
|
|
||||||
char *c_str = gb_alloc_array(heap_allocator(), char, fullpath.len+1);
|
char *c_str = gb_alloc_array(heap_allocator(), char, fullpath.len+1);
|
||||||
|
defer (gb_free(heap_allocator(), c_str));
|
||||||
|
|
||||||
gb_memcopy(c_str, fullpath.text, fullpath.len);
|
gb_memcopy(c_str, fullpath.text, fullpath.len);
|
||||||
c_str[fullpath.len] = '\0';
|
c_str[fullpath.len] = '\0';
|
||||||
|
|
||||||
// TODO(bill): Memory map rather than copy contents
|
// TODO(bill): Memory map rather than copy contents
|
||||||
gbFileContents fc = gb_file_read_contents(heap_allocator(), true, c_str);
|
gbFileContents fc = gb_file_read_contents(heap_allocator(), true, c_str);
|
||||||
gb_zero_item(t);
|
gb_zero_item(t);
|
||||||
|
|
||||||
|
t->fullpath = fullpath;
|
||||||
|
t->line_count = 1;
|
||||||
|
|
||||||
if (fc.data != nullptr) {
|
if (fc.data != nullptr) {
|
||||||
t->start = cast(u8 *)fc.data;
|
t->start = cast(u8 *)fc.data;
|
||||||
t->line = t->read_curr = t->curr = t->start;
|
t->line = t->read_curr = t->curr = t->start;
|
||||||
t->end = t->start + fc.size;
|
t->end = t->start + fc.size;
|
||||||
t->fullpath = fullpath;
|
|
||||||
t->line_count = 1;
|
|
||||||
|
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
if (t->curr_rune == GB_RUNE_BOM) {
|
if (t->curr_rune == GB_RUNE_BOM) {
|
||||||
@@ -450,6 +456,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
|
|||||||
} else {
|
} else {
|
||||||
gbFile f = {};
|
gbFile f = {};
|
||||||
gbFileError file_err = gb_file_open(&f, c_str);
|
gbFileError file_err = gb_file_open(&f, c_str);
|
||||||
|
defer (gb_file_close(&f));
|
||||||
|
|
||||||
switch (file_err) {
|
switch (file_err) {
|
||||||
case gbFileError_Invalid: err = TokenizerInit_Invalid; break;
|
case gbFileError_Invalid: err = TokenizerInit_Invalid; break;
|
||||||
@@ -460,11 +467,8 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
|
|||||||
if (err == TokenizerInit_None && gb_file_size(&f) == 0) {
|
if (err == TokenizerInit_None && gb_file_size(&f) == 0) {
|
||||||
err = TokenizerInit_Empty;
|
err = TokenizerInit_Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_file_close(&f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_free(heap_allocator(), c_str);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+212
-97
@@ -3,6 +3,7 @@ struct AstNode;
|
|||||||
|
|
||||||
enum BasicKind {
|
enum BasicKind {
|
||||||
Basic_Invalid,
|
Basic_Invalid,
|
||||||
|
|
||||||
Basic_bool,
|
Basic_bool,
|
||||||
Basic_i8,
|
Basic_i8,
|
||||||
Basic_u8,
|
Basic_u8,
|
||||||
@@ -27,9 +28,10 @@ enum BasicKind {
|
|||||||
|
|
||||||
Basic_int,
|
Basic_int,
|
||||||
Basic_uint,
|
Basic_uint,
|
||||||
|
Basic_uintptr,
|
||||||
Basic_rawptr,
|
Basic_rawptr,
|
||||||
Basic_string, // ^u8 + int
|
Basic_string, // ^u8 + int
|
||||||
Basic_any, // ^Type_Info + rawptr
|
Basic_any, // rawptr + ^Type_Info
|
||||||
|
|
||||||
Basic_UntypedBool,
|
Basic_UntypedBool,
|
||||||
Basic_UntypedInteger,
|
Basic_UntypedInteger,
|
||||||
@@ -82,6 +84,7 @@ struct TypeStruct {
|
|||||||
bool is_raw_union;
|
bool is_raw_union;
|
||||||
bool is_polymorphic;
|
bool is_polymorphic;
|
||||||
bool is_poly_specialized;
|
bool is_poly_specialized;
|
||||||
|
bool has_proc_default_values;
|
||||||
Type * polymorphic_params; // Type_Tuple
|
Type * polymorphic_params; // Type_Tuple
|
||||||
Type * polymorphic_parent;
|
Type * polymorphic_parent;
|
||||||
|
|
||||||
@@ -95,11 +98,20 @@ struct TypeStruct {
|
|||||||
i64 id; \
|
i64 id; \
|
||||||
String name; \
|
String name; \
|
||||||
Type * specialized; \
|
Type * specialized; \
|
||||||
|
Scope *scope; \
|
||||||
}) \
|
}) \
|
||||||
TYPE_KIND(Pointer, struct { Type *elem; }) \
|
TYPE_KIND(Pointer, struct { Type *elem; }) \
|
||||||
TYPE_KIND(Array, struct { Type *elem; i64 count; }) \
|
TYPE_KIND(Array, struct { \
|
||||||
|
Type *elem; \
|
||||||
|
i64 count; \
|
||||||
|
Type *generic_type; \
|
||||||
|
}) \
|
||||||
TYPE_KIND(DynamicArray, struct { Type *elem; }) \
|
TYPE_KIND(DynamicArray, struct { Type *elem; }) \
|
||||||
TYPE_KIND(Vector, struct { Type *elem; i64 count; }) \
|
TYPE_KIND(Vector, struct { \
|
||||||
|
Type *elem; \
|
||||||
|
i64 count; \
|
||||||
|
Type *generic_type; \
|
||||||
|
}) \
|
||||||
TYPE_KIND(Slice, struct { Type *elem; }) \
|
TYPE_KIND(Slice, struct { Type *elem; }) \
|
||||||
TYPE_KIND(Struct, TypeStruct) \
|
TYPE_KIND(Struct, TypeStruct) \
|
||||||
TYPE_KIND(Enum, struct { \
|
TYPE_KIND(Enum, struct { \
|
||||||
@@ -117,7 +129,6 @@ struct TypeStruct {
|
|||||||
Array<Type *> variants; \
|
Array<Type *> variants; \
|
||||||
AstNode *node; \
|
AstNode *node; \
|
||||||
Scope * scope; \
|
Scope * scope; \
|
||||||
Entity * union__type_info; \
|
|
||||||
i64 variant_block_size; \
|
i64 variant_block_size; \
|
||||||
i64 custom_align; \
|
i64 custom_align; \
|
||||||
}) \
|
}) \
|
||||||
@@ -138,14 +149,16 @@ struct TypeStruct {
|
|||||||
Type * results; /* Type_Tuple */ \
|
Type * results; /* Type_Tuple */ \
|
||||||
i32 param_count; \
|
i32 param_count; \
|
||||||
i32 result_count; \
|
i32 result_count; \
|
||||||
bool return_by_pointer; \
|
|
||||||
Type ** abi_compat_params; \
|
Type ** abi_compat_params; \
|
||||||
Type * abi_compat_result_type; \
|
Type * abi_compat_result_type; \
|
||||||
|
bool return_by_pointer; \
|
||||||
bool variadic; \
|
bool variadic; \
|
||||||
|
i32 variadic_index; \
|
||||||
bool require_results; \
|
bool require_results; \
|
||||||
bool c_vararg; \
|
bool c_vararg; \
|
||||||
bool is_polymorphic; \
|
bool is_polymorphic; \
|
||||||
bool is_poly_specialized; \
|
bool is_poly_specialized; \
|
||||||
|
bool has_proc_default_values; \
|
||||||
isize specialization_count; \
|
isize specialization_count; \
|
||||||
ProcCallingConvention calling_convention; \
|
ProcCallingConvention calling_convention; \
|
||||||
}) \
|
}) \
|
||||||
@@ -252,6 +265,7 @@ gb_global Type basic_types[] = {
|
|||||||
|
|
||||||
{Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}},
|
{Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}},
|
||||||
{Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}},
|
{Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}},
|
||||||
|
{Type_Basic, {Basic_uintptr, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uintptr")}},
|
||||||
|
|
||||||
{Type_Basic, {Basic_rawptr, BasicFlag_Pointer, -1, STR_LIT("rawptr")}},
|
{Type_Basic, {Basic_rawptr, BasicFlag_Pointer, -1, STR_LIT("rawptr")}},
|
||||||
{Type_Basic, {Basic_string, BasicFlag_String, -1, STR_LIT("string")}},
|
{Type_Basic, {Basic_string, BasicFlag_String, -1, STR_LIT("string")}},
|
||||||
@@ -297,6 +311,7 @@ gb_global Type *t_complex128 = &basic_types[Basic_complex128];
|
|||||||
|
|
||||||
gb_global Type *t_int = &basic_types[Basic_int];
|
gb_global Type *t_int = &basic_types[Basic_int];
|
||||||
gb_global Type *t_uint = &basic_types[Basic_uint];
|
gb_global Type *t_uint = &basic_types[Basic_uint];
|
||||||
|
gb_global Type *t_uintptr = &basic_types[Basic_uintptr];
|
||||||
|
|
||||||
gb_global Type *t_rawptr = &basic_types[Basic_rawptr];
|
gb_global Type *t_rawptr = &basic_types[Basic_rawptr];
|
||||||
gb_global Type *t_string = &basic_types[Basic_string];
|
gb_global Type *t_string = &basic_types[Basic_string];
|
||||||
@@ -461,11 +476,12 @@ Type *make_type_basic(gbAllocator a, BasicType basic) {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *make_type_generic(gbAllocator a, i64 id, String name, Type *specialized) {
|
Type *make_type_generic(gbAllocator a, Scope *scope, i64 id, String name, Type *specialized) {
|
||||||
Type *t = alloc_type(a, Type_Generic);
|
Type *t = alloc_type(a, Type_Generic);
|
||||||
t->Generic.id = id;
|
t->Generic.id = id;
|
||||||
t->Generic.name = name;
|
t->Generic.name = name;
|
||||||
t->Generic.specialized = specialized;
|
t->Generic.specialized = specialized;
|
||||||
|
t->Generic.scope = scope;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,10 +491,11 @@ Type *make_type_pointer(gbAllocator a, Type *elem) {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *make_type_array(gbAllocator a, Type *elem, i64 count) {
|
Type *make_type_array(gbAllocator a, Type *elem, i64 count, Type *generic_type = nullptr) {
|
||||||
Type *t = alloc_type(a, Type_Array);
|
Type *t = alloc_type(a, Type_Array);
|
||||||
t->Array.elem = elem;
|
t->Array.elem = elem;
|
||||||
t->Array.count = count;
|
t->Array.count = count;
|
||||||
|
t->Array.generic_type = generic_type;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,10 +505,11 @@ Type *make_type_dynamic_array(gbAllocator a, Type *elem) {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *make_type_vector(gbAllocator a, Type *elem, i64 count) {
|
Type *make_type_vector(gbAllocator a, Type *elem, i64 count, Type *generic_type = nullptr) {
|
||||||
Type *t = alloc_type(a, Type_Vector);
|
Type *t = alloc_type(a, Type_Vector);
|
||||||
t->Vector.elem = elem;
|
t->Vector.elem = elem;
|
||||||
t->Vector.count = count;
|
t->Vector.count = count;
|
||||||
|
t->Vector.generic_type = generic_type;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -657,6 +675,11 @@ bool is_type_numeric(Type *t) {
|
|||||||
if (t->kind == Type_Vector) {
|
if (t->kind == Type_Vector) {
|
||||||
return is_type_numeric(t->Vector.elem);
|
return is_type_numeric(t->Vector.elem);
|
||||||
}
|
}
|
||||||
|
#if defined(ALLOW_ARRAY_PROGRAMMING)
|
||||||
|
if (t->kind == Type_Array) {
|
||||||
|
return is_type_numeric(t->Array.elem);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool is_type_string(Type *t) {
|
bool is_type_string(Type *t) {
|
||||||
@@ -743,9 +766,9 @@ bool is_type_tuple(Type *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_type_int_or_uint(Type *t) {
|
bool is_type_uintptr(Type *t) {
|
||||||
if (t->kind == Type_Basic) {
|
if (t->kind == Type_Basic) {
|
||||||
return (t->Basic.kind == Basic_int) || (t->Basic.kind == Basic_uint);
|
return (t->Basic.kind == Basic_uintptr);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -805,6 +828,29 @@ Type *base_vector_type(Type *t) {
|
|||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
Type *base_array_type(Type *t) {
|
||||||
|
if (is_type_array(t)) {
|
||||||
|
t = base_type(t);
|
||||||
|
return t->Array.elem;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_type_generic(Type *t) {
|
||||||
|
t = base_type(t);
|
||||||
|
return t->kind == Type_Generic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Type *core_array_or_vector_type(Type *t) {
|
||||||
|
for (;;) {
|
||||||
|
Type *prev = t;
|
||||||
|
t = base_array_type(t);
|
||||||
|
t = base_vector_type(t);
|
||||||
|
if (prev == t) break;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
Type *base_complex_elem_type(Type *t) {
|
Type *base_complex_elem_type(Type *t) {
|
||||||
t = core_type(t);
|
t = core_type(t);
|
||||||
@@ -934,11 +980,14 @@ bool is_type_polymorphic(Type *t) {
|
|||||||
case Type_Pointer:
|
case Type_Pointer:
|
||||||
return is_type_polymorphic(t->Pointer.elem);
|
return is_type_polymorphic(t->Pointer.elem);
|
||||||
case Type_Array:
|
case Type_Array:
|
||||||
|
if (t->Array.generic_type != nullptr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return is_type_polymorphic(t->Array.elem);
|
return is_type_polymorphic(t->Array.elem);
|
||||||
case Type_DynamicArray:
|
|
||||||
return is_type_polymorphic(t->DynamicArray.elem);
|
|
||||||
case Type_Vector:
|
case Type_Vector:
|
||||||
return is_type_polymorphic(t->Vector.elem);
|
return is_type_polymorphic(t->Vector.elem);
|
||||||
|
case Type_DynamicArray:
|
||||||
|
return is_type_polymorphic(t->DynamicArray.elem);
|
||||||
case Type_Slice:
|
case Type_Slice:
|
||||||
return is_type_polymorphic(t->Slice.elem);
|
return is_type_polymorphic(t->Slice.elem);
|
||||||
|
|
||||||
@@ -1037,6 +1086,13 @@ bool type_has_nil(Type *t) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool elem_type_can_be_constant(Type *t) {
|
||||||
|
if (is_type_any(t) || is_type_union(t)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_type_comparable(Type *t) {
|
bool is_type_comparable(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
@@ -1055,7 +1111,7 @@ bool is_type_comparable(Type *t) {
|
|||||||
case Type_Enum:
|
case Type_Enum:
|
||||||
return is_type_comparable(core_type(t));
|
return is_type_comparable(core_type(t));
|
||||||
case Type_Array:
|
case Type_Array:
|
||||||
return false;
|
return is_type_comparable(t->Array.elem);
|
||||||
case Type_Vector:
|
case Type_Vector:
|
||||||
return is_type_comparable(t->Vector.elem);
|
return is_type_comparable(t->Vector.elem);
|
||||||
case Type_Proc:
|
case Type_Proc:
|
||||||
@@ -1111,6 +1167,24 @@ bool are_types_identical(Type *x, Type *y) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Type_BitField:
|
||||||
|
if (y->kind == Type_BitField) {
|
||||||
|
if (x->BitField.field_count == y->BitField.field_count &&
|
||||||
|
x->BitField.custom_align == y->BitField.custom_align) {
|
||||||
|
for (i32 i = 0; i < x->BitField.field_count; i++) {
|
||||||
|
if (x->BitField.offsets[i] != y->BitField.offsets[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (x->BitField.sizes[i] != y->BitField.sizes[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
case Type_Enum:
|
case Type_Enum:
|
||||||
return x == y; // NOTE(bill): All enums are unique
|
return x == y; // NOTE(bill): All enums are unique
|
||||||
@@ -1308,6 +1382,42 @@ bool is_type_cte_safe(Type *type) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i64 union_variant_index(Type *u, Type *v) {
|
||||||
|
u = base_type(u);
|
||||||
|
GB_ASSERT(u->kind == Type_Union);
|
||||||
|
|
||||||
|
for_array(i, u->Union.variants) {
|
||||||
|
Type *vt = u->Union.variants[i];
|
||||||
|
if (are_types_identical(v, vt)) {
|
||||||
|
return cast(i64)(i+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
i64 union_tag_size(Type *u) {
|
||||||
|
u = base_type(u);
|
||||||
|
GB_ASSERT(u->kind == Type_Union);
|
||||||
|
u64 cl2 = ceil_log2(cast(u64)u->Union.variants.count);
|
||||||
|
i64 s = (next_pow2(cast(i64)cl2) + 7)/8;
|
||||||
|
return gb_clamp(s, 1, build_context.word_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *union_tag_type(Type *u) {
|
||||||
|
i64 s = union_tag_size(u);
|
||||||
|
switch (s) {
|
||||||
|
case 1: return t_u8;
|
||||||
|
case 2: return t_u16;
|
||||||
|
case 4: return t_u32;
|
||||||
|
case 8: return t_u64;
|
||||||
|
case 16: return t_u128;
|
||||||
|
}
|
||||||
|
GB_PANIC("Invalid union_tag_size");
|
||||||
|
return t_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum ProcTypeOverloadKind {
|
enum ProcTypeOverloadKind {
|
||||||
ProcOverload_Identical, // The types are identical
|
ProcOverload_Identical, // The types are identical
|
||||||
|
|
||||||
@@ -1587,20 +1697,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (type->kind == Type_Union) {
|
} else if (type->kind == Type_Union) {
|
||||||
if (field_name == "__type_info") {
|
|
||||||
Entity *e = type->Union.union__type_info;
|
|
||||||
if (e == nullptr) {
|
|
||||||
Entity *__type_info = make_entity_field(a, nullptr, make_token_ident(str_lit("__type_info")), t_type_info_ptr, false, -1);
|
|
||||||
type->Union.union__type_info = __type_info;
|
|
||||||
e = __type_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
GB_ASSERT(e != nullptr);
|
|
||||||
selection_add_index(&sel, -1); // HACK(bill): Leaky memory
|
|
||||||
sel.entity = e;
|
|
||||||
|
|
||||||
return sel;
|
|
||||||
}
|
|
||||||
} else if (type->kind == Type_Struct) {
|
} else if (type->kind == Type_Struct) {
|
||||||
for_array(i, type->Struct.fields) {
|
for_array(i, type->Struct.fields) {
|
||||||
Entity *f = type->Struct.fields[i];
|
Entity *f = type->Struct.fields[i];
|
||||||
@@ -1651,7 +1748,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
|||||||
|
|
||||||
|
|
||||||
struct TypePath {
|
struct TypePath {
|
||||||
Array<Type *> path; // Entity_TypeName;
|
Array<Entity *> path; // Entity_TypeName;
|
||||||
bool failure;
|
bool failure;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1668,38 +1765,37 @@ void type_path_print_illegal_cycle(TypePath *tp, isize start_index) {
|
|||||||
GB_ASSERT(tp != nullptr);
|
GB_ASSERT(tp != nullptr);
|
||||||
|
|
||||||
GB_ASSERT(start_index < tp->path.count);
|
GB_ASSERT(start_index < tp->path.count);
|
||||||
Type *t = tp->path[start_index];
|
Entity *e = tp->path[start_index];
|
||||||
GB_ASSERT(t != nullptr);
|
GB_ASSERT(e != nullptr);
|
||||||
|
error(e->token, "Illegal declaration cycle of `%.*s`", LIT(e->token.string));
|
||||||
GB_ASSERT_MSG(is_type_named(t), "%s", type_to_string(t));
|
|
||||||
Entity *e = t->Named.type_name;
|
|
||||||
error(e->token, "Illegal declaration cycle of `%.*s`", LIT(t->Named.name));
|
|
||||||
// NOTE(bill): Print cycle, if it's deep enough
|
// NOTE(bill): Print cycle, if it's deep enough
|
||||||
for (isize j = start_index; j < tp->path.count; j++) {
|
for (isize j = start_index; j < tp->path.count; j++) {
|
||||||
Type *t = tp->path[j];
|
Entity *e = tp->path[j];
|
||||||
GB_ASSERT_MSG(is_type_named(t), "%s", type_to_string(t));
|
error(e->token, "\t%.*s refers to", LIT(e->token.string));
|
||||||
Entity *e = t->Named.type_name;
|
|
||||||
error(e->token, "\t%.*s refers to", LIT(t->Named.name));
|
|
||||||
}
|
}
|
||||||
// NOTE(bill): This will only print if the path count > 1
|
// NOTE(bill): This will only print if the path count > 1
|
||||||
error(e->token, "\t%.*s", LIT(t->Named.name));
|
error(e->token, "\t%.*s", LIT(e->token.string));
|
||||||
tp->failure = true;
|
tp->failure = true;
|
||||||
t->failure = true;
|
e->type->failure = true;
|
||||||
|
base_type(e->type)->failure = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePath *type_path_push(TypePath *tp, Type *t) {
|
bool type_path_push(TypePath *tp, Type *t) {
|
||||||
GB_ASSERT(tp != nullptr);
|
GB_ASSERT(tp != nullptr);
|
||||||
|
if (t->kind != Type_Named) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Entity *e = t->Named.type_name;
|
||||||
|
|
||||||
for (isize i = 0; i < tp->path.count; i++) {
|
for (isize i = 0; i < tp->path.count; i++) {
|
||||||
if (tp->path[i] == t) {
|
Entity *p = tp->path[i];
|
||||||
|
if (p == e) {
|
||||||
type_path_print_illegal_cycle(tp, i);
|
type_path_print_illegal_cycle(tp, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tp->failure && is_type_named(t)) {
|
array_add(&tp->path, e);
|
||||||
array_add(&tp->path, t);
|
return true;
|
||||||
}
|
|
||||||
return tp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void type_path_pop(TypePath *tp) {
|
void type_path_pop(TypePath *tp) {
|
||||||
@@ -1750,6 +1846,7 @@ i64 type_align_of(gbAllocator allocator, Type *t) {
|
|||||||
|
|
||||||
|
|
||||||
i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||||
|
GB_ASSERT(path != nullptr);
|
||||||
if (t->failure) {
|
if (t->failure) {
|
||||||
return FAILURE_ALIGNMENT;
|
return FAILURE_ALIGNMENT;
|
||||||
}
|
}
|
||||||
@@ -1763,7 +1860,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
case Basic_string: return build_context.word_size;
|
case Basic_string: return build_context.word_size;
|
||||||
case Basic_any: return build_context.word_size;
|
case Basic_any: return build_context.word_size;
|
||||||
|
|
||||||
case Basic_int: case Basic_uint: case Basic_rawptr:
|
case Basic_int: case Basic_uint: case Basic_uintptr: case Basic_rawptr:
|
||||||
return build_context.word_size;
|
return build_context.word_size;
|
||||||
|
|
||||||
case Basic_complex64: case Basic_complex128:
|
case Basic_complex64: case Basic_complex128:
|
||||||
@@ -1773,14 +1870,26 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
|
|
||||||
case Type_Array: {
|
case Type_Array: {
|
||||||
Type *elem = t->Array.elem;
|
Type *elem = t->Array.elem;
|
||||||
type_path_push(path, elem);
|
bool pop = type_path_push(path, elem);
|
||||||
if (path->failure) {
|
if (path->failure) {
|
||||||
return FAILURE_ALIGNMENT;
|
return FAILURE_ALIGNMENT;
|
||||||
}
|
}
|
||||||
i64 align = type_align_of_internal(allocator, t->Array.elem, path);
|
i64 align = type_align_of_internal(allocator, t->Array.elem, path);
|
||||||
type_path_pop(path);
|
if (pop) type_path_pop(path);
|
||||||
return align;
|
return align;
|
||||||
}
|
}
|
||||||
|
case Type_Vector: {
|
||||||
|
Type *elem = t->Vector.elem;
|
||||||
|
bool pop = type_path_push(path, elem);
|
||||||
|
if (path->failure) {
|
||||||
|
return FAILURE_ALIGNMENT;
|
||||||
|
}
|
||||||
|
i64 size = type_size_of_internal(allocator, t->Vector.elem, path);
|
||||||
|
if (pop) type_path_pop(path);
|
||||||
|
i64 count = gb_max(prev_pow2(t->Vector.count), 1);
|
||||||
|
i64 total = size * count;
|
||||||
|
return gb_clamp(total, 1, build_context.max_align);
|
||||||
|
} break;
|
||||||
|
|
||||||
case Type_DynamicArray:
|
case Type_DynamicArray:
|
||||||
// data, count, capacity, allocator
|
// data, count, capacity, allocator
|
||||||
@@ -1789,18 +1898,6 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
case Type_Slice:
|
case Type_Slice:
|
||||||
return build_context.word_size;
|
return build_context.word_size;
|
||||||
|
|
||||||
case Type_Vector: {
|
|
||||||
Type *elem = t->Vector.elem;
|
|
||||||
type_path_push(path, elem);
|
|
||||||
if (path->failure) {
|
|
||||||
return FAILURE_ALIGNMENT;
|
|
||||||
}
|
|
||||||
i64 size = type_size_of_internal(allocator, t->Vector.elem, path);
|
|
||||||
type_path_pop(path);
|
|
||||||
i64 count = gb_max(prev_pow2(t->Vector.count), 1);
|
|
||||||
i64 total = size * count;
|
|
||||||
return gb_clamp(total, 1, build_context.max_align);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case Type_Tuple: {
|
case Type_Tuple: {
|
||||||
i64 max = 1;
|
i64 max = 1;
|
||||||
@@ -1827,15 +1924,16 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
if (t->Union.custom_align > 0) {
|
if (t->Union.custom_align > 0) {
|
||||||
return gb_clamp(t->Union.custom_align, 1, build_context.max_align);
|
return gb_clamp(t->Union.custom_align, 1, build_context.max_align);
|
||||||
}
|
}
|
||||||
i64 max = build_context.word_size;
|
|
||||||
|
i64 max = union_tag_size(t);
|
||||||
for_array(i, t->Union.variants) {
|
for_array(i, t->Union.variants) {
|
||||||
Type *variant = t->Union.variants[i];
|
Type *variant = t->Union.variants[i];
|
||||||
type_path_push(path, variant);
|
bool pop = type_path_push(path, variant);
|
||||||
if (path->failure) {
|
if (path->failure) {
|
||||||
return FAILURE_ALIGNMENT;
|
return FAILURE_ALIGNMENT;
|
||||||
}
|
}
|
||||||
i64 align = type_align_of_internal(allocator, variant, path);
|
i64 align = type_align_of_internal(allocator, variant, path);
|
||||||
type_path_pop(path);
|
if (pop) type_path_pop(path);
|
||||||
if (max < align) {
|
if (max < align) {
|
||||||
max = align;
|
max = align;
|
||||||
}
|
}
|
||||||
@@ -1851,12 +1949,12 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
i64 max = 1;
|
i64 max = 1;
|
||||||
for_array(i, t->Struct.fields) {
|
for_array(i, t->Struct.fields) {
|
||||||
Type *field_type = t->Struct.fields[i]->type;
|
Type *field_type = t->Struct.fields[i]->type;
|
||||||
type_path_push(path, field_type);
|
bool pop = type_path_push(path, field_type);
|
||||||
if (path->failure) {
|
if (path->failure) {
|
||||||
return FAILURE_ALIGNMENT;
|
return FAILURE_ALIGNMENT;
|
||||||
}
|
}
|
||||||
i64 align = type_align_of_internal(allocator, field_type, path);
|
i64 align = type_align_of_internal(allocator, field_type, path);
|
||||||
type_path_pop(path);
|
if (pop) type_path_pop(path);
|
||||||
if (max < align) {
|
if (max < align) {
|
||||||
max = align;
|
max = align;
|
||||||
}
|
}
|
||||||
@@ -1864,21 +1962,20 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
return max;
|
return max;
|
||||||
} else if (t->Struct.fields.count > 0) {
|
} else if (t->Struct.fields.count > 0) {
|
||||||
i64 max = 1;
|
i64 max = 1;
|
||||||
if (t->Struct.is_packed) {
|
// NOTE(bill): Check the fields to check for cyclic definitions
|
||||||
max = build_context.word_size;
|
|
||||||
}
|
|
||||||
for_array(i, t->Struct.fields) {
|
for_array(i, t->Struct.fields) {
|
||||||
Type *field_type = t->Struct.fields[i]->type;
|
Type *field_type = t->Struct.fields[i]->type;
|
||||||
type_path_push(path, field_type);
|
bool pop = type_path_push(path, field_type);
|
||||||
if (path->failure) {
|
if (path->failure) return FAILURE_ALIGNMENT;
|
||||||
return FAILURE_ALIGNMENT;
|
|
||||||
}
|
|
||||||
i64 align = type_align_of_internal(allocator, field_type, path);
|
i64 align = type_align_of_internal(allocator, field_type, path);
|
||||||
type_path_pop(path);
|
if (pop) type_path_pop(path);
|
||||||
if (max < align) {
|
if (max < align) {
|
||||||
max = align;
|
max = align;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (t->Struct.is_packed) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@@ -1953,12 +2050,12 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
|
|
||||||
switch (t->kind) {
|
switch (t->kind) {
|
||||||
case Type_Named: {
|
case Type_Named: {
|
||||||
type_path_push(path, t);
|
bool pop = type_path_push(path, t);
|
||||||
if (path->failure) {
|
if (path->failure) {
|
||||||
return FAILURE_ALIGNMENT;
|
return FAILURE_ALIGNMENT;
|
||||||
}
|
}
|
||||||
i64 size = type_size_of_internal(allocator, t->Named.base, path);
|
i64 size = type_size_of_internal(allocator, t->Named.base, path);
|
||||||
type_path_pop(path);
|
if (pop) type_path_pop(path);
|
||||||
return size;
|
return size;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -1973,7 +2070,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
case Basic_string: return 2*build_context.word_size;
|
case Basic_string: return 2*build_context.word_size;
|
||||||
case Basic_any: return 2*build_context.word_size;
|
case Basic_any: return 2*build_context.word_size;
|
||||||
|
|
||||||
case Basic_int: case Basic_uint: case Basic_rawptr:
|
case Basic_int: case Basic_uint: case Basic_uintptr: case Basic_rawptr:
|
||||||
return build_context.word_size;
|
return build_context.word_size;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@@ -2000,12 +2097,12 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
type_path_push(path, t->Vector.elem);
|
bool pop = type_path_push(path, t->Vector.elem);
|
||||||
if (path->failure) {
|
if (path->failure) {
|
||||||
return FAILURE_SIZE;
|
return FAILURE_SIZE;
|
||||||
}
|
}
|
||||||
bit_size = 8*type_size_of_internal(allocator, t->Vector.elem, path);
|
bit_size = 8*type_size_of_internal(allocator, t->Vector.elem, path);
|
||||||
type_path_pop(path);
|
if (pop) type_path_pop(path);
|
||||||
if (is_type_boolean(t->Vector.elem)) {
|
if (is_type_boolean(t->Vector.elem)) {
|
||||||
bit_size = 1; // NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
|
bit_size = 1; // NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
|
||||||
// Silly LLVM spec
|
// Silly LLVM spec
|
||||||
@@ -2076,12 +2173,13 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): Align to int
|
// NOTE(bill): Align to tag
|
||||||
i64 size = align_formula(max, build_context.word_size);
|
i64 tag_size = union_tag_size(t);
|
||||||
|
i64 size = align_formula(max, tag_size);
|
||||||
// NOTE(bill): Calculate the padding between the common fields and the tag
|
// NOTE(bill): Calculate the padding between the common fields and the tag
|
||||||
t->Union.variant_block_size = size - field_size;
|
t->Union.variant_block_size = size - field_size;
|
||||||
|
|
||||||
size += type_size_of(allocator, t_int);
|
size += tag_size;
|
||||||
size = align_formula(size, align);
|
size = align_formula(size, align);
|
||||||
return size;
|
return size;
|
||||||
} break;
|
} break;
|
||||||
@@ -2349,12 +2447,19 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
|
|
||||||
case Type_Tuple:
|
case Type_Tuple:
|
||||||
if (type->Tuple.variables.count > 0) {
|
if (type->Tuple.variables.count > 0) {
|
||||||
|
isize comma_index = 0;
|
||||||
for_array(i, type->Tuple.variables) {
|
for_array(i, type->Tuple.variables) {
|
||||||
Entity *var = type->Tuple.variables[i];
|
Entity *var = type->Tuple.variables[i];
|
||||||
if (var != nullptr) {
|
if (var != nullptr) {
|
||||||
if (i > 0) {
|
if (var->kind == Entity_Constant) {
|
||||||
|
// Ignore
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comma_index++ > 0) {
|
||||||
str = gb_string_appendc(str, ", ");
|
str = gb_string_appendc(str, ", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (var->kind == Entity_Variable) {
|
if (var->kind == Entity_Variable) {
|
||||||
if (var->flags&EntityFlag_CVarArg) {
|
if (var->flags&EntityFlag_CVarArg) {
|
||||||
str = gb_string_appendc(str, "#c_vararg ");
|
str = gb_string_appendc(str, "#c_vararg ");
|
||||||
@@ -2382,7 +2487,31 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Type_Proc:
|
case Type_Proc:
|
||||||
str = gb_string_appendc(str, "proc(");
|
str = gb_string_appendc(str, "proc");
|
||||||
|
|
||||||
|
switch (type->Proc.calling_convention) {
|
||||||
|
case ProcCC_Odin:
|
||||||
|
break;
|
||||||
|
case ProcCC_Contextless:
|
||||||
|
str = gb_string_appendc(str, " \"contextless\" ");
|
||||||
|
break;
|
||||||
|
case ProcCC_CDecl:
|
||||||
|
str = gb_string_appendc(str, " \"cdecl\" ");
|
||||||
|
break;
|
||||||
|
case ProcCC_StdCall:
|
||||||
|
str = gb_string_appendc(str, " \"stdcall\" ");
|
||||||
|
break;
|
||||||
|
case ProcCC_FastCall:
|
||||||
|
str = gb_string_appendc(str, " \"fastcall\" ");
|
||||||
|
break;
|
||||||
|
// case ProcCC_VectorCall:
|
||||||
|
// str = gb_string_appendc(str, " \"vectorcall\" ");
|
||||||
|
// break;
|
||||||
|
// case ProcCC_ClrCall:
|
||||||
|
// str = gb_string_appendc(str, " \"clrcall\" ");
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
str = gb_string_appendc(str, "(");
|
||||||
if (type->Proc.params) {
|
if (type->Proc.params) {
|
||||||
str = write_type_to_string(str, type->Proc.params);
|
str = write_type_to_string(str, type->Proc.params);
|
||||||
}
|
}
|
||||||
@@ -2391,20 +2520,6 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
str = gb_string_appendc(str, " -> ");
|
str = gb_string_appendc(str, " -> ");
|
||||||
str = write_type_to_string(str, type->Proc.results);
|
str = write_type_to_string(str, type->Proc.results);
|
||||||
}
|
}
|
||||||
switch (type->Proc.calling_convention) {
|
|
||||||
case ProcCC_Odin:
|
|
||||||
// str = gb_string_appendc(str, " #cc_odin");
|
|
||||||
break;
|
|
||||||
case ProcCC_C:
|
|
||||||
str = gb_string_appendc(str, " #cc_c");
|
|
||||||
break;
|
|
||||||
case ProcCC_Std:
|
|
||||||
str = gb_string_appendc(str, " #cc_std");
|
|
||||||
break;
|
|
||||||
case ProcCC_Fast:
|
|
||||||
str = gb_string_appendc(str, " #cc_fast");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Type_BitField:
|
case Type_BitField:
|
||||||
|
|||||||
Reference in New Issue
Block a user