mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-05 11:11:37 -07:00
Compare commits
116 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 73beed0477 | |||
| e0ecdd4b24 | |||
| 5168cf03a9 | |||
| b886ae6515 | |||
| 277a973b98 | |||
| 0ec4d97bfd | |||
| e6236e5c3e | |||
| e201280844 | |||
| 8e50a6c61b | |||
| 7e6f5f89d0 | |||
| 97acc57649 | |||
| 83c8c48ed7 | |||
| 0815b4d59f | |||
| a0135080b3 | |||
| f45e8e5d47 | |||
| 98ba4beede | |||
| a9304f2fef | |||
| a0697ab057 | |||
| 2e895c72d3 | |||
| 674ebe395f | |||
| 96eecaab54 | |||
| b1ae5bc9fe | |||
| 7258588ed5 | |||
| d913155972 | |||
| 9746e25784 | |||
| d26cfd2141 | |||
| 21f2c06f4b | |||
| 727a25f41f | |||
| 3f27cb2309 | |||
| f213622982 | |||
| 4aad835a66 | |||
| 4af8a64580 | |||
| c9c3611b1d | |||
| 220dfd7440 | |||
| bce8819ed5 | |||
| 5f2b220a85 | |||
| f174c805a9 | |||
| 25869b7504 | |||
| ecd81e8a53 | |||
| d7f9f7f170 | |||
| 08f5259d77 | |||
| a9f744cb64 | |||
| b02e42c6dc | |||
| cb0273b5d7 | |||
| 8dbf45a65a | |||
| 9f64de9568 | |||
| 0ebe9ba487 | |||
| efe00e1aa6 | |||
| 2bdbce55f9 | |||
| 9614ca92f0 | |||
| d30e59f539 | |||
| a3afe617c2 | |||
| 69daac583e | |||
| b28d4b753b | |||
| e6ab4f4856 | |||
| c8ab1b7ee1 | |||
| 9f10487678 | |||
| 2542983d70 | |||
| d492fb3501 | |||
| 1829aa1638 | |||
| 4cb4173ced | |||
| 00e704b216 | |||
| 227ee0f705 | |||
| 17f47a7ab0 | |||
| 4e8bc0786d | |||
| 3d3ccf061f | |||
| 3a8adc6721 | |||
| e1748a5dd1 | |||
| 59b4c889d3 | |||
| b6408d1b3f | |||
| 3db3047f47 | |||
| 7420fbd95b | |||
| 7c990b3833 | |||
| 9c059f1a12 | |||
| fb167d1d0a | |||
| 0992239d86 | |||
| 9eb3da0474 | |||
| e91f8feedf | |||
| 22a0c3fce1 | |||
| 6c7e5748a8 | |||
| 0b0c6da8b0 | |||
| 78826071c0 | |||
| e61b73d7ad | |||
| f886632bf1 | |||
| eafa5098aa | |||
| 0571b80d37 | |||
| 80c10644dd | |||
| 041625381c | |||
| 48f56d728b | |||
| 872d391cfb | |||
| 3e6ec65dd9 | |||
| 157c87b2a2 | |||
| d3081bd889 | |||
| 2ae5bf4395 | |||
| f28547cae1 | |||
| 5332705e31 | |||
| bfb082cda4 | |||
| 37d04198ab | |||
| ae9d540c1c | |||
| c90b7c38f1 | |||
| 9e376fbda7 | |||
| 00739bf06d | |||
| e8148055ad | |||
| dd0a20ab45 | |||
| babbc304b8 | |||
| a8b44f33bd | |||
| bd48561688 | |||
| 23842a8950 | |||
| 0a8e6169d7 | |||
| b89bb87759 | |||
| 89222a0ab2 | |||
| a315e7c962 | |||
| 42364f2fce | |||
| 8f600798ef | |||
| f28c268d97 | |||
| f1cff20249 |
@@ -1,5 +1,5 @@
|
||||
name: CI
|
||||
on: [push, pull_request]
|
||||
on: [push, pull_request, workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
name: "Close Stale Issues & PRs"
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 21 * * *"
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Close Stale Issues
|
||||
uses: actions/stale@v4.1.0
|
||||
with:
|
||||
# stale-issue-message: |
|
||||
# Hello!
|
||||
#
|
||||
# I am marking this issue as stale as it has not received any engagement from the community or maintainers 120 days. That does not imply that the issue has no merit! If you feel strongly about this issue
|
||||
# - open a PR referencing and resolving the issue;
|
||||
# - leave a comment on it and discuss ideas how you could contribute towards resolving it;
|
||||
# - leave a comment and describe in detail why this issue is critical for your use case;
|
||||
# - open a new issue with updated details and a plan on resolving the issue.
|
||||
#
|
||||
# The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone..
|
||||
#
|
||||
# stale-pr-message: |
|
||||
# Hello!
|
||||
#
|
||||
# I am marking this PR as stale as it has not received any engagement from the community or maintainers 120 days. That does not imply that the issue has no merit! If you feel strongly about this issue
|
||||
# - leave a comment on it and discuss ideas how you could contribute towards resolving it;
|
||||
# - leave a comment and describe in detail why this issue is critical for your use case;
|
||||
#
|
||||
# The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone..
|
||||
|
||||
days-before-stale: 120
|
||||
days-before-close: 30
|
||||
exempt-draft-pr: true
|
||||
ascending: true
|
||||
operations-per-run: 1000
|
||||
exempt-issue-labels: "ignore"
|
||||
@@ -58,7 +58,7 @@ set libs= ^
|
||||
set linker_flags= -incremental:no -opt:ref -subsystem:console
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
set linker_flags=%linker_flags% -debug
|
||||
set linker_flags=%linker_flags% -debug /NATVIS:src\odin_compiler.natvis
|
||||
) else ( rem Release
|
||||
set linker_flags=%linker_flags% -debug
|
||||
)
|
||||
|
||||
+34
-22
@@ -1,12 +1,20 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
GIT_SHA=$(git rev-parse --short HEAD)
|
||||
: ${CXX=clang++}
|
||||
: ${CPPFLAGS=}
|
||||
: ${CXXFLAGS=}
|
||||
: ${LDFLAGS=}
|
||||
: ${ODIN_VERSION=dev-$(date +"%Y-%m")}
|
||||
|
||||
CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"$ODIN_VERSION\""
|
||||
CXXFLAGS="$CXXFLAGS -std=c++14"
|
||||
LDFLAGS="$LDFLAGS -pthread -lm -lstdc++"
|
||||
|
||||
GIT_SHA=$(git rev-parse --short HEAD || :)
|
||||
if [ "$GIT_SHA" ]; then CPPFLAGS="$CPPFLAGS -DGIT_SHA=\"$GIT_SHA\""; fi
|
||||
|
||||
DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value"
|
||||
LDFLAGS="-pthread -lm -lstdc++"
|
||||
CFLAGS="-std=c++14 -DGIT_SHA=\"$GIT_SHA\""
|
||||
CFLAGS="$CFLAGS -DODIN_VERSION_RAW=\"dev-$(date +"%Y-%m")\""
|
||||
CC=clang
|
||||
OS=$(uname)
|
||||
|
||||
panic() {
|
||||
@@ -18,7 +26,7 @@ version() { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }';
|
||||
|
||||
config_darwin() {
|
||||
ARCH=$(uname -m)
|
||||
LLVM_CONFIG=llvm-config
|
||||
: ${LLVM_CONFIG=llvm-config}
|
||||
|
||||
# allow for arm only llvm's with version 13
|
||||
if [ ARCH == arm64 ]; then
|
||||
@@ -37,34 +45,38 @@ config_darwin() {
|
||||
fi
|
||||
|
||||
LDFLAGS="$LDFLAGS -liconv -ldl"
|
||||
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS -lLLVM-C"
|
||||
}
|
||||
|
||||
config_freebsd() {
|
||||
LLVM_CONFIG=/usr/local/bin/llvm-config11
|
||||
: ${LLVM_CONFIG=/usr/local/bin/llvm-config11}
|
||||
|
||||
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
}
|
||||
|
||||
config_openbsd() {
|
||||
LLVM_CONFIG=/usr/local/bin/llvm-config
|
||||
: ${LLVM_CONFIG=/usr/local/bin/llvm-config}
|
||||
|
||||
LDFLAGS="$LDFLAGS -liconv"
|
||||
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
}
|
||||
|
||||
config_linux() {
|
||||
if which llvm-config > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config
|
||||
elif which llvm-config-11 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config-11
|
||||
elif which llvm-config-11-64 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config-11-64
|
||||
else
|
||||
panic "Unable to find LLVM-config"
|
||||
: ${LLVM_CONFIG=}
|
||||
|
||||
if [ ! "$LLVM_CONFIG" ]; then
|
||||
if which llvm-config > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config
|
||||
elif which llvm-config-11 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config-11
|
||||
elif which llvm-config-11-64 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config-11-64
|
||||
else
|
||||
panic "Unable to find LLVM-config"
|
||||
fi
|
||||
fi
|
||||
|
||||
MIN_LLVM_VERSION=("11.0.0")
|
||||
@@ -74,7 +86,7 @@ config_linux() {
|
||||
fi
|
||||
|
||||
LDFLAGS="$LDFLAGS -ldl"
|
||||
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
}
|
||||
|
||||
@@ -97,7 +109,7 @@ build_odin() {
|
||||
esac
|
||||
|
||||
set -x
|
||||
$CC src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CFLAGS $EXTRAFLAGS $LDFLAGS -o odin
|
||||
$CXX src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CPPFLAGS $CXXFLAGS $EXTRAFLAGS $LDFLAGS -o odin
|
||||
set +x
|
||||
}
|
||||
|
||||
|
||||
@@ -161,6 +161,10 @@ buffer_write :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) {
|
||||
return copy(b.buf[m:], p), nil
|
||||
}
|
||||
|
||||
buffer_write_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.Error) {
|
||||
return buffer_write(b, ([^]byte)(ptr)[:size])
|
||||
}
|
||||
|
||||
buffer_write_string :: proc(b: ^Buffer, s: string) -> (n: int, err: io.Error) {
|
||||
b.last_read = .Invalid
|
||||
m, ok := _buffer_try_grow(b, len(s))
|
||||
@@ -229,6 +233,10 @@ buffer_read :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) {
|
||||
return
|
||||
}
|
||||
|
||||
buffer_read_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.Error) {
|
||||
return buffer_read(b, ([^]byte)(ptr)[:size])
|
||||
}
|
||||
|
||||
buffer_read_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) {
|
||||
b.last_read = .Invalid
|
||||
|
||||
|
||||
@@ -519,7 +519,7 @@ join_adjacent_string_literals :: proc(cpp: ^Preprocessor, initial_tok: ^Token) {
|
||||
|
||||
|
||||
quote_string :: proc(s: string) -> []byte {
|
||||
b := strings.make_builder(0, len(s)+2)
|
||||
b := strings.builder_make(0, len(s)+2)
|
||||
io.write_quoted_string(strings.to_writer(&b), s, '"')
|
||||
return b.buf[:]
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ foreign libc {
|
||||
getc :: proc(stream: ^FILE) -> int ---
|
||||
getchar :: proc() -> int ---
|
||||
putc :: proc(c: int, stream: ^FILE) -> int ---
|
||||
putchar :: proc() -> int ---
|
||||
putchar :: proc(c: int) -> int ---
|
||||
puts :: proc(s: cstring) -> int ---
|
||||
ungetc :: proc(c: int, stream: ^FILE) -> int ---
|
||||
fread :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---
|
||||
|
||||
@@ -25,8 +25,8 @@ import "core:strings"
|
||||
|
||||
MAX_RUNE_CODEPOINT :: int(unicode.MAX_RUNE)
|
||||
|
||||
write_rune :: strings.write_rune_builder
|
||||
write_string :: strings.write_string_builder
|
||||
write_rune :: strings.write_rune
|
||||
write_string :: strings.write_string
|
||||
|
||||
Error :: enum u8 {
|
||||
None = 0,
|
||||
@@ -94,8 +94,8 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
|
||||
l := len(input)
|
||||
if l == 0 { return "", .None }
|
||||
|
||||
builder := strings.make_builder()
|
||||
defer strings.destroy_builder(&builder)
|
||||
builder := strings.builder_make()
|
||||
defer strings.builder_destroy(&builder)
|
||||
|
||||
t := Tokenizer{src=input}
|
||||
in_data := false
|
||||
|
||||
@@ -8,7 +8,7 @@ import "core:time"
|
||||
|
||||
doc_print :: proc(doc: ^xml.Document) {
|
||||
buf: strings.Builder
|
||||
defer strings.destroy_builder(&buf)
|
||||
defer strings.builder_destroy(&buf)
|
||||
w := strings.to_writer(&buf)
|
||||
|
||||
xml.print(w, doc)
|
||||
|
||||
@@ -18,9 +18,9 @@ Marshal_Error :: union #shared_nil {
|
||||
}
|
||||
|
||||
marshal :: proc(v: any, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) {
|
||||
b := strings.make_builder(allocator)
|
||||
b := strings.builder_make(allocator)
|
||||
defer if err != nil {
|
||||
strings.destroy_builder(&b)
|
||||
strings.builder_destroy(&b)
|
||||
}
|
||||
|
||||
marshal_to_builder(&b, v) or_return
|
||||
|
||||
@@ -325,7 +325,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
UNSUPPORTED_TYPE := Unsupported_Type_Error{v.id, p.curr_token}
|
||||
|
||||
if end_token == .Close_Brace {
|
||||
assert(expect_token(p, .Open_Brace) == nil)
|
||||
unmarshal_expect_token(p, .Open_Brace)
|
||||
}
|
||||
|
||||
v := v
|
||||
@@ -473,7 +473,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
}
|
||||
|
||||
if end_token == .Close_Brace {
|
||||
assert(expect_token(p, .Close_Brace) == nil)
|
||||
unmarshal_expect_token(p, .Close_Brace)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ example :: proc() {
|
||||
|
||||
doc_hash :: proc(doc: ^xml.Document, print := false) -> (crc32: u32) {
|
||||
buf: strings.Builder
|
||||
defer strings.destroy_builder(&buf)
|
||||
defer strings.builder_destroy(&buf)
|
||||
w := strings.to_writer(&buf)
|
||||
|
||||
xml.print(w, doc)
|
||||
|
||||
+8
-8
@@ -77,7 +77,7 @@ register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Regist
|
||||
// They must be freed accordingly
|
||||
aprint :: proc(args: ..any, sep := " ") -> string {
|
||||
str: strings.Builder
|
||||
strings.init_builder(&str)
|
||||
strings.builder_init(&str)
|
||||
sbprint(buf=&str, args=args, sep=sep)
|
||||
return strings.to_string(str)
|
||||
}
|
||||
@@ -85,7 +85,7 @@ aprint :: proc(args: ..any, sep := " ") -> string {
|
||||
// They must be freed accordingly
|
||||
aprintln :: proc(args: ..any, sep := " ") -> string {
|
||||
str: strings.Builder
|
||||
strings.init_builder(&str)
|
||||
strings.builder_init(&str)
|
||||
sbprintln(buf=&str, args=args, sep=sep)
|
||||
return strings.to_string(str)
|
||||
}
|
||||
@@ -93,7 +93,7 @@ aprintln :: proc(args: ..any, sep := " ") -> string {
|
||||
// They must be freed accordingly
|
||||
aprintf :: proc(fmt: string, args: ..any) -> string {
|
||||
str: strings.Builder
|
||||
strings.init_builder(&str)
|
||||
strings.builder_init(&str)
|
||||
sbprintf(&str, fmt, ..args)
|
||||
return strings.to_string(str)
|
||||
}
|
||||
@@ -102,21 +102,21 @@ aprintf :: proc(fmt: string, args: ..any) -> string {
|
||||
// tprint procedure return a string that was allocated with the current context's temporary allocator
|
||||
tprint :: proc(args: ..any, sep := " ") -> string {
|
||||
str: strings.Builder
|
||||
strings.init_builder(&str, context.temp_allocator)
|
||||
strings.builder_init(&str, context.temp_allocator)
|
||||
sbprint(buf=&str, args=args, sep=sep)
|
||||
return strings.to_string(str)
|
||||
}
|
||||
// tprintln procedure return a string that was allocated with the current context's temporary allocator
|
||||
tprintln :: proc(args: ..any, sep := " ") -> string {
|
||||
str: strings.Builder
|
||||
strings.init_builder(&str, context.temp_allocator)
|
||||
strings.builder_init(&str, context.temp_allocator)
|
||||
sbprintln(buf=&str, args=args, sep=sep)
|
||||
return strings.to_string(str)
|
||||
}
|
||||
// tprintf procedure return a string that was allocated with the current context's temporary allocator
|
||||
tprintf :: proc(fmt: string, args: ..any) -> string {
|
||||
str: strings.Builder
|
||||
strings.init_builder(&str, context.temp_allocator)
|
||||
strings.builder_init(&str, context.temp_allocator)
|
||||
sbprintf(&str, fmt, ..args)
|
||||
return strings.to_string(str)
|
||||
}
|
||||
@@ -776,7 +776,7 @@ fmt_rune :: proc(fi: ^Info, r: rune, verb: rune) {
|
||||
case 'c', 'r', 'v':
|
||||
io.write_rune(fi.writer, r, &fi.n)
|
||||
case 'q':
|
||||
fi.n += strings.write_quoted_rune(fi.writer, r)
|
||||
fi.n += io.write_quoted_rune(fi.writer, r)
|
||||
case:
|
||||
fmt_int(fi, u64(r), false, 32, verb)
|
||||
}
|
||||
@@ -1014,7 +1014,7 @@ fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) {
|
||||
u := u64(uintptr(p))
|
||||
switch verb {
|
||||
case 'p', 'v':
|
||||
if !fi.hash || verb == 'v' {
|
||||
if !fi.hash && verb == 'v' {
|
||||
io.write_string(fi.writer, "0x", &fi.n)
|
||||
}
|
||||
_fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER)
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
package hash
|
||||
|
||||
@(optimization_mode="speed")
|
||||
crc64_ecma_182 :: proc(data: []byte, seed := u32(0)) -> u64 #no_bounds_check {
|
||||
result := u64(seed)
|
||||
crc64_ecma_182 :: proc(data: []byte, seed := u64(0)) -> (result: u64) #no_bounds_check {
|
||||
result = seed
|
||||
#no_bounds_check for b in data {
|
||||
result = result<<8 ~ _crc64_table_ecma_182[((result>>56) ~ u64(b)) & 0xff]
|
||||
}
|
||||
|
||||
+101
-95
@@ -172,108 +172,114 @@ murmur32 :: proc(data: []byte, seed := u32(0)) -> u32 {
|
||||
return h1
|
||||
}
|
||||
|
||||
// See https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp#L96
|
||||
@(optimization_mode="speed")
|
||||
murmur64 :: proc(data: []byte, seed := u64(0x9747b28c)) -> u64 {
|
||||
when size_of(int) == 8 {
|
||||
m :: 0xc6a4a7935bd1e995
|
||||
r :: 47
|
||||
murmur64a :: proc(data: []byte, seed := u64(0x9747b28c)) -> u64 {
|
||||
m :: 0xc6a4a7935bd1e995
|
||||
r :: 47
|
||||
|
||||
h: u64 = seed ~ (u64(len(data)) * m)
|
||||
data64 := mem.slice_ptr(cast(^u64)raw_data(data), len(data)/size_of(u64))
|
||||
h: u64 = seed ~ (u64(len(data)) * m)
|
||||
data64 := mem.slice_data_cast([]u64, data)
|
||||
|
||||
for _, i in data64 {
|
||||
k := data64[i]
|
||||
for _, i in data64 {
|
||||
k := data64[i]
|
||||
|
||||
k *= m
|
||||
k ~= k>>r
|
||||
k *= m
|
||||
k *= m
|
||||
k ~= k>>r
|
||||
k *= m
|
||||
|
||||
h ~= k
|
||||
h *= m
|
||||
}
|
||||
|
||||
switch len(data)&7 {
|
||||
case 7: h ~= u64(data[6]) << 48; fallthrough
|
||||
case 6: h ~= u64(data[5]) << 40; fallthrough
|
||||
case 5: h ~= u64(data[4]) << 32; fallthrough
|
||||
case 4: h ~= u64(data[3]) << 24; fallthrough
|
||||
case 3: h ~= u64(data[2]) << 16; fallthrough
|
||||
case 2: h ~= u64(data[1]) << 8; fallthrough
|
||||
case 1:
|
||||
h ~= u64(data[0])
|
||||
h *= m
|
||||
}
|
||||
|
||||
h ~= h>>r
|
||||
h ~= k
|
||||
h *= m
|
||||
h ~= h>>r
|
||||
|
||||
return h
|
||||
} else {
|
||||
m :: 0x5bd1e995
|
||||
r :: 24
|
||||
|
||||
h1 := u32(seed) ~ u32(len(data))
|
||||
h2 := u32(seed) >> 32
|
||||
data32 := mem.slice_ptr(cast(^u32)raw_data(data), len(data)/size_of(u32))
|
||||
len := len(data)
|
||||
i := 0
|
||||
|
||||
for len >= 8 {
|
||||
k1, k2: u32
|
||||
k1 = data32[i]; i += 1
|
||||
k1 *= m
|
||||
k1 ~= k1>>r
|
||||
k1 *= m
|
||||
h1 *= m
|
||||
h1 ~= k1
|
||||
len -= 4
|
||||
|
||||
k2 = data32[i]; i += 1
|
||||
k2 *= m
|
||||
k2 ~= k2>>r
|
||||
k2 *= m
|
||||
h2 *= m
|
||||
h2 ~= k2
|
||||
len -= 4
|
||||
}
|
||||
|
||||
if len >= 4 {
|
||||
k1: u32
|
||||
k1 = data32[i]; i += 1
|
||||
k1 *= m
|
||||
k1 ~= k1>>r
|
||||
k1 *= m
|
||||
h1 *= m
|
||||
h1 ~= k1
|
||||
len -= 4
|
||||
}
|
||||
|
||||
// TODO(bill): Fix this
|
||||
#no_bounds_check data8 := mem.slice_to_bytes(data32[i:])[:3]
|
||||
switch len {
|
||||
case 3:
|
||||
h2 ~= u32(data8[2]) << 16
|
||||
fallthrough
|
||||
case 2:
|
||||
h2 ~= u32(data8[1]) << 8
|
||||
fallthrough
|
||||
case 1:
|
||||
h2 ~= u32(data8[0])
|
||||
h2 *= m
|
||||
}
|
||||
|
||||
h1 ~= h2>>18
|
||||
h1 *= m
|
||||
h2 ~= h1>>22
|
||||
h2 *= m
|
||||
h1 ~= h2>>17
|
||||
h1 *= m
|
||||
h2 ~= h1>>19
|
||||
h2 *= m
|
||||
|
||||
return u64(h1)<<32 | u64(h2)
|
||||
}
|
||||
|
||||
offset := len(data64) * size_of(u64)
|
||||
|
||||
switch len(data)&7 {
|
||||
case 7: h ~= u64(data[offset + 6]) << 48; fallthrough
|
||||
case 6: h ~= u64(data[offset + 5]) << 40; fallthrough
|
||||
case 5: h ~= u64(data[offset + 4]) << 32; fallthrough
|
||||
case 4: h ~= u64(data[offset + 3]) << 24; fallthrough
|
||||
case 3: h ~= u64(data[offset + 2]) << 16; fallthrough
|
||||
case 2: h ~= u64(data[offset + 1]) << 8; fallthrough
|
||||
case 1:
|
||||
h ~= u64(data[offset + 0])
|
||||
h *= m
|
||||
}
|
||||
|
||||
h ~= h>>r
|
||||
h *= m
|
||||
h ~= h>>r
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
// See https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp#L140
|
||||
@(optimization_mode="speed")
|
||||
murmur64b :: proc(data: []byte, seed := u64(0x9747b28c)) -> u64 {
|
||||
m :: 0x5bd1e995
|
||||
r :: 24
|
||||
|
||||
h1 := u32(seed) ~ u32(len(data))
|
||||
h2 := u32(seed) >> 32
|
||||
|
||||
data32 := mem.slice_ptr(cast(^u32)raw_data(data), len(data)/size_of(u32))
|
||||
len := len(data)
|
||||
i := 0
|
||||
|
||||
for len >= 8 {
|
||||
k1, k2: u32
|
||||
k1 = data32[i]; i += 1
|
||||
k1 *= m
|
||||
k1 ~= k1>>r
|
||||
k1 *= m
|
||||
h1 *= m
|
||||
h1 ~= k1
|
||||
len -= 4
|
||||
|
||||
k2 = data32[i]; i += 1
|
||||
k2 *= m
|
||||
k2 ~= k2>>r
|
||||
k2 *= m
|
||||
h2 *= m
|
||||
h2 ~= k2
|
||||
len -= 4
|
||||
}
|
||||
|
||||
if len >= 4 {
|
||||
k1: u32
|
||||
k1 = data32[i]; i += 1
|
||||
k1 *= m
|
||||
k1 ~= k1>>r
|
||||
k1 *= m
|
||||
h1 *= m
|
||||
h1 ~= k1
|
||||
len -= 4
|
||||
}
|
||||
|
||||
// TODO(bill): Fix this
|
||||
#no_bounds_check data8 := mem.slice_to_bytes(data32[i:])[:3]
|
||||
switch len {
|
||||
case 3:
|
||||
h2 ~= u32(data8[2]) << 16
|
||||
fallthrough
|
||||
case 2:
|
||||
h2 ~= u32(data8[1]) << 8
|
||||
fallthrough
|
||||
case 1:
|
||||
h2 ~= u32(data8[0])
|
||||
h2 *= m
|
||||
}
|
||||
|
||||
h1 ~= h2>>18
|
||||
h1 *= m
|
||||
h2 ~= h1>>22
|
||||
h2 *= m
|
||||
h1 ~= h2>>17
|
||||
h1 *= m
|
||||
h2 ~= h1>>19
|
||||
h2 *= m
|
||||
|
||||
return u64(h1)<<32 | u64(h2)
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
|
||||
@@ -130,7 +130,7 @@ save_to_buffer :: proc(img: ^Image, custom_info: Info = {}, allocator := context
|
||||
|
||||
// we will write to a string builder
|
||||
data: strings.Builder
|
||||
strings.init_builder(&data)
|
||||
strings.builder_init(&data)
|
||||
|
||||
// all PNM headers start with the format
|
||||
fmt.sbprintf(&data, "%s\n", header.format)
|
||||
@@ -409,7 +409,7 @@ _parse_header_pam :: proc(data: []byte, allocator := context.allocator) -> (head
|
||||
|
||||
// string buffer for the tupltype
|
||||
tupltype: strings.Builder
|
||||
strings.init_builder(&tupltype, context.temp_allocator); defer strings.destroy_builder(&tupltype)
|
||||
strings.builder_init(&tupltype, context.temp_allocator); defer strings.builder_destroy(&tupltype)
|
||||
fmt.sbprint(&tupltype, "")
|
||||
|
||||
// PAM uses actual lines, so we can iterate easily
|
||||
|
||||
@@ -247,6 +247,30 @@ write_quoted_string :: proc(w: Writer, str: string, quote: byte = '"', n_written
|
||||
return
|
||||
}
|
||||
|
||||
// writer append a quoted rune into the byte buffer, return the written size
|
||||
write_quoted_rune :: proc(w: Writer, r: rune) -> (n: int) {
|
||||
_write_byte :: #force_inline proc(w: Writer, c: byte) -> int {
|
||||
err := write_byte(w, c)
|
||||
return 1 if err == nil else 0
|
||||
}
|
||||
|
||||
quote := byte('\'')
|
||||
n += _write_byte(w, quote)
|
||||
buf, width := utf8.encode_rune(r)
|
||||
if width == 1 && r == utf8.RUNE_ERROR {
|
||||
n += _write_byte(w, '\\')
|
||||
n += _write_byte(w, 'x')
|
||||
n += _write_byte(w, DIGITS_LOWER[buf[0]>>4])
|
||||
n += _write_byte(w, DIGITS_LOWER[buf[0]&0xf])
|
||||
} else {
|
||||
i, _ := write_escaped_rune(w, r, quote)
|
||||
n += i
|
||||
}
|
||||
n += _write_byte(w, quote)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Tee_Reader :: struct {
|
||||
|
||||
@@ -476,21 +476,21 @@ quaternion_angle_axis :: proc{
|
||||
|
||||
angle_from_quaternion_f16 :: proc(q: Quaternionf16) -> f16 {
|
||||
if abs(q.w) > math.SQRT_THREE*0.5 {
|
||||
return math.asin(q.x*q.x + q.y*q.y + q.z*q.z) * 2
|
||||
return math.asin(math.sqrt(q.x*q.x + q.y*q.y + q.z*q.z)) * 2
|
||||
}
|
||||
|
||||
return math.acos(q.w) * 2
|
||||
}
|
||||
angle_from_quaternion_f32 :: proc(q: Quaternionf32) -> f32 {
|
||||
if abs(q.w) > math.SQRT_THREE*0.5 {
|
||||
return math.asin(q.x*q.x + q.y*q.y + q.z*q.z) * 2
|
||||
return math.asin(math.sqrt(q.x*q.x + q.y*q.y + q.z*q.z)) * 2
|
||||
}
|
||||
|
||||
return math.acos(q.w) * 2
|
||||
}
|
||||
angle_from_quaternion_f64 :: proc(q: Quaternionf64) -> f64 {
|
||||
if abs(q.w) > math.SQRT_THREE*0.5 {
|
||||
return math.asin(q.x*q.x + q.y*q.y + q.z*q.z) * 2
|
||||
return math.asin(math.sqrt(q.x*q.x + q.y*q.y + q.z*q.z)) * 2
|
||||
}
|
||||
|
||||
return math.acos(q.w) * 2
|
||||
|
||||
+1
-1
@@ -1357,7 +1357,7 @@ atan :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
|
||||
}
|
||||
|
||||
asin :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
|
||||
return atan2(x, 1 + sqrt(1 - x*x))
|
||||
return atan2(x, sqrt(1 - x*x))
|
||||
}
|
||||
|
||||
acos :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
//+build darwin
|
||||
//+private
|
||||
package mem_virtual
|
||||
|
||||
foreign import libc "System.framework"
|
||||
import "core:c"
|
||||
|
||||
PROT_NONE :: 0x0 /* [MC2] no permissions */
|
||||
PROT_READ :: 0x1 /* [MC2] pages can be read */
|
||||
PROT_WRITE :: 0x2 /* [MC2] pages can be written */
|
||||
PROT_EXEC :: 0x4 /* [MC2] pages can be executed */
|
||||
|
||||
// Sharing options
|
||||
MAP_SHARED :: 0x1 /* [MF|SHM] share changes */
|
||||
MAP_PRIVATE :: 0x2 /* [MF|SHM] changes are private */
|
||||
|
||||
// Other flags
|
||||
MAP_FIXED :: 0x0010 /* [MF|SHM] interpret addr exactly */
|
||||
MAP_RENAME :: 0x0020 /* Sun: rename private pages to file */
|
||||
MAP_NORESERVE :: 0x0040 /* Sun: don't reserve needed swap area */
|
||||
MAP_RESERVED0080 :: 0x0080 /* previously unimplemented MAP_INHERIT */
|
||||
MAP_NOEXTEND :: 0x0100 /* for MAP_FILE, don't change file size */
|
||||
MAP_HASSEMAPHORE :: 0x0200 /* region may contain semaphores */
|
||||
MAP_NOCACHE :: 0x0400 /* don't cache pages for this mapping */
|
||||
MAP_JIT :: 0x0800 /* Allocate a region that will be used for JIT purposes */
|
||||
|
||||
// Mapping type
|
||||
MAP_FILE :: 0x0000 /* map from file (default) */
|
||||
MAP_ANONYMOUS :: 0x1000 /* allocated from memory, swap space */
|
||||
|
||||
|
||||
/*
|
||||
* The MAP_RESILIENT_* flags can be used when the caller wants to map some
|
||||
* possibly unreliable memory and be able to access it safely, possibly
|
||||
* getting the wrong contents rather than raising any exception.
|
||||
* For safety reasons, such mappings have to be read-only (PROT_READ access
|
||||
* only).
|
||||
*
|
||||
* MAP_RESILIENT_CODESIGN:
|
||||
* accessing this mapping will not generate code-signing violations,
|
||||
* even if the contents are tainted.
|
||||
* MAP_RESILIENT_MEDIA:
|
||||
* accessing this mapping will not generate an exception if the contents
|
||||
* are not available (unreachable removable or remote media, access beyond
|
||||
* end-of-file, ...). Missing contents will be replaced with zeroes.
|
||||
*/
|
||||
MAP_RESILIENT_CODESIGN :: 0x2000 /* no code-signing failures */
|
||||
MAP_RESILIENT_MEDIA :: 0x4000 /* no backing-store failures */
|
||||
|
||||
MAP_32BIT :: 0x8000 /* Return virtual addresses <4G only */
|
||||
|
||||
// Flags used to support translated processes.
|
||||
MAP_TRANSLATED_ALLOW_EXECUTE :: 0x20000 /* allow execute in translated processes */
|
||||
MAP_UNIX03 :: 0x40000 /* UNIX03 compliance */
|
||||
|
||||
// Process memory locking
|
||||
MCL_CURRENT :: 0x0001 /* [ML] Lock only current memory */
|
||||
MCL_FUTURE :: 0x0002 /* [ML] Lock all future memory as well */
|
||||
|
||||
MADV_NORMAL :: 0 /* [MC1] no further special treatment */
|
||||
MADV_RANDOM :: 1 /* [MC1] expect random page refs */
|
||||
MADV_SEQUENTIAL :: 2 /* [MC1] expect sequential page refs */
|
||||
MADV_WILLNEED :: 3 /* [MC1] will need these pages */
|
||||
MADV_DONTNEED :: 4 /* [MC1] dont need these pages */
|
||||
MADV_FREE :: 5 /* pages unneeded, discard contents */
|
||||
MADV_ZERO_WIRED_PAGES :: 6 /* zero the wired pages that have not been unwired before the entry is deleted */
|
||||
MADV_FREE_REUSABLE :: 7 /* pages can be reused (by anyone) */
|
||||
MADV_FREE_REUSE :: 8 /* caller wants to reuse those pages */
|
||||
MADV_CAN_REUSE :: 9
|
||||
MADV_PAGEOUT :: 10 /* page out now (internal only) */
|
||||
|
||||
// msync() flags
|
||||
MS_ASYNC :: 0x0001 /* [MF|SIO] return immediately */
|
||||
MS_INVALIDATE :: 0x0002 /* [MF|SIO] invalidate all cached data */
|
||||
MS_SYNC :: 0x0010 /* [MF|SIO] msync synchronously */
|
||||
MS_KILLPAGES :: 0x0004 /* invalidate pages, leave mapped */
|
||||
MS_DEACTIVATE :: 0x0008 /* deactivate pages, leave mapped */
|
||||
|
||||
// Return bits from mincore
|
||||
MINCORE_INCORE :: 0x1 /* Page is incore */
|
||||
MINCORE_REFERENCED :: 0x2 /* Page has been referenced by us */
|
||||
MINCORE_MODIFIED :: 0x4 /* Page has been modified by us */
|
||||
MINCORE_REFERENCED_OTHER :: 0x8 /* Page has been referenced */
|
||||
MINCORE_MODIFIED_OTHER :: 0x10 /* Page has been modified */
|
||||
MINCORE_PAGED_OUT :: 0x20 /* Page has been paged out */
|
||||
MINCORE_COPIED :: 0x40 /* Page has been copied */
|
||||
MINCORE_ANONYMOUS :: 0x80 /* Page belongs to an anonymous object */
|
||||
|
||||
// Allocation failure result
|
||||
MAP_FAILED : rawptr = rawptr(~uintptr(0))
|
||||
|
||||
foreign libc {
|
||||
@(link_name="mlockall") _mlockall :: proc(flags: c.int) -> c.int ---
|
||||
@(link_name="munlockall") _munlockall :: proc() -> c.int ---
|
||||
@(link_name="mlock") _mlock :: proc(addr: rawptr, len: c.size_t) -> c.int ---
|
||||
@(link_name="mmap") _mmap :: proc(addr: rawptr, len: c.size_t, prot: c.int, flags: c.int, fd: c.int, offset: int) -> rawptr ---
|
||||
@(link_name="mprotect") _mprotect :: proc(addr: rawptr, len: c.size_t, prot: c.int) -> c.int ---
|
||||
@(link_name="msync") _msync :: proc(addr: rawptr, len: c.size_t) -> c.int ---
|
||||
@(link_name="munlock") _munlock :: proc(addr: rawptr, len: c.size_t) -> c.int ---
|
||||
@(link_name="munmap") _munmap :: proc(addr: rawptr, len: c.size_t) -> c.int ---
|
||||
@(link_name="shm_open") _shm_open :: proc(name: cstring, oflag: c.int, #c_vararg args: ..any) -> c.int ---
|
||||
@(link_name="shm_unlink") _shm_unlink :: proc(name: cstring) -> c.int ---
|
||||
@(link_name="posix_madvise") _posix_madvise :: proc(addr: rawptr, len: c.size_t, advice: c.int) -> c.int ---
|
||||
@(link_name="madvise") _madvise :: proc(addr: rawptr, len: c.size_t, advice: c.int) -> c.int ---
|
||||
@(link_name="mincore") _mincore :: proc(addr: rawptr, len: c.size_t, vec: cstring) -> c.int ---
|
||||
@(link_name="minherit") _minherit :: proc(addr: rawptr, len: c.size_t, inherit: c.int) -> c.int ---
|
||||
}
|
||||
|
||||
|
||||
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
result := _mmap(nil, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
|
||||
if result == MAP_FAILED {
|
||||
return nil, .Out_Of_Memory
|
||||
}
|
||||
return ([^]byte)(uintptr(result))[:size], nil
|
||||
}
|
||||
|
||||
_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
||||
result := _mprotect(data, size, PROT_READ|PROT_WRITE)
|
||||
if result != 0 {
|
||||
return .Out_Of_Memory
|
||||
}
|
||||
return nil
|
||||
}
|
||||
_decommit :: proc "contextless" (data: rawptr, size: uint) {
|
||||
_mprotect(data, size, PROT_NONE)
|
||||
_madvise(data, size, MADV_FREE)
|
||||
}
|
||||
_release :: proc "contextless" (data: rawptr, size: uint) {
|
||||
_munmap(data, size)
|
||||
}
|
||||
_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
||||
pflags: c.int
|
||||
pflags = PROT_NONE
|
||||
if .Read in flags { pflags |= PROT_READ }
|
||||
if .Write in flags { pflags |= PROT_WRITE }
|
||||
if .Execute in flags { pflags |= PROT_EXEC }
|
||||
err := _mprotect(data, size, pflags)
|
||||
return err != 0
|
||||
}
|
||||
|
||||
|
||||
_platform_memory_init :: proc() {
|
||||
DEFAULT_PAGE_SIZE = 4096
|
||||
|
||||
// is power of two
|
||||
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
||||
}
|
||||
+36
-1
@@ -552,13 +552,20 @@ unparen_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
|
||||
return
|
||||
}
|
||||
|
||||
Field_Flags :: distinct bit_set[Field_Flag]
|
||||
|
||||
Field_Flag :: enum {
|
||||
Invalid,
|
||||
Unknown,
|
||||
|
||||
Ellipsis,
|
||||
Using,
|
||||
No_Alias,
|
||||
C_Vararg,
|
||||
Auto_Cast,
|
||||
Any_Int,
|
||||
Subtype,
|
||||
By_Ptr,
|
||||
|
||||
Results,
|
||||
Tags,
|
||||
@@ -566,11 +573,38 @@ Field_Flag :: enum {
|
||||
Typeid_Token,
|
||||
}
|
||||
|
||||
Field_Flags :: distinct bit_set[Field_Flag]
|
||||
field_flag_strings := [Field_Flag]string{
|
||||
.Invalid = "",
|
||||
.Unknown = "",
|
||||
|
||||
.Ellipsis = "..",
|
||||
.Using = "using",
|
||||
.No_Alias = "#no_alias",
|
||||
.C_Vararg = "#c_vararg",
|
||||
.Auto_Cast = "auto_cast",
|
||||
.Any_Int = "#any_int",
|
||||
.Subtype = "#subtype",
|
||||
.By_Ptr = "#by_ptr",
|
||||
|
||||
.Results = "results",
|
||||
.Tags = "field tag",
|
||||
.Default_Parameters = "default parameters",
|
||||
.Typeid_Token = "typeid",
|
||||
}
|
||||
|
||||
field_hash_flag_strings := []struct{key: string, flag: Field_Flag}{
|
||||
{"no_alias", .No_Alias},
|
||||
{"c_vararg", .C_Vararg},
|
||||
{"any_int", .Any_Int},
|
||||
{"subtype", .Subtype},
|
||||
{"by_ptr", .By_Ptr},
|
||||
}
|
||||
|
||||
|
||||
Field_Flags_Struct :: Field_Flags{
|
||||
.Using,
|
||||
.Tags,
|
||||
.Subtype,
|
||||
}
|
||||
Field_Flags_Record_Poly_Params :: Field_Flags{
|
||||
.Typeid_Token,
|
||||
@@ -583,6 +617,7 @@ Field_Flags_Signature :: Field_Flags{
|
||||
.C_Vararg,
|
||||
.Auto_Cast,
|
||||
.Any_Int,
|
||||
.By_Ptr,
|
||||
.Default_Parameters,
|
||||
}
|
||||
|
||||
|
||||
@@ -1611,20 +1611,6 @@ new_ast_field :: proc(names: []^ast.Expr, type: ^ast.Expr, default_value: ^ast.E
|
||||
return field
|
||||
}
|
||||
|
||||
|
||||
Field_Prefix :: enum {
|
||||
Invalid,
|
||||
Unknown,
|
||||
|
||||
Using,
|
||||
No_Alias,
|
||||
C_Vararg,
|
||||
Auto_Cast,
|
||||
Any_Int,
|
||||
}
|
||||
|
||||
Field_Prefixes :: distinct bit_set[Field_Prefix]
|
||||
|
||||
Expr_And_Flags :: struct {
|
||||
expr: ^ast.Expr,
|
||||
flags: ast.Field_Flags,
|
||||
@@ -1666,7 +1652,7 @@ convert_to_ident_list :: proc(p: ^Parser, list: []Expr_And_Flags, ignore_flags,
|
||||
return idents[:]
|
||||
}
|
||||
|
||||
is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
|
||||
is_token_field_prefix :: proc(p: ^Parser) -> ast.Field_Flag {
|
||||
#partial switch p.curr_tok.kind {
|
||||
case .EOF:
|
||||
return .Invalid
|
||||
@@ -1677,17 +1663,15 @@ is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
|
||||
advance_token(p)
|
||||
return .Auto_Cast
|
||||
case .Hash:
|
||||
tok: tokenizer.Token
|
||||
advance_token(p)
|
||||
defer advance_token(p)
|
||||
#partial switch p.curr_tok.kind {
|
||||
case .Ident:
|
||||
switch p.curr_tok.text {
|
||||
case "no_alias":
|
||||
return .No_Alias
|
||||
case "c_vararg":
|
||||
return .C_Vararg
|
||||
case "any_int":
|
||||
return .Any_Int
|
||||
tok = p.curr_tok
|
||||
advance_token(p)
|
||||
if tok.kind == .Ident {
|
||||
for kf in ast.field_hash_flag_strings {
|
||||
if kf.key == tok.text {
|
||||
return kf.flag
|
||||
}
|
||||
}
|
||||
}
|
||||
return .Unknown
|
||||
@@ -1695,8 +1679,8 @@ is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
|
||||
return .Invalid
|
||||
}
|
||||
|
||||
parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
|
||||
counts: [len(Field_Prefix)]int
|
||||
parse_field_prefixes :: proc(p: ^Parser) -> (flags: ast.Field_Flags) {
|
||||
counts: [len(ast.Field_Flag)]int
|
||||
|
||||
for {
|
||||
kind := is_token_field_prefix(p)
|
||||
@@ -1712,31 +1696,17 @@ parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
|
||||
counts[kind] += 1
|
||||
}
|
||||
|
||||
flags: ast.Field_Flags
|
||||
|
||||
for kind in Field_Prefix {
|
||||
for kind in ast.Field_Flag {
|
||||
count := counts[kind]
|
||||
switch kind {
|
||||
case .Invalid, .Unknown: // Ignore
|
||||
case .Using:
|
||||
if count > 1 { error(p, p.curr_tok.pos, "multiple 'using' in this field list") }
|
||||
if count > 0 { flags += {.Using} }
|
||||
case .No_Alias:
|
||||
if count > 1 { error(p, p.curr_tok.pos, "multiple '#no_alias' in this field list") }
|
||||
if count > 0 { flags += {.No_Alias} }
|
||||
case .C_Vararg:
|
||||
if count > 1 { error(p, p.curr_tok.pos, "multiple '#c_vararg' in this field list") }
|
||||
if count > 0 { flags += {.C_Vararg} }
|
||||
case .Auto_Cast:
|
||||
if count > 1 { error(p, p.curr_tok.pos, "multiple 'auto_cast' in this field list") }
|
||||
if count > 0 { flags += {.Auto_Cast} }
|
||||
case .Any_Int:
|
||||
if count > 1 { error(p, p.curr_tok.pos, "multiple '#any_int' in this field list") }
|
||||
if count > 0 { flags += {.Any_Int} }
|
||||
if kind == .Invalid || kind == .Unknown {
|
||||
// Ignore
|
||||
} else {
|
||||
if count > 1 { error(p, p.curr_tok.pos, "multiple '%s' in this field list", ast.field_flag_strings[kind]) }
|
||||
if count > 0 { flags += {kind} }
|
||||
}
|
||||
}
|
||||
|
||||
return flags
|
||||
return
|
||||
}
|
||||
|
||||
check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, set_flags: ast.Field_Flags) -> (flags: ast.Field_Flags) {
|
||||
@@ -1748,19 +1718,13 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se
|
||||
|
||||
for flag in ast.Field_Flag {
|
||||
if flag not_in allowed_flags && flag in flags {
|
||||
switch flag {
|
||||
case .Using:
|
||||
error(p, p.curr_tok.pos, "'using' is not allowed within this field list")
|
||||
case .No_Alias:
|
||||
error(p, p.curr_tok.pos, "'#no_alias' is not allowed within this field list")
|
||||
case .C_Vararg:
|
||||
error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list")
|
||||
case .Auto_Cast:
|
||||
error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list")
|
||||
case .Any_Int:
|
||||
error(p, p.curr_tok.pos, "'#any_int' is not allowed within this field list")
|
||||
#partial switch flag {
|
||||
case .Unknown, .Invalid:
|
||||
// ignore
|
||||
case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token:
|
||||
panic("Impossible prefixes")
|
||||
case:
|
||||
error(p, p.curr_tok.pos, "'%s' is not allowed within this field list", ast.field_flag_strings[flag])
|
||||
}
|
||||
flags -= {flag}
|
||||
}
|
||||
@@ -2631,7 +2595,6 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
tok := expect_token(p, .Union)
|
||||
poly_params: ^ast.Field_List
|
||||
align: ^ast.Expr
|
||||
is_maybe: bool
|
||||
is_no_nil: bool
|
||||
is_shared_nil: bool
|
||||
|
||||
@@ -2656,10 +2619,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
}
|
||||
align = parse_expr(p, true)
|
||||
case "maybe":
|
||||
if is_maybe {
|
||||
error(p, tag.pos, "duplicate union tag '#%s'", tag.text)
|
||||
}
|
||||
is_maybe = true
|
||||
error(p, tag.pos, "#%s functionality has now been merged with standard 'union' functionality", tag.text)
|
||||
case "no_nil":
|
||||
if is_no_nil {
|
||||
error(p, tag.pos, "duplicate union tag '#%s'", tag.text)
|
||||
@@ -2676,19 +2636,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
}
|
||||
p.expr_level = prev_level
|
||||
|
||||
if is_no_nil && is_maybe {
|
||||
error(p, p.curr_tok.pos, "#maybe and #no_nil cannot be applied together")
|
||||
}
|
||||
if is_no_nil && is_shared_nil {
|
||||
error(p, p.curr_tok.pos, "#shared_nil and #no_nil cannot be applied together")
|
||||
}
|
||||
if is_shared_nil && is_maybe {
|
||||
error(p, p.curr_tok.pos, "#maybe and #shared_nil cannot be applied together")
|
||||
}
|
||||
|
||||
union_kind := ast.Union_Type_Kind.Normal
|
||||
switch {
|
||||
case is_maybe: union_kind = .maybe
|
||||
case is_no_nil: union_kind = .no_nil
|
||||
case is_shared_nil: union_kind = .shared_nil
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string {
|
||||
|
||||
fix_lines(p)
|
||||
|
||||
builder := strings.make_builder(0, 5 * mem.Megabyte, p.allocator)
|
||||
builder := strings.builder_make(0, 5 * mem.Megabyte, p.allocator)
|
||||
|
||||
last_line := 0
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int {
|
||||
|
||||
return 0
|
||||
} else {
|
||||
builder := strings.make_builder(context.temp_allocator)
|
||||
builder := strings.builder_make(context.temp_allocator)
|
||||
|
||||
c_len := len(comment.text)
|
||||
trim_space := true
|
||||
@@ -90,12 +90,12 @@ push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int {
|
||||
continue
|
||||
case c == '\r' && comment.text[min(c_len - 1, i + 1)] == '\n':
|
||||
append(&multilines, strings.to_string(builder))
|
||||
builder = strings.make_builder(context.temp_allocator)
|
||||
builder = strings.builder_make(context.temp_allocator)
|
||||
trim_space = true
|
||||
i += 1
|
||||
case c == '\n':
|
||||
append(&multilines, strings.to_string(builder))
|
||||
builder = strings.make_builder(context.temp_allocator)
|
||||
builder = strings.builder_make(context.temp_allocator)
|
||||
trim_space = true
|
||||
case c == '/' && comment.text[min(c_len - 1, i + 1)] == '*':
|
||||
strings.write_string(&builder, "/*")
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package os
|
||||
|
||||
import "core:strings"
|
||||
import "core:mem"
|
||||
|
||||
read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
|
||||
@@ -51,10 +50,13 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
|
||||
continue
|
||||
}
|
||||
|
||||
fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator)
|
||||
fullpath := make([]byte, len(dirpath)+1+len(filename))
|
||||
copy(fullpath, dirpath)
|
||||
copy(fullpath[len(dirpath):], "/")
|
||||
copy(fullpath[len(dirpath)+1:], filename)
|
||||
defer delete(fullpath, context.temp_allocator)
|
||||
|
||||
fi_, err = stat(fullpath, allocator)
|
||||
fi_, err = stat(string(fullpath), allocator)
|
||||
if err != ERROR_NONE {
|
||||
for fi__ in dfi {
|
||||
file_info_delete(fi__, allocator)
|
||||
|
||||
+16
-16
@@ -11,24 +11,24 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin
|
||||
return
|
||||
}
|
||||
wkey := win32.utf8_to_wstring(key)
|
||||
b := make([dynamic]u16, 100, context.temp_allocator)
|
||||
for {
|
||||
n := win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
|
||||
if n == 0 {
|
||||
err := win32.GetLastError()
|
||||
if err == u32(ERROR_ENVVAR_NOT_FOUND) {
|
||||
return "", false
|
||||
}
|
||||
n := win32.GetEnvironmentVariableW(wkey, nil, 0)
|
||||
if n == 0 {
|
||||
err := win32.GetLastError()
|
||||
if err == u32(ERROR_ENVVAR_NOT_FOUND) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if n <= u32(len(b)) {
|
||||
value, _ = win32.utf16_to_utf8(b[:n], allocator)
|
||||
found = true
|
||||
return
|
||||
}
|
||||
|
||||
resize(&b, len(b)*2)
|
||||
}
|
||||
b := make([dynamic]u16, n, context.temp_allocator)
|
||||
n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
|
||||
if n == 0 {
|
||||
err := win32.GetLastError()
|
||||
if err == u32(ERROR_ENVVAR_NOT_FOUND) {
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
value, _ = win32.utf16_to_utf8(b[:n], allocator)
|
||||
found = true
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -241,13 +241,13 @@ S_ISGID :: 0o2000 // Set group id on execution
|
||||
S_ISVTX :: 0o1000 // Directory restrcted delete
|
||||
|
||||
|
||||
S_ISLNK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFLNK
|
||||
S_ISREG :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFREG
|
||||
S_ISDIR :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFDIR
|
||||
S_ISCHR :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFCHR
|
||||
S_ISBLK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFBLK
|
||||
S_ISFIFO :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFIFO
|
||||
S_ISSOCK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFSOCK
|
||||
S_ISLNK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFLNK }
|
||||
S_ISREG :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFREG }
|
||||
S_ISDIR :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFDIR }
|
||||
S_ISCHR :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFCHR }
|
||||
S_ISBLK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFBLK }
|
||||
S_ISFIFO :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFIFO }
|
||||
S_ISSOCK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFSOCK }
|
||||
|
||||
F_OK :: 0 // Test for file existance
|
||||
X_OK :: 1 // Test for execute permission
|
||||
@@ -257,7 +257,7 @@ R_OK :: 4 // Test for read permission
|
||||
foreign libc {
|
||||
@(link_name="__error") __errno_location :: proc() -> ^int ---
|
||||
|
||||
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---
|
||||
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---
|
||||
@(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
|
||||
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||
|
||||
@@ -271,7 +271,7 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string, allocator := cont
|
||||
}
|
||||
|
||||
|
||||
d, derr := os.open(dir)
|
||||
d, derr := os.open(dir, os.O_RDONLY)
|
||||
if derr != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ clean :: proc(path: string, allocator := context.allocator) -> string {
|
||||
}
|
||||
|
||||
// join joins numerous path elements into a single path
|
||||
join :: proc(elems: ..string, allocator := context.allocator) -> string {
|
||||
join :: proc(elems: []string, allocator := context.allocator) -> string {
|
||||
context.allocator = allocator
|
||||
for elem, i in elems {
|
||||
if elem != "" {
|
||||
|
||||
@@ -573,11 +573,11 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
|
||||
write_type(w, info.elem, &n) or_return
|
||||
case is_rune(info.elem):
|
||||
io.write_encoded_rune(w, rune(info.lower), true, &n) or_return
|
||||
io.write_string(w, "..", &n) or_return
|
||||
io.write_string(w, "..=", &n) or_return
|
||||
io.write_encoded_rune(w, rune(info.upper), true, &n) or_return
|
||||
case:
|
||||
io.write_i64(w, info.lower, 10, &n) or_return
|
||||
io.write_string(w, "..", &n) or_return
|
||||
io.write_string(w, "..=", &n) or_return
|
||||
io.write_i64(w, info.upper, 10, &n) or_return
|
||||
}
|
||||
if info.underlying != nil {
|
||||
|
||||
@@ -339,19 +339,22 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
|
||||
if array == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if cap(array) < len(array)+1 {
|
||||
cap := 2 * cap(array) + max(8, 1)
|
||||
_ = reserve(array, cap, loc)
|
||||
}
|
||||
if cap(array)-len(array) > 0 {
|
||||
a := (^Raw_Dynamic_Array)(array)
|
||||
when size_of(E) != 0 {
|
||||
data := ([^]E)(a.data)
|
||||
assert(condition=data != nil, loc=loc)
|
||||
data[a.len] = arg
|
||||
}
|
||||
when size_of(E) == 0 {
|
||||
a.len += 1
|
||||
} else {
|
||||
if cap(array) < len(array)+1 {
|
||||
cap := 2 * cap(array) + max(8, 1)
|
||||
_ = reserve(array, cap, loc)
|
||||
}
|
||||
if cap(array)-len(array) > 0 {
|
||||
a := (^Raw_Dynamic_Array)(array)
|
||||
when size_of(E) != 0 {
|
||||
data := ([^]E)(a.data)
|
||||
assert(condition=data != nil, loc=loc)
|
||||
data[a.len] = arg
|
||||
}
|
||||
a.len += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,20 +369,23 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if cap(array) < len(array)+arg_len {
|
||||
cap := 2 * cap(array) + max(8, arg_len)
|
||||
_ = reserve(array, cap, loc)
|
||||
}
|
||||
arg_len = min(cap(array)-len(array), arg_len)
|
||||
if arg_len > 0 {
|
||||
a := (^Raw_Dynamic_Array)(array)
|
||||
when size_of(E) != 0 {
|
||||
data := ([^]E)(a.data)
|
||||
assert(condition=data != nil, loc=loc)
|
||||
intrinsics.mem_copy(&data[a.len], raw_data(args), size_of(E) * arg_len)
|
||||
}
|
||||
when size_of(E) == 0 {
|
||||
a.len += arg_len
|
||||
} else {
|
||||
if cap(array) < len(array)+arg_len {
|
||||
cap := 2 * cap(array) + max(8, arg_len)
|
||||
_ = reserve(array, cap, loc)
|
||||
}
|
||||
arg_len = min(cap(array)-len(array), arg_len)
|
||||
if arg_len > 0 {
|
||||
a := (^Raw_Dynamic_Array)(array)
|
||||
when size_of(E) != 0 {
|
||||
data := ([^]E)(a.data)
|
||||
assert(condition=data != nil, loc=loc)
|
||||
intrinsics.mem_copy(&data[a.len], raw_data(args), size_of(E) * arg_len)
|
||||
}
|
||||
a.len += arg_len
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,7 +419,7 @@ append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) {
|
||||
|
||||
|
||||
@builtin
|
||||
insert_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
if array == nil {
|
||||
return
|
||||
}
|
||||
@@ -432,7 +438,7 @@ insert_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
|
||||
}
|
||||
|
||||
@builtin
|
||||
insert_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
if array == nil {
|
||||
return
|
||||
}
|
||||
@@ -456,7 +462,7 @@ insert_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
|
||||
}
|
||||
|
||||
@builtin
|
||||
insert_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
if array == nil {
|
||||
return
|
||||
}
|
||||
@@ -477,7 +483,51 @@ insert_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
|
||||
return
|
||||
}
|
||||
|
||||
@builtin insert_at :: proc{insert_at_elem, insert_at_elems, insert_at_elem_string}
|
||||
@builtin inject_at :: proc{inject_at_elem, inject_at_elems, inject_at_elem_string}
|
||||
|
||||
|
||||
|
||||
@builtin
|
||||
assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
if index < len(array) {
|
||||
array[index] = arg
|
||||
ok = true
|
||||
} else if resize(array, index+1, loc) {
|
||||
array[index] = arg
|
||||
ok = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@builtin
|
||||
assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
if index+len(args) < len(array) {
|
||||
copy(array[index:], args)
|
||||
ok = true
|
||||
} else if resize(array, index+1+len(args), loc) {
|
||||
copy(array[index:], args)
|
||||
ok = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@builtin
|
||||
assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
if len(args) == 0 {
|
||||
ok = true
|
||||
} else if index+len(args) < len(array) {
|
||||
copy(array[index:], args)
|
||||
ok = true
|
||||
} else if resize(array, index+1+len(args), loc) {
|
||||
copy(array[index:], args)
|
||||
ok = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@builtin assign_at :: proc{assign_at_elem, assign_at_elems, assign_at_elem_string}
|
||||
|
||||
|
||||
|
||||
|
||||
+43
-105
@@ -17,50 +17,53 @@ Builder :: struct {
|
||||
}
|
||||
|
||||
// return a builder, default length 0 / cap 16 are done through make
|
||||
make_builder_none :: proc(allocator := context.allocator) -> Builder {
|
||||
builder_make_none :: proc(allocator := context.allocator) -> Builder {
|
||||
return Builder{buf=make([dynamic]byte, allocator)}
|
||||
}
|
||||
|
||||
// return a builder, with a set length `len` and cap 16 byte buffer
|
||||
make_builder_len :: proc(len: int, allocator := context.allocator) -> Builder {
|
||||
builder_make_len :: proc(len: int, allocator := context.allocator) -> Builder {
|
||||
return Builder{buf=make([dynamic]byte, len, allocator)}
|
||||
}
|
||||
|
||||
// return a builder, with a set length `len` byte buffer and a custom `cap`
|
||||
make_builder_len_cap :: proc(len, cap: int, allocator := context.allocator) -> Builder {
|
||||
builder_make_len_cap :: proc(len, cap: int, allocator := context.allocator) -> Builder {
|
||||
return Builder{buf=make([dynamic]byte, len, cap, allocator)}
|
||||
}
|
||||
|
||||
// overload simple `make_builder_*` with or without len / cap parameters
|
||||
make_builder :: proc{
|
||||
make_builder_none,
|
||||
make_builder_len,
|
||||
make_builder_len_cap,
|
||||
// overload simple `builder_make_*` with or without len / cap parameters
|
||||
builder_make :: proc{
|
||||
builder_make_none,
|
||||
builder_make_len,
|
||||
builder_make_len_cap,
|
||||
}
|
||||
|
||||
// initialize a builder, default length 0 / cap 16 are done through make
|
||||
// replaces the existing `buf`
|
||||
init_builder_none :: proc(b: ^Builder, allocator := context.allocator) {
|
||||
builder_init_none :: proc(b: ^Builder, allocator := context.allocator) -> ^Builder {
|
||||
b.buf = make([dynamic]byte, allocator)
|
||||
return b
|
||||
}
|
||||
|
||||
// initialize a builder, with a set length `len` and cap 16 byte buffer
|
||||
// replaces the existing `buf`
|
||||
init_builder_len :: proc(b: ^Builder, len: int, allocator := context.allocator) {
|
||||
builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator) -> ^Builder {
|
||||
b.buf = make([dynamic]byte, len, allocator)
|
||||
return b
|
||||
}
|
||||
|
||||
// initialize a builder, with a set length `len` byte buffer and a custom `cap`
|
||||
// replaces the existing `buf`
|
||||
init_builder_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator) {
|
||||
builder_init_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator) -> ^Builder {
|
||||
b.buf = make([dynamic]byte, len, cap, allocator)
|
||||
return b
|
||||
}
|
||||
|
||||
// overload simple `init_builder_*` with or without len / ap parameters
|
||||
init_builder :: proc{
|
||||
init_builder_none,
|
||||
init_builder_len,
|
||||
init_builder_len_cap,
|
||||
// overload simple `builder_init_*` with or without len / ap parameters
|
||||
builder_init :: proc{
|
||||
builder_init_none,
|
||||
builder_init_len,
|
||||
builder_init_len_cap,
|
||||
}
|
||||
|
||||
@(private)
|
||||
@@ -103,18 +106,18 @@ to_writer :: proc(b: ^Builder) -> io.Writer {
|
||||
}
|
||||
|
||||
// delete and clear the builder byte buffer content
|
||||
destroy_builder :: proc(b: ^Builder) {
|
||||
builder_destroy :: proc(b: ^Builder) {
|
||||
delete(b.buf)
|
||||
clear(&b.buf)
|
||||
}
|
||||
|
||||
// reserve the builfer byte buffer to a specific cap, when it's higher than before
|
||||
grow_builder :: proc(b: ^Builder, cap: int) {
|
||||
builder_grow :: proc(b: ^Builder, cap: int) {
|
||||
reserve(&b.buf, cap)
|
||||
}
|
||||
|
||||
// clear the builder byte buffer content
|
||||
reset_builder :: proc(b: ^Builder) {
|
||||
builder_reset :: proc(b: ^Builder) {
|
||||
clear(&b.buf)
|
||||
}
|
||||
|
||||
@@ -165,7 +168,7 @@ builder_space :: proc(b: Builder) -> int {
|
||||
/*
|
||||
appends a byte to the builder, returns the append diff
|
||||
|
||||
builder := strings.make_builder()
|
||||
builder := strings.builder_make()
|
||||
strings.write_byte(&builder, 'a') // 1
|
||||
strings.write_byte(&builder, 'b') // 1
|
||||
strings.write_byte(&builder, 'c') // 1
|
||||
@@ -181,7 +184,7 @@ write_byte :: proc(b: ^Builder, x: byte) -> (n: int) {
|
||||
/*
|
||||
appends a slice of bytes to the builder, returns the append diff
|
||||
|
||||
builder := strings.make_builder()
|
||||
builder := strings.builder_make()
|
||||
bytes := [?]byte { 'a', 'b', 'c' }
|
||||
strings.write_bytes(&builder, bytes[:]) // 3
|
||||
fmt.println(strings.to_string(builder)) // -> abc
|
||||
@@ -196,77 +199,46 @@ write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) {
|
||||
/*
|
||||
appends a single rune into the builder, returns written rune size and an `io.Error`
|
||||
|
||||
builder := strings.make_builder()
|
||||
strings.write_rune_builder(&builder, 'ä') // 2 None
|
||||
strings.write_rune_builder(&builder, 'b') // 1 None
|
||||
strings.write_rune_builder(&builder, 'c') // 1 None
|
||||
builder := strings.builder_make()
|
||||
strings.write_rune(&builder, 'ä') // 2 None
|
||||
strings.write_rune(&builder, 'b') // 1 None
|
||||
strings.write_rune(&builder, 'c') // 1 None
|
||||
fmt.println(strings.to_string(builder)) // -> äbc
|
||||
*/
|
||||
write_rune_builder :: proc(b: ^Builder, r: rune) -> (int, io.Error) {
|
||||
write_rune :: proc(b: ^Builder, r: rune) -> (int, io.Error) {
|
||||
return io.write_rune(to_writer(b), r)
|
||||
}
|
||||
|
||||
/*
|
||||
appends a quoted rune into the builder, returns written size
|
||||
|
||||
builder := strings.make_builder()
|
||||
builder := strings.builder_make()
|
||||
strings.write_string(&builder, "abc") // 3
|
||||
strings.write_quoted_rune_builder(&builder, 'ä') // 4
|
||||
strings.write_quoted_rune(&builder, 'ä') // 4
|
||||
strings.write_string(&builder, "abc") // 3
|
||||
fmt.println(strings.to_string(builder)) // -> abc'ä'abc
|
||||
*/
|
||||
write_quoted_rune_builder :: proc(b: ^Builder, r: rune) -> (n: int) {
|
||||
return write_quoted_rune(to_writer(b), r)
|
||||
write_quoted_rune :: proc(b: ^Builder, r: rune) -> (n: int) {
|
||||
return io.write_quoted_rune(to_writer(b), r)
|
||||
}
|
||||
|
||||
@(private)
|
||||
_write_byte :: proc(w: io.Writer, c: byte) -> int {
|
||||
err := io.write_byte(w, c)
|
||||
return 1 if err == nil else 0
|
||||
}
|
||||
|
||||
// writer append a quoted rune into the byte buffer, return the written size
|
||||
write_quoted_rune :: proc(w: io.Writer, r: rune) -> (n: int) {
|
||||
quote := byte('\'')
|
||||
n += _write_byte(w, quote)
|
||||
buf, width := utf8.encode_rune(r)
|
||||
if width == 1 && r == utf8.RUNE_ERROR {
|
||||
n += _write_byte(w, '\\')
|
||||
n += _write_byte(w, 'x')
|
||||
n += _write_byte(w, DIGITS_LOWER[buf[0]>>4])
|
||||
n += _write_byte(w, DIGITS_LOWER[buf[0]&0xf])
|
||||
} else {
|
||||
i, _ := io.write_escaped_rune(w, r, quote)
|
||||
n += i
|
||||
}
|
||||
n += _write_byte(w, quote)
|
||||
return
|
||||
}
|
||||
|
||||
// overload for `write_string_*` variants
|
||||
write_string :: proc{
|
||||
write_string_builder,
|
||||
write_string_writer,
|
||||
}
|
||||
|
||||
/*
|
||||
appends a string to the builder, return the written byte size
|
||||
|
||||
builder := strings.make_builder()
|
||||
builder := strings.builder_make()
|
||||
strings.write_string(&builder, "a") // 1
|
||||
strings.write_string(&builder, "bc") // 2
|
||||
strings.write_string(&builder, "xyz") // 3
|
||||
fmt.println(strings.to_string(builder)) // -> abcxyz
|
||||
*/
|
||||
write_string_builder :: proc(b: ^Builder, s: string) -> (n: int) {
|
||||
return write_string_writer(to_writer(b), s)
|
||||
write_string :: proc(b: ^Builder, s: string) -> (n: int) {
|
||||
n0 := len(b.buf)
|
||||
append(&b.buf, s)
|
||||
n1 := len(b.buf)
|
||||
return n1-n0
|
||||
}
|
||||
|
||||
// appends a string to the writer
|
||||
write_string_writer :: proc(w: io.Writer, s: string) -> (n: int) {
|
||||
n, _ = io.write(w, transmute([]byte)s)
|
||||
return
|
||||
}
|
||||
|
||||
// pops and returns the last byte in the builder
|
||||
// returns 0 when the builder is empty
|
||||
@@ -297,70 +269,36 @@ pop_rune :: proc(b: ^Builder) -> (r: rune, width: int) {
|
||||
@(private)
|
||||
DIGITS_LOWER := "0123456789abcdefx"
|
||||
|
||||
// overload for `write_quoted_string_*` variants
|
||||
write_quoted_string :: proc{
|
||||
write_quoted_string_builder,
|
||||
write_quoted_string_writer,
|
||||
}
|
||||
|
||||
/*
|
||||
append a quoted string into the builder, return the written byte size
|
||||
|
||||
builder := strings.make_builder()
|
||||
builder := strings.builder_make()
|
||||
strings.write_quoted_string(&builder, "a") // 3
|
||||
strings.write_quoted_string(&builder, "bc", '\'') // 4
|
||||
strings.write_quoted_string(&builder, "xyz") // 5
|
||||
fmt.println(strings.to_string(builder)) // -> "a"'bc'xyz"
|
||||
*/
|
||||
write_quoted_string_builder :: proc(b: ^Builder, str: string, quote: byte = '"') -> (n: int) {
|
||||
write_quoted_string :: proc(b: ^Builder, str: string, quote: byte = '"') -> (n: int) {
|
||||
n, _ = io.write_quoted_string(to_writer(b), str, quote)
|
||||
return
|
||||
}
|
||||
|
||||
@(deprecated="prefer io.write_quoted_string")
|
||||
write_quoted_string_writer :: proc(w: io.Writer, str: string, quote: byte = '"') -> (n: int) {
|
||||
n, _ = io.write_quoted_string(w, str, quote)
|
||||
return
|
||||
}
|
||||
|
||||
// overload for `write_encoded_rune_*`
|
||||
write_encoded_rune :: proc{
|
||||
write_encoded_rune_builder,
|
||||
write_encoded_rune_writer,
|
||||
}
|
||||
|
||||
// appends a rune to the builder, optional `write_quote` boolean tag, returns the written rune size
|
||||
write_encoded_rune_builder :: proc(b: ^Builder, r: rune, write_quote := true) -> (n: int) {
|
||||
write_encoded_rune :: proc(b: ^Builder, r: rune, write_quote := true) -> (n: int) {
|
||||
n, _ = io.write_encoded_rune(to_writer(b), r, write_quote)
|
||||
return
|
||||
|
||||
}
|
||||
@(deprecated="prefer io.write_encoded_rune")
|
||||
write_encoded_rune_writer :: proc(w: io.Writer, r: rune, write_quote := true) -> (n: int) {
|
||||
n, _ = io.write_encoded_rune(w, r, write_quote)
|
||||
return
|
||||
}
|
||||
|
||||
// overload for `write_escaped_rune_*`
|
||||
write_escaped_rune :: proc{
|
||||
write_escaped_rune_builder,
|
||||
write_escaped_rune_writer,
|
||||
}
|
||||
|
||||
// appends a rune to the builder, fully written out in case of escaped runes e.g. '\a' will be written as such
|
||||
// when `r` and `quote` match and `quote` is `\\` - they will be written as two slashes
|
||||
// `html_safe` flag in case the runes '<', '>', '&' should be encoded as digits e.g. `\u0026`
|
||||
write_escaped_rune_builder :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false) -> (n: int) {
|
||||
write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false) -> (n: int) {
|
||||
n, _ = io.write_escaped_rune(to_writer(b), r, quote, html_safe)
|
||||
return
|
||||
}
|
||||
|
||||
@(deprecated="prefer io.write_escaped_rune")
|
||||
write_escaped_rune_writer :: proc(w: io.Writer, r: rune, quote: byte, html_safe := false) -> (n: int) {
|
||||
n, _ = io.write_escaped_rune(w, r, quote, html_safe)
|
||||
return
|
||||
}
|
||||
|
||||
// writes a u64 value `i` in `base` = 10 into the builder, returns the written amount of characters
|
||||
write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) {
|
||||
buf: [32]byte
|
||||
|
||||
@@ -10,7 +10,7 @@ to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) ->
|
||||
}
|
||||
|
||||
b: Builder
|
||||
init_builder(&b, 0, 0, allocator)
|
||||
builder_init(&b, 0, 0, allocator)
|
||||
|
||||
s := s
|
||||
for c, i in s {
|
||||
@@ -20,7 +20,7 @@ to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) ->
|
||||
|
||||
_, w := utf8.decode_rune_in_string(s[i:])
|
||||
if w == 1 {
|
||||
grow_builder(&b, len(s) + len(replacement))
|
||||
builder_grow(&b, len(s) + len(replacement))
|
||||
write_string(&b, s[:i])
|
||||
s = s[i:]
|
||||
break
|
||||
@@ -67,9 +67,9 @@ to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) ->
|
||||
*/
|
||||
to_lower :: proc(s: string, allocator := context.allocator) -> string {
|
||||
b: Builder
|
||||
init_builder(&b, 0, len(s), allocator)
|
||||
builder_init(&b, 0, len(s), allocator)
|
||||
for r in s {
|
||||
write_rune_builder(&b, unicode.to_lower(r))
|
||||
write_rune(&b, unicode.to_lower(r))
|
||||
}
|
||||
return to_string(b)
|
||||
}
|
||||
@@ -83,9 +83,9 @@ to_lower :: proc(s: string, allocator := context.allocator) -> string {
|
||||
*/
|
||||
to_upper :: proc(s: string, allocator := context.allocator) -> string {
|
||||
b: Builder
|
||||
init_builder(&b, 0, len(s), allocator)
|
||||
builder_init(&b, 0, len(s), allocator)
|
||||
for r in s {
|
||||
write_rune_builder(&b, unicode.to_upper(r))
|
||||
write_rune(&b, unicode.to_upper(r))
|
||||
}
|
||||
return to_string(b)
|
||||
}
|
||||
@@ -147,7 +147,7 @@ to_camel_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
s := s
|
||||
s = trim_space(s)
|
||||
b: Builder
|
||||
init_builder(&b, 0, len(s), allocator)
|
||||
builder_init(&b, 0, len(s), allocator)
|
||||
w := to_writer(&b)
|
||||
|
||||
string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) {
|
||||
@@ -172,7 +172,7 @@ to_pascal_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
s := s
|
||||
s = trim_space(s)
|
||||
b: Builder
|
||||
init_builder(&b, 0, len(s), allocator)
|
||||
builder_init(&b, 0, len(s), allocator)
|
||||
w := to_writer(&b)
|
||||
|
||||
string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) {
|
||||
@@ -203,7 +203,7 @@ to_delimiter_case :: proc(s: string, delimiter: rune, all_upper_case: bool, allo
|
||||
s := s
|
||||
s = trim_space(s)
|
||||
b: Builder
|
||||
init_builder(&b, 0, len(s), allocator)
|
||||
builder_init(&b, 0, len(s), allocator)
|
||||
w := to_writer(&b)
|
||||
|
||||
adjust_case := unicode.to_upper if all_upper_case else unicode.to_lower
|
||||
@@ -272,7 +272,7 @@ to_ada_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
s := s
|
||||
s = trim_space(s)
|
||||
b: Builder
|
||||
init_builder(&b, 0, len(s), allocator)
|
||||
builder_init(&b, 0, len(s), allocator)
|
||||
w := to_writer(&b)
|
||||
|
||||
prev, curr: rune
|
||||
|
||||
@@ -1553,7 +1553,7 @@ split_multi_iterate :: proc(using sm: ^Split_Multi) -> (res: string, ok: bool) #
|
||||
scrub :: proc(s: string, replacement: string, allocator := context.allocator) -> string {
|
||||
str := s
|
||||
b: Builder
|
||||
init_builder(&b, 0, len(s), allocator)
|
||||
builder_init(&b, 0, len(s), allocator)
|
||||
|
||||
has_error := false
|
||||
cursor := 0
|
||||
@@ -1622,7 +1622,7 @@ expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) ->
|
||||
}
|
||||
|
||||
b: Builder
|
||||
init_builder(&b, allocator)
|
||||
builder_init(&b, allocator)
|
||||
writer := to_writer(&b)
|
||||
str := s
|
||||
column: int
|
||||
@@ -1690,8 +1690,8 @@ centre_justify :: proc(str: string, length: int, pad: string, allocator := conte
|
||||
pad_len := rune_count(pad)
|
||||
|
||||
b: Builder
|
||||
init_builder(&b, allocator)
|
||||
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad))
|
||||
builder_init(&b, allocator)
|
||||
builder_grow(&b, len(str) + (remains/pad_len + 1)*len(pad))
|
||||
|
||||
w := to_writer(&b)
|
||||
|
||||
@@ -1713,8 +1713,8 @@ left_justify :: proc(str: string, length: int, pad: string, allocator := context
|
||||
pad_len := rune_count(pad)
|
||||
|
||||
b: Builder
|
||||
init_builder(&b, allocator)
|
||||
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad))
|
||||
builder_init(&b, allocator)
|
||||
builder_grow(&b, len(str) + (remains/pad_len + 1)*len(pad))
|
||||
|
||||
w := to_writer(&b)
|
||||
|
||||
@@ -1735,8 +1735,8 @@ right_justify :: proc(str: string, length: int, pad: string, allocator := contex
|
||||
pad_len := rune_count(pad)
|
||||
|
||||
b: Builder
|
||||
init_builder(&b, allocator)
|
||||
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad))
|
||||
builder_init(&b, allocator)
|
||||
builder_grow(&b, len(str) + (remains/pad_len + 1)*len(pad))
|
||||
|
||||
w := to_writer(&b)
|
||||
|
||||
|
||||
@@ -3,24 +3,22 @@
|
||||
package sync
|
||||
|
||||
import "core:c"
|
||||
import "core:os"
|
||||
import "core:time"
|
||||
|
||||
UMTX_OP_WAIT :: 2
|
||||
UMTX_OP_WAKE :: 3
|
||||
|
||||
ETIMEDOUT :: 60
|
||||
|
||||
foreign import libc "system:c"
|
||||
|
||||
foreign libc {
|
||||
_umtx_op :: proc "c" (obj: rawptr, op: c.int, val: c.ulong, uaddr: rawptr, uaddr2: rawptr) -> c.int ---
|
||||
__error :: proc "c" () -> ^c.int ---
|
||||
}
|
||||
|
||||
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
timeout := os.Unix_File_Time{
|
||||
seconds = 5,
|
||||
nanoseconds = 0,
|
||||
}
|
||||
|
||||
timeout := [2]i64{14400, 0} // 4 hours
|
||||
for {
|
||||
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout)
|
||||
|
||||
@@ -28,7 +26,7 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
if os.Errno(os.get_last_error()) == os.ETIMEDOUT {
|
||||
if __error()^ == ETIMEDOUT {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -42,16 +40,14 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
|
||||
return false
|
||||
}
|
||||
|
||||
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &os.Unix_File_Time{
|
||||
seconds = (os.time_t)(duration/1e9),
|
||||
nanoseconds = (c.long)(duration%1e9),
|
||||
})
|
||||
timeout := [2]i64{i64(duration/1e9), i64(duration%1e9)}
|
||||
|
||||
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout)
|
||||
if res != -1 {
|
||||
return true
|
||||
}
|
||||
|
||||
if os.Errno(os.get_last_error()) == os.ETIMEDOUT {
|
||||
if __error()^ == ETIMEDOUT {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,14 @@
|
||||
//+private
|
||||
package sync
|
||||
|
||||
import "core:os"
|
||||
import "core:c"
|
||||
|
||||
foreign import dl "system:dl"
|
||||
|
||||
foreign dl {
|
||||
pthread_getthreadid_np :: proc "c" () -> c.int ---
|
||||
}
|
||||
|
||||
_current_thread_id :: proc "contextless" () -> int {
|
||||
return os.current_thread_id()
|
||||
return int(pthread_getthreadid_np())
|
||||
}
|
||||
|
||||
+171
-259
@@ -1148,6 +1148,156 @@ foreign wasi {
|
||||
*/
|
||||
how: sdflags_t,
|
||||
) -> errno_t ---
|
||||
|
||||
|
||||
/**
|
||||
* Return a description of the given preopened file descriptor.
|
||||
*/
|
||||
fd_prestat_dir_name :: proc(
|
||||
fd: fd_t,
|
||||
/**
|
||||
* A buffer into which to write the preopened directory name.
|
||||
*/
|
||||
path: string,
|
||||
) -> errno_t ---
|
||||
/**
|
||||
* Create a directory.
|
||||
* Note: This is similar to `mkdirat` in POSIX.
|
||||
*/
|
||||
path_create_directory :: proc(
|
||||
fd: fd_t,
|
||||
/**
|
||||
* The path at which to create the directory.
|
||||
*/
|
||||
path: string,
|
||||
) -> errno_t ---
|
||||
/**
|
||||
* Adjust the timestamps of a file or directory.
|
||||
* Note: This is similar to `utimensat` in POSIX.
|
||||
*/
|
||||
path_filestat_set_times :: proc(
|
||||
fd: fd_t,
|
||||
/**
|
||||
* Flags determining the method of how the path is resolved.
|
||||
*/
|
||||
flags: lookupflags_t,
|
||||
/**
|
||||
* The path of the file or directory to operate on.
|
||||
*/
|
||||
path: string,
|
||||
/**
|
||||
* The desired values of the data access timestamp.
|
||||
*/
|
||||
atim: timestamp_t,
|
||||
/**
|
||||
* The desired values of the data modification timestamp.
|
||||
*/
|
||||
mtim: timestamp_t,
|
||||
/**
|
||||
* A bitmask indicating which timestamps to adjust.
|
||||
*/
|
||||
fst_flags: fstflags_t,
|
||||
) -> errno_t ---
|
||||
/**
|
||||
* Remove a directory.
|
||||
* Return `errno::notempty` if the directory is not empty.
|
||||
* Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX.
|
||||
*/
|
||||
path_remove_directory :: proc(
|
||||
fd: fd_t,
|
||||
/**
|
||||
* The path to a directory to remove.
|
||||
*/
|
||||
path: string,
|
||||
) -> errno_t ---
|
||||
/**
|
||||
* Create a hard link.
|
||||
* Note: This is similar to `linkat` in POSIX.
|
||||
*/
|
||||
path_link :: proc(
|
||||
old_fd: fd_t,
|
||||
/**
|
||||
* Flags determining the method of how the path is resolved.
|
||||
*/
|
||||
old_flags: lookupflags_t,
|
||||
/**
|
||||
* The source path from which to link.
|
||||
*/
|
||||
old_path: string,
|
||||
/**
|
||||
* The working directory at which the resolution of the new path starts.
|
||||
*/
|
||||
new_fd: fd_t,
|
||||
/**
|
||||
* The destination path at which to create the hard link.
|
||||
*/
|
||||
new_path: string,
|
||||
) -> errno_t ---
|
||||
|
||||
/**
|
||||
* Rename a file or directory.
|
||||
* Note: This is similar to `renameat` in POSIX.
|
||||
*/
|
||||
path_rename :: proc(
|
||||
fd: fd_t,
|
||||
/**
|
||||
* The source path of the file or directory to rename.
|
||||
*/
|
||||
old_path: string,
|
||||
/**
|
||||
* The working directory at which the resolution of the new path starts.
|
||||
*/
|
||||
new_fd: fd_t,
|
||||
/**
|
||||
* The destination path to which to rename the file or directory.
|
||||
*/
|
||||
new_path: string,
|
||||
) -> errno_t ---
|
||||
|
||||
/**
|
||||
* Create a symbolic link.
|
||||
* Note: This is similar to `symlinkat` in POSIX.
|
||||
*/
|
||||
path_symlink :: proc(
|
||||
/**
|
||||
* The contents of the symbolic link.
|
||||
*/
|
||||
old_path: string,
|
||||
fd: fd_t,
|
||||
/**
|
||||
* The destination path at which to create the symbolic link.
|
||||
*/
|
||||
new_path: string,
|
||||
) -> errno_t ---
|
||||
|
||||
/**
|
||||
* Unlink a file.
|
||||
* Return `errno::isdir` if the path refers to a directory.
|
||||
* Note: This is similar to `unlinkat(fd, path, 0)` in POSIX.
|
||||
*/
|
||||
path_unlink_file :: proc(
|
||||
fd: fd_t,
|
||||
/**
|
||||
* The path to a file to unlink.
|
||||
*/
|
||||
path: string,
|
||||
) -> errno_t ---
|
||||
|
||||
/**
|
||||
* Write high-quality random data into a buffer.
|
||||
* This function blocks when the implementation is unable to immediately
|
||||
* provide sufficient high-quality random data.
|
||||
* This function may execute slowly, so when large mounts of random data are
|
||||
* required, it's advisable to use this function to seed a pseudo-random
|
||||
* number generator, rather than to provide the random data directly.
|
||||
*/
|
||||
random_get :: proc(
|
||||
/**
|
||||
* The buffer to fill with random data.
|
||||
*/
|
||||
buf: []u8,
|
||||
) -> errno_t ---
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1250,7 +1400,7 @@ fd_pread :: proc "c" (
|
||||
*/
|
||||
offset: filesize_t,
|
||||
) -> (n: size_t, err: errno_t) {
|
||||
err = wasi_fd_pread(fd, raw_data(iovs), len(iovs), offset, &n)
|
||||
err = wasi_fd_pread(fd, iovs, offset, &n)
|
||||
return
|
||||
}
|
||||
/**
|
||||
@@ -1281,7 +1431,7 @@ fd_pwrite :: proc "c" (
|
||||
*/
|
||||
offset: filesize_t,
|
||||
) -> (n: size_t, err: errno_t) {
|
||||
err = wasi_fd_pwrite(fd, raw_data(iovs), len(iovs), offset, &n)
|
||||
err = wasi_fd_pwrite(fd, iovs, offset, &n)
|
||||
return
|
||||
}
|
||||
/**
|
||||
@@ -1297,7 +1447,7 @@ fd_read :: proc "c" (
|
||||
*/
|
||||
iovs: []iovec_t,
|
||||
) -> (n: size_t, err: errno_t) {
|
||||
err = wasi_fd_read(fd, raw_data(iovs), len(iovs), &n)
|
||||
err = wasi_fd_read(fd, iovs, &n)
|
||||
return
|
||||
}
|
||||
/**
|
||||
@@ -1324,7 +1474,7 @@ fd_readdir :: proc "c" (
|
||||
*/
|
||||
cookie: dircookie_t,
|
||||
) -> (n: size_t, err: errno_t) {
|
||||
err = wasi_fd_readdir(fd, raw_data(buf), len(buf), cookie, &n)
|
||||
err = wasi_fd_readdir(fd, buf, cookie, &n)
|
||||
return
|
||||
}
|
||||
/**
|
||||
@@ -1370,7 +1520,7 @@ fd_write :: proc "c" (
|
||||
*/
|
||||
iovs: []ciovec_t,
|
||||
) -> (n: size_t, err: errno_t) {
|
||||
err = wasi_fd_write(fd, raw_data(iovs), len(iovs), &n)
|
||||
err = wasi_fd_write(fd, iovs, &n)
|
||||
return
|
||||
}
|
||||
/**
|
||||
@@ -1390,7 +1540,7 @@ path_filestat_get :: proc "c" (
|
||||
*/
|
||||
path: string,
|
||||
) -> (offset: filestat_t, err: errno_t) {
|
||||
err = wasi_path_filestat_get(fd, flags, raw_data(path), len(path), &offset)
|
||||
err = wasi_path_filestat_get(fd, flags, path, &offset)
|
||||
return
|
||||
}
|
||||
/**
|
||||
@@ -1432,7 +1582,7 @@ path_open :: proc "c" (
|
||||
fs_rights_inheriting: rights_t,
|
||||
fdflags: fdflags_t,
|
||||
) -> (file: fd_t, err: errno_t) {
|
||||
err = wasi_path_open(fd, dirflags, raw_data(path), len(path), oflags, fs_rights_base, fs_rights_inheriting, fdflags, &file)
|
||||
err = wasi_path_open(fd, dirflags, path, oflags, fs_rights_base, fs_rights_inheriting, fdflags, &file)
|
||||
return
|
||||
}
|
||||
/**
|
||||
@@ -1452,7 +1602,7 @@ path_readlink :: proc "c" (
|
||||
*/
|
||||
buf: []u8,
|
||||
) -> (n: size_t, err: errno_t) {
|
||||
err = wasi_path_readlink(fd, raw_data(path), len(path), raw_data(buf), len(buf), &n)
|
||||
err = wasi_path_readlink(fd, path, buf, &n)
|
||||
return
|
||||
}
|
||||
/**
|
||||
@@ -1495,7 +1645,7 @@ sock_recv :: proc "c" (
|
||||
*/
|
||||
ri_flags: riflags_t,
|
||||
) -> (n: size_t, flags: roflags_t, err: errno_t) {
|
||||
err = wasi_sock_recv(fd, raw_data(ri_data), len(ri_data), ri_flags, &n, &flags)
|
||||
err = wasi_sock_recv(fd, ri_data, ri_flags, &n, &flags)
|
||||
return
|
||||
}
|
||||
/**
|
||||
@@ -1516,172 +1666,11 @@ sock_send :: proc "c" (
|
||||
*/
|
||||
si_flags: siflags_t,
|
||||
) -> (n: size_t, err: errno_t) {
|
||||
err = wasi_sock_send(fd, raw_data(si_data), len(si_data), si_flags, &n)
|
||||
err = wasi_sock_send(fd, si_data, si_flags, &n)
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description of the given preopened file descriptor.
|
||||
*/
|
||||
fd_prestat_dir_name :: proc(
|
||||
fd: fd_t,
|
||||
/**
|
||||
* A buffer into which to write the preopened directory name.
|
||||
*/
|
||||
path: string,
|
||||
) -> errno_t {
|
||||
return wasm_fd_prestat_dir_name(fd, raw_data(path), len(path))
|
||||
}
|
||||
/**
|
||||
* Create a directory.
|
||||
* Note: This is similar to `mkdirat` in POSIX.
|
||||
*/
|
||||
path_create_directory :: proc(
|
||||
fd: fd_t,
|
||||
/**
|
||||
* The path at which to create the directory.
|
||||
*/
|
||||
path: string,
|
||||
) -> errno_t {
|
||||
return wasm_path_create_directory(fd, raw_data(path), len(path))
|
||||
}
|
||||
/**
|
||||
* Adjust the timestamps of a file or directory.
|
||||
* Note: This is similar to `utimensat` in POSIX.
|
||||
*/
|
||||
path_filestat_set_times :: proc(
|
||||
fd: fd_t,
|
||||
/**
|
||||
* Flags determining the method of how the path is resolved.
|
||||
*/
|
||||
flags: lookupflags_t,
|
||||
/**
|
||||
* The path of the file or directory to operate on.
|
||||
*/
|
||||
path: string,
|
||||
/**
|
||||
* The desired values of the data access timestamp.
|
||||
*/
|
||||
atim: timestamp_t,
|
||||
/**
|
||||
* The desired values of the data modification timestamp.
|
||||
*/
|
||||
mtim: timestamp_t,
|
||||
/**
|
||||
* A bitmask indicating which timestamps to adjust.
|
||||
*/
|
||||
fst_flags: fstflags_t,
|
||||
) -> errno_t {
|
||||
return wasm_path_filestat_set_times(fd, flags, raw_data(path), len(path), atim, mtim, fst_flags)
|
||||
}
|
||||
/**
|
||||
* Remove a directory.
|
||||
* Return `errno::notempty` if the directory is not empty.
|
||||
* Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX.
|
||||
*/
|
||||
path_remove_directory :: proc(
|
||||
fd: fd_t,
|
||||
/**
|
||||
* The path to a directory to remove.
|
||||
*/
|
||||
path: string,
|
||||
) -> errno_t {
|
||||
return wasm_path_remove_directory(fd, raw_data(path), len(path))
|
||||
}
|
||||
/**
|
||||
* Create a hard link.
|
||||
* Note: This is similar to `linkat` in POSIX.
|
||||
*/
|
||||
path_link :: proc(
|
||||
old_fd: fd_t,
|
||||
/**
|
||||
* Flags determining the method of how the path is resolved.
|
||||
*/
|
||||
old_flags: lookupflags_t,
|
||||
/**
|
||||
* The source path from which to link.
|
||||
*/
|
||||
old_path: string,
|
||||
/**
|
||||
* The working directory at which the resolution of the new path starts.
|
||||
*/
|
||||
new_fd: fd_t,
|
||||
/**
|
||||
* The destination path at which to create the hard link.
|
||||
*/
|
||||
new_path: string,
|
||||
) -> errno_t {
|
||||
return wasm_path_link(old_fd, old_flags, raw_data(old_path), len(old_path), new_fd, raw_data(new_path), len(new_path))
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename a file or directory.
|
||||
* Note: This is similar to `renameat` in POSIX.
|
||||
*/
|
||||
path_rename :: proc(
|
||||
fd: fd_t,
|
||||
/**
|
||||
* The source path of the file or directory to rename.
|
||||
*/
|
||||
old_path: string,
|
||||
/**
|
||||
* The working directory at which the resolution of the new path starts.
|
||||
*/
|
||||
new_fd: fd_t,
|
||||
/**
|
||||
* The destination path to which to rename the file or directory.
|
||||
*/
|
||||
new_path: string,
|
||||
) -> errno_t {
|
||||
return wasm_path_rename(fd, raw_data(old_path), len(old_path), new_fd, raw_data(new_path), len(new_path))
|
||||
}
|
||||
/**
|
||||
* Create a symbolic link.
|
||||
* Note: This is similar to `symlinkat` in POSIX.
|
||||
*/
|
||||
path_symlink :: proc(
|
||||
/**
|
||||
* The contents of the symbolic link.
|
||||
*/
|
||||
old_path: string,
|
||||
fd: fd_t,
|
||||
/**
|
||||
* The destination path at which to create the symbolic link.
|
||||
*/
|
||||
new_path: string,
|
||||
) -> errno_t {
|
||||
return wasm_path_symlink(raw_data(old_path), len(old_path), fd, raw_data(new_path), len(new_path))
|
||||
}
|
||||
/**
|
||||
* Unlink a file.
|
||||
* Return `errno::isdir` if the path refers to a directory.
|
||||
* Note: This is similar to `unlinkat(fd, path, 0)` in POSIX.
|
||||
*/
|
||||
path_unlink_file :: proc(
|
||||
fd: fd_t,
|
||||
/**
|
||||
* The path to a file to unlink.
|
||||
*/
|
||||
path: string,
|
||||
) -> errno_t {
|
||||
return wasm_path_unlink_file(fd, raw_data(path), len(path))
|
||||
}
|
||||
/**
|
||||
* Write high-quality random data into a buffer.
|
||||
* This function blocks when the implementation is unable to immediately
|
||||
* provide sufficient high-quality random data.
|
||||
* This function may execute slowly, so when large mounts of random data are
|
||||
* required, it's advisable to use this function to seed a pseudo-random
|
||||
* number generator, rather than to provide the random data directly.
|
||||
*/
|
||||
random_get :: proc(
|
||||
/**
|
||||
* The buffer to fill with random data.
|
||||
*/
|
||||
buf: []u8,
|
||||
) -> errno_t {
|
||||
return wasm_random_get(raw_data(buf), len(buf))
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1722,8 +1711,7 @@ foreign wasi {
|
||||
@(link_name="fd_pread")
|
||||
wasi_fd_pread :: proc(
|
||||
fd: fd_t,
|
||||
iovs: [^]iovec_t,
|
||||
iovs_len: size_t,
|
||||
iovs: []iovec_t,
|
||||
offset: filesize_t,
|
||||
retptr0: ^size_t,
|
||||
) -> errno_t ---
|
||||
@@ -1735,23 +1723,20 @@ foreign wasi {
|
||||
@(link_name="fd_pwrite")
|
||||
wasi_fd_pwrite :: proc(
|
||||
fd: fd_t,
|
||||
iovs: [^]ciovec_t,
|
||||
iovs_len: size_t,
|
||||
iovs: []ciovec_t,
|
||||
offset: filesize_t,
|
||||
retptr0: ^size_t,
|
||||
) -> errno_t ---
|
||||
@(link_name="fd_read")
|
||||
wasi_fd_read :: proc(
|
||||
fd: fd_t,
|
||||
iovs: [^]iovec_t,
|
||||
iovs_len: size_t,
|
||||
iovs: []iovec_t,
|
||||
retptr0: ^size_t,
|
||||
) -> errno_t ---
|
||||
@(link_name="fd_readdir")
|
||||
wasi_fd_readdir :: proc(
|
||||
fd: fd_t,
|
||||
buf: [^]u8,
|
||||
buf_len: size_t,
|
||||
buf: []u8,
|
||||
cookie: dircookie_t,
|
||||
retptr0: ^size_t,
|
||||
) -> errno_t ---
|
||||
@@ -1770,8 +1755,7 @@ foreign wasi {
|
||||
@(link_name="fd_write")
|
||||
wasi_fd_write :: proc(
|
||||
fd: fd_t,
|
||||
iovs: [^]ciovec_t,
|
||||
iovs_len: size_t,
|
||||
iovs: []ciovec_t,
|
||||
retptr0: ^size_t,
|
||||
) -> errno_t ---
|
||||
@(link_name="path_filestat_get")
|
||||
@@ -1781,16 +1765,14 @@ foreign wasi {
|
||||
/**
|
||||
* The path of the file or directory to inspect.
|
||||
*/
|
||||
path: [^]u8,
|
||||
path_len: size_t,
|
||||
path: string,
|
||||
retptr0: ^filestat_t,
|
||||
) -> errno_t ---
|
||||
@(link_name="path_open")
|
||||
wasi_path_open :: proc(
|
||||
fd: fd_t,
|
||||
dirflags: lookupflags_t,
|
||||
path: [^]u8,
|
||||
path_len: size_t,
|
||||
path: string,
|
||||
oflags: oflags_t,
|
||||
fs_rights_base: rights_t,
|
||||
fs_rights_inheriting: rights_t,
|
||||
@@ -1800,10 +1782,8 @@ foreign wasi {
|
||||
@(link_name="path_readlink")
|
||||
wasi_path_readlink :: proc(
|
||||
fd: fd_t,
|
||||
path: [^]u8,
|
||||
path_len: size_t,
|
||||
buf: [^]u8,
|
||||
buf_len: size_t,
|
||||
path: string,
|
||||
buf: []u8,
|
||||
retptr0: ^size_t,
|
||||
) -> errno_t ---
|
||||
@(link_name="poll_oneoff")
|
||||
@@ -1816,8 +1796,7 @@ foreign wasi {
|
||||
@(link_name="sock_recv")
|
||||
wasi_sock_recv :: proc(
|
||||
fd: fd_t,
|
||||
ri_data: [^]iovec_t,
|
||||
ri_data_len: size_t,
|
||||
ri_data: []iovec_t,
|
||||
ri_flags: riflags_t,
|
||||
retptr0: ^size_t,
|
||||
retptr1: ^roflags_t,
|
||||
@@ -1825,75 +1804,8 @@ foreign wasi {
|
||||
@(link_name="sock_send")
|
||||
wasi_sock_send :: proc(
|
||||
fd: fd_t,
|
||||
si_data: [^]ciovec_t,
|
||||
si_data_len: size_t,
|
||||
si_data: []ciovec_t,
|
||||
si_flags: siflags_t,
|
||||
retptr0: ^size_t,
|
||||
) -> errno_t ---
|
||||
@(link_name="fd_prestat_dir_name")
|
||||
wasm_fd_prestat_dir_name :: proc(
|
||||
fd: fd_t,
|
||||
path: [^]u8,
|
||||
path_len: size_t,
|
||||
) -> errno_t ---
|
||||
@(link_name="path_create_directory")
|
||||
wasm_path_create_directory :: proc(
|
||||
fd: fd_t,
|
||||
path: [^]u8,
|
||||
path_len: size_t,
|
||||
) -> errno_t ---
|
||||
@(link_name="path_filestat_set_times")
|
||||
wasm_path_filestat_set_times :: proc(
|
||||
fd: fd_t,
|
||||
flags: lookupflags_t,
|
||||
path: [^]u8,
|
||||
path_len: size_t,
|
||||
atim: timestamp_t,
|
||||
mtim: timestamp_t,
|
||||
fst_flags: fstflags_t,
|
||||
) -> errno_t ---
|
||||
@(link_name="path_remove_directory")
|
||||
wasm_path_remove_directory :: proc(
|
||||
fd: fd_t,
|
||||
path: [^]u8,
|
||||
path_len: size_t,
|
||||
) -> errno_t ---
|
||||
@(link_name="path_link")
|
||||
wasm_path_link :: proc(
|
||||
old_fd: fd_t,
|
||||
old_flags: lookupflags_t,
|
||||
old_path: [^]u8,
|
||||
old_path_len: size_t,
|
||||
new_fd: fd_t,
|
||||
new_path: [^]u8,
|
||||
new_path_len: size_t,
|
||||
) -> errno_t ---
|
||||
@(link_name="path_rename")
|
||||
wasm_path_rename :: proc(
|
||||
fd: fd_t,
|
||||
old_path: [^]u8,
|
||||
old_path_len: size_t,
|
||||
new_fd: fd_t,
|
||||
new_path: [^]u8,
|
||||
new_path_len: size_t,
|
||||
) -> errno_t ---
|
||||
@(link_name="path_symlink")
|
||||
wasm_path_symlink :: proc(
|
||||
old_path: [^]u8,
|
||||
old_path_len: size_t,
|
||||
fd: fd_t,
|
||||
new_path: [^]u8,
|
||||
new_path_len: size_t,
|
||||
) -> errno_t ---
|
||||
@(link_name="path_unlink_file")
|
||||
wasm_path_unlink_file :: proc(
|
||||
fd: fd_t,
|
||||
path: [^]u8,
|
||||
path_len: size_t,
|
||||
) -> errno_t ---
|
||||
@(link_name="random_get")
|
||||
wasm_random_get :: proc(
|
||||
buf: [^]u8,
|
||||
buf_len: size_t,
|
||||
) -> errno_t ---
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ foreign user32 {
|
||||
|
||||
RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM ---
|
||||
RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM ---
|
||||
UnregisterClassW :: proc(lpClassName: LPCWSTR, hInstance: HINSTANCE) -> BOOL ---
|
||||
|
||||
CreateWindowExW :: proc(
|
||||
dwExStyle: DWORD,
|
||||
|
||||
@@ -22,6 +22,10 @@ GET_Y_LPARAM :: #force_inline proc "contextless" (lp: LPARAM) -> c_int {
|
||||
return cast(c_int)cast(c_short)HIWORD(cast(DWORD)lp)
|
||||
}
|
||||
|
||||
MAKE_WORD :: #force_inline proc "contextless" (x, y: WORD) -> WORD {
|
||||
return x << 8 | y
|
||||
}
|
||||
|
||||
utf8_to_utf16 :: proc(s: string, allocator := context.temp_allocator) -> []u16 {
|
||||
if len(s) < 1 {
|
||||
return nil
|
||||
|
||||
@@ -45,4 +45,4 @@ ERROR_NOT_SAME_OBJECT : DWORD : 1656
|
||||
|
||||
E_NOTIMPL :: HRESULT(-0x7fff_bfff) // 0x8000_4001
|
||||
|
||||
SUCCEEDED :: #force_inline proc(#any_int result: int) -> bool do return result >= 0
|
||||
SUCCEEDED :: #force_inline proc(#any_int result: int) -> bool { return result >= 0 }
|
||||
|
||||
@@ -45,7 +45,7 @@ generate_encoding_entity_table :: proc() {
|
||||
printf("\"%v\" loaded and parsed.\n", filename)
|
||||
|
||||
generated_buf: strings.Builder
|
||||
defer strings.destroy_builder(&generated_buf)
|
||||
defer strings.builder_destroy(&generated_buf)
|
||||
w := strings.to_writer(&generated_buf)
|
||||
|
||||
charlist, charlist_ok := xml.find_child_by_ident(doc.root, "charlist")
|
||||
|
||||
@@ -1322,6 +1322,7 @@ bool init_build_paths(String init_filename) {
|
||||
}
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
if (bc->metrics.os == TargetOs_windows) {
|
||||
if (bc->resource_filepath.len > 0) {
|
||||
bc->build_paths[BuildPath_RC] = path_from_string(ha, bc->resource_filepath);
|
||||
bc->build_paths[BuildPath_RES] = path_from_string(ha, bc->resource_filepath);
|
||||
@@ -1377,6 +1378,7 @@ bool init_build_paths(String init_filename) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// All the build targets and OSes.
|
||||
|
||||
+35
-18
@@ -2959,7 +2959,14 @@ void check_binary_matrix(CheckerContext *c, Token const &op, Operand *x, Operand
|
||||
goto matrix_error;
|
||||
}
|
||||
x->mode = Addressing_Value;
|
||||
x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count);
|
||||
if (are_types_identical(xt, yt)) {
|
||||
if (!is_type_named(x->type) && is_type_named(y->type)) {
|
||||
// prefer the named type
|
||||
x->type = y->type;
|
||||
}
|
||||
} else {
|
||||
x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count);
|
||||
}
|
||||
goto matrix_success;
|
||||
} else if (yt->kind == Type_Array) {
|
||||
if (!are_types_identical(xt->Matrix.elem, yt->Array.elem)) {
|
||||
@@ -3021,7 +3028,6 @@ void check_binary_matrix(CheckerContext *c, Token const &op, Operand *x, Operand
|
||||
|
||||
matrix_success:
|
||||
x->type = check_matrix_type_hint(x->type, type_hint);
|
||||
|
||||
return;
|
||||
|
||||
|
||||
@@ -8404,23 +8410,30 @@ ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *
|
||||
if (is_type_bit_set(type)) {
|
||||
// NOTE(bill): Encode as an integer
|
||||
|
||||
i64 lower = base_type(type)->BitSet.lower;
|
||||
Type *bt = base_type(type);
|
||||
BigInt bits = {};
|
||||
BigInt one = {};
|
||||
big_int_from_u64(&one, 1);
|
||||
|
||||
u64 bits = 0;
|
||||
for_array(index, cl->elems) {
|
||||
Ast *elem = cl->elems[index];
|
||||
GB_ASSERT(elem->kind != Ast_FieldValue);
|
||||
TypeAndValue tav = elem->tav;
|
||||
ExactValue i = exact_value_to_integer(tav.value);
|
||||
if (i.kind != ExactValue_Integer) {
|
||||
for_array(i, cl->elems) {
|
||||
Ast *e = cl->elems[i];
|
||||
GB_ASSERT(e->kind != Ast_FieldValue);
|
||||
|
||||
TypeAndValue tav = e->tav;
|
||||
if (tav.mode != Addressing_Constant) {
|
||||
continue;
|
||||
}
|
||||
i64 val = big_int_to_i64(&i.value_integer);
|
||||
val -= lower;
|
||||
u64 bit = u64(1ll<<val);
|
||||
bits |= bit;
|
||||
GB_ASSERT(tav.value.kind == ExactValue_Integer);
|
||||
i64 v = big_int_to_i64(&tav.value.value_integer);
|
||||
i64 lower = bt->BitSet.lower;
|
||||
u64 index = cast(u64)(v-lower);
|
||||
BigInt bit = {};
|
||||
big_int_from_u64(&bit, index);
|
||||
big_int_shl(&bit, &one, &bit);
|
||||
big_int_or(&bits, &bits, &bit);
|
||||
}
|
||||
o->value = exact_value_u64(bits);
|
||||
o->value.kind = ExactValue_Integer;
|
||||
o->value.value_integer = bits;
|
||||
} else if (is_type_constant_type(type) && cl->elems.count == 0) {
|
||||
ExactValue value = exact_value_compound(node);
|
||||
Type *bt = core_type(type);
|
||||
@@ -8643,6 +8656,8 @@ ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
Ast *first_arg = x.expr->SelectorExpr.expr;
|
||||
GB_ASSERT(first_arg != nullptr);
|
||||
|
||||
first_arg->state_flags |= StateFlag_SelectorCallExpr;
|
||||
|
||||
Type *pt = base_type(x.type);
|
||||
GB_ASSERT(pt->kind == Type_Proc);
|
||||
Type *first_type = nullptr;
|
||||
@@ -8668,6 +8683,7 @@ ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
y.mode = first_arg->tav.mode;
|
||||
y.type = first_arg->tav.type;
|
||||
y.value = first_arg->tav.value;
|
||||
|
||||
if (check_is_assignable_to(c, &y, first_type)) {
|
||||
// Do nothing, it's valid
|
||||
} else {
|
||||
@@ -9286,7 +9302,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
check_unary_expr(c, o, ue->op, node);
|
||||
}
|
||||
o->expr = node;
|
||||
return kind;
|
||||
return Expr_Expr;
|
||||
case_end;
|
||||
|
||||
|
||||
@@ -10034,9 +10050,10 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) {
|
||||
str = write_expr_to_string(str, ce->proc, shorthand);
|
||||
str = gb_string_appendc(str, "(");
|
||||
|
||||
for_array(i, ce->args) {
|
||||
isize idx0 = cast(isize)ce->was_selector;
|
||||
for (isize i = idx0; i < ce->args.count; i++) {
|
||||
Ast *arg = ce->args[i];
|
||||
if (i > 0) {
|
||||
if (i > idx0) {
|
||||
str = gb_string_appendc(str, ", ");
|
||||
}
|
||||
str = write_expr_to_string(str, arg, shorthand);
|
||||
|
||||
+44
-8
@@ -695,11 +695,6 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
||||
error(ut->align, "A union with #no_nil must have at least 2 variants");
|
||||
}
|
||||
break;
|
||||
case UnionType_maybe:
|
||||
if (variants.count != 1) {
|
||||
error(ut->align, "A union with #maybe must have at 1 variant, got %lld", cast(long long)variants.count);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ut->align != nullptr) {
|
||||
@@ -1345,7 +1340,9 @@ ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type *
|
||||
param_value.kind = ParameterValue_Constant;
|
||||
param_value.value = o.value;
|
||||
} else {
|
||||
error(expr, "Default parameter must be a constant, %d", o.mode);
|
||||
gbString s = expr_to_string(o.expr);
|
||||
error(expr, "Default parameter must be a constant, got %s", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1614,6 +1611,10 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
error(name, "'#any_int' can only be applied to variable fields");
|
||||
p->flags &= ~FieldFlag_any_int;
|
||||
}
|
||||
if (p->flags&FieldFlag_by_ptr) {
|
||||
error(name, "'#by_ptr' can only be applied to variable fields");
|
||||
p->flags &= ~FieldFlag_by_ptr;
|
||||
}
|
||||
|
||||
param = alloc_entity_type_name(scope, name->Ident.token, type, EntityState_Resolved);
|
||||
param->TypeName.is_type_alias = true;
|
||||
@@ -1690,10 +1691,17 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
|
||||
if (p->flags&FieldFlag_no_alias) {
|
||||
if (!is_type_pointer(type)) {
|
||||
error(name, "'#no_alias' can only be applied to fields of pointer type");
|
||||
error(name, "'#no_alias' can only be applied pointer typed parameters");
|
||||
p->flags &= ~FieldFlag_no_alias; // Remove the flag
|
||||
}
|
||||
}
|
||||
if (p->flags&FieldFlag_by_ptr) {
|
||||
if (is_type_internally_pointer_like(type)) {
|
||||
error(name, "'#by_ptr' can only be applied to non-pointer-like parameters");
|
||||
p->flags &= ~FieldFlag_by_ptr; // Remove the flag
|
||||
}
|
||||
}
|
||||
|
||||
if (is_poly_name) {
|
||||
if (p->flags&FieldFlag_no_alias) {
|
||||
error(name, "'#no_alias' can only be applied to non constant values");
|
||||
@@ -1711,6 +1719,10 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
error(name, "'#const' can only be applied to variable fields");
|
||||
p->flags &= ~FieldFlag_const;
|
||||
}
|
||||
if (p->flags&FieldFlag_by_ptr) {
|
||||
error(name, "'#by_ptr' can only be applied to variable fields");
|
||||
p->flags &= ~FieldFlag_by_ptr;
|
||||
}
|
||||
|
||||
if (!is_type_constant_type(type) && !is_type_polymorphic(type)) {
|
||||
gbString str = type_to_string(type);
|
||||
@@ -1743,6 +1755,9 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
if (p->flags&FieldFlag_const) {
|
||||
param->flags |= EntityFlag_ConstInput;
|
||||
}
|
||||
if (p->flags&FieldFlag_by_ptr) {
|
||||
param->flags |= EntityFlag_ByPtr;
|
||||
}
|
||||
|
||||
param->state = EntityState_Resolved; // NOTE(bill): This should have be resolved whilst determining it
|
||||
add_entity(ctx, scope, name, param);
|
||||
@@ -2685,7 +2700,28 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
|
||||
case_end;
|
||||
|
||||
case_ast_node(pt, PointerType, e);
|
||||
*type = alloc_type_pointer(check_type(ctx, pt->type));
|
||||
CheckerContext c = *ctx;
|
||||
c.type_path = new_checker_type_path();
|
||||
defer (destroy_checker_type_path(c.type_path));
|
||||
|
||||
Type *elem = t_invalid;
|
||||
Operand o = {};
|
||||
check_expr_or_type(&c, &o, pt->type);
|
||||
if (o.mode != Addressing_Invalid && o.mode != Addressing_Type) {
|
||||
// NOTE(bill): call check_type_expr again to get a consistent error message
|
||||
begin_error_block();
|
||||
elem = check_type_expr(&c, pt->type, nullptr);
|
||||
if (o.mode == Addressing_Variable) {
|
||||
gbString s = expr_to_string(pt->type);
|
||||
error_line("\tSuggestion: ^ is used for pointer types, did you mean '&%s'?\n", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
end_error_block();
|
||||
} else {
|
||||
elem = o.type;
|
||||
}
|
||||
|
||||
*type = alloc_type_pointer(elem);
|
||||
set_base_type(named_type, *type);
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
@@ -434,7 +434,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
|
||||
{STR_LIT("simd_neg"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("simd_abs"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("simd_abs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("simd_min"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("simd_max"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
@@ -98,7 +98,6 @@ enum OdinDocTypeFlag_Struct : u32 {
|
||||
enum OdinDocTypeFlag_Union : u32 {
|
||||
OdinDocTypeFlag_Union_polymorphic = 1<<0,
|
||||
OdinDocTypeFlag_Union_no_nil = 1<<1,
|
||||
OdinDocTypeFlag_Union_maybe = 1<<2,
|
||||
OdinDocTypeFlag_Union_shared_nil = 1<<3,
|
||||
};
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ enum EntityFlag : u64 {
|
||||
EntityFlag_CustomLinkage_LinkOnce = 1ull<<44,
|
||||
|
||||
EntityFlag_Require = 1ull<<50,
|
||||
EntityFlag_ByPtr = 1ull<<51, // enforce parameter is passed by pointer
|
||||
|
||||
EntityFlag_Overridden = 1ull<<63,
|
||||
};
|
||||
|
||||
@@ -90,6 +90,10 @@ extern "C" {
|
||||
#error This operating system is not supported
|
||||
#endif
|
||||
|
||||
#if defined(GB_SYSTEM_OPENBSD)
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define GB_COMPILER_MSVC 1
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
+14
-7
@@ -233,7 +233,7 @@ i64 lb_sizeof(LLVMTypeRef type) {
|
||||
i64 elem_size = lb_sizeof(elem);
|
||||
i64 count = LLVMGetVectorSize(type);
|
||||
i64 size = count * elem_size;
|
||||
return gb_clamp(next_pow2(size), 1, build_context.max_align);
|
||||
return next_pow2(size);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -801,16 +801,23 @@ namespace lbAbiAmd64SysV {
|
||||
i64 elem_sz = lb_sizeof(elem);
|
||||
LLVMTypeKind elem_kind = LLVMGetTypeKind(elem);
|
||||
RegClass reg = RegClass_NoClass;
|
||||
unsigned elem_width = LLVMGetIntTypeWidth(elem);
|
||||
switch (elem_kind) {
|
||||
case LLVMIntegerTypeKind:
|
||||
case LLVMHalfTypeKind:
|
||||
switch (LLVMGetIntTypeWidth(elem)) {
|
||||
case 8: reg = RegClass_SSEInt8;
|
||||
case 16: reg = RegClass_SSEInt16;
|
||||
case 32: reg = RegClass_SSEInt32;
|
||||
case 64: reg = RegClass_SSEInt64;
|
||||
switch (elem_width) {
|
||||
case 8: reg = RegClass_SSEInt8; break;
|
||||
case 16: reg = RegClass_SSEInt16; break;
|
||||
case 32: reg = RegClass_SSEInt32; break;
|
||||
case 64: reg = RegClass_SSEInt64; break;
|
||||
default:
|
||||
GB_PANIC("Unhandled integer width for vector type");
|
||||
if (elem_width > 64) {
|
||||
for (i64 i = 0; i < len; i++) {
|
||||
classify_with(elem, cls, ix, off + i*elem_sz);
|
||||
}
|
||||
break;
|
||||
}
|
||||
GB_PANIC("Unhandled integer width for vector type %u", elem_width);
|
||||
}
|
||||
break;
|
||||
case LLVMFloatTypeKind:
|
||||
|
||||
@@ -292,6 +292,9 @@ struct lbProcedure {
|
||||
LLVMMetadataRef debug_info;
|
||||
|
||||
lbCopyElisionHint copy_elision_hint;
|
||||
|
||||
PtrMap<Ast *, lbValue> selector_values;
|
||||
PtrMap<Ast *, lbAddr> selector_addr;
|
||||
};
|
||||
|
||||
|
||||
@@ -479,7 +482,11 @@ LLVMValueRef llvm_basic_shuffle(lbProcedure *p, LLVMValueRef vector, LLVMValueRe
|
||||
|
||||
void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
|
||||
void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
|
||||
LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile);
|
||||
|
||||
i64 lb_max_zero_init_size(void) {
|
||||
return cast(i64)(4*build_context.word_size);
|
||||
}
|
||||
|
||||
#define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
|
||||
#define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info"
|
||||
|
||||
+10
-12
@@ -1025,7 +1025,10 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
|
||||
u64 bits = 0;
|
||||
BigInt bits = {};
|
||||
BigInt one = {};
|
||||
big_int_from_u64(&one, 1);
|
||||
|
||||
for_array(i, cl->elems) {
|
||||
Ast *e = cl->elems[i];
|
||||
GB_ASSERT(e->kind != Ast_FieldValue);
|
||||
@@ -1037,18 +1040,13 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
|
||||
GB_ASSERT(tav.value.kind == ExactValue_Integer);
|
||||
i64 v = big_int_to_i64(&tav.value.value_integer);
|
||||
i64 lower = type->BitSet.lower;
|
||||
bits |= 1ull<<cast(u64)(v-lower);
|
||||
u64 index = cast(u64)(v-lower);
|
||||
BigInt bit = {};
|
||||
big_int_from_u64(&bit, index);
|
||||
big_int_shl(&bit, &one, &bit);
|
||||
big_int_or(&bits, &bits, &bit);
|
||||
}
|
||||
if (is_type_different_to_arch_endianness(type)) {
|
||||
i64 size = type_size_of(type);
|
||||
switch (size) {
|
||||
case 2: bits = cast(u64)gb_endian_swap16(cast(u16)bits); break;
|
||||
case 4: bits = cast(u64)gb_endian_swap32(cast(u32)bits); break;
|
||||
case 8: bits = cast(u64)gb_endian_swap64(cast(u64)bits); break;
|
||||
}
|
||||
}
|
||||
|
||||
res.value = LLVMConstInt(lb_type(m, original_type), bits, false);
|
||||
res.value = lb_big_int_to_llvm(m, original_type, &bits);
|
||||
return res;
|
||||
} else if (is_type_matrix(type)) {
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
|
||||
@@ -43,6 +43,10 @@ LLVMMetadataRef lb_debug_location_from_ast(lbProcedure *p, Ast *node) {
|
||||
GB_ASSERT(node != nullptr);
|
||||
return lb_debug_location_from_token_pos(p, ast_token(node).pos);
|
||||
}
|
||||
LLVMMetadataRef lb_debug_end_location_from_ast(lbProcedure *p, Ast *node) {
|
||||
GB_ASSERT(node != nullptr);
|
||||
return lb_debug_location_from_token_pos(p, ast_end_token(node).pos);
|
||||
}
|
||||
|
||||
LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) {
|
||||
i64 size = type_size_of(type); // Check size
|
||||
@@ -969,7 +973,7 @@ void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T
|
||||
);
|
||||
|
||||
LLVMValueRef storage = ptr;
|
||||
LLVMBasicBlockRef block = p->decl_block->block;
|
||||
LLVMBasicBlockRef block = p->curr_block->block;
|
||||
LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos);
|
||||
LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0);
|
||||
lb_set_llvm_metadata(m, ptr, llvm_expr);
|
||||
|
||||
+81
-29
@@ -1,3 +1,4 @@
|
||||
lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise=false);
|
||||
|
||||
lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type) {
|
||||
lbModule *m = p->module;
|
||||
@@ -265,6 +266,11 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type)
|
||||
} else {
|
||||
res.value = LLVMBuildNeg(p->builder, x.value, "");
|
||||
}
|
||||
} else if (is_type_matrix(x.type)) {
|
||||
lbValue zero = {};
|
||||
zero.value = LLVMConstNull(lb_type(p->module, type));
|
||||
zero.type = type;
|
||||
return lb_emit_arith_matrix(p, Token_Sub, zero, x, type, true);
|
||||
} else {
|
||||
GB_PANIC("Unhandled type %s", type_to_string(x.type));
|
||||
}
|
||||
@@ -976,7 +982,7 @@ lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type
|
||||
|
||||
|
||||
|
||||
lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise=false) {
|
||||
lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise) {
|
||||
GB_ASSERT(is_type_matrix(lhs.type) || is_type_matrix(rhs.type));
|
||||
|
||||
|
||||
@@ -1425,10 +1431,13 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
|
||||
|
||||
Type *it = bit_set_to_int(rt);
|
||||
left = lb_emit_conv(p, left, it);
|
||||
if (is_type_different_to_arch_endianness(it)) {
|
||||
left = lb_emit_byte_swap(p, left, integer_endian_type_to_platform_type(it));
|
||||
}
|
||||
|
||||
lbValue lower = lb_const_value(p->module, it, exact_value_i64(rt->BitSet.lower));
|
||||
lbValue key = lb_emit_arith(p, Token_Sub, left, lower, it);
|
||||
lbValue bit = lb_emit_arith(p, Token_Shl, lb_const_int(p->module, it, 1), key, it);
|
||||
lbValue lower = lb_const_value(p->module, left.type, exact_value_i64(rt->BitSet.lower));
|
||||
lbValue key = lb_emit_arith(p, Token_Sub, left, lower, left.type);
|
||||
lbValue bit = lb_emit_arith(p, Token_Shl, lb_const_int(p->module, left.type, 1), key, left.type);
|
||||
bit = lb_emit_conv(p, bit, it);
|
||||
|
||||
lbValue old_value = lb_emit_transmute(p, right, it);
|
||||
@@ -2993,9 +3002,8 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
|
||||
return lb_build_addr_ptr(p, ue->expr);
|
||||
}
|
||||
|
||||
lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr);
|
||||
lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
u16 prev_state_flags = p->state_flags;
|
||||
defer (p->state_flags = prev_state_flags);
|
||||
|
||||
@@ -3022,6 +3030,38 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
p->state_flags = out;
|
||||
}
|
||||
|
||||
|
||||
// IMPORTANT NOTE(bill):
|
||||
// Selector Call Expressions (foo->bar(...))
|
||||
// must only evaluate `foo` once as it gets transformed into
|
||||
// `foo.bar(foo, ...)`
|
||||
// And if `foo` is a procedure call or something more complex, storing the value
|
||||
// once is a very good idea
|
||||
// If a stored value is found, it must be removed from the cache
|
||||
if (expr->state_flags & StateFlag_SelectorCallExpr) {
|
||||
lbValue *pp = map_get(&p->selector_values, expr);
|
||||
if (pp != nullptr) {
|
||||
lbValue res = *pp;
|
||||
map_remove(&p->selector_values, expr);
|
||||
return res;
|
||||
}
|
||||
lbAddr *pa = map_get(&p->selector_addr, expr);
|
||||
if (pa != nullptr) {
|
||||
lbAddr res = *pa;
|
||||
map_remove(&p->selector_addr, expr);
|
||||
return lb_addr_load(p, res);
|
||||
}
|
||||
}
|
||||
lbValue res = lb_build_expr_internal(p, expr);
|
||||
if (expr->state_flags & StateFlag_SelectorCallExpr) {
|
||||
map_set(&p->selector_values, expr, res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
expr = unparen_expr(expr);
|
||||
|
||||
TokenPos expr_pos = ast_token(expr).pos;
|
||||
@@ -3040,17 +3080,6 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
return lb_const_value(p->module, type, tv.value);
|
||||
}
|
||||
|
||||
#if 0
|
||||
LLVMMetadataRef prev_debug_location = nullptr;
|
||||
if (p->debug_info != nullptr) {
|
||||
prev_debug_location = LLVMGetCurrentDebugLocation2(p->builder);
|
||||
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, expr));
|
||||
}
|
||||
defer (if (prev_debug_location != nullptr) {
|
||||
LLVMSetCurrentDebugLocation2(p->builder, prev_debug_location);
|
||||
});
|
||||
#endif
|
||||
|
||||
switch (expr->kind) {
|
||||
case_ast_node(bl, BasicLit, expr);
|
||||
TokenPos pos = bl->token.pos;
|
||||
@@ -3119,14 +3148,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
|
||||
case_ast_node(se, SelectorCallExpr, expr);
|
||||
GB_ASSERT(se->modified_call);
|
||||
TypeAndValue tav = type_and_value_of_expr(expr);
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
lbValue res = lb_build_call_expr(p, se->call);
|
||||
|
||||
ast_node(ce, CallExpr, se->call);
|
||||
ce->sce_temp_data = gb_alloc_copy(permanent_allocator(), &res, gb_size_of(res));
|
||||
|
||||
return res;
|
||||
return lb_build_call_expr(p, se->call);
|
||||
case_end;
|
||||
|
||||
case_ast_node(te, TernaryIfExpr, expr);
|
||||
@@ -3142,19 +3164,27 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
lb_start_block(p, then);
|
||||
|
||||
Type *type = default_type(type_of_expr(expr));
|
||||
LLVMTypeRef llvm_type = lb_type(p->module, type);
|
||||
|
||||
incoming_values[0] = lb_emit_conv(p, lb_build_expr(p, te->x), type).value;
|
||||
if (is_type_internally_pointer_like(type)) {
|
||||
incoming_values[0] = LLVMBuildBitCast(p->builder, incoming_values[0], llvm_type, "");
|
||||
}
|
||||
|
||||
lb_emit_jump(p, done);
|
||||
lb_start_block(p, else_);
|
||||
|
||||
incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, te->y), type).value;
|
||||
|
||||
if (is_type_internally_pointer_like(type)) {
|
||||
incoming_values[1] = LLVMBuildBitCast(p->builder, incoming_values[1], llvm_type, "");
|
||||
}
|
||||
|
||||
lb_emit_jump(p, done);
|
||||
lb_start_block(p, done);
|
||||
|
||||
lbValue res = {};
|
||||
res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), "");
|
||||
res.value = LLVMBuildPhi(p->builder, llvm_type, "");
|
||||
res.type = type;
|
||||
|
||||
GB_ASSERT(p->curr_block->preds.count >= 2);
|
||||
@@ -3412,9 +3442,34 @@ lbAddr lb_build_array_swizzle_addr(lbProcedure *p, AstCallExpr *ce, TypeAndValue
|
||||
}
|
||||
|
||||
|
||||
lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr);
|
||||
lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
|
||||
expr = unparen_expr(expr);
|
||||
|
||||
// IMPORTANT NOTE(bill):
|
||||
// Selector Call Expressions (foo->bar(...))
|
||||
// must only evaluate `foo` once as it gets transformed into
|
||||
// `foo.bar(foo, ...)`
|
||||
// And if `foo` is a procedure call or something more complex, storing the value
|
||||
// once is a very good idea
|
||||
// If a stored value is found, it must be removed from the cache
|
||||
if (expr->state_flags & StateFlag_SelectorCallExpr) {
|
||||
lbAddr *pp = map_get(&p->selector_addr, expr);
|
||||
if (pp != nullptr) {
|
||||
lbAddr res = *pp;
|
||||
map_remove(&p->selector_addr, expr);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
lbAddr addr = lb_build_addr_internal(p, expr);
|
||||
if (expr->state_flags & StateFlag_SelectorCallExpr) {
|
||||
map_set(&p->selector_addr, expr, addr);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
|
||||
switch (expr->kind) {
|
||||
case_ast_node(i, Implicit, expr);
|
||||
lbAddr v = {};
|
||||
@@ -3556,9 +3611,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
|
||||
case_end;
|
||||
|
||||
case_ast_node(se, SelectorCallExpr, expr);
|
||||
GB_ASSERT(se->modified_call);
|
||||
TypeAndValue tav = type_and_value_of_expr(expr);
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
lbValue e = lb_build_expr(p, expr);
|
||||
return lb_addr(lb_address_from_load_or_generate_local(p, e));
|
||||
case_end;
|
||||
|
||||
@@ -855,7 +855,11 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
|
||||
|
||||
if (LLVMIsNull(value.value)) {
|
||||
LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value));
|
||||
LLVMBuildStore(p->builder, LLVMConstNull(src_t), ptr.value);
|
||||
if (lb_sizeof(src_t) <= lb_max_zero_init_size()) {
|
||||
LLVMBuildStore(p->builder, LLVMConstNull(src_t), ptr.value);
|
||||
} else {
|
||||
lb_mem_zero_ptr(p, ptr.value, a, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (is_type_boolean(a)) {
|
||||
@@ -1958,11 +1962,12 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
|
||||
if (e->flags & EntityFlag_CVarArg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Type *e_type = reduce_tuple_to_single_type(e->type);
|
||||
|
||||
LLVMTypeRef param_type = nullptr;
|
||||
if (is_type_boolean(e_type) &&
|
||||
if (e->flags & EntityFlag_ByPtr) {
|
||||
param_type = lb_type(m, alloc_type_pointer(e_type));
|
||||
} else if (is_type_boolean(e_type) &&
|
||||
type_size_of(e_type) <= 1) {
|
||||
param_type = LLVMInt1TypeInContext(m->ctx);
|
||||
} else {
|
||||
@@ -2369,6 +2374,9 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) {
|
||||
LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name);
|
||||
LLVMSetInitializer(global_data, data);
|
||||
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
|
||||
LLVMSetAlignment(global_data, 1);
|
||||
LLVMSetGlobalConstant(global_data, true);
|
||||
|
||||
LLVMValueRef ptr = LLVMConstInBoundsGEP(global_data, indices, 2);
|
||||
string_map_set(&m->const_strings, key, ptr);
|
||||
@@ -2411,6 +2419,9 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
|
||||
LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name);
|
||||
LLVMSetInitializer(global_data, data);
|
||||
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
|
||||
LLVMSetAlignment(global_data, 1);
|
||||
LLVMSetGlobalConstant(global_data, true);
|
||||
|
||||
LLVMValueRef ptr = nullptr;
|
||||
if (str.len != 0) {
|
||||
@@ -2647,6 +2658,7 @@ lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String
|
||||
g.type = alloc_type_pointer(t);
|
||||
LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, t)));
|
||||
LLVMSetLinkage(g.value, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddress(g.value, LLVMGlobalUnnamedAddr);
|
||||
string_map_set(&m->members, s, g);
|
||||
return g;
|
||||
}
|
||||
@@ -2729,20 +2741,18 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 p
|
||||
if (!zero_init && !force_no_init) {
|
||||
// If there is any padding of any kind, just zero init regardless of zero_init parameter
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(llvm_type);
|
||||
if (kind == LLVMArrayTypeKind) {
|
||||
kind = LLVMGetTypeKind(lb_type(p->module, core_array_type(type)));
|
||||
}
|
||||
|
||||
if (kind == LLVMStructTypeKind) {
|
||||
i64 sz = type_size_of(type);
|
||||
if (type_size_of_struct_pretend_is_packed(type) != sz) {
|
||||
zero_init = true;
|
||||
}
|
||||
} else if (kind == LLVMArrayTypeKind) {
|
||||
zero_init = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (zero_init) {
|
||||
lb_mem_zero_ptr(p, ptr, type, alignment);
|
||||
}
|
||||
|
||||
lbValue val = {};
|
||||
val.value = ptr;
|
||||
val.type = alloc_type_pointer(type);
|
||||
@@ -2752,6 +2762,10 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 p
|
||||
lb_add_debug_local_variable(p, ptr, type, e->token);
|
||||
}
|
||||
|
||||
if (zero_init) {
|
||||
lb_mem_zero_ptr(p, ptr, type, alignment);
|
||||
}
|
||||
|
||||
return lb_addr(val);
|
||||
}
|
||||
|
||||
|
||||
+43
-18
@@ -113,6 +113,8 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
|
||||
p->branch_blocks.allocator = a;
|
||||
p->context_stack.allocator = a;
|
||||
p->scope_stack.allocator = a;
|
||||
map_init(&p->selector_values, a, 0);
|
||||
map_init(&p->selector_addr, a, 0);
|
||||
|
||||
if (p->is_foreign) {
|
||||
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
|
||||
@@ -433,6 +435,40 @@ void lb_start_block(lbProcedure *p, lbBlock *b) {
|
||||
p->curr_block = b;
|
||||
}
|
||||
|
||||
void lb_set_debug_position_to_procedure_begin(lbProcedure *p) {
|
||||
if (p->debug_info == nullptr) {
|
||||
return;
|
||||
}
|
||||
TokenPos pos = {};
|
||||
if (p->body != nullptr) {
|
||||
pos = ast_token(p->body).pos;
|
||||
} else if (p->type_expr != nullptr) {
|
||||
pos = ast_token(p->type_expr).pos;
|
||||
} else if (p->entity != nullptr) {
|
||||
pos = p->entity->token.pos;
|
||||
}
|
||||
if (pos.file_id != 0) {
|
||||
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_token_pos(p, pos));
|
||||
}
|
||||
}
|
||||
|
||||
void lb_set_debug_position_to_procedure_end(lbProcedure *p) {
|
||||
if (p->debug_info == nullptr) {
|
||||
return;
|
||||
}
|
||||
TokenPos pos = {};
|
||||
if (p->body != nullptr) {
|
||||
pos = ast_end_token(p->body).pos;
|
||||
} else if (p->type_expr != nullptr) {
|
||||
pos = ast_end_token(p->type_expr).pos;
|
||||
} else if (p->entity != nullptr) {
|
||||
pos = p->entity->token.pos;
|
||||
}
|
||||
if (pos.file_id != 0) {
|
||||
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_token_pos(p, pos));
|
||||
}
|
||||
}
|
||||
|
||||
void lb_begin_procedure_body(lbProcedure *p) {
|
||||
DeclInfo *decl = decl_info_of_entity(p->entity);
|
||||
if (decl != nullptr) {
|
||||
@@ -564,29 +600,21 @@ void lb_begin_procedure_body(lbProcedure *p) {
|
||||
lb_push_context_onto_stack_from_implicit_parameter(p);
|
||||
}
|
||||
|
||||
lb_start_block(p, p->entry_block);
|
||||
|
||||
lb_set_debug_position_to_procedure_begin(p);
|
||||
if (p->debug_info != nullptr) {
|
||||
TokenPos pos = {};
|
||||
if (p->body != nullptr) {
|
||||
pos = ast_token(p->body).pos;
|
||||
} else if (p->type_expr != nullptr) {
|
||||
pos = ast_token(p->type_expr).pos;
|
||||
} else if (p->entity != nullptr) {
|
||||
pos = p->entity->token.pos;
|
||||
}
|
||||
if (pos.file_id != 0) {
|
||||
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_token_pos(p, pos));
|
||||
}
|
||||
|
||||
if (p->context_stack.count != 0) {
|
||||
p->curr_block = p->decl_block;
|
||||
lb_add_debug_context_variable(p, lb_find_or_generate_context_ptr(p));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
lb_start_block(p, p->entry_block);
|
||||
}
|
||||
|
||||
void lb_end_procedure_body(lbProcedure *p) {
|
||||
lb_set_debug_position_to_procedure_begin(p);
|
||||
|
||||
LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block);
|
||||
LLVMBuildBr(p->builder, p->entry_block->block);
|
||||
LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block);
|
||||
@@ -598,6 +626,7 @@ void lb_end_procedure_body(lbProcedure *p) {
|
||||
instr = LLVMGetLastInstruction(p->curr_block->block);
|
||||
if (!lb_is_instr_terminating(instr)) {
|
||||
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
|
||||
lb_set_debug_position_to_procedure_end(p);
|
||||
LLVMBuildRetVoid(p->builder);
|
||||
}
|
||||
}
|
||||
@@ -2832,10 +2861,6 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
|
||||
expr = unparen_expr(expr);
|
||||
ast_node(ce, CallExpr, expr);
|
||||
|
||||
if (ce->sce_temp_data) {
|
||||
return *(lbValue *)ce->sce_temp_data;
|
||||
}
|
||||
|
||||
lbValue res = lb_build_call_expr_internal(p, expr);
|
||||
|
||||
if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures
|
||||
|
||||
+20
-10
@@ -1210,8 +1210,8 @@ void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
|
||||
}
|
||||
|
||||
lb_emit_jump(p, done);
|
||||
lb_close_scope(p, lbDeferExit_Default, done);
|
||||
lb_start_block(p, done);
|
||||
lb_close_scope(p, lbDeferExit_Default, done);
|
||||
}
|
||||
|
||||
void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value) {
|
||||
@@ -1253,7 +1253,6 @@ void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, l
|
||||
ast_node(cc, CaseClause, clause);
|
||||
|
||||
lb_push_target_list(p, label, done, nullptr, nullptr);
|
||||
lb_open_scope(p, body->scope);
|
||||
lb_build_stmt_list(p, cc->stmts);
|
||||
lb_close_scope(p, lbDeferExit_Default, body);
|
||||
lb_pop_target_list(p);
|
||||
@@ -1263,6 +1262,7 @@ void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, l
|
||||
|
||||
void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
lbModule *m = p->module;
|
||||
lb_open_scope(p, ss->scope);
|
||||
|
||||
ast_node(as, AssignStmt, ss->tag);
|
||||
GB_ASSERT(as->lhs.count == 1);
|
||||
@@ -1321,6 +1321,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
for_array(i, body->stmts) {
|
||||
Ast *clause = body->stmts[i];
|
||||
ast_node(cc, CaseClause, clause);
|
||||
lb_open_scope(p, cc->scope);
|
||||
if (cc->list.count == 0) {
|
||||
lb_start_block(p, default_block);
|
||||
lb_store_type_case_implicit(p, clause, parent_value);
|
||||
@@ -1329,6 +1330,9 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
}
|
||||
|
||||
lbBlock *body = lb_create_block(p, "typeswitch.body");
|
||||
if (p->debug_info != nullptr) {
|
||||
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, clause));
|
||||
}
|
||||
Type *case_type = nullptr;
|
||||
for_array(type_index, cc->list) {
|
||||
case_type = type_of_expr(cc->list[type_index]);
|
||||
@@ -1375,6 +1379,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
|
||||
lb_emit_jump(p, done);
|
||||
lb_start_block(p, done);
|
||||
lb_close_scope(p, lbDeferExit_Default, done);
|
||||
}
|
||||
|
||||
|
||||
@@ -1721,6 +1726,9 @@ void lb_build_for_stmt(lbProcedure *p, Ast *node) {
|
||||
ast_node(fs, ForStmt, node);
|
||||
|
||||
lb_open_scope(p, fs->scope); // Open Scope here
|
||||
if (p->debug_info != nullptr) {
|
||||
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, node));
|
||||
}
|
||||
|
||||
if (fs->init != nullptr) {
|
||||
#if 1
|
||||
@@ -1741,11 +1749,14 @@ void lb_build_for_stmt(lbProcedure *p, Ast *node) {
|
||||
post = lb_create_block(p, "for.post");
|
||||
}
|
||||
|
||||
|
||||
lb_emit_jump(p, loop);
|
||||
lb_start_block(p, loop);
|
||||
|
||||
if (loop != body) {
|
||||
// right now the condition (all expressions) will not set it's debug location, so we will do it here
|
||||
if (p->debug_info != nullptr) {
|
||||
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, fs->cond));
|
||||
}
|
||||
lb_build_cond(p, fs->cond, body, done);
|
||||
lb_start_block(p, body);
|
||||
}
|
||||
@@ -1753,10 +1764,12 @@ void lb_build_for_stmt(lbProcedure *p, Ast *node) {
|
||||
lb_push_target_list(p, fs->label, done, post, nullptr);
|
||||
|
||||
lb_build_stmt(p, fs->body);
|
||||
lb_close_scope(p, lbDeferExit_Default, nullptr);
|
||||
|
||||
lb_pop_target_list(p);
|
||||
|
||||
if (p->debug_info != nullptr) {
|
||||
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_end_location_from_ast(p, fs->body));
|
||||
}
|
||||
lb_emit_jump(p, post);
|
||||
|
||||
if (fs->post != nullptr) {
|
||||
@@ -1766,6 +1779,7 @@ void lb_build_for_stmt(lbProcedure *p, Ast *node) {
|
||||
}
|
||||
|
||||
lb_start_block(p, done);
|
||||
lb_close_scope(p, lbDeferExit_Default, nullptr);
|
||||
}
|
||||
|
||||
void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) {
|
||||
@@ -1971,14 +1985,9 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
|
||||
}
|
||||
}
|
||||
|
||||
LLVMMetadataRef prev_debug_location = nullptr;
|
||||
if (p->debug_info != nullptr) {
|
||||
prev_debug_location = LLVMGetCurrentDebugLocation2(p->builder);
|
||||
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, node));
|
||||
}
|
||||
defer (if (prev_debug_location != nullptr) {
|
||||
LLVMSetCurrentDebugLocation2(p->builder, prev_debug_location);
|
||||
});
|
||||
|
||||
u16 prev_state_flags = p->state_flags;
|
||||
defer (p->state_flags = prev_state_flags);
|
||||
@@ -2073,7 +2082,8 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
|
||||
lbAddr lval = {};
|
||||
if (!is_blank_ident(name)) {
|
||||
Entity *e = entity_of_node(name);
|
||||
bool zero_init = true; // Always do it
|
||||
// bool zero_init = true; // Always do it
|
||||
bool zero_init = vd->values.count == 0;
|
||||
lval = lb_add_local(p, e->type, e, zero_init);
|
||||
}
|
||||
array_add(&lvals, lval);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name);
|
||||
|
||||
bool lb_is_type_aggregate(Type *t) {
|
||||
t = base_type(t);
|
||||
switch (t->kind) {
|
||||
@@ -48,18 +50,19 @@ lbValue lb_correct_endianness(lbProcedure *p, lbValue value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
void lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) {
|
||||
LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) {
|
||||
bool is_inlinable = false;
|
||||
|
||||
i64 const_len = 0;
|
||||
if (LLVMIsConstant(len)) {
|
||||
const_len = cast(i64)LLVMConstIntGetSExtValue(len);
|
||||
// TODO(bill): Determine when it is better to do the `*.inline` versions
|
||||
if (const_len <= 4*build_context.word_size) {
|
||||
if (const_len <= lb_max_zero_init_size()) {
|
||||
is_inlinable = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char const *name = "llvm.memset";
|
||||
if (is_inlinable) {
|
||||
name = "llvm.memset.inline";
|
||||
@@ -69,17 +72,29 @@ void lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len
|
||||
lb_type(p->module, t_rawptr),
|
||||
lb_type(p->module, t_int)
|
||||
};
|
||||
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
|
||||
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]));
|
||||
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
|
||||
if (true || is_inlinable) {
|
||||
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
|
||||
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]));
|
||||
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
|
||||
|
||||
LLVMValueRef args[4] = {};
|
||||
args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], "");
|
||||
args[1] = LLVMConstInt(LLVMInt8TypeInContext(p->module->ctx), 0, false);
|
||||
args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, "");
|
||||
args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), is_volatile, false);
|
||||
LLVMValueRef args[4] = {};
|
||||
args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], "");
|
||||
args[1] = LLVMConstInt(LLVMInt8TypeInContext(p->module->ctx), 0, false);
|
||||
args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, "");
|
||||
args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), is_volatile, false);
|
||||
|
||||
return LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
|
||||
} else {
|
||||
LLVMValueRef ip = lb_lookup_runtime_procedure(p->module, str_lit("memset")).value;
|
||||
|
||||
LLVMValueRef args[3] = {};
|
||||
args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], "");
|
||||
args[1] = LLVMConstInt(LLVMInt32TypeInContext(p->module->ctx), 0, false);
|
||||
args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, "");
|
||||
|
||||
return LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
|
||||
}
|
||||
|
||||
LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
|
||||
}
|
||||
|
||||
void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment) {
|
||||
@@ -1842,8 +1857,6 @@ void lb_set_wasm_export_attributes(LLVMValueRef value, String export_name) {
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name);
|
||||
|
||||
|
||||
lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) {
|
||||
lbAddr *found = string_map_get(&p->module->objc_selectors, name);
|
||||
|
||||
+9
-2
@@ -463,8 +463,15 @@ i32 linker_stage(lbGenerator *gen) {
|
||||
// correctly this way since all the other dependencies provided implicitly
|
||||
// by the compiler frontend are still needed and most of the command
|
||||
// line arguments prepared previously are incompatible with ld.
|
||||
link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' ");
|
||||
link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' ");
|
||||
if (build_context.metrics.os == TargetOs_darwin) {
|
||||
link_settings = gb_string_appendc(link_settings, "-Wl,-init,'__odin_entry_point' ");
|
||||
// NOTE(weshardee): __odin_exit_point should also be added, but -fini
|
||||
// does not exist on MacOS
|
||||
} else {
|
||||
link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' ");
|
||||
link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' ");
|
||||
}
|
||||
|
||||
} else if (build_context.metrics.os != TargetOs_openbsd) {
|
||||
// OpenBSD defaults to PIE executable. do not pass -no-pie for it.
|
||||
link_settings = gb_string_appendc(link_settings, "-no-pie ");
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="String">
|
||||
<DisplayString>{text,[len]s8}</DisplayString>
|
||||
<StringView>text,[len]s8</StringView>
|
||||
</Type>
|
||||
<Type Name="Array<*>">
|
||||
<DisplayString>{{ size={count} capacity={capacity} }}</DisplayString>
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
<Size>count</Size>
|
||||
<ValuePointer>data</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="Slice<*>">
|
||||
<DisplayString>{{ size={count} }}</DisplayString>
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
<Size>count</Size>
|
||||
<ValuePointer>data</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="lbProcedure">
|
||||
<DisplayString>Procedure {name}</DisplayString>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
+26
-48
@@ -2324,11 +2324,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
body = convert_stmt_to_body(f, parse_stmt(f));
|
||||
f->curr_proc = curr_proc;
|
||||
|
||||
if (build_context.disallow_do) {
|
||||
syntax_error(body, "'do' has been disallowed");
|
||||
} else if (!ast_on_same_line(type, body)) {
|
||||
syntax_error(body, "The body of a 'do' must be on the same line as the signature");
|
||||
}
|
||||
syntax_error(body, "'do' for procedure bodies is not allowed, prefer {}");
|
||||
|
||||
return ast_proc_lit(f, type, body, tags, where_token, where_clauses);
|
||||
}
|
||||
@@ -2552,21 +2548,15 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
syntax_error(tag, "Invalid union tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
}
|
||||
if (no_nil && maybe) {
|
||||
syntax_error(f->curr_token, "#maybe and #no_nil cannot be applied together");
|
||||
}
|
||||
|
||||
if (no_nil && shared_nil) {
|
||||
syntax_error(f->curr_token, "#shared_nil and #no_nil cannot be applied together");
|
||||
}
|
||||
if (shared_nil && maybe) {
|
||||
syntax_error(f->curr_token, "#maybe and #shared_nil cannot be applied together");
|
||||
}
|
||||
|
||||
|
||||
if (maybe) {
|
||||
union_kind = UnionType_maybe;
|
||||
syntax_error(f->curr_token, "#maybe functionality has now been merged with standard 'union' functionality");
|
||||
} else if (no_nil) {
|
||||
}
|
||||
if (no_nil) {
|
||||
union_kind = UnionType_no_nil;
|
||||
} else if (shared_nil) {
|
||||
union_kind = UnionType_shared_nil;
|
||||
@@ -3554,47 +3544,34 @@ Ast *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_typeid_token) {
|
||||
}
|
||||
|
||||
|
||||
enum FieldPrefixKind : i32 {
|
||||
FieldPrefix_Unknown = -1,
|
||||
FieldPrefix_Invalid = 0,
|
||||
|
||||
FieldPrefix_using, // implies #subtype
|
||||
FieldPrefix_const,
|
||||
FieldPrefix_no_alias,
|
||||
FieldPrefix_c_vararg,
|
||||
FieldPrefix_auto_cast,
|
||||
FieldPrefix_any_int,
|
||||
FieldPrefix_subtype, // does not imply `using` semantics
|
||||
};
|
||||
|
||||
struct ParseFieldPrefixMapping {
|
||||
String name;
|
||||
TokenKind token_kind;
|
||||
FieldPrefixKind prefix;
|
||||
FieldFlag flag;
|
||||
};
|
||||
|
||||
gb_global ParseFieldPrefixMapping parse_field_prefix_mappings[] = {
|
||||
{str_lit("using"), Token_using, FieldPrefix_using, FieldFlag_using},
|
||||
{str_lit("auto_cast"), Token_auto_cast, FieldPrefix_auto_cast, FieldFlag_auto_cast},
|
||||
{str_lit("no_alias"), Token_Hash, FieldPrefix_no_alias, FieldFlag_no_alias},
|
||||
{str_lit("c_vararg"), Token_Hash, FieldPrefix_c_vararg, FieldFlag_c_vararg},
|
||||
{str_lit("const"), Token_Hash, FieldPrefix_const, FieldFlag_const},
|
||||
{str_lit("any_int"), Token_Hash, FieldPrefix_any_int, FieldFlag_any_int},
|
||||
{str_lit("subtype"), Token_Hash, FieldPrefix_subtype, FieldFlag_subtype},
|
||||
{str_lit("using"), Token_using, FieldFlag_using},
|
||||
{str_lit("auto_cast"), Token_auto_cast, FieldFlag_auto_cast},
|
||||
{str_lit("no_alias"), Token_Hash, FieldFlag_no_alias},
|
||||
{str_lit("c_vararg"), Token_Hash, FieldFlag_c_vararg},
|
||||
{str_lit("const"), Token_Hash, FieldFlag_const},
|
||||
{str_lit("any_int"), Token_Hash, FieldFlag_any_int},
|
||||
{str_lit("subtype"), Token_Hash, FieldFlag_subtype},
|
||||
{str_lit("by_ptr"), Token_Hash, FieldFlag_by_ptr},
|
||||
};
|
||||
|
||||
|
||||
FieldPrefixKind is_token_field_prefix(AstFile *f) {
|
||||
FieldFlag is_token_field_prefix(AstFile *f) {
|
||||
switch (f->curr_token.kind) {
|
||||
case Token_EOF:
|
||||
return FieldPrefix_Invalid;
|
||||
return FieldFlag_Invalid;
|
||||
|
||||
case Token_using:
|
||||
return FieldPrefix_using;
|
||||
return FieldFlag_using;
|
||||
|
||||
case Token_auto_cast:
|
||||
return FieldPrefix_auto_cast;
|
||||
return FieldFlag_auto_cast;
|
||||
|
||||
case Token_Hash:
|
||||
advance_token(f);
|
||||
@@ -3604,33 +3581,33 @@ FieldPrefixKind is_token_field_prefix(AstFile *f) {
|
||||
auto const &mapping = parse_field_prefix_mappings[i];
|
||||
if (mapping.token_kind == Token_Hash) {
|
||||
if (f->curr_token.string == mapping.name) {
|
||||
return mapping.prefix;
|
||||
return mapping.flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return FieldPrefix_Unknown;
|
||||
return FieldFlag_Unknown;
|
||||
}
|
||||
return FieldPrefix_Invalid;
|
||||
return FieldFlag_Invalid;
|
||||
}
|
||||
|
||||
u32 parse_field_prefixes(AstFile *f) {
|
||||
i32 counts[gb_count_of(parse_field_prefix_mappings)] = {};
|
||||
|
||||
for (;;) {
|
||||
FieldPrefixKind kind = is_token_field_prefix(f);
|
||||
if (kind == FieldPrefix_Invalid) {
|
||||
FieldFlag flag = is_token_field_prefix(f);
|
||||
if (flag & FieldFlag_Invalid) {
|
||||
break;
|
||||
}
|
||||
if (kind == FieldPrefix_Unknown) {
|
||||
if (flag & FieldFlag_Unknown) {
|
||||
syntax_error(f->curr_token, "Unknown prefix kind '#%.*s'", LIT(f->curr_token.string));
|
||||
advance_token(f);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i32 i = 0; i < gb_count_of(parse_field_prefix_mappings); i++) {
|
||||
if (parse_field_prefix_mappings[i].prefix == kind) {
|
||||
if (parse_field_prefix_mappings[i].flag == flag) {
|
||||
counts[i] += 1;
|
||||
advance_token(f);
|
||||
break;
|
||||
@@ -3896,7 +3873,8 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
|
||||
|
||||
|
||||
while (f->curr_token.kind != follow &&
|
||||
f->curr_token.kind != Token_EOF) {
|
||||
f->curr_token.kind != Token_EOF &&
|
||||
f->curr_token.kind != Token_Semicolon) {
|
||||
CommentGroup *docs = f->lead_comment;
|
||||
u32 set_flags = parse_field_prefixes(f);
|
||||
Token tag = {};
|
||||
@@ -3924,7 +3902,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
|
||||
default_value = parse_expr(f, false);
|
||||
if (!allow_default_parameters) {
|
||||
syntax_error(f->curr_token, "Default parameters are only allowed for procedures");
|
||||
default_value = nullptr;
|
||||
default_value = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-3
@@ -282,6 +282,8 @@ enum StateFlag : u8 {
|
||||
StateFlag_type_assert = 1<<2,
|
||||
StateFlag_no_type_assert = 1<<3,
|
||||
|
||||
StateFlag_SelectorCallExpr = 1<<6,
|
||||
|
||||
StateFlag_BeenHandled = 1<<7,
|
||||
};
|
||||
|
||||
@@ -300,13 +302,18 @@ enum FieldFlag : u32 {
|
||||
FieldFlag_const = 1<<5,
|
||||
FieldFlag_any_int = 1<<6,
|
||||
FieldFlag_subtype = 1<<7,
|
||||
FieldFlag_by_ptr = 1<<8,
|
||||
|
||||
// Internal use by the parser only
|
||||
FieldFlag_Tags = 1<<10,
|
||||
FieldFlag_Results = 1<<16,
|
||||
|
||||
|
||||
FieldFlag_Unknown = 1u<<30,
|
||||
FieldFlag_Invalid = 1u<<31,
|
||||
|
||||
// Parameter List Restrictions
|
||||
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast|FieldFlag_const|FieldFlag_any_int,
|
||||
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast|FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr,
|
||||
FieldFlag_Struct = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags,
|
||||
};
|
||||
|
||||
@@ -332,7 +339,6 @@ char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = {
|
||||
|
||||
enum UnionTypeKind : u8 {
|
||||
UnionType_Normal = 0,
|
||||
UnionType_maybe = 1, // removed
|
||||
UnionType_no_nil = 2,
|
||||
UnionType_shared_nil = 3,
|
||||
};
|
||||
@@ -411,7 +417,7 @@ AST_KIND(_ExprBegin, "", bool) \
|
||||
Token ellipsis; \
|
||||
ProcInlining inlining; \
|
||||
bool optional_ok_one; \
|
||||
void *sce_temp_data; \
|
||||
bool was_selector; \
|
||||
}) \
|
||||
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
|
||||
AST_KIND(EnumFieldValue, "enum field value", struct { \
|
||||
|
||||
@@ -79,8 +79,8 @@ test_leb128 :: proc(t: ^testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
for num_bytes in 1..uint(16) {
|
||||
for _ in 0..RANDOM_TESTS {
|
||||
for num_bytes in 1..=uint(16) {
|
||||
for _ in 0..=RANDOM_TESTS {
|
||||
unsigned, signed := get_random(num_bytes)
|
||||
|
||||
{
|
||||
@@ -109,7 +109,7 @@ test_leb128 :: proc(t: ^testing.T) {
|
||||
get_random :: proc(byte_count: uint) -> (u: u128, i: i128) {
|
||||
assert(byte_count >= 0 && byte_count <= size_of(u128))
|
||||
|
||||
for _ in 1..byte_count {
|
||||
for _ in 1..=byte_count {
|
||||
u <<= 8
|
||||
u |= u128(rand.uint32() & 0xff)
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) {
|
||||
}
|
||||
|
||||
buf: strings.Builder
|
||||
defer strings.destroy_builder(&buf)
|
||||
defer strings.builder_destroy(&buf)
|
||||
|
||||
print(strings.to_writer(&buf), doc)
|
||||
return strings.clone(strings.to_string(buf))
|
||||
|
||||
Vendored
+1
@@ -5,6 +5,7 @@ package odin_gl
|
||||
import "core:os"
|
||||
import "core:fmt"
|
||||
import "core:strings"
|
||||
_ :: fmt
|
||||
|
||||
Shader_Type :: enum i32 {
|
||||
NONE = 0x0000,
|
||||
|
||||
Vendored
+44
@@ -947,6 +947,13 @@ impl_DrawTransformFeedbackStream: proc "c" (mode: u32, id: u32, stream: u32)
|
||||
impl_BeginQueryIndexed: proc "c" (target: u32, index: u32, id: u32)
|
||||
impl_EndQueryIndexed: proc "c" (target: u32, index: u32)
|
||||
impl_GetQueryIndexediv: proc "c" (target: u32, index: u32, pname: u32, params: [^]i32)
|
||||
impl_GetTextureHandleARB: proc "c" (texture: u32) -> u64
|
||||
impl_GetTextureSamplerHandleARB: proc "c" (texture, sampler: u32) -> u64
|
||||
impl_GetImageHandleARB: proc "c" (texture: u32, level: i32, layered: bool, layer: i32, format: u32) -> u64
|
||||
impl_MakeTextureHandleResidentARB: proc "c" (handle: u64)
|
||||
impl_MakeImageHandleResidentARB: proc "c" (handle: u64, access: u32)
|
||||
impl_MakeTextureHandleNonResidentARB:proc "c" (handle: u64)
|
||||
impl_MakeImageHandleNonResidentARB: proc "c" (handle: u64)
|
||||
|
||||
load_4_0 :: proc(set_proc_address: Set_Proc_Address_Type) {
|
||||
set_proc_address(&impl_MinSampleShading, "glMinSampleShading")
|
||||
@@ -995,6 +1002,42 @@ load_4_0 :: proc(set_proc_address: Set_Proc_Address_Type) {
|
||||
set_proc_address(&impl_BeginQueryIndexed, "glBeginQueryIndexed")
|
||||
set_proc_address(&impl_EndQueryIndexed, "glEndQueryIndexed")
|
||||
set_proc_address(&impl_GetQueryIndexediv, "glGetQueryIndexediv")
|
||||
|
||||
// Load ARB (architecture review board, vendor specific) extensions that might be available
|
||||
set_proc_address(&impl_GetTextureHandleARB, "glGetTextureHandleARB")
|
||||
if impl_GetTextureHandleARB == nil {
|
||||
set_proc_address(&impl_GetTextureHandleARB, "glGetTextureHandleNV")
|
||||
}
|
||||
|
||||
set_proc_address(&impl_GetTextureSamplerHandleARB, "glGetTextureSamplerHandleARB")
|
||||
if impl_GetTextureSamplerHandleARB == nil {
|
||||
set_proc_address(&impl_GetTextureSamplerHandleARB, "glGetTextureSamplerHandleNV")
|
||||
}
|
||||
|
||||
set_proc_address(&impl_GetImageHandleARB, "glGetImageHandleARB")
|
||||
if impl_GetImageHandleARB == nil {
|
||||
set_proc_address(&impl_GetImageHandleARB, "glGetImageHandleNV")
|
||||
}
|
||||
|
||||
set_proc_address(&impl_MakeTextureHandleResidentARB, "glMakeTextureHandleResidentARB")
|
||||
if impl_MakeTextureHandleResidentARB == nil {
|
||||
set_proc_address(&impl_MakeTextureHandleResidentARB, "glMakeTextureHandleResidentNV")
|
||||
}
|
||||
|
||||
set_proc_address(&impl_MakeImageHandleResidentARB, "glMakeImageHandleResidentARB")
|
||||
if impl_MakeImageHandleResidentARB == nil {
|
||||
set_proc_address(&impl_MakeImageHandleResidentARB, "glMakeImageHandleResidentNV")
|
||||
}
|
||||
|
||||
set_proc_address(&impl_MakeTextureHandleNonResidentARB, "glMakeTextureHandleNonResidentARB")
|
||||
if impl_MakeTextureHandleNonResidentARB == nil {
|
||||
set_proc_address(&impl_MakeTextureHandleNonResidentARB, "glMakeTextureHandleNonResidentNV")
|
||||
}
|
||||
|
||||
set_proc_address(&impl_MakeImageHandleNonResidentARB, "glMakeImageHandleNonResidentARB")
|
||||
if impl_MakeImageHandleNonResidentARB == nil {
|
||||
set_proc_address(&impl_MakeImageHandleNonResidentARB, "glMakeImageHandleNonResidentNV")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1594,3 +1637,4 @@ load_4_6 :: proc(set_proc_address: Set_Proc_Address_Type) {
|
||||
set_proc_address(&impl_MultiDrawElementsIndirectCount, "glMultiDrawElementsIndirectCount")
|
||||
set_proc_address(&impl_PolygonOffsetClamp, "glPolygonOffsetClamp")
|
||||
}
|
||||
|
||||
|
||||
Vendored
+30
@@ -449,6 +449,20 @@ when !ODIN_DEBUG {
|
||||
BeginQueryIndexed :: proc "c" (target: u32, index: u32, id: u32) { impl_BeginQueryIndexed(target, index, id) }
|
||||
EndQueryIndexed :: proc "c" (target: u32, index: u32) { impl_EndQueryIndexed(target, index) }
|
||||
GetQueryIndexediv :: proc "c" (target: u32, index: u32, pname: u32, params: [^]i32) { impl_GetQueryIndexediv(target, index, pname, params) }
|
||||
GetTextureHandleARB :: proc "c" (texture: u32) -> u64
|
||||
{ return impl_GetTextureHandleARB(texture) }
|
||||
GetTextureSamplerHandleARB :: proc "c" (texture, sampler: u32) -> u64
|
||||
{ return impl_GetTextureSamplerHandleARB(texture, sampler) }
|
||||
GetImageHandleARB :: proc "c" (texture: u32, level: i32, layered: bool, layer: i32, format: u32) -> u64
|
||||
{ return impl_GetImageHandleARB(texture, level, layered, layer, format) }
|
||||
MakeTextureHandleResidentARB :: proc "c" (handle: u64)
|
||||
{ impl_MakeTextureHandleResidentARB(handle) }
|
||||
MakeImageHandleResidentARB :: proc "c" (handle: u64, access: u32)
|
||||
{ impl_MakeImageHandleResidentARB(handle, access) }
|
||||
MakeTextureHandleNonResidentARB:: proc "c" (handle: u64)
|
||||
{ impl_MakeTextureHandleNonResidentARB(handle) }
|
||||
MakeImageHandleNonResidentARB :: proc "c" (handle: u64)
|
||||
{ impl_MakeImageHandleNonResidentARB(handle) }
|
||||
|
||||
// VERSION_4_1
|
||||
ReleaseShaderCompiler :: proc "c" () { impl_ReleaseShaderCompiler() }
|
||||
@@ -1249,6 +1263,22 @@ when !ODIN_DEBUG {
|
||||
BeginQueryIndexed :: proc "c" (target: u32, index: u32, id: u32, loc := #caller_location) { impl_BeginQueryIndexed(target, index, id); debug_helper(loc, 0, target, index, id) }
|
||||
EndQueryIndexed :: proc "c" (target: u32, index: u32, loc := #caller_location) { impl_EndQueryIndexed(target, index); debug_helper(loc, 0, target, index) }
|
||||
GetQueryIndexediv :: proc "c" (target: u32, index: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetQueryIndexediv(target, index, pname, params); debug_helper(loc, 0, target, index, pname, params) }
|
||||
GetTextureHandleARB :: proc "c" (target: u32, loc := #caller_location) -> u64
|
||||
{ ret := impl_GetTextureHandleARB(target); debug_helper(loc, 0, target); return ret }
|
||||
GetTextureSamplerHandleARB :: proc "c" (texture, sampler: u32, loc := #caller_location) -> u64
|
||||
{ ret := impl_GetTextureSamplerHandleARB(texture, sampler); debug_helper(loc, 0, texture, sampler); return ret }
|
||||
GetImageHandleARB :: proc "c" (texture: u32, level: i32, layered: bool, layer: i32, format: u32, loc := #caller_location) -> u64
|
||||
{ ret := impl_GetImageHandleARB(texture, level, layered, layer, format); debug_helper(loc, 0, texture, level, layered, layer, format); return ret }
|
||||
MakeTextureHandleResidentARB :: proc "c" (handle: u64, loc := #caller_location)
|
||||
{ impl_MakeTextureHandleResidentARB(handle); debug_helper(loc, 0, handle) }
|
||||
MakeImageHandleResidentARB :: proc "c" (handle: u64, access: u32, loc := #caller_location)
|
||||
{ impl_MakeImageHandleResidentARB(handle, access); debug_helper(loc, 0, handle, access) }
|
||||
MakeTextureHandleNonResidentARB:: proc "c" (handle: u64, loc := #caller_location)
|
||||
{ impl_MakeTextureHandleNonResidentARB(handle); debug_helper(loc, 0, handle) }
|
||||
MakeImageHandleNonResidentARB :: proc "c" (handle: u64, loc := #caller_location)
|
||||
{ impl_MakeImageHandleNonResidentARB(handle); debug_helper(loc, 0, handle) }
|
||||
|
||||
|
||||
|
||||
// VERSION_4_1
|
||||
ReleaseShaderCompiler :: proc "c" (loc := #caller_location) { impl_ReleaseShaderCompiler(); debug_helper(loc, 0) }
|
||||
|
||||
Vendored
+4
-4
@@ -38,10 +38,10 @@ IUnknown_VTable :: struct {
|
||||
|
||||
@(default_calling_convention="stdcall")
|
||||
foreign dxgi {
|
||||
CreateDXGIFactory :: proc(riid: ^IID, ppFactory: rawptr) -> HRESULT ---
|
||||
CreateDXGIFactory1 :: proc(riid: ^IID, ppFactory: rawptr) -> HRESULT ---
|
||||
CreateDXGIFactory2 :: proc(Flags: u32, riid: ^IID, ppFactory: rawptr) -> HRESULT ---
|
||||
DXGIGetDebugInterface1 :: proc(Flags: u32, riid: ^IID, pDebug: rawptr) -> HRESULT ---
|
||||
CreateDXGIFactory :: proc(riid: ^IID, ppFactory: ^rawptr) -> HRESULT ---
|
||||
CreateDXGIFactory1 :: proc(riid: ^IID, ppFactory: ^rawptr) -> HRESULT ---
|
||||
CreateDXGIFactory2 :: proc(Flags: u32, riid: ^IID, ppFactory: ^rawptr) -> HRESULT ---
|
||||
DXGIGetDebugInterface1 :: proc(Flags: u32, riid: ^IID, pDebug: ^rawptr) -> HRESULT ---
|
||||
}
|
||||
|
||||
STANDARD_MULTISAMPLE_QUALITY_PATTERN :: 0xffffffff
|
||||
|
||||
Vendored
+7
@@ -13,6 +13,13 @@ when ODIN_OS == .Windows {
|
||||
} else when ODIN_OS == .Linux {
|
||||
// TODO: Add the billion-or-so static libs to link to in linux
|
||||
foreign import glfw "system:glfw"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import glfw {
|
||||
"../lib/darwin/libglfw3.a",
|
||||
"system:Cocoa.framework",
|
||||
"system:IOKit.framework",
|
||||
"system:OpenGL.framework",
|
||||
}
|
||||
} else {
|
||||
foreign import glfw "system:glfw"
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -4,7 +4,7 @@ package glfw
|
||||
/* Versions */
|
||||
VERSION_MAJOR :: 3
|
||||
VERSION_MINOR :: 3
|
||||
VERSION_REVISION :: 4
|
||||
VERSION_REVISION :: 8
|
||||
|
||||
/* Booleans */
|
||||
TRUE :: true
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
+1
-1
@@ -353,7 +353,7 @@ end :: proc(ctx: ^Context) {
|
||||
|
||||
/* reset input state */
|
||||
ctx.key_pressed_bits = {} // clear
|
||||
strings.reset_builder(&ctx.text_input)
|
||||
strings.builder_reset(&ctx.text_input)
|
||||
ctx.mouse_pressed_bits = {} // clear
|
||||
ctx.mouse_released_bits = {} // clear
|
||||
ctx.scroll_delta = Vec2{0, 0}
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
+14
-5
@@ -106,11 +106,20 @@ when ODIN_OS == .Windows {
|
||||
"system:pthread",
|
||||
}
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import lib {
|
||||
"macos/libraylib.a",
|
||||
"system:Cocoa.framework",
|
||||
"system:OpenGL.framework",
|
||||
"system:IOKit.framework",
|
||||
when ODIN_ARCH == .arm64 {
|
||||
foreign import lib {
|
||||
"macos-arm64/libraylib.a",
|
||||
"system:Cocoa.framework",
|
||||
"system:OpenGL.framework",
|
||||
"system:IOKit.framework",
|
||||
}
|
||||
} else {
|
||||
foreign import lib {
|
||||
"macos/libraylib.a",
|
||||
"system:Cocoa.framework",
|
||||
"system:OpenGL.framework",
|
||||
"system:IOKit.framework",
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreign import lib "system:raylib"
|
||||
|
||||
+1
-1
@@ -185,4 +185,4 @@ foreign lib {
|
||||
space: colorspace, alloc_context: rawptr,
|
||||
s0, t0, s1, t1: f32) -> c.int ---
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
+2
-2
@@ -10,6 +10,6 @@ The `js_wasm32` target assumes that the WASM output will be ran within a web bro
|
||||
<!-- Copy `vendor:wasm/js/runtime.js` into your web server -->
|
||||
<script type="text/javascript" src="runtime.js"></script>
|
||||
<script type="text/javascript">
|
||||
odin.runWasm(pathToWasm, webglCanvasElement, consolePreElement);
|
||||
odin.runWasm(pathToWasm, consolePreElement);
|
||||
</script>
|
||||
```
|
||||
```
|
||||
|
||||
Vendored
+30
-3
@@ -79,6 +79,8 @@ Event_Kind :: enum u32 {
|
||||
|
||||
Context_Menu,
|
||||
|
||||
Custom,
|
||||
|
||||
}
|
||||
event_kind_string := [Event_Kind]string{
|
||||
.Invalid = "",
|
||||
@@ -155,6 +157,8 @@ event_kind_string := [Event_Kind]string{
|
||||
.Touch_Start = "touchstart",
|
||||
|
||||
.Context_Menu = "contextmenu",
|
||||
|
||||
.Custom = "?custom?",
|
||||
}
|
||||
|
||||
Delta_Mode :: enum u32 {
|
||||
@@ -186,6 +190,13 @@ Event_Phase :: enum u8 {
|
||||
Bubbling_Phase = 3,
|
||||
}
|
||||
|
||||
Event_Option :: enum u8 {
|
||||
Bubbles = 0,
|
||||
Cancelable = 1,
|
||||
Composed = 2,
|
||||
}
|
||||
Event_Options :: distinct bit_set[Event_Option; u8]
|
||||
|
||||
Event :: struct {
|
||||
kind: Event_Kind,
|
||||
target_kind: Event_Target_Kind,
|
||||
@@ -194,9 +205,7 @@ Event :: struct {
|
||||
timestamp: f64,
|
||||
|
||||
phase: Event_Phase,
|
||||
bubbles: bool,
|
||||
cancelable: bool,
|
||||
composed: bool,
|
||||
options: Event_Options,
|
||||
is_composing: bool,
|
||||
is_trusted: bool,
|
||||
|
||||
@@ -255,6 +264,7 @@ foreign dom_lib {
|
||||
event_stop_propagation :: proc() ---
|
||||
event_stop_immediate_propagation :: proc() ---
|
||||
event_prevent_default :: proc() ---
|
||||
dispatch_custom_event :: proc(id: string, name: string, options := Event_Options{}) -> bool ---
|
||||
}
|
||||
|
||||
add_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
|
||||
@@ -301,6 +311,23 @@ remove_event_listener_from_event :: proc(e: Event) -> bool {
|
||||
return remove_event_listener(e.id, e.kind, e.user_data, e.callback)
|
||||
}
|
||||
|
||||
add_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
|
||||
@(default_calling_convention="contextless")
|
||||
foreign dom_lib {
|
||||
@(link_name="add_event_listener")
|
||||
_add_event_listener :: proc(id: string, name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
|
||||
}
|
||||
return _add_event_listener(id, name, .Custom, user_data, callback, use_capture)
|
||||
}
|
||||
remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event)) -> bool {
|
||||
@(default_calling_convention="contextless")
|
||||
foreign dom_lib {
|
||||
@(link_name="remove_event_listener")
|
||||
_remove_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc "odin" (Event)) -> bool ---
|
||||
}
|
||||
return _remove_event_listener(id, name, user_data, callback)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Vendored
+41
-14
@@ -1,6 +1,14 @@
|
||||
"use strict";
|
||||
|
||||
(function() {
|
||||
|
||||
function getElement(name) {
|
||||
if (name) {
|
||||
return document.getElementById(name);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
class WasmMemoryInterface {
|
||||
constructor() {
|
||||
this.memory = null;
|
||||
@@ -204,12 +212,12 @@ class WebGLInterface {
|
||||
return {
|
||||
SetCurrentContextById: (name_ptr, name_len) => {
|
||||
let name = this.mem.loadString(name_ptr, name_len);
|
||||
let element = document.getElementById(name);
|
||||
let element = getElement(name);
|
||||
return this.setCurrentContext(element, {alpha: true, antialias: true, depth: true, premultipliedAlpha: true});
|
||||
},
|
||||
CreateCurrentContextById: (name_ptr, name_len, attributes) => {
|
||||
let name = this.mem.loadString(name_ptr, name_len);
|
||||
let element = document.getElementById(name);
|
||||
let element = getElement(name);
|
||||
|
||||
let contextSettings = {
|
||||
alpha: !(attributes & (1<<0)),
|
||||
@@ -1380,9 +1388,11 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
|
||||
wmi.storeF64(off(8), e.timeStamp*1e-3);
|
||||
|
||||
wmi.storeU8(off(1), e.eventPhase);
|
||||
wmi.storeU8(off(1), !!e.bubbles);
|
||||
wmi.storeU8(off(1), !!e.cancelable);
|
||||
wmi.storeU8(off(1), !!e.composed);
|
||||
let options = 0;
|
||||
if (!!e.bubbles) { options |= 1<<0; }
|
||||
if (!!e.cancelable) { options |= 1<<1; }
|
||||
if (!!e.composed) { options |= 1<<2; }
|
||||
wmi.storeU8(off(1), options);
|
||||
wmi.storeU8(off(1), !!e.isComposing);
|
||||
wmi.storeU8(off(1), !!e.isTrusted);
|
||||
|
||||
@@ -1433,7 +1443,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
|
||||
add_event_listener: (id_ptr, id_len, name_ptr, name_len, name_code, data, callback, use_capture) => {
|
||||
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
|
||||
let name = wasmMemoryInterface.loadString(name_ptr, name_len);
|
||||
let element = document.getElementById(id);
|
||||
let element = getElement(id);
|
||||
if (element == undefined) {
|
||||
return false;
|
||||
}
|
||||
@@ -1454,7 +1464,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
|
||||
remove_event_listener: (id_ptr, id_len, name_ptr, name_len, data, callback) => {
|
||||
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
|
||||
let name = wasmMemoryInterface.loadString(name_ptr, name_len);
|
||||
let element = document.getElementById(id);
|
||||
let element = getElement(id);
|
||||
if (element == undefined) {
|
||||
return false;
|
||||
}
|
||||
@@ -1514,14 +1524,31 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
|
||||
}
|
||||
},
|
||||
|
||||
dispatch_custom_event: (id_ptr, id_len, name_ptr, name_len, options_bits) => {
|
||||
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
|
||||
let name = wasmMemoryInterface.loadString(name_ptr, name_len);
|
||||
let options = {
|
||||
bubbles: (options_bits & (1<<0)) !== 0,
|
||||
cancelabe: (options_bits & (1<<1)) !== 0,
|
||||
composed: (options_bits & (1<<2)) !== 0,
|
||||
};
|
||||
|
||||
let element = getElement(id);
|
||||
if (element) {
|
||||
element.dispatchEvent(new Event(name, options));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
get_element_value_f64: (id_ptr, id_len) => {
|
||||
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
|
||||
let element = document.getElementById(id);
|
||||
let element = getElement(id);
|
||||
return element ? element.value : 0;
|
||||
},
|
||||
get_element_value_string: (id_ptr, id_len, buf_ptr, buf_len) => {
|
||||
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
|
||||
let element = document.getElementById(id);
|
||||
let element = getElement(id);
|
||||
if (element) {
|
||||
let str = element.value;
|
||||
if (buf_len > 0 && buf_ptr) {
|
||||
@@ -1535,7 +1562,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
|
||||
},
|
||||
get_element_value_string_length: (id_ptr, id_len) => {
|
||||
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
|
||||
let element = document.getElementById(id);
|
||||
let element = getElement(id);
|
||||
if (element) {
|
||||
return element.value.length;
|
||||
}
|
||||
@@ -1543,7 +1570,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
|
||||
},
|
||||
get_element_min_max: (ptr_array2_f64, id_ptr, id_len) => {
|
||||
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
|
||||
let element = document.getElementById(id);
|
||||
let element = getElement(id);
|
||||
if (element) {
|
||||
let values = wasmMemoryInterface.loadF64Array(ptr_array2_f64, 2);
|
||||
values[0] = element.min;
|
||||
@@ -1552,7 +1579,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
|
||||
},
|
||||
set_element_value_f64: (id_ptr, id_len, value) => {
|
||||
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
|
||||
let element = document.getElementById(id);
|
||||
let element = getElement(id);
|
||||
if (element) {
|
||||
element.value = value;
|
||||
}
|
||||
@@ -1560,7 +1587,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
|
||||
set_element_value_string: (id_ptr, id_len, value_ptr, value_id) => {
|
||||
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
|
||||
let value = wasmMemoryInterface.loadString(value_ptr, value_len);
|
||||
let element = document.getElementById(id);
|
||||
let element = getElement(id);
|
||||
if (element) {
|
||||
element.value = value;
|
||||
}
|
||||
@@ -1569,7 +1596,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
|
||||
|
||||
get_bounding_client_rect: (rect_ptr, id_ptr, id_len) => {
|
||||
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
|
||||
let element = document.getElementById(id);
|
||||
let element = getElement(id);
|
||||
if (element) {
|
||||
let values = wasmMemoryInterface.loadF64Array(rect_ptr, 4);
|
||||
let rect = element.getBoundingClientRect();
|
||||
|
||||
Reference in New Issue
Block a user