mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-13 01:21:38 -07: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;
|
||||
if arg.data != null {
|
||||
match info.size {
|
||||
case 1: u = (arg.data as ^u8)^ as uint
|
||||
case 2: u = (arg.data as ^u16)^ as uint
|
||||
case 4: u = (arg.data as ^u32)^ as uint
|
||||
case 8: u = (arg.data as ^u64)^ as uint
|
||||
case 1: u = (arg.data as ^u8)^ as uint
|
||||
case 2: u = (arg.data as ^u16)^ as uint
|
||||
case 4: u = (arg.data as ^u32)^ as uint
|
||||
case 8: u = (arg.data as ^u64)^ 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;
|
||||
if arg.data != null {
|
||||
match info.size {
|
||||
case 1: v = (arg.data as ^i8)^ as int
|
||||
case 2: v = (arg.data as ^i16)^ as int
|
||||
case 4: v = (arg.data as ^i32)^ as int
|
||||
case 8: v = (arg.data as ^i64)^ as int
|
||||
case 1: v = (arg.data as ^i8)^ as int
|
||||
case 2: v = (arg.data as ^i16)^ as int
|
||||
case 4: v = (arg.data as ^i32)^ as int
|
||||
case 8: v = (arg.data as ^i64)^ as int
|
||||
case 16: v = (arg.data as ^i128)^ as int
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#load "basic.odin"
|
||||
#load "math.odin"
|
||||
|
||||
main :: proc() {
|
||||
a: any = 1
|
||||
println(137, "Hello", 1.25, true)
|
||||
}
|
||||
|
||||
+10
-9
@@ -16,9 +16,7 @@ time_now :: proc() -> f64 {
|
||||
win32_print_last_error :: proc() {
|
||||
err_code := GetLastError() as int
|
||||
if err_code != 0 {
|
||||
print_string("GetLastError: ")
|
||||
print_int(err_code)
|
||||
print_string("\n")
|
||||
println("GetLastError:", err_code)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +44,8 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W
|
||||
|
||||
class_name := "Win32-Odin-Window\x00"
|
||||
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)
|
||||
|
||||
@@ -59,6 +58,7 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W
|
||||
};
|
||||
|
||||
if RegisterClassExA(^w.wc) == 0 {
|
||||
win32_print_last_error( )
|
||||
return w, false
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@ run_game :: proc() {
|
||||
return DefWindowProcA(hwnd, msg, wparam, lparam)
|
||||
}
|
||||
|
||||
|
||||
window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc)
|
||||
if !window_success {
|
||||
return
|
||||
@@ -155,7 +156,7 @@ run_game :: proc() {
|
||||
_ = DispatchMessageA(^msg)
|
||||
}
|
||||
|
||||
if is_key_down(VK_ESCAPE) {
|
||||
if is_key_down(Key_Code.ESCAPE) {
|
||||
running = false
|
||||
}
|
||||
|
||||
@@ -163,10 +164,10 @@ run_game :: proc() {
|
||||
SPEED :: 500
|
||||
v: Vec2
|
||||
|
||||
if is_key_down(VK_RIGHT) { v[0] += 1 }
|
||||
if is_key_down(VK_LEFT) { v[0] -= 1 }
|
||||
if is_key_down(VK_UP) { v[1] += 1 }
|
||||
if is_key_down(VK_DOWN) { v[1] -= 1 }
|
||||
if is_key_down(Key_Code.RIGHT) { v[0] += 1 }
|
||||
if is_key_down(Key_Code.LEFT) { v[0] -= 1 }
|
||||
if is_key_down(Key_Code.UP) { v[1] += 1 }
|
||||
if is_key_down(Key_Code.DOWN) { v[1] -= 1 }
|
||||
|
||||
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_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"
|
||||
heap_alloc :: proc(len: int) -> rawptr {
|
||||
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len)
|
||||
}
|
||||
|
||||
heap_dealloc :: proc(ptr: rawptr) {
|
||||
_ = HeapFree(GetProcessHeap(), 0, ptr)
|
||||
}
|
||||
|
||||
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"
|
||||
@@ -258,6 +262,7 @@ __default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocation_Mode,
|
||||
return default_resize_align(old_memory, old_size, size, alignment)
|
||||
case DEALLOC:
|
||||
heap_dealloc(old_memory)
|
||||
return null
|
||||
case DEALLOC_ALL:
|
||||
// NOTE(bill): Does nothing
|
||||
}
|
||||
|
||||
+141
-141
@@ -242,160 +242,160 @@ wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #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
|
||||
}
|
||||
|
||||
Key_Code :: enum i32 {
|
||||
LBUTTON = 0x01,
|
||||
RBUTTON = 0x02,
|
||||
CANCEL = 0x03,
|
||||
MBUTTON = 0x04,
|
||||
|
||||
VK_LBUTTON :: 0x01
|
||||
VK_RBUTTON :: 0x02
|
||||
VK_CANCEL :: 0x03
|
||||
VK_MBUTTON :: 0x04
|
||||
BACK = 0x08,
|
||||
TAB = 0x09,
|
||||
|
||||
VK_BACK :: 0x08
|
||||
VK_TAB :: 0x09
|
||||
CLEAR = 0x0C,
|
||||
RETURN = 0x0D,
|
||||
|
||||
VK_CLEAR :: 0x0C
|
||||
VK_RETURN :: 0x0D
|
||||
SHIFT = 0x10,
|
||||
CONTROL = 0x11,
|
||||
MENU = 0x12,
|
||||
PAUSE = 0x13,
|
||||
CAPITAL = 0x14,
|
||||
|
||||
VK_SHIFT :: 0x10
|
||||
VK_CONTROL :: 0x11
|
||||
VK_MENU :: 0x12
|
||||
VK_PAUSE :: 0x13
|
||||
VK_CAPITAL :: 0x14
|
||||
KANA = 0x15,
|
||||
HANGEUL = 0x15,
|
||||
HANGUL = 0x15,
|
||||
JUNJA = 0x17,
|
||||
FINAL = 0x18,
|
||||
HANJA = 0x19,
|
||||
KANJI = 0x19,
|
||||
|
||||
VK_KANA :: 0x15
|
||||
VK_HANGEUL :: 0x15
|
||||
VK_HANGUL :: 0x15
|
||||
VK_JUNJA :: 0x17
|
||||
VK_FINAL :: 0x18
|
||||
VK_HANJA :: 0x19
|
||||
VK_KANJI :: 0x19
|
||||
ESCAPE = 0x1B,
|
||||
|
||||
VK_ESCAPE :: 0x1B
|
||||
CONVERT = 0x1C,
|
||||
NONCONVERT = 0x1D,
|
||||
ACCEPT = 0x1E,
|
||||
MODECHANGE = 0x1F,
|
||||
|
||||
VK_CONVERT :: 0x1C
|
||||
VK_NONCONVERT :: 0x1D
|
||||
VK_ACCEPT :: 0x1E
|
||||
VK_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,
|
||||
|
||||
VK_SPACE :: 0x20
|
||||
VK_PRIOR :: 0x21
|
||||
VK_NEXT :: 0x22
|
||||
VK_END :: 0x23
|
||||
VK_HOME :: 0x24
|
||||
VK_LEFT :: 0x25
|
||||
VK_UP :: 0x26
|
||||
VK_RIGHT :: 0x27
|
||||
VK_DOWN :: 0x28
|
||||
VK_SELECT :: 0x29
|
||||
VK_PRINT :: 0x2A
|
||||
VK_EXECUTE :: 0x2B
|
||||
VK_SNAPSHOT :: 0x2C
|
||||
VK_INSERT :: 0x2D
|
||||
VK_DELETE :: 0x2E
|
||||
VK_HELP :: 0x2F
|
||||
NUM0 = #rune "0",
|
||||
NUM1 = #rune "1",
|
||||
NUM2 = #rune "2",
|
||||
NUM3 = #rune "3",
|
||||
NUM4 = #rune "4",
|
||||
NUM5 = #rune "5",
|
||||
NUM6 = #rune "6",
|
||||
NUM7 = #rune "7",
|
||||
NUM8 = #rune "8",
|
||||
NUM9 = #rune "9",
|
||||
|
||||
VK_0 :: #rune "0"
|
||||
VK_1 :: #rune "1"
|
||||
VK_2 :: #rune "2"
|
||||
VK_3 :: #rune "3"
|
||||
VK_4 :: #rune "4"
|
||||
VK_5 :: #rune "5"
|
||||
VK_6 :: #rune "6"
|
||||
VK_7 :: #rune "7"
|
||||
VK_8 :: #rune "8"
|
||||
VK_9 :: #rune "9"
|
||||
A = #rune "A",
|
||||
B = #rune "B",
|
||||
C = #rune "C",
|
||||
D = #rune "D",
|
||||
E = #rune "E",
|
||||
F = #rune "F",
|
||||
G = #rune "G",
|
||||
H = #rune "H",
|
||||
I = #rune "I",
|
||||
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"
|
||||
VK_B :: #rune "B"
|
||||
VK_C :: #rune "C"
|
||||
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"
|
||||
LWIN = 0x5B,
|
||||
RWIN = 0x5C,
|
||||
APPS = 0x5D,
|
||||
|
||||
VK_LWIN :: 0x5B
|
||||
VK_RWIN :: 0x5C
|
||||
VK_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,
|
||||
|
||||
VK_NUMPAD0 :: 0x60
|
||||
VK_NUMPAD1 :: 0x61
|
||||
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
|
||||
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,
|
||||
}
|
||||
|
||||
+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);
|
||||
|
||||
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);
|
||||
switch (bt->kind) {
|
||||
case Type_Named: add_type_info_type(c, bt->Named.base); break;
|
||||
case Type_Array: add_type_info_type(c, bt->Array.elem); break;
|
||||
case Type_Slice: add_type_info_type(c, bt->Slice.elem); break;
|
||||
case Type_Basic: {
|
||||
if (bt->Basic.kind == Basic_string) {
|
||||
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_Pointer: add_type_info_type(c, bt->Pointer.elem); break;
|
||||
case Type_Record: {
|
||||
@@ -1372,7 +1392,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
|
||||
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))
|
||||
return true;
|
||||
|
||||
@@ -1387,20 +1407,20 @@ b32 check_castable_to(Checker *c, Operand *operand, Type *y) {
|
||||
|
||||
|
||||
// Cast between booleans and integers
|
||||
if (is_type_boolean(x) || is_type_integer(x)) {
|
||||
if (is_type_boolean(y) || is_type_integer(y))
|
||||
if (is_type_boolean(xb) || is_type_integer(xb)) {
|
||||
if (is_type_boolean(yb) || is_type_integer(yb))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cast between numbers
|
||||
if (is_type_integer(x) || is_type_float(x)) {
|
||||
if (is_type_integer(y) || is_type_float(y))
|
||||
if (is_type_integer(xb) || is_type_float(xb)) {
|
||||
if (is_type_integer(yb) || is_type_float(yb))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cast between pointers
|
||||
if (is_type_pointer(x)) {
|
||||
if (is_type_pointer(y))
|
||||
if (is_type_pointer(xb)) {
|
||||
if (is_type_pointer(yb))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1494,7 +1514,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
can_convert = true;
|
||||
}
|
||||
}
|
||||
} else if (check_castable_to(c, x, type)) {
|
||||
} else if (check_is_castable_to(c, x, type)) {
|
||||
x->mode = Addressing_Value;
|
||||
can_convert = true;
|
||||
}
|
||||
|
||||
+15
-10
@@ -706,8 +706,8 @@ void selection_add_index(Selection *s, isize index) {
|
||||
gb_array_append(s->index, index);
|
||||
}
|
||||
|
||||
gb_global Entity *entity_any_type_info = NULL;
|
||||
gb_global Entity *entity_any_data = NULL;
|
||||
gb_global Entity *entity__any_type_info = NULL;
|
||||
gb_global Entity *entity__any_data = NULL;
|
||||
|
||||
Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) {
|
||||
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);
|
||||
|
||||
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 data_str = make_string("data");
|
||||
if (entity_any_type_info == NULL) {
|
||||
if (entity__any_type_info == NULL) {
|
||||
Token token = {Token_Identifier};
|
||||
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.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)) {
|
||||
selection_add_index(&sel, 0);
|
||||
sel.entity = entity_any_type_info;
|
||||
sel.entity = entity__any_type_info;
|
||||
return sel;
|
||||
} else if (are_strings_equal(field_name, data_str)) {
|
||||
selection_add_index(&sel, 1);
|
||||
sel.entity = entity_any_data;
|
||||
sel.entity = entity__any_data;
|
||||
return sel;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
return sel;
|
||||
@@ -916,8 +918,11 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||
if (size > 0)
|
||||
return size;
|
||||
}
|
||||
if (kind == Basic_string)
|
||||
if (kind == Basic_string) {
|
||||
return 2 * s.word_size;
|
||||
} else if (kind == Basic_any) {
|
||||
return 2 * s.word_size;
|
||||
}
|
||||
} break;
|
||||
|
||||
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"));
|
||||
}
|
||||
|
||||
if (gb_array_count(cc->list)) {
|
||||
if (gb_array_count(cc->list) == 0) {
|
||||
// default case
|
||||
default_stmts = cc->stmts;
|
||||
default_stmts = cc->stmts;
|
||||
default_fall = fall;
|
||||
default_block = body;
|
||||
continue;
|
||||
|
||||
+2
-1
@@ -78,6 +78,7 @@ enum CallExprKind {
|
||||
AstNodeArray make_ast_node_array(AstFile *f) {
|
||||
AstNodeArray a;
|
||||
gb_array_init(a, gb_arena_allocator(&f->arena));
|
||||
GB_ASSERT(a != NULL);
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -2220,7 +2221,7 @@ AstNode *parse_for_stmt(AstFile *f) {
|
||||
|
||||
AstNode *parse_case_clause(AstFile *f) {
|
||||
Token token = f->cursor[0];
|
||||
AstNodeArray list = NULL;
|
||||
AstNodeArray list = make_ast_node_array(f);
|
||||
if (allow_token(f, Token_case)) {
|
||||
list = parse_rhs_expr_list(f);
|
||||
} 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);
|
||||
memcpy(c_str, fullpath.text, fullpath.len);
|
||||
c_str[fullpath.len] = '\0';
|
||||
|
||||
defer (gb_free(gb_heap_allocator(), c_str));
|
||||
|
||||
gbFileContents fc = gb_file_read_contents(gb_heap_allocator(), true, c_str);
|
||||
|
||||
Reference in New Issue
Block a user