Nearly finished Jai-like declarations

This commit is contained in:
Ginger Bill
2017-01-01 20:41:10 +00:00
parent a48e0c7179
commit 9202bd1b06
18 changed files with 858 additions and 1074 deletions
+10 -12
View File
@@ -1,15 +1,13 @@
import { import "atomic.odin";
"atomic.odin"; import "fmt.odin";
"fmt.odin"; import "hash.odin";
"hash.odin"; import "math.odin";
"math.odin"; import "mem.odin";
"mem.odin"; import "opengl.odin";
"opengl.odin"; import "os.odin";
"os.odin"; import "sync.odin";
"sync.odin"; import "utf8.odin";
"utf8.odin"; import win32 "sys/windows.odin";
win32 "sys/windows.odin";
}
Thing :: enum f64 { Thing :: enum f64 {
_, // Ignore first value _, // Ignore first value
+110 -114
View File
@@ -12,74 +12,72 @@ import "mem.odin";
// IMPORTANT NOTE(bill): Do not change the order of any of this data // IMPORTANT NOTE(bill): Do not change the order of any of this data
// The compiler relies upon this _exact_ order // The compiler relies upon this _exact_ order
type { Type_Info_Member :: struct #ordered {
Type_Info_Member struct #ordered { name string; // can be empty if tuple
name string; // can be empty if tuple type_info ^Type_Info;
type_info ^Type_Info; offset int; // offsets are not used in tuples
offset int; // offsets are not used in tuples }
} Type_Info_Record :: struct #ordered {
Type_Info_Record struct #ordered { fields []Type_Info_Member;
fields []Type_Info_Member; size int; // in bytes
size int; // in bytes align int; // in bytes
align int; // in bytes packed bool;
packed bool; ordered bool;
ordered bool;
}
Type_Info union {
Named struct #ordered {
name string;
base ^Type_Info; // This will _not_ be a Type_Info.Named
};
Integer struct #ordered {
size int; // in bytes
signed bool;
};
Float struct #ordered {
size int; // in bytes
};
Any struct #ordered {};
String struct #ordered {};
Boolean struct #ordered {};
Pointer struct #ordered {
elem ^Type_Info; // nil -> rawptr
};
Maybe struct #ordered {
elem ^Type_Info;
};
Procedure struct #ordered {
params ^Type_Info; // Type_Info.Tuple
results ^Type_Info; // Type_Info.Tuple
variadic bool;
};
Array struct #ordered {
elem ^Type_Info;
elem_size int;
count int;
};
Slice struct #ordered {
elem ^Type_Info;
elem_size int;
};
Vector struct #ordered {
elem ^Type_Info;
elem_size int;
count int;
align int;
};
Tuple Type_Info_Record;
Struct Type_Info_Record;
Union Type_Info_Record;
Raw_Union Type_Info_Record;
Enum struct #ordered {
base ^Type_Info;
names []string;
// TODO(bill): store values some how. Maybe using a raw_union
};
}
} }
proc type_info_base(info ^Type_Info) -> ^Type_Info { Type_Info :: union {
Named struct #ordered {
name string;
base ^Type_Info; // This will _not_ be a Type_Info.Named
};
Integer struct #ordered {
size int; // in bytes
signed bool;
};
Float struct #ordered {
size int; // in bytes
};
Any struct #ordered {};
String struct #ordered {};
Boolean struct #ordered {};
Pointer struct #ordered {
elem ^Type_Info; // nil -> rawptr
};
Maybe struct #ordered {
elem ^Type_Info;
};
Procedure struct #ordered {
params ^Type_Info; // Type_Info.Tuple
results ^Type_Info; // Type_Info.Tuple
variadic bool;
};
Array struct #ordered {
elem ^Type_Info;
elem_size int;
count int;
};
Slice struct #ordered {
elem ^Type_Info;
elem_size int;
};
Vector struct #ordered {
elem ^Type_Info;
elem_size int;
count int;
align int;
};
Tuple Type_Info_Record;
Struct Type_Info_Record;
Union Type_Info_Record;
Raw_Union Type_Info_Record;
Enum struct #ordered {
base ^Type_Info;
names []string;
// TODO(bill): store values some how. Maybe using a raw_union
};
}
type_info_base :: proc(info ^Type_Info) -> ^Type_Info {
if info == nil { if info == nil {
return nil; return nil;
} }
@@ -93,51 +91,49 @@ proc type_info_base(info ^Type_Info) -> ^Type_Info {
proc assume(cond bool) #foreign "llvm.assume" assume :: proc(cond bool) #foreign "llvm.assume"
proc __debug_trap () #foreign "llvm.debugtrap" __debug_trap :: proc() #foreign "llvm.debugtrap"
proc __trap () #foreign "llvm.trap" __trap :: proc() #foreign "llvm.trap"
proc read_cycle_counter() -> u64 #foreign "llvm.readcyclecounter" read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
proc bit_reverse16(b u16) -> u16 #foreign "llvm.bitreverse.i16" bit_reverse16 :: proc(b u16) -> u16 #foreign "llvm.bitreverse.i16"
proc bit_reverse32(b u32) -> u32 #foreign "llvm.bitreverse.i32" bit_reverse32 :: proc(b u32) -> u32 #foreign "llvm.bitreverse.i32"
proc bit_reverse64(b u64) -> u64 #foreign "llvm.bitreverse.i64" bit_reverse64 :: proc(b u64) -> u64 #foreign "llvm.bitreverse.i64"
proc byte_swap16(b u16) -> u16 #foreign "llvm.bswap.i16" byte_swap16 :: proc(b u16) -> u16 #foreign "llvm.bswap.i16"
proc byte_swap32(b u32) -> u32 #foreign "llvm.bswap.i32" byte_swap32 :: proc(b u32) -> u32 #foreign "llvm.bswap.i32"
proc byte_swap64(b u64) -> u64 #foreign "llvm.bswap.i64" byte_swap64 :: proc(b u64) -> u64 #foreign "llvm.bswap.i64"
proc fmuladd32(a, b, c f32) -> f32 #foreign "llvm.fmuladd.f32" fmuladd32 :: proc(a, b, c f32) -> f32 #foreign "llvm.fmuladd.f32"
proc fmuladd64(a, b, c f64) -> f64 #foreign "llvm.fmuladd.f64" fmuladd64 :: proc(a, b, c f64) -> f64 #foreign "llvm.fmuladd.f64"
type Allocator_Mode enum u8 { Allocator_Mode :: enum u8 {
ALLOC = iota, ALLOC = iota,
FREE, FREE,
FREE_ALL, FREE_ALL,
RESIZE, RESIZE,
} }
type { Allocator_Proc :: type proc(allocator_data rawptr, mode Allocator_Mode,
Allocator_Proc proc(allocator_data rawptr, mode Allocator_Mode, size, alignment int,
size, alignment int, old_memory rawptr, old_size int, flags u64) -> rawptr;
old_memory rawptr, old_size int, flags u64) -> rawptr; Allocator :: struct #ordered {
Allocator struct #ordered { procedure Allocator_Proc;
procedure Allocator_Proc; data rawptr;
data rawptr; }
}
Context struct #ordered { Context :: struct #ordered {
thread_id int; thread_id int;
allocator Allocator; allocator Allocator;
user_data rawptr; user_data rawptr;
user_index int; user_index int;
}
} }
#thread_local __context: Context; #thread_local __context: Context;
@@ -146,7 +142,7 @@ type {
DEFAULT_ALIGNMENT :: align_of([vector 4]f32); DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
proc __check_context() { __check_context:: proc() {
c := ^__context; c := ^__context;
if c.allocator.procedure == nil { if c.allocator.procedure == nil {
@@ -157,30 +153,30 @@ proc __check_context() {
} }
} }
proc alloc(size int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT); } alloc:: proc(size int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT); }
proc alloc_align(size, alignment int) -> rawptr #inline { alloc_align:: proc(size, alignment int) -> rawptr #inline {
__check_context(); __check_context();
a := context.allocator; a := context.allocator;
return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0); return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0);
} }
proc free(ptr rawptr) #inline { free:: proc(ptr rawptr) #inline {
__check_context(); __check_context();
a := context.allocator; a := context.allocator;
if ptr != nil { if ptr != nil {
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0); a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
} }
} }
proc free_all() #inline { free_all:: proc() #inline {
__check_context(); __check_context();
a := context.allocator; a := context.allocator;
a.procedure(a.data, Allocator_Mode.FREE_ALL, 0, 0, nil, 0, 0); a.procedure(a.data, Allocator_Mode.FREE_ALL, 0, 0, nil, 0, 0);
} }
proc resize (ptr rawptr, old_size, new_size int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT); } resize:: proc (ptr rawptr, old_size, new_size int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT); }
proc resize_align(ptr rawptr, old_size, new_size, alignment int) -> rawptr #inline { resize_align:: proc(ptr rawptr, old_size, new_size, alignment int) -> rawptr #inline {
__check_context(); __check_context();
a := context.allocator; a := context.allocator;
return a.procedure(a.data, Allocator_Mode.RESIZE, new_size, alignment, ptr, old_size, 0); return a.procedure(a.data, Allocator_Mode.RESIZE, new_size, alignment, ptr, old_size, 0);
@@ -188,7 +184,7 @@ proc resize_align(ptr rawptr, old_size, new_size, alignment int) -> rawptr #inli
proc default_resize_align(old_memory rawptr, old_size, new_size, alignment int) -> rawptr { default_resize_align:: proc(old_memory rawptr, old_size, new_size, alignment int) -> rawptr {
if old_memory == nil { if old_memory == nil {
return alloc_align(new_size, alignment); return alloc_align(new_size, alignment);
} }
@@ -213,7 +209,7 @@ proc default_resize_align(old_memory rawptr, old_size, new_size, alignment int)
} }
proc default_allocator_proc(allocator_data rawptr, mode Allocator_Mode, default_allocator_proc:: proc(allocator_data rawptr, mode Allocator_Mode,
size, alignment int, size, alignment int,
old_memory rawptr, old_size int, flags u64) -> rawptr { old_memory rawptr, old_size int, flags u64) -> rawptr {
using Allocator_Mode; using Allocator_Mode;
@@ -263,7 +259,7 @@ proc default_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
return nil; return nil;
} }
proc default_allocator() -> Allocator { default_allocator:: proc() -> Allocator {
return Allocator{ return Allocator{
procedure = default_allocator_proc, procedure = default_allocator_proc,
data = nil, data = nil,
@@ -280,7 +276,7 @@ proc default_allocator() -> Allocator {
proc __string_eq(a, b string) -> bool { __string_eq:: proc(a, b string) -> bool {
if a.count != b.count { if a.count != b.count {
return false; return false;
} }
@@ -290,24 +286,24 @@ proc __string_eq(a, b string) -> bool {
return mem.compare(a.data, b.data, a.count) == 0; return mem.compare(a.data, b.data, a.count) == 0;
} }
proc __string_cmp(a, b string) -> int { __string_cmp:: proc(a, b string) -> int {
return mem.compare(a.data, b.data, min(a.count, b.count)); return mem.compare(a.data, b.data, min(a.count, b.count));
} }
proc __string_ne(a, b string) -> bool #inline { return !__string_eq(a, b); } __string_ne:: proc(a, b string) -> bool #inline { return !__string_eq(a, b); }
proc __string_lt(a, b string) -> bool #inline { return __string_cmp(a, b) < 0; } __string_lt:: proc(a, b string) -> bool #inline { return __string_cmp(a, b) < 0; }
proc __string_gt(a, b string) -> bool #inline { return __string_cmp(a, b) > 0; } __string_gt:: proc(a, b string) -> bool #inline { return __string_cmp(a, b) > 0; }
proc __string_le(a, b string) -> bool #inline { return __string_cmp(a, b) <= 0; } __string_le:: proc(a, b string) -> bool #inline { return __string_cmp(a, b) <= 0; }
proc __string_ge(a, b string) -> bool #inline { return __string_cmp(a, b) >= 0; } __string_ge:: proc(a, b string) -> bool #inline { return __string_cmp(a, b) >= 0; }
proc __assert(file string, line, column int, msg string) #inline { __assert:: proc(file string, line, column int, msg string) #inline {
fmt.fprintf(os.stderr, "%(%:%) Runtime assertion: %\n", fmt.fprintf(os.stderr, "%(%:%) Runtime assertion: %\n",
file, line, column, msg); file, line, column, msg);
__debug_trap(); __debug_trap();
} }
proc __bounds_check_error(file string, line, column int, index, count int) { __bounds_check_error:: proc(file string, line, column int, index, count int) {
if 0 <= index && index < count { if 0 <= index && index < count {
return; return;
} }
@@ -316,7 +312,7 @@ proc __bounds_check_error(file string, line, column int, index, count int) {
__debug_trap(); __debug_trap();
} }
proc __slice_expr_error(file string, line, column int, low, high, max int) { __slice_expr_error:: proc(file string, line, column int, low, high, max int) {
if 0 <= low && low <= high && high <= max { if 0 <= low && low <= high && high <= max {
return; return;
} }
@@ -324,7 +320,7 @@ proc __slice_expr_error(file string, line, column int, low, high, max int) {
file, line, column, low, high, max); file, line, column, low, high, max);
__debug_trap(); __debug_trap();
} }
proc __substring_expr_error(file string, line, column int, low, high int) { __substring_expr_error:: proc(file string, line, column int, low, high int) {
if 0 <= low && low <= high { if 0 <= low && low <= high {
return; return;
} }
+24 -24
View File
@@ -5,36 +5,36 @@ import win32 "sys/windows.odin" when ODIN_OS == "windows";
_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version _ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
proc yield_thread() { win32._mm_pause(); } yield_thread :: proc() { win32._mm_pause(); }
proc mfence () { win32.ReadWriteBarrier(); } mfence :: proc() { win32.ReadWriteBarrier(); }
proc sfence () { win32.WriteBarrier(); } sfence :: proc() { win32.WriteBarrier(); }
proc lfence () { win32.ReadBarrier(); } lfence :: proc() { win32.ReadBarrier(); }
proc load32(a ^i32) -> i32 { load32 :: proc(a ^i32) -> i32 {
return a^; return a^;
} }
proc store32(a ^i32, value i32) { store32 :: proc(a ^i32, value i32) {
a^ = value; a^ = value;
} }
proc compare_exchange32(a ^i32, expected, desired i32) -> i32 { compare_exchange32 :: proc(a ^i32, expected, desired i32) -> i32 {
return win32.InterlockedCompareExchange(a, desired, expected); return win32.InterlockedCompareExchange(a, desired, expected);
} }
proc exchanged32(a ^i32, desired i32) -> i32 { exchanged32 :: proc(a ^i32, desired i32) -> i32 {
return win32.InterlockedExchange(a, desired); return win32.InterlockedExchange(a, desired);
} }
proc fetch_add32(a ^i32, operand i32) -> i32 { fetch_add32 :: proc(a ^i32, operand i32) -> i32 {
return win32.InterlockedExchangeAdd(a, operand); return win32.InterlockedExchangeAdd(a, operand);
} }
proc fetch_and32(a ^i32, operand i32) -> i32 { fetch_and32 :: proc(a ^i32, operand i32) -> i32 {
return win32.InterlockedAnd(a, operand); return win32.InterlockedAnd(a, operand);
} }
proc fetch_or32(a ^i32, operand i32) -> i32 { fetch_or32 :: proc(a ^i32, operand i32) -> i32 {
return win32.InterlockedOr(a, operand); return win32.InterlockedOr(a, operand);
} }
proc spin_lock32(a ^i32, time_out int) -> bool { // NOTE(bill) time_out = -1 as default spin_lock32 :: proc(a ^i32, time_out int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange32(a, 1, 0); old_value := compare_exchange32(a, 1, 0);
counter := 0; counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) { for old_value != 0 && (time_out < 0 || counter < time_out) {
@@ -45,11 +45,11 @@ proc spin_lock32(a ^i32, time_out int) -> bool { // NOTE(bill) time_out = -1 as
} }
return old_value == 0; return old_value == 0;
} }
proc spin_unlock32(a ^i32) { spin_unlock32 :: proc(a ^i32) {
store32(a, 0); store32(a, 0);
mfence(); mfence();
} }
proc try_acquire_lock32(a ^i32) -> bool { try_acquire_lock32 :: proc(a ^i32) -> bool {
yield_thread(); yield_thread();
old_value := compare_exchange32(a, 1, 0); old_value := compare_exchange32(a, 1, 0);
mfence(); mfence();
@@ -57,28 +57,28 @@ proc try_acquire_lock32(a ^i32) -> bool {
} }
proc load64(a ^i64) -> i64 { load64 :: proc(a ^i64) -> i64 {
return a^; return a^;
} }
proc store64(a ^i64, value i64) { store64 :: proc(a ^i64, value i64) {
a^ = value; a^ = value;
} }
proc compare_exchange64(a ^i64, expected, desired i64) -> i64 { compare_exchange64 :: proc(a ^i64, expected, desired i64) -> i64 {
return win32.InterlockedCompareExchange64(a, desired, expected); return win32.InterlockedCompareExchange64(a, desired, expected);
} }
proc exchanged64(a ^i64, desired i64) -> i64 { exchanged64 :: proc(a ^i64, desired i64) -> i64 {
return win32.InterlockedExchange64(a, desired); return win32.InterlockedExchange64(a, desired);
} }
proc fetch_add64(a ^i64, operand i64) -> i64 { fetch_add64 :: proc(a ^i64, operand i64) -> i64 {
return win32.InterlockedExchangeAdd64(a, operand); return win32.InterlockedExchangeAdd64(a, operand);
} }
proc fetch_and64(a ^i64, operand i64) -> i64 { fetch_and64 :: proc(a ^i64, operand i64) -> i64 {
return win32.InterlockedAnd64(a, operand); return win32.InterlockedAnd64(a, operand);
} }
proc fetch_or64(a ^i64, operand i64) -> i64 { fetch_or64 :: proc(a ^i64, operand i64) -> i64 {
return win32.InterlockedOr64(a, operand); return win32.InterlockedOr64(a, operand);
} }
proc spin_lock64(a ^i64, time_out int) -> bool { // NOTE(bill) time_out = -1 as default spin_lock64 :: proc(a ^i64, time_out int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange64(a, 1, 0); old_value := compare_exchange64(a, 1, 0);
counter := 0; counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) { for old_value != 0 && (time_out < 0 || counter < time_out) {
@@ -89,11 +89,11 @@ proc spin_lock64(a ^i64, time_out int) -> bool { // NOTE(bill) time_out = -1 as
} }
return old_value == 0; return old_value == 0;
} }
proc spin_unlock64(a ^i64) { spin_unlock64 :: proc(a ^i64) {
store64(a, 0); store64(a, 0);
mfence(); mfence();
} }
proc try_acquire_lock64(a ^i64) -> bool { try_acquire_lock64 :: proc(a ^i64) -> bool {
yield_thread(); yield_thread();
old_value := compare_exchange64(a, 1, 0); old_value := compare_exchange64(a, 1, 0);
mfence(); mfence();
+37 -37
View File
@@ -6,23 +6,23 @@ import {
PRINT_BUF_SIZE :: 1<<12; PRINT_BUF_SIZE :: 1<<12;
proc fprint(fd os.Handle, args ..any) -> int { fprint :: proc(fd os.Handle, args ..any) -> int {
data :[PRINT_BUF_SIZE]byte; data: [PRINT_BUF_SIZE]byte;
buf := data[:0]; buf := data[:0];
bprint(^buf, ..args); bprint(^buf, ..args);
os.write(fd, buf); os.write(fd, buf);
return buf.count; return buf.count;
} }
proc fprintln(fd os.Handle, args ..any) -> int { fprintln :: proc(fd os.Handle, args ..any) -> int {
data :[PRINT_BUF_SIZE]byte; data: [PRINT_BUF_SIZE]byte;
buf := data[:0]; buf := data[:0];
bprintln(^buf, ..args); bprintln(^buf, ..args);
os.write(fd, buf); os.write(fd, buf);
return buf.count; return buf.count;
} }
proc fprintf(fd os.Handle, fmt string, args ..any) -> int { fprintf :: proc(fd os.Handle, fmt string, args ..any) -> int {
data :[PRINT_BUF_SIZE]byte; data: [PRINT_BUF_SIZE]byte;
buf := data[:0]; buf := data[:0];
bprintf(^buf, fmt, ..args); bprintf(^buf, fmt, ..args);
os.write(fd, buf); os.write(fd, buf);
@@ -30,20 +30,20 @@ proc fprintf(fd os.Handle, fmt string, args ..any) -> int {
} }
proc print(args ..any) -> int { print :: proc(args ..any) -> int {
return fprint(os.stdout, ..args); return fprint(os.stdout, ..args);
} }
proc println(args ..any) -> int { println :: proc(args ..any) -> int {
return fprintln(os.stdout, ..args); return fprintln(os.stdout, ..args);
} }
proc printf(fmt string, args ..any) -> int { printf :: proc(fmt string, args ..any) -> int {
return fprintf(os.stdout, fmt, ..args); return fprintf(os.stdout, fmt, ..args);
} }
proc fprint_type(fd os.Handle, info ^Type_Info) { fprint_type :: proc(fd os.Handle, info ^Type_Info) {
data :[PRINT_BUF_SIZE]byte; data: [PRINT_BUF_SIZE]byte;
buf := data[:0]; buf := data[:0];
bprint_type(^buf, info); bprint_type(^buf, info);
os.write(fd, buf); os.write(fd, buf);
@@ -51,7 +51,7 @@ proc fprint_type(fd os.Handle, info ^Type_Info) {
proc print_byte_buffer(buf ^[]byte, b []byte) { print_byte_buffer :: proc(buf ^[]byte, b []byte) {
if buf.count < buf.capacity { if buf.count < buf.capacity {
n := min(buf.capacity-buf.count, b.count); n := min(buf.capacity-buf.count, b.count);
if n > 0 { if n > 0 {
@@ -61,29 +61,29 @@ proc print_byte_buffer(buf ^[]byte, b []byte) {
} }
} }
proc bprint_string(buf ^[]byte, s string) { bprint_string :: proc(buf ^[]byte, s string) {
print_byte_buffer(buf, s as []byte); print_byte_buffer(buf, s as []byte);
} }
proc byte_reverse(b []byte) { byte_reverse :: proc(b []byte) {
n := b.count; n := b.count;
for i := 0; i < n/2; i++ { for i := 0; i < n/2; i++ {
b[i], b[n-1-i] = b[n-1-i], b[i]; b[i], b[n-1-i] = b[n-1-i], b[i];
} }
} }
proc bprint_rune(buf ^[]byte, r rune) { bprint_rune :: proc(buf ^[]byte, r rune) {
b, n := utf8.encode_rune(r); b, n := utf8.encode_rune(r);
bprint_string(buf, b[:n] as string); bprint_string(buf, b[:n] as string);
} }
proc bprint_space(buf ^[]byte) { bprint_rune(buf, ' '); } bprint_space :: proc(buf ^[]byte) { bprint_rune(buf, ' '); }
proc bprint_nl (buf ^[]byte) { bprint_rune(buf, '\n'); } bprint_nl :: proc (buf ^[]byte) { bprint_rune(buf, '\n'); }
__NUM_TO_CHAR_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"; __NUM_TO_CHAR_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$";
proc bprint_bool(buffer ^[]byte, b bool) { bprint_bool :: proc(buffer ^[]byte, b bool) {
if b { if b {
bprint_string(buffer, "true"); bprint_string(buffer, "true");
} else { } else {
@@ -91,15 +91,15 @@ proc bprint_bool(buffer ^[]byte, b bool) {
} }
} }
proc bprint_pointer(buffer ^[]byte, p rawptr) #inline { bprint_pointer :: proc(buffer ^[]byte, p rawptr) #inline {
bprint_string(buffer, "0x"); bprint_string(buffer, "0x");
bprint_u64(buffer, p as uint as u64); bprint_u64(buffer, p as uint as u64);
} }
proc bprint_f16 (buffer ^[]byte, f f32) #inline { print__f64(buffer, f as f64, 4); } bprint_f16 :: proc (buffer ^[]byte, f f32) #inline { print__f64(buffer, f as f64, 4); }
proc bprint_f32 (buffer ^[]byte, f f32) #inline { print__f64(buffer, f as f64, 7); } bprint_f32 :: proc (buffer ^[]byte, f f32) #inline { print__f64(buffer, f as f64, 7); }
proc bprint_f64 (buffer ^[]byte, f f64) #inline { print__f64(buffer, f as f64, 16); } bprint_f64 :: proc (buffer ^[]byte, f f64) #inline { print__f64(buffer, f as f64, 16); }
proc bprint_u64(buffer ^[]byte, value u64) { bprint_u64 :: proc(buffer ^[]byte, value u64) {
i := value; i := value;
buf :[20]byte; buf :[20]byte;
len := 0; len := 0;
@@ -115,7 +115,7 @@ proc bprint_u64(buffer ^[]byte, value u64) {
byte_reverse(buf[:len]); byte_reverse(buf[:len]);
bprint_string(buffer, buf[:len] as string); bprint_string(buffer, buf[:len] as string);
} }
proc bprint_i64(buffer ^[]byte, value i64) { bprint_i64 :: proc(buffer ^[]byte, value i64) {
// TODO(bill): Cleanup printing // TODO(bill): Cleanup printing
i := value; i := value;
if i < 0 { if i < 0 {
@@ -126,14 +126,14 @@ proc bprint_i64(buffer ^[]byte, value i64) {
} }
/* /*
proc bprint_u128(buffer ^[]byte, value u128) { bprint_u128 :: proc(buffer ^[]byte, value u128) {
a := value transmute [2]u64; a := value transmute [2]u64;
if a[1] != 0 { if a[1] != 0 {
bprint_u64(buffer, a[1]); bprint_u64(buffer, a[1]);
} }
bprint_u64(buffer, a[0]); bprint_u64(buffer, a[0]);
} }
proc bprint_i128(buffer ^[]byte, value i128) { bprint_i128 :: proc(buffer ^[]byte, value i128) {
i := value; i := value;
if i < 0 { if i < 0 {
i = -i; i = -i;
@@ -144,7 +144,7 @@ proc bprint_i128(buffer ^[]byte, value i128) {
*/ */
proc print__f64(buffer ^[]byte, value f64, decimal_places int) { print__f64 :: proc(buffer ^[]byte, value f64, decimal_places int) {
f := value; f := value;
if f == 0 { if f == 0 {
bprint_rune(buffer, '0'); bprint_rune(buffer, '0');
@@ -170,7 +170,7 @@ proc print__f64(buffer ^[]byte, value f64, decimal_places int) {
} }
} }
proc bprint_type(buf ^[]byte, ti ^Type_Info) { bprint_type :: proc(buf ^[]byte, ti ^Type_Info) {
if ti == nil { if ti == nil {
return; return;
} }
@@ -302,14 +302,14 @@ proc bprint_type(buf ^[]byte, ti ^Type_Info) {
} }
proc make_any(type_info ^Type_Info, data rawptr) -> any { make_any :: proc(type_info ^Type_Info, data rawptr) -> any {
a :any; a :any;
a.type_info = type_info; a.type_info = type_info;
a.data = data; a.data = data;
return a; return a;
} }
proc bprint_any(buf ^[]byte, arg any) { bprint_any :: proc(buf ^[]byte, arg any) {
if arg.type_info == nil { if arg.type_info == nil {
bprint_string(buf, "<nil>"); bprint_string(buf, "<nil>");
return; return;
@@ -423,7 +423,7 @@ proc bprint_any(buf ^[]byte, arg any) {
} }
case Vector: case Vector:
proc is_bool(type_info ^Type_Info) -> bool { is_bool :: proc(type_info ^Type_Info) -> bool {
match type info : type_info { match type info : type_info {
case Named: case Named:
return is_bool(info.base); return is_bool(info.base);
@@ -481,12 +481,12 @@ proc bprint_any(buf ^[]byte, arg any) {
} }
proc bprintf(buf ^[]byte, fmt string, args ..any) -> int { bprintf :: proc(buf ^[]byte, fmt string, args ..any) -> int {
proc is_digit(r rune) -> bool #inline { is_digit :: proc(r rune) -> bool #inline {
return '0' <= r && r <= '9'; return '0' <= r && r <= '9';
} }
proc parse_int(s string, offset int) -> (int, int) { parse_int :: proc(s string, offset int) -> (int, int) {
result := 0; result := 0;
for ; offset < s.count; offset++ { for ; offset < s.count; offset++ {
@@ -546,8 +546,8 @@ proc bprintf(buf ^[]byte, fmt string, args ..any) -> int {
} }
proc bprint(buf ^[]byte, args ..any) -> int { bprint :: proc(buf ^[]byte, args ..any) -> int {
proc is_type_string(info ^Type_Info) -> bool { is_type_string :: proc(info ^Type_Info) -> bool {
using Type_Info; using Type_Info;
if info == nil { if info == nil {
return false; return false;
@@ -574,7 +574,7 @@ proc bprint(buf ^[]byte, args ..any) -> int {
return buf.count; return buf.count;
} }
proc bprintln(buf ^[]byte, args ..any) -> int { bprintln :: proc(buf ^[]byte, args ..any) -> int {
for i := 0; i < args.count; i++ { for i := 0; i < args.count; i++ {
if i > 0 { if i > 0 {
append(buf, ' '); append(buf, ' ');
+7 -7
View File
@@ -1,4 +1,4 @@
proc crc32(data rawptr, len int) -> u32 { crc32 :: proc(data rawptr, len int) -> u32 {
result := ~(0 as u32); result := ~(0 as u32);
s := slice_ptr(data as ^u8, len); s := slice_ptr(data as ^u8, len);
for i := 0; i < len; i++ { for i := 0; i < len; i++ {
@@ -7,7 +7,7 @@ proc crc32(data rawptr, len int) -> u32 {
} }
return ~result; return ~result;
} }
proc crc64(data rawptr, len int) -> u64 { crc64 :: proc(data rawptr, len int) -> u64 {
result := ~(0 as u64); result := ~(0 as u64);
s := slice_ptr(data as ^u8, len); s := slice_ptr(data as ^u8, len);
for i := 0; i < len; i++ { for i := 0; i < len; i++ {
@@ -17,7 +17,7 @@ proc crc64(data rawptr, len int) -> u64 {
return ~result; return ~result;
} }
proc fnv32(data rawptr, len int) -> u32 { fnv32 :: proc(data rawptr, len int) -> u32 {
s := slice_ptr(data as ^u8, len); s := slice_ptr(data as ^u8, len);
h :u32 = 0x811c9dc5; h :u32 = 0x811c9dc5;
@@ -27,7 +27,7 @@ proc fnv32(data rawptr, len int) -> u32 {
return h; return h;
} }
proc fnv64(data rawptr, len int) -> u64 { fnv64 :: proc(data rawptr, len int) -> u64 {
s := slice_ptr(data as ^u8, len); s := slice_ptr(data as ^u8, len);
h :u64 = 0xcbf29ce484222325; h :u64 = 0xcbf29ce484222325;
@@ -37,7 +37,7 @@ proc fnv64(data rawptr, len int) -> u64 {
return h; return h;
} }
proc fnv32a(data rawptr, len int) -> u32 { fnv32a :: proc(data rawptr, len int) -> u32 {
s := slice_ptr(data as ^u8, len); s := slice_ptr(data as ^u8, len);
h :u32 = 0x811c9dc5; h :u32 = 0x811c9dc5;
@@ -47,7 +47,7 @@ proc fnv32a(data rawptr, len int) -> u32 {
return h; return h;
} }
proc fnv64a(data rawptr, len int) -> u64 { fnv64a :: proc(data rawptr, len int) -> u64 {
s := slice_ptr(data as ^u8, len); s := slice_ptr(data as ^u8, len);
h :u64 = 0xcbf29ce484222325; h :u64 = 0xcbf29ce484222325;
@@ -58,7 +58,7 @@ proc fnv64a(data rawptr, len int) -> u64 {
} }
proc murmur64(data_ rawptr, len int) -> u64 { murmur64 :: proc(data_ rawptr, len int) -> u64 {
SEED :: 0x9747b28c; SEED :: 0x9747b28c;
when size_of(int) == 8 { when size_of(int) == 8 {
+51 -53
View File
@@ -16,67 +16,65 @@ EPSILON :: 1.19209290e-7;
τ :: TAU; τ :: TAU;
π :: PI; π :: PI;
type { Vec2 :: [vector 2]f32;
Vec2 [vector 2]f32; Vec3 :: [vector 3]f32;
Vec3 [vector 3]f32; Vec4 :: [vector 4]f32;
Vec4 [vector 4]f32;
Mat2 [2]Vec2; Mat2 :: [2]Vec2;
Mat3 [3]Vec3; Mat3 :: [3]Vec3;
Mat4 [4]Vec4; Mat4 :: [4]Vec4;
}
proc sqrt32(x f32) -> f32 #foreign "llvm.sqrt.f32" sqrt32 :: proc(x f32) -> f32 #foreign "llvm.sqrt.f32"
proc sqrt64(x f64) -> f64 #foreign "llvm.sqrt.f64" sqrt64 :: proc(x f64) -> f64 #foreign "llvm.sqrt.f64"
proc sin32(x f32) -> f32 #foreign "llvm.sin.f32" sin32 :: proc(x f32) -> f32 #foreign "llvm.sin.f32"
proc sin64(x f64) -> f64 #foreign "llvm.sin.f64" sin64 :: proc(x f64) -> f64 #foreign "llvm.sin.f64"
proc cos32(x f32) -> f32 #foreign "llvm.cos.f32" cos32 :: proc(x f32) -> f32 #foreign "llvm.cos.f32"
proc cos64(x f64) -> f64 #foreign "llvm.cos.f64" cos64 :: proc(x f64) -> f64 #foreign "llvm.cos.f64"
proc tan32(x f32) -> f32 #inline { return sin32(x)/cos32(x); } tan32 :: proc(x f32) -> f32 #inline { return sin32(x)/cos32(x); }
proc tan64(x f64) -> f64 #inline { return sin64(x)/cos64(x); } tan64 :: proc(x f64) -> f64 #inline { return sin64(x)/cos64(x); }
proc lerp32(a, b, t f32) -> f32 { return a*(1-t) + b*t; } lerp32 :: proc(a, b, t f32) -> f32 { return a*(1-t) + b*t; }
proc lerp64(a, b, t f64) -> f64 { return a*(1-t) + b*t; } lerp64 :: proc(a, b, t f64) -> f64 { return a*(1-t) + b*t; }
proc sign32(x f32) -> f32 { if x >= 0 { return +1; } return -1; } sign32 :: proc(x f32) -> f32 { if x >= 0 { return +1; } return -1; }
proc sign64(x f64) -> f64 { if x >= 0 { return +1; } return -1; } sign64 :: proc(x f64) -> f64 { if x >= 0 { return +1; } return -1; }
proc copy_sign32(x, y f32) -> f32 { copy_sign32 :: proc(x, y f32) -> f32 {
ix := x transmute u32; ix := x transmute u32;
iy := y transmute u32; iy := y transmute u32;
ix &= 0x7fffffff; ix &= 0x7fffffff;
ix |= iy & 0x80000000; ix |= iy & 0x80000000;
return ix transmute f32; return ix transmute f32;
} }
proc round32(x f32) -> f32 { round32 :: proc(x f32) -> f32 {
if x >= 0 { if x >= 0 {
return floor32(x + 0.5); return floor32(x + 0.5);
} }
return ceil32(x - 0.5); return ceil32(x - 0.5);
} }
proc floor32(x f32) -> f32 { floor32 :: proc(x f32) -> f32 {
if x >= 0 { if x >= 0 {
return x as int as f32; return x as int as f32;
} }
return (x-0.5) as int as f32; return (x-0.5) as int as f32;
} }
proc ceil32(x f32) -> f32 { ceil32 :: proc(x f32) -> f32 {
if x < 0 { if x < 0 {
return x as int as f32; return x as int as f32;
} }
return ((x as int)+1) as f32; return ((x as int)+1) as f32;
} }
proc remainder32(x, y f32) -> f32 { remainder32 :: proc(x, y f32) -> f32 {
return x - round32(x/y) * y; return x - round32(x/y) * y;
} }
proc fmod32(x, y f32) -> f32 { fmod32 :: proc(x, y f32) -> f32 {
y = abs(y); y = abs(y);
result := remainder32(abs(x), y); result := remainder32(abs(x), y);
if sign32(result) < 0 { if sign32(result) < 0 {
@@ -86,32 +84,32 @@ proc fmod32(x, y f32) -> f32 {
} }
proc to_radians(degrees f32) -> f32 { return degrees * TAU / 360; } to_radians :: proc(degrees f32) -> f32 { return degrees * TAU / 360; }
proc to_degrees(radians f32) -> f32 { return radians * 360 / TAU; } to_degrees :: proc(radians f32) -> f32 { return radians * 360 / TAU; }
proc dot2(a, b Vec2) -> f32 { c := a*b; return c.x + c.y; } dot2 :: proc(a, b Vec2) -> f32 { c := a*b; return c.x + c.y; }
proc dot3(a, b Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; } dot3 :: proc(a, b Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
proc dot4(a, b Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; } dot4 :: proc(a, b Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
proc cross3(x, y Vec3) -> Vec3 { cross3 :: proc(x, y Vec3) -> Vec3 {
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1); a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0); b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
return a - b; return a - b;
} }
proc vec2_mag(v Vec2) -> f32 { return sqrt32(dot2(v, v)); } vec2_mag :: proc(v Vec2) -> f32 { return sqrt32(dot2(v, v)); }
proc vec3_mag(v Vec3) -> f32 { return sqrt32(dot3(v, v)); } vec3_mag :: proc(v Vec3) -> f32 { return sqrt32(dot3(v, v)); }
proc vec4_mag(v Vec4) -> f32 { return sqrt32(dot4(v, v)); } vec4_mag :: proc(v Vec4) -> f32 { return sqrt32(dot4(v, v)); }
proc vec2_norm(v Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)}; } vec2_norm :: proc(v Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)}; }
proc vec3_norm(v Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; } vec3_norm :: proc(v Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; }
proc vec4_norm(v Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)}; } vec4_norm :: proc(v Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)}; }
proc vec2_norm0(v Vec2) -> Vec2 { vec2_norm0 :: proc(v Vec2) -> Vec2 {
m := vec2_mag(v); m := vec2_mag(v);
if m == 0 { if m == 0 {
return Vec2{0}; return Vec2{0};
@@ -119,7 +117,7 @@ proc vec2_norm0(v Vec2) -> Vec2 {
return v / Vec2{m}; return v / Vec2{m};
} }
proc vec3_norm0(v Vec3) -> Vec3 { vec3_norm0 :: proc(v Vec3) -> Vec3 {
m := vec3_mag(v); m := vec3_mag(v);
if m == 0 { if m == 0 {
return Vec3{0}; return Vec3{0};
@@ -127,7 +125,7 @@ proc vec3_norm0(v Vec3) -> Vec3 {
return v / Vec3{m}; return v / Vec3{m};
} }
proc vec4_norm0(v Vec4) -> Vec4 { vec4_norm0 :: proc(v Vec4) -> Vec4 {
m := vec4_mag(v); m := vec4_mag(v);
if m == 0 { if m == 0 {
return Vec4{0}; return Vec4{0};
@@ -137,7 +135,7 @@ proc vec4_norm0(v Vec4) -> Vec4 {
proc mat4_identity() -> Mat4 { mat4_identity :: proc() -> Mat4 {
return Mat4{ return Mat4{
{1, 0, 0, 0}, {1, 0, 0, 0},
{0, 1, 0, 0}, {0, 1, 0, 0},
@@ -146,7 +144,7 @@ proc mat4_identity() -> Mat4 {
}; };
} }
proc mat4_transpose(m Mat4) -> Mat4 { mat4_transpose :: proc(m Mat4) -> Mat4 {
for j := 0; j < 4; j++ { for j := 0; j < 4; j++ {
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
m[i][j], m[j][i] = m[j][i], m[i][j]; m[i][j], m[j][i] = m[j][i], m[i][j];
@@ -155,7 +153,7 @@ proc mat4_transpose(m Mat4) -> Mat4 {
return m; return m;
} }
proc mat4_mul(a, b Mat4) -> Mat4 { mat4_mul :: proc(a, b Mat4) -> Mat4 {
c: Mat4; c: Mat4;
for j := 0; j < 4; j++ { for j := 0; j < 4; j++ {
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
@@ -168,7 +166,7 @@ proc mat4_mul(a, b Mat4) -> Mat4 {
return c; return c;
} }
proc mat4_mul_vec4(m Mat4, v Vec4) -> Vec4 { mat4_mul_vec4 :: proc(m Mat4, v Vec4) -> Vec4 {
return Vec4{ return Vec4{
m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w, m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w,
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w, m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
@@ -177,7 +175,7 @@ proc mat4_mul_vec4(m Mat4, v Vec4) -> Vec4 {
}; };
} }
proc mat4_inverse(m Mat4) -> Mat4 { mat4_inverse :: proc(m Mat4) -> Mat4 {
o: Mat4; o: Mat4;
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3]; sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
@@ -246,7 +244,7 @@ proc mat4_inverse(m Mat4) -> Mat4 {
} }
proc mat4_translate(v Vec3) -> Mat4 { mat4_translate :: proc(v Vec3) -> Mat4 {
m := mat4_identity(); m := mat4_identity();
m[3][0] = v.x; m[3][0] = v.x;
m[3][1] = v.y; m[3][1] = v.y;
@@ -255,7 +253,7 @@ proc mat4_translate(v Vec3) -> Mat4 {
return m; return m;
} }
proc mat4_rotate(v Vec3, angle_radians f32) -> Mat4 { mat4_rotate :: proc(v Vec3, angle_radians f32) -> Mat4 {
c := cos32(angle_radians); c := cos32(angle_radians);
s := sin32(angle_radians); s := sin32(angle_radians);
@@ -282,14 +280,14 @@ proc mat4_rotate(v Vec3, angle_radians f32) -> Mat4 {
return rot; return rot;
} }
proc mat4_scale(m Mat4, v Vec3) -> Mat4 { mat4_scale :: proc(m Mat4, v Vec3) -> Mat4 {
m[0][0] *= v.x; m[0][0] *= v.x;
m[1][1] *= v.y; m[1][1] *= v.y;
m[2][2] *= v.z; m[2][2] *= v.z;
return m; return m;
} }
proc mat4_scalef(m Mat4, s f32) -> Mat4 { mat4_scalef :: proc(m Mat4, s f32) -> Mat4 {
m[0][0] *= s; m[0][0] *= s;
m[1][1] *= s; m[1][1] *= s;
m[2][2] *= s; m[2][2] *= s;
@@ -297,7 +295,7 @@ proc mat4_scalef(m Mat4, s f32) -> Mat4 {
} }
proc mat4_look_at(eye, centre, up Vec3) -> Mat4 { mat4_look_at :: proc(eye, centre, up Vec3) -> Mat4 {
f := vec3_norm(centre - eye); f := vec3_norm(centre - eye);
s := vec3_norm(cross3(f, up)); s := vec3_norm(cross3(f, up));
u := cross3(s, f); u := cross3(s, f);
@@ -311,7 +309,7 @@ proc mat4_look_at(eye, centre, up Vec3) -> Mat4 {
return m; return m;
} }
proc mat4_perspective(fovy, aspect, near, far f32) -> Mat4 { mat4_perspective :: proc(fovy, aspect, near, far f32) -> Mat4 {
m: Mat4; m: Mat4;
tan_half_fovy := tan32(0.5 * fovy); tan_half_fovy := tan32(0.5 * fovy);
m[0][0] = 1.0 / (aspect*tan_half_fovy); m[0][0] = 1.0 / (aspect*tan_half_fovy);
@@ -323,7 +321,7 @@ proc mat4_perspective(fovy, aspect, near, far f32) -> Mat4 {
} }
proc mat4_ortho3d(left, right, bottom, top, near, far f32) -> Mat4 { mat4_ortho3d :: proc(left, right, bottom, top, near, far f32) -> Mat4 {
m := mat4_identity(); m := mat4_identity();
m[0][0] = +2.0 / (right - left); m[0][0] = +2.0 / (right - left);
m[1][1] = +2.0 / (top - bottom); m[1][1] = +2.0 / (top - bottom);
+38 -40
View File
@@ -3,32 +3,31 @@ import {
"os.odin"; "os.odin";
} }
proc set(data rawptr, value i32, len int) -> rawptr #link_name "__mem_set" { set :: proc(data rawptr, value i32, len int) -> rawptr #link_name "__mem_set" {
proc llvm_memset_64bit(dst rawptr, val byte, len int, align i32, is_volatile bool) #foreign "llvm.memset.p0i8.i64" llvm_memset_64bit :: proc(dst rawptr, val byte, len int, align i32, is_volatile bool) #foreign "llvm.memset.p0i8.i64"
llvm_memset_64bit(data, value as byte, len, 1, false); llvm_memset_64bit(data, value as byte, len, 1, false);
return data; return data;
} }
proc zero(data rawptr, len int) -> rawptr #link_name "__mem_zero" { zero :: proc(data rawptr, len int) -> rawptr #link_name "__mem_zero" {
return set(data, 0, len); return set(data, 0, len);
} }
proc copy(dst, src rawptr, len int) -> rawptr #link_name "__mem_copy" { copy :: proc(dst, src rawptr, len int) -> rawptr #link_name "__mem_copy" {
// NOTE(bill): This _must_ implemented like C's memmove // NOTE(bill): This _must_ implemented like C's memmove
proc llvm_memmove_64bit(dst, src rawptr, len int, align i32, is_volatile bool) #foreign "llvm.memmove.p0i8.p0i8.i64" llvm_memmove_64bit :: proc(dst, src rawptr, len int, align i32, is_volatile bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
llvm_memmove_64bit(dst, src, len, 1, false); llvm_memmove_64bit(dst, src, len, 1, false);
return dst; return dst;
} }
proc copy_non_overlapping(dst, src rawptr, len int) -> rawptr #link_name "__mem_copy_non_overlapping" { copy_non_overlapping :: proc(dst, src rawptr, len int) -> rawptr #link_name "__mem_copy_non_overlapping" {
// NOTE(bill): This _must_ implemented like C's memcpy // NOTE(bill): This _must_ implemented like C's memcpy
proc llvm_memcpy_64bit(dst, src rawptr, len int, align i32, is_volatile bool) #foreign "llvm.memcpy.p0i8.p0i8.i64" llvm_memcpy_64bit :: proc(dst, src rawptr, len int, align i32, is_volatile bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
llvm_memcpy_64bit(dst, src, len, 1, false); llvm_memcpy_64bit(dst, src, len, 1, false);
return dst; return dst;
} }
compare :: proc(dst, src rawptr, n int) -> int #link_name "__mem_compare" {
proc compare(dst, src rawptr, n int) -> int #link_name "__mem_compare" {
// Translation of http://mgronhol.github.io/fast-strcmp/ // Translation of http://mgronhol.github.io/fast-strcmp/
a := slice_ptr(dst as ^byte, n); a := slice_ptr(dst as ^byte, n);
b := slice_ptr(src as ^byte, n); b := slice_ptr(src as ^byte, n);
@@ -65,19 +64,19 @@ proc compare(dst, src rawptr, n int) -> int #link_name "__mem_compare" {
proc kilobytes(x int) -> int #inline { return (x) * 1024; } kilobytes :: proc(x int) -> int #inline { return (x) * 1024; }
proc megabytes(x int) -> int #inline { return kilobytes(x) * 1024; } megabytes :: proc(x int) -> int #inline { return kilobytes(x) * 1024; }
proc gigabytes(x int) -> int #inline { return gigabytes(x) * 1024; } gigabytes :: proc(x int) -> int #inline { return gigabytes(x) * 1024; }
proc terabytes(x int) -> int #inline { return terabytes(x) * 1024; } terabytes :: proc(x int) -> int #inline { return terabytes(x) * 1024; }
proc is_power_of_two(x int) -> bool { is_power_of_two :: proc(x int) -> bool {
if x <= 0 { if x <= 0 {
return false; return false;
} }
return (x & (x-1)) == 0; return (x & (x-1)) == 0;
} }
proc align_forward(ptr rawptr, align int) -> rawptr { align_forward :: proc(ptr rawptr, align int) -> rawptr {
assert(is_power_of_two(align)); assert(is_power_of_two(align));
a := align as uint; a := align as uint;
@@ -91,11 +90,11 @@ proc align_forward(ptr rawptr, align int) -> rawptr {
type Allocation_Header struct { Allocation_Header :: struct {
size int; size int;
} }
proc allocation_header_fill(header ^Allocation_Header, data rawptr, size int) { allocation_header_fill :: proc(header ^Allocation_Header, data rawptr, size int) {
header.size = size; header.size = size;
ptr := (header+1) as ^int; ptr := (header+1) as ^int;
@@ -103,7 +102,7 @@ proc allocation_header_fill(header ^Allocation_Header, data rawptr, size int) {
(ptr+i)^ = -1; (ptr+i)^ = -1;
} }
} }
proc allocation_header(data rawptr) -> ^Allocation_Header { allocation_header :: proc(data rawptr) -> ^Allocation_Header {
p := data as ^int; p := data as ^int;
for (p-1)^ == -1 { for (p-1)^ == -1 {
p = (p-1); p = (p-1);
@@ -116,35 +115,34 @@ proc allocation_header(data rawptr) -> ^Allocation_Header {
// Custom allocators // Custom allocators
type { Arena :: struct {
Arena struct { backing Allocator;
backing Allocator; memory []byte;
memory []byte; temp_count int;
temp_count int; }
}
Arena_Temp_Memory struct { Arena_Temp_Memory :: struct {
arena ^Arena; arena ^Arena;
original_count int; original_count int;
}
} }
proc init_arena_from_memory(using a ^Arena, data []byte) {
init_arena_from_memory :: proc(using a ^Arena, data []byte) {
backing = Allocator{}; backing = Allocator{};
memory = data[:0]; memory = data[:0];
temp_count = 0; temp_count = 0;
} }
proc init_arena_from_context(using a ^Arena, size int) { init_arena_from_context :: proc(using a ^Arena, size int) {
backing = context.allocator; backing = context.allocator;
memory = new_slice(byte, 0, size); memory = new_slice(byte, 0, size);
temp_count = 0; temp_count = 0;
} }
proc free_arena(using a ^Arena) { free_arena :: proc(using a ^Arena) {
if backing.procedure != nil { if backing.procedure != nil {
push_allocator backing { push_allocator backing {
free(memory.data); free(memory.data);
@@ -153,14 +151,14 @@ proc free_arena(using a ^Arena) {
} }
} }
proc arena_allocator(arena ^Arena) -> Allocator { arena_allocator :: proc(arena ^Arena) -> Allocator {
return Allocator{ return Allocator{
procedure = arena_allocator_proc, procedure = arena_allocator_proc,
data = arena, data = arena,
}; };
} }
proc arena_allocator_proc(allocator_data rawptr, mode Allocator_Mode, arena_allocator_proc :: proc(allocator_data rawptr, mode Allocator_Mode,
size, alignment int, size, alignment int,
old_memory rawptr, old_size int, flags u64) -> rawptr { old_memory rawptr, old_size int, flags u64) -> rawptr {
using Allocator_Mode; using Allocator_Mode;
@@ -195,7 +193,7 @@ proc arena_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
return nil; return nil;
} }
proc begin_arena_temp_memory(a ^Arena) -> Arena_Temp_Memory { begin_arena_temp_memory :: proc(a ^Arena) -> Arena_Temp_Memory {
tmp: Arena_Temp_Memory; tmp: Arena_Temp_Memory;
tmp.arena = a; tmp.arena = a;
tmp.original_count = a.memory.count; tmp.original_count = a.memory.count;
@@ -203,7 +201,7 @@ proc begin_arena_temp_memory(a ^Arena) -> Arena_Temp_Memory {
return tmp; return tmp;
} }
proc end_arena_temp_memory(using tmp Arena_Temp_Memory) { end_arena_temp_memory :: proc(using tmp Arena_Temp_Memory) {
assert(arena.memory.count >= original_count); assert(arena.memory.count >= original_count);
assert(arena.temp_count > 0); assert(arena.temp_count > 0);
arena.memory.count = original_count; arena.memory.count = original_count;
@@ -216,8 +214,8 @@ proc end_arena_temp_memory(using tmp Arena_Temp_Memory) {
proc align_of_type_info(type_info ^Type_Info) -> int { align_of_type_info :: proc(type_info ^Type_Info) -> int {
proc prev_pow2(n i64) -> i64 { prev_pow2 :: proc(n i64) -> i64 {
if n <= 0 { if n <= 0 {
return 0; return 0;
} }
@@ -271,12 +269,12 @@ proc align_of_type_info(type_info ^Type_Info) -> int {
return 0; return 0;
} }
proc align_formula(size, align int) -> int { align_formula :: proc(size, align int) -> int {
result := size + align-1; result := size + align-1;
return result - result%align; return result - result%align;
} }
proc size_of_type_info(type_info ^Type_Info) -> int { size_of_type_info :: proc(type_info ^Type_Info) -> int {
WORD_SIZE :: size_of(int); WORD_SIZE :: size_of(int);
using Type_Info; using Type_Info;
match type info : type_info { match type info : type_info {
@@ -310,7 +308,7 @@ proc size_of_type_info(type_info ^Type_Info) -> int {
case Slice: case Slice:
return 3*WORD_SIZE; return 3*WORD_SIZE;
case Vector: case Vector:
proc is_bool(type_info ^Type_Info) -> bool { is_bool :: proc(type_info ^Type_Info) -> bool {
match type info : type_info { match type info : type_info {
case Named: case Named:
return is_bool(info.base); return is_bool(info.base);
+27 -27
View File
@@ -2,37 +2,37 @@
import win32 "sys/windows.odin" when ODIN_OS == "windows"; import win32 "sys/windows.odin" when ODIN_OS == "windows";
include "opengl_constants.odin"; include "opengl_constants.odin";
proc Clear (mask u32) #foreign "glClear" Clear :: proc(mask u32) #foreign "glClear"
proc ClearColor (r, g, b, a f32) #foreign "glClearColor" ClearColor :: proc(r, g, b, a f32) #foreign "glClearColor"
proc Begin (mode i32) #foreign "glBegin" Begin :: proc(mode i32) #foreign "glBegin"
proc End () #foreign "glEnd" End :: proc() #foreign "glEnd"
proc Finish () #foreign "glFinish" Finish :: proc() #foreign "glFinish"
proc BlendFunc (sfactor, dfactor i32) #foreign "glBlendFunc" BlendFunc :: proc(sfactor, dfactor i32) #foreign "glBlendFunc"
proc Enable (cap i32) #foreign "glEnable" Enable :: proc(cap i32) #foreign "glEnable"
proc Disable (cap i32) #foreign "glDisable" Disable :: proc(cap i32) #foreign "glDisable"
proc GenTextures (count i32, result ^u32) #foreign "glGenTextures" GenTextures :: proc(count i32, result ^u32) #foreign "glGenTextures"
proc DeleteTextures(count i32, result ^u32) #foreign "glDeleteTextures" DeleteTextures:: proc(count i32, result ^u32) #foreign "glDeleteTextures"
proc TexParameteri (target, pname, param i32) #foreign "glTexParameteri" TexParameteri :: proc(target, pname, param i32) #foreign "glTexParameteri"
proc TexParameterf (target i32, pname i32, param f32) #foreign "glTexParameterf" TexParameterf :: proc(target i32, pname i32, param f32) #foreign "glTexParameterf"
proc BindTexture (target i32, texture u32) #foreign "glBindTexture" BindTexture :: proc(target i32, texture u32) #foreign "glBindTexture"
proc LoadIdentity () #foreign "glLoadIdentity" LoadIdentity :: proc() #foreign "glLoadIdentity"
proc Viewport (x, y, width, height i32) #foreign "glViewport" Viewport :: proc(x, y, width, height i32) #foreign "glViewport"
proc Ortho (left, right, bottom, top, near, far f64) #foreign "glOrtho" Ortho :: proc(left, right, bottom, top, near, far f64) #foreign "glOrtho"
proc Color3f (r, g, b f32) #foreign "glColor3f" Color3f :: proc(r, g, b f32) #foreign "glColor3f"
proc Vertex3f (x, y, z f32) #foreign "glVertex3f" Vertex3f :: proc(x, y, z f32) #foreign "glVertex3f"
proc TexImage2D (target, level, internal_format, TexImage2D :: proc(target, level, internal_format,
width, height, border, width, height, border,
format, _type i32, pixels rawptr) #foreign "glTexImage2D" format, _type i32, pixels rawptr) #foreign "glTexImage2D"
proc GetError () -> i32 #foreign "glGetError" GetError :: proc() -> i32 #foreign "glGetError"
proc GetString (name i32) -> ^byte #foreign "glGetString" GetString :: proc(name i32) -> ^byte #foreign "glGetString"
proc GetIntegerv(name i32, v ^i32) #foreign "glGetIntegerv" GetIntegerv :: proc(name i32, v ^i32) #foreign "glGetIntegerv"
_libgl := win32.LoadLibraryA(("opengl32.dll\x00" as string).data); _libgl := win32.LoadLibraryA(("opengl32.dll\x00" as string).data);
proc GetProcAddress(name string) -> proc() #cc_c { GetProcAddress :: proc(name string) -> proc() #cc_c {
assert(name[name.count-1] == 0); assert(name[name.count-1] == 0);
res := win32.wglGetProcAddress(name.data); res := win32.wglGetProcAddress(name.data);
if res == nil { if res == nil {
@@ -99,8 +99,8 @@ UniformMatrix4fv: proc(loc i32, count u32, transpose i32, value ^f32) #cc_c;
GetUniformLocation: proc(program u32, name ^byte) -> i32 #cc_c; GetUniformLocation: proc(program u32, name ^byte) -> i32 #cc_c;
proc init() { init :: proc() {
proc set_proc_address(p rawptr, name string) #inline { (p as ^(proc() #cc_c))^ = GetProcAddress(name); } set_proc_address :: proc(p rawptr, name string) #inline { (p as ^(proc() #cc_c))^ = GetProcAddress(name); }
set_proc_address(^GenBuffers, "glGenBuffers\x00"); set_proc_address(^GenBuffers, "glGenBuffers\x00");
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00"); set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
+18 -20
View File
@@ -4,11 +4,9 @@ import {
} }
type { Handle :: uint;
Handle uint; File_Time :: u64;
File_Time u64; Error :: int;
Error int;
}
INVALID_HANDLE: Handle : ~(0 as Handle); INVALID_HANDLE: Handle : ~(0 as Handle);
@@ -56,7 +54,7 @@ ERROR_FILE_IS_PIPE : Error : 1<<29 + 0;
proc open(path string, mode int, perm u32) -> (Handle, Error) { open :: proc(path string, mode int, perm u32) -> (Handle, Error) {
using win32; using win32;
if path.count == 0 { if path.count == 0 {
return INVALID_HANDLE, ERROR_FILE_NOT_FOUND; return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
@@ -109,11 +107,11 @@ proc open(path string, mode int, perm u32) -> (Handle, Error) {
return INVALID_HANDLE, err as Error; return INVALID_HANDLE, err as Error;
} }
proc close(fd Handle) { close :: proc(fd Handle) {
win32.CloseHandle(fd as win32.HANDLE); win32.CloseHandle(fd as win32.HANDLE);
} }
proc write(fd Handle, data []byte) -> (int, Error) { write :: proc(fd Handle, data []byte) -> (int, Error) {
bytes_written: i32; bytes_written: i32;
e := win32.WriteFile(fd as win32.HANDLE, data.data, data.count as i32, ^bytes_written, nil); e := win32.WriteFile(fd as win32.HANDLE, data.data, data.count as i32, ^bytes_written, nil);
if e != 0 { if e != 0 {
@@ -122,7 +120,7 @@ proc write(fd Handle, data []byte) -> (int, Error) {
return bytes_written as int, ERROR_NONE; return bytes_written as int, ERROR_NONE;
} }
proc read(fd Handle, data []byte) -> (int, Error) { read :: proc(fd Handle, data []byte) -> (int, Error) {
bytes_read: i32; bytes_read: i32;
e := win32.ReadFile(fd as win32.HANDLE, data.data, data.count as u32, ^bytes_read, nil); e := win32.ReadFile(fd as win32.HANDLE, data.data, data.count as u32, ^bytes_read, nil);
if e != win32.FALSE { if e != win32.FALSE {
@@ -132,7 +130,7 @@ proc read(fd Handle, data []byte) -> (int, Error) {
return bytes_read as int, ERROR_NONE; return bytes_read as int, ERROR_NONE;
} }
proc seek(fd Handle, offset i64, whence int) -> (i64, Error) { seek :: proc(fd Handle, offset i64, whence int) -> (i64, Error) {
using win32; using win32;
w: u32; w: u32;
match whence { match whence {
@@ -161,7 +159,7 @@ stdout := get_std_handle(win32.STD_OUTPUT_HANDLE);
stderr := get_std_handle(win32.STD_ERROR_HANDLE); stderr := get_std_handle(win32.STD_ERROR_HANDLE);
proc get_std_handle(h int) -> Handle { get_std_handle :: proc(h int) -> Handle {
fd := win32.GetStdHandle(h as i32); fd := win32.GetStdHandle(h as i32);
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0); win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
return fd as Handle; return fd as Handle;
@@ -172,7 +170,7 @@ proc get_std_handle(h int) -> Handle {
proc last_write_time(fd Handle) -> File_Time { last_write_time :: proc(fd Handle) -> File_Time {
file_info: win32.BY_HANDLE_FILE_INFORMATION; file_info: win32.BY_HANDLE_FILE_INFORMATION;
win32.GetFileInformationByHandle(fd as win32.HANDLE, ^file_info); win32.GetFileInformationByHandle(fd as win32.HANDLE, ^file_info);
lo := file_info.last_write_time.lo as File_Time; lo := file_info.last_write_time.lo as File_Time;
@@ -180,7 +178,7 @@ proc last_write_time(fd Handle) -> File_Time {
return lo | hi << 32; return lo | hi << 32;
} }
proc last_write_time_by_name(name string) -> File_Time { last_write_time_by_name :: proc(name string) -> File_Time {
last_write_time: win32.FILETIME; last_write_time: win32.FILETIME;
data: win32.FILE_ATTRIBUTE_DATA; data: win32.FILE_ATTRIBUTE_DATA;
buf: [1024]byte; buf: [1024]byte;
@@ -202,7 +200,7 @@ proc last_write_time_by_name(name string) -> File_Time {
proc read_entire_file(name string) -> ([]byte, bool) { read_entire_file :: proc(name string) -> ([]byte, bool) {
buf: [300]byte; buf: [300]byte;
copy(buf[:], name as []byte); copy(buf[:], name as []byte);
@@ -250,25 +248,25 @@ proc read_entire_file(name string) -> ([]byte, bool) {
proc heap_alloc(size int) -> rawptr { heap_alloc :: proc(size int) -> rawptr {
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size); return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size);
} }
proc heap_resize(ptr rawptr, new_size int) -> rawptr { heap_resize :: proc(ptr rawptr, new_size int) -> rawptr {
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size); return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
} }
proc heap_free(ptr rawptr) { heap_free :: proc(ptr rawptr) {
win32.HeapFree(win32.GetProcessHeap(), 0, ptr); win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
} }
proc exit(code int) { exit :: proc(code int) {
win32.ExitProcess(code as u32); win32.ExitProcess(code as u32);
} }
proc current_thread_id() -> int { current_thread_id :: proc() -> int {
proc GetCurrentThreadId() -> u32 #foreign #dll_import GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
return GetCurrentThreadId() as int; return GetCurrentThreadId() as int;
} }
+20 -22
View File
@@ -3,52 +3,50 @@ import {
"atomic.odin"; "atomic.odin";
} }
type { Semaphore :: struct {
Semaphore struct { handle win32.HANDLE;
handle win32.HANDLE;
}
Mutex struct {
semaphore Semaphore;
counter i32;
owner i32;
recursion i32;
}
} }
proc current_thread_id() -> i32 { Mutex :: struct {
semaphore Semaphore;
counter i32;
owner i32;
recursion i32;
}
current_thread_id :: proc() -> i32 {
return win32.GetCurrentThreadId() as i32; return win32.GetCurrentThreadId() as i32;
} }
proc semaphore_init(s ^Semaphore) { semaphore_init :: proc(s ^Semaphore) {
s.handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil); s.handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
} }
proc semaphore_destroy(s ^Semaphore) { semaphore_destroy :: proc(s ^Semaphore) {
win32.CloseHandle(s.handle); win32.CloseHandle(s.handle);
} }
proc semaphore_post(s ^Semaphore, count int) { semaphore_post :: proc(s ^Semaphore, count int) {
win32.ReleaseSemaphore(s.handle, count as i32, nil); win32.ReleaseSemaphore(s.handle, count as i32, nil);
} }
proc semaphore_release(s ^Semaphore) #inline { semaphore_post(s, 1); } semaphore_release :: proc(s ^Semaphore) #inline { semaphore_post(s, 1); }
proc semaphore_wait(s ^Semaphore) { semaphore_wait :: proc(s ^Semaphore) {
win32.WaitForSingleObject(s.handle, win32.INFINITE); win32.WaitForSingleObject(s.handle, win32.INFINITE);
} }
proc mutex_init(m ^Mutex) { mutex_init :: proc(m ^Mutex) {
atomic.store32(^m.counter, 0); atomic.store32(^m.counter, 0);
atomic.store32(^m.owner, current_thread_id()); atomic.store32(^m.owner, current_thread_id());
semaphore_init(^m.semaphore); semaphore_init(^m.semaphore);
m.recursion = 0; m.recursion = 0;
} }
proc mutex_destroy(m ^Mutex) { mutex_destroy :: proc(m ^Mutex) {
semaphore_destroy(^m.semaphore); semaphore_destroy(^m.semaphore);
} }
proc mutex_lock(m ^Mutex) { mutex_lock :: proc(m ^Mutex) {
thread_id := current_thread_id(); thread_id := current_thread_id();
if atomic.fetch_add32(^m.counter, 1) > 0 { if atomic.fetch_add32(^m.counter, 1) > 0 {
if thread_id != atomic.load32(^m.owner) { if thread_id != atomic.load32(^m.owner) {
@@ -58,7 +56,7 @@ proc mutex_lock(m ^Mutex) {
atomic.store32(^m.owner, thread_id); atomic.store32(^m.owner, thread_id);
m.recursion++; m.recursion++;
} }
proc mutex_try_lock(m ^Mutex) -> bool { mutex_try_lock :: proc(m ^Mutex) -> bool {
thread_id := current_thread_id(); thread_id := current_thread_id();
if atomic.load32(^m.owner) == thread_id { if atomic.load32(^m.owner) == thread_id {
atomic.fetch_add32(^m.counter, 1); atomic.fetch_add32(^m.counter, 1);
@@ -75,7 +73,7 @@ proc mutex_try_lock(m ^Mutex) -> bool {
m.recursion++; m.recursion++;
return true; return true;
} }
proc mutex_unlock(m ^Mutex) { mutex_unlock :: proc(m ^Mutex) {
recursion: i32; recursion: i32;
thread_id := current_thread_id(); thread_id := current_thread_id();
assert(thread_id == atomic.load32(^m.owner)); assert(thread_id == atomic.load32(^m.owner));
+210 -217
View File
@@ -1,24 +1,22 @@
#foreign_system_library "user32" when ODIN_OS == "windows"; #foreign_system_library "user32" when ODIN_OS == "windows";
#foreign_system_library "gdi32" when ODIN_OS == "windows"; #foreign_system_library "gdi32" when ODIN_OS == "windows";
type { HANDLE :: rawptr;
HANDLE rawptr; HWND :: HANDLE;
HWND HANDLE; HDC :: HANDLE;
HDC HANDLE; HINSTANCE :: HANDLE;
HINSTANCE HANDLE; HICON :: HANDLE;
HICON HANDLE; HCURSOR :: HANDLE;
HCURSOR HANDLE; HMENU :: HANDLE;
HMENU HANDLE; HBRUSH :: HANDLE;
HBRUSH HANDLE; HGDIOBJ :: HANDLE;
HGDIOBJ HANDLE; HMODULE :: HANDLE;
HMODULE HANDLE; WPARAM :: uint;
WPARAM uint; LPARAM :: int;
LPARAM int; LRESULT :: int;
LRESULT int; ATOM :: i16;
ATOM i16; BOOL :: i32;
BOOL i32; WNDPROC :: type proc(hwnd HWND, msg u32, wparam WPARAM, lparam LPARAM) -> LRESULT;
WNDPROC proc(hwnd HWND, msg u32, wparam WPARAM, lparam LPARAM) -> LRESULT;
}
INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE; INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE;
@@ -57,137 +55,136 @@ SM_CYSCREEN :: 1;
SW_SHOW :: 5; SW_SHOW :: 5;
type { POINT :: struct #ordered {
POINT struct #ordered { x, y i32;
x, y i32;
}
WNDCLASSEXA struct #ordered {
size, style u32;
wnd_proc WNDPROC;
cls_extra, wnd_extra i32;
instance HINSTANCE;
icon HICON;
cursor HCURSOR;
background HBRUSH;
menu_name, class_name ^u8;
sm HICON;
}
MSG struct #ordered {
hwnd HWND;
message u32;
wparam WPARAM;
lparam LPARAM;
time u32;
pt POINT;
}
RECT struct #ordered {
left i32;
top i32;
right i32;
bottom i32;
}
FILETIME struct #ordered {
lo, hi u32;
}
BY_HANDLE_FILE_INFORMATION struct #ordered {
file_attributes u32;
creation_time,
last_access_time,
last_write_time FILETIME;
volume_serial_number,
file_size_high,
file_size_low,
number_of_links,
file_index_high,
file_index_low u32;
}
FILE_ATTRIBUTE_DATA struct #ordered {
file_attributes u32;
creation_time,
last_access_time,
last_write_time FILETIME;
file_size_high,
file_size_low u32;
}
GET_FILEEX_INFO_LEVELS i32;
} }
WNDCLASSEXA :: struct #ordered {
size, style u32;
wnd_proc WNDPROC;
cls_extra, wnd_extra i32;
instance HINSTANCE;
icon HICON;
cursor HCURSOR;
background HBRUSH;
menu_name, class_name ^u8;
sm HICON;
}
MSG :: struct #ordered {
hwnd HWND;
message u32;
wparam WPARAM;
lparam LPARAM;
time u32;
pt POINT;
}
RECT :: struct #ordered {
left i32;
top i32;
right i32;
bottom i32;
}
FILETIME :: struct #ordered {
lo, hi u32;
}
BY_HANDLE_FILE_INFORMATION :: struct #ordered {
file_attributes u32;
creation_time,
last_access_time,
last_write_time FILETIME;
volume_serial_number,
file_size_high,
file_size_low,
number_of_links,
file_index_high,
file_index_low u32;
}
FILE_ATTRIBUTE_DATA :: struct #ordered {
file_attributes u32;
creation_time,
last_access_time,
last_write_time FILETIME;
file_size_high,
file_size_low u32;
}
GET_FILEEX_INFO_LEVELS :: i32;
GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0; GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0;
GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1; GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1;
proc GetLastError () -> i32 #foreign #dll_import GetLastError :: proc() -> i32 #foreign #dll_import
proc ExitProcess (exit_code u32) #foreign #dll_import ExitProcess :: proc(exit_code u32) #foreign #dll_import
proc GetDesktopWindow() -> HWND #foreign #dll_import GetDesktopWindow :: proc() -> HWND #foreign #dll_import
proc GetCursorPos (p ^POINT) -> i32 #foreign #dll_import GetCursorPos :: proc(p ^POINT) -> i32 #foreign #dll_import
proc ScreenToClient (h HWND, p ^POINT) -> i32 #foreign #dll_import ScreenToClient :: proc(h HWND, p ^POINT) -> i32 #foreign #dll_import
proc GetModuleHandleA(module_name ^u8) -> HINSTANCE #foreign #dll_import GetModuleHandleA :: proc(module_name ^u8) -> HINSTANCE #foreign #dll_import
proc GetStockObject (fn_object i32) -> HGDIOBJ #foreign #dll_import GetStockObject :: proc(fn_object i32) -> HGDIOBJ #foreign #dll_import
proc PostQuitMessage (exit_code i32) #foreign #dll_import PostQuitMessage :: proc(exit_code i32) #foreign #dll_import
proc SetWindowTextA (hwnd HWND, c_string ^u8) -> BOOL #foreign #dll_import SetWindowTextA :: proc(hwnd HWND, c_string ^u8) -> BOOL #foreign #dll_import
proc QueryPerformanceFrequency(result ^i64) -> i32 #foreign #dll_import QueryPerformanceFrequency :: proc(result ^i64) -> i32 #foreign #dll_import
proc QueryPerformanceCounter (result ^i64) -> i32 #foreign #dll_import QueryPerformanceCounter :: proc(result ^i64) -> i32 #foreign #dll_import
proc Sleep(ms i32) -> i32 #foreign #dll_import Sleep :: proc(ms i32) -> i32 #foreign #dll_import
proc OutputDebugStringA(c_str ^u8) #foreign #dll_import OutputDebugStringA :: proc(c_str ^u8) #foreign #dll_import
proc RegisterClassExA(wc ^WNDCLASSEXA) -> ATOM #foreign #dll_import RegisterClassExA :: proc(wc ^WNDCLASSEXA) -> ATOM #foreign #dll_import
proc CreateWindowExA (ex_style u32, CreateWindowExA :: proc(ex_style u32,
class_name, title ^u8, class_name, title ^u8,
style u32, style u32,
x, y, w, h i32, x, y, w, h i32,
parent HWND, menu HMENU, instance HINSTANCE, parent HWND, menu HMENU, instance HINSTANCE,
param rawptr) -> HWND #foreign #dll_import param rawptr) -> HWND #foreign #dll_import
proc ShowWindow (hwnd HWND, cmd_show i32) -> BOOL #foreign #dll_import ShowWindow :: proc(hwnd HWND, cmd_show i32) -> BOOL #foreign #dll_import
proc TranslateMessage(msg ^MSG) -> BOOL #foreign #dll_import TranslateMessage :: proc(msg ^MSG) -> BOOL #foreign #dll_import
proc DispatchMessageA(msg ^MSG) -> LRESULT #foreign #dll_import DispatchMessageA :: proc(msg ^MSG) -> LRESULT #foreign #dll_import
proc UpdateWindow (hwnd HWND) -> BOOL #foreign #dll_import UpdateWindow :: proc(hwnd HWND) -> BOOL #foreign #dll_import
proc PeekMessageA (msg ^MSG, hwnd HWND, PeekMessageA :: proc(msg ^MSG, hwnd HWND,
msg_filter_min, msg_filter_max, remove_msg u32) -> BOOL #foreign #dll_import msg_filter_min, msg_filter_max, remove_msg u32) -> BOOL #foreign #dll_import
proc DefWindowProcA (hwnd HWND, msg u32, wparam WPARAM, lparam LPARAM) -> LRESULT #foreign #dll_import DefWindowProcA :: proc(hwnd HWND, msg u32, wparam WPARAM, lparam LPARAM) -> LRESULT #foreign #dll_import
proc AdjustWindowRect(rect ^RECT, style u32, menu BOOL) -> BOOL #foreign #dll_import AdjustWindowRect :: proc(rect ^RECT, style u32, menu BOOL) -> BOOL #foreign #dll_import
proc GetActiveWindow () -> HWND #foreign #dll_import GetActiveWindow :: proc() -> HWND #foreign #dll_import
proc GetQueryPerformanceFrequency() -> i64 { GetQueryPerformanceFrequency :: proc() -> i64 {
r: i64; r: i64;
QueryPerformanceFrequency(^r); QueryPerformanceFrequency(^r);
return r; return r;
} }
proc GetCommandLineA() -> ^u8 #foreign #dll_import GetCommandLineA :: proc() -> ^u8 #foreign #dll_import
proc GetSystemMetrics(index i32) -> i32 #foreign #dll_import GetSystemMetrics :: proc(index i32) -> i32 #foreign #dll_import
proc GetCurrentThreadId() -> u32 #foreign #dll_import GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
// File Stuff // File Stuff
proc CloseHandle (h HANDLE) -> i32 #foreign #dll_import CloseHandle :: proc(h HANDLE) -> i32 #foreign #dll_import
proc GetStdHandle(h i32) -> HANDLE #foreign #dll_import GetStdHandle :: proc(h i32) -> HANDLE #foreign #dll_import
proc CreateFileA (filename ^u8, desired_access, share_mode u32, CreateFileA :: proc(filename ^u8, desired_access, share_mode u32,
security rawptr, security rawptr,
creation, flags_and_attribs u32, template_file HANDLE) -> HANDLE #foreign #dll_import creation, flags_and_attribs u32, template_file HANDLE) -> HANDLE #foreign #dll_import
proc ReadFile (h HANDLE, buf rawptr, to_read u32, bytes_read ^i32, overlapped rawptr) -> BOOL #foreign #dll_import ReadFile :: proc(h HANDLE, buf rawptr, to_read u32, bytes_read ^i32, overlapped rawptr) -> BOOL #foreign #dll_import
proc WriteFile (h HANDLE, buf rawptr, len i32, written_result ^i32, overlapped rawptr) -> i32 #foreign #dll_import WriteFile :: proc(h HANDLE, buf rawptr, len i32, written_result ^i32, overlapped rawptr) -> i32 #foreign #dll_import
proc GetFileSizeEx (file_handle HANDLE, file_size ^i64) -> BOOL #foreign #dll_import GetFileSizeEx :: proc(file_handle HANDLE, file_size ^i64) -> BOOL #foreign #dll_import
proc GetFileAttributesExA (filename ^u8, info_level_id GET_FILEEX_INFO_LEVELS, file_info rawptr) -> BOOL #foreign #dll_import GetFileAttributesExA :: proc(filename ^u8, info_level_id GET_FILEEX_INFO_LEVELS, file_info rawptr) -> BOOL #foreign #dll_import
proc GetFileInformationByHandle(file_handle HANDLE, file_info ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign #dll_import GetFileInformationByHandle :: proc(file_handle HANDLE, file_info ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign #dll_import
proc GetFileType(file_handle HANDLE) -> u32 #foreign #dll_import GetFileType :: proc(file_handle HANDLE) -> u32 #foreign #dll_import
proc SetFilePointer(file_handle HANDLE, distance_to_move i32, distance_to_move_high ^i32, move_method u32) -> u32 #foreign #dll_import SetFilePointer :: proc(file_handle HANDLE, distance_to_move i32, distance_to_move_high ^i32, move_method u32) -> u32 #foreign #dll_import
proc SetHandleInformation(obj HANDLE, mask, flags u32) -> BOOL #foreign #dll_import SetHandleInformation :: proc(obj HANDLE, mask, flags u32) -> BOOL #foreign #dll_import
HANDLE_FLAG_INHERIT :: 1; HANDLE_FLAG_INHERIT :: 1;
HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2; HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2;
@@ -241,17 +238,17 @@ INVALID_SET_FILE_POINTER :: ~(0 as u32);
proc HeapAlloc (h HANDLE, flags u32, bytes int) -> rawptr #foreign #dll_import HeapAlloc :: proc (h HANDLE, flags u32, bytes int) -> rawptr #foreign #dll_import
proc HeapReAlloc (h HANDLE, flags u32, memory rawptr, bytes int) -> rawptr #foreign #dll_import HeapReAlloc :: proc (h HANDLE, flags u32, memory rawptr, bytes int) -> rawptr #foreign #dll_import
proc HeapFree (h HANDLE, flags u32, memory rawptr) -> BOOL #foreign #dll_import HeapFree :: proc (h HANDLE, flags u32, memory rawptr) -> BOOL #foreign #dll_import
proc GetProcessHeap() -> HANDLE #foreign #dll_import GetProcessHeap :: proc () -> HANDLE #foreign #dll_import
HEAP_ZERO_MEMORY :: 0x00000008; HEAP_ZERO_MEMORY :: 0x00000008;
// Synchronization // Synchronization
type SECURITY_ATTRIBUTES struct #ordered { SECURITY_ATTRIBUTES :: struct #ordered {
length u32; length u32;
security_descriptor rawptr; security_descriptor rawptr;
inherit_handle BOOL; inherit_handle BOOL;
@@ -259,51 +256,49 @@ type SECURITY_ATTRIBUTES struct #ordered {
INFINITE :: 0xffffffff; INFINITE :: 0xffffffff;
proc CreateSemaphoreA (attributes ^SECURITY_ATTRIBUTES, initial_count, maximum_count i32, name ^byte) -> HANDLE #foreign #dll_import CreateSemaphoreA :: proc(attributes ^SECURITY_ATTRIBUTES, initial_count, maximum_count i32, name ^byte) -> HANDLE #foreign #dll_import
proc ReleaseSemaphore (semaphore HANDLE, release_count i32, previous_count ^i32) -> BOOL #foreign #dll_import ReleaseSemaphore :: proc(semaphore HANDLE, release_count i32, previous_count ^i32) -> BOOL #foreign #dll_import
proc WaitForSingleObject(handle HANDLE, milliseconds u32) -> u32 #foreign #dll_import WaitForSingleObject :: proc(handle HANDLE, milliseconds u32) -> u32 #foreign #dll_import
proc InterlockedCompareExchange(dst ^i32, exchange, comparand i32) -> i32 #foreign InterlockedCompareExchange :: proc(dst ^i32, exchange, comparand i32) -> i32 #foreign
proc InterlockedExchange (dst ^i32, desired i32) -> i32 #foreign InterlockedExchange :: proc(dst ^i32, desired i32) -> i32 #foreign
proc InterlockedExchangeAdd (dst ^i32, desired i32) -> i32 #foreign InterlockedExchangeAdd :: proc(dst ^i32, desired i32) -> i32 #foreign
proc InterlockedAnd (dst ^i32, desired i32) -> i32 #foreign InterlockedAnd :: proc(dst ^i32, desired i32) -> i32 #foreign
proc InterlockedOr (dst ^i32, desired i32) -> i32 #foreign InterlockedOr :: proc(dst ^i32, desired i32) -> i32 #foreign
proc InterlockedCompareExchange64(dst ^i64, exchange, comparand i64) -> i64 #foreign InterlockedCompareExchange64 :: proc(dst ^i64, exchange, comparand i64) -> i64 #foreign
proc InterlockedExchange64 (dst ^i64, desired i64) -> i64 #foreign InterlockedExchange64 :: proc(dst ^i64, desired i64) -> i64 #foreign
proc InterlockedExchangeAdd64 (dst ^i64, desired i64) -> i64 #foreign InterlockedExchangeAdd64 :: proc(dst ^i64, desired i64) -> i64 #foreign
proc InterlockedAnd64 (dst ^i64, desired i64) -> i64 #foreign InterlockedAnd64 :: proc(dst ^i64, desired i64) -> i64 #foreign
proc InterlockedOr64 (dst ^i64, desired i64) -> i64 #foreign InterlockedOr64 :: proc(dst ^i64, desired i64) -> i64 #foreign
proc _mm_pause () #foreign _mm_pause :: proc() #foreign
proc ReadWriteBarrier() #foreign ReadWriteBarrier :: proc() #foreign
proc WriteBarrier () #foreign WriteBarrier :: proc() #foreign
proc ReadBarrier () #foreign ReadBarrier :: proc() #foreign
// GDI // GDI
type { BITMAPINFOHEADER :: struct #ordered {
BITMAPINFOHEADER struct #ordered { size u32;
size u32; width, height i32;
width, height i32; planes, bit_count i16;
planes, bit_count i16; compression u32;
compression u32; size_image u32;
size_image u32; x_pels_per_meter i32;
x_pels_per_meter i32; y_pels_per_meter i32;
y_pels_per_meter i32; clr_used u32;
clr_used u32; clr_important u32;
clr_important u32; }
} BITMAPINFO :: struct #ordered {
BITMAPINFO struct #ordered { using header BITMAPINFOHEADER;
using header BITMAPINFOHEADER; colors [1]RGBQUAD;
colors [1]RGBQUAD; }
}
RGBQUAD struct #ordered { RGBQUAD :: struct #ordered {
blue, green, red, reserved byte; blue, green, red, reserved byte;
}
} }
BI_RGB :: 0; BI_RGB :: 0;
@@ -311,20 +306,20 @@ DIB_RGB_COLORS :: 0x00;
SRCCOPY: u32 : 0x00cc0020; SRCCOPY: u32 : 0x00cc0020;
proc StretchDIBits(hdc HDC, StretchDIBits :: proc (hdc HDC,
x_dst, y_dst, width_dst, height_dst i32, x_dst, y_dst, width_dst, height_dst i32,
x_src, y_src, width_src, header_src i32, x_src, y_src, width_src, header_src i32,
bits rawptr, bits_info ^BITMAPINFO, bits rawptr, bits_info ^BITMAPINFO,
usage u32, usage u32,
rop u32) -> i32 #foreign #dll_import rop u32) -> i32 #foreign #dll_import
proc LoadLibraryA (c_str ^u8) -> HMODULE #foreign LoadLibraryA :: proc (c_str ^u8) -> HMODULE #foreign
proc FreeLibrary (h HMODULE) #foreign FreeLibrary :: proc (h HMODULE) #foreign
proc GetProcAddress(h HMODULE, c_str ^u8) -> PROC #foreign GetProcAddress :: proc (h HMODULE, c_str ^u8) -> PROC #foreign
proc GetClientRect(hwnd HWND, rect ^RECT) -> BOOL #foreign GetClientRect :: proc(hwnd HWND, rect ^RECT) -> BOOL #foreign
@@ -351,49 +346,47 @@ PFD_DEPTH_DONTCARE :: 0x20000000;
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000; PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
PFD_STEREO_DONTCARE :: 0x80000000; PFD_STEREO_DONTCARE :: 0x80000000;
type { HGLRC :: HANDLE;
HGLRC HANDLE; PROC :: type proc() #cc_c;
PROC proc() #cc_c; wglCreateContextAttribsARBType :: proc(hdc HDC, hshareContext rawptr, attribList ^i32) -> HGLRC;
wglCreateContextAttribsARBType proc(hdc HDC, hshareContext rawptr, attribList ^i32) -> HGLRC;
PIXELFORMATDESCRIPTOR struct #ordered { PIXELFORMATDESCRIPTOR :: struct #ordered {
size, size,
version, version,
flags u32; flags u32;
pixel_type, pixel_type,
color_bits, color_bits,
red_bits, red_bits,
red_shift, red_shift,
green_bits, green_bits,
green_shift, green_shift,
blue_bits, blue_bits,
blue_shift, blue_shift,
alpha_bits, alpha_bits,
alpha_shift, alpha_shift,
accum_bits, accum_bits,
accum_red_bits, accum_red_bits,
accum_green_bits, accum_green_bits,
accum_blue_bits, accum_blue_bits,
accum_alpha_bits, accum_alpha_bits,
depth_bits, depth_bits,
stencil_bits, stencil_bits,
aux_buffers, aux_buffers,
layer_type, layer_type,
reserved byte; reserved byte;
layer_mask, layer_mask,
visible_mask, visible_mask,
damage_mask u32; damage_mask u32;
}
} }
proc GetDC (h HANDLE) -> HDC #foreign GetDC :: proc(h HANDLE) -> HDC #foreign
proc SetPixelFormat (hdc HDC, pixel_format i32, pfd ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign #dll_import SetPixelFormat :: proc(hdc HDC, pixel_format i32, pfd ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign #dll_import
proc ChoosePixelFormat(hdc HDC, pfd ^PIXELFORMATDESCRIPTOR) -> i32 #foreign #dll_import ChoosePixelFormat :: proc(hdc HDC, pfd ^PIXELFORMATDESCRIPTOR) -> i32 #foreign #dll_import
proc SwapBuffers (hdc HDC) -> BOOL #foreign #dll_import SwapBuffers :: proc(hdc HDC) -> BOOL #foreign #dll_import
proc ReleaseDC (wnd HWND, hdc HDC) -> i32 #foreign #dll_import ReleaseDC :: proc(wnd HWND, hdc HDC) -> i32 #foreign #dll_import
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091; WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092; WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092;
@@ -401,19 +394,19 @@ WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126;
WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001; WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001;
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002; WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002;
proc wglCreateContext (hdc HDC) -> HGLRC #foreign #dll_import wglCreateContext :: proc(hdc HDC) -> HGLRC #foreign #dll_import
proc wglMakeCurrent (hdc HDC, hglrc HGLRC) -> BOOL #foreign #dll_import wglMakeCurrent :: proc(hdc HDC, hglrc HGLRC) -> BOOL #foreign #dll_import
proc wglGetProcAddress(c_str ^u8) -> PROC #foreign #dll_import wglGetProcAddress :: proc(c_str ^u8) -> PROC #foreign #dll_import
proc wglDeleteContext (hglrc HGLRC) -> BOOL #foreign #dll_import wglDeleteContext :: proc(hglrc HGLRC) -> BOOL #foreign #dll_import
proc GetKeyState (v_key i32) -> i16 #foreign #dll_import GetKeyState :: proc(v_key i32) -> i16 #foreign #dll_import
proc GetAsyncKeyState(v_key i32) -> i16 #foreign #dll_import GetAsyncKeyState :: proc(v_key i32) -> i16 #foreign #dll_import
proc is_key_down(key Key_Code) -> bool #inline { return GetAsyncKeyState(key as i32) < 0; } is_key_down :: proc(key Key_Code) -> bool #inline { return GetAsyncKeyState(key as i32) < 0; }
type Key_Code enum i32 { Key_Code :: enum i32 {
LBUTTON = 0x01, LBUTTON = 0x01,
RBUTTON = 0x02, RBUTTON = 0x02,
CANCEL = 0x03, CANCEL = 0x03,
+7 -7
View File
@@ -8,7 +8,7 @@ UTF_MAX :: 4;
SURROGATE_MIN :: 0xd800; SURROGATE_MIN :: 0xd800;
SURROGATE_MAX :: 0xdfff; SURROGATE_MAX :: 0xdfff;
type Accept_Range struct { Accept_Range :: struct {
lo, hi u8; lo, hi u8;
} }
@@ -40,7 +40,7 @@ accept_sizes := [256]byte{
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff 0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
}; };
proc encode_rune(r rune) -> ([4]byte, int) { encode_rune :: proc(r rune) -> ([4]byte, int) {
buf: [4]byte; buf: [4]byte;
i := r as u32; i := r as u32;
mask: byte : 0x3f; mask: byte : 0x3f;
@@ -74,7 +74,7 @@ proc encode_rune(r rune) -> ([4]byte, int) {
return buf, 4; return buf, 4;
} }
proc decode_rune(s string) -> (rune, int) { decode_rune :: proc(s string) -> (rune, int) {
n := s.count; n := s.count;
if n < 1 { if n < 1 {
return RUNE_ERROR, 0; return RUNE_ERROR, 0;
@@ -119,7 +119,7 @@ proc decode_rune(s string) -> (rune, int) {
} }
proc valid_rune(r rune) -> bool { valid_rune :: proc(r rune) -> bool {
if r < 0 { if r < 0 {
return false; return false;
} else if SURROGATE_MIN <= r && r <= SURROGATE_MAX { } else if SURROGATE_MIN <= r && r <= SURROGATE_MAX {
@@ -130,7 +130,7 @@ proc valid_rune(r rune) -> bool {
return true; return true;
} }
proc valid_string(s string) -> bool { valid_string :: proc(s string) -> bool {
n := s.count; n := s.count;
for i := 0; i < n; { for i := 0; i < n; {
si := s[i]; si := s[i];
@@ -163,7 +163,7 @@ proc valid_string(s string) -> bool {
return true; return true;
} }
proc rune_count(s string) -> int { rune_count :: proc(s string) -> int {
count := 0; count := 0;
n := s.count; n := s.count;
for i := 0; i < n; count++ { for i := 0; i < n; count++ {
@@ -200,7 +200,7 @@ proc rune_count(s string) -> int {
} }
proc rune_size(r rune) -> int { rune_size :: proc(r rune) -> int {
match { match {
case r < 0: return -1; case r < 0: return -1;
case r <= 1<<7 - 1: return 1; case r <= 1<<7 - 1: return 1;
-36
View File
@@ -308,11 +308,6 @@ bool decl_info_has_init(DeclInfo *d) {
} }
if (d->proc_decl != NULL) { if (d->proc_decl != NULL) {
switch (d->proc_decl->kind) { switch (d->proc_decl->kind) {
case_ast_node(pd, ProcDecl, d->proc_decl);
if (pd->body != NULL) {
return true;
}
case_end;
case_ast_node(pd, ProcLit, d->proc_decl); case_ast_node(pd, ProcLit, d->proc_decl);
if (pd->body != NULL) { if (pd->body != NULL) {
return true; return true;
@@ -1260,23 +1255,6 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
DelayedDecl di = {parent_scope, spec}; DelayedDecl di = {parent_scope, spec};
array_add(&c->delayed_imports, di); array_add(&c->delayed_imports, di);
case_end; case_end;
case_ast_node(ts, TypeSpec, spec);
if (ts->name->kind != AstNode_Ident) {
error_node(ts->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[ts->name->kind]));
continue;
}
ast_node(n, Ident, ts->name);
Entity *e = make_entity_type_name(c->allocator, parent_scope, *n, NULL);
e->identifier = ts->name;
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
d->type_expr = ts->type;
d->init_expr = ts->type;
add_entity_and_decl_info(c, ts->name, e, d);
case_end;
default: default:
error(ast_node_token(spec), "Invalid specification in declaration: `%.*s`", LIT(ast_node_strings[spec->kind])); error(ast_node_token(spec), "Invalid specification in declaration: `%.*s`", LIT(ast_node_strings[spec->kind]));
break; break;
@@ -1293,20 +1271,6 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
DelayedDecl di = {parent_scope, decl}; DelayedDecl di = {parent_scope, decl};
array_add(&c->delayed_foreign_libraries, di); array_add(&c->delayed_foreign_libraries, di);
case_end; case_end;
case_ast_node(pd, ProcDecl, decl);
if (pd->name->kind != AstNode_Ident) {
error_node(pd->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[pd->name->kind]));
continue;
}
ast_node(n, Ident, pd->name);
Token token = *n;
Entity *e = make_entity_procedure(c->allocator, parent_scope, token, NULL, pd->tags);
e->identifier = pd->name;
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
d->proc_decl = decl;
add_entity_and_decl_info(c, pd->name, e, d);
case_end;
default: default:
if (parent_scope->is_file) { if (parent_scope->is_file) {
error_node(decl, "Only declarations are allowed at file scope"); error_node(decl, "Only declarations are allowed at file scope");
+108 -209
View File
@@ -282,6 +282,10 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
check_init_constant(c, e, &operand); check_init_constant(c, e, &operand);
c->context.iota = (ExactValue){0}; c->context.iota = (ExactValue){0};
if (e->type == t_invalid) {
error(e->token, "Illegal cyclic declaration");
}
} }
@@ -326,224 +330,119 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
GB_ASSERT(e->type == NULL); GB_ASSERT(e->type == NULL);
if (d->proc_decl->kind != AstNode_ProcLit) {
// TOOD(bill): Better error message
error_node(d->proc_decl, "Expected a procedure to check");
return;
}
Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin); Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
e->type = proc_type; e->type = proc_type;
if (d->proc_decl->kind == AstNode_ProcDecl) { ast_node(pd, ProcLit, d->proc_decl);
ast_node(pd, ProcDecl, d->proc_decl);
check_open_scope(c, pd->type); check_open_scope(c, pd->type);
check_procedure_type(c, proc_type, pd->type); check_procedure_type(c, proc_type, pd->type);
bool is_foreign = (pd->tags & ProcTag_foreign) != 0; bool is_foreign = (pd->tags & ProcTag_foreign) != 0;
bool is_link_name = (pd->tags & ProcTag_link_name) != 0; bool is_link_name = (pd->tags & ProcTag_link_name) != 0;
bool is_export = (pd->tags & ProcTag_export) != 0; bool is_export = (pd->tags & ProcTag_export) != 0;
bool is_inline = (pd->tags & ProcTag_inline) != 0; bool is_inline = (pd->tags & ProcTag_inline) != 0;
bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0; bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
if ((d->scope->is_file || d->scope->is_global) && if ((d->scope->is_file || d->scope->is_global) &&
str_eq(e->token.string, str_lit("main"))) { str_eq(e->token.string, str_lit("main"))) {
if (proc_type != NULL) { if (proc_type != NULL) {
TypeProc *pt = &proc_type->Proc; TypeProc *pt = &proc_type->Proc;
if (pt->param_count != 0 || if (pt->param_count != 0 ||
pt->result_count != 0) { pt->result_count != 0) {
gbString str = type_to_string(proc_type); gbString str = type_to_string(proc_type);
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str); error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
gb_string_free(str); gb_string_free(str);
}
} }
} }
if (is_inline && is_no_inline) {
error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
}
if (is_foreign && is_link_name) {
error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
} else if (is_foreign && is_export) {
error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
}
if (pd->body != NULL) {
if (is_foreign) {
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
}
if (proc_type->Proc.calling_convention != ProcCC_Odin) {
error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention");
proc_type->Proc.calling_convention = ProcCC_Odin;
}
d->scope = c->context.scope;
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
}
if (is_foreign) {
MapEntity *fp = &c->info.foreign_procs;
AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
String name = proc_decl->name->Ident.string;
if (proc_decl->foreign_name.len > 0) {
name = proc_decl->foreign_name;
}
e->Procedure.is_foreign = true;
e->Procedure.foreign_name = name;
HashKey key = hash_string(name);
Entity **found = map_entity_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
Type *this_type = base_type(e->type);
Type *other_type = base_type(f->type);
if (!are_signatures_similar_enough(this_type, other_type)) {
error_node(d->proc_decl,
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
} else {
map_entity_set(fp, key, e);
}
} else {
String name = e->token.string;
if (is_link_name) {
AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
name = proc_decl->link_name;
}
if (is_link_name || is_export) {
MapEntity *fp = &c->info.foreign_procs;
e->Procedure.link_name = name;
HashKey key = hash_string(name);
Entity **found = map_entity_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
// TODO(bill): Better error message?
error_node(d->proc_decl,
"Non unique linking name for procedure `%.*s`\n"
"\tother at %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
} else {
map_entity_set(fp, key, e);
}
}
}
check_close_scope(c);
} else if (d->proc_decl->kind == AstNode_ProcLit) {
ast_node(pd, ProcLit, d->proc_decl);
check_open_scope(c, pd->type);
check_procedure_type(c, proc_type, pd->type);
bool is_foreign = (pd->tags & ProcTag_foreign) != 0;
bool is_link_name = (pd->tags & ProcTag_link_name) != 0;
bool is_export = (pd->tags & ProcTag_export) != 0;
bool is_inline = (pd->tags & ProcTag_inline) != 0;
bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
if ((d->scope->is_file || d->scope->is_global) &&
str_eq(e->token.string, str_lit("main"))) {
if (proc_type != NULL) {
TypeProc *pt = &proc_type->Proc;
if (pt->param_count != 0 ||
pt->result_count != 0) {
gbString str = type_to_string(proc_type);
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
gb_string_free(str);
}
}
}
if (is_inline && is_no_inline) {
error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
}
if (is_foreign && is_link_name) {
error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
} else if (is_foreign && is_export) {
error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
}
if (pd->body != NULL) {
if (is_foreign) {
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
}
if (proc_type->Proc.calling_convention != ProcCC_Odin) {
error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention");
proc_type->Proc.calling_convention = ProcCC_Odin;
}
d->scope = c->context.scope;
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
}
if (is_foreign) {
MapEntity *fp = &c->info.foreign_procs;
String name = e->token.string;
if (pd->foreign_name.len > 0) {
name = pd->foreign_name;
}
e->Procedure.is_foreign = true;
e->Procedure.foreign_name = name;
HashKey key = hash_string(name);
Entity **found = map_entity_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
Type *this_type = base_type(e->type);
Type *other_type = base_type(f->type);
if (!are_signatures_similar_enough(this_type, other_type)) {
error_node(d->proc_decl,
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
} else {
map_entity_set(fp, key, e);
}
} else {
String name = e->token.string;
if (is_link_name) {
name = pd->link_name;
}
if (is_link_name || is_export) {
MapEntity *fp = &c->info.foreign_procs;
e->Procedure.link_name = name;
HashKey key = hash_string(name);
Entity **found = map_entity_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
// TODO(bill): Better error message?
error_node(d->proc_decl,
"Non unique linking name for procedure `%.*s`\n"
"\tother at %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
} else {
map_entity_set(fp, key, e);
}
}
}
check_close_scope(c);
} }
if (is_inline && is_no_inline) {
error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
}
if (is_foreign && is_link_name) {
error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
} else if (is_foreign && is_export) {
error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
}
if (pd->body != NULL) {
if (is_foreign) {
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
}
if (proc_type->Proc.calling_convention != ProcCC_Odin) {
error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention");
proc_type->Proc.calling_convention = ProcCC_Odin;
}
d->scope = c->context.scope;
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
}
if (is_foreign) {
MapEntity *fp = &c->info.foreign_procs;
String name = e->token.string;
if (pd->foreign_name.len > 0) {
name = pd->foreign_name;
}
e->Procedure.is_foreign = true;
e->Procedure.foreign_name = name;
HashKey key = hash_string(name);
Entity **found = map_entity_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
Type *this_type = base_type(e->type);
Type *other_type = base_type(f->type);
if (!are_signatures_similar_enough(this_type, other_type)) {
error_node(d->proc_decl,
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
} else {
map_entity_set(fp, key, e);
}
} else {
String name = e->token.string;
if (is_link_name) {
name = pd->link_name;
}
if (is_link_name || is_export) {
MapEntity *fp = &c->info.foreign_procs;
e->Procedure.link_name = name;
HashKey key = hash_string(name);
Entity **found = map_entity_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
// TODO(bill): Better error message?
error_node(d->proc_decl,
"Non unique linking name for procedure `%.*s`\n"
"\tother at %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
} else {
map_entity_set(fp, key, e);
}
}
}
check_close_scope(c);
} }
void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) { void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) {
+11 -38
View File
@@ -137,43 +137,6 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
switch (spec->kind) { switch (spec->kind) {
case_ast_node(bd, BadDecl, spec); case_ast_node(bd, BadDecl, spec);
case_end; case_end;
case_ast_node(ts, TypeSpec, spec);
if (ts->name->kind != AstNode_Ident) {
error_node(ts->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[ts->name->kind]));
break;
}
Token name_token = ts->name->Ident;
Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, NULL);
e->identifier = ts->name;
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
d->type_expr = ts->type;
add_entity_and_decl_info(c, ts->name, e, d);
DelayedEntity delay = {ts->name, e, d};
array_add(delayed_entities, delay);
if (dof != NULL) {
if (str_eq(name_token.string, str_lit("_"))) {
dof->other_fields[dof->other_field_index++] = e;
} else {
HashKey key = hash_string(name_token.string);
if (map_entity_get(dof->entity_map, key) != NULL) {
// TODO(bill): Scope checking already checks the declaration
error(name_token, "`%.*s` is already declared in this record", LIT(name_token.string));
} else {
map_entity_set(dof->entity_map, key, e);
dof->other_fields[dof->other_field_index++] = e;
}
add_entity(c, c->context.scope, ts->name, e);
add_entity_use(c, ts->name, e);
}
}
case_end;
} }
} }
case_end; case_end;
@@ -975,7 +938,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) {
} }
if (e == e_iota) { if (e == e_iota) {
if (c->context.iota.kind == ExactValue_Invalid) { if (c->context.iota.kind == ExactValue_Invalid) {
error(e->token, "Use of `iota` outside a constant declaration is not allowed"); error(e->token, "Use of `iota` outside a enumeration is not allowed");
return; return;
} }
o->value = c->context.iota; o->value = c->context.iota;
@@ -1141,6 +1104,11 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
} }
case_end; case_end;
case_ast_node(ht, HelperType, e);
type = check_type(c, ht->type);
goto end;
case_end;
case_ast_node(pt, PointerType, e); case_ast_node(pt, PointerType, e);
Type *elem = check_type(c, pt->type); Type *elem = check_type(c, pt->type);
type = make_type_pointer(c->allocator, elem); type = make_type_pointer(c->allocator, elem);
@@ -4825,6 +4793,11 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
str = gb_string_appendc(str, "{"); str = gb_string_appendc(str, "{");
str = gb_string_appendc(str, "}"); str = gb_string_appendc(str, "}");
case_end; case_end;
case_ast_node(ht, HelperType, node);
str = gb_string_appendc(str, "type ");
str = write_expr_to_string(str, ht->type);
case_end;
} }
return str; return str;
-25
View File
@@ -1170,36 +1170,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
switch (spec->kind) { switch (spec->kind) {
case_ast_node(bd, BadDecl, spec); case_ast_node(bd, BadDecl, spec);
case_end; case_end;
case_ast_node(ts, TypeSpec, spec);
// NOTE(bill): Handled elsewhere
case_end;
default: default:
error(ast_node_token(spec), "Invalid specification in declaration: `%.*s`", LIT(ast_node_strings[spec->kind])); error(ast_node_token(spec), "Invalid specification in declaration: `%.*s`", LIT(ast_node_strings[spec->kind]));
break; break;
} }
} }
case_end; case_end;
case_ast_node(pd, ProcDecl, node);
// NOTE(bill): Handled elsewhere
#if 1
// NOTE(bill): This must be handled here so it has access to the parent scope stuff
// e.g. using
if (pd->name->kind != AstNode_Ident) {
error_node(pd->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[pd->name->kind]));
break;
}
Entity *e = make_entity_procedure(c->allocator, c->context.scope, pd->name->Ident, NULL, pd->tags);
e->identifier = pd->name;
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
d->proc_decl = node;
add_entity_and_decl_info(c, pd->name, e, d);
check_entity_decl(c, e, d, NULL);
#endif
case_end;
} }
} }
+81 -56
View File
@@ -281,15 +281,6 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
AstNodeArray values; \ AstNodeArray values; \
u64 tags; \ u64 tags; \
}) \ }) \
AST_NODE_KIND(ProcDecl, "procedure declaration", struct { \
AstNode *name; \
AstNode *type; \
AstNode *body; \
u64 tags; \
String foreign_name; \
String link_name; \
AstNode *note; \
}) \
AST_NODE_KIND(ForeignLibrary, "foreign library", struct { \ AST_NODE_KIND(ForeignLibrary, "foreign library", struct { \
Token token, filepath; \ Token token, filepath; \
String base_dir; \ String base_dir; \
@@ -303,6 +294,10 @@ AST_NODE_KIND(_DeclEnd, "", i32) \
bool is_using; \ bool is_using; \
}) \ }) \
AST_NODE_KIND(_TypeBegin, "", i32) \ AST_NODE_KIND(_TypeBegin, "", i32) \
AST_NODE_KIND(HelperType, "type", struct { \
Token token; \
AstNode *type; \
}) \
AST_NODE_KIND(ProcType, "procedure type", struct { \ AST_NODE_KIND(ProcType, "procedure type", struct { \
Token token; \ Token token; \
AstNodeArray params; \ AstNodeArray params; \
@@ -501,8 +496,6 @@ Token ast_node_token(AstNode *node) {
return node->GenericDecl.token; return node->GenericDecl.token;
case AstNode_ValueDecl: case AstNode_ValueDecl:
return ast_node_token(node->ValueDecl.names.e[0]); return ast_node_token(node->ValueDecl.names.e[0]);
case AstNode_ProcDecl:
return ast_node_token(node->ProcDecl.name);
case AstNode_ForeignLibrary: case AstNode_ForeignLibrary:
return node->ForeignLibrary.token; return node->ForeignLibrary.token;
@@ -519,6 +512,10 @@ Token ast_node_token(AstNode *node) {
return ast_node_token(node->Field.type); return ast_node_token(node->Field.type);
} }
} }
case AstNode_HelperType:
return node->HelperType.token;
case AstNode_ProcType: case AstNode_ProcType:
return node->ProcType.token; return node->ProcType.token;
case AstNode_PointerType: case AstNode_PointerType:
@@ -969,6 +966,15 @@ AstNode *make_field(AstFile *f, AstNodeArray names, AstNode *type, bool is_using
return result; return result;
} }
AstNode *make_helper_type(AstFile *f, Token token, AstNode *type) {
AstNode *result = make_node(f, AstNode_HelperType);
result->HelperType.token = token;
result->HelperType.type = type;
return result;
}
AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results, u64 tags, ProcCallingConvention calling_convention) { AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results, u64 tags, ProcCallingConvention calling_convention) {
AstNode *result = make_node(f, AstNode_ProcType); AstNode *result = make_node(f, AstNode_ProcType);
result->ProcType.token = token; result->ProcType.token = token;
@@ -979,17 +985,6 @@ AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArr
return result; return result;
} }
AstNode *make_proc_decl(AstFile *f, AstNode *name, AstNode *proc_type, AstNode *body, u64 tags, String foreign_name, String link_name) {
AstNode *result = make_node(f, AstNode_ProcDecl);
result->ProcDecl.name = name;
result->ProcDecl.type = proc_type;
result->ProcDecl.body = body;
result->ProcDecl.tags = tags;
result->ProcDecl.foreign_name = foreign_name;
result->ProcDecl.link_name = link_name;
return result;
}
AstNode *make_pointer_type(AstFile *f, Token token, AstNode *type) { AstNode *make_pointer_type(AstFile *f, Token token, AstNode *type) {
AstNode *result = make_node(f, AstNode_PointerType); AstNode *result = make_node(f, AstNode_PointerType);
result->PointerType.token = token; result->PointerType.token = token;
@@ -1264,6 +1259,52 @@ Token expect_closing(AstFile *f, TokenKind kind, String context) {
return expect_token(f, kind); return expect_token(f, kind);
} }
bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) {
if (s == NULL) {
return false;
}
switch (s->kind) {
case AstNode_HelperType:
return is_semicolon_optional_for_node(f, s->HelperType.type);
case AstNode_StructType:
case AstNode_UnionType:
case AstNode_RawUnionType:
case AstNode_EnumType:
return true;
case AstNode_ProcLit:
return true;
case AstNode_ValueDecl:
if (!s->ValueDecl.is_var) {
if (s->ValueDecl.values.count > 0) {
AstNode *last = s->ValueDecl.values.e[s->ValueDecl.values.count-1];
return is_semicolon_optional_for_node(f, last);
}
}
break;
case AstNode_GenericDecl:
if (s->GenericDecl.close.kind == Token_CloseBrace) {
return true;
} else if (s->GenericDecl.token.kind == Token_type) {
if (f->prev_token.kind == Token_CloseBrace) {
return true;
}
}
break;
case AstNode_TypeSpec:
if (f->prev_token.kind == Token_CloseBrace) {
return true;
}
break;
}
return false;
}
void expect_semicolon(AstFile *f, AstNode *s) { void expect_semicolon(AstFile *f, AstNode *s) {
if (allow_token(f, Token_Semicolon)) { if (allow_token(f, Token_Semicolon)) {
return; return;
@@ -1277,24 +1318,8 @@ void expect_semicolon(AstFile *f, AstNode *s) {
if (s != NULL) { if (s != NULL) {
if (prev_token.pos.line != f->curr_token.pos.line) { if (prev_token.pos.line != f->curr_token.pos.line) {
switch (s->kind) { if (is_semicolon_optional_for_node(f, s)) {
case AstNode_ProcDecl:
return; return;
case AstNode_GenericDecl:
if (s->GenericDecl.close.kind == Token_CloseBrace) {
return;
} else if (s->GenericDecl.token.kind == Token_type) {
if (f->prev_token.kind == Token_CloseBrace) {
return;
}
}
break;
case AstNode_TypeSpec:
if (f->prev_token.kind == Token_CloseBrace) {
return;
}
break;
} }
} else { } else {
switch (s->kind) { switch (s->kind) {
@@ -1319,7 +1344,6 @@ AstNode * parse_proc_type(AstFile *f, String *foreign_name_, String *link_nam
AstNodeArray parse_stmt_list(AstFile *f); AstNodeArray parse_stmt_list(AstFile *f);
AstNode * parse_stmt(AstFile *f); AstNode * parse_stmt(AstFile *f);
AstNode * parse_body(AstFile *f); AstNode * parse_body(AstFile *f);
AstNode * parse_proc_decl(AstFile *f);
void parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results); void parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results);
@@ -1571,6 +1595,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n
AstNodeArray parse_lhs_expr_list(AstFile *f); AstNodeArray parse_lhs_expr_list(AstFile *f);
AstNodeArray parse_rhs_expr_list(AstFile *f); AstNodeArray parse_rhs_expr_list(AstFile *f);
AstNode * parse_simple_stmt (AstFile *f); AstNode * parse_simple_stmt (AstFile *f);
AstNode * parse_type (AstFile *f);
AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) { AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) {
if (statement == NULL) { if (statement == NULL) {
@@ -1745,10 +1770,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
String foreign_name = {0}; String foreign_name = {0};
String link_name = {0}; String link_name = {0};
AstNode *type = parse_proc_type(f, &foreign_name, &link_name); AstNode *type = parse_proc_type(f, &foreign_name, &link_name);
u64 tags = type->ProcType.tags;
if (f->curr_token.kind == Token_OpenBrace) { if (f->curr_token.kind == Token_OpenBrace) {
u64 tags = type->ProcType.tags;
if ((tags & ProcTag_foreign) != 0) { if ((tags & ProcTag_foreign) != 0) {
syntax_error(token, "A procedure tagged as `#foreign` cannot have a body"); syntax_error(token, "A procedure tagged as `#foreign` cannot have a body");
} }
@@ -1760,6 +1784,13 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
return make_proc_lit(f, type, body, tags, foreign_name, link_name); return make_proc_lit(f, type, body, tags, foreign_name, link_name);
} }
if ((tags & ProcTag_foreign) != 0) {
return make_proc_lit(f, type, NULL, tags, foreign_name, link_name);
}
if ((tags & ProcTag_link_name) != 0) {
syntax_error(token, "A procedure typed cannot be tagged with `#link_name`");
}
return type; return type;
} }
@@ -1932,7 +1963,6 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
return operand; return operand;
} }
AstNode *parse_type(AstFile *f);
AstNode *parse_unary_expr(AstFile *f, bool lhs) { AstNode *parse_unary_expr(AstFile *f, bool lhs) {
switch (f->curr_token.kind) { switch (f->curr_token.kind) {
@@ -2240,17 +2270,6 @@ PARSE_SPEC_PROC(parse_include_spec) {
AstNode *parse_decl(AstFile *f) { AstNode *parse_decl(AstFile *f) {
switch (f->curr_token.kind) { switch (f->curr_token.kind) {
// case Token_var:
// case Token_const:
// return parse_generic_decl(f, f->curr_token.kind, parse_value_spec);
case Token_type:
return parse_generic_decl(f, f->curr_token.kind, parse_type_spec);
case Token_proc:
// TODO(bill): Should I allow procedures to use the generic declaration syntax?
return parse_proc_decl(f);
case Token_import: case Token_import:
return parse_generic_decl(f, f->curr_token.kind, parse_import_spec); return parse_generic_decl(f, f->curr_token.kind, parse_import_spec);
case Token_include: case Token_include:
@@ -2504,6 +2523,12 @@ AstNode *parse_identifier_or_type(AstFile *f) {
return e; return e;
} }
case Token_type: {
Token token = expect_token(f, Token_type);
AstNode *type = parse_type(f);
return make_helper_type(f, token, type);
}
case Token_Pointer: { case Token_Pointer: {
Token token = expect_token(f, Token_Pointer); Token token = expect_token(f, Token_Pointer);
AstNode *elem = parse_type(f); AstNode *elem = parse_type(f);
@@ -2681,7 +2706,7 @@ AstNode *parse_body(AstFile *f) {
} }
/*
AstNode *parse_proc_decl(AstFile *f) { AstNode *parse_proc_decl(AstFile *f) {
if (look_ahead_token_kind(f, 1) == Token_OpenParen) { if (look_ahead_token_kind(f, 1) == Token_OpenParen) {
// NOTE(bill): It's an anonymous procedure // NOTE(bill): It's an anonymous procedure
@@ -2720,7 +2745,7 @@ AstNode *parse_proc_decl(AstFile *f) {
} }
return make_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name); return make_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name);
} } */
AstNode *parse_if_stmt(AstFile *f) { AstNode *parse_if_stmt(AstFile *f) {
if (f->curr_proc == NULL) { if (f->curr_proc == NULL) {
+99 -130
View File
@@ -3978,104 +3978,96 @@ void ssa_build_stmt_internal(ssaProcedure *proc, AstNode *node) {
} }
gb_temp_arena_memory_end(tmp); gb_temp_arena_memory_end(tmp);
}
case_end;
case_ast_node(gd, GenericDecl, node);
for_array(spec_index, gd->specs) {
AstNode *spec = gd->specs.e[spec_index];
switch (spec->kind) {
case_ast_node(ts, TypeSpec, spec);
// NOTE(bill): Generate a new name
// parent_proc.name-guid
String ts_name = ts->name->Ident.string;
isize name_len = proc->name.len + 1 + ts_name.len + 1 + 10 + 1;
u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
i32 guid = cast(i32)proc->module->members.entries.count;
name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(ts_name), guid);
String name = make_string(name_text, name_len-1);
Entity **found = map_entity_get(&proc->module->info->definitions, hash_pointer(ts->name));
GB_ASSERT(found != NULL);
Entity *e = *found;
ssaValue *value = ssa_make_value_type_name(proc->module->allocator,
name, e->type);
map_string_set(&proc->module->type_names, hash_pointer(e->type), name);
ssa_gen_global_type_name(proc->module, e, name);
case_end;
}
}
case_end;
case_ast_node(pd, ProcDecl, node);
if (pd->body != NULL) {
CheckerInfo *info = proc->module->info;
Entity **found = map_entity_get(&info->definitions, hash_pointer(pd->name));
GB_ASSERT_MSG(found != NULL, "Unable to find: %.*s", LIT(pd->name->Ident.string));
Entity *e = *found;
if (map_entity_get(&proc->module->min_dep_map, hash_pointer(e)) == NULL) {
// NOTE(bill): Nothing depends upon it so doesn't need to be built
break;
}
// NOTE(bill): Generate a new name
// parent.name-guid
String original_name = pd->name->Ident.string;
String pd_name = original_name;
if (pd->link_name.len > 0) {
pd_name = pd->link_name;
}
isize name_len = proc->name.len + 1 + pd_name.len + 1 + 10 + 1;
u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
i32 guid = cast(i32)proc->children.count;
name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(pd_name), guid);
String name = make_string(name_text, name_len-1);
ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
proc->module, e, e->type, pd->type, pd->body, name);
value->Proc.tags = pd->tags;
value->Proc.parent = proc;
ssa_module_add_value(proc->module, e, value);
array_add(&proc->children, &value->Proc);
array_add(&proc->module->procs_to_generate, value);
} else { } else {
CheckerInfo *info = proc->module->info; for_array(i, vd->names) {
AstNode *ident = vd->names.e[i];
GB_ASSERT(ident->kind == AstNode_Ident);
Entity *e = entity_of_ident(proc->module->info, ident);
GB_ASSERT(e != NULL);
switch (e->kind) {
case Entity_TypeName: {
// NOTE(bill): Generate a new name
// parent_proc.name-guid
String ts_name = e->token.string;
isize name_len = proc->name.len + 1 + ts_name.len + 1 + 10 + 1;
u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
i32 guid = cast(i32)proc->module->members.entries.count;
name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(ts_name), guid);
String name = make_string(name_text, name_len-1);
Entity **found = map_entity_get(&info->definitions, hash_pointer(pd->name)); ssaValue *value = ssa_make_value_type_name(proc->module->allocator,
GB_ASSERT_MSG(found != NULL, "Unable to find: %.*s", LIT(pd->name->Ident.string)); name, e->type);
Entity *e = *found; map_string_set(&proc->module->type_names, hash_pointer(e->type), name);
ssa_gen_global_type_name(proc->module, e, name);
} break;
case Entity_Procedure: {
DeclInfo **decl_info = map_decl_info_get(&proc->module->info->entities, hash_pointer(e));
GB_ASSERT(decl_info != NULL);
DeclInfo *dl = *decl_info;
ast_node(pd, ProcLit, dl->proc_decl);
if (pd->body != NULL) {
CheckerInfo *info = proc->module->info;
// FFI - Foreign function interace if (map_entity_get(&proc->module->min_dep_map, hash_pointer(e)) == NULL) {
String original_name = pd->name->Ident.string; // NOTE(bill): Nothing depends upon it so doesn't need to be built
String name = original_name; break;
if (pd->foreign_name.len > 0) { }
name = pd->foreign_name;
}
ssaValue *value = ssa_make_value_procedure(proc->module->allocator, // NOTE(bill): Generate a new name
proc->module, e, e->type, pd->type, pd->body, name); // parent.name-guid
String original_name = e->token.string;
String pd_name = original_name;
if (pd->link_name.len > 0) {
pd_name = pd->link_name;
}
value->Proc.tags = pd->tags; isize name_len = proc->name.len + 1 + pd_name.len + 1 + 10 + 1;
u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
i32 guid = cast(i32)proc->children.count;
name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(pd_name), guid);
String name = make_string(name_text, name_len-1);
ssa_module_add_value(proc->module, e, value);
ssa_build_proc(value, proc);
if (value->Proc.tags & ProcTag_foreign) { ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
HashKey key = hash_string(name); proc->module, e, e->type, pd->type, pd->body, name);
ssaValue **prev_value = map_ssa_value_get(&proc->module->members, key);
if (prev_value == NULL) { value->Proc.tags = pd->tags;
// NOTE(bill): Don't do mutliple declarations in the IR value->Proc.parent = proc;
map_ssa_value_set(&proc->module->members, key, value);
ssa_module_add_value(proc->module, e, value);
array_add(&proc->children, &value->Proc);
array_add(&proc->module->procs_to_generate, value);
} else {
CheckerInfo *info = proc->module->info;
// FFI - Foreign function interace
String original_name = e->token.string;
String name = original_name;
if (pd->foreign_name.len > 0) {
name = pd->foreign_name;
}
ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
proc->module, e, e->type, pd->type, pd->body, name);
value->Proc.tags = pd->tags;
ssa_module_add_value(proc->module, e, value);
ssa_build_proc(value, proc);
if (value->Proc.tags & ProcTag_foreign) {
HashKey key = hash_string(name);
ssaValue **prev_value = map_ssa_value_get(&proc->module->members, key);
if (prev_value == NULL) {
// NOTE(bill): Don't do mutliple declarations in the IR
map_ssa_value_set(&proc->module->members, key, value);
}
} else {
array_add(&proc->children, &value->Proc);
}
}
} break;
} }
} else {
array_add(&proc->children, &value->Proc);
} }
} }
case_end; case_end;
@@ -5034,48 +5026,25 @@ void ssa_gen_tree(ssaGen *s) {
} break; } break;
case Entity_Procedure: { case Entity_Procedure: {
if (decl->proc_decl->kind == AstNode_ProcDecl) { ast_node(pd, ProcLit, decl->proc_decl);
AstNodeProcDecl *pd = &decl->proc_decl->ProcDecl; String original_name = name;
String original_name = name; AstNode *body = pd->body;
AstNode *body = pd->body; if (e->Procedure.is_foreign) {
if (e->Procedure.is_foreign) { name = e->token.string; // NOTE(bill): Don't use the mangled name
name = e->token.string; // NOTE(bill): Don't use the mangled name }
} if (pd->foreign_name.len > 0) {
if (pd->foreign_name.len > 0) { name = pd->foreign_name;
name = pd->foreign_name; } else if (pd->link_name.len > 0) {
} else if (pd->link_name.len > 0) { name = pd->link_name;
name = pd->link_name; }
}
ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name); ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
p->Proc.tags = pd->tags; p->Proc.tags = pd->tags;
ssa_module_add_value(m, e, p); ssa_module_add_value(m, e, p);
HashKey hash_name = hash_string(name); HashKey hash_name = hash_string(name);
if (map_ssa_value_get(&m->members, hash_name) == NULL) { if (map_ssa_value_get(&m->members, hash_name) == NULL) {
map_ssa_value_set(&m->members, hash_name, p); map_ssa_value_set(&m->members, hash_name, p);
}
} else if (decl->proc_decl->kind == AstNode_ProcLit) {
AstNodeProcLit *pd = &decl->proc_decl->ProcLit;
String original_name = name;
AstNode *body = pd->body;
if (e->Procedure.is_foreign) {
name = e->token.string; // NOTE(bill): Don't use the mangled name
}
if (pd->foreign_name.len > 0) {
name = pd->foreign_name;
} else if (pd->link_name.len > 0) {
name = pd->link_name;
}
ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
p->Proc.tags = pd->tags;
ssa_module_add_value(m, e, p);
HashKey hash_name = hash_string(name);
if (map_ssa_value_get(&m->members, hash_name) == NULL) {
map_ssa_value_set(&m->members, hash_name, p);
}
} }
} break; } break;
} }