mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Fix match statements for the new AstNodeArray type
This commit is contained in:
+8
-8
@@ -183,10 +183,10 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) {
|
|||||||
u: uint = 0;
|
u: uint = 0;
|
||||||
if arg.data != null {
|
if arg.data != null {
|
||||||
match info.size {
|
match info.size {
|
||||||
case 1: u = (arg.data as ^u8)^ as uint
|
case 1: u = (arg.data as ^u8)^ as uint
|
||||||
case 2: u = (arg.data as ^u16)^ as uint
|
case 2: u = (arg.data as ^u16)^ as uint
|
||||||
case 4: u = (arg.data as ^u32)^ as uint
|
case 4: u = (arg.data as ^u32)^ as uint
|
||||||
case 8: u = (arg.data as ^u64)^ as uint
|
case 8: u = (arg.data as ^u64)^ as uint
|
||||||
case 16: u = (arg.data as ^u128)^ as uint
|
case 16: u = (arg.data as ^u128)^ as uint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,10 +195,10 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) {
|
|||||||
v: int = 0;
|
v: int = 0;
|
||||||
if arg.data != null {
|
if arg.data != null {
|
||||||
match info.size {
|
match info.size {
|
||||||
case 1: v = (arg.data as ^i8)^ as int
|
case 1: v = (arg.data as ^i8)^ as int
|
||||||
case 2: v = (arg.data as ^i16)^ as int
|
case 2: v = (arg.data as ^i16)^ as int
|
||||||
case 4: v = (arg.data as ^i32)^ as int
|
case 4: v = (arg.data as ^i32)^ as int
|
||||||
case 8: v = (arg.data as ^i64)^ as int
|
case 8: v = (arg.data as ^i64)^ as int
|
||||||
case 16: v = (arg.data as ^i128)^ as int
|
case 16: v = (arg.data as ^i128)^ as int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#load "basic.odin"
|
#load "basic.odin"
|
||||||
#load "math.odin"
|
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
a: any = 1
|
|
||||||
println(137, "Hello", 1.25, true)
|
println(137, "Hello", 1.25, true)
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-9
@@ -16,9 +16,7 @@ time_now :: proc() -> f64 {
|
|||||||
win32_print_last_error :: proc() {
|
win32_print_last_error :: proc() {
|
||||||
err_code := GetLastError() as int
|
err_code := GetLastError() as int
|
||||||
if err_code != 0 {
|
if err_code != 0 {
|
||||||
print_string("GetLastError: ")
|
println("GetLastError:", err_code)
|
||||||
print_int(err_code)
|
|
||||||
print_string("\n")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +44,8 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W
|
|||||||
|
|
||||||
class_name := "Win32-Odin-Window\x00"
|
class_name := "Win32-Odin-Window\x00"
|
||||||
c_class_name := ^class_name[0]
|
c_class_name := ^class_name[0]
|
||||||
w.c_title = to_c_string(title)
|
// w.c_title = to_c_string(title)
|
||||||
|
w.c_title = "Title\x00" as []byte
|
||||||
|
|
||||||
instance := GetModuleHandleA(null)
|
instance := GetModuleHandleA(null)
|
||||||
|
|
||||||
@@ -59,6 +58,7 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W
|
|||||||
};
|
};
|
||||||
|
|
||||||
if RegisterClassExA(^w.wc) == 0 {
|
if RegisterClassExA(^w.wc) == 0 {
|
||||||
|
win32_print_last_error( )
|
||||||
return w, false
|
return w, false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +129,7 @@ run_game :: proc() {
|
|||||||
return DefWindowProcA(hwnd, msg, wparam, lparam)
|
return DefWindowProcA(hwnd, msg, wparam, lparam)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc)
|
window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc)
|
||||||
if !window_success {
|
if !window_success {
|
||||||
return
|
return
|
||||||
@@ -155,7 +156,7 @@ run_game :: proc() {
|
|||||||
_ = DispatchMessageA(^msg)
|
_ = DispatchMessageA(^msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_key_down(VK_ESCAPE) {
|
if is_key_down(Key_Code.ESCAPE) {
|
||||||
running = false
|
running = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,10 +164,10 @@ run_game :: proc() {
|
|||||||
SPEED :: 500
|
SPEED :: 500
|
||||||
v: Vec2
|
v: Vec2
|
||||||
|
|
||||||
if is_key_down(VK_RIGHT) { v[0] += 1 }
|
if is_key_down(Key_Code.RIGHT) { v[0] += 1 }
|
||||||
if is_key_down(VK_LEFT) { v[0] -= 1 }
|
if is_key_down(Key_Code.LEFT) { v[0] -= 1 }
|
||||||
if is_key_down(VK_UP) { v[1] += 1 }
|
if is_key_down(Key_Code.UP) { v[1] += 1 }
|
||||||
if is_key_down(VK_DOWN) { v[1] -= 1 }
|
if is_key_down(Key_Code.DOWN) { v[1] -= 1 }
|
||||||
|
|
||||||
v = vec2_norm0(v)
|
v = vec2_norm0(v)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,900 @@
|
|||||||
|
// Demo 002
|
||||||
|
#load "basic.odin"
|
||||||
|
#load "math.odin"
|
||||||
|
// #load "game.odin"
|
||||||
|
|
||||||
|
#thread_local tls_int: int
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
// Forenotes
|
||||||
|
|
||||||
|
// Semicolons are now optional
|
||||||
|
// Rule for when a semicolon is expected after a statement
|
||||||
|
// - If the next token is not on the same line
|
||||||
|
// - if the next token is a closing brace }
|
||||||
|
// - Otherwise, a semicolon is needed
|
||||||
|
//
|
||||||
|
// Expections:
|
||||||
|
// for, if, match
|
||||||
|
// if x := thing(); x < 123 {}
|
||||||
|
// for i := 0; i < 123; i++ {}
|
||||||
|
|
||||||
|
// Q: Should I use the new rule or go back to the old one without optional semicolons?
|
||||||
|
|
||||||
|
|
||||||
|
// #thread_local - see runtime.odin and above at `tls_int`
|
||||||
|
// #foreign_system_library - see win32.odin
|
||||||
|
|
||||||
|
// struct_compound_literals()
|
||||||
|
// enumerations()
|
||||||
|
// variadic_procedures()
|
||||||
|
// new_builtins()
|
||||||
|
// match_statement()
|
||||||
|
// namespacing()
|
||||||
|
// subtyping()
|
||||||
|
// tagged_unions()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct_compound_literals :: proc() {
|
||||||
|
Thing :: type struct {
|
||||||
|
id: int
|
||||||
|
x: f32
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
{
|
||||||
|
t1: Thing
|
||||||
|
t1.id = 1
|
||||||
|
|
||||||
|
t3 := Thing{}
|
||||||
|
t4 := Thing{1, 2, "Fred"}
|
||||||
|
// t5 := Thing{1, 2}
|
||||||
|
|
||||||
|
t6 := Thing{
|
||||||
|
name = "Tom",
|
||||||
|
x = 23,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enumerations :: proc() {
|
||||||
|
{
|
||||||
|
Fruit :: type enum {
|
||||||
|
APPLE, // 0
|
||||||
|
BANANA, // 1
|
||||||
|
PEAR, // 2
|
||||||
|
}
|
||||||
|
|
||||||
|
f := Fruit.APPLE
|
||||||
|
// g12: int = Fruit.BANANA
|
||||||
|
g: int = Fruit.BANANA as int
|
||||||
|
// However, you can use enums are index values as _any_ integer allowed
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Fruit1 :: type enum int {
|
||||||
|
APPLE,
|
||||||
|
BANANA,
|
||||||
|
PEAR,
|
||||||
|
}
|
||||||
|
|
||||||
|
Fruit2 :: type enum u8 {
|
||||||
|
APPLE,
|
||||||
|
BANANA,
|
||||||
|
PEAR,
|
||||||
|
}
|
||||||
|
|
||||||
|
Fruit3 :: type enum u8 {
|
||||||
|
APPLE = 1,
|
||||||
|
BANANA, // 2
|
||||||
|
PEAR = 5,
|
||||||
|
TOMATO, // 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Q: remove the need for `type` if it's a record (struct/enum/raw_union/union)?
|
||||||
|
}
|
||||||
|
|
||||||
|
variadic_procedures :: proc() {
|
||||||
|
print_ints :: proc(args: ..int) {
|
||||||
|
for i := 0; i < len(args); i++ {
|
||||||
|
if i > 0 {
|
||||||
|
print_string(", ")
|
||||||
|
}
|
||||||
|
print_int(args[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print_ints(); // nl()
|
||||||
|
print_ints(1); nl()
|
||||||
|
print_ints(1, 2, 3); nl()
|
||||||
|
|
||||||
|
print_prefix_f32s :: proc(prefix: string, args: ..f32) {
|
||||||
|
print_string(prefix)
|
||||||
|
print_string(": ")
|
||||||
|
for i := 0; i < len(args); i++ {
|
||||||
|
if i > 0 {
|
||||||
|
print_string(", ")
|
||||||
|
}
|
||||||
|
print_f32(args[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print_prefix_f32s("a"); nl()
|
||||||
|
print_prefix_f32s("b", 1); nl()
|
||||||
|
print_prefix_f32s("c", 1, 2, 3); nl()
|
||||||
|
|
||||||
|
// Internally, the variadic procedures get allocated to an array on the stack,
|
||||||
|
// and this array is passed a slice
|
||||||
|
|
||||||
|
// This is first step for a `print` procedure but I do not have an `any` type
|
||||||
|
// yet as this requires a few other things first - i.e. introspection
|
||||||
|
|
||||||
|
// NOTE(bill): I haven't yet added the feature of expanding a slice or array into
|
||||||
|
// a variadic a parameter but it's pretty trivial to add
|
||||||
|
}
|
||||||
|
|
||||||
|
new_builtins :: proc() {
|
||||||
|
{
|
||||||
|
a := new(int)
|
||||||
|
b := new_slice(int, 12)
|
||||||
|
c := new_slice(int, 12, 16)
|
||||||
|
|
||||||
|
defer delete(a)
|
||||||
|
defer delete(b)
|
||||||
|
defer delete(c)
|
||||||
|
|
||||||
|
// NOTE(bill): These use the current context's allocator not the default allocator
|
||||||
|
// see runtime.odin
|
||||||
|
|
||||||
|
// Q: Should this be `free` rather than `delete` and should I overload it for slices too?
|
||||||
|
|
||||||
|
{
|
||||||
|
prev_context := context
|
||||||
|
defer context = prev_context
|
||||||
|
// Q: Should I add a `push_context` feature to the language?
|
||||||
|
|
||||||
|
context.allocator = __default_allocator()
|
||||||
|
|
||||||
|
a := new(int)
|
||||||
|
defer delete(a)
|
||||||
|
|
||||||
|
// Do whatever
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
a: int = 123
|
||||||
|
b: type_of_val(a) = 321
|
||||||
|
|
||||||
|
// NOTE(bill): This matches the current naming scheme
|
||||||
|
// size_of
|
||||||
|
// align_of
|
||||||
|
// offset_of
|
||||||
|
//
|
||||||
|
// size_of_val
|
||||||
|
// align_of_val
|
||||||
|
// offset_of_val
|
||||||
|
// type_of_val
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Compile time assert
|
||||||
|
COND :: true
|
||||||
|
assert(COND)
|
||||||
|
// assert(!COND)
|
||||||
|
|
||||||
|
// Runtime assert
|
||||||
|
x := true
|
||||||
|
assert(x)
|
||||||
|
// assert(!x)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
x: ^u32 = null;
|
||||||
|
y := ptr_offset(x, 100)
|
||||||
|
z := ptr_sub(y, x)
|
||||||
|
w := slice_ptr(x, 12)
|
||||||
|
t := slice_ptr(x, 12, 16)
|
||||||
|
|
||||||
|
// NOTE(bill): These are here because I've removed:
|
||||||
|
// pointer arithmetic
|
||||||
|
// pointer indexing
|
||||||
|
// pointer slicing
|
||||||
|
|
||||||
|
// Reason
|
||||||
|
|
||||||
|
a: [16]int
|
||||||
|
a[1] = 1;
|
||||||
|
b := ^a
|
||||||
|
// Auto pointer deref
|
||||||
|
// consistent with record members
|
||||||
|
assert(b[1] == 1)
|
||||||
|
|
||||||
|
// Q: Should I add them back in at the cost of inconsitency?
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
a, b := -1, 2
|
||||||
|
print_int(min(a, b)); nl()
|
||||||
|
print_int(max(a, b)); nl()
|
||||||
|
print_int(abs(a)); nl()
|
||||||
|
|
||||||
|
// These work at compile time too
|
||||||
|
A :: -1
|
||||||
|
B :: 2
|
||||||
|
C :: min(A, B)
|
||||||
|
D :: max(A, B)
|
||||||
|
E :: abs(A)
|
||||||
|
|
||||||
|
print_int(C); nl()
|
||||||
|
print_int(D); nl()
|
||||||
|
print_int(E); nl()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
match_statement :: proc() {
|
||||||
|
// NOTE(bill): `match` statements are similar to `switch` statements
|
||||||
|
// in other languages but there are few differences
|
||||||
|
|
||||||
|
{
|
||||||
|
match x := 5; x {
|
||||||
|
case 1: // cases must be constant expression
|
||||||
|
print_string("1!\n")
|
||||||
|
// break by default
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
s := "2!\n"; // Each case has its own scope
|
||||||
|
print_string(s)
|
||||||
|
break // explicit break
|
||||||
|
|
||||||
|
case 3, 4: // multiple cases
|
||||||
|
print_string("3 or 4!\n")
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
print_string("5!\n")
|
||||||
|
fallthrough // explicit fallthrough
|
||||||
|
|
||||||
|
default:
|
||||||
|
print_string("default!\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
match x := 1.5; x {
|
||||||
|
case 1.5:
|
||||||
|
print_string("1.5!\n")
|
||||||
|
// break by default
|
||||||
|
case MATH_TAU:
|
||||||
|
print_string("τ!\n")
|
||||||
|
default:
|
||||||
|
print_string("default!\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
match x := "Hello"; x {
|
||||||
|
case "Hello":
|
||||||
|
print_string("greeting\n")
|
||||||
|
// break by default
|
||||||
|
case "Goodbye":
|
||||||
|
print_string("farewell\n")
|
||||||
|
default:
|
||||||
|
print_string("???\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
a := 53
|
||||||
|
match {
|
||||||
|
case a == 1:
|
||||||
|
print_string("one\n")
|
||||||
|
case a == 2:
|
||||||
|
print_string("a couple\n")
|
||||||
|
case a < 7, a == 7:
|
||||||
|
print_string("a few\n")
|
||||||
|
case a < 12: // intentional bug
|
||||||
|
print_string("several\n")
|
||||||
|
case a >= 12 && a < 100:
|
||||||
|
print_string("dozens\n")
|
||||||
|
case a >= 100 && a < 1000:
|
||||||
|
print_string("hundreds\n")
|
||||||
|
default:
|
||||||
|
print_string("a fuck ton\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identical to this
|
||||||
|
|
||||||
|
b := 53
|
||||||
|
if b == 1 {
|
||||||
|
print_string("one\n")
|
||||||
|
} else if b == 2 {
|
||||||
|
print_string("a couple\n")
|
||||||
|
} else if b < 7 || b == 7 {
|
||||||
|
print_string("a few\n")
|
||||||
|
} else if b < 12 { // intentional bug
|
||||||
|
print_string("several\n")
|
||||||
|
} else if b >= 12 && b < 100 {
|
||||||
|
print_string("dozens\n")
|
||||||
|
} else if b >= 100 && b < 1000 {
|
||||||
|
print_string("hundreds\n")
|
||||||
|
} else {
|
||||||
|
print_string("a fuck ton\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// However, match statements allow for `break` and `fallthrough` unlike
|
||||||
|
// an if statement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 :: type struct {
|
||||||
|
x, y, z: f32
|
||||||
|
}
|
||||||
|
|
||||||
|
print_floats :: proc(args: ..f32) {
|
||||||
|
for i := 0; i < len(args); i++ {
|
||||||
|
if i > 0 {
|
||||||
|
print_string(", ")
|
||||||
|
}
|
||||||
|
print_f32(args[i])
|
||||||
|
}
|
||||||
|
print_nl()
|
||||||
|
}
|
||||||
|
|
||||||
|
namespacing :: proc() {
|
||||||
|
{
|
||||||
|
Thing :: type struct {
|
||||||
|
x: f32
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
a: Thing
|
||||||
|
a.x = 3
|
||||||
|
{
|
||||||
|
Thing :: type struct {
|
||||||
|
y: int
|
||||||
|
test: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
b: Thing // Uses this scope's Thing
|
||||||
|
b.test = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Entity :: type struct {
|
||||||
|
Guid :: type int
|
||||||
|
Nested :: type struct {
|
||||||
|
MyInt :: type int
|
||||||
|
i: int
|
||||||
|
}
|
||||||
|
|
||||||
|
CONSTANT :: 123
|
||||||
|
|
||||||
|
|
||||||
|
guid: Guid
|
||||||
|
name: string
|
||||||
|
pos: Vector3
|
||||||
|
vel: Vector3
|
||||||
|
nested: Nested
|
||||||
|
}
|
||||||
|
|
||||||
|
guid: Entity.Guid = Entity.CONSTANT
|
||||||
|
i: Entity.Nested.MyInt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
using Entity
|
||||||
|
guid: Guid = CONSTANT
|
||||||
|
using Nested
|
||||||
|
i: MyInt
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
using Entity.Nested
|
||||||
|
guid: Entity.Guid = Entity.CONSTANT
|
||||||
|
i: MyInt
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
e: Entity
|
||||||
|
using e
|
||||||
|
guid = 27832
|
||||||
|
name = "Bob"
|
||||||
|
|
||||||
|
print_int(e.guid as int); nl()
|
||||||
|
print_string(e.name); nl()
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
using e: Entity
|
||||||
|
guid = 78456
|
||||||
|
name = "Thing"
|
||||||
|
|
||||||
|
print_int(e.guid as int); nl()
|
||||||
|
print_string(e.name); nl()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Entity :: type struct {
|
||||||
|
Guid :: type int
|
||||||
|
Nested :: type struct {
|
||||||
|
MyInt :: type int
|
||||||
|
i: int
|
||||||
|
}
|
||||||
|
|
||||||
|
CONSTANT :: 123
|
||||||
|
|
||||||
|
|
||||||
|
guid: Guid
|
||||||
|
name: string
|
||||||
|
using pos: Vector3
|
||||||
|
vel: Vector3
|
||||||
|
using nested: ^Nested
|
||||||
|
}
|
||||||
|
|
||||||
|
e := Entity{nested = new(Entity.Nested)}
|
||||||
|
e.x = 123
|
||||||
|
e.i = Entity.CONSTANT
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
Entity :: type struct {
|
||||||
|
position: Vector3
|
||||||
|
}
|
||||||
|
|
||||||
|
print_pos_1 :: proc(entity: ^Entity) {
|
||||||
|
print_string("print_pos_1: ")
|
||||||
|
print_floats(entity.position.x, entity.position.y, entity.position.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
print_pos_2 :: proc(entity: ^Entity) {
|
||||||
|
using entity
|
||||||
|
print_string("print_pos_2: ")
|
||||||
|
print_floats(position.x, position.y, position.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
print_pos_3 :: proc(using entity: ^Entity) {
|
||||||
|
print_string("print_pos_3: ")
|
||||||
|
print_floats(position.x, position.y, position.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
print_pos_4 :: proc(using entity: ^Entity) {
|
||||||
|
using position
|
||||||
|
print_string("print_pos_4: ")
|
||||||
|
print_floats(x, y, z)
|
||||||
|
}
|
||||||
|
|
||||||
|
e := Entity{position = Vector3{1, 2, 3}}
|
||||||
|
print_pos_1(^e)
|
||||||
|
print_pos_2(^e)
|
||||||
|
print_pos_3(^e)
|
||||||
|
print_pos_4(^e)
|
||||||
|
|
||||||
|
// This is similar to C++'s `this` pointer that is implicit and only available in methods
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subtyping :: proc() {
|
||||||
|
{
|
||||||
|
// C way for subtyping/subclassing
|
||||||
|
|
||||||
|
Entity :: type struct {
|
||||||
|
position: Vector3
|
||||||
|
}
|
||||||
|
|
||||||
|
Frog :: type struct {
|
||||||
|
entity: Entity
|
||||||
|
jump_height: f32
|
||||||
|
}
|
||||||
|
|
||||||
|
f: Frog
|
||||||
|
f.entity.position = Vector3{1, 2, 3}
|
||||||
|
|
||||||
|
using f.entity
|
||||||
|
position = Vector3{1, 2, 3}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// C++ way for subtyping/subclassing
|
||||||
|
|
||||||
|
Entity :: type struct {
|
||||||
|
position: Vector3
|
||||||
|
}
|
||||||
|
|
||||||
|
Frog :: type struct {
|
||||||
|
using entity: Entity
|
||||||
|
jump_height: f32
|
||||||
|
}
|
||||||
|
|
||||||
|
f: Frog
|
||||||
|
f.position = Vector3{1, 2, 3}
|
||||||
|
|
||||||
|
|
||||||
|
print_pos :: proc(using entity: Entity) {
|
||||||
|
print_string("print_pos: ")
|
||||||
|
print_floats(position.x, position.y, position.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
print_pos(f.entity)
|
||||||
|
print_pos(f)
|
||||||
|
|
||||||
|
// Subtype Polymorphism
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// More than C++ way for subtyping/subclassing
|
||||||
|
|
||||||
|
Entity :: type struct {
|
||||||
|
position: Vector3
|
||||||
|
}
|
||||||
|
|
||||||
|
Frog :: type struct {
|
||||||
|
jump_height: f32
|
||||||
|
using entity: ^Entity // Doesn't have to be first member!
|
||||||
|
}
|
||||||
|
|
||||||
|
f: Frog
|
||||||
|
f.entity = new(Entity)
|
||||||
|
f.position = Vector3{1, 2, 3}
|
||||||
|
|
||||||
|
|
||||||
|
print_pos :: proc(using entity: ^Entity) {
|
||||||
|
print_string("print_pos: ")
|
||||||
|
print_floats(position.x, position.y, position.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
print_pos(f.entity)
|
||||||
|
print_pos(^f)
|
||||||
|
print_pos(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// More efficient subtyping
|
||||||
|
|
||||||
|
Entity :: type struct {
|
||||||
|
position: Vector3
|
||||||
|
}
|
||||||
|
|
||||||
|
Frog :: type struct {
|
||||||
|
jump_height: f32
|
||||||
|
using entity: ^Entity
|
||||||
|
}
|
||||||
|
|
||||||
|
MAX_ENTITES :: 64
|
||||||
|
entities: [MAX_ENTITES]Entity
|
||||||
|
entity_count := 0
|
||||||
|
|
||||||
|
next_entity :: proc(entities: []Entity, entity_count: ^int) -> ^Entity {
|
||||||
|
e := ^entities[entity_count^]
|
||||||
|
entity_count^++
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
f: Frog
|
||||||
|
f.entity = next_entity(entities[:], ^entity_count)
|
||||||
|
f.position = Vector3{3, 4, 6}
|
||||||
|
|
||||||
|
using f.position
|
||||||
|
print_floats(x, y, z)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Down casting
|
||||||
|
|
||||||
|
Entity :: type struct {
|
||||||
|
position: Vector3
|
||||||
|
}
|
||||||
|
|
||||||
|
Frog :: type struct {
|
||||||
|
jump_height: f32
|
||||||
|
using entity: Entity
|
||||||
|
}
|
||||||
|
|
||||||
|
f: Frog
|
||||||
|
f.jump_height = 564
|
||||||
|
e := ^f.entity
|
||||||
|
|
||||||
|
frog := e down_cast ^Frog
|
||||||
|
print_string("down_cast: ")
|
||||||
|
print_f32(frog.jump_height); nl()
|
||||||
|
|
||||||
|
// NOTE(bill): `down_cast` is unsafe and there are not check are compile time or run time
|
||||||
|
// Q: Should I completely remove `down_cast` as I added it in about 30 minutes
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Multiple "inheritance"/subclassing
|
||||||
|
|
||||||
|
Entity :: type struct {
|
||||||
|
position: Vector3
|
||||||
|
}
|
||||||
|
Climber :: type struct {
|
||||||
|
speed: f32
|
||||||
|
}
|
||||||
|
|
||||||
|
Frog :: type struct {
|
||||||
|
using entity: Entity
|
||||||
|
using climber: Climber
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tagged_unions :: proc() {
|
||||||
|
{
|
||||||
|
EntityKind :: type enum {
|
||||||
|
INVALID,
|
||||||
|
FROG,
|
||||||
|
GIRAFFE,
|
||||||
|
HELICOPTER,
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity :: type struct {
|
||||||
|
kind: EntityKind
|
||||||
|
using data: raw_union {
|
||||||
|
frog: struct {
|
||||||
|
jump_height: f32
|
||||||
|
colour: u32
|
||||||
|
}
|
||||||
|
giraffe: struct {
|
||||||
|
neck_length: f32
|
||||||
|
spot_count: int
|
||||||
|
}
|
||||||
|
helicopter: struct {
|
||||||
|
blade_count: int
|
||||||
|
weight: f32
|
||||||
|
pilot_name: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e: Entity
|
||||||
|
e.kind = EntityKind.FROG
|
||||||
|
e.frog.jump_height = 12
|
||||||
|
|
||||||
|
f: type_of_val(e.frog);
|
||||||
|
|
||||||
|
// But this is very unsafe and extremely cumbersome to write
|
||||||
|
// In C++, I use macros to alleviate this but it's not a solution
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Entity :: type union {
|
||||||
|
Frog: struct {
|
||||||
|
jump_height: f32
|
||||||
|
colour: u32
|
||||||
|
}
|
||||||
|
Giraffe: struct {
|
||||||
|
neck_length: f32
|
||||||
|
spot_count: int
|
||||||
|
}
|
||||||
|
Helicopter: struct {
|
||||||
|
blade_count: int
|
||||||
|
weight: f32
|
||||||
|
pilot_name: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using Entity
|
||||||
|
f1: Frog = Frog{12, 0xff9900}
|
||||||
|
f2: Entity = Frog{12, 0xff9900} // Implicit cast
|
||||||
|
f3 := Frog{12, 0xff9900} as Entity // Explicit cast
|
||||||
|
|
||||||
|
// f3.Frog.jump_height = 12 // There are "members" of a union
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
e, f, g, h: Entity
|
||||||
|
f = Frog{12, 0xff9900}
|
||||||
|
g = Giraffe{2.1, 23}
|
||||||
|
h = Helicopter{4, 1000, "Frank"}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Requires a pointer to the union
|
||||||
|
// `x` will be a pointer to type of the case
|
||||||
|
|
||||||
|
match type x : ^f {
|
||||||
|
case Frog:
|
||||||
|
print_string("Frog!\n")
|
||||||
|
print_f32(x.jump_height); nl()
|
||||||
|
x.jump_height = 3
|
||||||
|
print_f32(x.jump_height); nl()
|
||||||
|
case Giraffe:
|
||||||
|
print_string("Giraffe!\n")
|
||||||
|
case Helicopter:
|
||||||
|
print_string("ROFLCOPTER!\n")
|
||||||
|
default:
|
||||||
|
print_string("invalid entity\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Q: Allow for a non pointer version with takes a copy instead?
|
||||||
|
// Or it takes the pointer the data and not a copy
|
||||||
|
|
||||||
|
|
||||||
|
fp := ^f as ^Frog // Unsafe
|
||||||
|
print_f32(fp.jump_height); nl()
|
||||||
|
|
||||||
|
|
||||||
|
// Internals of a tagged union
|
||||||
|
/*
|
||||||
|
struct {
|
||||||
|
data: [size_of_biggest_tag]u8
|
||||||
|
tag_index: int
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// This is to allow for pointer casting if needed
|
||||||
|
|
||||||
|
|
||||||
|
// Advantage over subtyping version
|
||||||
|
MAX_ENTITES :: 64
|
||||||
|
entities: [MAX_ENTITES]Entity
|
||||||
|
|
||||||
|
entities[0] = Frog{}
|
||||||
|
entities[1] = Helicopter{}
|
||||||
|
// etc.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
// Transliteration of code from this actual compiler
|
||||||
|
// Some stuff is missing
|
||||||
|
Type :: type struct {}
|
||||||
|
Scope :: type struct {}
|
||||||
|
Token :: type struct {}
|
||||||
|
AstNode :: type struct {}
|
||||||
|
ExactValue :: type struct {}
|
||||||
|
|
||||||
|
EntityKind :: type enum {
|
||||||
|
Invalid,
|
||||||
|
Constant,
|
||||||
|
Variable,
|
||||||
|
UsingVariable,
|
||||||
|
TypeName,
|
||||||
|
Procedure,
|
||||||
|
Builtin,
|
||||||
|
Count,
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity :: type struct {
|
||||||
|
Guid :: type i64
|
||||||
|
|
||||||
|
kind: EntityKind
|
||||||
|
guid: Guid
|
||||||
|
|
||||||
|
scope: ^Scope
|
||||||
|
token: Token
|
||||||
|
type_: ^Type
|
||||||
|
|
||||||
|
using data: raw_union {
|
||||||
|
Constant: struct {
|
||||||
|
value: ExactValue
|
||||||
|
}
|
||||||
|
Variable: struct {
|
||||||
|
visited: bool // Cycle detection
|
||||||
|
used: bool // Variable is used
|
||||||
|
is_field: bool // Is struct field
|
||||||
|
anonymous: bool // Variable is an anonymous
|
||||||
|
}
|
||||||
|
UsingVariable: struct {
|
||||||
|
}
|
||||||
|
TypeName: struct {
|
||||||
|
}
|
||||||
|
Procedure: struct {
|
||||||
|
used: bool
|
||||||
|
}
|
||||||
|
Builtin: struct {
|
||||||
|
id: int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plus all the constructing procedures that go along with them!!!!
|
||||||
|
// It's a nightmare
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Type :: type struct {}
|
||||||
|
Scope :: type struct {}
|
||||||
|
Token :: type struct {}
|
||||||
|
AstNode :: type struct {}
|
||||||
|
ExactValue :: type struct {}
|
||||||
|
|
||||||
|
|
||||||
|
Entity :: type union {
|
||||||
|
Base :: type struct {
|
||||||
|
Guid :: type i64
|
||||||
|
guid: Guid
|
||||||
|
|
||||||
|
scope: ^Scope
|
||||||
|
token: Token
|
||||||
|
type_: ^Type
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Constant: struct {
|
||||||
|
using base: Base
|
||||||
|
value: ExactValue
|
||||||
|
}
|
||||||
|
Variable: struct {
|
||||||
|
using base: Base
|
||||||
|
visited: bool // Cycle detection
|
||||||
|
used: bool // Variable is used
|
||||||
|
is_field: bool // Is struct field
|
||||||
|
anonymous: bool // Variable is an anonymous
|
||||||
|
}
|
||||||
|
UsingVariable: struct {
|
||||||
|
using base: Base
|
||||||
|
}
|
||||||
|
TypeName: struct {
|
||||||
|
using base: Base
|
||||||
|
}
|
||||||
|
Procedure: struct {
|
||||||
|
using base: Base
|
||||||
|
used: bool
|
||||||
|
}
|
||||||
|
Builtin: struct {
|
||||||
|
using base: Base
|
||||||
|
id: int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using Entity
|
||||||
|
|
||||||
|
e: Entity
|
||||||
|
|
||||||
|
e = Variable{
|
||||||
|
base = Base{},
|
||||||
|
used = true,
|
||||||
|
anonymous = false,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Q: Allow a "base" type to be added to a union?
|
||||||
|
// Or even `using` on union to get the same properties?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
// `Raw` unions still have uses, especially for mathematic types
|
||||||
|
|
||||||
|
Vector2 :: type raw_union {
|
||||||
|
using xy_: struct { x, y: f32 }
|
||||||
|
e: [2]f32
|
||||||
|
v: {2}f32
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 :: type raw_union {
|
||||||
|
using xyz_: struct { x, y, z: f32 }
|
||||||
|
xy: Vector2
|
||||||
|
e: [3]f32
|
||||||
|
v: {3}f32
|
||||||
|
}
|
||||||
|
|
||||||
|
v2: Vector2
|
||||||
|
v2.x = 1
|
||||||
|
v2.e[0] = 1
|
||||||
|
v2.v[0] = 1
|
||||||
|
|
||||||
|
v3: Vector3
|
||||||
|
v3.x = 1
|
||||||
|
v3.e[0] = 1
|
||||||
|
v3.v[0] = 1
|
||||||
|
v3.xy.x = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nl :: proc() { print_nl() }
|
||||||
@@ -0,0 +1,412 @@
|
|||||||
|
#load "win32.odin"
|
||||||
|
|
||||||
|
assume :: proc(cond: bool) #foreign "llvm.assume"
|
||||||
|
|
||||||
|
__debug_trap :: proc() #foreign "llvm.debugtrap"
|
||||||
|
__trap :: proc() #foreign "llvm.trap"
|
||||||
|
read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
|
||||||
|
|
||||||
|
bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
|
||||||
|
bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
|
||||||
|
bit_reverse64 :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64"
|
||||||
|
|
||||||
|
byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
|
||||||
|
byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
|
||||||
|
byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
|
||||||
|
|
||||||
|
fmuladd_f32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
|
||||||
|
fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
|
||||||
|
|
||||||
|
// TODO(bill): make custom heap procedures
|
||||||
|
heap_alloc :: proc(len: int) -> rawptr #foreign "malloc"
|
||||||
|
heap_dealloc :: proc(ptr: rawptr) #foreign "free"
|
||||||
|
|
||||||
|
memory_zero :: proc(data: rawptr, len: int) {
|
||||||
|
d := slice_ptr(data as ^byte, len)
|
||||||
|
for i := 0; i < len; i++ {
|
||||||
|
d[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_compare :: proc(dst, src: rawptr, len: int) -> int {
|
||||||
|
s1, s2: ^byte = dst, src
|
||||||
|
for i := 0; i < len; i++ {
|
||||||
|
a := ptr_offset(s1, i)^
|
||||||
|
b := ptr_offset(s2, i)^
|
||||||
|
if a != b {
|
||||||
|
return (a - b) as int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_copy :: proc(dst, src: rawptr, n: int) #inline {
|
||||||
|
if dst == src {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v128b :: type {4}u32
|
||||||
|
assert(align_of(v128b) == 16)
|
||||||
|
|
||||||
|
d, s: ^byte = dst, src
|
||||||
|
|
||||||
|
for ; s as uint % 16 != 0 && n != 0; n-- {
|
||||||
|
d^ = s^
|
||||||
|
d, s = ptr_offset(d, 1), ptr_offset(s, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if d as uint % 16 == 0 {
|
||||||
|
for ; n >= 16; d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 {
|
||||||
|
(d as ^v128b)^ = (s as ^v128b)^
|
||||||
|
}
|
||||||
|
|
||||||
|
if n&8 != 0 {
|
||||||
|
(d as ^u64)^ = (s as ^u64)^
|
||||||
|
d, s = ptr_offset(d, 8), ptr_offset(s, 8)
|
||||||
|
}
|
||||||
|
if n&4 != 0 {
|
||||||
|
(d as ^u32)^ = (s as ^u32)^;
|
||||||
|
d, s = ptr_offset(d, 4), ptr_offset(s, 4)
|
||||||
|
}
|
||||||
|
if n&2 != 0 {
|
||||||
|
(d as ^u16)^ = (s as ^u16)^
|
||||||
|
d, s = ptr_offset(d, 2), ptr_offset(s, 2)
|
||||||
|
}
|
||||||
|
if n&1 != 0 {
|
||||||
|
d^ = s^
|
||||||
|
d, s = ptr_offset(d, 1), ptr_offset(s, 1)
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IMPORTANT NOTE(bill): Little endian only
|
||||||
|
LS :: proc(a, b: u32) -> u32 #inline { return a << b }
|
||||||
|
RS :: proc(a, b: u32) -> u32 #inline { return a >> b }
|
||||||
|
/* NOTE(bill): Big endian version
|
||||||
|
LS :: proc(a, b: u32) -> u32 #inline { return a >> b; }
|
||||||
|
RS :: proc(a, b: u32) -> u32 #inline { return a << b; }
|
||||||
|
*/
|
||||||
|
|
||||||
|
w, x: u32
|
||||||
|
|
||||||
|
if d as uint % 4 == 1 {
|
||||||
|
w = (s as ^u32)^
|
||||||
|
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
|
||||||
|
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
|
||||||
|
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
|
||||||
|
n -= 3
|
||||||
|
|
||||||
|
for n > 16 {
|
||||||
|
d32 := d as ^u32
|
||||||
|
s32 := ptr_offset(s, 1) as ^u32
|
||||||
|
x = s32^; d32^ = LS(w, 24) | RS(x, 8)
|
||||||
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
w = s32^; d32^ = LS(x, 24) | RS(w, 8)
|
||||||
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
x = s32^; d32^ = LS(w, 24) | RS(x, 8)
|
||||||
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
w = s32^; d32^ = LS(x, 24) | RS(w, 8)
|
||||||
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
|
||||||
|
d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if d as uint % 4 == 2 {
|
||||||
|
w = (s as ^u32)^
|
||||||
|
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
|
||||||
|
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
|
||||||
|
n -= 2
|
||||||
|
|
||||||
|
for n > 17 {
|
||||||
|
d32 := d as ^u32
|
||||||
|
s32 := ptr_offset(s, 2) as ^u32
|
||||||
|
x = s32^; d32^ = LS(w, 16) | RS(x, 16)
|
||||||
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
w = s32^; d32^ = LS(x, 16) | RS(w, 16)
|
||||||
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
x = s32^; d32^ = LS(w, 16) | RS(x, 16)
|
||||||
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
w = s32^; d32^ = LS(x, 16) | RS(w, 16)
|
||||||
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
|
||||||
|
d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if d as uint % 4 == 3 {
|
||||||
|
w = (s as ^u32)^
|
||||||
|
d^ = s^
|
||||||
|
n -= 1
|
||||||
|
|
||||||
|
for n > 18 {
|
||||||
|
d32 := d as ^u32
|
||||||
|
s32 := ptr_offset(s, 3) as ^u32
|
||||||
|
x = s32^; d32^ = LS(w, 8) | RS(x, 24)
|
||||||
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
w = s32^; d32^ = LS(x, 8) | RS(w, 24)
|
||||||
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
x = s32^; d32^ = LS(w, 8) | RS(x, 24)
|
||||||
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
w = s32^; d32^ = LS(x, 8) | RS(w, 24)
|
||||||
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
|
||||||
|
d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if n&16 != 0 {
|
||||||
|
(d as ^v128b)^ = (s as ^v128b)^
|
||||||
|
d, s = ptr_offset(d, 16), ptr_offset(s, 16)
|
||||||
|
}
|
||||||
|
if n&8 != 0 {
|
||||||
|
(d as ^u64)^ = (s as ^u64)^
|
||||||
|
d, s = ptr_offset(d, 8), ptr_offset(s, 8)
|
||||||
|
}
|
||||||
|
if n&4 != 0 {
|
||||||
|
(d as ^u32)^ = (s as ^u32)^;
|
||||||
|
d, s = ptr_offset(d, 4), ptr_offset(s, 4)
|
||||||
|
}
|
||||||
|
if n&2 != 0 {
|
||||||
|
(d as ^u16)^ = (s as ^u16)^
|
||||||
|
d, s = ptr_offset(d, 2), ptr_offset(s, 2)
|
||||||
|
}
|
||||||
|
if n&1 != 0 {
|
||||||
|
d^ = s^
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_move :: proc(dst, src: rawptr, n: int) #inline {
|
||||||
|
d, s: ^byte = dst, src
|
||||||
|
if d == s {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if d >= ptr_offset(s, n) || ptr_offset(d, n) <= s {
|
||||||
|
memory_copy(d, s, n)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(bill): Vectorize the shit out of this
|
||||||
|
if d < s {
|
||||||
|
if s as int % size_of(int) == d as int % size_of(int) {
|
||||||
|
for d as int % size_of(int) != 0 {
|
||||||
|
if n == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n--
|
||||||
|
d^ = s^
|
||||||
|
d, s = ptr_offset(d, 1), ptr_offset(s, 1)
|
||||||
|
}
|
||||||
|
di, si := d as ^int, s as ^int
|
||||||
|
for n >= size_of(int) {
|
||||||
|
di^ = si^
|
||||||
|
di, si = ptr_offset(di, 1), ptr_offset(si, 1)
|
||||||
|
n -= size_of(int)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ; n > 0; n-- {
|
||||||
|
d^ = s^
|
||||||
|
d, s = ptr_offset(d, 1), ptr_offset(s, 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if s as int % size_of(int) == d as int % size_of(int) {
|
||||||
|
for ptr_offset(d, n) as int % size_of(int) != 0 {
|
||||||
|
if n == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n--
|
||||||
|
d^ = s^
|
||||||
|
d, s = ptr_offset(d, 1), ptr_offset(s, 1)
|
||||||
|
}
|
||||||
|
for n >= size_of(int) {
|
||||||
|
n -= size_of(int)
|
||||||
|
di := ptr_offset(d, n) as ^int
|
||||||
|
si := ptr_offset(s, n) as ^int
|
||||||
|
di^ = si^
|
||||||
|
}
|
||||||
|
for ; n > 0; n-- {
|
||||||
|
d^ = s^
|
||||||
|
d, s = ptr_offset(d, 1), ptr_offset(s, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for n > 0 {
|
||||||
|
n--
|
||||||
|
dn := ptr_offset(d, n)
|
||||||
|
sn := ptr_offset(s, n)
|
||||||
|
dn^ = sn^
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__string_eq :: proc(a, b: string) -> bool {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if ^a[0] == ^b[0] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return memory_compare(^a[0], ^b[0], len(a)) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
__string_cmp :: proc(a, b : string) -> int {
|
||||||
|
min_len := len(a)
|
||||||
|
if len(b) < min_len {
|
||||||
|
min_len = len(b)
|
||||||
|
}
|
||||||
|
for i := 0; i < min_len; i++ {
|
||||||
|
x := a[i]
|
||||||
|
y := b[i]
|
||||||
|
if x < y {
|
||||||
|
return -1
|
||||||
|
} else if x > y {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(a) < len(b) {
|
||||||
|
return -1
|
||||||
|
} else if len(a) > len(b) {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
__string_ne :: proc(a, b : string) -> bool #inline { return !__string_eq(a, b) }
|
||||||
|
__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0 }
|
||||||
|
__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0 }
|
||||||
|
__string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 }
|
||||||
|
__string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0 }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Allocation_Mode :: type enum {
|
||||||
|
ALLOC,
|
||||||
|
DEALLOC,
|
||||||
|
DEALLOC_ALL,
|
||||||
|
RESIZE,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocation_Mode,
|
||||||
|
size, alignment: int,
|
||||||
|
old_memory: rawptr, old_size: int, flags: u64) -> rawptr
|
||||||
|
|
||||||
|
Allocator :: type struct {
|
||||||
|
procedure: Allocator_Proc;
|
||||||
|
data: rawptr
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Context :: type struct {
|
||||||
|
thread_ptr: rawptr
|
||||||
|
|
||||||
|
user_data: rawptr
|
||||||
|
user_index: int
|
||||||
|
|
||||||
|
allocator: Allocator
|
||||||
|
}
|
||||||
|
|
||||||
|
#thread_local context: Context
|
||||||
|
|
||||||
|
DEFAULT_ALIGNMENT :: 2*size_of(int)
|
||||||
|
|
||||||
|
|
||||||
|
__check_context :: proc() {
|
||||||
|
if context.allocator.procedure == null {
|
||||||
|
context.allocator = __default_allocator()
|
||||||
|
}
|
||||||
|
if context.thread_ptr == null {
|
||||||
|
// TODO(bill):
|
||||||
|
// context.thread_ptr = current_thread_pointer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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, Allocation_Mode.ALLOC, size, alignment, null, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
dealloc :: proc(ptr: rawptr) #inline {
|
||||||
|
__check_context()
|
||||||
|
a := context.allocator
|
||||||
|
_ = a.procedure(a.data, Allocation_Mode.DEALLOC, 0, 0, ptr, 0, 0)
|
||||||
|
}
|
||||||
|
dealloc_all :: proc(ptr: rawptr) #inline {
|
||||||
|
__check_context()
|
||||||
|
a := context.allocator
|
||||||
|
_ = a.procedure(a.data, Allocation_Mode.DEALLOC_ALL, 0, 0, ptr, 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, Allocation_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 == null {
|
||||||
|
return alloc_align(new_size, alignment)
|
||||||
|
}
|
||||||
|
|
||||||
|
if new_size == 0 {
|
||||||
|
dealloc(old_memory)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if new_size == old_size {
|
||||||
|
return old_memory
|
||||||
|
}
|
||||||
|
|
||||||
|
new_memory := alloc_align(new_size, alignment)
|
||||||
|
if new_memory == null {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_copy(new_memory, old_memory, min(old_size, new_size));
|
||||||
|
dealloc(old_memory)
|
||||||
|
return new_memory
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocation_Mode,
|
||||||
|
size, alignment: int,
|
||||||
|
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||||
|
using Allocation_Mode
|
||||||
|
match mode {
|
||||||
|
case ALLOC:
|
||||||
|
return heap_alloc(size)
|
||||||
|
case RESIZE:
|
||||||
|
return default_resize_align(old_memory, old_size, size, alignment)
|
||||||
|
case DEALLOC:
|
||||||
|
heap_dealloc(old_memory)
|
||||||
|
case DEALLOC_ALL:
|
||||||
|
// NOTE(bill): Does nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
__default_allocator :: proc() -> Allocator {
|
||||||
|
return Allocator{
|
||||||
|
__default_allocator_proc,
|
||||||
|
null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
__assert :: proc(msg: string) {
|
||||||
|
file_write(file_get_standard(File_Standard.ERROR), msg as []byte)
|
||||||
|
// TODO(bill): Which is better?
|
||||||
|
// __trap()
|
||||||
|
__debug_trap()
|
||||||
|
}
|
||||||
@@ -68,9 +68,13 @@ byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
|
|||||||
fmuladd_f32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
|
fmuladd_f32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
|
||||||
fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
|
fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
|
||||||
|
|
||||||
// TODO(bill): make custom heap procedures
|
heap_alloc :: proc(len: int) -> rawptr {
|
||||||
heap_alloc :: proc(len: int) -> rawptr #foreign "malloc"
|
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len)
|
||||||
heap_dealloc :: proc(ptr: rawptr) #foreign "free"
|
}
|
||||||
|
|
||||||
|
heap_dealloc :: proc(ptr: rawptr) {
|
||||||
|
_ = HeapFree(GetProcessHeap(), 0, ptr)
|
||||||
|
}
|
||||||
|
|
||||||
memory_zero :: proc(data: rawptr, len: int) {
|
memory_zero :: proc(data: rawptr, len: int) {
|
||||||
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
|
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
|
||||||
@@ -258,6 +262,7 @@ __default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocation_Mode,
|
|||||||
return default_resize_align(old_memory, old_size, size, alignment)
|
return default_resize_align(old_memory, old_size, size, alignment)
|
||||||
case DEALLOC:
|
case DEALLOC:
|
||||||
heap_dealloc(old_memory)
|
heap_dealloc(old_memory)
|
||||||
|
return null
|
||||||
case DEALLOC_ALL:
|
case DEALLOC_ALL:
|
||||||
// NOTE(bill): Does nothing
|
// NOTE(bill): Does nothing
|
||||||
}
|
}
|
||||||
|
|||||||
+141
-141
@@ -242,160 +242,160 @@ wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign
|
|||||||
|
|
||||||
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign
|
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign
|
||||||
|
|
||||||
is_key_down :: proc(key: int) -> bool {
|
is_key_down :: proc(key: Key_Code) -> bool {
|
||||||
return GetAsyncKeyState(key as i32) < 0
|
return GetAsyncKeyState(key as i32) < 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Key_Code :: enum i32 {
|
||||||
|
LBUTTON = 0x01,
|
||||||
|
RBUTTON = 0x02,
|
||||||
|
CANCEL = 0x03,
|
||||||
|
MBUTTON = 0x04,
|
||||||
|
|
||||||
VK_LBUTTON :: 0x01
|
BACK = 0x08,
|
||||||
VK_RBUTTON :: 0x02
|
TAB = 0x09,
|
||||||
VK_CANCEL :: 0x03
|
|
||||||
VK_MBUTTON :: 0x04
|
|
||||||
|
|
||||||
VK_BACK :: 0x08
|
CLEAR = 0x0C,
|
||||||
VK_TAB :: 0x09
|
RETURN = 0x0D,
|
||||||
|
|
||||||
VK_CLEAR :: 0x0C
|
SHIFT = 0x10,
|
||||||
VK_RETURN :: 0x0D
|
CONTROL = 0x11,
|
||||||
|
MENU = 0x12,
|
||||||
|
PAUSE = 0x13,
|
||||||
|
CAPITAL = 0x14,
|
||||||
|
|
||||||
VK_SHIFT :: 0x10
|
KANA = 0x15,
|
||||||
VK_CONTROL :: 0x11
|
HANGEUL = 0x15,
|
||||||
VK_MENU :: 0x12
|
HANGUL = 0x15,
|
||||||
VK_PAUSE :: 0x13
|
JUNJA = 0x17,
|
||||||
VK_CAPITAL :: 0x14
|
FINAL = 0x18,
|
||||||
|
HANJA = 0x19,
|
||||||
|
KANJI = 0x19,
|
||||||
|
|
||||||
VK_KANA :: 0x15
|
ESCAPE = 0x1B,
|
||||||
VK_HANGEUL :: 0x15
|
|
||||||
VK_HANGUL :: 0x15
|
|
||||||
VK_JUNJA :: 0x17
|
|
||||||
VK_FINAL :: 0x18
|
|
||||||
VK_HANJA :: 0x19
|
|
||||||
VK_KANJI :: 0x19
|
|
||||||
|
|
||||||
VK_ESCAPE :: 0x1B
|
CONVERT = 0x1C,
|
||||||
|
NONCONVERT = 0x1D,
|
||||||
|
ACCEPT = 0x1E,
|
||||||
|
MODECHANGE = 0x1F,
|
||||||
|
|
||||||
VK_CONVERT :: 0x1C
|
SPACE = 0x20,
|
||||||
VK_NONCONVERT :: 0x1D
|
PRIOR = 0x21,
|
||||||
VK_ACCEPT :: 0x1E
|
NEXT = 0x22,
|
||||||
VK_MODECHANGE :: 0x1F
|
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,
|
||||||
|
|
||||||
VK_SPACE :: 0x20
|
NUM0 = #rune "0",
|
||||||
VK_PRIOR :: 0x21
|
NUM1 = #rune "1",
|
||||||
VK_NEXT :: 0x22
|
NUM2 = #rune "2",
|
||||||
VK_END :: 0x23
|
NUM3 = #rune "3",
|
||||||
VK_HOME :: 0x24
|
NUM4 = #rune "4",
|
||||||
VK_LEFT :: 0x25
|
NUM5 = #rune "5",
|
||||||
VK_UP :: 0x26
|
NUM6 = #rune "6",
|
||||||
VK_RIGHT :: 0x27
|
NUM7 = #rune "7",
|
||||||
VK_DOWN :: 0x28
|
NUM8 = #rune "8",
|
||||||
VK_SELECT :: 0x29
|
NUM9 = #rune "9",
|
||||||
VK_PRINT :: 0x2A
|
|
||||||
VK_EXECUTE :: 0x2B
|
|
||||||
VK_SNAPSHOT :: 0x2C
|
|
||||||
VK_INSERT :: 0x2D
|
|
||||||
VK_DELETE :: 0x2E
|
|
||||||
VK_HELP :: 0x2F
|
|
||||||
|
|
||||||
VK_0 :: #rune "0"
|
A = #rune "A",
|
||||||
VK_1 :: #rune "1"
|
B = #rune "B",
|
||||||
VK_2 :: #rune "2"
|
C = #rune "C",
|
||||||
VK_3 :: #rune "3"
|
D = #rune "D",
|
||||||
VK_4 :: #rune "4"
|
E = #rune "E",
|
||||||
VK_5 :: #rune "5"
|
F = #rune "F",
|
||||||
VK_6 :: #rune "6"
|
G = #rune "G",
|
||||||
VK_7 :: #rune "7"
|
H = #rune "H",
|
||||||
VK_8 :: #rune "8"
|
I = #rune "I",
|
||||||
VK_9 :: #rune "9"
|
J = #rune "J",
|
||||||
|
K = #rune "K",
|
||||||
|
L = #rune "L",
|
||||||
|
M = #rune "M",
|
||||||
|
N = #rune "N",
|
||||||
|
O = #rune "O",
|
||||||
|
P = #rune "P",
|
||||||
|
Q = #rune "Q",
|
||||||
|
R = #rune "R",
|
||||||
|
S = #rune "S",
|
||||||
|
T = #rune "T",
|
||||||
|
U = #rune "U",
|
||||||
|
V = #rune "V",
|
||||||
|
W = #rune "W",
|
||||||
|
X = #rune "X",
|
||||||
|
Y = #rune "Y",
|
||||||
|
Z = #rune "Z",
|
||||||
|
|
||||||
VK_A :: #rune "A"
|
LWIN = 0x5B,
|
||||||
VK_B :: #rune "B"
|
RWIN = 0x5C,
|
||||||
VK_C :: #rune "C"
|
APPS = 0x5D,
|
||||||
VK_D :: #rune "D"
|
|
||||||
VK_E :: #rune "E"
|
|
||||||
VK_F :: #rune "F"
|
|
||||||
VK_G :: #rune "G"
|
|
||||||
VK_H :: #rune "H"
|
|
||||||
VK_I :: #rune "I"
|
|
||||||
VK_J :: #rune "J"
|
|
||||||
VK_K :: #rune "K"
|
|
||||||
VK_L :: #rune "L"
|
|
||||||
VK_M :: #rune "M"
|
|
||||||
VK_N :: #rune "N"
|
|
||||||
VK_O :: #rune "O"
|
|
||||||
VK_P :: #rune "P"
|
|
||||||
VK_Q :: #rune "Q"
|
|
||||||
VK_R :: #rune "R"
|
|
||||||
VK_S :: #rune "S"
|
|
||||||
VK_T :: #rune "T"
|
|
||||||
VK_U :: #rune "U"
|
|
||||||
VK_V :: #rune "V"
|
|
||||||
VK_W :: #rune "W"
|
|
||||||
VK_X :: #rune "X"
|
|
||||||
VK_Y :: #rune "Y"
|
|
||||||
VK_Z :: #rune "Z"
|
|
||||||
|
|
||||||
VK_LWIN :: 0x5B
|
NUMPAD0 = 0x60,
|
||||||
VK_RWIN :: 0x5C
|
NUMPAD1 = 0x61,
|
||||||
VK_APPS :: 0x5D
|
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,
|
||||||
|
|
||||||
VK_NUMPAD0 :: 0x60
|
NUMLOCK = 0x90,
|
||||||
VK_NUMPAD1 :: 0x61
|
SCROLL = 0x91,
|
||||||
VK_NUMPAD2 :: 0x62
|
|
||||||
VK_NUMPAD3 :: 0x63
|
|
||||||
VK_NUMPAD4 :: 0x64
|
|
||||||
VK_NUMPAD5 :: 0x65
|
|
||||||
VK_NUMPAD6 :: 0x66
|
|
||||||
VK_NUMPAD7 :: 0x67
|
|
||||||
VK_NUMPAD8 :: 0x68
|
|
||||||
VK_NUMPAD9 :: 0x69
|
|
||||||
VK_MULTIPLY :: 0x6A
|
|
||||||
VK_ADD :: 0x6B
|
|
||||||
VK_SEPARATOR :: 0x6C
|
|
||||||
VK_SUBTRACT :: 0x6D
|
|
||||||
VK_DECIMAL :: 0x6E
|
|
||||||
VK_DIVIDE :: 0x6F
|
|
||||||
VK_F1 :: 0x70
|
|
||||||
VK_F2 :: 0x71
|
|
||||||
VK_F3 :: 0x72
|
|
||||||
VK_F4 :: 0x73
|
|
||||||
VK_F5 :: 0x74
|
|
||||||
VK_F6 :: 0x75
|
|
||||||
VK_F7 :: 0x76
|
|
||||||
VK_F8 :: 0x77
|
|
||||||
VK_F9 :: 0x78
|
|
||||||
VK_F10 :: 0x79
|
|
||||||
VK_F11 :: 0x7A
|
|
||||||
VK_F12 :: 0x7B
|
|
||||||
VK_F13 :: 0x7C
|
|
||||||
VK_F14 :: 0x7D
|
|
||||||
VK_F15 :: 0x7E
|
|
||||||
VK_F16 :: 0x7F
|
|
||||||
VK_F17 :: 0x80
|
|
||||||
VK_F18 :: 0x81
|
|
||||||
VK_F19 :: 0x82
|
|
||||||
VK_F20 :: 0x83
|
|
||||||
VK_F21 :: 0x84
|
|
||||||
VK_F22 :: 0x85
|
|
||||||
VK_F23 :: 0x86
|
|
||||||
VK_F24 :: 0x87
|
|
||||||
|
|
||||||
VK_NUMLOCK :: 0x90
|
|
||||||
VK_SCROLL :: 0x91
|
|
||||||
|
|
||||||
VK_LSHIFT :: 0xA0
|
|
||||||
VK_RSHIFT :: 0xA1
|
|
||||||
VK_LCONTROL :: 0xA2
|
|
||||||
VK_RCONTROL :: 0xA3
|
|
||||||
VK_LMENU :: 0xA4
|
|
||||||
VK_RMENU :: 0xA5
|
|
||||||
VK_PROCESSKEY :: 0xE5
|
|
||||||
VK_ATTN :: 0xF6
|
|
||||||
VK_CRSEL :: 0xF7
|
|
||||||
VK_EXSEL :: 0xF8
|
|
||||||
VK_EREOF :: 0xF9
|
|
||||||
VK_PLAY :: 0xFA
|
|
||||||
VK_ZOOM :: 0xFB
|
|
||||||
VK_NONAME :: 0xFC
|
|
||||||
VK_PA1 :: 0xFD
|
|
||||||
VK_OEM_CLEAR :: 0xFE
|
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|||||||
+31
-11
@@ -57,11 +57,31 @@ void add_type_info_type(Checker *c, Type *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
map_set(&c->info.type_info_types, hash_pointer(t), t);
|
map_set(&c->info.type_info_types, hash_pointer(t), t);
|
||||||
|
|
||||||
|
if (t->kind == Type_Named) {
|
||||||
|
// NOTE(bill): Just in case
|
||||||
|
add_type_info_type(c, t->Named.base);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Type *bt = get_base_type(t);
|
Type *bt = get_base_type(t);
|
||||||
switch (bt->kind) {
|
switch (bt->kind) {
|
||||||
case Type_Named: add_type_info_type(c, bt->Named.base); break;
|
case Type_Basic: {
|
||||||
case Type_Array: add_type_info_type(c, bt->Array.elem); break;
|
if (bt->Basic.kind == Basic_string) {
|
||||||
case Type_Slice: add_type_info_type(c, bt->Slice.elem); break;
|
add_type_info_type(c, make_type_pointer(c->allocator, t_u8));
|
||||||
|
add_type_info_type(c, t_int);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Type_Array:
|
||||||
|
add_type_info_type(c, bt->Array.elem);
|
||||||
|
add_type_info_type(c, make_type_pointer(c->allocator, bt->Array.elem));
|
||||||
|
add_type_info_type(c, t_int);
|
||||||
|
break;
|
||||||
|
case Type_Slice:
|
||||||
|
add_type_info_type(c, bt->Slice.elem);
|
||||||
|
add_type_info_type(c, make_type_pointer(c->allocator, bt->Slice.elem));
|
||||||
|
add_type_info_type(c, t_int);
|
||||||
|
break;
|
||||||
case Type_Vector: add_type_info_type(c, bt->Vector.elem); break;
|
case Type_Vector: add_type_info_type(c, bt->Vector.elem); break;
|
||||||
case Type_Pointer: add_type_info_type(c, bt->Pointer.elem); break;
|
case Type_Pointer: add_type_info_type(c, bt->Pointer.elem); break;
|
||||||
case Type_Record: {
|
case Type_Record: {
|
||||||
@@ -1372,7 +1392,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
|
|||||||
x->mode = Addressing_Value;
|
x->mode = Addressing_Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 check_castable_to(Checker *c, Operand *operand, Type *y) {
|
b32 check_is_castable_to(Checker *c, Operand *operand, Type *y) {
|
||||||
if (check_is_assignable_to(c, operand, y))
|
if (check_is_assignable_to(c, operand, y))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -1387,20 +1407,20 @@ b32 check_castable_to(Checker *c, Operand *operand, Type *y) {
|
|||||||
|
|
||||||
|
|
||||||
// Cast between booleans and integers
|
// Cast between booleans and integers
|
||||||
if (is_type_boolean(x) || is_type_integer(x)) {
|
if (is_type_boolean(xb) || is_type_integer(xb)) {
|
||||||
if (is_type_boolean(y) || is_type_integer(y))
|
if (is_type_boolean(yb) || is_type_integer(yb))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast between numbers
|
// Cast between numbers
|
||||||
if (is_type_integer(x) || is_type_float(x)) {
|
if (is_type_integer(xb) || is_type_float(xb)) {
|
||||||
if (is_type_integer(y) || is_type_float(y))
|
if (is_type_integer(yb) || is_type_float(yb))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast between pointers
|
// Cast between pointers
|
||||||
if (is_type_pointer(x)) {
|
if (is_type_pointer(xb)) {
|
||||||
if (is_type_pointer(y))
|
if (is_type_pointer(yb))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1494,7 +1514,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
|||||||
can_convert = true;
|
can_convert = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (check_castable_to(c, x, type)) {
|
} else if (check_is_castable_to(c, x, type)) {
|
||||||
x->mode = Addressing_Value;
|
x->mode = Addressing_Value;
|
||||||
can_convert = true;
|
can_convert = true;
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-10
@@ -706,8 +706,8 @@ void selection_add_index(Selection *s, isize index) {
|
|||||||
gb_array_append(s->index, index);
|
gb_array_append(s->index, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_global Entity *entity_any_type_info = NULL;
|
gb_global Entity *entity__any_type_info = NULL;
|
||||||
gb_global Entity *entity_any_data = NULL;
|
gb_global Entity *entity__any_data = NULL;
|
||||||
|
|
||||||
Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) {
|
Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) {
|
||||||
GB_ASSERT(type_ != NULL);
|
GB_ASSERT(type_ != NULL);
|
||||||
@@ -721,29 +721,31 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
|
|||||||
type = get_base_type(type);
|
type = get_base_type(type);
|
||||||
|
|
||||||
if (type->kind == Type_Basic) {
|
if (type->kind == Type_Basic) {
|
||||||
if (type->Basic.kind == Basic_any) {
|
switch (type->Basic.kind) {
|
||||||
|
case Basic_any: {
|
||||||
String type_info_str = make_string("type_info");
|
String type_info_str = make_string("type_info");
|
||||||
String data_str = make_string("data");
|
String data_str = make_string("data");
|
||||||
if (entity_any_type_info == NULL) {
|
if (entity__any_type_info == NULL) {
|
||||||
Token token = {Token_Identifier};
|
Token token = {Token_Identifier};
|
||||||
token.string = type_info_str;
|
token.string = type_info_str;
|
||||||
entity_any_type_info = make_entity_field(gb_heap_allocator(), NULL, token, t_type_info_ptr, false);
|
entity__any_type_info = make_entity_field(gb_heap_allocator(), NULL, token, t_type_info_ptr, false);
|
||||||
}
|
}
|
||||||
if (entity_any_data == NULL) {
|
if (entity__any_data == NULL) {
|
||||||
Token token = {Token_Identifier};
|
Token token = {Token_Identifier};
|
||||||
token.string = data_str;
|
token.string = data_str;
|
||||||
entity_any_data = make_entity_field(gb_heap_allocator(), NULL, token, t_type_info_ptr, false);
|
entity__any_data = make_entity_field(gb_heap_allocator(), NULL, token, t_rawptr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (are_strings_equal(field_name, type_info_str)) {
|
if (are_strings_equal(field_name, type_info_str)) {
|
||||||
selection_add_index(&sel, 0);
|
selection_add_index(&sel, 0);
|
||||||
sel.entity = entity_any_type_info;
|
sel.entity = entity__any_type_info;
|
||||||
return sel;
|
return sel;
|
||||||
} else if (are_strings_equal(field_name, data_str)) {
|
} else if (are_strings_equal(field_name, data_str)) {
|
||||||
selection_add_index(&sel, 1);
|
selection_add_index(&sel, 1);
|
||||||
sel.entity = entity_any_data;
|
sel.entity = entity__any_data;
|
||||||
return sel;
|
return sel;
|
||||||
}
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sel;
|
return sel;
|
||||||
@@ -916,8 +918,11 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
|||||||
if (size > 0)
|
if (size > 0)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
if (kind == Basic_string)
|
if (kind == Basic_string) {
|
||||||
return 2 * s.word_size;
|
return 2 * s.word_size;
|
||||||
|
} else if (kind == Basic_any) {
|
||||||
|
return 2 * s.word_size;
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Type_Array: {
|
case Type_Array: {
|
||||||
|
|||||||
+2
-2
@@ -3184,9 +3184,9 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
|||||||
fall = ssa__make_block(proc, clause, make_string("match.fall.body"));
|
fall = ssa__make_block(proc, clause, make_string("match.fall.body"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gb_array_count(cc->list)) {
|
if (gb_array_count(cc->list) == 0) {
|
||||||
// default case
|
// default case
|
||||||
default_stmts = cc->stmts;
|
default_stmts = cc->stmts;
|
||||||
default_fall = fall;
|
default_fall = fall;
|
||||||
default_block = body;
|
default_block = body;
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
+2
-1
@@ -78,6 +78,7 @@ enum CallExprKind {
|
|||||||
AstNodeArray make_ast_node_array(AstFile *f) {
|
AstNodeArray make_ast_node_array(AstFile *f) {
|
||||||
AstNodeArray a;
|
AstNodeArray a;
|
||||||
gb_array_init(a, gb_arena_allocator(&f->arena));
|
gb_array_init(a, gb_arena_allocator(&f->arena));
|
||||||
|
GB_ASSERT(a != NULL);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2220,7 +2221,7 @@ AstNode *parse_for_stmt(AstFile *f) {
|
|||||||
|
|
||||||
AstNode *parse_case_clause(AstFile *f) {
|
AstNode *parse_case_clause(AstFile *f) {
|
||||||
Token token = f->cursor[0];
|
Token token = f->cursor[0];
|
||||||
AstNodeArray list = NULL;
|
AstNodeArray list = make_ast_node_array(f);
|
||||||
if (allow_token(f, Token_case)) {
|
if (allow_token(f, Token_case)) {
|
||||||
list = parse_rhs_expr_list(f);
|
list = parse_rhs_expr_list(f);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -323,6 +323,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
|
|||||||
char *c_str = gb_alloc_array(gb_heap_allocator(), char, fullpath.len+1);
|
char *c_str = gb_alloc_array(gb_heap_allocator(), char, fullpath.len+1);
|
||||||
memcpy(c_str, fullpath.text, fullpath.len);
|
memcpy(c_str, fullpath.text, fullpath.len);
|
||||||
c_str[fullpath.len] = '\0';
|
c_str[fullpath.len] = '\0';
|
||||||
|
|
||||||
defer (gb_free(gb_heap_allocator(), c_str));
|
defer (gb_free(gb_heap_allocator(), c_str));
|
||||||
|
|
||||||
gbFileContents fc = gb_file_read_contents(gb_heap_allocator(), true, c_str);
|
gbFileContents fc = gb_file_read_contents(gb_heap_allocator(), true, c_str);
|
||||||
|
|||||||
Reference in New Issue
Block a user