mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-26 21:04:58 +00:00
Semicolons mandatory again (and probably forever now...)
This commit is contained in:
34
README.md
34
README.md
@@ -30,27 +30,27 @@ Odin is fast, concise, readable, pragmatic and open sourced. It is designed with
|
||||
## Warnings
|
||||
|
||||
* This is still highly in development and the language's design is quite volatile.
|
||||
* Syntax is not fixed.
|
||||
* Syntax is definitely not fixed
|
||||
|
||||
## Roadmap
|
||||
|
||||
Not in any particular order
|
||||
|
||||
* Compile Time Execution (CTE)
|
||||
- More metaprogramming madness
|
||||
- Compiler as a library
|
||||
- AST inspection and modification
|
||||
* CTE-based build system
|
||||
* Replace LLVM backend with my own custom backend
|
||||
* Improve SSA design to accommodate for lowering to a "bytecode"
|
||||
* SSA optimizations
|
||||
* Parametric Polymorphism ("Generics")
|
||||
* Documentation Generator for "Entities"
|
||||
* Multiple Architecture support
|
||||
* Language level atomics and concurrency support
|
||||
* Debug Information
|
||||
* Custom backend to replace LLVM
|
||||
- Improve SSA design to accommodate for lowering to a "bytecode"
|
||||
- SSA optimizations
|
||||
- COFF generation
|
||||
- linker
|
||||
* Type safe "macros"
|
||||
* Documentation generator for "Entities"
|
||||
* Multiple architecture support
|
||||
* Inline assembly
|
||||
* Linking options
|
||||
- Executable
|
||||
- Static/Dynamic Library
|
||||
* Debug information
|
||||
- pdb format too
|
||||
* Command Line Tooling
|
||||
* Compiler Internals:
|
||||
* Command line tooling
|
||||
* Compiler internals:
|
||||
- Big numbers library
|
||||
- Multithreading for performance increase
|
||||
|
||||
|
||||
20
build.bat
20
build.bat
@@ -4,9 +4,9 @@
|
||||
set exe_name=odin.exe
|
||||
|
||||
:: Debug = 0, Release = 1
|
||||
set release_mode=1
|
||||
set release_mode=0
|
||||
|
||||
set compiler_flags= -nologo -Oi -TC -W4 -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
||||
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
set compiler_flags=%compiler_flags% -Od -MDd -Z7
|
||||
@@ -16,7 +16,7 @@ if %release_mode% EQU 0 ( rem Debug
|
||||
)
|
||||
|
||||
set compiler_warnings= ^
|
||||
-we4002 -we4013 -we4020 -we4024 -we4029 -we4031 -we4047 -we4133 -we4706 -we4715 ^
|
||||
-W4 -WX ^
|
||||
-wd4100 -wd4101 -wd4127 -wd4189 ^
|
||||
-wd4201 -wd4204 -wd4244 ^
|
||||
-wd4306 ^
|
||||
@@ -40,20 +40,14 @@ set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings%
|
||||
set linker_settings=%libs% %linker_flags%
|
||||
|
||||
|
||||
rem set build_dir= "\"
|
||||
rem if not exist %build_dir% mkdir %build_dir%
|
||||
rem pushd %build_dir%
|
||||
del *.pdb > NUL 2> NUL
|
||||
del *.ilk > NUL 2> NUL
|
||||
del *.pdb > NUL 2> NUL
|
||||
del *.ilk > NUL 2> NUL
|
||||
|
||||
cl %compiler_settings% "src\main.c" ^
|
||||
/link %linker_settings% -OUT:%exe_name% ^
|
||||
cl %compiler_settings% "src\main.c" ^
|
||||
/link %linker_settings% -OUT:%exe_name% ^
|
||||
&& odin run code/demo.odin
|
||||
rem && odin build_dll code/example.odin ^
|
||||
rem && odin run code/demo.odin
|
||||
|
||||
|
||||
:do_not_compile_exe
|
||||
rem popd
|
||||
:end_of_build
|
||||
|
||||
|
||||
@@ -1,55 +1,60 @@
|
||||
#import "win32.odin"
|
||||
#import "fmt.odin"
|
||||
#import "sync.odin"
|
||||
#import win32 "sys/windows.odin";
|
||||
#import "fmt.odin";
|
||||
#import "sync.odin";
|
||||
#import "hash.odin";
|
||||
#import "math.odin";
|
||||
#import "mem.odin";
|
||||
#import "opengl.odin";
|
||||
#import "os.odin";
|
||||
#import "utf8.odin";
|
||||
|
||||
Dll :: struct {
|
||||
Handle :: type rawptr
|
||||
name: string
|
||||
handle: Handle
|
||||
Handle :: type rawptr;
|
||||
name: string;
|
||||
handle: Handle;
|
||||
}
|
||||
|
||||
load_library :: proc(name: string) -> (Dll, bool) {
|
||||
buf: [4096]byte
|
||||
copy(buf[:], name as []byte)
|
||||
buf: [4096]byte;
|
||||
copy(buf[:], name as []byte);
|
||||
|
||||
lib := win32.LoadLibraryA(^buf[0])
|
||||
lib := win32.LoadLibraryA(^buf[0]);
|
||||
if lib == nil {
|
||||
return nil, false
|
||||
return nil, false;
|
||||
}
|
||||
return Dll{name, lib as Dll.Handle}, true
|
||||
return Dll{name, lib as Dll.Handle}, true;
|
||||
}
|
||||
|
||||
free_library :: proc(dll: Dll) {
|
||||
win32.FreeLibrary(dll.handle as win32.HMODULE)
|
||||
win32.FreeLibrary(dll.handle as win32.HMODULE);
|
||||
}
|
||||
|
||||
get_proc_address :: proc(dll: Dll, name: string) -> (rawptr, bool) {
|
||||
buf: [4096]byte
|
||||
copy(buf[:], name as []byte)
|
||||
buf: [4096]byte;
|
||||
copy(buf[:], name as []byte);
|
||||
|
||||
addr := win32.GetProcAddress(dll.handle as win32.HMODULE, ^buf[0]) as rawptr
|
||||
addr := win32.GetProcAddress(dll.handle as win32.HMODULE, ^buf[0]) as rawptr;
|
||||
if addr == nil {
|
||||
return nil, false
|
||||
return nil, false;
|
||||
}
|
||||
return addr, true
|
||||
return addr, true;
|
||||
}
|
||||
|
||||
|
||||
main :: proc() {
|
||||
lib, lib_ok := load_library("example.dll")
|
||||
lib, lib_ok := load_library("example.dll");
|
||||
if !lib_ok {
|
||||
fmt.println("Could not load library")
|
||||
return
|
||||
fmt.println("Could not load library");
|
||||
return;
|
||||
}
|
||||
defer free_library(lib)
|
||||
defer free_library(lib);
|
||||
|
||||
|
||||
proc_addr, addr_ok := get_proc_address(lib, "some_thing")
|
||||
proc_addr, addr_ok := get_proc_address(lib, "some_thing");
|
||||
if !addr_ok {
|
||||
fmt.println("Could not load 'some_thing'")
|
||||
return
|
||||
fmt.println("Could not load 'some_thing'");
|
||||
return;
|
||||
}
|
||||
|
||||
some_thing := (proc_addr as proc())
|
||||
some_thing()
|
||||
some_thing := (proc_addr as proc());
|
||||
some_thing();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#shared_global_scope
|
||||
#shared_global_scope;
|
||||
|
||||
#import "os.odin"
|
||||
#import "fmt.odin"
|
||||
#import "mem.odin"
|
||||
#import "os.odin";
|
||||
#import "fmt.odin";
|
||||
#import "mem.odin";
|
||||
|
||||
// IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a
|
||||
// #shared_global_scope due to the internals of the compiler.
|
||||
@@ -12,81 +12,81 @@
|
||||
|
||||
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
||||
// The compiler relies upon this _exact_ order
|
||||
Type_Info :: union {
|
||||
Member :: struct #ordered {
|
||||
name: string; // can be empty if tuple
|
||||
type_info: ^Type_Info
|
||||
offset: int; // offsets are not used in tuples
|
||||
}
|
||||
Record :: struct #ordered {
|
||||
fields: []Member
|
||||
size: int; // in bytes
|
||||
align: int; // in bytes
|
||||
packed: bool
|
||||
ordered: bool
|
||||
}
|
||||
Type_Info_Member :: struct #ordered {
|
||||
name: string; // can be empty if tuple
|
||||
type_info: ^Type_Info;
|
||||
offset: int; // offsets are not used in tuples
|
||||
};
|
||||
Type_Info_Record :: struct #ordered {
|
||||
fields: []Type_Info_Member;
|
||||
size: int; // in bytes
|
||||
align: int; // in bytes
|
||||
packed: bool;
|
||||
ordered: bool;
|
||||
};
|
||||
|
||||
Type_Info :: union {
|
||||
Named: struct #ordered {
|
||||
name: string
|
||||
name: string;
|
||||
base: ^Type_Info; // This will _not_ be a Type_Info.Named
|
||||
}
|
||||
};
|
||||
Integer: struct #ordered {
|
||||
size: int; // in bytes
|
||||
signed: bool
|
||||
}
|
||||
signed: bool;
|
||||
};
|
||||
Float: struct #ordered {
|
||||
size: int; // in bytes
|
||||
}
|
||||
Any: struct #ordered {}
|
||||
String: struct #ordered {}
|
||||
Boolean: struct #ordered {}
|
||||
};
|
||||
Any: struct #ordered {};
|
||||
String: struct #ordered {};
|
||||
Boolean: struct #ordered {};
|
||||
Pointer: struct #ordered {
|
||||
elem: ^Type_Info; // nil -> rawptr
|
||||
}
|
||||
};
|
||||
Maybe: struct #ordered {
|
||||
elem: ^Type_Info
|
||||
}
|
||||
elem: ^Type_Info;
|
||||
};
|
||||
Procedure: struct #ordered {
|
||||
params: ^Type_Info; // Type_Info.Tuple
|
||||
results: ^Type_Info; // Type_Info.Tuple
|
||||
variadic: bool
|
||||
}
|
||||
variadic: bool;
|
||||
};
|
||||
Array: struct #ordered {
|
||||
elem: ^Type_Info
|
||||
elem_size: int
|
||||
count: int
|
||||
}
|
||||
elem: ^Type_Info;
|
||||
elem_size: int;
|
||||
count: int;
|
||||
};
|
||||
Slice: struct #ordered {
|
||||
elem: ^Type_Info
|
||||
elem_size: int
|
||||
}
|
||||
elem: ^Type_Info;
|
||||
elem_size: int;
|
||||
};
|
||||
Vector: struct #ordered {
|
||||
elem: ^Type_Info
|
||||
elem_size: int
|
||||
count: int
|
||||
align: int
|
||||
}
|
||||
Tuple: Record
|
||||
Struct: Record
|
||||
Union: Record
|
||||
Raw_Union: Record
|
||||
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
|
||||
values: []i64
|
||||
names: []string
|
||||
}
|
||||
}
|
||||
base: ^Type_Info;
|
||||
values: []i64;
|
||||
names: []string;
|
||||
};
|
||||
};
|
||||
|
||||
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
||||
if info == nil {
|
||||
return nil
|
||||
return nil;
|
||||
}
|
||||
base := info
|
||||
base := info;
|
||||
match type i : base {
|
||||
case Type_Info.Named:
|
||||
base = i.base
|
||||
base = i.base;
|
||||
}
|
||||
return base
|
||||
return base;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,160 +113,160 @@ fmuladd64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
|
||||
|
||||
|
||||
|
||||
Allocator_Mode :: enum {
|
||||
ALLOC,
|
||||
FREE,
|
||||
FREE_ALL,
|
||||
RESIZE,
|
||||
}
|
||||
Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
|
||||
|
||||
|
||||
|
||||
Allocator :: struct #ordered {
|
||||
Mode :: enum {
|
||||
ALLOC,
|
||||
FREE,
|
||||
FREE_ALL,
|
||||
RESIZE,
|
||||
}
|
||||
Proc :: type proc(allocator_data: rawptr, mode: Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr
|
||||
|
||||
|
||||
procedure: Proc
|
||||
data: rawptr
|
||||
procedure: Allocator_Proc;
|
||||
data: rawptr;
|
||||
}
|
||||
|
||||
|
||||
Context :: struct #ordered {
|
||||
thread_id: int
|
||||
thread_id: int;
|
||||
|
||||
allocator: Allocator
|
||||
allocator: Allocator;
|
||||
|
||||
user_data: rawptr
|
||||
user_index: int
|
||||
user_data: rawptr;
|
||||
user_index: int;
|
||||
}
|
||||
|
||||
#thread_local __context: Context
|
||||
#thread_local __context: Context;
|
||||
|
||||
|
||||
DEFAULT_ALIGNMENT :: align_of([vector 4]f32)
|
||||
DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
|
||||
|
||||
|
||||
__check_context :: proc() {
|
||||
c := ^__context
|
||||
c := ^__context;
|
||||
|
||||
if c.allocator.procedure == nil {
|
||||
c.allocator = default_allocator()
|
||||
c.allocator = default_allocator();
|
||||
}
|
||||
if c.thread_id == 0 {
|
||||
c.thread_id = os.current_thread_id()
|
||||
c.thread_id = os.current_thread_id();
|
||||
}
|
||||
}
|
||||
|
||||
alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT); }
|
||||
|
||||
alloc_align :: proc(size, alignment: int) -> rawptr #inline {
|
||||
__check_context()
|
||||
a := context.allocator
|
||||
return a.procedure(a.data, Allocator.Mode.ALLOC, size, alignment, nil, 0, 0)
|
||||
__check_context();
|
||||
a := context.allocator;
|
||||
return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0);
|
||||
}
|
||||
|
||||
free :: proc(ptr: rawptr) #inline {
|
||||
__check_context()
|
||||
a := context.allocator
|
||||
__check_context();
|
||||
a := context.allocator;
|
||||
if ptr != nil {
|
||||
a.procedure(a.data, Allocator.Mode.FREE, 0, 0, ptr, 0, 0)
|
||||
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
|
||||
}
|
||||
}
|
||||
free_all :: proc() #inline {
|
||||
__check_context()
|
||||
a := context.allocator
|
||||
a.procedure(a.data, Allocator.Mode.FREE_ALL, 0, 0, nil, 0, 0)
|
||||
__check_context();
|
||||
a := context.allocator;
|
||||
a.procedure(a.data, Allocator_Mode.FREE_ALL, 0, 0, nil, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT); }
|
||||
resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
|
||||
__check_context()
|
||||
a := context.allocator
|
||||
return a.procedure(a.data, Allocator.Mode.RESIZE, new_size, alignment, ptr, old_size, 0)
|
||||
__check_context();
|
||||
a := context.allocator;
|
||||
return a.procedure(a.data, Allocator_Mode.RESIZE, new_size, alignment, ptr, old_size, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
|
||||
if old_memory == nil {
|
||||
return alloc_align(new_size, alignment)
|
||||
return alloc_align(new_size, alignment);
|
||||
}
|
||||
|
||||
if new_size == 0 {
|
||||
free(old_memory)
|
||||
return nil
|
||||
free(old_memory);
|
||||
return nil;
|
||||
}
|
||||
|
||||
if new_size == old_size {
|
||||
return old_memory
|
||||
return old_memory;
|
||||
}
|
||||
|
||||
new_memory := alloc_align(new_size, alignment)
|
||||
new_memory := alloc_align(new_size, alignment);
|
||||
if new_memory == nil {
|
||||
return nil
|
||||
return nil;
|
||||
}
|
||||
|
||||
mem.copy(new_memory, old_memory, min(old_size, new_size));
|
||||
free(old_memory)
|
||||
return new_memory
|
||||
mem.copy(new_memory, old_memory, min(old_size, new_size));;
|
||||
free(old_memory);
|
||||
return new_memory;
|
||||
}
|
||||
|
||||
|
||||
default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
||||
default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||
using Allocator.Mode
|
||||
using Allocator_Mode;
|
||||
when false {
|
||||
match mode {
|
||||
case ALLOC:
|
||||
total_size := size + alignment + size_of(mem.AllocationHeader)
|
||||
ptr := os.heap_alloc(total_size)
|
||||
header := ptr as ^mem.AllocationHeader
|
||||
ptr = mem.align_forward(header+1, alignment)
|
||||
mem.allocation_header_fill(header, ptr, size)
|
||||
return mem.zero(ptr, size)
|
||||
total_size := size + alignment + size_of(mem.AllocationHeader);
|
||||
ptr := os.heap_alloc(total_size);
|
||||
header := ptr as ^mem.AllocationHeader;
|
||||
ptr = mem.align_forward(header+1, alignment);
|
||||
mem.allocation_header_fill(header, ptr, size);
|
||||
return mem.zero(ptr, size);
|
||||
|
||||
case FREE:
|
||||
os.heap_free(mem.allocation_header(old_memory))
|
||||
return nil
|
||||
os.heap_free(mem.allocation_header(old_memory));
|
||||
return nil;
|
||||
|
||||
case FREE_ALL:
|
||||
// NOTE(bill): Does nothing
|
||||
|
||||
case RESIZE:
|
||||
total_size := size + alignment + size_of(mem.AllocationHeader)
|
||||
ptr := os.heap_resize(mem.allocation_header(old_memory), total_size)
|
||||
header := ptr as ^mem.AllocationHeader
|
||||
ptr = mem.align_forward(header+1, alignment)
|
||||
mem.allocation_header_fill(header, ptr, size)
|
||||
return mem.zero(ptr, size)
|
||||
total_size := size + alignment + size_of(mem.AllocationHeader);
|
||||
ptr := os.heap_resize(mem.allocation_header(old_memory), total_size);
|
||||
header := ptr as ^mem.AllocationHeader;
|
||||
ptr = mem.align_forward(header+1, alignment);
|
||||
mem.allocation_header_fill(header, ptr, size);
|
||||
return mem.zero(ptr, size);
|
||||
}
|
||||
} else {
|
||||
match mode {
|
||||
case ALLOC:
|
||||
return os.heap_alloc(size)
|
||||
return os.heap_alloc(size);
|
||||
|
||||
case FREE:
|
||||
os.heap_free(old_memory)
|
||||
return nil
|
||||
os.heap_free(old_memory);
|
||||
return nil;
|
||||
|
||||
case FREE_ALL:
|
||||
// NOTE(bill): Does nothing
|
||||
|
||||
case RESIZE:
|
||||
return os.heap_resize(old_memory, size)
|
||||
return os.heap_resize(old_memory, size);
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil;
|
||||
}
|
||||
|
||||
default_allocator :: proc() -> Allocator {
|
||||
return Allocator{
|
||||
procedure = default_allocator_proc,
|
||||
data = nil,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -281,16 +281,16 @@ default_allocator :: proc() -> Allocator {
|
||||
|
||||
__string_eq :: proc(a, b: string) -> bool {
|
||||
if a.count != b.count {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
if a.data == b.data {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
return mem.compare(a.data, b.data, a.count) == 0
|
||||
return mem.compare(a.data, b.data, a.count) == 0;
|
||||
}
|
||||
|
||||
__string_cmp :: proc(a, b : string) -> int {
|
||||
return mem.compare(a.data, b.data, min(a.count, b.count))
|
||||
return mem.compare(a.data, b.data, min(a.count, b.count));
|
||||
}
|
||||
|
||||
__string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); }
|
||||
@@ -302,37 +302,37 @@ __string_ge :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) >=
|
||||
|
||||
__assert :: proc(file: string, line, column: int, msg: string) #inline {
|
||||
fmt.fprintf(os.stderr, "%(%:%) Runtime assertion: %\n",
|
||||
file, line, column, msg)
|
||||
__debug_trap()
|
||||
file, line, column, msg);
|
||||
__debug_trap();
|
||||
}
|
||||
|
||||
__bounds_check_error :: proc(file: string, line, column: int,
|
||||
index, count: int) {
|
||||
if 0 <= index && index < count {
|
||||
return
|
||||
return;
|
||||
}
|
||||
fmt.fprintf(os.stderr, "%(%:%) Index % is out of bounds range [0, %)\n",
|
||||
file, line, column, index, count)
|
||||
__debug_trap()
|
||||
file, line, column, index, count);
|
||||
__debug_trap();
|
||||
}
|
||||
|
||||
__slice_expr_error :: proc(file: string, line, column: int,
|
||||
low, high, max: int) {
|
||||
if 0 <= low && low <= high && high <= max {
|
||||
return
|
||||
return;
|
||||
}
|
||||
fmt.fprintf(os.stderr, "%(%:%) Invalid slice indices: [%:%:%]\n",
|
||||
file, line, column, low, high, max)
|
||||
__debug_trap()
|
||||
file, line, column, low, high, max);
|
||||
__debug_trap();
|
||||
}
|
||||
__substring_expr_error :: proc(file: string, line, column: int,
|
||||
low, high: int) {
|
||||
if 0 <= low && low <= high {
|
||||
return
|
||||
return;
|
||||
}
|
||||
fmt.fprintf(os.stderr, "%(%:%) Invalid substring indices: [%:%:%]\n",
|
||||
file, line, column, low, high)
|
||||
__debug_trap()
|
||||
file, line, column, low, high);
|
||||
__debug_trap();
|
||||
}
|
||||
|
||||
__enum_to_string :: proc(info: ^Type_Info, value: i64) -> string {
|
||||
@@ -341,11 +341,11 @@ __enum_to_string :: proc(info: ^Type_Info, value: i64) -> string {
|
||||
// TODO(bill): Search faster than linearly
|
||||
for i := 0; i < ti.values.count; i++ {
|
||||
if ti.values[i] == value {
|
||||
return ti.names[i]
|
||||
return ti.names[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#shared_global_scope
|
||||
#shared_global_scope;
|
||||
|
||||
/*
|
||||
#import "fmt.odin"
|
||||
|
||||
528
core/fmt.odin
528
core/fmt.odin
@@ -1,596 +1,594 @@
|
||||
#import "os.odin"
|
||||
#import "mem.odin"
|
||||
#import "utf8.odin"
|
||||
#import "os.odin";
|
||||
#import "mem.odin";
|
||||
#import "utf8.odin";
|
||||
|
||||
PRINT_BUF_SIZE :: 1<<12
|
||||
PRINT_BUF_SIZE :: 1<<12;
|
||||
|
||||
fprint :: proc(f: ^os.File, args: ..any) -> int {
|
||||
data: [PRINT_BUF_SIZE]byte
|
||||
buf := data[:0]
|
||||
bprint(^buf, ..args)
|
||||
os.write(f, buf)
|
||||
return buf.count
|
||||
data: [PRINT_BUF_SIZE]byte;
|
||||
buf := data[:0];
|
||||
bprint(^buf, ..args);
|
||||
os.write(f, buf);
|
||||
return buf.count;
|
||||
}
|
||||
|
||||
fprintln :: proc(f: ^os.File, args: ..any) -> int {
|
||||
data: [PRINT_BUF_SIZE]byte
|
||||
buf := data[:0]
|
||||
bprintln(^buf, ..args)
|
||||
os.write(f, buf)
|
||||
return buf.count
|
||||
data: [PRINT_BUF_SIZE]byte;
|
||||
buf := data[:0];
|
||||
bprintln(^buf, ..args);
|
||||
os.write(f, buf);
|
||||
return buf.count;
|
||||
}
|
||||
fprintf :: proc(f: ^os.File, fmt: string, args: ..any) -> int {
|
||||
data: [PRINT_BUF_SIZE]byte
|
||||
buf := data[:0]
|
||||
bprintf(^buf, fmt, ..args)
|
||||
os.write(f, buf)
|
||||
return buf.count
|
||||
data: [PRINT_BUF_SIZE]byte;
|
||||
buf := data[:0];
|
||||
bprintf(^buf, fmt, ..args);
|
||||
os.write(f, buf);
|
||||
return buf.count;
|
||||
}
|
||||
|
||||
|
||||
print :: proc(args: ..any) -> int {
|
||||
return fprint(os.stdout, ..args)
|
||||
return fprint(os.stdout, ..args);
|
||||
}
|
||||
println :: proc(args: ..any) -> int {
|
||||
return fprintln(os.stdout, ..args)
|
||||
return fprintln(os.stdout, ..args);
|
||||
}
|
||||
printf :: proc(fmt: string, args: ..any) -> int {
|
||||
return fprintf(os.stdout, fmt, ..args)
|
||||
return fprintf(os.stdout, fmt, ..args);
|
||||
}
|
||||
|
||||
|
||||
|
||||
fprint_type :: proc(f: ^os.File, info: ^Type_Info) {
|
||||
data: [PRINT_BUF_SIZE]byte
|
||||
buf := data[:0]
|
||||
bprint_type(^buf, info)
|
||||
os.write(f, buf)
|
||||
data: [PRINT_BUF_SIZE]byte;
|
||||
buf := data[:0];
|
||||
bprint_type(^buf, info);
|
||||
os.write(f, buf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
|
||||
if buf.count < buf.capacity {
|
||||
n := min(buf.capacity-buf.count, b.count)
|
||||
n := min(buf.capacity-buf.count, b.count);
|
||||
if n > 0 {
|
||||
mem.copy(buf.data + buf.count, b.data, n)
|
||||
buf.count += n
|
||||
mem.copy(buf.data + buf.count, b.data, n);
|
||||
buf.count += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bprint_string :: proc(buf: ^[]byte, s: string) {
|
||||
print_byte_buffer(buf, s as []byte)
|
||||
print_byte_buffer(buf, s as []byte);
|
||||
}
|
||||
|
||||
|
||||
byte_reverse :: proc(b: []byte) {
|
||||
n := b.count
|
||||
n := b.count;
|
||||
for i := 0; i < n/2; i++ {
|
||||
b[i], b[n-1-i] = b[n-1-i], b[i]
|
||||
b[i], b[n-1-i] = b[n-1-i], b[i];
|
||||
}
|
||||
}
|
||||
|
||||
bprint_rune :: proc(buf: ^[]byte, r: rune) {
|
||||
b, n := utf8.encode_rune(r)
|
||||
bprint_string(buf, b[:n] as string)
|
||||
b, n := utf8.encode_rune(r);
|
||||
bprint_string(buf, b[:n] as string);
|
||||
}
|
||||
|
||||
bprint_space :: proc(buf: ^[]byte) { bprint_rune(buf, ' '); }
|
||||
bprint_nl :: proc(buf: ^[]byte) { bprint_rune(buf, '\n'); }
|
||||
|
||||
__NUM_TO_CHAR_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"
|
||||
__NUM_TO_CHAR_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$";
|
||||
|
||||
bprint_bool :: proc(buffer: ^[]byte, b : bool) {
|
||||
if b {
|
||||
bprint_string(buffer, "true")
|
||||
bprint_string(buffer, "true");
|
||||
} else {
|
||||
bprint_string(buffer, "false")
|
||||
bprint_string(buffer, "false");
|
||||
}
|
||||
}
|
||||
|
||||
bprint_pointer :: proc(buffer: ^[]byte, p: rawptr) #inline {
|
||||
bprint_string(buffer, "0x")
|
||||
bprint_u64(buffer, p as uint as u64)
|
||||
bprint_string(buffer, "0x");
|
||||
bprint_u64(buffer, p as uint as u64);
|
||||
}
|
||||
|
||||
bprint_f16 :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 4); }
|
||||
bprint_f32 :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7); }
|
||||
bprint_f64 :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f as f64, 16); }
|
||||
bprint_u64 :: proc(buffer: ^[]byte, value: u64) {
|
||||
i := value
|
||||
buf: [20]byte
|
||||
len := 0
|
||||
i := value;
|
||||
buf: [20]byte;
|
||||
len := 0;
|
||||
if i == 0 {
|
||||
buf[len] = '0'
|
||||
len++
|
||||
buf[len] = '0';
|
||||
len++;
|
||||
}
|
||||
for i > 0 {
|
||||
buf[len] = __NUM_TO_CHAR_TABLE[i % 10]
|
||||
len++
|
||||
i /= 10
|
||||
buf[len] = __NUM_TO_CHAR_TABLE[i % 10];
|
||||
len++;
|
||||
i /= 10;
|
||||
}
|
||||
byte_reverse(buf[:len])
|
||||
bprint_string(buffer, buf[:len] as string)
|
||||
byte_reverse(buf[:len]);
|
||||
bprint_string(buffer, buf[:len] as string);
|
||||
}
|
||||
bprint_i64 :: proc(buffer: ^[]byte, value: i64) {
|
||||
// TODO(bill): Cleanup printing
|
||||
i := value
|
||||
i := value;
|
||||
if i < 0 {
|
||||
i = -i
|
||||
bprint_rune(buffer, '-')
|
||||
i = -i;
|
||||
bprint_rune(buffer, '-');
|
||||
}
|
||||
bprint_u64(buffer, i as u64)
|
||||
bprint_u64(buffer, i as u64);
|
||||
}
|
||||
|
||||
/*
|
||||
bprint_u128 :: proc(buffer: ^[]byte, value: u128) {
|
||||
a := value transmute [2]u64
|
||||
a := value transmute [2]u64;
|
||||
if a[1] != 0 {
|
||||
bprint_u64(buffer, a[1])
|
||||
bprint_u64(buffer, a[1]);
|
||||
}
|
||||
bprint_u64(buffer, a[0])
|
||||
bprint_u64(buffer, a[0]);
|
||||
}
|
||||
bprint_i128 :: proc(buffer: ^[]byte, value: i128) {
|
||||
i := value
|
||||
i := value;
|
||||
if i < 0 {
|
||||
i = -i
|
||||
bprint_rune(buffer, '-')
|
||||
i = -i;
|
||||
bprint_rune(buffer, '-');
|
||||
}
|
||||
bprint_u128(buffer, i as u128)
|
||||
bprint_u128(buffer, i as u128);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
print__f64 :: proc(buffer: ^[]byte, value: f64, decimal_places: int) {
|
||||
f := value
|
||||
f := value;
|
||||
if f == 0 {
|
||||
bprint_rune(buffer, '0')
|
||||
return
|
||||
bprint_rune(buffer, '0');
|
||||
return;
|
||||
}
|
||||
if f < 0 {
|
||||
bprint_rune(buffer, '-')
|
||||
f = -f
|
||||
bprint_rune(buffer, '-');
|
||||
f = -f;
|
||||
}
|
||||
|
||||
i := f as u64
|
||||
bprint_u64(buffer, i)
|
||||
f -= i as f64
|
||||
i := f as u64;
|
||||
bprint_u64(buffer, i);
|
||||
f -= i as f64;
|
||||
|
||||
bprint_rune(buffer, '.')
|
||||
bprint_rune(buffer, '.');
|
||||
|
||||
mult: f64 = 10.0
|
||||
mult: f64 = 10.0;
|
||||
for ; decimal_places >= 0; decimal_places-- {
|
||||
i = (f * mult) as u64
|
||||
bprint_u64(buffer, i as u64)
|
||||
f -= i as f64 / mult
|
||||
mult *= 10
|
||||
i = (f * mult) as u64;
|
||||
bprint_u64(buffer, i as u64);
|
||||
f -= i as f64 / mult;
|
||||
mult *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
bprint_type :: proc(buf: ^[]byte, ti: ^Type_Info) {
|
||||
if ti == nil {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
using Type_Info
|
||||
using Type_Info;
|
||||
match type info : ti {
|
||||
case Named:
|
||||
bprint_string(buf, info.name)
|
||||
bprint_string(buf, info.name);
|
||||
case Integer:
|
||||
match {
|
||||
case ti == type_info(int):
|
||||
bprint_string(buf, "int")
|
||||
case ti == type_info(uint):
|
||||
bprint_string(buf, "uint")
|
||||
case ti == type_info(int): bprint_string(buf, "int");
|
||||
case ti == type_info(uint): bprint_string(buf, "uint");
|
||||
default:
|
||||
if info.signed {
|
||||
bprint_string(buf, "i")
|
||||
bprint_string(buf, "i");
|
||||
} else {
|
||||
bprint_string(buf, "u")
|
||||
bprint_string(buf, "u");
|
||||
}
|
||||
bprint_u64(buf, 8*info.size as u64)
|
||||
bprint_u64(buf, 8*info.size as u64);
|
||||
}
|
||||
|
||||
case Float:
|
||||
match info.size {
|
||||
case 4: bprint_string(buf, "f32")
|
||||
case 8: bprint_string(buf, "f64")
|
||||
case 4: bprint_string(buf, "f32");
|
||||
case 8: bprint_string(buf, "f64");
|
||||
}
|
||||
case String: bprint_string(buf, "string")
|
||||
case Boolean: bprint_string(buf, "bool")
|
||||
case String: bprint_string(buf, "string");
|
||||
case Boolean: bprint_string(buf, "bool");
|
||||
case Pointer:
|
||||
if info.elem == nil {
|
||||
bprint_string(buf, "rawptr")
|
||||
bprint_string(buf, "rawptr");
|
||||
} else {
|
||||
bprint_string(buf, "^")
|
||||
bprint_type(buf, info.elem)
|
||||
bprint_string(buf, "^");
|
||||
bprint_type(buf, info.elem);
|
||||
}
|
||||
case Maybe:
|
||||
bprint_string(buf, "?")
|
||||
bprint_type(buf, info.elem)
|
||||
bprint_string(buf, "?");
|
||||
bprint_type(buf, info.elem);
|
||||
case Procedure:
|
||||
bprint_string(buf, "proc")
|
||||
bprint_string(buf, "proc");
|
||||
if info.params == nil {
|
||||
bprint_string(buf, "()")
|
||||
bprint_string(buf, "()");
|
||||
} else {
|
||||
count := (info.params as ^Tuple).fields.count
|
||||
count := (info.params as ^Tuple).fields.count;
|
||||
if count == 1 { bprint_string(buf, "("); }
|
||||
bprint_type(buf, info.params)
|
||||
bprint_type(buf, info.params);
|
||||
if count == 1 { bprint_string(buf, ")"); }
|
||||
}
|
||||
if info.results != nil {
|
||||
bprint_string(buf, " -> ")
|
||||
bprint_type(buf, info.results)
|
||||
bprint_string(buf, " -> ");
|
||||
bprint_type(buf, info.results);
|
||||
}
|
||||
case Tuple:
|
||||
count := info.fields.count
|
||||
count := info.fields.count;
|
||||
if count != 1 { bprint_string(buf, "("); }
|
||||
for i := 0; i < count; i++ {
|
||||
if i > 0 { bprint_string(buf, ", "); }
|
||||
|
||||
f := info.fields[i]
|
||||
f := info.fields[i];
|
||||
|
||||
if f.name.count > 0 {
|
||||
bprint_string(buf, f.name)
|
||||
bprint_string(buf, ": ")
|
||||
bprint_string(buf, f.name);
|
||||
bprint_string(buf, ": ");
|
||||
}
|
||||
bprint_type(buf, f.type_info)
|
||||
bprint_type(buf, f.type_info);
|
||||
}
|
||||
if count != 1 { bprint_string(buf, ")"); }
|
||||
|
||||
case Array:
|
||||
bprint_string(buf, "[")
|
||||
bprint_i64(buf, info.count as i64)
|
||||
bprint_string(buf, "]")
|
||||
bprint_type(buf, info.elem)
|
||||
bprint_string(buf, "[");
|
||||
bprint_i64(buf, info.count as i64);
|
||||
bprint_string(buf, "]");
|
||||
bprint_type(buf, info.elem);
|
||||
case Slice:
|
||||
bprint_string(buf, "[")
|
||||
bprint_string(buf, "]")
|
||||
bprint_type(buf, info.elem)
|
||||
bprint_string(buf, "[");
|
||||
bprint_string(buf, "]");
|
||||
bprint_type(buf, info.elem);
|
||||
case Vector:
|
||||
bprint_string(buf, "[vector ")
|
||||
bprint_i64(buf, info.count as i64)
|
||||
bprint_string(buf, "]")
|
||||
bprint_type(buf, info.elem)
|
||||
bprint_string(buf, "[vector ");
|
||||
bprint_i64(buf, info.count as i64);
|
||||
bprint_string(buf, "]");
|
||||
bprint_type(buf, info.elem);
|
||||
|
||||
case Struct:
|
||||
bprint_string(buf, "struct ")
|
||||
bprint_string(buf, "struct ");
|
||||
if info.packed { bprint_string(buf, "#packed "); }
|
||||
if info.ordered { bprint_string(buf, "#ordered "); }
|
||||
bprint_string(buf, "{")
|
||||
bprint_string(buf, "{");
|
||||
for i := 0; i < info.fields.count; i++ {
|
||||
if i > 0 {
|
||||
bprint_string(buf, ", ")
|
||||
bprint_string(buf, ", ");
|
||||
}
|
||||
bprint_any(buf, info.fields[i].name)
|
||||
bprint_string(buf, ": ")
|
||||
bprint_type(buf, info.fields[i].type_info)
|
||||
bprint_any(buf, info.fields[i].name);
|
||||
bprint_string(buf, ": ");
|
||||
bprint_type(buf, info.fields[i].type_info);
|
||||
}
|
||||
bprint_string(buf, "}")
|
||||
bprint_string(buf, "}");
|
||||
|
||||
case Union:
|
||||
bprint_string(buf, "union {")
|
||||
bprint_string(buf, "union {");
|
||||
for i := 0; i < info.fields.count; i++ {
|
||||
if i > 0 {
|
||||
bprint_string(buf, ", ")
|
||||
bprint_string(buf, ", ");
|
||||
}
|
||||
bprint_any(buf, info.fields[i].name)
|
||||
bprint_string(buf, ": ")
|
||||
bprint_type(buf, info.fields[i].type_info)
|
||||
bprint_any(buf, info.fields[i].name);
|
||||
bprint_string(buf, ": ");
|
||||
bprint_type(buf, info.fields[i].type_info);
|
||||
}
|
||||
bprint_string(buf, "}")
|
||||
bprint_string(buf, "}");
|
||||
|
||||
case Raw_Union:
|
||||
bprint_string(buf, "raw_union {")
|
||||
bprint_string(buf, "raw_union {");
|
||||
for i := 0; i < info.fields.count; i++ {
|
||||
if i > 0 {
|
||||
bprint_string(buf, ", ")
|
||||
bprint_string(buf, ", ");
|
||||
}
|
||||
bprint_any(buf, info.fields[i].name)
|
||||
bprint_string(buf, ": ")
|
||||
bprint_type(buf, info.fields[i].type_info)
|
||||
bprint_any(buf, info.fields[i].name);
|
||||
bprint_string(buf, ": ");
|
||||
bprint_type(buf, info.fields[i].type_info);
|
||||
}
|
||||
bprint_string(buf, "}")
|
||||
bprint_string(buf, "}");
|
||||
|
||||
case Enum:
|
||||
bprint_string(buf, "enum ")
|
||||
bprint_type(buf, info.base)
|
||||
bprint_string(buf, "{}")
|
||||
bprint_string(buf, "enum ");
|
||||
bprint_type(buf, info.base);
|
||||
bprint_string(buf, "{}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
make_any :: proc(type_info: ^Type_Info, data: rawptr) -> any {
|
||||
a: any
|
||||
a.type_info = type_info
|
||||
a.data = data
|
||||
return a
|
||||
a: any;
|
||||
a.type_info = type_info;
|
||||
a.data = data;
|
||||
return a;
|
||||
}
|
||||
|
||||
bprint_any :: proc(buf: ^[]byte, arg: any) {
|
||||
if arg.type_info == nil {
|
||||
bprint_string(buf, "<nil>")
|
||||
return
|
||||
bprint_string(buf, "<nil>");
|
||||
return;
|
||||
}
|
||||
|
||||
if arg.data == nil {
|
||||
bprint_string(buf, "<nil>")
|
||||
return
|
||||
bprint_string(buf, "<nil>");
|
||||
return;
|
||||
}
|
||||
|
||||
using Type_Info
|
||||
using Type_Info;
|
||||
match type info : arg.type_info {
|
||||
case Named:
|
||||
a := make_any(info.base, arg.data)
|
||||
a := make_any(info.base, arg.data);
|
||||
match type b : info.base {
|
||||
case Struct:
|
||||
bprint_string(buf, info.name)
|
||||
bprint_string(buf, "{")
|
||||
bprint_string(buf, info.name);
|
||||
bprint_string(buf, "{");
|
||||
for i := 0; i < b.fields.count; i++ {
|
||||
f := b.fields[i]
|
||||
f := b.fields[i];
|
||||
if i > 0 {
|
||||
bprint_string(buf, ", ")
|
||||
bprint_string(buf, ", ");
|
||||
}
|
||||
bprint_string(buf, f.name)
|
||||
// bprint_any(buf, f.offset)
|
||||
bprint_string(buf, " = ")
|
||||
data := arg.data as ^byte + f.offset
|
||||
bprint_any(buf, make_any(f.type_info, data))
|
||||
bprint_string(buf, f.name);
|
||||
// bprint_any(buf, f.offset);
|
||||
bprint_string(buf, " = ");
|
||||
data := arg.data as ^byte + f.offset;
|
||||
bprint_any(buf, make_any(f.type_info, data));
|
||||
}
|
||||
bprint_string(buf, "}")
|
||||
bprint_string(buf, "}");
|
||||
|
||||
default:
|
||||
bprint_any(buf, a)
|
||||
bprint_any(buf, a);
|
||||
}
|
||||
|
||||
case Integer:
|
||||
match type i : arg {
|
||||
case i8: bprint_i64(buf, i as i64)
|
||||
case u8: bprint_u64(buf, i as u64)
|
||||
case i16: bprint_i64(buf, i as i64)
|
||||
case u16: bprint_u64(buf, i as u64)
|
||||
case i32: bprint_i64(buf, i as i64)
|
||||
case u32: bprint_u64(buf, i as u64)
|
||||
case i64: bprint_i64(buf, i)
|
||||
case u64: bprint_u64(buf, i)
|
||||
// case i128: bprint_i128(buf, i)
|
||||
// case u128: bprint_u128(buf, i)
|
||||
case i8: bprint_i64(buf, i as i64);
|
||||
case u8: bprint_u64(buf, i as u64);
|
||||
case i16: bprint_i64(buf, i as i64);
|
||||
case u16: bprint_u64(buf, i as u64);
|
||||
case i32: bprint_i64(buf, i as i64);
|
||||
case u32: bprint_u64(buf, i as u64);
|
||||
case i64: bprint_i64(buf, i);
|
||||
case u64: bprint_u64(buf, i);
|
||||
// case i128: bprint_i128(buf, i);
|
||||
// case u128: bprint_u128(buf, i);
|
||||
|
||||
case int: bprint_i64(buf, i as i64)
|
||||
case uint: bprint_u64(buf, i as u64)
|
||||
case int: bprint_i64(buf, i as i64);
|
||||
case uint: bprint_u64(buf, i as u64);
|
||||
}
|
||||
|
||||
case Float:
|
||||
match type f : arg {
|
||||
// case f16: bprint_f64(buf, f as f64)
|
||||
case f32: bprint_f32(buf, f)
|
||||
case f64: bprint_f64(buf, f)
|
||||
// case f128: bprint_f64(buf, f as f64)
|
||||
// case f16: bprint_f64(buf, f as f64);
|
||||
case f32: bprint_f32(buf, f);
|
||||
case f64: bprint_f64(buf, f);
|
||||
// case f128: bprint_f64(buf, f as f64);
|
||||
}
|
||||
|
||||
case String:
|
||||
match type s : arg {
|
||||
case string: bprint_string(buf, s)
|
||||
case string: bprint_string(buf, s);
|
||||
}
|
||||
|
||||
case Boolean:
|
||||
match type b : arg {
|
||||
case bool: bprint_bool(buf, b)
|
||||
case bool: bprint_bool(buf, b);
|
||||
}
|
||||
|
||||
case Pointer:
|
||||
match type p : arg {
|
||||
case ^Type_Info: bprint_type(buf, p)
|
||||
default: bprint_pointer(buf, (arg.data as ^rawptr)^)
|
||||
case ^Type_Info: bprint_type(buf, p);
|
||||
default: bprint_pointer(buf, (arg.data as ^rawptr)^);
|
||||
}
|
||||
|
||||
case Maybe:
|
||||
size := mem.size_of_type_info(info.elem)
|
||||
data := slice_ptr(arg.data as ^byte, size+1)
|
||||
size := mem.size_of_type_info(info.elem);
|
||||
data := slice_ptr(arg.data as ^byte, size+1);
|
||||
if data[size] != 0 {
|
||||
bprint_any(buf, make_any(info.elem, arg.data))
|
||||
bprint_any(buf, make_any(info.elem, arg.data));
|
||||
} else {
|
||||
bprint_string(buf, "nil")
|
||||
bprint_string(buf, "nil");
|
||||
}
|
||||
|
||||
case Enum:
|
||||
value: i64 = 0
|
||||
value: i64 = 0;
|
||||
|
||||
match type i : make_any(info.base, arg.data) {
|
||||
case i8: value = i as i64
|
||||
case i16: value = i as i64
|
||||
case i32: value = i as i64
|
||||
case i64: value = i as i64
|
||||
case u8: value = i as i64
|
||||
case u16: value = i as i64
|
||||
case u32: value = i as i64
|
||||
case u64: value = i as i64
|
||||
case i8: value = i as i64;
|
||||
case i16: value = i as i64;
|
||||
case i32: value = i as i64;
|
||||
case i64: value = i as i64;
|
||||
case u8: value = i as i64;
|
||||
case u16: value = i as i64;
|
||||
case u32: value = i as i64;
|
||||
case u64: value = i as i64;
|
||||
}
|
||||
bprint_string(buf, __enum_to_string(arg.type_info, value))
|
||||
bprint_string(buf, __enum_to_string(arg.type_info, value));
|
||||
|
||||
case Array:
|
||||
bprintf(buf, "[%]%{", info.count, info.elem)
|
||||
defer bprint_string(buf, "}")
|
||||
bprintf(buf, "[%]%{", info.count, info.elem);
|
||||
defer bprint_string(buf, "}");
|
||||
|
||||
for i := 0; i < info.count; i++ {
|
||||
if i > 0 {
|
||||
bprint_string(buf, ", ")
|
||||
bprint_string(buf, ", ");
|
||||
}
|
||||
|
||||
data := arg.data as ^byte + i*info.elem_size
|
||||
bprint_any(buf, make_any(info.elem, data))
|
||||
data := arg.data as ^byte + i*info.elem_size;
|
||||
bprint_any(buf, make_any(info.elem, data));
|
||||
}
|
||||
|
||||
case Slice:
|
||||
slice := arg.data as ^[]byte
|
||||
bprintf(buf, "[]%{", info.elem)
|
||||
defer bprint_string(buf, "}")
|
||||
slice := arg.data as ^[]byte;
|
||||
bprintf(buf, "[]%{", info.elem);
|
||||
defer bprint_string(buf, "}");
|
||||
|
||||
for i := 0; i < slice.count; i++ {
|
||||
if i > 0 {
|
||||
bprint_string(buf, ", ")
|
||||
bprint_string(buf, ", ");
|
||||
}
|
||||
|
||||
data := slice.data + i*info.elem_size
|
||||
bprint_any(buf, make_any(info.elem, data))
|
||||
data := slice.data + i*info.elem_size;
|
||||
bprint_any(buf, make_any(info.elem, data));
|
||||
}
|
||||
|
||||
case Vector:
|
||||
is_bool :: proc(type_info: ^Type_Info) -> bool {
|
||||
match type info : type_info {
|
||||
case Named:
|
||||
return is_bool(info.base)
|
||||
return is_bool(info.base);
|
||||
case Boolean:
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
bprintf(buf, "[vector %]%{", info.count, info.elem)
|
||||
defer bprint_string(buf, "}")
|
||||
bprintf(buf, "[vector %]%{", info.count, info.elem);
|
||||
defer bprint_string(buf, "}");
|
||||
|
||||
if is_bool(info.elem) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
for i := 0; i < info.count; i++ {
|
||||
if i > 0 {
|
||||
bprint_string(buf, ", ")
|
||||
bprint_string(buf, ", ");
|
||||
}
|
||||
|
||||
data := arg.data as ^byte + i*info.elem_size
|
||||
bprint_any(buf, make_any(info.elem, data))
|
||||
data := arg.data as ^byte + i*info.elem_size;
|
||||
bprint_any(buf, make_any(info.elem, data));
|
||||
}
|
||||
|
||||
|
||||
case Struct:
|
||||
bprintf(buf, "%{", arg.type_info)
|
||||
defer bprint_string(buf, "}")
|
||||
bprintf(buf, "%{", arg.type_info);
|
||||
defer bprint_string(buf, "}");
|
||||
|
||||
for i := 0; i < info.fields.count; i++ {
|
||||
if i > 0 {
|
||||
bprint_string(buf, ", ")
|
||||
bprint_string(buf, ", ");
|
||||
}
|
||||
bprint_string(buf, info.fields[i].name)
|
||||
bprint_string(buf, " = ")
|
||||
data := arg.data as ^byte + info.fields[i].offset
|
||||
ti := info.fields[i].type_info
|
||||
bprint_any(buf, make_any(ti, data))
|
||||
bprint_string(buf, info.fields[i].name);
|
||||
bprint_string(buf, " = ");
|
||||
data := arg.data as ^byte + info.fields[i].offset;
|
||||
ti := info.fields[i].type_info;
|
||||
bprint_any(buf, make_any(ti, data));
|
||||
}
|
||||
|
||||
case Union:
|
||||
bprint_string(buf, "(union)")
|
||||
bprint_string(buf, "(union)");
|
||||
case Raw_Union:
|
||||
bprint_string(buf, "(raw_union)")
|
||||
bprint_string(buf, "(raw_union)");
|
||||
case Procedure:
|
||||
bprint_type(buf, arg.type_info)
|
||||
bprint_string(buf, " @ ")
|
||||
bprint_pointer(buf, (arg.data as ^rawptr)^)
|
||||
bprint_type(buf, arg.type_info);
|
||||
bprint_string(buf, " @ ");
|
||||
bprint_pointer(buf, (arg.data as ^rawptr)^);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bprintf :: proc(buf: ^[]byte, fmt: string, args: ..any) -> int {
|
||||
is_digit :: proc(r: rune) -> bool #inline {
|
||||
return '0' <= r && r <= '9'
|
||||
return '0' <= r && r <= '9';
|
||||
}
|
||||
|
||||
parse_int :: proc(s: string, offset: int) -> (int, int) {
|
||||
result := 0
|
||||
result := 0;
|
||||
|
||||
for ; offset < s.count; offset++ {
|
||||
c := s[offset] as rune
|
||||
c := s[offset] as rune;
|
||||
if !is_digit(c) {
|
||||
break
|
||||
break;
|
||||
}
|
||||
|
||||
result *= 10
|
||||
result += (c - '0') as int
|
||||
result *= 10;
|
||||
result += (c - '0') as int;
|
||||
}
|
||||
|
||||
return result, offset
|
||||
return result, offset;
|
||||
}
|
||||
|
||||
prev := 0
|
||||
implicit_index := 0
|
||||
prev := 0;
|
||||
implicit_index := 0;
|
||||
|
||||
for i := 0; i < fmt.count; i++ {
|
||||
r := fmt[i] as rune
|
||||
index := implicit_index
|
||||
r := fmt[i] as rune;
|
||||
index := implicit_index;
|
||||
|
||||
if r != '%' {
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
|
||||
bprint_string(buf, fmt[prev:i])
|
||||
bprint_string(buf, fmt[prev:i]);
|
||||
i++; // Skip %
|
||||
if i < fmt.count {
|
||||
next := fmt[i] as rune
|
||||
next := fmt[i] as rune;
|
||||
|
||||
if next == '%' {
|
||||
bprint_string(buf, "%")
|
||||
i++
|
||||
prev = i
|
||||
continue
|
||||
bprint_string(buf, "%");
|
||||
i++;
|
||||
prev = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if is_digit(next) {
|
||||
index, i = parse_int(fmt, i)
|
||||
index, i = parse_int(fmt, i);
|
||||
}
|
||||
}
|
||||
|
||||
if 0 <= index && index < args.count {
|
||||
bprint_any(buf, args[index])
|
||||
implicit_index = index+1
|
||||
bprint_any(buf, args[index]);
|
||||
implicit_index = index+1;
|
||||
} else {
|
||||
// TODO(bill): Error check index out bounds
|
||||
bprint_string(buf, "<invalid>")
|
||||
bprint_string(buf, "<invalid>");
|
||||
}
|
||||
|
||||
prev = i
|
||||
prev = i;
|
||||
}
|
||||
|
||||
bprint_string(buf, fmt[prev:])
|
||||
return buf.count
|
||||
bprint_string(buf, fmt[prev:]);
|
||||
return buf.count;
|
||||
}
|
||||
|
||||
|
||||
bprint :: proc(buf: ^[]byte, args: ..any) -> int {
|
||||
is_type_string :: proc(info: ^Type_Info) -> bool {
|
||||
using Type_Info
|
||||
using Type_Info;
|
||||
if info == nil {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
match type i : type_info_base(info) {
|
||||
case String:
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
prev_string := false
|
||||
prev_string := false;
|
||||
for i := 0; i < args.count; i++ {
|
||||
arg := args[i]
|
||||
is_string := arg.data != nil && is_type_string(arg.type_info)
|
||||
arg := args[i];
|
||||
is_string := arg.data != nil && is_type_string(arg.type_info);
|
||||
if i > 0 && !is_string && !prev_string {
|
||||
bprint_space(buf)
|
||||
bprint_space(buf);
|
||||
}
|
||||
bprint_any(buf, arg)
|
||||
prev_string = is_string
|
||||
bprint_any(buf, arg);
|
||||
prev_string = is_string;
|
||||
}
|
||||
return buf.count
|
||||
return buf.count;
|
||||
}
|
||||
|
||||
bprintln :: proc(buf: ^[]byte, args: ..any) -> int {
|
||||
for i := 0; i < args.count; i++ {
|
||||
if i > 0 {
|
||||
append(buf, ' ')
|
||||
append(buf, ' ');
|
||||
}
|
||||
bprint_any(buf, args[i])
|
||||
bprint_any(buf, args[i]);
|
||||
}
|
||||
bprint_nl(buf)
|
||||
return buf.count
|
||||
bprint_nl(buf);
|
||||
return buf.count;
|
||||
}
|
||||
|
||||
192
core/hash.odin
192
core/hash.odin
@@ -1,164 +1,164 @@
|
||||
crc32 :: proc(data: rawptr, len: int) -> u32 {
|
||||
result := ~(0 as u32)
|
||||
s := slice_ptr(data as ^u8, len)
|
||||
result := ~(0 as u32);
|
||||
s := slice_ptr(data as ^u8, len);
|
||||
for i := 0; i < len; i++ {
|
||||
b := s[i] as u32
|
||||
result = result>>8 ~ __CRC32_TABLE[(result ~ b) & 0xff]
|
||||
b := s[i] as u32;
|
||||
result = result>>8 ~ __CRC32_TABLE[(result ~ b) & 0xff];
|
||||
}
|
||||
return ~result
|
||||
return ~result;
|
||||
}
|
||||
crc64 :: proc(data: rawptr, len: int) -> u64 {
|
||||
result := ~(0 as u64)
|
||||
s := slice_ptr(data as ^u8, len)
|
||||
result := ~(0 as u64);
|
||||
s := slice_ptr(data as ^u8, len);
|
||||
for i := 0; i < len; i++ {
|
||||
b := s[i] as u64
|
||||
result = result>>8 ~ __CRC64_TABLE[(result ~ b) & 0xff]
|
||||
b := s[i] as u64;
|
||||
result = result>>8 ~ __CRC64_TABLE[(result ~ b) & 0xff];
|
||||
}
|
||||
return ~result
|
||||
return ~result;
|
||||
}
|
||||
|
||||
fnv32 :: proc(data: rawptr, len: int) -> u32 {
|
||||
s := slice_ptr(data as ^u8, len)
|
||||
s := slice_ptr(data as ^u8, len);
|
||||
|
||||
h: u32 = 0x811c9dc5
|
||||
h: u32 = 0x811c9dc5;
|
||||
for i := 0; i < len; i++ {
|
||||
h = (h * 0x01000193) ~ s[i] as u32
|
||||
h = (h * 0x01000193) ~ s[i] as u32;
|
||||
}
|
||||
return h
|
||||
return h;
|
||||
}
|
||||
|
||||
fnv64 :: proc(data: rawptr, len: int) -> u64 {
|
||||
s := slice_ptr(data as ^u8, len)
|
||||
s := slice_ptr(data as ^u8, len);
|
||||
|
||||
h: u64 = 0xcbf29ce484222325
|
||||
h: u64 = 0xcbf29ce484222325;
|
||||
for i := 0; i < len; i++ {
|
||||
h = (h * 0x100000001b3) ~ s[i] as u64
|
||||
h = (h * 0x100000001b3) ~ s[i] as u64;
|
||||
}
|
||||
return h
|
||||
return h;
|
||||
}
|
||||
|
||||
fnv32a :: proc(data: rawptr, len: int) -> u32 {
|
||||
s := slice_ptr(data as ^u8, len)
|
||||
s := slice_ptr(data as ^u8, len);
|
||||
|
||||
h: u32 = 0x811c9dc5
|
||||
h: u32 = 0x811c9dc5;
|
||||
for i := 0; i < len; i++ {
|
||||
h = (h ~ s[i] as u32) * 0x01000193
|
||||
h = (h ~ s[i] as u32) * 0x01000193;
|
||||
}
|
||||
return h
|
||||
return h;
|
||||
}
|
||||
|
||||
fnv64a :: proc(data: rawptr, len: int) -> u64 {
|
||||
s := slice_ptr(data as ^u8, len)
|
||||
s := slice_ptr(data as ^u8, len);
|
||||
|
||||
h: u64 = 0xcbf29ce484222325
|
||||
h: u64 = 0xcbf29ce484222325;
|
||||
for i := 0; i < len; i++ {
|
||||
h = (h ~ s[i] as u64) * 0x100000001b3
|
||||
h = (h ~ s[i] as u64) * 0x100000001b3;
|
||||
}
|
||||
return h
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
||||
SEED :: 0x9747b28c
|
||||
SEED :: 0x9747b28c;
|
||||
|
||||
if size_of(int) == 8 {
|
||||
m :: 0xc6a4a7935bd1e995
|
||||
r :: 47
|
||||
when size_of(int) == 8 {
|
||||
m :: 0xc6a4a7935bd1e995;
|
||||
r :: 47;
|
||||
|
||||
h: u64 = SEED ~ (len as u64 * m)
|
||||
h: u64 = SEED ~ (len as u64 * m);
|
||||
|
||||
data := slice_ptr(data_ as ^u64, len/size_of(u64))
|
||||
data2 := slice_ptr(data_ as ^u8, len)
|
||||
data := slice_ptr(data_ as ^u64, len/size_of(u64));
|
||||
data2 := slice_ptr(data_ as ^u8, len);
|
||||
|
||||
for i := 0; i < data.count; i++ {
|
||||
k := data[i]
|
||||
k := data[i];
|
||||
|
||||
k *= m
|
||||
k ~= k>>r
|
||||
k *= m
|
||||
k *= m;
|
||||
k ~= k>>r;
|
||||
k *= m;
|
||||
|
||||
h ~= k
|
||||
h *= m
|
||||
h ~= k;
|
||||
h *= m;
|
||||
}
|
||||
|
||||
match len & 7 {
|
||||
case 7: h ~= data2[6] as u64 << 48; fallthrough
|
||||
case 6: h ~= data2[5] as u64 << 40; fallthrough
|
||||
case 5: h ~= data2[4] as u64 << 32; fallthrough
|
||||
case 4: h ~= data2[3] as u64 << 24; fallthrough
|
||||
case 3: h ~= data2[2] as u64 << 16; fallthrough
|
||||
case 2: h ~= data2[1] as u64 << 8; fallthrough
|
||||
case 7: h ~= data2[6] as u64 << 48; fallthrough;
|
||||
case 6: h ~= data2[5] as u64 << 40; fallthrough;
|
||||
case 5: h ~= data2[4] as u64 << 32; fallthrough;
|
||||
case 4: h ~= data2[3] as u64 << 24; fallthrough;
|
||||
case 3: h ~= data2[2] as u64 << 16; fallthrough;
|
||||
case 2: h ~= data2[1] as u64 << 8; fallthrough;
|
||||
case 1:
|
||||
h ~= data2[0] as u64
|
||||
h *= m
|
||||
h ~= data2[0] as u64;
|
||||
h *= m;
|
||||
}
|
||||
|
||||
h ~= h>>r
|
||||
h *= m
|
||||
h ~= h>>r
|
||||
h ~= h>>r;
|
||||
h *= m;
|
||||
h ~= h>>r;
|
||||
|
||||
return h
|
||||
return h;
|
||||
} else {
|
||||
m :: 0x5bd1e995
|
||||
r :: 24
|
||||
m :: 0x5bd1e995;
|
||||
r :: 24;
|
||||
|
||||
h1: u32 = SEED as u32 ~ len as u32
|
||||
h2: u32 = SEED >> 32
|
||||
h1: u32 = SEED as u32 ~ len as u32;
|
||||
h2: u32 = SEED >> 32;
|
||||
|
||||
data := slice_ptr(data_ as ^u32, len/size_of(u32))
|
||||
data := slice_ptr(data_ as ^u32, len/size_of(u32));
|
||||
|
||||
i := 0
|
||||
i := 0;
|
||||
for len >= 8 {
|
||||
k1, k2: u32
|
||||
k1 = data[i]; i++
|
||||
k1 *= m
|
||||
k1 ~= k1>>r
|
||||
k1 *= m
|
||||
h1 *= m
|
||||
h1 ~= k1
|
||||
len -= 4
|
||||
k1, k2: u32;
|
||||
k1 = data[i]; i++;
|
||||
k1 *= m;
|
||||
k1 ~= k1>>r;
|
||||
k1 *= m;
|
||||
h1 *= m;
|
||||
h1 ~= k1;
|
||||
len -= 4;
|
||||
|
||||
k2 = data[i]; i++
|
||||
k2 *= m
|
||||
k2 ~= k2>>r
|
||||
k2 *= m
|
||||
h2 *= m
|
||||
h2 ~= k2
|
||||
len -= 4
|
||||
k2 = data[i]; i++;
|
||||
k2 *= m;
|
||||
k2 ~= k2>>r;
|
||||
k2 *= m;
|
||||
h2 *= m;
|
||||
h2 ~= k2;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
if (len >= 4) {
|
||||
k1: u32
|
||||
k1 = data[i]; i++
|
||||
k1 *= m
|
||||
k1 ~= k1>>r
|
||||
k1 *= m
|
||||
h1 *= m
|
||||
h1 ~= k1
|
||||
len -= 4
|
||||
k1: u32;
|
||||
k1 = data[i]; i++;
|
||||
k1 *= m;
|
||||
k1 ~= k1>>r;
|
||||
k1 *= m;
|
||||
h1 *= m;
|
||||
h1 ~= k1;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
data8 := slice_ptr((data.data+i) as ^u8, 3); // NOTE(bill): This is unsafe
|
||||
|
||||
match len {
|
||||
case 3: h2 ~= data8[2] as u32 << 16; fallthrough
|
||||
case 2: h2 ~= data8[1] as u32 << 8; fallthrough
|
||||
case 3: h2 ~= data8[2] as u32 << 16; fallthrough;
|
||||
case 2: h2 ~= data8[1] as u32 << 8; fallthrough;
|
||||
case 1:
|
||||
h2 ~= data8[0] as u32
|
||||
h2 *= m
|
||||
h2 ~= data8[0] as u32;
|
||||
h2 *= m;
|
||||
}
|
||||
|
||||
h1 ~= h2>>18
|
||||
h1 *= m
|
||||
h2 ~= h1>>22
|
||||
h2 *= m
|
||||
h1 ~= h2>>17
|
||||
h1 *= m
|
||||
h2 ~= h1>>19
|
||||
h2 *= m
|
||||
h1 ~= h2>>18;
|
||||
h1 *= m;
|
||||
h2 ~= h1>>22;
|
||||
h2 *= m;
|
||||
h1 ~= h2>>17;
|
||||
h1 *= m;
|
||||
h2 ~= h1>>19;
|
||||
h2 *= m;
|
||||
|
||||
h := (h1 as u64)<<32 | h2 as u64
|
||||
return h
|
||||
h := (h1 as u64)<<32 | h2 as u64;
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ __CRC32_TABLE := [256]u32{
|
||||
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
|
||||
}
|
||||
};
|
||||
__CRC64_TABLE := [256]u64{
|
||||
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
|
||||
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
|
||||
@@ -295,4 +295,4 @@ __CRC64_TABLE := [256]u64{
|
||||
0xcf8b0890283e370c, 0x8d7be97b81d4019f, 0x4a6acb477bea5a2a, 0x089a2aacd2006cb9,
|
||||
0x14dea25f3af9026d, 0x562e43b4931334fe, 0x913f6188692d6f4b, 0xd3cf8063c0c759d8,
|
||||
0x5dedc41a34bbeeb2, 0x1f1d25f19d51d821, 0xd80c07cd676f8394, 0x9afce626ce85b507,
|
||||
}
|
||||
};
|
||||
|
||||
388
core/math.odin
388
core/math.odin
@@ -1,29 +1,29 @@
|
||||
TAU :: 6.28318530717958647692528676655900576
|
||||
PI :: 3.14159265358979323846264338327950288
|
||||
ONE_OVER_TAU :: 0.636619772367581343075535053490057448
|
||||
ONE_OVER_PI :: 0.159154943091895335768883763372514362
|
||||
TAU :: 6.28318530717958647692528676655900576;
|
||||
PI :: 3.14159265358979323846264338327950288;
|
||||
ONE_OVER_TAU :: 0.636619772367581343075535053490057448;
|
||||
ONE_OVER_PI :: 0.159154943091895335768883763372514362;
|
||||
|
||||
E :: 2.71828182845904523536
|
||||
SQRT_TWO :: 1.41421356237309504880168872420969808
|
||||
SQRT_THREE :: 1.73205080756887729352744634150587236
|
||||
SQRT_FIVE :: 2.23606797749978969640917366873127623
|
||||
E :: 2.71828182845904523536;
|
||||
SQRT_TWO :: 1.41421356237309504880168872420969808;
|
||||
SQRT_THREE :: 1.73205080756887729352744634150587236;
|
||||
SQRT_FIVE :: 2.23606797749978969640917366873127623;
|
||||
|
||||
LOG_TWO :: 0.693147180559945309417232121458176568
|
||||
LOG_TEN :: 2.30258509299404568401799145468436421
|
||||
LOG_TWO :: 0.693147180559945309417232121458176568;
|
||||
LOG_TEN :: 2.30258509299404568401799145468436421;
|
||||
|
||||
EPSILON :: 1.19209290e-7
|
||||
EPSILON :: 1.19209290e-7;
|
||||
|
||||
τ :: TAU
|
||||
π :: PI
|
||||
τ :: TAU;
|
||||
π :: PI;
|
||||
|
||||
|
||||
Vec2 :: type [vector 2]f32
|
||||
Vec3 :: type [vector 3]f32
|
||||
Vec4 :: type [vector 4]f32
|
||||
|
||||
Mat2 :: type [2]Vec2
|
||||
Mat3 :: type [3]Vec3
|
||||
Mat4 :: type [4]Vec4
|
||||
Vec2 :: type [vector 2]f32;
|
||||
Vec3 :: type [vector 3]f32;
|
||||
Vec4 :: type [vector 4]f32;
|
||||
;
|
||||
Mat2 :: type [2]Vec2;
|
||||
Mat3 :: type [3]Vec3;
|
||||
Mat4 :: type [4]Vec4;
|
||||
|
||||
|
||||
sqrt32 :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
|
||||
@@ -47,42 +47,42 @@ sign64 :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
|
||||
|
||||
|
||||
copy_sign32 :: proc(x, y: f32) -> f32 {
|
||||
ix := x transmute u32
|
||||
iy := y transmute u32
|
||||
ix &= 0x7fffffff
|
||||
ix |= iy & 0x80000000
|
||||
return ix transmute f32
|
||||
ix := x transmute u32;
|
||||
iy := y transmute u32;
|
||||
ix &= 0x7fffffff;
|
||||
ix |= iy & 0x80000000;
|
||||
return ix transmute f32;
|
||||
}
|
||||
round32 :: proc(x: f32) -> f32 {
|
||||
if x >= 0 {
|
||||
return floor32(x + 0.5)
|
||||
return floor32(x + 0.5);
|
||||
}
|
||||
return ceil32(x - 0.5)
|
||||
return ceil32(x - 0.5);
|
||||
}
|
||||
floor32 :: proc(x: f32) -> f32 {
|
||||
if x >= 0 {
|
||||
return x as int as f32
|
||||
return x as int as f32;
|
||||
}
|
||||
return (x-0.5) as int as f32
|
||||
return (x-0.5) as int as f32;
|
||||
}
|
||||
ceil32 :: proc(x: f32) -> f32 {
|
||||
if x < 0 {
|
||||
return x as int as f32
|
||||
return x as int as f32;
|
||||
}
|
||||
return ((x as int)+1) as f32
|
||||
return ((x as int)+1) as f32;
|
||||
}
|
||||
|
||||
remainder32 :: proc(x, y: f32) -> f32 {
|
||||
return x - round32(x/y) * y
|
||||
return x - round32(x/y) * y;
|
||||
}
|
||||
|
||||
fmod32 :: proc(x, y: f32) -> f32 {
|
||||
y = abs(y)
|
||||
result := remainder32(abs(x), y)
|
||||
y = abs(y);
|
||||
result := remainder32(abs(x), y);
|
||||
if sign32(result) < 0 {
|
||||
result += y
|
||||
result += y;
|
||||
}
|
||||
return copy_sign32(result, x)
|
||||
return copy_sign32(result, x);
|
||||
}
|
||||
|
||||
|
||||
@@ -97,9 +97,9 @@ dot3 :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
|
||||
dot4 :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
|
||||
|
||||
cross3 :: proc(x, y: Vec3) -> Vec3 {
|
||||
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1)
|
||||
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0)
|
||||
return a - b
|
||||
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
|
||||
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
|
||||
return a - b;
|
||||
}
|
||||
|
||||
|
||||
@@ -112,27 +112,27 @@ vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; }
|
||||
vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)}; }
|
||||
|
||||
vec2_norm0 :: proc(v: Vec2) -> Vec2 {
|
||||
m := vec2_mag(v)
|
||||
m := vec2_mag(v);
|
||||
if m == 0 {
|
||||
return Vec2{0}
|
||||
return Vec2{0};
|
||||
}
|
||||
return v / Vec2{m}
|
||||
return v / Vec2{m};
|
||||
}
|
||||
|
||||
vec3_norm0 :: proc(v: Vec3) -> Vec3 {
|
||||
m := vec3_mag(v)
|
||||
m := vec3_mag(v);
|
||||
if m == 0 {
|
||||
return Vec3{0}
|
||||
return Vec3{0};
|
||||
}
|
||||
return v / Vec3{m}
|
||||
return v / Vec3{m};
|
||||
}
|
||||
|
||||
vec4_norm0 :: proc(v: Vec4) -> Vec4 {
|
||||
m := vec4_mag(v)
|
||||
m := vec4_mag(v);
|
||||
if m == 0 {
|
||||
return Vec4{0}
|
||||
return Vec4{0};
|
||||
}
|
||||
return v / Vec4{m}
|
||||
return v / Vec4{m};
|
||||
}
|
||||
|
||||
|
||||
@@ -143,29 +143,29 @@ mat4_identity :: proc() -> Mat4 {
|
||||
{0, 1, 0, 0},
|
||||
{0, 0, 1, 0},
|
||||
{0, 0, 0, 1},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
||||
for j := 0; j < 4; j++ {
|
||||
for i := 0; i < 4; i++ {
|
||||
m[i][j], m[j][i] = m[j][i], m[i][j]
|
||||
m[i][j], m[j][i] = m[j][i], m[i][j];
|
||||
}
|
||||
}
|
||||
return m
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
|
||||
c: Mat4
|
||||
c: Mat4;
|
||||
for j := 0; j < 4; j++ {
|
||||
for i := 0; i < 4; i++ {
|
||||
c[j][i] = a[0][i]*b[j][0]
|
||||
+ a[1][i]*b[j][1]
|
||||
+ a[2][i]*b[j][2]
|
||||
+ a[3][i]*b[j][3]
|
||||
c[j][i] = a[0][i]*b[j][0] +
|
||||
a[1][i]*b[j][1] +
|
||||
a[2][i]*b[j][2] +
|
||||
a[3][i]*b[j][3];
|
||||
}
|
||||
}
|
||||
return c
|
||||
return c;
|
||||
}
|
||||
|
||||
mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||
@@ -174,197 +174,195 @@ mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
|
||||
m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z + m[3][2]*v.w,
|
||||
m[0][3]*v.x + m[1][3]*v.y + m[2][3]*v.z + m[3][3]*v.w,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mat4_inverse :: proc(m: Mat4) -> Mat4 {
|
||||
o: Mat4
|
||||
o: Mat4;
|
||||
|
||||
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3]
|
||||
sf01 := m[2][1] * m[3][3] - m[3][1] * m[2][3]
|
||||
sf02 := m[2][1] * m[3][2] - m[3][1] * m[2][2]
|
||||
sf03 := m[2][0] * m[3][3] - m[3][0] * m[2][3]
|
||||
sf04 := m[2][0] * m[3][2] - m[3][0] * m[2][2]
|
||||
sf05 := m[2][0] * m[3][1] - m[3][0] * m[2][1]
|
||||
sf06 := m[1][2] * m[3][3] - m[3][2] * m[1][3]
|
||||
sf07 := m[1][1] * m[3][3] - m[3][1] * m[1][3]
|
||||
sf08 := m[1][1] * m[3][2] - m[3][1] * m[1][2]
|
||||
sf09 := m[1][0] * m[3][3] - m[3][0] * m[1][3]
|
||||
sf10 := m[1][0] * m[3][2] - m[3][0] * m[1][2]
|
||||
sf11 := m[1][1] * m[3][3] - m[3][1] * m[1][3]
|
||||
sf12 := m[1][0] * m[3][1] - m[3][0] * m[1][1]
|
||||
sf13 := m[1][2] * m[2][3] - m[2][2] * m[1][3]
|
||||
sf14 := m[1][1] * m[2][3] - m[2][1] * m[1][3]
|
||||
sf15 := m[1][1] * m[2][2] - m[2][1] * m[1][2]
|
||||
sf16 := m[1][0] * m[2][3] - m[2][0] * m[1][3]
|
||||
sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2]
|
||||
sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1]
|
||||
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
|
||||
sf01 := m[2][1] * m[3][3] - m[3][1] * m[2][3];
|
||||
sf02 := m[2][1] * m[3][2] - m[3][1] * m[2][2];
|
||||
sf03 := m[2][0] * m[3][3] - m[3][0] * m[2][3];
|
||||
sf04 := m[2][0] * m[3][2] - m[3][0] * m[2][2];
|
||||
sf05 := m[2][0] * m[3][1] - m[3][0] * m[2][1];
|
||||
sf06 := m[1][2] * m[3][3] - m[3][2] * m[1][3];
|
||||
sf07 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
|
||||
sf08 := m[1][1] * m[3][2] - m[3][1] * m[1][2];
|
||||
sf09 := m[1][0] * m[3][3] - m[3][0] * m[1][3];
|
||||
sf10 := m[1][0] * m[3][2] - m[3][0] * m[1][2];
|
||||
sf11 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
|
||||
sf12 := m[1][0] * m[3][1] - m[3][0] * m[1][1];
|
||||
sf13 := m[1][2] * m[2][3] - m[2][2] * m[1][3];
|
||||
sf14 := m[1][1] * m[2][3] - m[2][1] * m[1][3];
|
||||
sf15 := m[1][1] * m[2][2] - m[2][1] * m[1][2];
|
||||
sf16 := m[1][0] * m[2][3] - m[2][0] * m[1][3];
|
||||
sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2];
|
||||
sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1];
|
||||
|
||||
o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02)
|
||||
o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04)
|
||||
o[0][2] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05)
|
||||
o[0][3] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05)
|
||||
o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02);
|
||||
o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04);
|
||||
o[0][2] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05);
|
||||
o[0][3] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05);
|
||||
|
||||
o[1][0] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02)
|
||||
o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04)
|
||||
o[1][2] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05)
|
||||
o[1][3] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05)
|
||||
o[1][0] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02);
|
||||
o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04);
|
||||
o[1][2] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05);
|
||||
o[1][3] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05);
|
||||
|
||||
o[2][0] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08)
|
||||
o[2][1] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10)
|
||||
o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12)
|
||||
o[2][3] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12)
|
||||
o[2][0] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08);
|
||||
o[2][1] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10);
|
||||
o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12);
|
||||
o[2][3] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12);
|
||||
|
||||
o[3][0] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15)
|
||||
o[3][1] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17)
|
||||
o[3][2] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18)
|
||||
o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18)
|
||||
o[3][0] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15);
|
||||
o[3][1] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17);
|
||||
o[3][2] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18);
|
||||
o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18);
|
||||
|
||||
ood := 1.0 / (m[0][0] * o[0][0] +
|
||||
m[0][1] * o[0][1] +
|
||||
m[0][2] * o[0][2] +
|
||||
m[0][3] * o[0][3])
|
||||
m[0][3] * o[0][3]);
|
||||
|
||||
o[0][0] *= ood
|
||||
o[0][1] *= ood
|
||||
o[0][2] *= ood
|
||||
o[0][3] *= ood
|
||||
o[1][0] *= ood
|
||||
o[1][1] *= ood
|
||||
o[1][2] *= ood
|
||||
o[1][3] *= ood
|
||||
o[2][0] *= ood
|
||||
o[2][1] *= ood
|
||||
o[2][2] *= ood
|
||||
o[2][3] *= ood
|
||||
o[3][0] *= ood
|
||||
o[3][1] *= ood
|
||||
o[3][2] *= ood
|
||||
o[3][3] *= ood
|
||||
o[0][0] *= ood;
|
||||
o[0][1] *= ood;
|
||||
o[0][2] *= ood;
|
||||
o[0][3] *= ood;
|
||||
o[1][0] *= ood;
|
||||
o[1][1] *= ood;
|
||||
o[1][2] *= ood;
|
||||
o[1][3] *= ood;
|
||||
o[2][0] *= ood;
|
||||
o[2][1] *= ood;
|
||||
o[2][2] *= ood;
|
||||
o[2][3] *= ood;
|
||||
o[3][0] *= ood;
|
||||
o[3][1] *= ood;
|
||||
o[3][2] *= ood;
|
||||
o[3][3] *= ood;
|
||||
|
||||
return o
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
mat4_translate :: proc(v: Vec3) -> Mat4 {
|
||||
m := mat4_identity()
|
||||
m[3][0] = v.x
|
||||
m[3][1] = v.y
|
||||
m[3][2] = v.z
|
||||
m[3][3] = 1
|
||||
return m
|
||||
m := mat4_identity();
|
||||
m[3][0] = v.x;
|
||||
m[3][1] = v.y;
|
||||
m[3][2] = v.z;
|
||||
m[3][3] = 1;
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
||||
c := cos32(angle_radians)
|
||||
s := sin32(angle_radians)
|
||||
c := cos32(angle_radians);
|
||||
s := sin32(angle_radians);
|
||||
|
||||
a := vec3_norm(v)
|
||||
t := a * Vec3{1-c}
|
||||
a := vec3_norm(v);
|
||||
t := a * Vec3{1-c};
|
||||
|
||||
rot := mat4_identity()
|
||||
rot := mat4_identity();
|
||||
|
||||
rot[0][0] = c + t.x*a.x
|
||||
rot[0][1] = 0 + t.x*a.y + s*a.z
|
||||
rot[0][2] = 0 + t.x*a.z - s*a.y
|
||||
rot[0][3] = 0
|
||||
rot[0][0] = c + t.x*a.x;
|
||||
rot[0][1] = 0 + t.x*a.y + s*a.z;
|
||||
rot[0][2] = 0 + t.x*a.z - s*a.y;
|
||||
rot[0][3] = 0;
|
||||
|
||||
rot[1][0] = 0 + t.y*a.x - s*a.z
|
||||
rot[1][1] = c + t.y*a.y
|
||||
rot[1][2] = 0 + t.y*a.z + s*a.x
|
||||
rot[1][3] = 0
|
||||
rot[1][0] = 0 + t.y*a.x - s*a.z;
|
||||
rot[1][1] = c + t.y*a.y;
|
||||
rot[1][2] = 0 + t.y*a.z + s*a.x;
|
||||
rot[1][3] = 0;
|
||||
|
||||
rot[2][0] = 0 + t.z*a.x + s*a.y
|
||||
rot[2][1] = 0 + t.z*a.y - s*a.x
|
||||
rot[2][2] = c + t.z*a.z
|
||||
rot[2][3] = 0
|
||||
rot[2][0] = 0 + t.z*a.x + s*a.y;
|
||||
rot[2][1] = 0 + t.z*a.y - s*a.x;
|
||||
rot[2][2] = c + t.z*a.z;
|
||||
rot[2][3] = 0;
|
||||
|
||||
return rot
|
||||
return rot;
|
||||
}
|
||||
|
||||
mat4_scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
||||
m[0][0] = v.x
|
||||
m[1][1] = v.y
|
||||
m[2][2] = v.z
|
||||
return m
|
||||
m[0][0] *= v.x;
|
||||
m[1][1] *= v.y;
|
||||
m[2][2] *= v.z;
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4_scalef :: proc(m: Mat4, s: f32) -> Mat4 {
|
||||
m[0][0] = s
|
||||
m[1][1] = s
|
||||
m[2][2] = s
|
||||
return m
|
||||
m[0][0] *= s;
|
||||
m[1][1] *= s;
|
||||
m[2][2] *= s;
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
mat4_look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
||||
f := vec3_norm(centre - eye)
|
||||
s := vec3_norm(cross3(f, up))
|
||||
u := cross3(s, f)
|
||||
f := vec3_norm(centre - eye);
|
||||
s := vec3_norm(cross3(f, up));
|
||||
u := cross3(s, f);
|
||||
|
||||
m: Mat4
|
||||
m: Mat4;
|
||||
|
||||
m[0] = Vec4{+s.x, +s.y, +s.z, 0}
|
||||
m[1] = Vec4{+u.x, +u.y, +u.z, 0}
|
||||
m[2] = Vec4{-f.x, -f.y, -f.z, 0}
|
||||
m[3] = Vec4{dot3(s, eye), dot3(u, eye), dot3(f, eye), 1}
|
||||
m[0] = Vec4{+s.x, +s.y, +s.z, 0};
|
||||
m[1] = Vec4{+u.x, +u.y, +u.z, 0};
|
||||
m[2] = Vec4{-f.x, -f.y, -f.z, 0};
|
||||
m[3] = Vec4{dot3(s, eye), dot3(u, eye), dot3(f, eye), 1};
|
||||
|
||||
return m
|
||||
return m;
|
||||
}
|
||||
mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
|
||||
m: Mat4
|
||||
tan_half_fovy := tan32(0.5 * fovy)
|
||||
m[0][0] = 1.0 / (aspect*tan_half_fovy)
|
||||
m[1][1] = 1.0 / (tan_half_fovy)
|
||||
m[2][2] = -(far + near) / (far - near)
|
||||
m[2][3] = -1.0
|
||||
m[3][2] = -2.0*far*near / (far - near)
|
||||
return m
|
||||
m: Mat4;
|
||||
tan_half_fovy := tan32(0.5 * fovy);
|
||||
m[0][0] = 1.0 / (aspect*tan_half_fovy);
|
||||
m[1][1] = 1.0 / (tan_half_fovy);
|
||||
m[2][2] = -(far + near) / (far - near);
|
||||
m[2][3] = -1.0;
|
||||
m[3][2] = -2.0*far*near / (far - near);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
mat4_ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
|
||||
m := mat4_identity()
|
||||
|
||||
m[0][0] = +2.0 / (right - left)
|
||||
m[1][1] = +2.0 / (top - bottom)
|
||||
m[2][2] = -2.0 / (far - near)
|
||||
m[3][0] = -(right + left) / (right - left)
|
||||
m[3][1] = -(top + bottom) / (top - bottom)
|
||||
m[3][2] = -(far + near) / (far - near)
|
||||
|
||||
return m
|
||||
m := mat4_identity();
|
||||
m[0][0] = +2.0 / (right - left);
|
||||
m[1][1] = +2.0 / (top - bottom);
|
||||
m[2][2] = -2.0 / (far - near);
|
||||
m[3][0] = -(right + left) / (right - left);
|
||||
m[3][1] = -(top + bottom) / (top - bottom);
|
||||
m[3][2] = -(far + near) / (far - near);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
F32_DIG :: 6
|
||||
F32_EPSILON :: 1.192092896e-07
|
||||
F32_GUARD :: 0
|
||||
F32_MANT_DIG :: 24
|
||||
F32_MAX :: 3.402823466e+38
|
||||
F32_MAX_10_EXP :: 38
|
||||
F32_MAX_EXP :: 128
|
||||
F32_MIN :: 1.175494351e-38
|
||||
F32_MIN_10_EXP :: -37
|
||||
F32_MIN_EXP :: -125
|
||||
F32_NORMALIZE :: 0
|
||||
F32_RADIX :: 2
|
||||
F32_ROUNDS :: 1
|
||||
F32_DIG :: 6;
|
||||
F32_EPSILON :: 1.192092896e-07;
|
||||
F32_GUARD :: 0;
|
||||
F32_MANT_DIG :: 24;
|
||||
F32_MAX :: 3.402823466e+38;
|
||||
F32_MAX_10_EXP :: 38;
|
||||
F32_MAX_EXP :: 128;
|
||||
F32_MIN :: 1.175494351e-38;
|
||||
F32_MIN_10_EXP :: -37;
|
||||
F32_MIN_EXP :: -125;
|
||||
F32_NORMALIZE :: 0;
|
||||
F32_RADIX :: 2;
|
||||
F32_ROUNDS :: 1;
|
||||
|
||||
F64_DIG :: 15 // # of decimal digits of precision
|
||||
F64_EPSILON :: 2.2204460492503131e-016 // smallest such that 1.0+F64_EPSILON != 1.0
|
||||
F64_MANT_DIG :: 53 // # of bits in mantissa
|
||||
F64_MAX :: 1.7976931348623158e+308 // max value
|
||||
F64_MAX_10_EXP :: 308 // max decimal exponent
|
||||
F64_MAX_EXP :: 1024 // max binary exponent
|
||||
F64_MIN :: 2.2250738585072014e-308 // min positive value
|
||||
F64_MIN_10_EXP :: -307 // min decimal exponent
|
||||
F64_MIN_EXP :: -1021 // min binary exponent
|
||||
F64_RADIX :: 2 // exponent radix
|
||||
F64_ROUNDS :: 1 // addition rounding: near
|
||||
F64_DIG :: 15; // # of decimal digits of precision
|
||||
F64_EPSILON :: 2.2204460492503131e-016; // smallest such that 1.0+F64_EPSILON != 1.0
|
||||
F64_MANT_DIG :: 53; // # of bits in mantissa
|
||||
F64_MAX :: 1.7976931348623158e+308; // max value
|
||||
F64_MAX_10_EXP :: 308; // max decimal exponent
|
||||
F64_MAX_EXP :: 1024; // max binary exponent
|
||||
F64_MIN :: 2.2250738585072014e-308; // min positive value
|
||||
F64_MIN_10_EXP :: -307; // min decimal exponent
|
||||
F64_MIN_EXP :: -1021; // min binary exponent
|
||||
F64_RADIX :: 2; // exponent radix
|
||||
F64_ROUNDS :: 1; // addition rounding: near
|
||||
|
||||
|
||||
|
||||
|
||||
280
core/mem.odin
280
core/mem.odin
@@ -1,51 +1,51 @@
|
||||
#import "fmt.odin"
|
||||
#import "os.odin"
|
||||
#import "fmt.odin";
|
||||
#import "os.odin";
|
||||
|
||||
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
|
||||
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
|
||||
llvm_memset_64bit(data, value as byte, len, 1, false)
|
||||
return data
|
||||
llvm_memset_64bit(data, value as byte, len, 1, false);
|
||||
return data;
|
||||
}
|
||||
|
||||
zero :: proc(data: rawptr, len: int) -> rawptr {
|
||||
return set(data, 0, len)
|
||||
zero :: proc(data: rawptr, len: int) -> rawptr #link_name "__mem_zero" {
|
||||
return set(data, 0, len);
|
||||
}
|
||||
|
||||
copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
|
||||
// NOTE(bill): This _must_ implemented like C's memmove
|
||||
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
|
||||
llvm_memmove_64bit(dst, src, len, 1, false)
|
||||
return dst
|
||||
llvm_memmove_64bit(dst, src, len, 1, false);
|
||||
return dst;
|
||||
}
|
||||
|
||||
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
|
||||
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)
|
||||
return dst
|
||||
llvm_memcpy_64bit(dst, src, len, 1, false);
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
|
||||
// Translation of http://mgronhol.github.io/fast-strcmp/
|
||||
a := slice_ptr(dst as ^byte, n)
|
||||
b := slice_ptr(src as ^byte, n)
|
||||
a := slice_ptr(dst as ^byte, n);
|
||||
b := slice_ptr(src as ^byte, n);
|
||||
|
||||
fast := n/size_of(int) + 1
|
||||
offset := (fast-1)*size_of(int)
|
||||
curr_block := 0
|
||||
fast := n/size_of(int) + 1;
|
||||
offset := (fast-1)*size_of(int);
|
||||
curr_block := 0;
|
||||
if n <= size_of(int) {
|
||||
fast = 0
|
||||
fast = 0;
|
||||
}
|
||||
|
||||
la := slice_ptr(^a[0] as ^int, fast)
|
||||
lb := slice_ptr(^b[0] as ^int, fast)
|
||||
la := slice_ptr(^a[0] as ^int, fast);
|
||||
lb := slice_ptr(^b[0] as ^int, fast);
|
||||
|
||||
for ; curr_block < fast; curr_block++ {
|
||||
if (la[curr_block] ~ lb[curr_block]) != 0 {
|
||||
for pos := curr_block*size_of(int); pos < n; pos++ {
|
||||
if (a[pos] ~ b[pos]) != 0 {
|
||||
return a[pos] as int - b[pos] as int
|
||||
return a[pos] as int - b[pos] as int;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,11 +54,11 @@ compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
|
||||
|
||||
for ; offset < n; offset++ {
|
||||
if (a[offset] ~ b[offset]) != 0 {
|
||||
return a[offset] as int - b[offset] as int
|
||||
return a[offset] as int - b[offset] as int;
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,42 +70,42 @@ terabytes :: proc(x: int) -> int #inline { return terabytes(x) * 1024; }
|
||||
|
||||
is_power_of_two :: proc(x: int) -> bool {
|
||||
if x <= 0 {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
return (x & (x-1)) == 0
|
||||
return (x & (x-1)) == 0;
|
||||
}
|
||||
|
||||
align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
|
||||
assert(is_power_of_two(align))
|
||||
assert(is_power_of_two(align));
|
||||
|
||||
a := align as uint
|
||||
p := ptr as uint
|
||||
modulo := p & (a-1)
|
||||
a := align as uint;
|
||||
p := ptr as uint;
|
||||
modulo := p & (a-1);
|
||||
if modulo != 0 {
|
||||
p += a - modulo
|
||||
p += a - modulo;
|
||||
}
|
||||
return p as rawptr
|
||||
return p as rawptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AllocationHeader :: struct {
|
||||
size: int
|
||||
size: int;
|
||||
}
|
||||
allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: int) {
|
||||
header.size = size
|
||||
ptr := (header+1) as ^int
|
||||
header.size = size;
|
||||
ptr := (header+1) as ^int;
|
||||
|
||||
for i := 0; ptr as rawptr < data; i++ {
|
||||
(ptr+i)^ = -1
|
||||
(ptr+i)^ = -1;
|
||||
}
|
||||
}
|
||||
allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
|
||||
p := data as ^int
|
||||
p := data as ^int;
|
||||
for (p-1)^ == -1 {
|
||||
p = (p-1)
|
||||
p = (p-1);
|
||||
}
|
||||
return (p as ^AllocationHeader)-1
|
||||
return (p as ^AllocationHeader)-1;
|
||||
}
|
||||
|
||||
|
||||
@@ -115,14 +115,14 @@ allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
|
||||
// Custom allocators
|
||||
|
||||
Arena :: struct {
|
||||
backing: Allocator
|
||||
memory: []byte
|
||||
temp_count: int
|
||||
backing: Allocator;
|
||||
memory: []byte;
|
||||
temp_count: int;
|
||||
}
|
||||
|
||||
Temp_Memory :: struct {
|
||||
arena: ^Arena
|
||||
original_count: int
|
||||
}
|
||||
Arena_Temp_Memory :: struct {
|
||||
arena: ^Arena;
|
||||
original_count: int;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,22 +130,22 @@ Arena :: struct {
|
||||
|
||||
|
||||
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
|
||||
backing = Allocator{}
|
||||
memory = data[:0]
|
||||
temp_count = 0
|
||||
backing = Allocator{};
|
||||
memory = data[:0];
|
||||
temp_count = 0;
|
||||
}
|
||||
|
||||
init_arena_from_context :: proc(using a: ^Arena, size: int) {
|
||||
backing = context.allocator
|
||||
memory = new_slice(byte, 0, size)
|
||||
temp_count = 0
|
||||
backing = context.allocator;
|
||||
memory = new_slice(byte, 0, size);
|
||||
temp_count = 0;
|
||||
}
|
||||
|
||||
free_arena :: proc(using a: ^Arena) {
|
||||
if backing.procedure != nil {
|
||||
push_allocator backing {
|
||||
free(memory.data)
|
||||
memory = memory[0:0:0]
|
||||
free(memory.data);
|
||||
memory = memory[0:0:0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,57 +154,57 @@ arena_allocator :: proc(arena: ^Arena) -> Allocator {
|
||||
return Allocator{
|
||||
procedure = arena_allocator_proc,
|
||||
data = arena,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
||||
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||
arena := allocator_data as ^Arena
|
||||
arena := allocator_data as ^Arena;
|
||||
|
||||
using Allocator.Mode
|
||||
using Allocator_Mode;
|
||||
match mode {
|
||||
case ALLOC:
|
||||
total_size := size + alignment
|
||||
total_size := size + alignment;
|
||||
|
||||
if arena.memory.count + total_size > arena.memory.capacity {
|
||||
fmt.fprintln(os.stderr, "Arena out of memory")
|
||||
return nil
|
||||
fmt.fprintln(os.stderr, "Arena out of memory");
|
||||
return nil;
|
||||
}
|
||||
|
||||
#no_bounds_check end := ^arena.memory[arena.memory.count]
|
||||
#no_bounds_check end := ^arena.memory[arena.memory.count];
|
||||
|
||||
ptr := align_forward(end, alignment)
|
||||
arena.memory.count += total_size
|
||||
return zero(ptr, size)
|
||||
ptr := align_forward(end, alignment);
|
||||
arena.memory.count += total_size;
|
||||
return zero(ptr, size);
|
||||
|
||||
case FREE:
|
||||
// NOTE(bill): Free all at once
|
||||
// Use Arena.Temp_Memory if you want to free a block
|
||||
// Use Arena_Temp_Memory if you want to free a block
|
||||
|
||||
case FREE_ALL:
|
||||
arena.memory.count = 0
|
||||
arena.memory.count = 0;
|
||||
|
||||
case RESIZE:
|
||||
return default_resize_align(old_memory, old_size, size, alignment)
|
||||
return default_resize_align(old_memory, old_size, size, alignment);
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil;
|
||||
}
|
||||
|
||||
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena.Temp_Memory {
|
||||
tmp: Arena.Temp_Memory
|
||||
tmp.arena = a
|
||||
tmp.original_count = a.memory.count
|
||||
a.temp_count++
|
||||
return tmp
|
||||
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
|
||||
tmp: Arena_Temp_Memory;
|
||||
tmp.arena = a;
|
||||
tmp.original_count = a.memory.count;
|
||||
a.temp_count++;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
end_arena_temp_memory :: proc(using tmp: Arena.Temp_Memory) {
|
||||
assert(arena.memory.count >= original_count)
|
||||
assert(arena.temp_count > 0)
|
||||
arena.memory.count = original_count
|
||||
arena.temp_count--
|
||||
end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) {
|
||||
assert(arena.memory.count >= original_count);
|
||||
assert(arena.temp_count > 0);
|
||||
arena.memory.count = original_count;
|
||||
arena.temp_count--;
|
||||
}
|
||||
|
||||
|
||||
@@ -214,119 +214,135 @@ end_arena_temp_memory :: proc(using tmp: Arena.Temp_Memory) {
|
||||
|
||||
|
||||
align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||
WORD_SIZE :: size_of(int)
|
||||
using Type_Info
|
||||
prev_pow2 :: proc(n: i64) -> i64 {
|
||||
if n <= 0 {
|
||||
return 0;
|
||||
}
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n |= n >> 16;
|
||||
n |= n >> 32;
|
||||
return n - (n >> 1);
|
||||
}
|
||||
|
||||
WORD_SIZE :: size_of(int);
|
||||
MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
|
||||
using Type_Info;
|
||||
|
||||
match type info : type_info {
|
||||
case Named:
|
||||
return align_of_type_info(info.base)
|
||||
return align_of_type_info(info.base);
|
||||
case Integer:
|
||||
return info.size
|
||||
return info.size;
|
||||
case Float:
|
||||
return info.size
|
||||
return info.size;
|
||||
case String:
|
||||
return WORD_SIZE
|
||||
return WORD_SIZE;
|
||||
case Boolean:
|
||||
return 1
|
||||
return 1;
|
||||
case Pointer:
|
||||
return WORD_SIZE
|
||||
return WORD_SIZE;
|
||||
case Maybe:
|
||||
return max(align_of_type_info(info.elem), 1)
|
||||
return max(align_of_type_info(info.elem), 1);
|
||||
case Procedure:
|
||||
return WORD_SIZE
|
||||
return WORD_SIZE;
|
||||
case Array:
|
||||
return align_of_type_info(info.elem)
|
||||
return align_of_type_info(info.elem);
|
||||
case Slice:
|
||||
return WORD_SIZE
|
||||
return WORD_SIZE;
|
||||
case Vector:
|
||||
return align_of_type_info(info.elem)
|
||||
size := size_of_type_info(info.elem);
|
||||
count := max(prev_pow2(info.count as i64), 1) as int;
|
||||
total := size * count;
|
||||
return clamp(total, 1, MAX_ALIGN);
|
||||
case Struct:
|
||||
return info.align
|
||||
return info.align;
|
||||
case Union:
|
||||
return info.align
|
||||
return info.align;
|
||||
case Raw_Union:
|
||||
return info.align
|
||||
return info.align;
|
||||
case Enum:
|
||||
return align_of_type_info(info.base)
|
||||
return align_of_type_info(info.base);
|
||||
}
|
||||
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
align_formula :: proc(size, align: int) -> int {
|
||||
result := size + align-1
|
||||
return result - result%align
|
||||
}
|
||||
result := size + align-1;
|
||||
return result - result%align;
|
||||
};
|
||||
|
||||
size_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||
WORD_SIZE :: size_of(int)
|
||||
using Type_Info
|
||||
|
||||
WORD_SIZE :: size_of(int);
|
||||
using Type_Info;
|
||||
match type info : type_info {
|
||||
case Named:
|
||||
return size_of_type_info(info.base)
|
||||
return size_of_type_info(info.base);
|
||||
case Integer:
|
||||
return info.size
|
||||
return info.size;
|
||||
case Float:
|
||||
return info.size
|
||||
return info.size;
|
||||
case Any:
|
||||
return 2*WORD_SIZE
|
||||
return 2*WORD_SIZE;
|
||||
case String:
|
||||
return 2*WORD_SIZE
|
||||
return 2*WORD_SIZE;
|
||||
case Boolean:
|
||||
return 1
|
||||
return 1;
|
||||
case Pointer:
|
||||
return WORD_SIZE
|
||||
return WORD_SIZE;
|
||||
case Maybe:
|
||||
return size_of_type_info(info.elem) + 1
|
||||
return size_of_type_info(info.elem) + 1;
|
||||
case Procedure:
|
||||
return WORD_SIZE
|
||||
return WORD_SIZE;
|
||||
case Array:
|
||||
count := info.count
|
||||
count := info.count;
|
||||
if count == 0 {
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
size := size_of_type_info(info.elem)
|
||||
align := align_of_type_info(info.elem)
|
||||
alignment := align_formula(size, align)
|
||||
return alignment*(count-1) + size
|
||||
size := size_of_type_info(info.elem);
|
||||
align := align_of_type_info(info.elem);
|
||||
alignment := align_formula(size, align);
|
||||
return alignment*(count-1) + size;
|
||||
case Slice:
|
||||
return 3*WORD_SIZE
|
||||
return 3*WORD_SIZE;
|
||||
case Vector:
|
||||
is_bool :: proc(type_info: ^Type_Info) -> bool {
|
||||
match type info : type_info {
|
||||
case Named:
|
||||
return is_bool(info.base)
|
||||
return is_bool(info.base);
|
||||
case Boolean:
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
count := info.count
|
||||
count := info.count;
|
||||
if count == 0 {
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
bit_size := 8*size_of_type_info(info.elem)
|
||||
bit_size := 8*size_of_type_info(info.elem);
|
||||
if is_bool(info.elem) {
|
||||
// NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
|
||||
// Silly LLVM spec
|
||||
bit_size = 1
|
||||
bit_size = 1;
|
||||
}
|
||||
total_size_in_bits := bit_size * count
|
||||
total_size := (total_size_in_bits+7)/8
|
||||
return total_size
|
||||
total_size_in_bits := bit_size * count;
|
||||
total_size := (total_size_in_bits+7)/8;
|
||||
return total_size;
|
||||
|
||||
case Struct:
|
||||
return info.size
|
||||
return info.size;
|
||||
case Union:
|
||||
return info.size
|
||||
return info.size;
|
||||
case Raw_Union:
|
||||
return info.size
|
||||
return info.size;
|
||||
case Enum:
|
||||
return size_of_type_info(info.base)
|
||||
return size_of_type_info(info.base);
|
||||
}
|
||||
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
186
core/opengl.odin
186
core/opengl.odin
@@ -1,6 +1,6 @@
|
||||
#foreign_system_library "opengl32" when ODIN_OS == "windows"
|
||||
#import "win32.odin" when ODIN_OS == "windows"
|
||||
#include "opengl_constants.odin"
|
||||
#foreign_system_library "opengl32" when ODIN_OS == "windows";
|
||||
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
|
||||
#include "opengl_constants.odin";
|
||||
|
||||
Clear :: proc(mask: u32) #foreign "glClear"
|
||||
ClearColor :: proc(r, g, b, a: f32) #foreign "glClearColor"
|
||||
@@ -30,126 +30,126 @@ GetIntegerv :: proc(name: i32, v: ^i32) #foreign "glGetIntegerv"
|
||||
|
||||
|
||||
|
||||
_libgl := win32.LoadLibraryA(("opengl32.dll\x00" as string).data)
|
||||
_libgl := win32.LoadLibraryA(("opengl32.dll\x00" as string).data);
|
||||
|
||||
GetProcAddress :: proc(name: string) -> proc() {
|
||||
assert(name[name.count-1] == 0)
|
||||
res := win32.wglGetProcAddress(name.data)
|
||||
assert(name[name.count-1] == 0);
|
||||
res := win32.wglGetProcAddress(name.data);
|
||||
if res == nil {
|
||||
res = win32.GetProcAddress(_libgl, name.data)
|
||||
res = win32.GetProcAddress(_libgl, name.data);
|
||||
}
|
||||
return res
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
GenBuffers: proc(count: i32, buffers: ^u32)
|
||||
GenVertexArrays: proc(count: i32, buffers: ^u32)
|
||||
GenSamplers: proc(count: i32, buffers: ^u32)
|
||||
BindBuffer: proc(target: i32, buffer: u32)
|
||||
BindVertexArray: proc(buffer: u32)
|
||||
BindSampler: proc(position: i32, sampler: u32)
|
||||
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32)
|
||||
BufferSubData: proc(target: i32, offset, size: int, data: rawptr)
|
||||
GenBuffers: proc(count: i32, buffers: ^u32);
|
||||
GenVertexArrays: proc(count: i32, buffers: ^u32);
|
||||
GenSamplers: proc(count: i32, buffers: ^u32);
|
||||
BindBuffer: proc(target: i32, buffer: u32);
|
||||
BindVertexArray: proc(buffer: u32);
|
||||
BindSampler: proc(position: i32, sampler: u32);
|
||||
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32);
|
||||
BufferSubData: proc(target: i32, offset, size: int, data: rawptr);
|
||||
|
||||
DrawArrays: proc(mode, first: i32, count: u32)
|
||||
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr)
|
||||
DrawArrays: proc(mode, first: i32, count: u32);
|
||||
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr);
|
||||
|
||||
MapBuffer: proc(target, access: i32) -> rawptr
|
||||
UnmapBuffer: proc(target: i32)
|
||||
MapBuffer: proc(target, access: i32) -> rawptr;
|
||||
UnmapBuffer: proc(target: i32);
|
||||
|
||||
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr)
|
||||
EnableVertexAttribArray: proc(index: u32)
|
||||
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr);
|
||||
EnableVertexAttribArray: proc(index: u32);
|
||||
|
||||
CreateShader: proc(shader_type: i32) -> u32
|
||||
ShaderSource: proc(shader: u32, count: u32, string: ^^byte, length: ^i32)
|
||||
CompileShader: proc(shader: u32)
|
||||
CreateProgram: proc() -> u32
|
||||
AttachShader: proc(program, shader: u32)
|
||||
DetachShader: proc(program, shader: u32)
|
||||
DeleteShader: proc(shader: u32)
|
||||
LinkProgram: proc(program: u32)
|
||||
UseProgram: proc(program: u32)
|
||||
DeleteProgram: proc(program: u32)
|
||||
CreateShader: proc(shader_type: i32) -> u32;
|
||||
ShaderSource: proc(shader: u32, count: u32, string: ^^byte, length: ^i32);
|
||||
CompileShader: proc(shader: u32);
|
||||
CreateProgram: proc() -> u32;
|
||||
AttachShader: proc(program, shader: u32);
|
||||
DetachShader: proc(program, shader: u32);
|
||||
DeleteShader: proc(shader: u32);
|
||||
LinkProgram: proc(program: u32);
|
||||
UseProgram: proc(program: u32);
|
||||
DeleteProgram: proc(program: u32);
|
||||
|
||||
|
||||
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32)
|
||||
GetProgramiv: proc(program: u32, pname: i32, params: ^i32)
|
||||
GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^byte)
|
||||
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte)
|
||||
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32);
|
||||
GetProgramiv: proc(program: u32, pname: i32, params: ^i32);
|
||||
GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^byte);
|
||||
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte);
|
||||
|
||||
ActiveTexture: proc(texture: i32)
|
||||
GenerateMipmap: proc(target: i32)
|
||||
ActiveTexture: proc(texture: i32);
|
||||
GenerateMipmap: proc(target: i32);
|
||||
|
||||
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32)
|
||||
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32)
|
||||
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32)
|
||||
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32)
|
||||
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32)
|
||||
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32)
|
||||
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32);
|
||||
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32);
|
||||
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32);
|
||||
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32);
|
||||
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32);
|
||||
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32);
|
||||
|
||||
|
||||
Uniform1i: proc(loc: i32, v0: i32)
|
||||
Uniform2i: proc(loc: i32, v0, v1: i32)
|
||||
Uniform3i: proc(loc: i32, v0, v1, v2: i32)
|
||||
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32)
|
||||
Uniform1f: proc(loc: i32, v0: f32)
|
||||
Uniform2f: proc(loc: i32, v0, v1: f32)
|
||||
Uniform3f: proc(loc: i32, v0, v1, v2: f32)
|
||||
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32)
|
||||
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32)
|
||||
Uniform1i: proc(loc: i32, v0: i32);
|
||||
Uniform2i: proc(loc: i32, v0, v1: i32);
|
||||
Uniform3i: proc(loc: i32, v0, v1, v2: i32);
|
||||
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32);
|
||||
Uniform1f: proc(loc: i32, v0: f32);
|
||||
Uniform2f: proc(loc: i32, v0, v1: f32);
|
||||
Uniform3f: proc(loc: i32, v0, v1, v2: f32);
|
||||
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32);
|
||||
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32);
|
||||
|
||||
GetUniformLocation: proc(program: u32, name: ^byte) -> i32
|
||||
GetUniformLocation: proc(program: u32, name: ^byte) -> i32;
|
||||
|
||||
init :: proc() {
|
||||
set_proc_address :: proc(p: rawptr, name: string) #inline { (p as ^proc())^ = GetProcAddress(name); }
|
||||
|
||||
set_proc_address(^GenBuffers, "glGenBuffers\x00")
|
||||
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00")
|
||||
set_proc_address(^GenSamplers, "glGenSamplers\x00")
|
||||
set_proc_address(^BindBuffer, "glBindBuffer\x00")
|
||||
set_proc_address(^BindSampler, "glBindSampler\x00")
|
||||
set_proc_address(^BindVertexArray, "glBindVertexArray\x00")
|
||||
set_proc_address(^BufferData, "glBufferData\x00")
|
||||
set_proc_address(^BufferSubData, "glBufferSubData\x00")
|
||||
set_proc_address(^GenBuffers, "glGenBuffers\x00");
|
||||
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
|
||||
set_proc_address(^GenSamplers, "glGenSamplers\x00");
|
||||
set_proc_address(^BindBuffer, "glBindBuffer\x00");
|
||||
set_proc_address(^BindSampler, "glBindSampler\x00");
|
||||
set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
|
||||
set_proc_address(^BufferData, "glBufferData\x00");
|
||||
set_proc_address(^BufferSubData, "glBufferSubData\x00");
|
||||
|
||||
set_proc_address(^DrawArrays, "glDrawArrays\x00")
|
||||
set_proc_address(^DrawElements, "glDrawElements\x00")
|
||||
set_proc_address(^DrawArrays, "glDrawArrays\x00");
|
||||
set_proc_address(^DrawElements, "glDrawElements\x00");
|
||||
|
||||
set_proc_address(^MapBuffer, "glMapBuffer\x00")
|
||||
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00")
|
||||
set_proc_address(^MapBuffer, "glMapBuffer\x00");
|
||||
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00");
|
||||
|
||||
set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00")
|
||||
set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00")
|
||||
set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00");
|
||||
set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00");
|
||||
|
||||
set_proc_address(^CreateShader, "glCreateShader\x00")
|
||||
set_proc_address(^ShaderSource, "glShaderSource\x00")
|
||||
set_proc_address(^CompileShader, "glCompileShader\x00")
|
||||
set_proc_address(^CreateProgram, "glCreateProgram\x00")
|
||||
set_proc_address(^AttachShader, "glAttachShader\x00")
|
||||
set_proc_address(^DetachShader, "glDetachShader\x00")
|
||||
set_proc_address(^DeleteShader, "glDeleteShader\x00")
|
||||
set_proc_address(^LinkProgram, "glLinkProgram\x00")
|
||||
set_proc_address(^UseProgram, "glUseProgram\x00")
|
||||
set_proc_address(^DeleteProgram, "glDeleteProgram\x00")
|
||||
set_proc_address(^CreateShader, "glCreateShader\x00");
|
||||
set_proc_address(^ShaderSource, "glShaderSource\x00");
|
||||
set_proc_address(^CompileShader, "glCompileShader\x00");
|
||||
set_proc_address(^CreateProgram, "glCreateProgram\x00");
|
||||
set_proc_address(^AttachShader, "glAttachShader\x00");
|
||||
set_proc_address(^DetachShader, "glDetachShader\x00");
|
||||
set_proc_address(^DeleteShader, "glDeleteShader\x00");
|
||||
set_proc_address(^LinkProgram, "glLinkProgram\x00");
|
||||
set_proc_address(^UseProgram, "glUseProgram\x00");
|
||||
set_proc_address(^DeleteProgram, "glDeleteProgram\x00");
|
||||
|
||||
set_proc_address(^GetShaderiv, "glGetShaderiv\x00")
|
||||
set_proc_address(^GetProgramiv, "glGetProgramiv\x00")
|
||||
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00")
|
||||
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00")
|
||||
set_proc_address(^GetShaderiv, "glGetShaderiv\x00");
|
||||
set_proc_address(^GetProgramiv, "glGetProgramiv\x00");
|
||||
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00");
|
||||
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00");
|
||||
|
||||
set_proc_address(^ActiveTexture, "glActiveTexture\x00")
|
||||
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00")
|
||||
set_proc_address(^ActiveTexture, "glActiveTexture\x00");
|
||||
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00");
|
||||
|
||||
set_proc_address(^Uniform1i, "glUniform1i\x00")
|
||||
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00")
|
||||
set_proc_address(^Uniform1i, "glUniform1i\x00");
|
||||
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00");
|
||||
|
||||
set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00")
|
||||
set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00");
|
||||
|
||||
set_proc_address(^SamplerParameteri, "glSamplerParameteri\x00")
|
||||
set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00")
|
||||
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00")
|
||||
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00")
|
||||
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00")
|
||||
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00")
|
||||
set_proc_address(^SamplerParameteri, "glSamplerParameteri\x00");
|
||||
set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00");
|
||||
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00");
|
||||
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00");
|
||||
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00");
|
||||
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,83 +1,84 @@
|
||||
#import "win32.odin"
|
||||
#import "fmt.odin"
|
||||
#import win32 "sys/windows.odin";
|
||||
#import "fmt.odin";
|
||||
|
||||
File_Time :: type u64
|
||||
File_Time :: type u64;
|
||||
|
||||
File_Handle :: raw_union {
|
||||
p: rawptr;
|
||||
i: int;
|
||||
}
|
||||
|
||||
File :: struct {
|
||||
Handle :: raw_union {
|
||||
p: rawptr
|
||||
i: int
|
||||
}
|
||||
handle: Handle
|
||||
last_write_time: File_Time
|
||||
handle: File_Handle;
|
||||
last_write_time: File_Time;
|
||||
}
|
||||
|
||||
open :: proc(name: string) -> (File, bool) {
|
||||
using win32
|
||||
buf: [300]byte
|
||||
copy(buf[:], name as []byte)
|
||||
f: File
|
||||
f.handle.p = CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, nil) as rawptr
|
||||
success := f.handle.p != INVALID_HANDLE_VALUE
|
||||
f.last_write_time = last_write_time(^f)
|
||||
return f, success
|
||||
using win32;
|
||||
buf: [300]byte;
|
||||
copy(buf[:], name as []byte);
|
||||
f: File;
|
||||
f.handle.p = CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, nil) as rawptr;
|
||||
success := f.handle.p != INVALID_HANDLE_VALUE;
|
||||
f.last_write_time = last_write_time(^f);
|
||||
return f, success;
|
||||
}
|
||||
|
||||
create :: proc(name: string) -> (File, bool) {
|
||||
using win32
|
||||
buf: [300]byte
|
||||
copy(buf[:], name as []byte)
|
||||
f: File
|
||||
f.handle.p = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_ALWAYS, 0, nil) as rawptr
|
||||
success := f.handle.p != INVALID_HANDLE_VALUE
|
||||
f.last_write_time = last_write_time(^f)
|
||||
return f, success
|
||||
using win32;
|
||||
buf: [300]byte;
|
||||
copy(buf[:], name as []byte);
|
||||
f: File;
|
||||
f.handle.p = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_ALWAYS, 0, nil) as rawptr;
|
||||
success := f.handle.p != INVALID_HANDLE_VALUE;
|
||||
f.last_write_time = last_write_time(^f);
|
||||
return f, success;
|
||||
}
|
||||
|
||||
close :: proc(using f: ^File) {
|
||||
win32.CloseHandle(handle.p as win32.HANDLE)
|
||||
win32.CloseHandle(handle.p as win32.HANDLE);
|
||||
}
|
||||
|
||||
write :: proc(using f: ^File, buf: []byte) -> bool {
|
||||
bytes_written: i32
|
||||
return win32.WriteFile(handle.p as win32.HANDLE, buf.data, buf.count as i32, ^bytes_written, nil) != 0
|
||||
bytes_written: i32;
|
||||
return win32.WriteFile(handle.p as win32.HANDLE, buf.data, buf.count as i32, ^bytes_written, nil) != 0;
|
||||
}
|
||||
|
||||
file_has_changed :: proc(f: ^File) -> bool {
|
||||
last_write_time := last_write_time(f)
|
||||
last_write_time := last_write_time(f);
|
||||
if f.last_write_time != last_write_time {
|
||||
f.last_write_time = last_write_time
|
||||
return true
|
||||
f.last_write_time = last_write_time;
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
last_write_time :: proc(f: ^File) -> File_Time {
|
||||
file_info: win32.BY_HANDLE_FILE_INFORMATION
|
||||
win32.GetFileInformationByHandle(f.handle.p as win32.HANDLE, ^file_info)
|
||||
l := file_info.last_write_time.low_date_time as File_Time
|
||||
h := file_info.last_write_time.high_date_time as File_Time
|
||||
return l | h << 32
|
||||
file_info: win32.BY_HANDLE_FILE_INFORMATION;
|
||||
win32.GetFileInformationByHandle(f.handle.p as win32.HANDLE, ^file_info);
|
||||
l := file_info.last_write_time.low_date_time as File_Time;
|
||||
h := file_info.last_write_time.high_date_time as File_Time;
|
||||
return l | h << 32;
|
||||
}
|
||||
|
||||
last_write_time_by_name :: proc(name: string) -> File_Time {
|
||||
last_write_time: win32.FILETIME
|
||||
data: win32.WIN32_FILE_ATTRIBUTE_DATA
|
||||
buf: [1024]byte
|
||||
last_write_time: win32.FILETIME;
|
||||
data: win32.WIN32_FILE_ATTRIBUTE_DATA;
|
||||
buf: [1024]byte;
|
||||
|
||||
assert(buf.count > name.count)
|
||||
assert(buf.count > name.count);
|
||||
|
||||
copy(buf[:], name as []byte)
|
||||
copy(buf[:], name as []byte);
|
||||
|
||||
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
|
||||
last_write_time = data.last_write_time
|
||||
last_write_time = data.last_write_time;
|
||||
}
|
||||
|
||||
l := last_write_time.low_date_time as File_Time
|
||||
h := last_write_time.high_date_time as File_Time
|
||||
return l | h << 32
|
||||
l := last_write_time.low_date_time as File_Time;
|
||||
h := last_write_time.high_date_time as File_Time;
|
||||
return l | h << 32;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,84 +92,84 @@ File_Standard :: enum {
|
||||
|
||||
// NOTE(bill): Uses startup to initialize it
|
||||
__std_files := [File_Standard.count]File{
|
||||
{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE) transmute File.Handle },
|
||||
{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE) transmute File.Handle },
|
||||
{handle = win32.GetStdHandle(win32.STD_ERROR_HANDLE) transmute File.Handle },
|
||||
}
|
||||
{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE) transmute File_Handle },
|
||||
{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE) transmute File_Handle },
|
||||
{handle = win32.GetStdHandle(win32.STD_ERROR_HANDLE) transmute File_Handle },
|
||||
};
|
||||
|
||||
stdin := ^__std_files[File_Standard.INPUT]
|
||||
stdout := ^__std_files[File_Standard.OUTPUT]
|
||||
stderr := ^__std_files[File_Standard.ERROR]
|
||||
stdin := ^__std_files[File_Standard.INPUT];
|
||||
stdout := ^__std_files[File_Standard.OUTPUT];
|
||||
stderr := ^__std_files[File_Standard.ERROR];
|
||||
|
||||
|
||||
|
||||
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||
buf: [300]byte
|
||||
copy(buf[:], name as []byte)
|
||||
buf: [300]byte;
|
||||
copy(buf[:], name as []byte);
|
||||
|
||||
f, file_ok := open(name)
|
||||
f, file_ok := open(name);
|
||||
if !file_ok {
|
||||
return nil, false
|
||||
return nil, false;
|
||||
}
|
||||
defer close(^f)
|
||||
defer close(^f);
|
||||
|
||||
length: i64
|
||||
file_size_ok := win32.GetFileSizeEx(f.handle.p as win32.HANDLE, ^length) != 0
|
||||
length: i64;
|
||||
file_size_ok := win32.GetFileSizeEx(f.handle.p as win32.HANDLE, ^length) != 0;
|
||||
if !file_size_ok {
|
||||
return nil, false
|
||||
return nil, false;
|
||||
}
|
||||
|
||||
data := new_slice(u8, length)
|
||||
data := new_slice(u8, length);
|
||||
if data.data == nil {
|
||||
return nil, false
|
||||
return nil, false;
|
||||
}
|
||||
|
||||
single_read_length: i32
|
||||
total_read: i64
|
||||
single_read_length: i32;
|
||||
total_read: i64;
|
||||
|
||||
for total_read < length {
|
||||
remaining := length - total_read
|
||||
to_read: u32
|
||||
MAX :: 1<<32-1
|
||||
remaining := length - total_read;
|
||||
to_read: u32;
|
||||
MAX :: 1<<32-1;
|
||||
if remaining <= MAX {
|
||||
to_read = remaining as u32
|
||||
to_read = remaining as u32;
|
||||
} else {
|
||||
to_read = MAX
|
||||
to_read = MAX;
|
||||
}
|
||||
|
||||
win32.ReadFile(f.handle.p as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, nil)
|
||||
win32.ReadFile(f.handle.p as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, nil);
|
||||
if single_read_length <= 0 {
|
||||
free(data.data)
|
||||
return nil, false
|
||||
free(data.data);
|
||||
return nil, false;
|
||||
}
|
||||
|
||||
total_read += single_read_length as i64
|
||||
total_read += single_read_length as i64;
|
||||
}
|
||||
|
||||
return data, true
|
||||
return data, true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
heap_alloc :: proc(size: int) -> rawptr {
|
||||
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size)
|
||||
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size);
|
||||
}
|
||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size)
|
||||
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
|
||||
}
|
||||
heap_free :: proc(ptr: rawptr) {
|
||||
win32.HeapFree(win32.GetProcessHeap(), 0, ptr)
|
||||
win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
|
||||
}
|
||||
|
||||
|
||||
exit :: proc(code: int) {
|
||||
win32.ExitProcess(code as u32)
|
||||
win32.ExitProcess(code as u32);
|
||||
}
|
||||
|
||||
|
||||
|
||||
current_thread_id :: proc() -> int {
|
||||
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
|
||||
return GetCurrentThreadId() as int
|
||||
return GetCurrentThreadId() as int;
|
||||
}
|
||||
|
||||
|
||||
188
core/utf8.odin
188
core/utf8.odin
@@ -1,18 +1,18 @@
|
||||
RUNE_ERROR :: '\ufffd'
|
||||
RUNE_SELF :: 0x80
|
||||
RUNE_BOM :: 0xfeff
|
||||
RUNE_EOF :: ~(0 as rune)
|
||||
MAX_RUNE :: '\U0010ffff'
|
||||
UTF_MAX :: 4
|
||||
RUNE_ERROR :: '\ufffd';
|
||||
RUNE_SELF :: 0x80;
|
||||
RUNE_BOM :: 0xfeff;
|
||||
RUNE_EOF :: ~(0 as rune);
|
||||
MAX_RUNE :: '\U0010ffff';
|
||||
UTF_MAX :: 4;
|
||||
|
||||
|
||||
SURROGATE_MIN :: 0xd800
|
||||
SURROGATE_MAX :: 0xdfff
|
||||
SURROGATE_MIN :: 0xd800;
|
||||
SURROGATE_MAX :: 0xdfff;
|
||||
|
||||
|
||||
Accept_Range :: struct {
|
||||
lo, hi: u8
|
||||
}
|
||||
lo, hi: u8;
|
||||
};
|
||||
|
||||
accept_ranges := [5]Accept_Range{
|
||||
{0x80, 0xbf},
|
||||
@@ -20,7 +20,7 @@ accept_ranges := [5]Accept_Range{
|
||||
{0x80, 0x9f},
|
||||
{0x90, 0xbf},
|
||||
{0x80, 0x8f},
|
||||
}
|
||||
};
|
||||
|
||||
accept_sizes := [256]byte{
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
||||
@@ -40,177 +40,177 @@ accept_sizes := [256]byte{
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
|
||||
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
|
||||
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
|
||||
}
|
||||
};
|
||||
|
||||
encode_rune :: proc(r_: rune) -> ([4]byte, int) {
|
||||
r := r_
|
||||
buf: [4]byte
|
||||
i := r as u32
|
||||
mask :: 0x3f as byte
|
||||
r := r_;
|
||||
buf: [4]byte;
|
||||
i := r as u32;
|
||||
mask :: 0x3f as byte;
|
||||
if i <= 1<<7-1 {
|
||||
buf[0] = r as byte
|
||||
return buf, 1
|
||||
buf[0] = r as byte;
|
||||
return buf, 1;
|
||||
}
|
||||
if i <= 1<<11-1 {
|
||||
buf[0] = 0xc0 | (r>>6) as byte
|
||||
buf[1] = 0x80 | (r) as byte & mask
|
||||
return buf, 2
|
||||
buf[0] = 0xc0 | (r>>6) as byte;
|
||||
buf[1] = 0x80 | (r) as byte & mask;
|
||||
return buf, 2;
|
||||
}
|
||||
|
||||
// Invalid or Surrogate range
|
||||
if i > 0x0010ffff ||
|
||||
(0xd800 <= i && i <= 0xdfff) {
|
||||
r = 0xfffd
|
||||
r = 0xfffd;
|
||||
}
|
||||
|
||||
if i <= 1<<16-1 {
|
||||
buf[0] = 0xe0 | (r>>12) as byte
|
||||
buf[1] = 0x80 | (r>>6) as byte & mask
|
||||
buf[2] = 0x80 | (r) as byte & mask
|
||||
return buf, 3
|
||||
buf[0] = 0xe0 | (r>>12) as byte;
|
||||
buf[1] = 0x80 | (r>>6) as byte & mask;
|
||||
buf[2] = 0x80 | (r) as byte & mask;
|
||||
return buf, 3;
|
||||
}
|
||||
|
||||
buf[0] = 0xf0 | (r>>18) as byte
|
||||
buf[1] = 0x80 | (r>>12) as byte & mask
|
||||
buf[2] = 0x80 | (r>>6) as byte & mask
|
||||
buf[3] = 0x80 | (r) as byte & mask
|
||||
return buf, 4
|
||||
buf[0] = 0xf0 | (r>>18) as byte;
|
||||
buf[1] = 0x80 | (r>>12) as byte & mask;
|
||||
buf[2] = 0x80 | (r>>6) as byte & mask;
|
||||
buf[3] = 0x80 | (r) as byte & mask;
|
||||
return buf, 4;
|
||||
}
|
||||
|
||||
decode_rune :: proc(s: string) -> (rune, int) {
|
||||
n := s.count
|
||||
n := s.count;
|
||||
if n < 1 {
|
||||
return RUNE_ERROR, 0
|
||||
return RUNE_ERROR, 0;
|
||||
}
|
||||
b0 := s[0]
|
||||
x := accept_sizes[b0]
|
||||
b0 := s[0];
|
||||
x := accept_sizes[b0];
|
||||
if x >= 0xf0 {
|
||||
mask := (x as rune << 31) >> 31; // all zeros or all ones
|
||||
return (b0 as rune) &~ mask | RUNE_ERROR&mask, 1
|
||||
return (b0 as rune) &~ mask | RUNE_ERROR&mask, 1;
|
||||
}
|
||||
size := x & 7
|
||||
ar := accept_ranges[x>>4]
|
||||
size := x & 7;
|
||||
ar := accept_ranges[x>>4];
|
||||
if n < size as int {
|
||||
return RUNE_ERROR, 1
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
b1 := s[1]
|
||||
b1 := s[1];
|
||||
if b1 < ar.lo || ar.hi < b1 {
|
||||
return RUNE_ERROR, 1
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
|
||||
MASK_X :: 0b00111111
|
||||
MASK_2 :: 0b00011111
|
||||
MASK_3 :: 0b00001111
|
||||
MASK_4 :: 0b00000111
|
||||
MASK_X :: 0b00111111;
|
||||
MASK_2 :: 0b00011111;
|
||||
MASK_3 :: 0b00001111;
|
||||
MASK_4 :: 0b00000111;
|
||||
|
||||
if size == 2 {
|
||||
return (b0&MASK_2) as rune <<6 | (b1&MASK_X) as rune, 2
|
||||
return (b0&MASK_2) as rune <<6 | (b1&MASK_X) as rune, 2;
|
||||
}
|
||||
b2 := s[2]
|
||||
b2 := s[2];
|
||||
if b2 < 0x80 || 0xbf < b2 {
|
||||
return RUNE_ERROR, 1
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
if size == 3 {
|
||||
return (b0&MASK_3) as rune <<12 | (b1&MASK_X) as rune <<6 | (b2&MASK_X) as rune, 3
|
||||
return (b0&MASK_3) as rune <<12 | (b1&MASK_X) as rune <<6 | (b2&MASK_X) as rune, 3;
|
||||
}
|
||||
b3 := s[3]
|
||||
b3 := s[3];
|
||||
if b3 < 0x80 || 0xbf < b3 {
|
||||
return RUNE_ERROR, 1
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
return (b0&MASK_4) as rune <<18 | (b1&MASK_X) as rune <<12 | (b3&MASK_X) as rune <<6 | (b3&MASK_X) as rune, 4
|
||||
return (b0&MASK_4) as rune <<18 | (b1&MASK_X) as rune <<12 | (b3&MASK_X) as rune <<6 | (b3&MASK_X) as rune, 4;
|
||||
|
||||
}
|
||||
|
||||
|
||||
valid_rune :: proc(r: rune) -> bool {
|
||||
if r < 0 {
|
||||
return false
|
||||
return false;
|
||||
} else if SURROGATE_MIN <= r && r <= SURROGATE_MAX {
|
||||
return false
|
||||
return false;
|
||||
} else if r > MAX_RUNE {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
valid_string :: proc(s: string) -> bool {
|
||||
n := s.count
|
||||
n := s.count;
|
||||
for i := 0; i < n; {
|
||||
si := s[i]
|
||||
si := s[i];
|
||||
if si < RUNE_SELF { // ascii
|
||||
i++
|
||||
continue
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
x := accept_sizes[si]
|
||||
x := accept_sizes[si];
|
||||
if x == 0xf1 {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
size := (x & 7) as int
|
||||
size := (x & 7) as int;
|
||||
if i+size > n {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
ar := accept_ranges[x>>4]
|
||||
ar := accept_ranges[x>>4];
|
||||
if b := s[i+1]; b < ar.lo || ar.hi < b {
|
||||
return false
|
||||
return false;
|
||||
} else if size == 2 {
|
||||
// Okay
|
||||
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
|
||||
return false
|
||||
return false;
|
||||
} else if size == 3 {
|
||||
// Okay
|
||||
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
i += size
|
||||
i += size;
|
||||
}
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
rune_count :: proc(s: string) -> int {
|
||||
count := 0
|
||||
n := s.count
|
||||
count := 0;
|
||||
n := s.count;
|
||||
for i := 0; i < n; count++ {
|
||||
si := s[i]
|
||||
si := s[i];
|
||||
if si < RUNE_SELF { // ascii
|
||||
i++
|
||||
continue
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
x := accept_sizes[si]
|
||||
x := accept_sizes[si];
|
||||
if x == 0xf1 {
|
||||
i++
|
||||
continue
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
size := (x & 7) as int
|
||||
size := (x & 7) as int;
|
||||
if i+size > n {
|
||||
i++
|
||||
continue
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
ar := accept_ranges[x>>4]
|
||||
ar := accept_ranges[x>>4];
|
||||
if b := s[i+1]; b < ar.lo || ar.hi < b {
|
||||
size = 1
|
||||
size = 1;
|
||||
} else if size == 2 {
|
||||
// Okay
|
||||
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
|
||||
size = 1
|
||||
size = 1;
|
||||
} else if size == 3 {
|
||||
// Okay
|
||||
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
|
||||
size = 1
|
||||
size = 1;
|
||||
}
|
||||
i += size
|
||||
i += size;
|
||||
}
|
||||
return count
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
rune_size :: proc(r: rune) -> int {
|
||||
match {
|
||||
case r < 0: return -1
|
||||
case r <= 1<<7 - 1: return 1
|
||||
case r <= 1<<11 - 1: return 2
|
||||
case SURROGATE_MIN <= r && r <= SURROGATE_MAX: return -1
|
||||
case r <= 1<<16 - 1: return 3
|
||||
case r <= MAX_RUNE: return 4
|
||||
case r < 0: return -1;
|
||||
case r <= 1<<7 - 1: return 1;
|
||||
case r <= 1<<11 - 1: return 2;
|
||||
case SURROGATE_MIN <= r && r <= SURROGATE_MAX: return -1;
|
||||
case r <= 1<<16 - 1: return 3;
|
||||
case r <= MAX_RUNE: return 4;
|
||||
}
|
||||
return -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
524
core/win32.odin
524
core/win32.odin
@@ -1,524 +0,0 @@
|
||||
#foreign_system_library "user32" when ODIN_OS == "windows"
|
||||
#foreign_system_library "gdi32" when ODIN_OS == "windows"
|
||||
|
||||
HANDLE :: type rawptr
|
||||
HWND :: type HANDLE
|
||||
HDC :: type HANDLE
|
||||
HINSTANCE :: type HANDLE
|
||||
HICON :: type HANDLE
|
||||
HCURSOR :: type HANDLE
|
||||
HMENU :: type HANDLE
|
||||
HBRUSH :: type HANDLE
|
||||
HGDIOBJ :: type HANDLE
|
||||
HMODULE :: type HANDLE
|
||||
WPARAM :: type uint
|
||||
LPARAM :: type int
|
||||
LRESULT :: type int
|
||||
ATOM :: type i16
|
||||
BOOL :: type i32
|
||||
WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
|
||||
|
||||
INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE
|
||||
|
||||
CS_VREDRAW :: 0x0001
|
||||
CS_HREDRAW :: 0x0002
|
||||
CS_OWNDC :: 0x0020
|
||||
CW_USEDEFAULT :: -0x80000000
|
||||
|
||||
WS_OVERLAPPED :: 0
|
||||
WS_MAXIMIZEBOX :: 0x00010000
|
||||
WS_MINIMIZEBOX :: 0x00020000
|
||||
WS_THICKFRAME :: 0x00040000
|
||||
WS_SYSMENU :: 0x00080000
|
||||
WS_CAPTION :: 0x00C00000
|
||||
WS_VISIBLE :: 0x10000000
|
||||
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX
|
||||
|
||||
WM_DESTROY :: 0x0002
|
||||
WM_CLOSE :: 0x0010
|
||||
WM_QUIT :: 0x0012
|
||||
WM_KEYDOWN :: 0x0100
|
||||
WM_KEYUP :: 0x0101
|
||||
|
||||
PM_REMOVE :: 1
|
||||
|
||||
COLOR_BACKGROUND :: 1 as HBRUSH
|
||||
BLACK_BRUSH :: 4
|
||||
|
||||
SM_CXSCREEN :: 0
|
||||
SM_CYSCREEN :: 1
|
||||
|
||||
SW_SHOW :: 5
|
||||
|
||||
POINT :: struct #ordered {
|
||||
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 {
|
||||
low_date_time, high_date_time: 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
|
||||
}
|
||||
|
||||
WIN32_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 :: type i32
|
||||
GetFileExInfoStandard :: 0 as GET_FILEEX_INFO_LEVELS
|
||||
GetFileExMaxInfoLevel :: 1 as GET_FILEEX_INFO_LEVELS
|
||||
|
||||
GetLastError :: proc() -> i32 #foreign #dll_import
|
||||
ExitProcess :: proc(exit_code: u32) #foreign #dll_import
|
||||
GetDesktopWindow :: proc() -> HWND #foreign #dll_import
|
||||
GetCursorPos :: proc(p: ^POINT) -> i32 #foreign #dll_import
|
||||
ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign #dll_import
|
||||
GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign #dll_import
|
||||
GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign #dll_import
|
||||
PostQuitMessage :: proc(exit_code: i32) #foreign #dll_import
|
||||
SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign #dll_import
|
||||
|
||||
QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign #dll_import
|
||||
QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign #dll_import
|
||||
|
||||
Sleep :: proc(ms: i32) -> i32 #foreign #dll_import
|
||||
|
||||
OutputDebugStringA :: proc(c_str: ^u8) #foreign #dll_import
|
||||
|
||||
|
||||
RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign #dll_import
|
||||
CreateWindowExA :: proc(ex_style: u32,
|
||||
class_name, title: ^u8,
|
||||
style: u32,
|
||||
x, y, w, h: i32,
|
||||
parent: HWND, menu: HMENU, instance: HINSTANCE,
|
||||
param: rawptr) -> HWND #foreign #dll_import
|
||||
|
||||
ShowWindow :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign #dll_import
|
||||
TranslateMessage :: proc(msg: ^MSG) -> BOOL #foreign #dll_import
|
||||
DispatchMessageA :: proc(msg: ^MSG) -> LRESULT #foreign #dll_import
|
||||
UpdateWindow :: proc(hwnd: HWND) -> BOOL #foreign #dll_import
|
||||
PeekMessageA :: proc(msg: ^MSG, hwnd: HWND,
|
||||
msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign #dll_import
|
||||
|
||||
DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign #dll_import
|
||||
|
||||
AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign #dll_import
|
||||
|
||||
|
||||
GetQueryPerformanceFrequency :: proc() -> i64 {
|
||||
r: i64
|
||||
QueryPerformanceFrequency(^r)
|
||||
return r
|
||||
}
|
||||
|
||||
GetCommandLineA :: proc() -> ^u8 #foreign #dll_import
|
||||
GetSystemMetrics :: proc(index: i32) -> i32 #foreign #dll_import
|
||||
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
|
||||
|
||||
// File Stuff
|
||||
|
||||
CloseHandle :: proc(h: HANDLE) -> i32 #foreign #dll_import
|
||||
GetStdHandle :: proc(h: i32) -> HANDLE #foreign #dll_import
|
||||
CreateFileA :: proc(filename: ^u8, desired_access, share_mode: u32,
|
||||
security: rawptr,
|
||||
creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign #dll_import
|
||||
ReadFile :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign #dll_import
|
||||
WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> i32 #foreign #dll_import
|
||||
|
||||
GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign #dll_import
|
||||
GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> BOOL #foreign #dll_import
|
||||
GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign #dll_import
|
||||
|
||||
FILE_SHARE_READ :: 0x00000001
|
||||
FILE_SHARE_WRITE :: 0x00000002
|
||||
FILE_SHARE_DELETE :: 0x00000004
|
||||
FILE_GENERIC_ALL :: 0x10000000
|
||||
FILE_GENERIC_EXECUTE :: 0x20000000
|
||||
FILE_GENERIC_WRITE :: 0x40000000
|
||||
FILE_GENERIC_READ :: 0x80000000
|
||||
|
||||
STD_INPUT_HANDLE :: -10
|
||||
STD_OUTPUT_HANDLE :: -11
|
||||
STD_ERROR_HANDLE :: -12
|
||||
|
||||
CREATE_NEW :: 1
|
||||
CREATE_ALWAYS :: 2
|
||||
OPEN_EXISTING :: 3
|
||||
OPEN_ALWAYS :: 4
|
||||
TRUNCATE_EXISTING :: 5
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
HeapAlloc :: proc(h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign #dll_import
|
||||
HeapReAlloc :: proc(h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign #dll_import
|
||||
HeapFree :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign #dll_import
|
||||
GetProcessHeap :: proc() -> HANDLE #foreign #dll_import
|
||||
|
||||
|
||||
HEAP_ZERO_MEMORY :: 0x00000008
|
||||
|
||||
// Synchronization
|
||||
|
||||
SECURITY_ATTRIBUTES :: struct #ordered {
|
||||
length: u32
|
||||
security_descriptor: rawptr
|
||||
inherit_handle: BOOL
|
||||
}
|
||||
|
||||
INFINITE :: 0xffffffff
|
||||
|
||||
CreateSemaphoreA :: proc(attributes: ^SECURITY_ATTRIBUTES, initial_count, maximum_count: i32, name: ^byte) -> HANDLE #foreign #dll_import
|
||||
ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign #dll_import
|
||||
WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign #dll_import
|
||||
|
||||
|
||||
InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign
|
||||
InterlockedExchange :: proc(dst: ^i32, desired: i32) -> i32 #foreign
|
||||
InterlockedExchangeAdd :: proc(dst: ^i32, desired: i32) -> i32 #foreign
|
||||
InterlockedAnd :: proc(dst: ^i32, desired: i32) -> i32 #foreign
|
||||
InterlockedOr :: proc(dst: ^i32, desired: i32) -> i32 #foreign
|
||||
|
||||
InterlockedCompareExchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 #foreign
|
||||
InterlockedExchange64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
|
||||
InterlockedExchangeAdd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
|
||||
InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
|
||||
InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
|
||||
|
||||
_mm_pause :: proc() #foreign
|
||||
ReadWriteBarrier :: proc() #foreign
|
||||
WriteBarrier :: proc() #foreign
|
||||
ReadBarrier :: proc() #foreign
|
||||
|
||||
|
||||
// GDI
|
||||
|
||||
BITMAPINFO :: struct #ordered {
|
||||
HEADER :: struct #ordered {
|
||||
size: u32
|
||||
width, height: i32
|
||||
planes, bit_count: i16
|
||||
compression: u32
|
||||
size_image: u32
|
||||
x_pels_per_meter: i32
|
||||
y_pels_per_meter: i32
|
||||
clr_used: u32
|
||||
clr_important: u32
|
||||
}
|
||||
using header: HEADER
|
||||
colors: [1]RGBQUAD
|
||||
}
|
||||
|
||||
|
||||
RGBQUAD :: struct #ordered {
|
||||
blue, green, red, reserved: byte
|
||||
}
|
||||
|
||||
BI_RGB :: 0
|
||||
DIB_RGB_COLORS :: 0x00
|
||||
SRCCOPY :: 0x00cc0020 as u32
|
||||
|
||||
StretchDIBits :: proc(hdc: HDC,
|
||||
x_dst, y_dst, width_dst, height_dst: i32,
|
||||
x_src, y_src, width_src, header_src: i32,
|
||||
bits: rawptr, bits_info: ^BITMAPINFO,
|
||||
usage: u32,
|
||||
rop: u32) -> i32 #foreign #dll_import
|
||||
|
||||
|
||||
|
||||
LoadLibraryA :: proc(c_str: ^u8) -> HMODULE #foreign
|
||||
FreeLibrary :: proc(h: HMODULE) #foreign
|
||||
GetProcAddress :: proc(h: HMODULE, c_str: ^u8) -> rawptr #foreign
|
||||
|
||||
GetClientRect :: proc(hwnd: HWND, rect: ^RECT) -> BOOL #foreign
|
||||
|
||||
|
||||
|
||||
// Windows OpenGL
|
||||
|
||||
PFD_TYPE_RGBA :: 0
|
||||
PFD_TYPE_COLORINDEX :: 1
|
||||
PFD_MAIN_PLANE :: 0
|
||||
PFD_OVERLAY_PLANE :: 1
|
||||
PFD_UNDERLAY_PLANE :: -1
|
||||
PFD_DOUBLEBUFFER :: 1
|
||||
PFD_STEREO :: 2
|
||||
PFD_DRAW_TO_WINDOW :: 4
|
||||
PFD_DRAW_TO_BITMAP :: 8
|
||||
PFD_SUPPORT_GDI :: 16
|
||||
PFD_SUPPORT_OPENGL :: 32
|
||||
PFD_GENERIC_FORMAT :: 64
|
||||
PFD_NEED_PALETTE :: 128
|
||||
PFD_NEED_SYSTEM_PALETTE :: 0x00000100
|
||||
PFD_SWAP_EXCHANGE :: 0x00000200
|
||||
PFD_SWAP_COPY :: 0x00000400
|
||||
PFD_SWAP_LAYER_BUFFERS :: 0x00000800
|
||||
PFD_GENERIC_ACCELERATED :: 0x00001000
|
||||
PFD_DEPTH_DONTCARE :: 0x20000000
|
||||
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000
|
||||
PFD_STEREO_DONTCARE :: 0x80000000
|
||||
|
||||
HGLRC :: type HANDLE
|
||||
PROC :: type proc()
|
||||
wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC
|
||||
|
||||
|
||||
PIXELFORMATDESCRIPTOR :: struct #ordered {
|
||||
size,
|
||||
version,
|
||||
flags: u32
|
||||
|
||||
pixel_type,
|
||||
color_bits,
|
||||
red_bits,
|
||||
red_shift,
|
||||
green_bits,
|
||||
green_shift,
|
||||
blue_bits,
|
||||
blue_shift,
|
||||
alpha_bits,
|
||||
alpha_shift,
|
||||
accum_bits,
|
||||
accum_red_bits,
|
||||
accum_green_bits,
|
||||
accum_blue_bits,
|
||||
accum_alpha_bits,
|
||||
depth_bits,
|
||||
stencil_bits,
|
||||
aux_buffers,
|
||||
layer_type,
|
||||
reserved: byte
|
||||
|
||||
layer_mask,
|
||||
visible_mask,
|
||||
damage_mask: u32
|
||||
}
|
||||
|
||||
GetDC :: proc(h: HANDLE) -> HDC #foreign
|
||||
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign #dll_import
|
||||
ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign #dll_import
|
||||
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign #dll_import
|
||||
ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign #dll_import
|
||||
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092
|
||||
WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126
|
||||
WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001
|
||||
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002
|
||||
|
||||
wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign #dll_import
|
||||
wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign #dll_import
|
||||
wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign #dll_import
|
||||
wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign #dll_import
|
||||
|
||||
|
||||
|
||||
GetKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
||||
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
||||
|
||||
is_key_down :: proc(key: Key_Code) -> bool {
|
||||
return GetAsyncKeyState(key as i32) < 0
|
||||
}
|
||||
|
||||
Key_Code :: enum i32 {
|
||||
LBUTTON = 0x01,
|
||||
RBUTTON = 0x02,
|
||||
CANCEL = 0x03,
|
||||
MBUTTON = 0x04,
|
||||
|
||||
BACK = 0x08,
|
||||
TAB = 0x09,
|
||||
|
||||
CLEAR = 0x0C,
|
||||
RETURN = 0x0D,
|
||||
|
||||
SHIFT = 0x10,
|
||||
CONTROL = 0x11,
|
||||
MENU = 0x12,
|
||||
PAUSE = 0x13,
|
||||
CAPITAL = 0x14,
|
||||
|
||||
KANA = 0x15,
|
||||
HANGEUL = 0x15,
|
||||
HANGUL = 0x15,
|
||||
JUNJA = 0x17,
|
||||
FINAL = 0x18,
|
||||
HANJA = 0x19,
|
||||
KANJI = 0x19,
|
||||
|
||||
ESCAPE = 0x1B,
|
||||
|
||||
CONVERT = 0x1C,
|
||||
NONCONVERT = 0x1D,
|
||||
ACCEPT = 0x1E,
|
||||
MODECHANGE = 0x1F,
|
||||
|
||||
SPACE = 0x20,
|
||||
PRIOR = 0x21,
|
||||
NEXT = 0x22,
|
||||
END = 0x23,
|
||||
HOME = 0x24,
|
||||
LEFT = 0x25,
|
||||
UP = 0x26,
|
||||
RIGHT = 0x27,
|
||||
DOWN = 0x28,
|
||||
SELECT = 0x29,
|
||||
PRINT = 0x2A,
|
||||
EXECUTE = 0x2B,
|
||||
SNAPSHOT = 0x2C,
|
||||
INSERT = 0x2D,
|
||||
DELETE = 0x2E,
|
||||
HELP = 0x2F,
|
||||
|
||||
NUM0 = '0',
|
||||
NUM1 = '1',
|
||||
NUM2 = '2',
|
||||
NUM3 = '3',
|
||||
NUM4 = '4',
|
||||
NUM5 = '5',
|
||||
NUM6 = '6',
|
||||
NUM7 = '7',
|
||||
NUM8 = '8',
|
||||
NUM9 = '9',
|
||||
|
||||
A = 'A',
|
||||
B = 'B',
|
||||
C = 'C',
|
||||
D = 'D',
|
||||
E = 'E',
|
||||
F = 'F',
|
||||
G = 'G',
|
||||
H = 'H',
|
||||
I = 'I',
|
||||
J = 'J',
|
||||
K = 'K',
|
||||
L = 'L',
|
||||
M = 'M',
|
||||
N = 'N',
|
||||
O = 'O',
|
||||
P = 'P',
|
||||
Q = 'Q',
|
||||
R = 'R',
|
||||
S = 'S',
|
||||
T = 'T',
|
||||
U = 'U',
|
||||
V = 'V',
|
||||
W = 'W',
|
||||
X = 'X',
|
||||
Y = 'Y',
|
||||
Z = 'Z',
|
||||
|
||||
LWIN = 0x5B,
|
||||
RWIN = 0x5C,
|
||||
APPS = 0x5D,
|
||||
|
||||
NUMPAD0 = 0x60,
|
||||
NUMPAD1 = 0x61,
|
||||
NUMPAD2 = 0x62,
|
||||
NUMPAD3 = 0x63,
|
||||
NUMPAD4 = 0x64,
|
||||
NUMPAD5 = 0x65,
|
||||
NUMPAD6 = 0x66,
|
||||
NUMPAD7 = 0x67,
|
||||
NUMPAD8 = 0x68,
|
||||
NUMPAD9 = 0x69,
|
||||
MULTIPLY = 0x6A,
|
||||
ADD = 0x6B,
|
||||
SEPARATOR = 0x6C,
|
||||
SUBTRACT = 0x6D,
|
||||
DECIMAL = 0x6E,
|
||||
DIVIDE = 0x6F,
|
||||
F1 = 0x70,
|
||||
F2 = 0x71,
|
||||
F3 = 0x72,
|
||||
F4 = 0x73,
|
||||
F5 = 0x74,
|
||||
F6 = 0x75,
|
||||
F7 = 0x76,
|
||||
F8 = 0x77,
|
||||
F9 = 0x78,
|
||||
F10 = 0x79,
|
||||
F11 = 0x7A,
|
||||
F12 = 0x7B,
|
||||
F13 = 0x7C,
|
||||
F14 = 0x7D,
|
||||
F15 = 0x7E,
|
||||
F16 = 0x7F,
|
||||
F17 = 0x80,
|
||||
F18 = 0x81,
|
||||
F19 = 0x82,
|
||||
F20 = 0x83,
|
||||
F21 = 0x84,
|
||||
F22 = 0x85,
|
||||
F23 = 0x86,
|
||||
F24 = 0x87,
|
||||
|
||||
NUMLOCK = 0x90,
|
||||
SCROLL = 0x91,
|
||||
|
||||
LSHIFT = 0xA0,
|
||||
RSHIFT = 0xA1,
|
||||
LCONTROL = 0xA2,
|
||||
RCONTROL = 0xA3,
|
||||
LMENU = 0xA4,
|
||||
RMENU = 0xA5,
|
||||
PROCESSKEY = 0xE5,
|
||||
ATTN = 0xF6,
|
||||
CRSEL = 0xF7,
|
||||
EXSEL = 0xF8,
|
||||
EREOF = 0xF9,
|
||||
PLAY = 0xFA,
|
||||
ZOOM = 0xFB,
|
||||
NONAME = 0xFC,
|
||||
PA1 = 0xFD,
|
||||
OEM_CLEAR = 0xFE,
|
||||
}
|
||||
|
||||
29
roadmap.md
29
roadmap.md
@@ -2,23 +2,20 @@
|
||||
|
||||
Not in any particular order
|
||||
|
||||
* Compile Time Execution (CTE)
|
||||
- More metaprogramming madness
|
||||
- Compiler as a library
|
||||
- AST inspection and modification
|
||||
* CTE-based build system
|
||||
* Replace LLVM backend with my own custom backend
|
||||
* Improve SSA design to accommodate for lowering to a "bytecode"
|
||||
* SSA optimizations
|
||||
* Parametric Polymorphism
|
||||
* Documentation Generator for "Entities"
|
||||
* Multiple Architecture support
|
||||
* Linking Options
|
||||
* Custom backend to replace LLVM
|
||||
- Improve SSA design to accommodate for lowering to a "bytecode"
|
||||
- SSA optimizations
|
||||
- COFF generation
|
||||
- linker
|
||||
* Type safe "macros"
|
||||
* Documentation generator for "Entities"
|
||||
* Multiple architecture support
|
||||
* Inline assembly
|
||||
* Linking options
|
||||
- Executable
|
||||
- Static/Dynamic Library
|
||||
* Debug Information
|
||||
* Debug information
|
||||
- pdb format too
|
||||
* Command Line Tooling
|
||||
* Compiler Internals:
|
||||
* Command line tooling
|
||||
* Compiler internals:
|
||||
- Big numbers library
|
||||
- Cyclic Type Checking (at the moment will cause compiler to go into an infinite loop)
|
||||
|
||||
@@ -991,17 +991,22 @@ void init_preload(Checker *c) {
|
||||
}
|
||||
|
||||
if (t_type_info == NULL) {
|
||||
Entity *e = current_scope_lookup_entity(c->global_scope, str_lit("Type_Info"));
|
||||
if (e == NULL) {
|
||||
Entity *type_info_entity = current_scope_lookup_entity(c->global_scope, str_lit("Type_Info"));
|
||||
if (type_info_entity == NULL) {
|
||||
compiler_error("Could not find type declaration for `Type_Info`\n"
|
||||
"Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
|
||||
}
|
||||
t_type_info = e->type;
|
||||
Entity *type_info_member_entity = current_scope_lookup_entity(c->global_scope, str_lit("Type_Info_Member"));
|
||||
if (type_info_entity == NULL) {
|
||||
compiler_error("Could not find type declaration for `Type_Info_Member`\n"
|
||||
"Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
|
||||
}
|
||||
t_type_info = type_info_entity->type;
|
||||
t_type_info_ptr = make_type_pointer(c->allocator, t_type_info);
|
||||
GB_ASSERT(is_type_union(e->type));
|
||||
TypeRecord *record = &base_type(e->type)->Record;
|
||||
GB_ASSERT(is_type_union(type_info_entity->type));
|
||||
TypeRecord *record = &base_type(type_info_entity->type)->Record;
|
||||
|
||||
t_type_info_member = record->other_fields[0]->type;
|
||||
t_type_info_member = type_info_member_entity->type;
|
||||
t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member);
|
||||
|
||||
if (record->field_count != 18) {
|
||||
|
||||
@@ -372,10 +372,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
Operand operand = {Addressing_Invalid};
|
||||
check_expr(c, &operand, ids->expr);
|
||||
if (operand.mode == Addressing_Invalid)
|
||||
if (operand.mode == Addressing_Invalid) {
|
||||
return;
|
||||
if (!is_type_numeric(operand.type)) {
|
||||
error(ids->op, "Non numeric type");
|
||||
}
|
||||
if (!is_type_numeric(operand.type) && !is_type_pointer(operand.type)) {
|
||||
gbString type_str = type_to_string(operand.type);
|
||||
error(ids->op, "Non numeric type `%s`", type_str);
|
||||
gb_string_free(type_str);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
47
src/parser.c
47
src/parser.c
@@ -1183,33 +1183,33 @@ Token expect_closing(AstFile *f, TokenKind kind, String context) {
|
||||
}
|
||||
|
||||
void expect_semicolon(AstFile *f, AstNode *s) {
|
||||
if (f->prev_token.kind == Token_CloseBrace ||
|
||||
f->prev_token.kind == Token_CloseBrace) {
|
||||
if (allow_token(f, Token_Semicolon)) {
|
||||
return;
|
||||
}
|
||||
Token prev_token = f->prev_token;
|
||||
|
||||
switch (f->curr_token.kind) {
|
||||
case Token_EOF:
|
||||
return;
|
||||
}
|
||||
|
||||
if (f->curr_token.kind != Token_CloseParen &&
|
||||
f->curr_token.kind != Token_CloseBrace) {
|
||||
switch (f->curr_token.kind) {
|
||||
case Token_Comma:
|
||||
expect_token(f, Token_Semicolon);
|
||||
/*fallthrough*/
|
||||
case Token_Semicolon:
|
||||
next_token(f);
|
||||
if (s != NULL) {
|
||||
switch (s->kind) {
|
||||
case AstNode_ProcDecl:
|
||||
return;
|
||||
case AstNode_TypeDecl:
|
||||
if (f->prev_token.kind == Token_CloseBrace) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
expect_token(f, Token_Semicolon);
|
||||
fix_advance_to_next_stmt(f);
|
||||
}
|
||||
}
|
||||
|
||||
// if (s != NULL) {
|
||||
// syntax_error(f->prev_token, "Expected `;` after %.*s, got `%.*s`",
|
||||
// LIT(ast_node_strings[s->kind]), LIT(token_strings[f->prev_token.kind]));
|
||||
// } else {
|
||||
// syntax_error(f->prev_token, "Expected `;`");
|
||||
// }
|
||||
// fix_advance_to_next_stmt(f);
|
||||
syntax_error(prev_token, "Expected `;` after %.*s, got %.*s",
|
||||
LIT(ast_node_strings[s->kind]), LIT(token_strings[prev_token.kind]));
|
||||
} else {
|
||||
syntax_error(prev_token, "Expected `;`");
|
||||
}
|
||||
fix_advance_to_next_stmt(f);
|
||||
}
|
||||
|
||||
bool parse_at_comma(AstFile *f, String context, TokenKind follow) {
|
||||
@@ -2497,8 +2497,6 @@ AstNode *parse_if_stmt(AstFile *f) {
|
||||
else_stmt = make_bad_stmt(f, f->curr_token, f->tokens.e[f->curr_token_index+1]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
expect_semicolon(f, body);
|
||||
}
|
||||
|
||||
return make_if_stmt(f, token, init, cond, body, else_stmt);
|
||||
@@ -2935,8 +2933,8 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
s = make_bad_decl(f, token, file_path);
|
||||
} else {
|
||||
s = make_import_decl(f, hash_token, file_path, import_name, cond, false);
|
||||
expect_semicolon(f, s);
|
||||
}
|
||||
expect_semicolon(f, s);
|
||||
return s;
|
||||
} else if (str_eq(tag, str_lit("include"))) {
|
||||
AstNode *cond = NULL;
|
||||
@@ -2984,6 +2982,7 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
return s;
|
||||
}
|
||||
|
||||
expect_semicolon(f, s);
|
||||
return make_tag_stmt(f, hash_token, name, parse_stmt(f));
|
||||
} break;
|
||||
|
||||
|
||||
105
src/tokenizer.c
105
src/tokenizer.c
@@ -304,8 +304,6 @@ typedef struct Tokenizer {
|
||||
u8 * line; // current line pos
|
||||
isize line_count;
|
||||
|
||||
bool insert_semicolon; // Inserts a semicolon before the next newline
|
||||
|
||||
isize error_count;
|
||||
Array(String) allocated_strings;
|
||||
} Tokenizer;
|
||||
@@ -418,7 +416,7 @@ gb_inline void destroy_tokenizer(Tokenizer *t) {
|
||||
void tokenizer_skip_whitespace(Tokenizer *t) {
|
||||
while (t->curr_rune == ' ' ||
|
||||
t->curr_rune == '\t' ||
|
||||
(t->curr_rune == '\n' && !t->insert_semicolon) ||
|
||||
t->curr_rune == '\n' ||
|
||||
t->curr_rune == '\r') {
|
||||
advance_to_next_rune(t);
|
||||
}
|
||||
@@ -677,8 +675,6 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
token.pos.line = t->line_count;
|
||||
token.pos.column = t->curr - t->line + 1;
|
||||
|
||||
bool insert_semicolon = false;
|
||||
|
||||
Rune curr_rune = t->curr_rune;
|
||||
if (rune_is_letter(curr_rune)) {
|
||||
token.kind = Token_Ident;
|
||||
@@ -706,48 +702,19 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (token.kind) {
|
||||
case Token_Ident:
|
||||
case Token_return:
|
||||
case Token_break:
|
||||
case Token_continue:
|
||||
case Token_fallthrough:
|
||||
insert_semicolon = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
insert_semicolon = true;
|
||||
}
|
||||
|
||||
} else if (gb_is_between(curr_rune, '0', '9')) {
|
||||
insert_semicolon = true;
|
||||
token = scan_number_to_token(t, false);
|
||||
} else {
|
||||
advance_to_next_rune(t);
|
||||
switch (curr_rune) {
|
||||
case GB_RUNE_EOF:
|
||||
if (t->insert_semicolon) {
|
||||
t->insert_semicolon = false;
|
||||
token.string = str_lit("\n");
|
||||
token.kind = Token_Semicolon;
|
||||
return token;
|
||||
}
|
||||
token.kind = Token_EOF;
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
// NOTE(bill): This will be only be reached if t->insert_semicolom was set
|
||||
// earlier and exited early from tokenizer_skip_whitespace()
|
||||
t->insert_semicolon = false;
|
||||
token.string = str_lit("\n");
|
||||
token.kind = Token_Semicolon;
|
||||
return token;
|
||||
|
||||
case '\'': // Rune Literal
|
||||
{
|
||||
insert_semicolon = true;
|
||||
|
||||
token.kind = Token_Rune;
|
||||
Rune quote = curr_rune;
|
||||
bool valid = true;
|
||||
@@ -780,7 +747,6 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
if (success == 2) {
|
||||
array_add(&t->allocated_strings, token.string);
|
||||
}
|
||||
t->insert_semicolon = true;
|
||||
return token;
|
||||
} else {
|
||||
tokenizer_err(t, "Invalid rune literal");
|
||||
@@ -790,8 +756,6 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
case '`': // Raw String Literal
|
||||
case '"': // String Literal
|
||||
{
|
||||
insert_semicolon = true;
|
||||
|
||||
i32 success;
|
||||
Rune quote = curr_rune;
|
||||
token.kind = Token_String;
|
||||
@@ -829,7 +793,6 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
if (success == 2) {
|
||||
array_add(&t->allocated_strings, token.string);
|
||||
}
|
||||
t->insert_semicolon = true;
|
||||
return token;
|
||||
} else {
|
||||
tokenizer_err(t, "Invalid string literal");
|
||||
@@ -839,7 +802,6 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
case '.':
|
||||
token.kind = Token_Period; // Default
|
||||
if (gb_is_between(t->curr_rune, '0', '9')) { // Might be a number
|
||||
insert_semicolon = true;
|
||||
token = scan_number_to_token(t, true);
|
||||
} else if (t->curr_rune == '.') { // Could be an ellipsis
|
||||
advance_to_next_rune(t);
|
||||
@@ -881,21 +843,18 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
token.kind = Token_OpenParen;
|
||||
break;
|
||||
case ')':
|
||||
insert_semicolon = true;
|
||||
token.kind = Token_CloseParen;
|
||||
break;
|
||||
case '[':
|
||||
token.kind = Token_OpenBracket;
|
||||
break;
|
||||
case ']':
|
||||
insert_semicolon = true;
|
||||
token.kind = Token_CloseBracket;
|
||||
break;
|
||||
case '{':
|
||||
token.kind = Token_OpenBrace;
|
||||
break;
|
||||
case '}':
|
||||
insert_semicolon = true;
|
||||
token.kind = Token_CloseBrace;
|
||||
break;
|
||||
|
||||
@@ -906,56 +865,37 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
|
||||
case '+':
|
||||
token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Increment);
|
||||
if (token.kind == Token_Increment) {
|
||||
insert_semicolon = true;
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Decrement, '>', Token_ArrowRight);
|
||||
if (token.kind == Token_Decrement) {
|
||||
insert_semicolon = true;
|
||||
}
|
||||
break;
|
||||
case '/': {
|
||||
if (t->curr_rune == '/' || t->curr_rune == '*') {
|
||||
if (t->insert_semicolon && tokenizer_find_line_end(t)) {
|
||||
t->curr_rune = '/';
|
||||
t->curr = token.string.text;
|
||||
t->read_curr = t->curr+1;
|
||||
t->insert_semicolon = false;
|
||||
|
||||
token.kind = Token_Semicolon;
|
||||
token.string = str_lit("\n");
|
||||
return token;
|
||||
}
|
||||
|
||||
if (t->curr_rune == '/') {
|
||||
while (t->curr_rune != '\n') {
|
||||
advance_to_next_rune(t);
|
||||
}
|
||||
token.kind = Token_Comment;
|
||||
} else if (t->curr_rune == '*') {
|
||||
isize comment_scope = 1;
|
||||
if (t->curr_rune == '/') {
|
||||
while (t->curr_rune != '\n') {
|
||||
advance_to_next_rune(t);
|
||||
while (comment_scope > 0) {
|
||||
}
|
||||
token.kind = Token_Comment;
|
||||
} else if (t->curr_rune == '*') {
|
||||
isize comment_scope = 1;
|
||||
advance_to_next_rune(t);
|
||||
while (comment_scope > 0) {
|
||||
if (t->curr_rune == '/') {
|
||||
advance_to_next_rune(t);
|
||||
if (t->curr_rune == '*') {
|
||||
advance_to_next_rune(t);
|
||||
comment_scope++;
|
||||
}
|
||||
} else if (t->curr_rune == '*') {
|
||||
advance_to_next_rune(t);
|
||||
if (t->curr_rune == '/') {
|
||||
advance_to_next_rune(t);
|
||||
if (t->curr_rune == '*') {
|
||||
advance_to_next_rune(t);
|
||||
comment_scope++;
|
||||
}
|
||||
} else if (t->curr_rune == '*') {
|
||||
advance_to_next_rune(t);
|
||||
if (t->curr_rune == '/') {
|
||||
advance_to_next_rune(t);
|
||||
comment_scope--;
|
||||
}
|
||||
} else {
|
||||
advance_to_next_rune(t);
|
||||
comment_scope--;
|
||||
}
|
||||
} else {
|
||||
advance_to_next_rune(t);
|
||||
}
|
||||
token.kind = Token_Comment;
|
||||
}
|
||||
token.kind = Token_Comment;
|
||||
} else {
|
||||
token.kind = token_kind_variant2(t, Token_Quo, Token_QuoEq);
|
||||
}
|
||||
@@ -994,14 +934,11 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
int len = cast(int)gb_utf8_encode_rune(str, curr_rune);
|
||||
tokenizer_err(t, "Illegal character: %.*s (%d) ", len, str, curr_rune);
|
||||
}
|
||||
insert_semicolon = t->insert_semicolon;
|
||||
token.kind = Token_Invalid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
t->insert_semicolon = insert_semicolon;
|
||||
|
||||
token.string.len = t->curr - token.string.text;
|
||||
return token;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user