Merge branch 'master' into freestanding_amd64

This commit is contained in:
gingerBill
2022-03-14 11:02:59 +00:00
committed by GitHub
150 changed files with 7091 additions and 3234 deletions
+1
View File
@@ -1,3 +1,4 @@
# These are supported funding model platforms
github: odin-lang
patreon: gingerbill
+15
View File
@@ -38,6 +38,12 @@ jobs:
cd tests/vendor
make
timeout-minutes: 10
- name: Odin check examples/all for Linux i386
run: ./odin check examples/all -vet -strict-style -target:linux_i386
timeout-minutes: 10
- name: Odin check examples/all for OpenBSD amd64
run: ./odin check examples/all -vet -strict-style -target:openbsd_amd64
timeout-minutes: 10
build_macOS:
runs-on: macos-latest
steps:
@@ -78,6 +84,9 @@ jobs:
cd tests/vendor
make
timeout-minutes: 10
- name: Odin check examples/all for Darwin arm64
run: ./odin check examples/all -vet -strict-style -target:darwin_arm64
timeout-minutes: 10
build_windows:
runs-on: windows-2019
steps:
@@ -138,3 +147,9 @@ jobs:
cd tests\core\math\big
call build.bat
timeout-minutes: 10
- name: Odin check examples/all for Windows 32bits
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin check examples/all -strict-style -target:windows_i386
timeout-minutes: 10
+2
View File
@@ -279,3 +279,5 @@ shared/
*.ll
*.sublime-workspace
examples/bug/
build.sh
+17 -3
View File
@@ -1,6 +1,6 @@
GIT_SHA=$(shell git rev-parse --short HEAD)
DISABLED_WARNINGS=-Wno-switch -Wno-macro-redefined -Wno-unused-value
LDFLAGS=-pthread -ldl -lm -lstdc++
LDFLAGS=-pthread -lm -lstdc++
CFLAGS=-std=c++14 -DGIT_SHA=\"$(GIT_SHA)\"
CFLAGS:=$(CFLAGS) -DODIN_VERSION_RAW=\"dev-$(shell date +"%Y-%m")\"
CC=clang
@@ -8,7 +8,7 @@ CC=clang
OS=$(shell uname)
ifeq ($(OS), Darwin)
ARCH=$(shell uname -m)
LLVM_CONFIG=llvm-config
@@ -35,7 +35,7 @@ ifeq ($(OS), Darwin)
endif
endif
LDFLAGS:=$(LDFLAGS) -liconv
LDFLAGS:=$(LDFLAGS) -liconv -ldl
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
LDFLAGS:=$(LDFLAGS) -lLLVM-C
endif
@@ -51,6 +51,20 @@ ifeq ($(OS), Linux)
endif
endif
LDFLAGS:=$(LDFLAGS) -ldl
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
endif
ifeq ($(OS), OpenBSD)
LLVM_CONFIG=/usr/local/bin/llvm-config
LDFLAGS:=$(LDFLAGS) -liconv
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
endif
ifeq ($(OS), FreeBSD)
LLVM_CONFIG=/usr/local/bin/llvm-config11
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
endif
+13
View File
@@ -27,6 +27,19 @@ when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
ERANGE :: 34
}
when ODIN_OS == .OpenBSD {
@(private="file")
@(default_calling_convention="c")
foreign libc {
@(link_name="__errno")
_get_errno :: proc() -> ^int ---
}
EDOM :: 33
EILSEQ :: 84
ERANGE :: 34
}
when ODIN_OS == .Windows {
@(private="file")
@(default_calling_convention="c")
+25
View File
@@ -78,6 +78,31 @@ when ODIN_OS == .Linux {
}
}
when ODIN_OS == .OpenBSD {
fpos_t :: i64
_IOFBF :: 0
_IOLBF :: 1
_IONBF :: 1
BUFSIZ :: 1024
EOF :: int(-1)
FOPEN_MAX :: 20
FILENAME_MAX :: 1024
SEEK_SET :: 0
SEEK_CUR :: 1
SEEK_END :: 2
foreign libc {
stderr: ^FILE
stdin: ^FILE
stdout: ^FILE
}
}
when ODIN_OS == .Darwin {
fpos_t :: distinct i64
+7 -2
View File
@@ -45,7 +45,7 @@ when ODIN_OS == .Windows {
}
}
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin {
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD {
@(default_calling_convention="c")
foreign libc {
// 7.27.2 Time manipulation functions
@@ -63,7 +63,12 @@ when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin {
strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t ---
}
CLOCKS_PER_SEC :: 1000000
when ODIN_OS == .OpenBSD {
CLOCKS_PER_SEC :: 100
} else {
CLOCKS_PER_SEC :: 1000000
}
TIME_UTC :: 1
time_t :: distinct i64
+5
View File
@@ -25,6 +25,11 @@ when ODIN_OS == .Darwin {
wctype_t :: distinct u32
}
when ODIN_OS == .OpenBSD {
wctrans_t :: distinct rawptr
wctype_t :: distinct rawptr
}
@(default_calling_convention="c")
foreign libc {
// 7.30.2.1 Wide character classification functions
+8 -2
View File
@@ -139,7 +139,13 @@ Context_Memory_Input :: struct #packed {
size_packed: i64,
size_unpacked: i64,
}
#assert(size_of(Context_Memory_Input) == 64)
when size_of(rawptr) == 8 {
#assert(size_of(Context_Memory_Input) == 64)
} else {
// e.g. `-target:windows_i386`
#assert(size_of(Context_Memory_Input) == 52)
}
Context_Stream_Input :: struct #packed {
input_data: []u8,
@@ -473,4 +479,4 @@ discard_to_next_byte_lsb_from_stream :: proc(z: ^Context_Stream_Input) {
consume_bits_lsb(z, discard)
}
discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream};
discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream}
+2 -2
View File
@@ -100,7 +100,7 @@ E_GZIP :: compress.GZIP_Error
E_ZLIB :: compress.ZLIB_Error
E_Deflate :: compress.Deflate_Error
GZIP_MAX_PAYLOAD_SIZE :: int(max(u32le))
GZIP_MAX_PAYLOAD_SIZE :: i64(max(u32le))
load :: proc{load_from_slice, load_from_file, load_from_context}
@@ -136,7 +136,7 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp
z.output = buf
if expected_output_size > GZIP_MAX_PAYLOAD_SIZE {
if i64(expected_output_size) > i64(GZIP_MAX_PAYLOAD_SIZE) {
return E_GZIP.Payload_Size_Exceeds_Max_Payload
}
+1 -1
View File
@@ -677,4 +677,4 @@ inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := fals
return inflate_raw(z=&ctx, expected_output_size=expected_output_size)
}
inflate :: proc{inflate_from_context, inflate_from_byte_array};
inflate :: proc{inflate_from_context, inflate_from_byte_array}
+17 -12
View File
@@ -1,6 +1,7 @@
package dynamic_bit_array
import "core:intrinsics"
import "core:mem"
/*
Note that these constants are dependent on the backing being a u64.
@@ -15,15 +16,16 @@ INDEX_MASK :: 63
NUM_BITS :: 64
Bit_Array :: struct {
bits: [dynamic]u64,
bias: int,
max_index: int,
bits: [dynamic]u64,
bias: int,
max_index: int,
free_pointer: bool,
}
Bit_Array_Iterator :: struct {
array: ^Bit_Array,
array: ^Bit_Array,
word_idx: int,
bit_idx: uint,
bit_idx: uint,
}
/*
@@ -186,7 +188,7 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator
/*
A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
*/
create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: Bit_Array, ok: bool) #optional_ok {
create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
context.allocator = allocator
size_in_bits := max_index - min_index
@@ -194,11 +196,11 @@ create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -
legs := size_in_bits >> INDEX_SHIFT
res = Bit_Array{
bias = min_index,
max_index = max_index,
}
return res, resize_if_needed(&res, legs)
res = new(Bit_Array)
res.bias = min_index
res.max_index = max_index
res.free_pointer = true
return res, resize_if_needed(res, legs)
}
/*
@@ -206,7 +208,7 @@ create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -
*/
clear :: proc(ba: ^Bit_Array) {
if ba == nil { return }
ba.bits = {}
mem.zero_slice(ba.bits[:])
}
/*
@@ -215,6 +217,9 @@ clear :: proc(ba: ^Bit_Array) {
destroy :: proc(ba: ^Bit_Array) {
if ba == nil { return }
delete(ba.bits)
if ba.free_pointer { // Only free if this Bit_Array was created using `create`, not when on the stack.
free(ba)
}
}
/*
+7 -6
View File
@@ -21,6 +21,7 @@ package dynamic_bit_array
// returns `false`, `false`, because this Bit Array wasn't created to allow negative indices.
was_set, was_retrieved := get(&bits, -1)
fmt.println(was_set, was_retrieved)
destroy(&bits)
}
-- A Bit Array can optionally allow for negative indices, if the mininum value was given during creation:
@@ -40,13 +41,13 @@ package dynamic_bit_array
using bit_array
bits := create(int(max(Foo)), int(min(Foo)))
defer destroy(&bits)
defer destroy(bits)
fmt.printf("Set(Bar): %v\n", set(&bits, Foo.Bar))
fmt.printf("Get(Bar): %v, %v\n", get(&bits, Foo.Bar))
fmt.printf("Set(Negative_Test): %v\n", set(&bits, Foo.Negative_Test))
fmt.printf("Get(Leaves): %v, %v\n", get(&bits, Foo.Leaves))
fmt.printf("Get(Negative_Test): %v, %v\n", get(&bits, Foo.Negative_Test))
fmt.printf("Set(Bar): %v\n", set(bits, Foo.Bar))
fmt.printf("Get(Bar): %v, %v\n", get(bits, Foo.Bar))
fmt.printf("Set(Negative_Test): %v\n", set(bits, Foo.Negative_Test))
fmt.printf("Get(Leaves): %v, %v\n", get(bits, Foo.Leaves))
fmt.printf("Get(Negative_Test): %v, %v\n", get(bits, Foo.Negative_Test))
fmt.printf("Freed.\n")
}
*/
+1 -1
View File
@@ -1,6 +1,6 @@
package crypto
when ODIN_OS != .Linux {
when ODIN_OS != .Linux && ODIN_OS != .OpenBSD && ODIN_OS != .Windows {
_rand_bytes :: proc (dst: []byte) {
unimplemented("crypto: rand_bytes not supported on this OS")
}
+12
View File
@@ -0,0 +1,12 @@
package crypto
import "core:c"
foreign import libc "system:c"
foreign libc {
arc4random_buf :: proc "c" (buf: rawptr, nbytes: c.size_t) ---
}
_rand_bytes :: proc (dst: []byte) {
arc4random_buf(raw_data(dst), len(dst))
}
+23
View File
@@ -0,0 +1,23 @@
package crypto
import win32 "core:sys/windows"
import "core:os"
import "core:fmt"
_rand_bytes :: proc(dst: []byte) {
ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG))
if ret != os.ERROR_NONE {
switch ret {
case os.ERROR_INVALID_HANDLE:
// The handle to the first parameter is invalid.
// This should not happen here, since we explicitly pass nil to it
panic("crypto: BCryptGenRandom Invalid handle for hAlgorithm")
case os.ERROR_INVALID_PARAMETER:
// One of the parameters was invalid
panic("crypto: BCryptGenRandom Invalid parameter")
case:
// Unknown error
panic(fmt.tprintf("crypto: BCryptGenRandom failed: %d\n", ret))
}
}
}
-1
View File
@@ -14,7 +14,6 @@ package siphash
import "core:crypto"
import "core:crypto/util"
import "core:mem"
/*
High level API
+1 -1
View File
@@ -1,4 +1,4 @@
// +build linux, darwin, freebsd
// +build linux, darwin, freebsd, openbsd
package dynlib
import "core:os"
+27
View File
@@ -0,0 +1,27 @@
/*
Implementation of the LEB128 variable integer encoding as used by DWARF encoding and DEX files, among others.
Author of this Odin package: Jeroen van Rijn
Example:
```odin
import "core:encoding/varint"
import "core:fmt"
main :: proc() {
buf: [varint.LEB128_MAX_BYTES]u8
value := u128(42)
encode_size, encode_err := varint.encode_uleb128(buf[:], value)
assert(encode_size == 1 && encode_err == .None)
fmt.println(buf[:encode_size])
decoded_val, decode_size, decode_err := varint.decode_uleb128(buf[:encode_size])
assert(decoded_val == value && decode_size == encode_size && decode_err == .None)
}
```
*/
package varint
+139
View File
@@ -0,0 +1,139 @@
/*
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
List of contributors:
Jeroen van Rijn: Initial implementation.
*/
// package varint implements variable length integer encoding and decoding using
// the LEB128 format as used by DWARF debug info, Android .dex and other file formats.
package varint
import "core:fmt"
// In theory we should use the bigint package. In practice, varints bigger than this indicate a corrupted file.
// Instead we'll set limits on the values we'll encode/decode
// 18 * 7 bits = 126, which means that a possible 19th byte may at most be `0b0000_0011`.
LEB128_MAX_BYTES :: 19
Error :: enum {
None = 0,
Buffer_Too_Small = 1,
Value_Too_Large = 2,
}
// Decode a slice of bytes encoding an unsigned LEB128 integer into value and number of bytes used.
// Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes.
decode_uleb128 :: proc(buf: []u8) -> (val: u128, size: int, err: Error) {
more := true
for v, i in buf {
size = i + 1
// 18 * 7 bits = 126, which means that a possible 19th byte may at most be 0b0000_0011.
if size > LEB128_MAX_BYTES || size == LEB128_MAX_BYTES && v > 0b0000_0011 {
return 0, 0, .Value_Too_Large
}
val |= u128(v & 0x7f) << uint(i * 7)
if v < 128 {
more = false
break
}
}
// If the buffer runs out before the number ends, return an error.
if more {
return 0, 0, .Buffer_Too_Small
}
return
}
// Decode a slice of bytes encoding a signed LEB128 integer into value and number of bytes used.
// Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes.
decode_ileb128 :: proc(buf: []u8) -> (val: i128, size: int, err: Error) {
shift: uint
if len(buf) == 0 {
return 0, 0, .Buffer_Too_Small
}
for v in buf {
size += 1
// 18 * 7 bits = 126, which including sign means we can have a 19th byte.
if size > LEB128_MAX_BYTES || size == LEB128_MAX_BYTES && v > 0x7f {
return 0, 0, .Value_Too_Large
}
val |= i128(v & 0x7f) << shift
shift += 7
if v < 128 { break }
}
if buf[size - 1] & 0x40 == 0x40 {
val |= max(i128) << shift
}
return
}
// Encode `val` into `buf` as an unsigned LEB128 encoded series of bytes.
// `buf` must be appropriately sized.
encode_uleb128 :: proc(buf: []u8, val: u128) -> (size: int, err: Error) {
val := val
for {
size += 1
if size > len(buf) {
fmt.println(val, buf[:size - 1])
return 0, .Buffer_Too_Small
}
low := val & 0x7f
val >>= 7
if val > 0 {
low |= 0x80 // more bytes to follow
}
buf[size - 1] = u8(low)
if val == 0 { break }
}
return
}
@(private)
SIGN_MASK :: (i128(1) << 121) // sign extend mask
// Encode `val` into `buf` as a signed LEB128 encoded series of bytes.
// `buf` must be appropriately sized.
encode_ileb128 :: proc(buf: []u8, val: i128) -> (size: int, err: Error) {
val := val
more := true
for more {
size += 1
if size > len(buf) {
return 0, .Buffer_Too_Small
}
low := val & 0x7f
val >>= 7
low = (low ~ SIGN_MASK) - SIGN_MASK
if (val == 0 && low & 0x40 != 0x40) || (val == -1 && low & 0x40 == 0x40) {
more = false
} else {
low |= 0x80
}
buf[size - 1] = u8(low)
}
return
}
+22 -6
View File
@@ -605,7 +605,7 @@ fmt_bad_verb :: proc(using fi: ^Info, verb: rune) {
fmt_bool :: proc(using fi: ^Info, b: bool, verb: rune) {
switch verb {
case 't', 'v':
io.write_string(writer, b ? "true" : "false", &fi.n)
fmt_string(fi, b ? "true" : "false", 's')
case:
fmt_bad_verb(fi, verb)
}
@@ -943,11 +943,27 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
fmt_string :: proc(fi: ^Info, s: string, verb: rune) {
switch verb {
case 's', 'v':
io.write_string(fi.writer, s, &fi.n)
if fi.width_set && len(s) < fi.width {
for _ in 0..<fi.width - len(s) {
io.write_byte(fi.writer, ' ', &fi.n)
if fi.width_set {
if fi.width > len(s) {
if fi.minus {
io.write_string(fi.writer, s, &fi.n)
}
for _ in 0..<fi.width - len(s) {
io.write_byte(fi.writer, ' ', &fi.n)
}
if !fi.minus {
io.write_string(fi.writer, s, &fi.n)
}
}
else {
io.write_string(fi.writer, s[:fi.width], &fi.n)
}
}
else
{
io.write_string(fi.writer, s, &fi.n)
}
case 'q': // quoted string
@@ -1058,7 +1074,7 @@ fmt_enum :: proc(fi: ^Info, v: any, verb: rune) {
fmt_arg(fi, any{v.data, runtime.type_info_base(e.base).id}, verb)
case 's', 'v':
if str, ok := enum_value_to_string(v); ok {
io.write_string(fi.writer, str, &fi.n)
fmt_string(fi, str, 's')
} else {
io.write_string(fi.writer, "%!(BAD ENUM VALUE=", &fi.n)
fmt_arg(fi, any{v.data, runtime.type_info_base(e.base).id}, 'i')
+1 -1
View File
@@ -151,7 +151,7 @@ murmur32 :: proc(data: []byte, seed := u32(0)) -> u32 {
k1 ~= u32(tail[2]) << 16
fallthrough
case 2:
k1 ~= u32(tail[2]) << 8
k1 ~= u32(tail[1]) << 8
fallthrough
case 1:
k1 ~= u32(tail[0])
+2
View File
@@ -41,6 +41,8 @@ mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) ---
mem_zero :: proc(ptr: rawptr, len: int) ---
mem_zero_volatile :: proc(ptr: rawptr, len: int) ---
unaligned_load :: proc(src: ^$T) -> T ---
unaligned_store :: proc(dst: ^$T, val: T) -> T ---
fixed_point_mul :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) ---
fixed_point_div :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) ---
+11 -11
View File
@@ -12,22 +12,22 @@ import "core:mem"
import "core:fmt"
_main :: proc() {
do stuff
do stuff
}
main :: proc() {
track: mem.Tracking_Allocator
mem.tracking_allocator_init(&track, context.allocator)
context.allocator = mem.tracking_allocator(&track)
track: mem.Tracking_Allocator
mem.tracking_allocator_init(&track, context.allocator)
context.allocator = mem.tracking_allocator(&track)
_main()
_main()
for _, v in track.allocation_map {
fmt.printf("%v leaked %v bytes", v.location, v.size)
}
for bf in track.bad_free_array {
fmt.printf("%v allocation %p was freed badly", bf.location, bf.memory)
}
for _, leak in track.allocation_map {
fmt.printf("%v leaked %v bytes\n", leak.location, leak.size)
}
for bad_free in track.bad_free_array {
fmt.printf("%v allocation %p was freed badly\n", bad_free.location, bad_free.memory)
}
}
```
*/
+35 -19
View File
@@ -6,25 +6,25 @@ DEFAULT_PAGE_SIZE := uint(4096)
Allocator_Error :: mem.Allocator_Error
reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
return _reserve(size)
}
commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
return _commit(data, size)
}
reserve_and_commit :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
data = reserve(size) or_return
commit(raw_data(data), size) or_return
return
}
decommit :: proc(data: rawptr, size: uint) {
decommit :: proc "contextless" (data: rawptr, size: uint) {
_decommit(data, size)
}
release :: proc(data: rawptr, size: uint) {
release :: proc "contextless" (data: rawptr, size: uint) {
_release(data, size)
}
@@ -36,7 +36,7 @@ Protect_Flag :: enum u32 {
Protect_Flags :: distinct bit_set[Protect_Flag; u32]
Protect_No_Access :: Protect_Flags{}
protect :: proc(data: rawptr, size: uint, flags: Protect_Flags) -> bool {
protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
return _protect(data, size, flags)
}
@@ -82,11 +82,13 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
pmblock := platform_memory_alloc(0, total_size) or_return
pmblock.block.base = ([^]byte)(uintptr(pmblock) + base_offset)
commit(pmblock.block.base, committed) or_return
commit_err := platform_memory_commit(pmblock, uint(base_offset) + committed)
assert(commit_err == nil)
// Should be zeroed
assert(pmblock.block.used == 0)
assert(pmblock.block.prev == nil)
if (do_protection) {
if do_protection {
protect(rawptr(uintptr(pmblock) + protect_offset), page_size, Protect_No_Access)
}
@@ -105,7 +107,7 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
}
alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int) -> (data: []byte, err: Allocator_Error) {
calc_alignment_offset :: proc(block: ^Memory_Block, alignment: uintptr) -> uint {
calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
alignment_offset := uint(0)
ptr := uintptr(block.base[block.used:])
mask := alignment-1
@@ -115,23 +117,37 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int)
return alignment_offset
}
do_commit_if_necessary :: proc(block: ^Memory_Block, size: uint) -> (err: Allocator_Error) {
if block.committed - block.used < size {
pmblock := (^Platform_Memory_Block)(block)
base_offset := uint(uintptr(block) - uintptr(pmblock))
platform_total_commit := base_offset + block.used + size
assert(pmblock.committed <= pmblock.reserved)
assert(pmblock.committed < platform_total_commit)
platform_memory_commit(pmblock, platform_total_commit) or_return
pmblock.committed = platform_total_commit
block.committed = pmblock.committed - base_offset
}
return nil
}
alignment_offset := calc_alignment_offset(block, uintptr(alignment))
size := uint(min_size) + alignment_offset
if block.used + size > block.reserved {
err = .Out_Of_Memory
return
}
ptr := block.base[block.used:]
ptr = ptr[alignment_offset:]
assert(block.committed <= block.reserved)
do_commit_if_necessary(block, size) or_return
data = block.base[block.used+alignment_offset:][:min_size]
block.used += size
assert(block.used <= block.reserved)
return ptr[:min_size], nil
return
}
+5 -5
View File
@@ -58,7 +58,7 @@ madvise :: proc "contextless" (addr: rawptr, length: uint, advice: c.int) -> c.i
}
_reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
MAP_FAILED := rawptr(~uintptr(0))
result := mmap(nil, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
if result == MAP_FAILED {
@@ -67,7 +67,7 @@ _reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
return ([^]byte)(result)[:size], nil
}
_commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
result := mprotect(data, size, PROT_READ|PROT_WRITE)
if result != 0 {
// TODO(bill): Handle error value correctly
@@ -75,14 +75,14 @@ _commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
}
return nil
}
_decommit :: proc(data: rawptr, size: uint) {
_decommit :: proc "contextless" (data: rawptr, size: uint) {
mprotect(data, size, PROT_NONE)
madvise(data, size, MADV_FREE)
}
_release :: proc(data: rawptr, size: uint) {
_release :: proc "contextless" (data: rawptr, size: uint) {
munmap(data, size)
}
_protect :: proc(data: rawptr, size: uint, flags: Protect_Flags) -> bool {
_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
pflags: c.int
pflags = PROT_NONE
if .Read in flags { pflags |= PROT_READ }
+21 -5
View File
@@ -4,12 +4,13 @@ package mem_virtual
import sync "core:sync/sync2"
Platform_Memory_Block :: struct {
block: Memory_Block,
reserved: uint,
block: Memory_Block,
committed: uint,
reserved: uint,
prev, next: ^Platform_Memory_Block,
}
platform_memory_alloc :: proc(to_commit, to_reserve: uint) -> (block: ^Platform_Memory_Block, err: Allocator_Error) {
platform_memory_alloc :: proc "contextless" (to_commit, to_reserve: uint) -> (block: ^Platform_Memory_Block, err: Allocator_Error) {
to_commit, to_reserve := to_commit, to_reserve
to_reserve = max(to_commit, to_reserve)
@@ -20,12 +21,13 @@ platform_memory_alloc :: proc(to_commit, to_reserve: uint) -> (block: ^Platform_
commit(raw_data(data), to_commit)
block = (^Platform_Memory_Block)(raw_data(data))
block.reserved = to_reserve
block.committed = to_commit
block.reserved = to_reserve
return
}
platform_memory_free :: proc(block: ^Platform_Memory_Block) {
platform_memory_free :: proc "contextless" (block: ^Platform_Memory_Block) {
if block != nil {
release(block, block.reserved)
}
@@ -52,3 +54,17 @@ platform_memory_init :: proc() {
global_platform_memory_block_sentinel_set = true
}
}
platform_memory_commit :: proc "contextless" (block: ^Platform_Memory_Block, to_commit: uint) -> (err: Allocator_Error) {
if to_commit < block.committed {
return nil
}
if to_commit > block.reserved {
return .Out_Of_Memory
}
commit(block, to_commit) or_return
block.committed = to_commit
return nil
}
+5 -5
View File
@@ -62,7 +62,7 @@ foreign Kernel32 {
}
_reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
result := VirtualAlloc(nil, size, MEM_RESERVE, PAGE_READWRITE)
if result == nil {
err = .Out_Of_Memory
@@ -72,7 +72,7 @@ _reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
return
}
_commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
result := VirtualAlloc(data, size, MEM_COMMIT, PAGE_READWRITE)
if result == nil {
switch err := GetLastError(); err {
@@ -85,13 +85,13 @@ _commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
}
return nil
}
_decommit :: proc(data: rawptr, size: uint) {
_decommit :: proc "contextless" (data: rawptr, size: uint) {
VirtualFree(data, size, MEM_DECOMMIT)
}
_release :: proc(data: rawptr, size: uint) {
_release :: proc "contextless" (data: rawptr, size: uint) {
VirtualFree(data, 0, MEM_RELEASE)
}
_protect :: proc(data: rawptr, size: uint, flags: Protect_Flags) -> bool {
_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
pflags: u32
pflags = PAGE_NOACCESS
switch flags {
+174 -3
View File
@@ -34,7 +34,7 @@ Node :: struct {
pos: tokenizer.Pos,
end: tokenizer.Pos,
state_flags: Node_State_Flags,
derived: any,
derived: Any_Node,
}
Comment_Group :: struct {
@@ -88,9 +88,11 @@ File :: struct {
Expr :: struct {
using expr_base: Node,
derived_expr: Any_Expr,
}
Stmt :: struct {
using stmt_base: Node,
derived_stmt: Any_Stmt,
}
Decl :: struct {
using decl_base: Stmt,
@@ -541,7 +543,7 @@ unparen_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
return
}
for {
e, ok := val.derived.(Paren_Expr)
e, ok := val.derived.(^Paren_Expr)
if !ok || e.expr == nil {
break
}
@@ -758,4 +760,173 @@ Matrix_Type :: struct {
row_count: ^Expr,
column_count: ^Expr,
elem: ^Expr,
}
}
Any_Node :: union {
^Package,
^File,
^Comment_Group,
^Bad_Expr,
^Ident,
^Implicit,
^Undef,
^Basic_Lit,
^Basic_Directive,
^Ellipsis,
^Proc_Lit,
^Comp_Lit,
^Tag_Expr,
^Unary_Expr,
^Binary_Expr,
^Paren_Expr,
^Selector_Expr,
^Implicit_Selector_Expr,
^Selector_Call_Expr,
^Index_Expr,
^Deref_Expr,
^Slice_Expr,
^Matrix_Index_Expr,
^Call_Expr,
^Field_Value,
^Ternary_If_Expr,
^Ternary_When_Expr,
^Or_Else_Expr,
^Or_Return_Expr,
^Type_Assertion,
^Type_Cast,
^Auto_Cast,
^Inline_Asm_Expr,
^Proc_Group,
^Typeid_Type,
^Helper_Type,
^Distinct_Type,
^Poly_Type,
^Proc_Type,
^Pointer_Type,
^Multi_Pointer_Type,
^Array_Type,
^Dynamic_Array_Type,
^Struct_Type,
^Union_Type,
^Enum_Type,
^Bit_Set_Type,
^Map_Type,
^Relative_Type,
^Matrix_Type,
^Bad_Stmt,
^Empty_Stmt,
^Expr_Stmt,
^Tag_Stmt,
^Assign_Stmt,
^Block_Stmt,
^If_Stmt,
^When_Stmt,
^Return_Stmt,
^Defer_Stmt,
^For_Stmt,
^Range_Stmt,
^Inline_Range_Stmt,
^Case_Clause,
^Switch_Stmt,
^Type_Switch_Stmt,
^Branch_Stmt,
^Using_Stmt,
^Bad_Decl,
^Value_Decl,
^Package_Decl,
^Import_Decl,
^Foreign_Block_Decl,
^Foreign_Import_Decl,
^Attribute,
^Field,
^Field_List,
}
Any_Expr :: union {
^Bad_Expr,
^Ident,
^Implicit,
^Undef,
^Basic_Lit,
^Basic_Directive,
^Ellipsis,
^Proc_Lit,
^Comp_Lit,
^Tag_Expr,
^Unary_Expr,
^Binary_Expr,
^Paren_Expr,
^Selector_Expr,
^Implicit_Selector_Expr,
^Selector_Call_Expr,
^Index_Expr,
^Deref_Expr,
^Slice_Expr,
^Matrix_Index_Expr,
^Call_Expr,
^Field_Value,
^Ternary_If_Expr,
^Ternary_When_Expr,
^Or_Else_Expr,
^Or_Return_Expr,
^Type_Assertion,
^Type_Cast,
^Auto_Cast,
^Inline_Asm_Expr,
^Proc_Group,
^Typeid_Type,
^Helper_Type,
^Distinct_Type,
^Poly_Type,
^Proc_Type,
^Pointer_Type,
^Multi_Pointer_Type,
^Array_Type,
^Dynamic_Array_Type,
^Struct_Type,
^Union_Type,
^Enum_Type,
^Bit_Set_Type,
^Map_Type,
^Relative_Type,
^Matrix_Type,
}
Any_Stmt :: union {
^Bad_Stmt,
^Empty_Stmt,
^Expr_Stmt,
^Tag_Stmt,
^Assign_Stmt,
^Block_Stmt,
^If_Stmt,
^When_Stmt,
^Return_Stmt,
^Defer_Stmt,
^For_Stmt,
^Range_Stmt,
^Inline_Range_Stmt,
^Case_Clause,
^Switch_Stmt,
^Type_Switch_Stmt,
^Branch_Stmt,
^Using_Stmt,
^Bad_Decl,
^Value_Decl,
^Package_Decl,
^Import_Decl,
^Foreign_Block_Decl,
^Foreign_Import_Decl,
}
+117 -83
View File
@@ -1,16 +1,25 @@
package odin_ast
import "core:intrinsics"
import "core:mem"
import "core:fmt"
import "core:reflect"
import "core:odin/tokenizer"
_ :: intrinsics
new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T {
n, _ := mem.new(T)
n.pos = pos
n.end = end
n.derived = n^
n.derived = n
base: ^Node = n // dummy check
_ = base // "Use" type to make -vet happy
when intrinsics.type_has_field(T, "derived_expr") {
n.derived_expr = n
}
when intrinsics.type_has_field(T, "derived_stmt") {
n.derived_stmt = n
}
return n
}
@@ -59,232 +68,257 @@ clone_node :: proc(node: ^Node) -> ^Node {
return nil
}
size := size_of(Node)
size := size_of(Node)
align := align_of(Node)
ti := type_info_of(node.derived.id)
ti := reflect.union_variant_type_info(node.derived)
if ti != nil {
size = ti.size
align = ti.align
elem := ti.variant.(reflect.Type_Info_Pointer).elem
size = elem.size
align = elem.align
}
switch in node.derived {
case Package, File:
#partial switch in node.derived {
case ^Package, ^File:
panic("Cannot clone this node type")
}
res := cast(^Node)mem.alloc(size, align)
src: rawptr = node
if node.derived != nil {
src = node.derived.data
src = (^rawptr)(&node.derived)^
}
mem.copy(res, src, size)
res.derived.data = rawptr(res)
res.derived.id = node.derived.id
res_ptr_any: any
res_ptr_any.data = &res
res_ptr_any.id = ti.id
switch r in &res.derived {
case Bad_Expr:
case Ident:
case Implicit:
case Undef:
case Basic_Lit:
reflect.set_union_value(res.derived, res_ptr_any)
case Ellipsis:
res_ptr := reflect.deref(res_ptr_any)
if de := reflect.struct_field_value_by_name(res_ptr, "derived_expr", true); de != nil {
reflect.set_union_value(de, res_ptr_any)
}
if ds := reflect.struct_field_value_by_name(res_ptr, "derived_stmt", true); ds != nil {
reflect.set_union_value(ds, res_ptr_any)
}
if res.derived != nil do switch r in res.derived {
case ^Package, ^File:
case ^Bad_Expr:
case ^Ident:
case ^Implicit:
case ^Undef:
case ^Basic_Lit:
case ^Basic_Directive:
case ^Comment_Group:
case ^Ellipsis:
r.expr = clone(r.expr)
case Proc_Lit:
case ^Proc_Lit:
r.type = auto_cast clone(r.type)
r.body = clone(r.body)
case Comp_Lit:
case ^Comp_Lit:
r.type = clone(r.type)
r.elems = clone(r.elems)
case Tag_Expr:
case ^Tag_Expr:
r.expr = clone(r.expr)
case Unary_Expr:
case ^Unary_Expr:
r.expr = clone(r.expr)
case Binary_Expr:
case ^Binary_Expr:
r.left = clone(r.left)
r.right = clone(r.right)
case Paren_Expr:
case ^Paren_Expr:
r.expr = clone(r.expr)
case Selector_Expr:
case ^Selector_Expr:
r.expr = clone(r.expr)
r.field = auto_cast clone(r.field)
case Implicit_Selector_Expr:
case ^Implicit_Selector_Expr:
r.field = auto_cast clone(r.field)
case Selector_Call_Expr:
case ^Selector_Call_Expr:
r.expr = clone(r.expr)
r.call = auto_cast clone(r.call)
case Index_Expr:
case ^Index_Expr:
r.expr = clone(r.expr)
r.index = clone(r.index)
case Matrix_Index_Expr:
case ^Matrix_Index_Expr:
r.expr = clone(r.expr)
r.row_index = clone(r.row_index)
r.column_index = clone(r.column_index)
case Deref_Expr:
case ^Deref_Expr:
r.expr = clone(r.expr)
case Slice_Expr:
case ^Slice_Expr:
r.expr = clone(r.expr)
r.low = clone(r.low)
r.high = clone(r.high)
case Call_Expr:
case ^Call_Expr:
r.expr = clone(r.expr)
r.args = clone(r.args)
case Field_Value:
case ^Field_Value:
r.field = clone(r.field)
r.value = clone(r.value)
case Ternary_If_Expr:
case ^Ternary_If_Expr:
r.x = clone(r.x)
r.cond = clone(r.cond)
r.y = clone(r.y)
case Ternary_When_Expr:
case ^Ternary_When_Expr:
r.x = clone(r.x)
r.cond = clone(r.cond)
r.y = clone(r.y)
case Or_Else_Expr:
case ^Or_Else_Expr:
r.x = clone(r.x)
r.y = clone(r.y)
case Or_Return_Expr:
case ^Or_Return_Expr:
r.expr = clone(r.expr)
case Type_Assertion:
case ^Type_Assertion:
r.expr = clone(r.expr)
r.type = clone(r.type)
case Type_Cast:
case ^Type_Cast:
r.type = clone(r.type)
r.expr = clone(r.expr)
case Auto_Cast:
case ^Auto_Cast:
r.expr = clone(r.expr)
case Inline_Asm_Expr:
case ^Inline_Asm_Expr:
r.param_types = clone(r.param_types)
r.return_type = clone(r.return_type)
r.constraints_string = clone(r.constraints_string)
r.asm_string = clone(r.asm_string)
case Bad_Stmt:
case ^Bad_Stmt:
// empty
case Empty_Stmt:
case ^Empty_Stmt:
// empty
case Expr_Stmt:
case ^Expr_Stmt:
r.expr = clone(r.expr)
case Tag_Stmt:
case ^Tag_Stmt:
r.stmt = clone(r.stmt)
case Assign_Stmt:
case ^Assign_Stmt:
r.lhs = clone(r.lhs)
r.rhs = clone(r.rhs)
case Block_Stmt:
case ^Block_Stmt:
r.label = clone(r.label)
r.stmts = clone(r.stmts)
case If_Stmt:
case ^If_Stmt:
r.label = clone(r.label)
r.init = clone(r.init)
r.cond = clone(r.cond)
r.body = clone(r.body)
r.else_stmt = clone(r.else_stmt)
case When_Stmt:
case ^When_Stmt:
r.cond = clone(r.cond)
r.body = clone(r.body)
r.else_stmt = clone(r.else_stmt)
case Return_Stmt:
case ^Return_Stmt:
r.results = clone(r.results)
case Defer_Stmt:
case ^Defer_Stmt:
r.stmt = clone(r.stmt)
case For_Stmt:
case ^For_Stmt:
r.label = clone(r.label)
r.init = clone(r.init)
r.cond = clone(r.cond)
r.post = clone(r.post)
r.body = clone(r.body)
case Range_Stmt:
case ^Range_Stmt:
r.label = clone(r.label)
r.vals = clone(r.vals)
r.expr = clone(r.expr)
r.body = clone(r.body)
case Case_Clause:
case ^Inline_Range_Stmt:
r.label = clone(r.label)
r.val0 = clone(r.val0)
r.val1 = clone(r.val1)
r.expr = clone(r.expr)
r.body = clone(r.body)
case ^Case_Clause:
r.list = clone(r.list)
r.body = clone(r.body)
case Switch_Stmt:
case ^Switch_Stmt:
r.label = clone(r.label)
r.init = clone(r.init)
r.cond = clone(r.cond)
r.body = clone(r.body)
case Type_Switch_Stmt:
case ^Type_Switch_Stmt:
r.label = clone(r.label)
r.tag = clone(r.tag)
r.expr = clone(r.expr)
r.body = clone(r.body)
case Branch_Stmt:
case ^Branch_Stmt:
r.label = auto_cast clone(r.label)
case Using_Stmt:
case ^Using_Stmt:
r.list = clone(r.list)
case Bad_Decl:
case Value_Decl:
case ^Bad_Decl:
case ^Value_Decl:
r.attributes = clone(r.attributes)
r.names = clone(r.names)
r.type = clone(r.type)
r.values = clone(r.values)
case Package_Decl:
case Import_Decl:
case Foreign_Block_Decl:
case ^Package_Decl:
case ^Import_Decl:
case ^Foreign_Block_Decl:
r.attributes = clone(r.attributes)
r.foreign_library = clone(r.foreign_library)
r.body = clone(r.body)
case Foreign_Import_Decl:
case ^Foreign_Import_Decl:
r.name = auto_cast clone(r.name)
case Proc_Group:
case ^Proc_Group:
r.args = clone(r.args)
case Attribute:
case ^Attribute:
r.elems = clone(r.elems)
case Field:
case ^Field:
r.names = clone(r.names)
r.type = clone(r.type)
r.default_value = clone(r.default_value)
case Field_List:
case ^Field_List:
r.list = clone(r.list)
case Typeid_Type:
case ^Typeid_Type:
r.specialization = clone(r.specialization)
case Helper_Type:
case ^Helper_Type:
r.type = clone(r.type)
case Distinct_Type:
case ^Distinct_Type:
r.type = clone(r.type)
case Poly_Type:
case ^Poly_Type:
r.type = auto_cast clone(r.type)
r.specialization = clone(r.specialization)
case Proc_Type:
case ^Proc_Type:
r.params = auto_cast clone(r.params)
r.results = auto_cast clone(r.results)
case Pointer_Type:
case ^Pointer_Type:
r.elem = clone(r.elem)
case Multi_Pointer_Type:
case ^Multi_Pointer_Type:
r.elem = clone(r.elem)
case Array_Type:
case ^Array_Type:
r.len = clone(r.len)
r.elem = clone(r.elem)
case Dynamic_Array_Type:
case ^Dynamic_Array_Type:
r.elem = clone(r.elem)
case Struct_Type:
case ^Struct_Type:
r.poly_params = auto_cast clone(r.poly_params)
r.align = clone(r.align)
r.fields = auto_cast clone(r.fields)
case Union_Type:
case ^Union_Type:
r.poly_params = auto_cast clone(r.poly_params)
r.align = clone(r.align)
r.variants = clone(r.variants)
case Enum_Type:
case ^Enum_Type:
r.base_type = clone(r.base_type)
r.fields = clone(r.fields)
case Bit_Set_Type:
case ^Bit_Set_Type:
r.elem = clone(r.elem)
r.underlying = clone(r.underlying)
case Map_Type:
case ^Map_Type:
r.key = clone(r.key)
r.value = clone(r.value)
case Matrix_Type:
case ^Matrix_Type:
r.row_count = clone(r.row_count)
r.column_count = clone(r.column_count)
r.elem = clone(r.elem)
case ^Relative_Type:
r.tag = clone(r.tag)
r.type = clone(r.type)
case:
fmt.panicf("Unhandled node kind: %T", r)
fmt.panicf("Unhandled node kind: %v", r)
}
return res
+77 -77
View File
@@ -59,64 +59,64 @@ walk :: proc(v: ^Visitor, node: ^Node) {
}
switch n in &node.derived {
case File:
case ^File:
if n.docs != nil {
walk(v, n.docs)
}
walk_stmt_list(v, n.decls[:])
case Package:
case ^Package:
for _, f in n.files {
walk(v, f)
}
case Comment_Group:
case ^Comment_Group:
// empty
case Bad_Expr:
case Ident:
case Implicit:
case Undef:
case Basic_Lit:
case Basic_Directive:
case Ellipsis:
case ^Bad_Expr:
case ^Ident:
case ^Implicit:
case ^Undef:
case ^Basic_Lit:
case ^Basic_Directive:
case ^Ellipsis:
if n.expr != nil {
walk(v, n.expr)
}
case Proc_Lit:
case ^Proc_Lit:
walk(v, n.type)
walk(v, n.body)
walk_expr_list(v, n.where_clauses)
case Comp_Lit:
case ^Comp_Lit:
if n.type != nil {
walk(v, n.type)
}
walk_expr_list(v, n.elems)
case Tag_Expr:
case ^Tag_Expr:
walk(v, n.expr)
case Unary_Expr:
case ^Unary_Expr:
walk(v, n.expr)
case Binary_Expr:
case ^Binary_Expr:
walk(v, n.left)
walk(v, n.right)
case Paren_Expr:
case ^Paren_Expr:
walk(v, n.expr)
case Selector_Expr:
case ^Selector_Expr:
walk(v, n.expr)
walk(v, n.field)
case Implicit_Selector_Expr:
case ^Implicit_Selector_Expr:
walk(v, n.field)
case Selector_Call_Expr:
case ^Selector_Call_Expr:
walk(v, n.expr)
walk(v, n.call)
case Index_Expr:
case ^Index_Expr:
walk(v, n.expr)
walk(v, n.index)
case Matrix_Index_Expr:
case ^Matrix_Index_Expr:
walk(v, n.expr)
walk(v, n.row_index)
walk(v, n.column_index)
case Deref_Expr:
case ^Deref_Expr:
walk(v, n.expr)
case Slice_Expr:
case ^Slice_Expr:
walk(v, n.expr)
if n.low != nil {
walk(v, n.low)
@@ -124,57 +124,57 @@ walk :: proc(v: ^Visitor, node: ^Node) {
if n.high != nil {
walk(v, n.high)
}
case Call_Expr:
case ^Call_Expr:
walk(v, n.expr)
walk_expr_list(v, n.args)
case Field_Value:
case ^Field_Value:
walk(v, n.field)
walk(v, n.value)
case Ternary_If_Expr:
case ^Ternary_If_Expr:
walk(v, n.x)
walk(v, n.cond)
walk(v, n.y)
case Ternary_When_Expr:
case ^Ternary_When_Expr:
walk(v, n.x)
walk(v, n.cond)
walk(v, n.y)
case Or_Else_Expr:
case ^Or_Else_Expr:
walk(v, n.x)
walk(v, n.y)
case Or_Return_Expr:
case ^Or_Return_Expr:
walk(v, n.expr)
case Type_Assertion:
case ^Type_Assertion:
walk(v, n.expr)
if n.type != nil {
walk(v, n.type)
}
case Type_Cast:
case ^Type_Cast:
walk(v, n.type)
walk(v, n.expr)
case Auto_Cast:
case ^Auto_Cast:
walk(v, n.expr)
case Inline_Asm_Expr:
case ^Inline_Asm_Expr:
walk_expr_list(v, n.param_types)
walk(v, n.return_type)
walk(v, n.constraints_string)
walk(v, n.asm_string)
case Bad_Stmt:
case Empty_Stmt:
case Expr_Stmt:
case ^Bad_Stmt:
case ^Empty_Stmt:
case ^Expr_Stmt:
walk(v, n.expr)
case Tag_Stmt:
case ^Tag_Stmt:
walk(v, n.stmt)
case Assign_Stmt:
case ^Assign_Stmt:
walk_expr_list(v, n.lhs)
walk_expr_list(v, n.rhs)
case Block_Stmt:
case ^Block_Stmt:
if n.label != nil {
walk(v, n.label)
}
walk_stmt_list(v, n.stmts)
case If_Stmt:
case ^If_Stmt:
if n.label != nil {
walk(v, n.label)
}
@@ -186,17 +186,17 @@ walk :: proc(v: ^Visitor, node: ^Node) {
if n.else_stmt != nil {
walk(v, n.else_stmt)
}
case When_Stmt:
case ^When_Stmt:
walk(v, n.cond)
walk(v, n.body)
if n.else_stmt != nil {
walk(v, n.else_stmt)
}
case Return_Stmt:
case ^Return_Stmt:
walk_expr_list(v, n.results)
case Defer_Stmt:
case ^Defer_Stmt:
walk(v, n.stmt)
case For_Stmt:
case ^For_Stmt:
if n.label != nil {
walk(v, n.label)
}
@@ -210,7 +210,7 @@ walk :: proc(v: ^Visitor, node: ^Node) {
walk(v, n.post)
}
walk(v, n.body)
case Range_Stmt:
case ^Range_Stmt:
if n.label != nil {
walk(v, n.label)
}
@@ -221,7 +221,7 @@ walk :: proc(v: ^Visitor, node: ^Node) {
}
walk(v, n.expr)
walk(v, n.body)
case Inline_Range_Stmt:
case ^Inline_Range_Stmt:
if n.label != nil {
walk(v, n.label)
}
@@ -233,10 +233,10 @@ walk :: proc(v: ^Visitor, node: ^Node) {
}
walk(v, n.expr)
walk(v, n.body)
case Case_Clause:
case ^Case_Clause:
walk_expr_list(v, n.list)
walk_stmt_list(v, n.body)
case Switch_Stmt:
case ^Switch_Stmt:
if n.label != nil {
walk(v, n.label)
}
@@ -247,7 +247,7 @@ walk :: proc(v: ^Visitor, node: ^Node) {
walk(v, n.cond)
}
walk(v, n.body)
case Type_Switch_Stmt:
case ^Type_Switch_Stmt:
if n.label != nil {
walk(v, n.label)
}
@@ -258,16 +258,16 @@ walk :: proc(v: ^Visitor, node: ^Node) {
walk(v, n.expr)
}
walk(v, n.body)
case Branch_Stmt:
case ^Branch_Stmt:
if n.label != nil {
walk(v, n.label)
}
case Using_Stmt:
case ^Using_Stmt:
walk_expr_list(v, n.list)
case Bad_Decl:
case Value_Decl:
case ^Bad_Decl:
case ^Value_Decl:
if n.docs != nil {
walk(v, n.docs)
}
@@ -280,21 +280,21 @@ walk :: proc(v: ^Visitor, node: ^Node) {
if n.comment != nil {
walk(v, n.comment)
}
case Package_Decl:
case ^Package_Decl:
if n.docs != nil {
walk(v, n.docs)
}
if n.comment != nil {
walk(v, n.comment)
}
case Import_Decl:
case ^Import_Decl:
if n.docs != nil {
walk(v, n.docs)
}
if n.comment != nil {
walk(v, n.comment)
}
case Foreign_Block_Decl:
case ^Foreign_Block_Decl:
if n.docs != nil {
walk(v, n.docs)
}
@@ -303,7 +303,7 @@ walk :: proc(v: ^Visitor, node: ^Node) {
walk(v, n.foreign_library)
}
walk(v, n.body)
case Foreign_Import_Decl:
case ^Foreign_Import_Decl:
if n.docs != nil {
walk(v, n.docs)
}
@@ -313,11 +313,11 @@ walk :: proc(v: ^Visitor, node: ^Node) {
walk(v, n.comment)
}
case Proc_Group:
case ^Proc_Group:
walk_expr_list(v, n.args)
case Attribute:
case ^Attribute:
walk_expr_list(v, n.elems)
case Field:
case ^Field:
if n.docs != nil {
walk(v, n.docs)
}
@@ -331,31 +331,31 @@ walk :: proc(v: ^Visitor, node: ^Node) {
if n.comment != nil {
walk(v, n.comment)
}
case Field_List:
case ^Field_List:
for x in n.list {
walk(v, x)
}
case Typeid_Type:
case ^Typeid_Type:
if n.specialization != nil {
walk(v, n.specialization)
}
case Helper_Type:
case ^Helper_Type:
walk(v, n.type)
case Distinct_Type:
case ^Distinct_Type:
walk(v, n.type)
case Poly_Type:
case ^Poly_Type:
walk(v, n.type)
if n.specialization != nil {
walk(v, n.specialization)
}
case Proc_Type:
case ^Proc_Type:
walk(v, n.params)
walk(v, n.results)
case Pointer_Type:
case ^Pointer_Type:
walk(v, n.elem)
case Multi_Pointer_Type:
case ^Multi_Pointer_Type:
walk(v, n.elem)
case Array_Type:
case ^Array_Type:
if n.tag != nil {
walk(v, n.tag)
}
@@ -363,12 +363,12 @@ walk :: proc(v: ^Visitor, node: ^Node) {
walk(v, n.len)
}
walk(v, n.elem)
case Dynamic_Array_Type:
case ^Dynamic_Array_Type:
if n.tag != nil {
walk(v, n.tag)
}
walk(v, n.elem)
case Struct_Type:
case ^Struct_Type:
if n.poly_params != nil {
walk(v, n.poly_params)
}
@@ -377,7 +377,7 @@ walk :: proc(v: ^Visitor, node: ^Node) {
}
walk_expr_list(v, n.where_clauses)
walk(v, n.fields)
case Union_Type:
case ^Union_Type:
if n.poly_params != nil {
walk(v, n.poly_params)
}
@@ -386,23 +386,23 @@ walk :: proc(v: ^Visitor, node: ^Node) {
}
walk_expr_list(v, n.where_clauses)
walk_expr_list(v, n.variants)
case Enum_Type:
case ^Enum_Type:
if n.base_type != nil {
walk(v, n.base_type)
}
walk_expr_list(v, n.fields)
case Bit_Set_Type:
case ^Bit_Set_Type:
walk(v, n.elem)
if n.underlying != nil {
walk(v, n.underlying)
}
case Map_Type:
case ^Map_Type:
walk(v, n.key)
walk(v, n.value)
case Relative_Type:
case ^Relative_Type:
walk(v, n.tag)
walk(v, n.type)
case Matrix_Type:
case ^Matrix_Type:
walk(v, n.row_count)
walk(v, n.column_count)
walk(v, n.elem)
+90 -90
View File
@@ -195,10 +195,10 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool {
for p.curr_tok.kind != .EOF {
stmt := parse_stmt(p)
if stmt != nil {
if _, ok := stmt.derived.(ast.Empty_Stmt); !ok {
if _, ok := stmt.derived.(^ast.Empty_Stmt); !ok {
append(&p.file.decls, stmt)
if es, es_ok := stmt.derived.(ast.Expr_Stmt); es_ok && es.expr != nil {
if _, pl_ok := es.expr.derived.(ast.Proc_Lit); pl_ok {
if es, es_ok := stmt.derived.(^ast.Expr_Stmt); es_ok && es.expr != nil {
if _, pl_ok := es.expr.derived.(^ast.Proc_Lit); pl_ok {
error(p, stmt.pos, "procedure literal evaluated but not used")
}
}
@@ -459,7 +459,7 @@ is_blank_ident_token :: proc(tok: tokenizer.Token) -> bool {
return false
}
is_blank_ident_node :: proc(node: ^ast.Node) -> bool {
if ident, ok := node.derived.(ast.Ident); ok {
if ident, ok := node.derived.(^ast.Ident); ok {
return is_blank_ident(ident.name)
}
return true
@@ -502,34 +502,34 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool {
return true
}
switch n in node.derived {
case ast.Empty_Stmt, ast.Block_Stmt:
#partial switch n in node.derived {
case ^ast.Empty_Stmt, ^ast.Block_Stmt:
return true
case ast.If_Stmt, ast.When_Stmt,
ast.For_Stmt, ast.Range_Stmt, ast.Inline_Range_Stmt,
ast.Switch_Stmt, ast.Type_Switch_Stmt:
case ^ast.If_Stmt, ^ast.When_Stmt,
^ast.For_Stmt, ^ast.Range_Stmt, ^ast.Inline_Range_Stmt,
^ast.Switch_Stmt, ^ast.Type_Switch_Stmt:
return true
case ast.Helper_Type:
case ^ast.Helper_Type:
return is_semicolon_optional_for_node(p, n.type)
case ast.Distinct_Type:
case ^ast.Distinct_Type:
return is_semicolon_optional_for_node(p, n.type)
case ast.Pointer_Type:
case ^ast.Pointer_Type:
return is_semicolon_optional_for_node(p, n.elem)
case ast.Struct_Type, ast.Union_Type, ast.Enum_Type:
case ^ast.Struct_Type, ^ast.Union_Type, ^ast.Enum_Type:
// Require semicolon within a procedure body
return p.curr_proc == nil
case ast.Proc_Lit:
case ^ast.Proc_Lit:
return true
case ast.Package_Decl, ast.Import_Decl, ast.Foreign_Import_Decl:
case ^ast.Package_Decl, ^ast.Import_Decl, ^ast.Foreign_Import_Decl:
return true
case ast.Foreign_Block_Decl:
case ^ast.Foreign_Block_Decl:
return is_semicolon_optional_for_node(p, n.body)
case ast.Value_Decl:
case ^ast.Value_Decl:
if n.is_mutable {
return false
}
@@ -641,10 +641,10 @@ parse_stmt_list :: proc(p: ^Parser) -> []^ast.Stmt {
p.curr_tok.kind != .EOF {
stmt := parse_stmt(p)
if stmt != nil {
if _, ok := stmt.derived.(ast.Empty_Stmt); !ok {
if _, ok := stmt.derived.(^ast.Empty_Stmt); !ok {
append(&list, stmt)
if es, es_ok := stmt.derived.(ast.Expr_Stmt); es_ok && es.expr != nil {
if _, pl_ok := es.expr.derived.(ast.Proc_Lit); pl_ok {
if es, es_ok := stmt.derived.(^ast.Expr_Stmt); es_ok && es.expr != nil {
if _, pl_ok := es.expr.derived.(^ast.Proc_Lit); pl_ok {
error(p, stmt.pos, "procedure literal evaluated but not used")
}
}
@@ -722,7 +722,7 @@ convert_stmt_to_expr :: proc(p: ^Parser, stmt: ^ast.Stmt, kind: string) -> ^ast.
if stmt == nil {
return nil
}
if es, ok := stmt.derived.(ast.Expr_Stmt); ok {
if es, ok := stmt.derived.(^ast.Expr_Stmt); ok {
return es.expr
}
error(p, stmt.pos, "expected %s, found a simple statement", kind)
@@ -864,7 +864,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
if p.curr_tok.kind != .Semicolon {
cond = parse_simple_stmt(p, {Stmt_Allow_Flag.In})
if as, ok := cond.derived.(ast.Assign_Stmt); ok && as.op.kind == .In {
if as, ok := cond.derived.(^ast.Assign_Stmt); ok && as.op.kind == .In {
is_range = true
}
}
@@ -906,7 +906,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
if is_range {
assign_stmt := cond.derived.(ast.Assign_Stmt)
assign_stmt := cond.derived.(^ast.Assign_Stmt)
vals := assign_stmt.lhs[:]
rhs: ^ast.Expr
@@ -987,7 +987,7 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
tag = as
} else {
tag = parse_simple_stmt(p, {Stmt_Allow_Flag.In})
if as, ok := tag.derived.(ast.Assign_Stmt); ok && as.op.kind == .In {
if as, ok := tag.derived.(^ast.Assign_Stmt); ok && as.op.kind == .In {
is_type_switch = true
} else if parse_control_statement_semicolon_separator(p) {
init = tag
@@ -1074,14 +1074,14 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind:
skip_possible_newline(p)
decl := parse_stmt(p)
switch d in &decl.derived {
case ast.Value_Decl:
#partial switch d in decl.derived_stmt {
case ^ast.Value_Decl:
if d.docs == nil { d.docs = docs }
append(&d.attributes, attribute)
case ast.Foreign_Block_Decl:
case ^ast.Foreign_Block_Decl:
if d.docs == nil { d.docs = docs }
append(&d.attributes, attribute)
case ast.Foreign_Import_Decl:
case ^ast.Foreign_Import_Decl:
if d.docs == nil { d.docs = docs }
append(&d.attributes, attribute)
case:
@@ -1095,11 +1095,11 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind:
parse_foreign_block_decl :: proc(p: ^Parser) -> ^ast.Stmt {
decl := parse_stmt(p)
switch in decl.derived {
case ast.Empty_Stmt, ast.Bad_Stmt, ast.Bad_Decl:
#partial switch in decl.derived_stmt {
case ^ast.Empty_Stmt, ^ast.Bad_Stmt, ^ast.Bad_Decl:
// Ignore
return nil
case ast.When_Stmt, ast.Value_Decl:
case ^ast.When_Stmt, ^ast.Value_Decl:
return decl
}
@@ -1303,13 +1303,13 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
case .Defer:
tok := advance_token(p)
stmt := parse_stmt(p)
switch s in stmt.derived {
case ast.Empty_Stmt:
#partial switch s in stmt.derived_stmt {
case ^ast.Empty_Stmt:
error(p, s.pos, "empty statement after defer (e.g. ';')")
case ast.Defer_Stmt:
case ^ast.Defer_Stmt:
error(p, s.pos, "you cannot defer a defer statement")
stmt = s.stmt
case ast.Return_Stmt:
case ^ast.Return_Stmt:
error(p, s.pos, "you cannot defer a return statement")
}
ds := ast.new(ast.Defer_Stmt, tok.pos, stmt.end)
@@ -1381,8 +1381,8 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
expect_token_after(p, .Colon, "identifier list")
decl := parse_value_decl(p, list, docs)
if decl != nil {
switch d in &decl.derived {
case ast.Value_Decl:
#partial switch d in decl.derived_stmt {
case ^ast.Value_Decl:
d.is_using = true
return decl
}
@@ -1413,9 +1413,9 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
return stmt
case "partial":
stmt := parse_stmt(p)
switch s in &stmt.derived {
case ast.Switch_Stmt: s.partial = true
case ast.Type_Switch_Stmt: s.partial = true
#partial switch s in stmt.derived_stmt {
case ^ast.Switch_Stmt: s.partial = true
case ^ast.Type_Switch_Stmt: s.partial = true
case: error(p, stmt.pos, "#partial can only be applied to a switch statement")
}
return stmt
@@ -1560,11 +1560,11 @@ parse_body :: proc(p: ^Parser) -> ^ast.Block_Stmt {
}
convert_stmt_to_body :: proc(p: ^Parser, stmt: ^ast.Stmt) -> ^ast.Stmt {
switch s in stmt.derived {
case ast.Block_Stmt:
#partial switch s in stmt.derived_stmt {
case ^ast.Block_Stmt:
error(p, stmt.pos, "expected a normal statement rather than a block statement")
return stmt
case ast.Empty_Stmt:
case ^ast.Empty_Stmt:
error(p, stmt.pos, "expected a non-empty statement")
}
@@ -1641,10 +1641,10 @@ convert_to_ident_list :: proc(p: ^Parser, list: []Expr_And_Flags, ignore_flags,
id: ^ast.Expr = ident.expr
switch n in ident.expr.derived {
case ast.Ident:
case ast.Bad_Expr:
case ast.Poly_Type:
#partial switch n in ident.expr.derived_expr {
case ^ast.Ident:
case ^ast.Bad_Expr:
case ^ast.Poly_Type:
if allow_poly_names {
if n.specialization == nil {
break
@@ -1806,21 +1806,21 @@ check_procedure_name_list :: proc(p: ^Parser, names: []^ast.Expr) -> bool {
return false
}
_, first_is_polymorphic := names[0].derived.(ast.Poly_Type)
_, first_is_polymorphic := names[0].derived.(^ast.Poly_Type)
any_polymorphic_names := first_is_polymorphic
for i := 1; i < len(names); i += 1 {
name := names[i]
if first_is_polymorphic {
if _, ok := name.derived.(ast.Poly_Type); ok {
if _, ok := name.derived.(^ast.Poly_Type); ok {
any_polymorphic_names = true
} else {
error(p, name.pos, "mixture of polymorphic and non-polymorphic identifiers")
return any_polymorphic_names
}
} else {
if _, ok := name.derived.(ast.Poly_Type); ok {
if _, ok := name.derived.(^ast.Poly_Type); ok {
any_polymorphic_names = true
error(p, name.pos, "mixture of polymorphic and non-polymorphic identifiers")
return any_polymorphic_names
@@ -1885,7 +1885,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
if type == nil {
return false
}
_, ok := type.derived.(ast.Ellipsis)
_, ok := type.derived.(^ast.Ellipsis)
return ok
}
@@ -1903,7 +1903,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
type = parse_var_type(p, allowed_flags)
tt := ast.unparen_expr(type)
if is_signature && !any_polymorphic_names {
if ti, ok := tt.derived.(ast.Typeid_Type); ok && ti.specialization != nil {
if ti, ok := tt.derived.(^ast.Typeid_Type); ok && ti.specialization != nil {
error(p, tt.pos, "specialization of typeid is not allowed without polymorphic names")
}
}
@@ -1979,7 +1979,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
p.curr_tok.kind != .EOF {
prefix_flags := parse_field_prefixes(p)
param := parse_var_type(p, allowed_flags & {.Typeid_Token, .Ellipsis})
if _, ok := param.derived.(ast.Ellipsis); ok {
if _, ok := param.derived.(^ast.Ellipsis); ok {
if seen_ellipsis {
error(p, param.pos, "extra variadic parameter after ellipsis")
}
@@ -2006,8 +2006,8 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
names := make([]^ast.Expr, 1)
names[0] = ast.new(ast.Ident, tok.pos, end_pos(tok))
switch ident in &names[0].derived {
case ast.Ident:
#partial switch ident in names[0].derived_expr {
case ^ast.Ident:
ident.name = tok.text
case:
unreachable()
@@ -2137,12 +2137,12 @@ parse_proc_type :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Proc_Type {
loop: for param in params.list {
if param.type != nil {
if _, ok := param.type.derived.(ast.Poly_Type); ok {
if _, ok := param.type.derived.(^ast.Poly_Type); ok {
is_generic = true
break loop
}
for name in param.names {
if _, ok := name.derived.(ast.Poly_Type); ok {
if _, ok := name.derived.(^ast.Poly_Type); ok {
is_generic = true
break loop
}
@@ -2179,13 +2179,13 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^
}
}
switch e in &ast.unparen_expr(expr).derived {
case ast.Proc_Lit:
#partial switch e in ast.unparen_expr(expr).derived_expr {
case ^ast.Proc_Lit:
if e.inlining != .None && e.inlining != pi {
error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure literal")
}
e.inlining = pi
case ast.Call_Expr:
case ^ast.Call_Expr:
if e.inlining != .None && e.inlining != pi {
error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure call")
}
@@ -2276,9 +2276,9 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
bd.name = name.text
original_type := parse_type(p)
type := ast.unparen_expr(original_type)
switch t in &type.derived {
case ast.Array_Type: t.tag = bd
case ast.Dynamic_Array_Type: t.tag = bd
#partial switch t in type.derived_expr {
case ^ast.Array_Type: t.tag = bd
case ^ast.Dynamic_Array_Type: t.tag = bd
case:
error(p, original_type.pos, "expected an array type after #%s", name.text)
}
@@ -2290,10 +2290,10 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tag.name = name.text
original_expr := parse_expr(p, lhs)
expr := ast.unparen_expr(original_expr)
switch t in &expr.derived {
case ast.Comp_Lit:
#partial switch t in expr.derived_expr {
case ^ast.Comp_Lit:
t.tag = tag
case ast.Array_Type:
case ^ast.Array_Type:
t.tag = tag
error(p, tok.pos, "#%s has been replaced with #sparse for non-contiguous enumerated array types", name.text)
case:
@@ -2308,8 +2308,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tag.name = name.text
original_type := parse_type(p)
type := ast.unparen_expr(original_type)
switch t in &type.derived {
case ast.Array_Type:
#partial switch t in type.derived_expr {
case ^ast.Array_Type:
t.tag = tag
case:
error(p, tok.pos, "expected an enumerated array type after #%s", name.text)
@@ -2689,7 +2689,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
variants: [dynamic]^ast.Expr
for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF {
type := parse_type(p)
if _, ok := type.derived.(ast.Bad_Expr); !ok {
if _, ok := type.derived.(^ast.Bad_Expr); !ok {
append(&variants, type)
}
if !allow_token(p, .Comma) {
@@ -2864,19 +2864,19 @@ is_literal_type :: proc(expr: ^ast.Expr) -> bool {
if val == nil {
return false
}
switch _ in val.derived {
case ast.Bad_Expr,
ast.Ident,
ast.Selector_Expr,
ast.Array_Type,
ast.Struct_Type,
ast.Union_Type,
ast.Enum_Type,
ast.Dynamic_Array_Type,
ast.Map_Type,
ast.Bit_Set_Type,
ast.Matrix_Type,
ast.Call_Expr:
#partial switch _ in val.derived_expr {
case ^ast.Bad_Expr,
^ast.Ident,
^ast.Selector_Expr,
^ast.Array_Type,
^ast.Struct_Type,
^ast.Union_Type,
^ast.Enum_Type,
^ast.Dynamic_Array_Type,
^ast.Map_Type,
^ast.Bit_Set_Type,
^ast.Matrix_Type,
^ast.Call_Expr:
return true
}
return false
@@ -2998,7 +2998,7 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
ce.close = close.pos
o := ast.unparen_expr(operand)
if se, ok := o.derived.(ast.Selector_Expr); ok && se.op.kind == .Arrow_Right {
if se, ok := o.derived.(^ast.Selector_Expr); ok && se.op.kind == .Arrow_Right {
sce := ast.new(ast.Selector_Call_Expr, ce.pos, ce.end)
sce.expr = o
sce.call = ce
@@ -3428,13 +3428,13 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
stmt := parse_stmt(p)
if stmt != nil {
switch n in &stmt.derived {
case ast.Block_Stmt: n.label = label
case ast.If_Stmt: n.label = label
case ast.For_Stmt: n.label = label
case ast.Switch_Stmt: n.label = label
case ast.Type_Switch_Stmt: n.label = label
case ast.Range_Stmt: n.label = label
#partial switch n in stmt.derived_stmt {
case ^ast.Block_Stmt: n.label = label
case ^ast.If_Stmt: n.label = label
case ^ast.For_Stmt: n.label = label
case ^ast.Switch_Stmt: n.label = label
case ^ast.Type_Switch_Stmt: n.label = label
case ^ast.Range_Stmt: n.label = label
}
}
+132 -94
View File
@@ -342,16 +342,16 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
return
}
switch v in &decl.derived {
case Expr_Stmt:
#partial switch v in decl.derived_stmt {
case ^Expr_Stmt:
move_line(p, decl.pos)
visit_expr(p, v.expr)
if p.config.semicolons {
push_generic_token(p, .Semicolon, 0)
}
case When_Stmt:
case ^When_Stmt:
visit_stmt(p, cast(^Stmt)decl)
case Foreign_Import_Decl:
case ^Foreign_Import_Decl:
if len(v.attributes) > 0 {
sort.sort(sort_attribute(&v.attributes))
move_line(p, v.attributes[0].pos)
@@ -370,7 +370,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
for path in v.fullpaths {
push_ident_token(p, path, 0)
}
case Foreign_Block_Decl:
case ^Foreign_Block_Decl:
if len(v.attributes) > 0 {
sort.sort(sort_attribute(&v.attributes))
move_line(p, v.attributes[0].pos)
@@ -383,7 +383,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
visit_expr(p, v.foreign_library)
visit_stmt(p, v.body)
case Import_Decl:
case ^Import_Decl:
move_line(p, decl.pos)
if v.name.text != "" {
@@ -395,7 +395,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
push_ident_token(p, v.fullpath, 1)
}
case Value_Decl:
case ^Value_Decl:
if len(v.attributes) > 0 {
sort.sort(sort_attribute(&v.attributes))
move_line(p, v.attributes[0].pos)
@@ -446,10 +446,10 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
add_semicolon := true
for value in v.values {
switch a in value.derived {
case Union_Type, Enum_Type, Struct_Type:
#partial switch a in value.derived {
case ^Union_Type, ^Enum_Type, ^Struct_Type:
add_semicolon = false || called_in_stmt
case Proc_Lit:
case ^Proc_Lit:
add_semicolon = false
}
}
@@ -516,23 +516,34 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
return
}
switch v in stmt.derived {
case Import_Decl:
visit_decl(p, cast(^Decl)stmt, true)
return
case Value_Decl:
visit_decl(p, cast(^Decl)stmt, true)
return
case Foreign_Import_Decl:
visit_decl(p, cast(^Decl)stmt, true)
return
case Foreign_Block_Decl:
visit_decl(p, cast(^Decl)stmt, true)
return
}
switch v in stmt.derived {
case Using_Stmt:
switch v in stmt.derived_stmt {
case ^Bad_Stmt:
case ^Bad_Decl:
case ^Package_Decl:
case ^Empty_Stmt:
push_generic_token(p, .Semicolon, 0)
case ^Tag_Stmt:
push_generic_token(p, .Hash, 1)
push_generic_token(p, v.op.kind, 1, v.op.text)
visit_stmt(p, v.stmt)
case ^Import_Decl:
visit_decl(p, cast(^Decl)stmt, true)
return
case ^Value_Decl:
visit_decl(p, cast(^Decl)stmt, true)
return
case ^Foreign_Import_Decl:
visit_decl(p, cast(^Decl)stmt, true)
return
case ^Foreign_Block_Decl:
visit_decl(p, cast(^Decl)stmt, true)
return
case ^Using_Stmt:
move_line(p, v.pos)
push_generic_token(p, .Using, 1)
@@ -542,7 +553,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
if p.config.semicolons {
push_generic_token(p, .Semicolon, 0)
}
case Block_Stmt:
case ^Block_Stmt:
move_line(p, v.pos)
if v.pos.line == v.end.line {
@@ -572,7 +583,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_end_brace(p, v.end)
}
}
case If_Stmt:
case ^If_Stmt:
move_line(p, v.pos)
if v.label != nil {
@@ -595,7 +606,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
uses_do := false
if check_stmt, ok := v.body.derived.(Block_Stmt); ok && check_stmt.uses_do {
if check_stmt, ok := v.body.derived.(^Block_Stmt); ok && check_stmt.uses_do {
uses_do = true
}
@@ -626,7 +637,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_stmt(p, v.else_stmt)
}
case Switch_Stmt:
case ^Switch_Stmt:
move_line(p, v.pos)
if v.label != nil {
@@ -654,7 +665,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_expr(p, v.cond)
visit_stmt(p, v.body)
case Case_Clause:
case ^Case_Clause:
move_line(p, v.pos)
if !p.config.indent_cases {
@@ -678,7 +689,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
if !p.config.indent_cases {
indent(p)
}
case Type_Switch_Stmt:
case ^Type_Switch_Stmt:
move_line(p, v.pos)
hint_current_line(p, {.Switch_Stmt})
@@ -696,7 +707,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_stmt(p, v.tag)
visit_stmt(p, v.body)
case Assign_Stmt:
case ^Assign_Stmt:
move_line(p, v.pos)
hint_current_line(p, {.Assign})
@@ -710,13 +721,13 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
if block_stmt && p.config.semicolons {
push_generic_token(p, .Semicolon, 0)
}
case Expr_Stmt:
case ^Expr_Stmt:
move_line(p, v.pos)
visit_expr(p, v.expr)
if block_stmt && p.config.semicolons {
push_generic_token(p, .Semicolon, 0)
}
case For_Stmt:
case ^For_Stmt:
// this should be simplified
move_line(p, v.pos)
@@ -753,7 +764,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_stmt(p, v.body)
case Inline_Range_Stmt:
case ^Inline_Range_Stmt:
move_line(p, v.pos)
if v.label != nil {
@@ -779,7 +790,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_expr(p, v.expr)
visit_stmt(p, v.body)
case Range_Stmt:
case ^Range_Stmt:
move_line(p, v.pos)
if v.label != nil {
@@ -805,7 +816,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_expr(p, v.expr)
visit_stmt(p, v.body)
case Return_Stmt:
case ^Return_Stmt:
move_line(p, v.pos)
push_generic_token(p, .Return, 1)
@@ -817,7 +828,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
if block_stmt && p.config.semicolons {
push_generic_token(p, .Semicolon, 0)
}
case Defer_Stmt:
case ^Defer_Stmt:
move_line(p, v.pos)
push_generic_token(p, .Defer, 0)
@@ -826,7 +837,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
if p.config.semicolons {
push_generic_token(p, .Semicolon, 0)
}
case When_Stmt:
case ^When_Stmt:
move_line(p, v.pos)
push_generic_token(p, .When, 1)
visit_expr(p, v.cond)
@@ -846,7 +857,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
visit_stmt(p, v.else_stmt)
}
case Branch_Stmt:
case ^Branch_Stmt:
move_line(p, v.pos)
push_generic_token(p, v.tok.kind, 0)
@@ -918,8 +929,15 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
set_source_position(p, expr.pos)
switch v in expr.derived {
case Inline_Asm_Expr:
switch v in expr.derived_expr {
case ^Bad_Expr:
case ^Tag_Expr:
push_generic_token(p, .Hash, 1)
push_generic_token(p, v.op.kind, 1, v.op.text)
visit_expr(p, v.expr)
case ^Inline_Asm_Expr:
push_generic_token(p, v.tok.kind, 1, v.tok.text)
push_generic_token(p, .Open_Paren, 1)
@@ -936,42 +954,42 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
push_generic_token(p, .Comma, 0)
visit_expr(p, v.constraints_string)
push_generic_token(p, .Close_Brace, 0)
case Undef:
case ^Undef:
push_generic_token(p, .Undef, 1)
case Auto_Cast:
case ^Auto_Cast:
push_generic_token(p, v.op.kind, 1)
visit_expr(p, v.expr)
case Ternary_If_Expr:
case ^Ternary_If_Expr:
visit_expr(p, v.x)
push_generic_token(p, v.op1.kind, 1)
visit_expr(p, v.cond)
push_generic_token(p, v.op2.kind, 1)
visit_expr(p, v.y)
case Ternary_When_Expr:
case ^Ternary_When_Expr:
visit_expr(p, v.x)
push_generic_token(p, v.op1.kind, 1)
visit_expr(p, v.cond)
push_generic_token(p, v.op2.kind, 1)
visit_expr(p, v.y)
case Or_Else_Expr:
case ^Or_Else_Expr:
visit_expr(p, v.x)
push_generic_token(p, v.token.kind, 1)
visit_expr(p, v.y)
case Or_Return_Expr:
case ^Or_Return_Expr:
visit_expr(p, v.expr)
push_generic_token(p, v.token.kind, 1)
case Selector_Call_Expr:
case ^Selector_Call_Expr:
visit_expr(p, v.call.expr)
push_generic_token(p, .Open_Paren, 1)
visit_exprs(p, v.call.args, {.Add_Comma})
push_generic_token(p, .Close_Paren, 0)
case Ellipsis:
case ^Ellipsis:
push_generic_token(p, .Ellipsis, 1)
visit_expr(p, v.expr)
case Relative_Type:
case ^Relative_Type:
visit_expr(p, v.tag)
visit_expr(p, v.type)
case Slice_Expr:
case ^Slice_Expr:
visit_expr(p, v.expr)
push_generic_token(p, .Open_Bracket, 0)
visit_expr(p, v.low)
@@ -981,37 +999,37 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
visit_expr(p, v.high)
}
push_generic_token(p, .Close_Bracket, 0)
case Ident:
case ^Ident:
if .Enforce_Poly_Names in options {
push_generic_token(p, .Dollar, 1)
push_ident_token(p, v.name, 0)
} else {
push_ident_token(p, v.name, 1)
}
case Deref_Expr:
case ^Deref_Expr:
visit_expr(p, v.expr)
push_generic_token(p, v.op.kind, 0)
case Type_Cast:
case ^Type_Cast:
push_generic_token(p, v.tok.kind, 1)
push_generic_token(p, .Open_Paren, 0)
visit_expr(p, v.type)
push_generic_token(p, .Close_Paren, 0)
merge_next_token(p)
visit_expr(p, v.expr)
case Basic_Directive:
case ^Basic_Directive:
push_generic_token(p, v.tok.kind, 1)
push_ident_token(p, v.name, 0)
case Distinct_Type:
case ^Distinct_Type:
push_generic_token(p, .Distinct, 1)
visit_expr(p, v.type)
case Dynamic_Array_Type:
case ^Dynamic_Array_Type:
visit_expr(p, v.tag)
push_generic_token(p, .Open_Bracket, 1)
push_generic_token(p, .Dynamic, 0)
push_generic_token(p, .Close_Bracket, 0)
merge_next_token(p)
visit_expr(p, v.elem)
case Bit_Set_Type:
case ^Bit_Set_Type:
push_generic_token(p, .Bit_Set, 1)
push_generic_token(p, .Open_Bracket, 0)
@@ -1023,7 +1041,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
}
push_generic_token(p, .Close_Bracket, 0)
case Union_Type:
case ^Union_Type:
push_generic_token(p, .Union, 1)
push_poly_params(p, v.poly_params)
@@ -1045,7 +1063,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
visit_exprs(p, v.variants, {.Add_Comma, .Trailing})
visit_end_brace(p, v.end)
}
case Enum_Type:
case ^Enum_Type:
push_generic_token(p, .Enum, 1)
hint_current_line(p, {.Enum})
@@ -1068,7 +1086,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
}
set_source_position(p, v.end)
case Struct_Type:
case ^Struct_Type:
push_generic_token(p, .Struct, 1)
hint_current_line(p, {.Struct})
@@ -1103,7 +1121,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
}
set_source_position(p, v.end)
case Proc_Lit:
case ^Proc_Lit:
switch v.inlining {
case .None:
case .Inline:
@@ -1112,7 +1130,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
push_ident_token(p, "#force_no_inline", 0)
}
visit_proc_type(p, v.type^, true)
visit_proc_type(p, v.type, true)
push_where_clauses(p, v.where_clauses)
@@ -1122,16 +1140,16 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
} else {
push_generic_token(p, .Undef, 1)
}
case Proc_Type:
case ^Proc_Type:
visit_proc_type(p, v)
case Basic_Lit:
case ^Basic_Lit:
push_generic_token(p, v.tok.kind, 1, v.tok.text)
case Binary_Expr:
case ^Binary_Expr:
visit_binary_expr(p, v)
case Implicit_Selector_Expr:
case ^Implicit_Selector_Expr:
push_generic_token(p, .Period, 1)
push_ident_token(p, v.field.name, 0)
case Call_Expr:
case ^Call_Expr:
visit_expr(p, v.expr)
push_format_token(p,
@@ -1146,27 +1164,34 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
visit_call_exprs(p, v.args, v.ellipsis.kind == .Ellipsis)
push_generic_token(p, .Close_Paren, 0)
case Typeid_Type:
case ^Typeid_Type:
push_generic_token(p, .Typeid, 1)
if v.specialization != nil {
push_generic_token(p, .Quo, 0)
visit_expr(p, v.specialization)
}
case Selector_Expr:
case ^Selector_Expr:
visit_expr(p, v.expr)
push_generic_token(p, v.op.kind, 0)
visit_expr(p, v.field)
case Paren_Expr:
case ^Paren_Expr:
push_generic_token(p, .Open_Paren, 1)
visit_expr(p, v.expr)
push_generic_token(p, .Close_Paren, 0)
case Index_Expr:
case ^Index_Expr:
visit_expr(p, v.expr)
push_generic_token(p, .Open_Bracket, 0)
visit_expr(p, v.index)
push_generic_token(p, .Close_Bracket, 0)
case Proc_Group:
case ^Matrix_Index_Expr:
visit_expr(p, v.expr)
push_generic_token(p, .Open_Bracket, 0)
visit_expr(p, v.row_index)
push_generic_token(p, .Comma, 0)
visit_expr(p, v.column_index)
push_generic_token(p, .Close_Bracket, 0)
case ^Proc_Group:
push_generic_token(p, v.tok.kind, 1)
if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line {
@@ -1181,7 +1206,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
push_generic_token(p, .Close_Brace, 0)
}
case Comp_Lit:
case ^Comp_Lit:
if v.type != nil {
visit_expr(p, v.type)
}
@@ -1198,18 +1223,18 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
push_generic_token(p, .Close_Brace, 0)
}
case Unary_Expr:
case ^Unary_Expr:
push_generic_token(p, v.op.kind, 1)
merge_next_token(p)
visit_expr(p, v.expr)
case Field_Value:
case ^Field_Value:
visit_expr(p, v.field)
push_generic_token(p, .Eq, 1)
visit_expr(p, v.value)
case Type_Assertion:
case ^Type_Assertion:
visit_expr(p, v.expr)
if unary, ok := v.type.derived.(Unary_Expr); ok && unary.op.text == "?" {
if unary, ok := v.type.derived.(^Unary_Expr); ok && unary.op.text == "?" {
push_generic_token(p, .Period, 0)
visit_expr(p, v.type)
} else {
@@ -1219,13 +1244,13 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
push_generic_token(p, .Close_Paren, 0)
}
case Pointer_Type:
case ^Pointer_Type:
push_generic_token(p, .Pointer, 1)
merge_next_token(p)
visit_expr(p, v.elem)
case Implicit:
case ^Implicit:
push_generic_token(p, v.tok.kind, 1)
case Poly_Type:
case ^Poly_Type:
push_generic_token(p, .Dollar, 1)
merge_next_token(p)
visit_expr(p, v.type)
@@ -1235,22 +1260,35 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
merge_next_token(p)
visit_expr(p, v.specialization)
}
case Array_Type:
case ^Array_Type:
visit_expr(p, v.tag)
push_generic_token(p, .Open_Bracket, 1)
visit_expr(p, v.len)
push_generic_token(p, .Close_Bracket, 0)
merge_next_token(p)
visit_expr(p, v.elem)
case Map_Type:
case ^Map_Type:
push_generic_token(p, .Map, 1)
push_generic_token(p, .Open_Bracket, 0)
visit_expr(p, v.key)
push_generic_token(p, .Close_Bracket, 0)
merge_next_token(p)
visit_expr(p, v.value)
case Helper_Type:
case ^Helper_Type:
visit_expr(p, v.type)
case ^Multi_Pointer_Type:
push_generic_token(p, .Open_Bracket, 1)
push_generic_token(p, .Pointer, 0)
push_generic_token(p, .Close_Bracket, 0)
visit_expr(p, v.elem)
case ^Matrix_Type:
push_generic_token(p, .Matrix, 1)
push_generic_token(p, .Open_Bracket, 0)
visit_expr(p, v.row_count)
push_generic_token(p, .Comma, 0)
visit_expr(p, v.column_count)
push_generic_token(p, .Close_Bracket, 0)
visit_expr(p, v.elem)
case:
panic(fmt.aprint(expr.derived))
}
@@ -1348,7 +1386,7 @@ visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, options := List_Opt
}
}
visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, is_proc_lit := false) {
visit_proc_type :: proc(p: ^Printer, proc_type: ^ast.Proc_Type, is_proc_lit := false) {
if is_proc_lit {
push_format_token(p, Format_Token {
kind = .Proc,
@@ -1392,7 +1430,7 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, is_proc_lit := fa
} else if len(proc_type.results.list) == 1 {
for name in proc_type.results.list[0].names {
if ident, ok := name.derived.(ast.Ident); ok {
if ident, ok := name.derived.(^ast.Ident); ok {
if ident.name != "_" {
use_parens = true
}
@@ -1410,19 +1448,19 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, is_proc_lit := fa
}
}
visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) {
visit_binary_expr :: proc(p: ^Printer, binary: ^ast.Binary_Expr) {
move_line(p, binary.left.pos)
if v, ok := binary.left.derived.(ast.Binary_Expr); ok {
if v, ok := binary.left.derived.(^ast.Binary_Expr); ok {
visit_binary_expr(p, v)
} else {
visit_expr(p, binary.left)
}
either_implicit_selector := false
if _, ok := binary.left.derived.(ast.Implicit_Selector_Expr); ok {
if _, ok := binary.left.derived.(^ast.Implicit_Selector_Expr); ok {
either_implicit_selector = true
} else if _, ok := binary.right.derived.(ast.Implicit_Selector_Expr); ok {
} else if _, ok := binary.right.derived.(^ast.Implicit_Selector_Expr); ok {
either_implicit_selector = true
}
@@ -1439,7 +1477,7 @@ visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) {
move_line(p, binary.right.pos)
if v, ok := binary.right.derived.(ast.Binary_Expr); ok {
if v, ok := binary.right.derived.(^ast.Binary_Expr); ok {
visit_binary_expr(p, v)
} else {
visit_expr(p, binary.right)
@@ -1499,7 +1537,7 @@ visit_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, remove_blank :=
named := false
for name in field.names {
if ident, ok := name.derived.(ast.Ident); ok {
if ident, ok := name.derived.(^ast.Ident); ok {
//for some reason the parser uses _ to mean empty
if ident.name != "_" || !remove_blank {
named = true
+71
View File
@@ -0,0 +1,71 @@
package os
import "core:strings"
import "core:mem"
read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
dirp: Dir
dirp, err = _fdopendir(fd)
if err != ERROR_NONE {
return
}
defer _closedir(dirp)
// XXX OpenBSD
dirpath: string
dirpath, err = absolute_path_from_handle(fd)
if err != ERROR_NONE {
return
}
defer delete(dirpath)
n := n
size := n
if n <= 0 {
n = -1
size = 100
}
dfi := make([dynamic]File_Info, 0, size, allocator)
for {
entry: Dirent
end_of_stream: bool
entry, err, end_of_stream = _readdir(dirp)
if err != ERROR_NONE {
for fi_ in dfi {
file_info_delete(fi_, allocator)
}
delete(dfi)
return
} else if end_of_stream {
break
}
fi_: File_Info
filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] })
if filename == "." || filename == ".." {
continue
}
fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator)
defer delete(fullpath, context.temp_allocator)
fi_, err = stat(fullpath, allocator)
if err != ERROR_NONE {
for fi__ in dfi {
file_info_delete(fi__, allocator)
}
delete(dfi)
return
}
append(&dfi, fi_)
}
return dfi[:], ERROR_NONE
}
+1
View File
@@ -680,6 +680,7 @@ make_directory :: proc(path: string, mode: u32 = 0o775) -> Errno {
}
exit :: proc "contextless" (code: int) -> ! {
runtime._cleanup_runtime_contextless()
_unix_exit(i32(code))
}
+3 -2
View File
@@ -232,10 +232,10 @@ foreign libc {
@(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 ---
@(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 ---
@(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 ---
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
@(link_name="stat64") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int ---
@(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int ---
@(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int ---
@(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
@@ -419,6 +419,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) {
}
exit :: proc "contextless" (code: int) -> ! {
runtime._cleanup_runtime_contextless()
_unix_exit(c.int(code))
}
+1
View File
@@ -802,6 +802,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) {
}
exit :: proc "contextless" (code: int) -> ! {
runtime._cleanup_runtime_contextless()
_unix_exit(c.int(code))
}
+707
View File
@@ -0,0 +1,707 @@
package os
foreign import libc "system:c"
import "core:strings"
import "core:c"
import "core:runtime"
Handle :: distinct i32
Pid :: distinct i32
File_Time :: distinct u64
Errno :: distinct i32
INVALID_HANDLE :: ~Handle(0)
ERROR_NONE: Errno: 0
EPERM: Errno: 1
ENOENT: Errno: 2
ESRCH: Errno: 3
EINTR: Errno: 4
EIO: Errno: 5
ENXIO: Errno: 6
E2BIG: Errno: 7
ENOEXEC: Errno: 8
EBADF: Errno: 9
ECHILD: Errno: 10
EDEADLK: Errno: 11
ENOMEM: Errno: 12
EACCES: Errno: 13
EFAULT: Errno: 14
ENOTBLK: Errno: 15
EBUSY: Errno: 16
EEXIST: Errno: 17
EXDEV: Errno: 18
ENODEV: Errno: 19
ENOTDIR: Errno: 20
EISDIR: Errno: 21
EINVAL: Errno: 22
ENFILE: Errno: 23
EMFILE: Errno: 24
ENOTTY: Errno: 25
ETXTBSY: Errno: 26
EFBIG: Errno: 27
ENOSPC: Errno: 28
ESPIPE: Errno: 29
EROFS: Errno: 30
EMLINK: Errno: 31
EPIPE: Errno: 32
EDOM: Errno: 33
ERANGE: Errno: 34
EAGAIN: Errno: 35
EWOULDBLOCK: Errno: EAGAIN
EINPROGRESS: Errno: 36
EALREADY: Errno: 37
ENOTSOCK: Errno: 38
EDESTADDRREQ: Errno: 39
EMSGSIZE: Errno: 40
EPROTOTYPE: Errno: 41
ENOPROTOOPT: Errno: 42
EPROTONOSUPPORT: Errno: 43
ESOCKTNOSUPPORT: Errno: 44
EOPNOTSUPP: Errno: 45
EPFNOSUPPORT: Errno: 46
EAFNOSUPPORT: Errno: 47
EADDRINUSE: Errno: 48
EADDRNOTAVAIL: Errno: 49
ENETDOWN: Errno: 50
ENETUNREACH: Errno: 51
ENETRESET: Errno: 52
ECONNABORTED: Errno: 53
ECONNRESET: Errno: 54
ENOBUFS: Errno: 55
EISCONN: Errno: 56
ENOTCONN: Errno: 57
ESHUTDOWN: Errno: 58
ETOOMANYREFS: Errno: 59
ETIMEDOUT: Errno: 60
ECONNREFUSED: Errno: 61
ELOOP: Errno: 62
ENAMETOOLONG: Errno: 63
EHOSTDOWN: Errno: 64
EHOSTUNREACH: Errno: 65
ENOTEMPTY: Errno: 66
EPROCLIM: Errno: 67
EUSERS: Errno: 68
EDQUOT: Errno: 69
ESTALE: Errno: 70
EREMOTE: Errno: 71
EBADRPC: Errno: 72
ERPCMISMATCH: Errno: 73
EPROGUNAVAIL: Errno: 74
EPROGMISMATCH: Errno: 75
EPROCUNAVAIL: Errno: 76
ENOLCK: Errno: 77
ENOSYS: Errno: 78
EFTYPE: Errno: 79
EAUTH: Errno: 80
ENEEDAUTH: Errno: 81
EIPSEC: Errno: 82
ENOATTR: Errno: 83
EILSEQ: Errno: 84
ENOMEDIUM: Errno: 85
EMEDIUMTYPE: Errno: 86
EOVERFLOW: Errno: 87
ECANCELED: Errno: 88
EIDRM: Errno: 89
ENOMSG: Errno: 90
ENOTSUP: Errno: 91
EBADMSG: Errno: 92
ENOTRECOVERABLE: Errno: 93
EOWNERDEAD: Errno: 94
EPROTO: Errno: 95
O_RDONLY :: 0x00000
O_WRONLY :: 0x00001
O_RDWR :: 0x00002
O_NONBLOCK :: 0x00004
O_APPEND :: 0x00008
O_ASYNC :: 0x00040
O_SYNC :: 0x00080
O_CREATE :: 0x00200
O_TRUNC :: 0x00400
O_EXCL :: 0x00800
O_NOCTTY :: 0x08000
O_CLOEXEC :: 0x10000
SEEK_SET :: 0
SEEK_CUR :: 1
SEEK_END :: 2
RTLD_LAZY :: 0x001
RTLD_NOW :: 0x002
RTLD_LOCAL :: 0x000
RTLD_GLOBAL :: 0x100
RTLD_TRACE :: 0x200
RTLD_NODELETE :: 0x400
MAX_PATH :: 1024
// "Argv" arguments converted to Odin strings
args := _alloc_command_line_arguments()
pid_t :: i32
time_t :: i64
mode_t :: u32
dev_t :: i32
ino_t :: u64
nlink_t :: u32
uid_t :: u32
gid_t :: u32
off_t :: i64
blkcnt_t :: u64
blksize_t :: i32
Unix_File_Time :: struct {
seconds: time_t,
nanoseconds: c.long,
}
OS_Stat :: struct {
mode: mode_t, // inode protection mode
device_id: dev_t, // inode's device
serial: ino_t, // inode's number
nlink: nlink_t, // number of hard links
uid: uid_t, // user ID of the file's owner
gid: gid_t, // group ID of the file's group
rdev: dev_t, // device type
last_access: Unix_File_Time, // time of last access
modified: Unix_File_Time, // time of last data modification
status_change: Unix_File_Time, // time of last file status change
size: off_t, // file size, in bytes
blocks: blkcnt_t, // blocks allocated for file
block_size: blksize_t, // optimal blocksize for I/O
flags: u32, // user defined flags for file
gen: u32, // file generation number
birthtime: Unix_File_Time, // time of file creation
}
MAXNAMLEN :: 255
// NOTE(laleksic, 2021-01-21): Comment and rename these to match OS_Stat above
Dirent :: struct {
ino: ino_t, // file number of entry
off: off_t, // offset after this entry
reclen: u16, // length of this record
type: u8, // file type
namlen: u8, // length of string in name
_padding: [4]u8,
name: [MAXNAMLEN + 1]byte, // name
}
Dir :: distinct rawptr // DIR*
// File type
S_IFMT :: 0o170000 // Type of file mask
S_IFIFO :: 0o010000 // Named pipe (fifo)
S_IFCHR :: 0o020000 // Character special
S_IFDIR :: 0o040000 // Directory
S_IFBLK :: 0o060000 // Block special
S_IFREG :: 0o100000 // Regular
S_IFLNK :: 0o120000 // Symbolic link
S_IFSOCK :: 0o140000 // Socket
S_ISVTX :: 0o001000 // Save swapped text even after use
// File mode
// Read, write, execute/search by owner
S_IRWXU :: 0o0700 // RWX mask for owner
S_IRUSR :: 0o0400 // R for owner
S_IWUSR :: 0o0200 // W for owner
S_IXUSR :: 0o0100 // X for owner
// Read, write, execute/search by group
S_IRWXG :: 0o0070 // RWX mask for group
S_IRGRP :: 0o0040 // R for group
S_IWGRP :: 0o0020 // W for group
S_IXGRP :: 0o0010 // X for group
// Read, write, execute/search by others
S_IRWXO :: 0o0007 // RWX mask for other
S_IROTH :: 0o0004 // R for other
S_IWOTH :: 0o0002 // W for other
S_IXOTH :: 0o0001 // X for other
S_ISUID :: 0o4000 // Set user id on execution
S_ISGID :: 0o2000 // Set group id on execution
S_ISTXT :: 0o1000 // Sticky bit
S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK }
S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG }
S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR }
S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR }
S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK }
S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO }
S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK }
F_OK :: 0x00 // Test for file existance
X_OK :: 0x01 // Test for execute permission
W_OK :: 0x02 // Test for write permission
R_OK :: 0x04 // Test for read permission
AT_FDCWD :: -100
AT_EACCESS :: 0x01
AT_SYMLINK_NOFOLLOW :: 0x02
AT_SYMLINK_FOLLOW :: 0x04
AT_REMOVEDIR :: 0x08
@(default_calling_convention="c")
foreign libc {
@(link_name="__errno") __errno :: proc() -> ^int ---
@(link_name="fork") _unix_fork :: proc() -> pid_t ---
@(link_name="getthrid") _unix_getthrid :: proc() -> int ---
@(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 ---
@(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: off_t, whence: c.int) -> off_t ---
@(link_name="stat") _unix_stat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
@(link_name="fstat") _unix_fstat :: proc(fd: Handle, sb: ^OS_Stat) -> c.int ---
@(link_name="lstat") _unix_lstat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
@(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
@(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
@(link_name="chdir") _unix_chdir :: proc(path: cstring) -> c.int ---
@(link_name="rename") _unix_rename :: proc(old, new: cstring) -> c.int ---
@(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int ---
@(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int ---
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
@(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
@(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---
@(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
}
is_path_separator :: proc(r: rune) -> bool {
return r == '/'
}
get_last_error :: proc() -> int {
return __errno()^
}
fork :: proc() -> (Pid, Errno) {
pid := _unix_fork()
if pid == -1 {
return Pid(-1), Errno(get_last_error())
}
return Pid(pid), ERROR_NONE
}
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
cstr := strings.clone_to_cstring(path, context.temp_allocator)
handle := _unix_open(cstr, c.int(flags), c.int(mode))
if handle == -1 {
return INVALID_HANDLE, Errno(get_last_error())
}
return handle, ERROR_NONE
}
close :: proc(fd: Handle) -> Errno {
result := _unix_close(fd)
if result == -1 {
return Errno(get_last_error())
}
return ERROR_NONE
}
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
bytes_read := _unix_read(fd, &data[0], c.size_t(len(data)))
if bytes_read == -1 {
return -1, Errno(get_last_error())
}
return int(bytes_read), ERROR_NONE
}
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE
}
bytes_written := _unix_write(fd, &data[0], c.size_t(len(data)))
if bytes_written == -1 {
return -1, Errno(get_last_error())
}
return int(bytes_written), ERROR_NONE
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
res := _unix_seek(fd, offset, c.int(whence))
if res == -1 {
return -1, Errno(get_last_error())
}
return res, ERROR_NONE
}
file_size :: proc(fd: Handle) -> (i64, Errno) {
s, err := _fstat(fd)
if err != ERROR_NONE {
return -1, err
}
return s.size, ERROR_NONE
}
rename :: proc(old_path, new_path: string) -> Errno {
old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator)
new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator)
res := _unix_rename(old_path_cstr, new_path_cstr)
if res == -1 {
return Errno(get_last_error())
}
return ERROR_NONE
}
remove :: proc(path: string) -> Errno {
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
res := _unix_unlink(path_cstr)
if res == -1 {
return Errno(get_last_error())
}
return ERROR_NONE
}
make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno {
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
res := _unix_mkdir(path_cstr, mode)
if res == -1 {
return Errno(get_last_error())
}
return ERROR_NONE
}
remove_directory :: proc(path: string) -> Errno {
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
res := _unix_rmdir(path_cstr)
if res == -1 {
return Errno(get_last_error())
}
return ERROR_NONE
}
is_file_handle :: proc(fd: Handle) -> bool {
s, err := _fstat(fd)
if err != ERROR_NONE {
return false
}
return S_ISREG(s.mode)
}
is_file_path :: proc(path: string, follow_links: bool = true) -> bool {
s: OS_Stat
err: Errno
if follow_links {
s, err = _stat(path)
} else {
s, err = _lstat(path)
}
if err != ERROR_NONE {
return false
}
return S_ISREG(s.mode)
}
is_dir_handle :: proc(fd: Handle) -> bool {
s, err := _fstat(fd)
if err != ERROR_NONE {
return false
}
return S_ISDIR(s.mode)
}
is_dir_path :: proc(path: string, follow_links: bool = true) -> bool {
s: OS_Stat
err: Errno
if follow_links {
s, err = _stat(path)
} else {
s, err = _lstat(path)
}
if err != ERROR_NONE {
return false
}
return S_ISDIR(s.mode)
}
is_file :: proc {is_file_path, is_file_handle}
is_dir :: proc {is_dir_path, is_dir_handle}
// NOTE(bill): Uses startup to initialize it
stdin: Handle = 0
stdout: Handle = 1
stderr: Handle = 2
/* TODO(zangent): Implement these!
last_write_time :: proc(fd: Handle) -> File_Time {}
last_write_time_by_name :: proc(name: string) -> File_Time {}
*/
last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
s, err := _fstat(fd)
if err != ERROR_NONE {
return 0, err
}
modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds
return File_Time(modified), ERROR_NONE
}
last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
s, err := _stat(name)
if err != ERROR_NONE {
return 0, err
}
modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds
return File_Time(modified), ERROR_NONE
}
@private
_stat :: proc(path: string) -> (OS_Stat, Errno) {
cstr := strings.clone_to_cstring(path, context.temp_allocator)
// deliberately uninitialized
s: OS_Stat = ---
res := _unix_stat(cstr, &s)
if res == -1 {
return s, Errno(get_last_error())
}
return s, ERROR_NONE
}
@private
_lstat :: proc(path: string) -> (OS_Stat, Errno) {
cstr := strings.clone_to_cstring(path, context.temp_allocator)
// deliberately uninitialized
s: OS_Stat = ---
res := _unix_lstat(cstr, &s)
if res == -1 {
return s, Errno(get_last_error())
}
return s, ERROR_NONE
}
@private
_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
// deliberately uninitialized
s: OS_Stat = ---
res := _unix_fstat(fd, &s)
if res == -1 {
return s, Errno(get_last_error())
}
return s, ERROR_NONE
}
@private
_fdopendir :: proc(fd: Handle) -> (Dir, Errno) {
dirp := _unix_fdopendir(fd)
if dirp == cast(Dir)nil {
return nil, Errno(get_last_error())
}
return dirp, ERROR_NONE
}
@private
_closedir :: proc(dirp: Dir) -> Errno {
rc := _unix_closedir(dirp)
if rc != 0 {
return Errno(get_last_error())
}
return ERROR_NONE
}
@private
_rewinddir :: proc(dirp: Dir) {
_unix_rewinddir(dirp)
}
@private
_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) {
result: ^Dirent
rc := _unix_readdir_r(dirp, &entry, &result)
if rc != 0 {
err = Errno(get_last_error())
return
}
err = ERROR_NONE
if result == nil {
end_of_stream = true
return
}
return
}
@private
_readlink :: proc(path: string) -> (string, Errno) {
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
bufsz : uint = MAX_PATH
buf := make([]byte, MAX_PATH)
for {
rc := _unix_readlink(path_cstr, &(buf[0]), bufsz)
if rc == -1 {
delete(buf)
return "", Errno(get_last_error())
} else if rc == int(bufsz) {
bufsz += MAX_PATH
delete(buf)
buf = make([]byte, bufsz)
} else {
return strings.string_from_ptr(&buf[0], rc), ERROR_NONE
}
}
unreachable()
}
// XXX OpenBSD
absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) {
return "", Errno(ENOSYS)
}
absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
rel := rel
if rel == "" {
rel = "."
}
rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
path_ptr := _unix_realpath(rel_cstr, nil)
if path_ptr == nil {
return "", Errno(get_last_error())
}
defer _unix_free(path_ptr)
path_cstr := transmute(cstring)path_ptr
path = strings.clone( string(path_cstr) )
return path, ERROR_NONE
}
access :: proc(path: string, mask: int) -> (bool, Errno) {
cstr := strings.clone_to_cstring(path, context.temp_allocator)
res := _unix_access(cstr, c.int(mask))
if res == -1 {
return false, Errno(get_last_error())
}
return true, ERROR_NONE
}
heap_alloc :: proc(size: int) -> rawptr {
assert(size >= 0)
return _unix_calloc(1, c.size_t(size))
}
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
// NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on
// POSIX platforms. Ensure your caller takes this into account.
return _unix_realloc(ptr, c.size_t(new_size))
}
heap_free :: proc(ptr: rawptr) {
_unix_free(ptr)
}
getenv :: proc(name: string) -> (string, bool) {
path_str := strings.clone_to_cstring(name, context.temp_allocator)
cstr := _unix_getenv(path_str)
if cstr == nil {
return "", false
}
return string(cstr), true
}
get_current_directory :: proc() -> string {
buf := make([dynamic]u8, MAX_PATH)
for {
cwd := _unix_getcwd(cstring(raw_data(buf)), c.size_t(len(buf)))
if cwd != nil {
return string(cwd)
}
if Errno(get_last_error()) != ERANGE {
return ""
}
resize(&buf, len(buf) + MAX_PATH)
}
unreachable()
}
set_current_directory :: proc(path: string) -> (err: Errno) {
cstr := strings.clone_to_cstring(path, context.temp_allocator)
res := _unix_chdir(cstr)
if res == -1 {
return Errno(get_last_error())
}
return ERROR_NONE
}
exit :: proc "contextless" (code: int) -> ! {
runtime._cleanup_runtime_contextless()
_unix_exit(c.int(code))
}
current_thread_id :: proc "contextless" () -> int {
return _unix_getthrid()
}
dlopen :: proc(filename: string, flags: int) -> rawptr {
cstr := strings.clone_to_cstring(filename, context.temp_allocator)
handle := _unix_dlopen(cstr, c.int(flags))
return handle
}
dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
assert(handle != nil)
cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
proc_handle := _unix_dlsym(handle, cstr)
return proc_handle
}
dlclose :: proc(handle: rawptr) -> bool {
assert(handle != nil)
return _unix_dlclose(handle) == 0
}
dlerror :: proc() -> string {
return string(_unix_dlerror())
}
get_page_size :: proc() -> int {
// NOTE(tetra): The page size never changes, so why do anything complicated
// if we don't have to.
@static page_size := -1
if page_size != -1 {
return page_size
}
page_size = int(_unix_getpagesize())
return page_size
}
_alloc_command_line_arguments :: proc() -> []string {
res := make([]string, len(runtime.args__))
for arg, i in runtime.args__ {
res[i] = string(arg)
}
return res
}
+2
View File
@@ -1,6 +1,7 @@
package os
import "core:sys/wasm/wasi"
import "core:runtime"
Handle :: distinct i32
Errno :: distinct i32
@@ -93,5 +94,6 @@ heap_free :: proc(ptr: rawptr) {
exit :: proc "contextless" (code: int) -> ! {
runtime._cleanup_runtime_contextless()
wasi.proc_exit(wasi.exitcode_t(code))
}
+2
View File
@@ -2,6 +2,7 @@
package os
import win32 "core:sys/windows"
import "core:runtime"
Handle :: distinct uintptr
File_Time :: distinct u64
@@ -128,6 +129,7 @@ get_page_size :: proc() -> int {
exit :: proc "contextless" (code: int) -> ! {
runtime._cleanup_runtime_contextless()
win32.ExitProcess(win32.DWORD(code))
}
+1 -1
View File
@@ -1,4 +1,4 @@
//+build linux, darwin, freebsd
//+build linux, darwin, openbsd
package os
import "core:time"
+10 -33
View File
@@ -132,26 +132,11 @@ cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
@(private)
cleanpath_from_handle :: proc(fd: Handle) -> (string, Errno) {
if fd == 0 {
return "", ERROR_INVALID_HANDLE
buf, err := cleanpath_from_handle_u16(fd)
if err != 0 {
return "", err
}
h := win32.HANDLE(fd)
MAX_PATH := win32.DWORD(260) + 1
buf: []u16
for {
buf = make([]u16, MAX_PATH, context.temp_allocator)
err := win32.GetFinalPathNameByHandleW(h, raw_data(buf), MAX_PATH, 0)
switch Errno(err) {
case ERROR_PATH_NOT_FOUND, ERROR_INVALID_PARAMETER:
return "", Errno(err)
case ERROR_NOT_ENOUGH_MEMORY:
MAX_PATH = MAX_PATH*2 + 1
continue
}
break
}
return cleanpath_from_buf(buf), ERROR_NONE
return win32.utf16_to_utf8(buf, context.allocator), err
}
@(private)
cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) {
@@ -160,21 +145,13 @@ cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) {
}
h := win32.HANDLE(fd)
MAX_PATH := win32.DWORD(260) + 1
buf: []u16
for {
buf = make([]u16, MAX_PATH, context.temp_allocator)
err := win32.GetFinalPathNameByHandleW(h, raw_data(buf), MAX_PATH, 0)
switch Errno(err) {
case ERROR_PATH_NOT_FOUND, ERROR_INVALID_PARAMETER:
return nil, Errno(err)
case ERROR_NOT_ENOUGH_MEMORY:
MAX_PATH = MAX_PATH*2 + 1
continue
}
break
n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0)
if n == 0 {
return nil, Errno(win32.GetLastError())
}
return cleanpath_strip_prefix(buf), ERROR_NONE
buf := make([]u16, max(n, win32.DWORD(260))+1, context.temp_allocator)
buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0)
return buf[:buf_len], ERROR_NONE
}
@(private)
cleanpath_from_buf :: proc(buf: []u16) -> string {
+6 -1
View File
@@ -1,4 +1,4 @@
//+build linux, darwin, freebsd
//+build linux, darwin, freebsd, openbsd
package filepath
when ODIN_OS == .Darwin {
@@ -59,6 +59,11 @@ when ODIN_OS == .Darwin {
foreign libc {
@(link_name="__error") __error :: proc() -> ^i32 ---
}
} else when ODIN_OS == .OpenBSD {
@(private)
foreign libc {
@(link_name="__errno") __error :: proc() -> ^i32 ---
}
} else {
@(private)
foreign libc {
+13 -1
View File
@@ -365,6 +365,19 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any {
return nil
}
deref :: proc(val: any) -> any {
if val != nil {
ti := type_info_base(type_info_of(val.id))
if info, ok := ti.variant.(Type_Info_Pointer); ok {
return any{
(^rawptr)(val.data)^,
info.elem.id,
}
}
}
return val
}
// Struct_Tag represents the type of the string of a struct field
@@ -680,7 +693,6 @@ union_variant_typeid :: proc(a: any) -> typeid {
return nil
}
panic("expected a union to reflect.union_variant_typeid")
}
get_union_variant_raw_tag :: proc(a: any) -> i64 {
+5
View File
@@ -459,6 +459,11 @@ _cleanup_runtime :: proc() {
default_temp_allocator_destroy(&global_default_temp_allocator_data)
}
_cleanup_runtime_contextless :: proc "contextless" () {
context = default_context()
_cleanup_runtime()
}
/////////////////////////////
/////////////////////////////
+1 -1
View File
@@ -1,5 +1,5 @@
//+private
//+build linux, darwin, freebsd
//+build linux, darwin, freebsd, openbsd
package runtime
import "core:intrinsics"
+96 -5
View File
@@ -304,7 +304,7 @@ filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) -
return r[:]
}
scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U)->V, allocator := context.allocator) -> []V {
scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := context.allocator) -> []V {
if len(s) == 0 { return {} }
res := make([]V, len(s), allocator)
@@ -344,15 +344,106 @@ max :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T
return
}
min_max :: proc(s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_ordered(T) {
if len(s) != 0 {
min, max = s[0], s[0]
ok = true
for v in s[1:] {
min = builtin.min(min, v)
max = builtin.max(max, v)
}
}
return
}
dot_product :: proc(a, b: $S/[]$T) -> T
any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) {
for v in s {
if v == value {
return true
}
}
return false
}
none_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) {
for v in s {
if v == value {
return false
}
}
return true
}
all_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) {
if len(s) == 0 {
return false
}
for v in s {
if v != value {
return false
}
}
return true
}
any_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
for v in s {
if f(v) {
return true
}
}
return false
}
none_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
for v in s {
if f(v) {
return false
}
}
return true
}
all_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
if len(s) == 0 {
return false
}
for v in s {
if !f(v) {
return false
}
}
return true
}
count :: proc(s: $S/[]$T, value: T) -> (n: int) where intrinsics.type_is_comparable(T) {
for v in s {
if v == value {
n += 1
}
}
return
}
count_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> (n: int) {
for v in s {
if f(v) {
n += 1
}
}
return
}
dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool)
where intrinsics.type_is_numeric(T) {
if len(a) != len(b) {
panic("slice.dot_product: slices of unequal length")
return
}
r: T
#no_bounds_check for _, i in a {
r += a[i] * b[i]
}
return r
return r, true
}
+1
View File
@@ -895,6 +895,7 @@ unquote_string :: proc(lit: string, allocator := context.allocator) -> (res: str
if s == `""` {
return "", false, true
}
s = s[1:len(s)-1]
if contains_rune(s, '\n') >= 0 {
return s, false, false
+1 -1
View File
@@ -1,4 +1,4 @@
// +build linux, darwin, freebsd
// +build linux, darwin, freebsd, openbsd
package sync
import "core:time"
+78
View File
@@ -0,0 +1,78 @@
//+private
//+build openbsd
package sync2
import "core:c"
import "core:os"
import "core:time"
FUTEX_WAIT :: 1
FUTEX_WAKE :: 2
FUTEX_PRIVATE_FLAG :: 128
FUTEX_WAIT_PRIVATE :: (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
FUTEX_WAKE_PRIVATE :: (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
foreign import libc "system:c"
foreign libc {
@(link_name="futex")
_unix_futex :: proc "c" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> c.int ---
}
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, nil)
if res != -1 {
return true
}
if os.Errno(os.get_last_error()) == os.ETIMEDOUT {
return false
}
panic("futex_wait failure")
}
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
if duration <= 0 {
return false
}
timespec_t :: struct {
tv_sec: c.long,
tv_nsec: c.long,
}
res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, &timespec_t{
tv_sec = (c.long)(duration/1e9),
tv_nsec = (c.long)(duration%1e9),
})
if res != -1 {
return true
}
if os.Errno(os.get_last_error()) == os.ETIMEDOUT {
return false
}
panic("futex_wait_with_timeout failure")
}
_futex_signal :: proc(f: ^Futex) {
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, 1, nil)
if res == -1 {
panic("futex_wake_single failure")
}
}
_futex_broadcast :: proc(f: ^Futex) {
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, u32(max(i32)), nil)
if res == -1 {
panic("_futex_wake_all failure")
}
}
+1 -1
View File
@@ -11,7 +11,7 @@ current_thread_id :: proc "contextless" () -> int {
//
// A Mutex must not be copied after first use
Mutex :: struct {
impl: _Mutex `This is a tag`,
impl: _Mutex,
}
// mutex_lock locks m
+9
View File
@@ -0,0 +1,9 @@
//+build openbsd
//+private
package sync2
import "core:os"
_current_thread_id :: proc "contextless" () -> int {
return os.current_thread_id()
}
+1 -1
View File
@@ -1,4 +1,4 @@
//+build linux, freebsd
//+build linux, freebsd, openbsd
//+private
package sync2
+36
View File
@@ -0,0 +1,36 @@
package sync
import "core:sys/unix"
import "core:os"
current_thread_id :: proc "contextless" () -> int {
return os.current_thread_id()
}
// The Darwin docs say it best:
// A semaphore is much like a lock, except that a finite number of threads can hold it simultaneously.
// Semaphores can be thought of as being much like piles of tokens; multiple threads can take these tokens,
// but when there are none left, a thread must wait until another thread returns one.
Semaphore :: struct #align 16 {
handle: unix.sem_t,
}
semaphore_init :: proc(s: ^Semaphore, initial_count := 0) {
assert(unix.sem_init(&s.handle, 0, u32(initial_count)) == 0)
}
semaphore_destroy :: proc(s: ^Semaphore) {
assert(unix.sem_destroy(&s.handle) == 0)
s.handle = {}
}
semaphore_post :: proc(s: ^Semaphore, count := 1) {
// NOTE: SPEED: If there's one syscall to do this, we should use it instead of the loop.
for in 0..<count {
assert(unix.sem_post(&s.handle) == 0)
}
}
semaphore_wait_for :: proc(s: ^Semaphore) {
assert(unix.sem_wait(&s.handle) == 0)
}
+1 -1
View File
@@ -1,4 +1,4 @@
// +build linux, darwin, freebsd
// +build linux, darwin, freebsd, openbsd
package sync
import "core:sys/unix"
+65
View File
@@ -0,0 +1,65 @@
//+build openbsd
package unix
import "core:c"
pthread_t :: distinct rawptr
pthread_attr_t :: distinct rawptr
pthread_mutex_t :: distinct rawptr
pthread_mutexattr_t :: distinct rawptr
pthread_cond_t :: distinct rawptr
pthread_condattr_t :: distinct rawptr
pthread_rwlock_t :: distinct rawptr
pthread_rwlockattr_t :: distinct rawptr
pthread_barrier_t :: distinct rawptr
pthread_barrierattr_t :: distinct rawptr
pthread_spinlock_t :: distinct rawptr
pthread_key_t :: distinct c.int
pthread_once_t :: struct {
state: c.int,
mutex: pthread_mutex_t,
}
PTHREAD_MUTEX_ERRORCHECK :: 1
PTHREAD_MUTEX_RECURSIVE :: 2
PTHREAD_MUTEX_NORMAL :: 3
PTHREAD_MUTEX_STRICT_NP :: 4
PTHREAD_DETACHED :: 0x1
PTHREAD_SCOPE_SYSTEM :: 0x2
PTHREAD_INHERIT_SCHED :: 0x4
PTHREAD_NOFLOAT :: 0x8
PTHREAD_CREATE_DETACHED :: PTHREAD_DETACHED
PTHREAD_CREATE_JOINABLE :: 0
PTHREAD_SCOPE_PROCESS :: 0
PTHREAD_EXPLICIT_SCHED :: 0
SCHED_FIFO :: 1
SCHED_OTHER :: 2
SCHED_RR :: 3
sched_param :: struct {
sched_priority: c.int,
}
sem_t :: distinct rawptr
foreign import libc "system:c"
@(default_calling_convention="c")
foreign libc {
sem_open :: proc(name: cstring, flags: c.int) -> ^sem_t ---
sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int ---
sem_destroy :: proc(sem: ^sem_t) -> c.int ---
sem_post :: proc(sem: ^sem_t) -> c.int ---
sem_wait :: proc(sem: ^sem_t) -> c.int ---
sem_trywait :: proc(sem: ^sem_t) -> c.int ---
//sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int ---
// NOTE: unclear whether pthread_yield is well-supported on Linux systems,
// see https://linux.die.net/man/3/pthread_yield
pthread_yield :: proc() ---
}
+1 -1
View File
@@ -1,4 +1,4 @@
//+build linux, darwin, freebsd
//+build linux, darwin, freebsd, openbsd
package unix
foreign import "system:pthread"
+1 -1
View File
@@ -1,4 +1,4 @@
// +build linux, darwin, freebsd
// +build linux, darwin, freebsd, openbsd
// +private
package thread
+23 -11
View File
@@ -1,4 +1,4 @@
//+build linux, darwin, freebsd
//+build linux, darwin, freebsd, openbsd
package time
IS_SUPPORTED :: true // NOTE: Times on Darwin are UTC.
@@ -22,16 +22,28 @@ TimeSpec :: struct {
tv_nsec : i64, /* nanoseconds */
}
CLOCK_REALTIME :: 0 // NOTE(tetra): May jump in time, when user changes the system time.
CLOCK_MONOTONIC :: 1 // NOTE(tetra): May stand still while system is asleep.
CLOCK_PROCESS_CPUTIME_ID :: 2
CLOCK_THREAD_CPUTIME_ID :: 3
CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP.
CLOCK_REALTIME_COARSE :: 5 // NOTE(tetra): "COARSE" clocks are apparently much faster, but not "fine-grained."
CLOCK_MONOTONIC_COARSE :: 6
CLOCK_BOOTTIME :: 7 // NOTE(tetra): Same as MONOTONIC, except also including time system was asleep.
CLOCK_REALTIME_ALARM :: 8
CLOCK_BOOTTIME_ALARM :: 9
when ODIN_OS == .OpenBSD {
CLOCK_REALTIME :: 0
CLOCK_PROCESS_CPUTIME_ID :: 2
CLOCK_MONOTONIC :: 3
CLOCK_THREAD_CPUTIME_ID :: 4
CLOCK_UPTIME :: 5
CLOCK_BOOTTIME :: 6
// CLOCK_MONOTONIC_RAW doesn't exist, use CLOCK_MONOTONIC
CLOCK_MONOTONIC_RAW :: CLOCK_MONOTONIC
} else {
CLOCK_REALTIME :: 0 // NOTE(tetra): May jump in time, when user changes the system time.
CLOCK_MONOTONIC :: 1 // NOTE(tetra): May stand still while system is asleep.
CLOCK_PROCESS_CPUTIME_ID :: 2
CLOCK_THREAD_CPUTIME_ID :: 3
CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP.
CLOCK_REALTIME_COARSE :: 5 // NOTE(tetra): "COARSE" clocks are apparently much faster, but not "fine-grained."
CLOCK_MONOTONIC_COARSE :: 6
CLOCK_BOOTTIME :: 7 // NOTE(tetra): Same as MONOTONIC, except also including time system was asleep.
CLOCK_REALTIME_ALARM :: 8
CLOCK_BOOTTIME_ALARM :: 9
}
// TODO(tetra, 2019-11-05): The original implementation of this package for Darwin used this constants.
// I do not know if Darwin programmers are used to the existance of these constants or not, so
+2
View File
@@ -54,6 +54,7 @@ import base64 "core:encoding/base64"
import csv "core:encoding/csv"
import hxa "core:encoding/hxa"
import json "core:encoding/json"
import varint "core:encoding/varint"
import fmt "core:fmt"
import hash "core:hash"
@@ -153,6 +154,7 @@ _ :: base64
_ :: csv
_ :: hxa
_ :: json
_ :: varint
_ :: fmt
_ :: hash
_ :: image
+1 -22
View File
@@ -1,4 +1,3 @@
//+build windows
package all
import botan "vendor:botan"
@@ -16,24 +15,12 @@ import IMG "vendor:sdl2/image"
import MIX "vendor:sdl2/mixer"
import TTF "vendor:sdl2/ttf"
import stb_easy_font "vendor:stb/easy_font"
import stbi "vendor:stb/image"
import stbrp "vendor:stb/rect_pack"
import stbtt "vendor:stb/truetype"
import stb_vorbis "vendor:stb/vorbis"
import vk "vendor:vulkan"
import D3D11 "vendor:directx/d3d11"
import D3D12 "vendor:directx/d3d12"
import DXGI "vendor:directx/dxgi"
// note these are technicaly darwin only but they are added to aid with documentation generation
import NS "vendor:darwin/Foundation"
import MTL "vendor:darwin/Metal"
import CA "vendor:darwin/QuartzCore"
_ :: botan
_ :: ENet
_ :: gl
@@ -47,15 +34,7 @@ _ :: SDLNet
_ :: IMG
_ :: MIX
_ :: TTF
_ :: stb_easy_font
_ :: stbi
_ :: stbrp
_ :: stbtt
_ :: stb_vorbis
_ :: vk
_ :: D3D11
_ :: D3D12
_ :: DXGI
_ :: NS
_ :: MTL
_ :: CA
_ :: CA
+10
View File
@@ -0,0 +1,10 @@
//+build windows
package all
import D3D11 "vendor:directx/d3d11"
import D3D12 "vendor:directx/d3d12"
import DXGI "vendor:directx/dxgi"
_ :: D3D11
_ :: D3D12
_ :: DXGI
+15
View File
@@ -0,0 +1,15 @@
//+build windows, linux
package all
import stb_easy_font "vendor:stb/easy_font"
import stbi "vendor:stb/image"
import stbrp "vendor:stb/rect_pack"
import stbtt "vendor:stb/truetype"
import stb_vorbis "vendor:stb/vorbis"
_ :: stb_easy_font
_ :: stbi
_ :: stbrp
_ :: stbtt
_ :: stb_vorbis
+22 -1
View File
@@ -17,6 +17,11 @@
#include <sys/sysctl.h>
#endif
#if defined(GB_SYSTEM_OPENBSD)
#include <sys/sysctl.h>
#include <sys/utsname.h>
#endif
/*
NOTE(Jeroen): This prints the Windows product edition only, to be called from `print_platform_details`.
*/
@@ -242,6 +247,14 @@ void report_ram_info() {
if (sysctl(sysctls, 2, &ram_amount, &val_size, NULL, 0) != -1) {
gb_printf("%lld MiB\n", ram_amount / gb_megabytes(1));
}
#elif defined(GB_SYSTEM_OPENBSD)
uint64_t ram_amount;
size_t val_size = sizeof(ram_amount);
int sysctls[] = { CTL_HW, HW_PHYSMEM64 };
if (sysctl(sysctls, 2, &ram_amount, &val_size, NULL, 0) != -1) {
gb_printf("%lld MiB\n", ram_amount / gb_megabytes(1));
}
#else
gb_printf("Unknown.\n");
#endif
@@ -643,6 +656,14 @@ void print_bug_report_help() {
} else {
gb_printf("macOS: Unknown\n");
}
#elif defined(GB_SYSTEM_OPENBSD)
struct utsname un;
if (uname(&un) != -1) {
gb_printf("%s %s %s %s\n", un.sysname, un.release, un.version, un.machine);
} else {
gb_printf("OpenBSD: Unknown\n");
}
#else
gb_printf("Unknown\n");
@@ -657,4 +678,4 @@ void print_bug_report_help() {
And RAM info.
*/
report_ram_info();
}
}
+57 -12
View File
@@ -1,4 +1,4 @@
#if defined(GB_SYSTEM_FREEBSD)
#if defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD)
#include <sys/types.h>
#include <sys/sysctl.h>
#endif
@@ -16,6 +16,7 @@ enum TargetOsKind : u16 {
TargetOs_linux,
TargetOs_essence,
TargetOs_freebsd,
TargetOs_openbsd,
TargetOs_wasi,
TargetOs_js,
@@ -63,6 +64,7 @@ String target_os_names[TargetOs_COUNT] = {
str_lit("linux"),
str_lit("essence"),
str_lit("freebsd"),
str_lit("openbsd"),
str_lit("wasi"),
str_lit("js"),
@@ -310,7 +312,7 @@ bool global_ignore_warnings(void) {
}
gb_global TargetMetrics target_windows_386 = {
gb_global TargetMetrics target_windows_i386 = {
TargetOs_windows,
TargetArch_i386,
4,
@@ -326,7 +328,7 @@ gb_global TargetMetrics target_windows_amd64 = {
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
};
gb_global TargetMetrics target_linux_386 = {
gb_global TargetMetrics target_linux_i386 = {
TargetOs_linux,
TargetArch_i386,
4,
@@ -369,7 +371,7 @@ gb_global TargetMetrics target_darwin_arm64 = {
str_lit("e-m:o-i64:64-i128:128-n32:64-S128"), // TODO(bill): Is this correct?
};
gb_global TargetMetrics target_freebsd_386 = {
gb_global TargetMetrics target_freebsd_i386 = {
TargetOs_freebsd,
TargetArch_i386,
4,
@@ -386,6 +388,15 @@ gb_global TargetMetrics target_freebsd_amd64 = {
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
};
gb_global TargetMetrics target_openbsd_amd64 = {
TargetOs_openbsd,
TargetArch_amd64,
8,
16,
str_lit("x86_64-unknown-openbsd-elf"),
str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"),
};
gb_global TargetMetrics target_essence_amd64 = {
TargetOs_essence,
TargetArch_amd64,
@@ -452,13 +463,14 @@ gb_global NamedTargetMetrics named_targets[] = {
{ str_lit("darwin_amd64"), &target_darwin_amd64 },
{ str_lit("darwin_arm64"), &target_darwin_arm64 },
{ str_lit("essence_amd64"), &target_essence_amd64 },
{ str_lit("linux_386"), &target_linux_386 },
{ str_lit("linux_i386"), &target_linux_i386 },
{ str_lit("linux_amd64"), &target_linux_amd64 },
{ str_lit("linux_arm64"), &target_linux_arm64 },
{ str_lit("windows_386"), &target_windows_386 },
{ str_lit("windows_i386"), &target_windows_i386 },
{ str_lit("windows_amd64"), &target_windows_amd64 },
{ str_lit("freebsd_386"), &target_freebsd_386 },
{ str_lit("freebsd_i386"), &target_freebsd_i386 },
{ str_lit("freebsd_amd64"), &target_freebsd_amd64 },
{ str_lit("openbsd_amd64"), &target_openbsd_amd64 },
{ str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
{ str_lit("wasi_wasm32"), &target_wasi_wasm32 },
{ str_lit("js_wasm32"), &target_js_wasm32 },
@@ -765,10 +777,38 @@ String internal_odin_root_dir(void) {
len = readlink("/proc/curproc/exe", &path_buf[0], path_buf.count);
#elif defined(GB_SYSTEM_DRAGONFLYBSD)
len = readlink("/proc/curproc/file", &path_buf[0], path_buf.count);
#else
#elif defined(GB_SYSTEM_LINUX)
len = readlink("/proc/self/exe", &path_buf[0], path_buf.count);
#elif defined(GB_SYSTEM_OPENBSD)
int error;
int mib[] = {
CTL_KERN,
KERN_PROC_ARGS,
getpid(),
KERN_PROC_ARGV,
};
// get argv size
error = sysctl(mib, 4, NULL, (size_t *) &len, NULL, 0);
if (error == -1) {
// sysctl error
return make_string(nullptr, 0);
}
// get argv
char **argv = (char **)gb_malloc(len);
error = sysctl(mib, 4, argv, (size_t *) &len, NULL, 0);
if (error == -1) {
// sysctl error
gb_mfree(argv);
return make_string(nullptr, 0);
}
// copy argv[0] to path_buf
len = gb_strlen(argv[0]);
if(len < path_buf.count) {
gb_memmove(&path_buf[0], argv[0], len);
}
gb_mfree(argv);
#endif
if(len == 0) {
if(len == 0 || len == -1) {
return make_string(nullptr, 0);
}
if (len < path_buf.count) {
@@ -964,6 +1004,8 @@ void init_build_context(TargetMetrics *cross_target) {
#endif
#elif defined(GB_SYSTEM_FREEBSD)
metrics = &target_freebsd_amd64;
#elif defined(GB_SYSTEM_OPENBSD)
metrics = &target_openbsd_amd64;
#elif defined(GB_CPU_ARM)
metrics = &target_linux_arm64;
#else
@@ -971,13 +1013,13 @@ void init_build_context(TargetMetrics *cross_target) {
#endif
#else
#if defined(GB_SYSTEM_WINDOWS)
metrics = &target_windows_386;
metrics = &target_windows_i386;
#elif defined(GB_SYSTEM_OSX)
#error "Build Error: Unsupported architecture"
#elif defined(GB_SYSTEM_FREEBSD)
metrics = &target_freebsd_386;
metrics = &target_freebsd_i386;
#else
metrics = &target_linux_386;
metrics = &target_linux_i386;
#endif
#endif
@@ -1037,6 +1079,9 @@ void init_build_context(TargetMetrics *cross_target) {
case TargetOs_freebsd:
bc->link_flags = str_lit("-arch x86-64 ");
break;
case TargetOs_openbsd:
bc->link_flags = str_lit("-arch x86-64 ");
break;
}
} else if (bc->metrics.arch == TargetArch_i386) {
switch (bc->metrics.os) {
+6 -5
View File
@@ -952,7 +952,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
mode = Addressing_Constant;
value = exact_value_i64(at->EnumeratedArray.count);
type = t_untyped_integer;
} else if (is_type_slice(op_type) && id == BuiltinProc_len) {
} else if ((is_type_slice(op_type) || is_type_relative_slice(op_type)) && id == BuiltinProc_len) {
mode = Addressing_Value;
} else if (is_type_dynamic_array(op_type)) {
mode = Addressing_Value;
@@ -1106,7 +1106,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
Selection sel = lookup_field(type, field_name, false);
if (sel.entity == nullptr) {
gbString type_str = type_to_string(type);
gbString type_str = type_to_string_shorthand(type);
error(ce->args[0],
"'%s' has no field named '%.*s'", type_str, LIT(field_name));
gb_string_free(type_str);
@@ -1118,7 +1118,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
return false;
}
if (sel.indirect) {
gbString type_str = type_to_string(type);
gbString type_str = type_to_string_shorthand(type);
error(ce->args[0],
"Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str);
gb_string_free(type_str);
@@ -1179,7 +1179,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
Selection sel = lookup_field(type, field_name, false);
if (sel.entity == nullptr) {
gbString type_str = type_to_string(type);
gbString type_str = type_to_string_shorthand(type);
error(ce->args[0],
"'%s' has no field named '%.*s'", type_str, LIT(field_name));
gb_string_free(type_str);
@@ -1191,7 +1191,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
return false;
}
if (sel.indirect) {
gbString type_str = type_to_string(type);
gbString type_str = type_to_string_shorthand(type);
error(ce->args[0],
"Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str);
gb_string_free(type_str);
@@ -3514,6 +3514,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
case TargetOs_linux:
case TargetOs_essence:
case TargetOs_freebsd:
case TargetOs_openbsd:
switch (build_context.metrics.arch) {
case TargetArch_i386:
case TargetArch_amd64:
+4 -4
View File
@@ -4470,7 +4470,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
if (entity == nullptr) {
gbString op_str = expr_to_string(op_expr);
gbString type_str = type_to_string(operand->type);
gbString type_str = type_to_string_shorthand(operand->type);
gbString sel_str = expr_to_string(selector);
error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str);
@@ -4511,7 +4511,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
}
gbString op_str = expr_to_string(op_expr);
gbString type_str = type_to_string(operand->type);
gbString type_str = type_to_string_shorthand(operand->type);
gbString sel_str = expr_to_string(selector);
error(op_expr, "Cannot access non-constant field '%s' from '%s'", sel_str, op_str);
gb_string_free(sel_str);
@@ -4536,7 +4536,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
}
gbString op_str = expr_to_string(op_expr);
gbString type_str = type_to_string(operand->type);
gbString type_str = type_to_string_shorthand(operand->type);
gbString sel_str = expr_to_string(selector);
error(op_expr, "Cannot access non-constant field '%s' from '%s'", sel_str, op_str);
gb_string_free(sel_str);
@@ -4549,7 +4549,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
if (expr_entity != nullptr && is_type_polymorphic(expr_entity->type)) {
gbString op_str = expr_to_string(op_expr);
gbString type_str = type_to_string(operand->type);
gbString type_str = type_to_string_shorthand(operand->type);
gbString sel_str = expr_to_string(selector);
error(op_expr, "Cannot access field '%s' from non-specialized polymorphic type '%s'", sel_str, op_str);
gb_string_free(sel_str);
+1
View File
@@ -924,6 +924,7 @@ void init_universal(void) {
{"Linux", TargetOs_linux},
{"Essence", TargetOs_essence},
{"FreeBSD", TargetOs_freebsd},
{"OpenBSD", TargetOs_openbsd},
{"WASI", TargetOs_wasi},
{"JS", TargetOs_js},
{"Freestanding", TargetOs_freestanding},
+1 -1
View File
@@ -848,7 +848,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
return ReadDirectory_None;
}
#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD)
#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD)
#include <dirent.h>
+86 -2
View File
@@ -79,6 +79,10 @@ extern "C" {
#ifndef GB_SYSTEM_FREEBSD
#define GB_SYSTEM_FREEBSD 1
#endif
#elif defined(__OpenBSD__)
#ifndef GB_SYSTEM_OPENBSD
#define GB_SYSTEM_OPENBSD 1
#endif
#else
#error This UNIX operating system is not supported
#endif
@@ -199,7 +203,7 @@ extern "C" {
#endif
#include <stdlib.h> // NOTE(bill): malloc on linux
#include <sys/mman.h>
#if !defined(GB_SYSTEM_OSX) && !defined(__FreeBSD__)
#if !defined(GB_SYSTEM_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
#include <sys/sendfile.h>
#endif
#include <sys/stat.h>
@@ -235,6 +239,12 @@ extern "C" {
#define sendfile(out, in, offset, count) sendfile(out, in, offset, count, NULL, NULL, 0)
#endif
#if defined(GB_SYSTEM_OPENBSD)
#include <stdio.h>
#include <pthread_np.h>
#define lseek64 lseek
#endif
#if defined(GB_SYSTEM_UNIX)
#include <semaphore.h>
#endif
@@ -783,6 +793,13 @@ typedef struct gbAffinity {
isize thread_count;
isize threads_per_core;
} gbAffinity;
#elif defined(GB_SYSTEM_OPENBSD)
typedef struct gbAffinity {
b32 is_accurate;
isize core_count;
isize thread_count;
isize threads_per_core;
} gbAffinity;
#else
#error TODO(bill): Unknown system
#endif
@@ -3678,6 +3695,30 @@ b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
return true;
}
isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
GB_ASSERT(0 <= core && core < a->core_count);
return a->threads_per_core;
}
#elif defined(GB_SYSTEM_OPENBSD)
#include <unistd.h>
void gb_affinity_init(gbAffinity *a) {
a->core_count = sysconf(_SC_NPROCESSORS_ONLN);
a->threads_per_core = 1;
a->is_accurate = a->core_count > 0;
a->core_count = a->is_accurate ? a->core_count : 1;
a->thread_count = a->core_count;
}
void gb_affinity_destroy(gbAffinity *a) {
gb_unused(a);
}
b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
return true;
}
isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
GB_ASSERT(0 <= core && core < a->core_count);
return a->threads_per_core;
@@ -6025,7 +6066,7 @@ gbFileTime gb_file_last_write_time(char const *filepath) {
gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filename, b32 fail_if_exists) {
#if defined(GB_SYSTEM_OSX)
return copyfile(existing_filename, new_filename, NULL, COPYFILE_DATA) == 0;
#else
#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_FREEBSD)
isize size;
int existing_fd = open(existing_filename, O_RDONLY, 0);
int new_fd = open(new_filename, O_WRONLY|O_CREAT, 0666);
@@ -6041,6 +6082,49 @@ gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filena
close(new_fd);
close(existing_fd);
return size == stat_existing.st_size;
#else
int new_flags = O_WRONLY | O_CREAT;
if (fail_if_exists) {
new_flags |= O_EXCL;
}
int existing_fd = open(existing_filename, O_RDONLY, 0);
int new_fd = open(new_filename, new_flags, 0666);
struct stat stat_existing;
if (fstat(existing_fd, &stat_existing) == -1) {
return 0;
}
size_t bsize = stat_existing.st_blksize > BUFSIZ ? stat_existing.st_blksize : BUFSIZ;
char *buf = (char *)malloc(bsize);
if (buf == NULL) {
close(new_fd);
close(existing_fd);
return 0;
}
isize size = 0;
ssize_t nread, nwrite, offset;
while ((nread = read(existing_fd, buf, bsize)) != -1 && nread != 0) {
for (offset = 0; nread; nread -= nwrite, offset += nwrite) {
if ((nwrite = write(new_fd, buf + offset, nread)) == -1 || nwrite == 0) {
free(buf);
close(new_fd);
close(existing_fd);
return 0;
}
size += nwrite;
}
}
free(buf);
close(new_fd);
close(existing_fd);
if (nread == -1) {
return 0;
}
return size == stat_existing.st_size;
#endif
}
+4
View File
@@ -1325,6 +1325,10 @@ void lb_generate_code(lbGenerator *gen) {
switch (build_context.reloc_mode) {
case RelocMode_Default:
if (build_context.metrics.os == TargetOs_openbsd) {
// Always use PIC for OpenBSD: it defaults to PIE
reloc_mode = LLVMRelocPIC;
}
break;
case RelocMode_Static:
reloc_mode = LLVMRelocStatic;
+15
View File
@@ -2202,6 +2202,21 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri
}
}
if (is_type_matrix(a) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) {
Type *tl = base_type(a);
lbValue lhs = lb_address_from_load_or_generate_local(p, left);
lbValue rhs = lb_address_from_load_or_generate_local(p, right);
// TODO(bill): Test to see if this is actually faster!!!!
auto args = array_make<lbValue>(permanent_allocator(), 3);
args[0] = lb_emit_conv(p, lhs, t_rawptr);
args[1] = lb_emit_conv(p, rhs, t_rawptr);
args[2] = lb_const_int(p->module, t_int, type_size_of(tl));
lbValue val = lb_emit_runtime_call(p, "memory_compare", args);
lbValue res = lb_emit_comp(p, op_kind, val, lb_const_nil(p->module, val.type));
return lb_emit_conv(p, res, t_bool);
}
if (is_type_array(a) || is_type_enumerated_array(a)) {
Type *tl = base_type(a);
lbValue lhs = lb_address_from_load_or_generate_local(p, left);
+17 -8
View File
@@ -1046,7 +1046,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
return lb_string_len(p, v);
} else if (is_type_array(t)) {
GB_PANIC("Array lengths are constant");
} else if (is_type_slice(t)) {
} else if (is_type_slice(t) || is_type_relative_slice(t)) {
return lb_slice_len(p, v);
} else if (is_type_dynamic_array(t)) {
return lb_dynamic_array_len(p, v);
@@ -1072,7 +1072,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
GB_PANIC("Unreachable");
} else if (is_type_array(t)) {
GB_PANIC("Array lengths are constant");
} else if (is_type_slice(t)) {
} else if (is_type_slice(t) || is_type_relative_slice(t)) {
return lb_slice_len(p, v);
} else if (is_type_dynamic_array(t)) {
return lb_dynamic_array_cap(p, v);
@@ -1406,14 +1406,23 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
case BuiltinProc_read_cycle_counter:
{
char const *name = "llvm.readcyclecounter";
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0);
lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, nullptr, 0, "");
res.type = tv.type;
if (build_context.metrics.arch == TargetArch_arm64) {
LLVMTypeRef func_type = LLVMFunctionType(LLVMInt64TypeInContext(p->module->ctx), nullptr, 0, false);
bool has_side_effects = false;
LLVMValueRef the_asm = llvm_get_inline_asm(func_type, str_lit("mrs x9, cntvct_el0"), str_lit("=r"), has_side_effects);
GB_ASSERT(the_asm != nullptr);
res.value = LLVMBuildCall2(p->builder, func_type, the_asm, nullptr, 0, "");
} else {
char const *name = "llvm.readcyclecounter";
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0);
res.value = LLVMBuildCall(p->builder, ip, nullptr, 0, "");
}
return res;
}
+2 -2
View File
@@ -1387,7 +1387,7 @@ lbValue lb_slice_elem(lbProcedure *p, lbValue slice) {
return lb_emit_struct_ev(p, slice, 0);
}
lbValue lb_slice_len(lbProcedure *p, lbValue slice) {
GB_ASSERT(is_type_slice(slice.type));
GB_ASSERT(is_type_slice(slice.type) || is_type_relative_slice(slice.type));
return lb_emit_struct_ev(p, slice, 1);
}
lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da) {
@@ -1793,7 +1793,7 @@ LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const &str, Strin
return LLVMGetInlineAsm(func_type,
cast(char *)str.text, cast(size_t)str.len,
cast(char *)clobbers.text, cast(size_t)clobbers.len,
/*HasSideEffects*/true, /*IsAlignStack*/false,
has_side_effects, is_align_stack,
dialect
#if LLVM_VERSION_MAJOR >= 13
, /*CanThrow*/false
+43 -37
View File
@@ -384,7 +384,7 @@ i32 linker_stage(lbGenerator *gen) {
// NOTE(zangent): Sometimes, you have to use -framework on MacOS.
// This allows you to specify '-f' in a #foreign_system_library,
// without having to implement any new syntax specifically for MacOS.
#if defined(GB_SYSTEM_OSX)
if (build_context.metrics.os == TargetOs_darwin) {
if (string_ends_with(lib, str_lit(".framework"))) {
// framework thingie
String lib_name = lib;
@@ -400,14 +400,14 @@ i32 linker_stage(lbGenerator *gen) {
// dynamic or static system lib, just link regularly searching system library paths
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
}
#else
} else {
// NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path,
// since those are statically linked to at link time. shared libraries (.so) has to be
// available at runtime wherever the executable is run, so we make require those to be
// local to the executable (unless the system collection is used, in which case we search
// the system library paths for the library file).
if (string_ends_with(lib, str_lit(".a"))) {
// static libs, absolute full path relative to the file in which the lib was imported from
if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o"))) {
// static libs and object files, absolute full path relative to the file in which the lib was imported from
lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib));
} else if (string_ends_with(lib, str_lit(".so"))) {
// dynamic lib, relative path to executable
@@ -418,7 +418,7 @@ i32 linker_stage(lbGenerator *gen) {
// dynamic or static system lib, just link regularly searching system library paths
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
}
#endif
}
}
gbString object_files = gb_string_make(heap_allocator(), "");
@@ -456,14 +456,15 @@ i32 linker_stage(lbGenerator *gen) {
// line arguments prepared previously are incompatible with ld.
//
// Shared libraries are .dylib on MacOS and .so on Linux.
#if defined(GB_SYSTEM_OSX)
if (build_context.metrics.os == TargetOs_darwin) {
output_ext = STR_LIT(".dylib");
#else
} else {
output_ext = STR_LIT(".so");
#endif
}
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 {
} 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 ");
}
if (build_context.out_filepath.len > 0) {
@@ -474,34 +475,39 @@ i32 linker_stage(lbGenerator *gen) {
}
}
result = system_exec_command_line_app("ld-link",
"clang -Wno-unused-command-line-argument %s -o \"%.*s%.*s\" %s "
" %s "
" %.*s "
" %.*s "
" %s "
#if defined(GB_SYSTEM_OSX)
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
// make sure to also change the 'mtriple' param passed to 'opt'
#if defined(GB_CPU_ARM)
" -mmacosx-version-min=12.0.0 "
#else
" -mmacosx-version-min=10.8.0 "
#endif
// This points the linker to where the entry point is
" -e _main "
#endif
, object_files, LIT(output_base), LIT(output_ext),
#if defined(GB_SYSTEM_OSX)
"-lSystem -lm -Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib",
#else
"-lc -lm",
#endif
lib_str,
LIT(build_context.link_flags),
LIT(build_context.extra_linker_flags),
link_settings);
gbString platform_lib_str = gb_string_make(heap_allocator(), "");
defer (gb_string_free(platform_lib_str));
if (build_context.metrics.os == TargetOs_darwin) {
platform_lib_str = gb_string_appendc(platform_lib_str, "-lSystem -lm -Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib");
} else {
platform_lib_str = gb_string_appendc(platform_lib_str, "-lc -lm");
}
if (build_context.metrics.os == TargetOs_darwin) {
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
// make sure to also change the 'mtriple' param passed to 'opt'
if (build_context.metrics.arch == TargetArch_arm64) {
link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=12.0.0 ");
} else {
link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=10.8.0 ");
}
// This points the linker to where the entry point is
link_settings = gb_string_appendc(link_settings, " -e _main ");
}
gbString link_command_line = gb_string_make(heap_allocator(), "clang -Wno-unused-command-line-argument ");
defer (gb_string_free(link_command_line));
link_command_line = gb_string_appendc(link_command_line, object_files);
link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s%.*s\" ", LIT(output_base), LIT(output_ext));
link_command_line = gb_string_append_fmt(link_command_line, " %s ", platform_lib_str);
link_command_line = gb_string_append_fmt(link_command_line, " %s ", lib_str);
link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.link_flags));
link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.extra_linker_flags));
link_command_line = gb_string_append_fmt(link_command_line, " %s ", link_settings);
result = system_exec_command_line_app("ld-link", link_command_line);
if (result) {
return result;
+18 -1
View File
@@ -1538,7 +1538,7 @@ void fix_advance_to_next_stmt(AstFile *f) {
Token expect_closing(AstFile *f, TokenKind kind, String context) {
if (f->curr_token.kind != kind &&
f->curr_token.kind == Token_Semicolon &&
f->curr_token.string == "\n") {
(f->curr_token.string == "\n" || f->curr_token.kind == Token_EOF)) {
Token tok = f->prev_token;
tok.pos.column += cast(i32)tok.string.len;
syntax_error(tok, "Missing ',' before newline in %.*s", LIT(context));
@@ -1560,6 +1560,7 @@ void assign_removal_flag_to_semicolon(AstFile *f) {
switch (curr_token->kind) {
case Token_CloseBrace:
case Token_CloseParen:
case Token_EOF:
ok = true;
break;
}
@@ -5719,6 +5720,22 @@ ParseFileError parse_packages(Parser *p, String init_filename) {
error_line("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename));
return ParseFile_WrongExtension;
}
} else if (init_fullpath.len != 0) {
String path = init_fullpath;
if (path[path.len-1] == '/') {
path.len -= 1;
}
if ((build_context.command_kind & Command__does_build) &&
build_context.build_mode == BuildMode_Executable) {
String short_path = filename_from_path(path);
char *cpath = alloc_cstring(heap_allocator(), short_path);
defer (gb_free(heap_allocator(), cpath));
if (gb_file_exists(cpath)) {
error_line("Please specify the executable name with -out:<string> as a directory exists with the same name in the current working directory");
return ParseFile_DirectoryAlreadyExists;
}
}
}
+1
View File
@@ -46,6 +46,7 @@ enum ParseFileError {
ParseFile_InvalidToken,
ParseFile_GeneralError,
ParseFile_FileTooLarge,
ParseFile_DirectoryAlreadyExists,
ParseFile_Count,
};
+1 -1
View File
@@ -486,7 +486,7 @@ void thread_set_name(Thread *t, char const *name) {
#elif defined(GB_SYSTEM_OSX)
// TODO(bill): Test if this works
pthread_setname_np(name);
#elif defined(GB_SYSTEM_FREEBSD)
#elif defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD)
pthread_set_name_np(t->posix_handle, name);
#else
// TODO(bill): Test if this works
+24 -15
View File
@@ -703,7 +703,7 @@ struct TypePath;
i64 type_size_of (Type *t);
i64 type_align_of (Type *t);
i64 type_offset_of (Type *t, i32 index);
gbString type_to_string (Type *type);
gbString type_to_string (Type *type, bool shorthand=false);
i64 type_size_of_internal(Type *t, TypePath *path);
void init_map_internal_types(Type *type);
Type * bit_set_to_int(Type *t);
@@ -3936,7 +3936,7 @@ Type *alloc_type_proc_from_types(Type **param_types, unsigned param_count, Type
gbString write_type_to_string(gbString str, Type *type) {
gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) {
if (type == nullptr) {
return gb_string_appendc(str, "<no type>");
}
@@ -4051,15 +4051,21 @@ gbString write_type_to_string(gbString str, Type *type) {
if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union");
if (type->Struct.custom_align != 0) str = gb_string_append_fmt(str, " #align %d", cast(int)type->Struct.custom_align);
str = gb_string_appendc(str, " {");
for_array(i, type->Struct.fields) {
Entity *f = type->Struct.fields[i];
GB_ASSERT(f->kind == Entity_Variable);
if (i > 0) {
str = gb_string_appendc(str, ", ");
if (shorthand && type->Struct.fields.count > 16) {
str = gb_string_append_fmt(str, "%lld fields...", cast(long long)type->Struct.fields.count);
} else {
for_array(i, type->Struct.fields) {
Entity *f = type->Struct.fields[i];
GB_ASSERT(f->kind == Entity_Variable);
if (i > 0) {
str = gb_string_appendc(str, ", ");
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, f->type);
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, f->type);
}
str = gb_string_append_rune(str, '}');
} break;
@@ -4234,13 +4240,16 @@ gbString write_type_to_string(gbString str, Type *type) {
}
gbString type_to_string(Type *type, gbAllocator allocator) {
return write_type_to_string(gb_string_make(allocator, ""), type);
gbString type_to_string(Type *type, gbAllocator allocator, bool shorthand=false) {
return write_type_to_string(gb_string_make(allocator, ""), type, shorthand);
}
gbString type_to_string(Type *type) {
return write_type_to_string(gb_string_make(heap_allocator(), ""), type);
gbString type_to_string(Type *type, bool shorthand) {
return write_type_to_string(gb_string_make(heap_allocator(), ""), type, shorthand);
}
gbString type_to_string_shorthand(Type *type) {
return type_to_string(type, true);
}
+6 -2
View File
@@ -1,7 +1,7 @@
ODIN=../../odin
PYTHON=$(shell which python3)
all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test
all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test
download_test_assets:
$(PYTHON) download_assets.py
@@ -22,4 +22,8 @@ crypto_test:
$(ODIN) run crypto -out=crypto_hash -o:speed -no-bounds-check
noise_test:
$(ODIN) run math/noise -out=test_noise
$(ODIN) run math/noise -out=test_noise
encoding_test:
$(ODIN) run encoding/json -out=test_json
$(ODIN) run encoding/varint -out=test_varint
+2 -1
View File
@@ -35,7 +35,8 @@ echo ---
echo ---
echo Running core:encoding tests
echo ---
%PATH_TO_ODIN% run encoding %COMMON%
%PATH_TO_ODIN% run encoding/json %COMMON%
%PATH_TO_ODIN% run encoding/varint %COMMON%
echo ---
echo Running core:math/noise tests
+4 -3
View File
@@ -30,14 +30,12 @@ when ODIN_TEST {
log :: testing.log
} else {
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
fmt.printf("[%v] ", loc)
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.println(message)
fmt.printf("[%v] %v\n", loc, message)
return
}
fmt.println(" PASS")
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
@@ -52,6 +50,9 @@ main :: proc() {
gzip_test(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 {
os.exit(1)
}
}
@test
File diff suppressed because it is too large Load Diff
Binary file not shown.
@@ -3,37 +3,39 @@ package test_core_json
import "core:encoding/json"
import "core:testing"
import "core:fmt"
import "core:os"
TEST_count := 0
TEST_fail := 0
when ODIN_TEST {
expect :: testing.expect
log :: testing.log
expect :: testing.expect
log :: testing.log
} else {
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
fmt.printf("[%v] ", loc)
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.println(message)
return
}
fmt.println(" PASS")
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.printf("[%v] %v\n", loc, message)
return
}
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
}
main :: proc() {
t := testing.T{}
t := testing.T{}
parse_json(&t)
marshal_json(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 {
os.exit(1)
}
}
@test
@@ -0,0 +1,156 @@
package test_core_varint
import "core:encoding/varint"
import "core:testing"
import "core:fmt"
import "core:os"
import "core:slice"
import "core:math/rand"
TEST_count := 0
TEST_fail := 0
RANDOM_TESTS :: 100
when ODIN_TEST {
expect :: testing.expect
log :: testing.log
} else {
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.printf("[%v] %v\n", loc, message)
return
}
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
}
main :: proc() {
t := testing.T{}
test_leb128(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 {
os.exit(1)
}
}
@(test)
test_leb128 :: proc(t: ^testing.T) {
buf: [varint.LEB128_MAX_BYTES]u8
for vector in ULEB_Vectors {
val, size, err := varint.decode_uleb128(vector.encoded)
msg := fmt.tprintf("Expected %02x to decode to %v consuming %v bytes, got %v and %v", vector.encoded, vector.value, vector.size, val, size)
expect(t, size == vector.size && val == vector.value, msg)
msg = fmt.tprintf("Expected decoder to return error %v, got %v", vector.error, err)
expect(t, err == vector.error, msg)
if err == .None { // Try to roundtrip
size, err = varint.encode_uleb128(buf[:], vector.value)
msg = fmt.tprintf("Expected %v to encode to %02x, got %02x", vector.value, vector.encoded, buf[:size])
expect(t, size == vector.size && slice.simple_equal(vector.encoded, buf[:size]), msg)
}
}
for vector in ILEB_Vectors {
val, size, err := varint.decode_ileb128(vector.encoded)
msg := fmt.tprintf("Expected %02x to decode to %v consuming %v bytes, got %v and %v", vector.encoded, vector.value, vector.size, val, size)
expect(t, size == vector.size && val == vector.value, msg)
msg = fmt.tprintf("Expected decoder to return error %v, got %v", vector.error, err)
expect(t, err == vector.error, msg)
if err == .None { // Try to roundtrip
size, err = varint.encode_ileb128(buf[:], vector.value)
msg = fmt.tprintf("Expected %v to encode to %02x, got %02x", vector.value, vector.encoded, buf[:size])
expect(t, size == vector.size && slice.simple_equal(vector.encoded, buf[:size]), msg)
}
}
for num_bytes in 1..uint(16) {
for _ in 0..RANDOM_TESTS {
unsigned, signed := get_random(num_bytes)
{
encode_size, encode_err := varint.encode_uleb128(buf[:], unsigned)
msg := fmt.tprintf("%v failed to encode as an unsigned LEB128 value, got %v", unsigned, encode_err)
expect(t, encode_err == .None, msg)
decoded, decode_size, decode_err := varint.decode_uleb128(buf[:])
msg = fmt.tprintf("Expected %02x to decode as %v, got %v", buf[:encode_size], unsigned, decoded)
expect(t, decode_err == .None && decode_size == encode_size && decoded == unsigned, msg)
}
{
encode_size, encode_err := varint.encode_ileb128(buf[:], signed)
msg := fmt.tprintf("%v failed to encode as a signed LEB128 value, got %v", signed, encode_err)
expect(t, encode_err == .None, msg)
decoded, decode_size, decode_err := varint.decode_ileb128(buf[:])
msg = fmt.tprintf("Expected %02x to decode as %v, got %v, err: %v", buf[:encode_size], signed, decoded, decode_err)
expect(t, decode_err == .None && decode_size == encode_size && decoded == signed, msg)
}
}
}
}
get_random :: proc(byte_count: uint) -> (u: u128, i: i128) {
assert(byte_count >= 0 && byte_count <= size_of(u128))
for _ in 1..byte_count {
u <<= 8
u |= u128(rand.uint32() & 0xff)
}
bias := i128(1 << (byte_count * 7)) - 1
i = i128(u) - bias
return
}
ULEB_Test_Vector :: struct {
encoded: []u8,
value: u128,
size: int,
error: varint.Error,
}
ULEB_Vectors :: []ULEB_Test_Vector{
{ []u8{0x00}, 0, 1, .None },
{ []u8{0x7f}, 127, 1, .None },
{ []u8{0xE5, 0x8E, 0x26}, 624485, 3, .None },
{ []u8{0x80}, 0, 0, .Buffer_Too_Small },
{ []u8{}, 0, 0, .Buffer_Too_Small },
{ []u8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03}, max(u128), 19, .None },
}
ILEB_Test_Vector :: struct {
encoded: []u8,
value: i128,
size: int,
error: varint.Error,
}
ILEB_Vectors :: []ILEB_Test_Vector{
{ []u8{0x00}, 0, 1, .None },
{ []u8{0x3f}, 63, 1, .None },
{ []u8{0x40}, -64, 1, .None },
{ []u8{0xC0, 0xBB, 0x78}, -123456, 3, .None },
{ []u8{}, 0, 0, .Buffer_Too_Small },
{ []u8{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7e}, min(i128), 19, .None },
{ []u8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01}, max(i128), 19, .None },
}
+5 -3
View File
@@ -5,6 +5,7 @@ import "core:hash"
import "core:time"
import "core:testing"
import "core:fmt"
import "core:os"
TEST_count := 0
TEST_fail := 0
@@ -14,14 +15,12 @@ when ODIN_TEST {
log :: testing.log
} else {
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
fmt.printf("[%v] ", loc)
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.println(" FAIL:", message)
fmt.printf("[%v] %v\n", loc, message)
return
}
fmt.println(" PASS")
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
@@ -35,6 +34,9 @@ main :: proc() {
test_xxhash_vectors(&t)
test_crc64_vectors(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 {
os.exit(1)
}
}
/*
+17 -16
View File
@@ -32,23 +32,21 @@ TEST_count := 0
TEST_fail := 0
when ODIN_TEST {
expect :: testing.expect
log :: testing.log
expect :: testing.expect
log :: testing.log
} else {
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
fmt.printf("[%v] ", loc)
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.println(message)
return
}
fmt.println(" PASS")
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.printf("[%v] %v\n", loc, message)
return
}
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
}
I_Error :: image.Error
@@ -57,6 +55,9 @@ main :: proc() {
png_test(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 {
os.exit(1)
}
}
PNG_Test :: struct {
+18 -16
View File
@@ -3,6 +3,7 @@ package test_core_math_noise
import "core:testing"
import "core:math/noise"
import "core:fmt"
import "core:os"
TEST_count := 0
TEST_fail := 0
@@ -12,29 +13,30 @@ V3 :: noise.Vec3
V4 :: noise.Vec4
when ODIN_TEST {
expect :: testing.expect
log :: testing.log
expect :: testing.expect
log :: testing.log
} else {
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
fmt.printf("[%v] ", loc)
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.println(message)
return
}
fmt.println(" PASS")
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.printf("[%v] %v\n", loc, message)
return
}
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
}
main :: proc() {
t := testing.T{}
noise_test(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 {
os.exit(1)
}
}
Test_Vector :: struct {
+22 -22
View File
@@ -2,7 +2,7 @@ package test_core_odin_parser
import "core:testing"
import "core:fmt"
import "core:os"
import "core:odin/parser"
@@ -10,31 +10,31 @@ TEST_count := 0
TEST_fail := 0
when ODIN_TEST {
expect :: testing.expect
log :: testing.log
expect :: testing.expect
log :: testing.log
} else {
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
fmt.printf("[%v] ", loc)
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.println(message)
return
}
fmt.println(" PASS")
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.printf("[%v] %v\n", loc, message)
return
}
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
}
main :: proc() {
t := testing.T{}
test_parse_demo(&t)
t := testing.T{}
test_parse_demo(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 {
os.exit(1)
}
}
@@ -47,4 +47,4 @@ test_parse_demo :: proc(t: ^testing.T) {
for key, value in pkg.files {
expect(t, value.syntax_error_count == 0, fmt.tprintf("%v should contain zero errors", key))
}
}
}
+33 -31
View File
@@ -3,61 +3,63 @@ package test_core_image
import "core:strings"
import "core:testing"
import "core:fmt"
import "core:os"
TEST_count := 0
TEST_fail := 0
when ODIN_TEST {
expect :: testing.expect
log :: testing.log
expect :: testing.expect
log :: testing.log
} else {
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
fmt.printf("[%v] ", loc)
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.println(message)
return
}
fmt.println(" PASS")
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.printf("[%v] %v\n", loc, message)
return
}
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
}
main :: proc() {
t := testing.T{}
test_index_any_small_string_not_found(&t)
test_index_any_larger_string_not_found(&t)
test_index_any_small_string_found(&t)
test_index_any_larger_string_found(&t)
t := testing.T{}
test_index_any_small_string_not_found(&t)
test_index_any_larger_string_not_found(&t)
test_index_any_small_string_found(&t)
test_index_any_larger_string_found(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 {
os.exit(1)
}
}
@test
test_index_any_small_string_not_found :: proc(t: ^testing.T) {
index := strings.index_any(".", "/:\"")
log(t, index)
expect(t, index == -1, "index_any should be negative")
index := strings.index_any(".", "/:\"")
log(t, index)
expect(t, index == -1, "index_any should be negative")
}
@test
test_index_any_larger_string_not_found :: proc(t: ^testing.T) {
index := strings.index_any("aaaaaaaa.aaaaaaaa", "/:\"")
expect(t, index == -1, "index_any should be negative")
index := strings.index_any("aaaaaaaa.aaaaaaaa", "/:\"")
expect(t, index == -1, "index_any should be negative")
}
@test
test_index_any_small_string_found :: proc(t: ^testing.T) {
index := strings.index_any(".", "/:.\"")
expect(t, index == 0, "index_any should be 0")
index := strings.index_any(".", "/:.\"")
expect(t, index == 0, "index_any should be 0")
}
@test
test_index_any_larger_string_found :: proc(t: ^testing.T) {
index := strings.index_any("aaaaaaaa:aaaaaaaa", "/:\"")
expect(t, index == 8, "index_any should be 8")
index := strings.index_any("aaaaaaaa:aaaaaaaa", "/:\"")
expect(t, index == 8, "index_any should be 8")
}
+8 -1
View File
@@ -1,6 +1,13 @@
ODIN=../../odin
ODINFLAGS=
OS=$(shell uname)
ifeq ($(OS), OpenBSD)
ODINFLAGS:=$(ODINFLAGS) -extra-linker-flags:-L/usr/local/lib
endif
all: botan_test
botan_test:
$(ODIN) run botan -out=botan_hash -o:speed -no-bounds-check
$(ODIN) run botan -out=botan_hash -o:speed -no-bounds-check $(ODINFLAGS)
+4
View File
@@ -14,6 +14,7 @@ package test_vendor_botan
import "core:testing"
import "core:fmt"
import "core:os"
import "vendor:botan/md4"
import "vendor:botan/md5"
@@ -86,6 +87,9 @@ main :: proc() {
test_siphash_2_4(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 {
os.exit(1)
}
}
TestHash :: struct {
+4
View File
@@ -3,6 +3,7 @@ package test_vendor_glfw
import "core:testing"
import "core:fmt"
import "vendor:glfw"
import "core:os"
GLFW_MAJOR :: 3
GLFW_MINOR :: 3
@@ -36,6 +37,9 @@ main :: proc() {
test_glfw(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 {
os.exit(1)
}
}
@(test)
+3 -3
View File
@@ -1,4 +1,4 @@
//+build linux, darwin, freebsd
//+build linux, darwin, freebsd, openbsd
package ENet
// When we implement the appropriate bindings for Unix, the section separated
@@ -14,7 +14,7 @@ import "core:c"
@(private="file") FD_ZERO :: #force_inline proc(s: ^fd_set) {
for i := size_of(fd_set) / size_of(c.long); i != 0; i -= 1 {
s.fds_bits[i] = 0;
s.fds_bits[i] = 0
}
}
@@ -56,4 +56,4 @@ SOCKETSET_REMOVE :: #force_inline proc(sockset: ^SocketSet, socket: Socket) {
SOCKSET_CHECK :: #force_inline proc(sockset: ^SocketSet, socket: Socket) -> bool {
return FD_ISSET(i32(socket), cast(^fd_set)sockset)
}
}
+2 -4
View File
@@ -142,9 +142,7 @@ fpe_t :: ^fpe_struct
when ODIN_OS == .Windows {
foreign import botan_lib "botan.lib"
} else when ODIN_OS == .Linux {
foreign import botan_lib "system:botan-2"
} else when ODIN_OS == .Darwin {
} else {
foreign import botan_lib "system:botan-2"
}
@@ -471,4 +469,4 @@ foreign botan_lib {
fpe_destroy :: proc(fpe: fpe_t) -> c.int ---
fpe_encrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int ---
fpe_decrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int ---
}
}
+5 -2
View File
@@ -3,8 +3,6 @@ package glfw_bindings
import "core:c"
import vk "vendor:vulkan"
when ODIN_OS == .Linux { foreign import glfw "system:glfw" } // TODO: Add the billion-or-so static libs to link to in linux
when ODIN_OS == .Darwin { foreign import glfw "system:glfw" }
when ODIN_OS == .Windows {
foreign import glfw {
"../lib/glfw3_mt.lib",
@@ -12,6 +10,11 @@ when ODIN_OS == .Windows {
"system:gdi32.lib",
"system:shell32.lib",
}
} else when ODIN_OS == .Linux {
// TODO: Add the billion-or-so static libs to link to in linux
foreign import glfw "system:glfw"
} else {
foreign import glfw "system:glfw"
}
#assert(size_of(c.int) == size_of(b32))
+7 -2
View File
@@ -2,8 +2,13 @@ package miniaudio
import "core:c"
when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" }
when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" }
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
handle :: distinct rawptr
+7 -3
View File
@@ -2,9 +2,13 @@ package miniaudio
import "core:c"
when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" }
when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" }
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
/************************************************************************************************************************************************************
*************************************************************************************************************************************************************
+8 -5
View File
@@ -2,10 +2,13 @@ package miniaudio
import "core:c"
when ODIN_OS == .Windows { foreign import lib "lib/miniaudio.lib" }
when ODIN_OS == .Linux { foreign import lib "lib/miniaudio.a" }
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
/************************************************************************************************************************************************************
@@ -164,4 +167,4 @@ foreign lib {
decode_from_vfs :: proc(pVFS: ^vfs, pFilePath: cstring, pConfig: ^decoder_config, pFrameCountOut: ^u64, ppPCMFramesOut: ^rawptr) -> result ---
decode_file :: proc(pFilePath: cstring, pConfig: ^decoder_config, pFrameCountOut: ^u64, ppPCMFramesOut: ^rawptr) -> result ---
decode_memory :: proc(pData: rawptr, dataSize: c.size_t, pConfig: ^decoder_config, pFrameCountOut: ^u64, ppPCMFramesOut: ^rawptr) -> result ---
}
}

Some files were not shown because too many files have changed in this diff Show More