mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 23:28:48 +00:00
Begin Type_Info
Missing stuff in records, procedures, and tuples
This commit is contained in:
@@ -51,7 +51,7 @@ pushd %build_dir%
|
|||||||
|
|
||||||
cl %compiler_settings% "..\src\main.cpp" ^
|
cl %compiler_settings% "..\src\main.cpp" ^
|
||||||
/link %linker_settings% -OUT:%exe_name% ^
|
/link %linker_settings% -OUT:%exe_name% ^
|
||||||
&& odin ..\examples/demo.odin
|
&& odin run ..\examples/demo.odin
|
||||||
rem odin run ..\examples/demo.odin
|
rem odin run ..\examples/demo.odin
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+30
-868
@@ -1,874 +1,36 @@
|
|||||||
// Demo 002
|
|
||||||
#load "basic.odin"
|
#load "basic.odin"
|
||||||
#load "game.odin"
|
#load "math.odin"
|
||||||
|
|
||||||
#thread_local tls_int: int
|
|
||||||
|
print_type_info_kind :: proc(info: ^Type_Info) {
|
||||||
|
using Type_Info
|
||||||
|
match type i : info {
|
||||||
|
case Named: print_string("Named\n")
|
||||||
|
case Integer: print_string("Integer\n")
|
||||||
|
case Float: print_string("Float\n")
|
||||||
|
case String: print_string("String\n")
|
||||||
|
case Boolean: print_string("Boolean\n")
|
||||||
|
case Pointer: print_string("Pointer\n")
|
||||||
|
case Procedure: print_string("Procedure\n")
|
||||||
|
case Array: print_string("Array\n")
|
||||||
|
case Slice: print_string("Slice\n")
|
||||||
|
case Vector: print_string("Vector\n")
|
||||||
|
case Struct: print_string("Struct\n")
|
||||||
|
case Union: print_string("Union\n")
|
||||||
|
case Raw_Union: print_string("RawUnion\n")
|
||||||
|
case Enum: print_string("Enum\n")
|
||||||
|
default: print_string("void\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
// Forenotes
|
i: int
|
||||||
|
s: struct {
|
||||||
|
x, y, z: f32
|
||||||
|
}
|
||||||
|
p := ^s
|
||||||
|
|
||||||
// Semicolons are now optional
|
print_type_info_kind(type_info(i))
|
||||||
// Rule for when a semicolon is expected after a statement
|
print_type_info_kind(type_info(s))
|
||||||
// - If the next token is not on the same line
|
print_type_info_kind(type_info(p))
|
||||||
// - 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
|
|
||||||
// g: int = Fruit.BANANA
|
|
||||||
g: int = Fruit.BANANA as int
|
|
||||||
}
|
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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?
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
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 := 2; 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 = 78456
|
|
||||||
name = "Thing"
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// Multiple "inheritance"
|
|
||||||
|
|
||||||
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
|
|
||||||
// Q: Allow for a non pointer version with takes a copy instead?
|
|
||||||
match type ^f -> x {
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {}
|
|
||||||
|
|
||||||
|
|
||||||
EntityBase :: type struct {
|
|
||||||
Guid :: type i64
|
|
||||||
guid: Guid
|
|
||||||
|
|
||||||
scope: ^Scope
|
|
||||||
token: Token
|
|
||||||
type_: ^Type
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity :: type union {
|
|
||||||
Constant: struct {
|
|
||||||
using base: EntityBase
|
|
||||||
value: ExactValue
|
|
||||||
}
|
|
||||||
Variable: struct {
|
|
||||||
using base: EntityBase
|
|
||||||
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: EntityBase
|
|
||||||
}
|
|
||||||
TypeName: struct {
|
|
||||||
using base: EntityBase
|
|
||||||
}
|
|
||||||
Procedure: struct {
|
|
||||||
using base: EntityBase
|
|
||||||
used: bool
|
|
||||||
}
|
|
||||||
Builtin: struct {
|
|
||||||
using base: EntityBase
|
|
||||||
id: int
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
using Entity
|
|
||||||
|
|
||||||
e: Entity
|
|
||||||
|
|
||||||
e = Variable{
|
|
||||||
base = EntityBase{},
|
|
||||||
used = true,
|
|
||||||
anonymous = false,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Q: Allow a "base" type to be added to a union?
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
// `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
|
|
||||||
|
|
||||||
// Q: If I applied using to a vector element in a raw_union,
|
|
||||||
// should that type now act as if it was a vector?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nl :: proc() { print_nl() }
|
|
||||||
|
|||||||
+102
-224
@@ -1,10 +1,68 @@
|
|||||||
#load "win32.odin"
|
#load "win32.odin"
|
||||||
|
|
||||||
|
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
||||||
|
// The compiler relies upon this _exact_ order
|
||||||
|
Type_Info :: union {
|
||||||
|
Member :: struct {
|
||||||
|
name: string
|
||||||
|
type_: ^Type_Info
|
||||||
|
offset: int
|
||||||
|
}
|
||||||
|
Record :: struct {
|
||||||
|
fields: []Member
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Named: struct {
|
||||||
|
name: string
|
||||||
|
base: ^Type_Info
|
||||||
|
}
|
||||||
|
Integer: struct {
|
||||||
|
bits: int
|
||||||
|
signed: bool
|
||||||
|
}
|
||||||
|
Float: struct {
|
||||||
|
bits: int
|
||||||
|
}
|
||||||
|
String: struct {}
|
||||||
|
Boolean: struct {}
|
||||||
|
Pointer: struct {
|
||||||
|
elem: ^Type_Info
|
||||||
|
}
|
||||||
|
Procedure: struct{}
|
||||||
|
Array: struct {
|
||||||
|
elem: ^Type_Info
|
||||||
|
count: int
|
||||||
|
}
|
||||||
|
Slice: struct {
|
||||||
|
elem: ^Type_Info
|
||||||
|
}
|
||||||
|
Vector: struct {
|
||||||
|
elem: ^Type_Info
|
||||||
|
count: int
|
||||||
|
}
|
||||||
|
Struct: Record
|
||||||
|
Union: Record
|
||||||
|
Raw_Union: Record
|
||||||
|
Enum: struct {
|
||||||
|
base: ^Type_Info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Any :: struct {
|
||||||
|
type_info: ^Type_Info
|
||||||
|
// pointer to the data stored
|
||||||
|
data: rawptr
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
assume :: proc(cond: bool) #foreign "llvm.assume"
|
assume :: proc(cond: bool) #foreign "llvm.assume"
|
||||||
|
|
||||||
__debug_trap :: proc() #foreign "llvm.debugtrap"
|
__debug_trap :: proc() #foreign "llvm.debugtrap"
|
||||||
__trap :: proc() #foreign "llvm.trap"
|
__trap :: proc() #foreign "llvm.trap"
|
||||||
read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
|
read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
|
||||||
|
|
||||||
bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
|
bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
|
||||||
bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
|
bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
|
||||||
@@ -22,218 +80,29 @@ heap_alloc :: proc(len: int) -> rawptr #foreign "malloc"
|
|||||||
heap_dealloc :: proc(ptr: rawptr) #foreign "free"
|
heap_dealloc :: proc(ptr: rawptr) #foreign "free"
|
||||||
|
|
||||||
memory_zero :: proc(data: rawptr, len: int) {
|
memory_zero :: proc(data: rawptr, len: int) {
|
||||||
d := slice_ptr(data as ^byte, len)
|
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
|
||||||
for i := 0; i < len; i++ {
|
llvm_memset_64bit(data, 0, len, 1, false)
|
||||||
d[i] = 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_compare :: proc(dst, src: rawptr, len: int) -> int {
|
memory_compare :: proc(dst, src: rawptr, len: int) -> int {
|
||||||
s1, s2: ^byte = dst, src
|
// TODO(bill): make a faster `memory_compare`
|
||||||
|
a, b := slice_ptr(dst as ^byte, len), slice_ptr(src as ^byte, len)
|
||||||
for i := 0; i < len; i++ {
|
for i := 0; i < len; i++ {
|
||||||
a := ptr_offset(s1, i)^
|
if a[i] != b[i] {
|
||||||
b := ptr_offset(s2, i)^
|
return (a[i] - b[i]) as int
|
||||||
if a != b {
|
|
||||||
return (a - b) as int
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_copy :: proc(dst, src: rawptr, n: int) #inline {
|
memory_copy :: proc(dst, src: rawptr, len: int) #inline {
|
||||||
if dst == src {
|
llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
|
||||||
return
|
llvm_memcpy_64bit(dst, src, len, 1, false)
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
memory_move :: proc(dst, src: rawptr, len: int) #inline {
|
||||||
d, s: ^byte = dst, src
|
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
|
||||||
if d == s {
|
llvm_memmove_64bit(dst, src, len, 1, false)
|
||||||
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 {
|
__string_eq :: proc(a, b: string) -> bool {
|
||||||
@@ -247,25 +116,36 @@ __string_eq :: proc(a, b: string) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
__string_cmp :: proc(a, b : string) -> int {
|
__string_cmp :: proc(a, b : string) -> int {
|
||||||
min_len := len(a)
|
// Translation of http://mgronhol.github.io/fast-strcmp/
|
||||||
if len(b) < min_len {
|
n := min(len(a), len(b))
|
||||||
min_len = len(b)
|
|
||||||
|
fast := n/size_of(int) + 1
|
||||||
|
offset := (fast-1)*size_of(int)
|
||||||
|
curr_block := 0
|
||||||
|
if n <= size_of(int) {
|
||||||
|
fast = 0
|
||||||
}
|
}
|
||||||
for i := 0; i < min_len; i++ {
|
|
||||||
x := a[i]
|
la := slice_ptr(^a[0] as ^int, fast)
|
||||||
y := b[i]
|
lb := slice_ptr(^b[0] as ^int, fast)
|
||||||
if x < y {
|
|
||||||
return -1
|
for ; curr_block < fast; curr_block++ {
|
||||||
} else if x > y {
|
if (la[curr_block] ~ lb[curr_block]) != 0 {
|
||||||
return +1
|
for pos := curr_block*size_of(int); pos < n; pos++ {
|
||||||
|
if (a[pos] ~ b[pos]) != 0 {
|
||||||
|
return a[pos] as int - b[pos] as int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for ; offset < n; offset++ {
|
||||||
|
if (a[offset] ~ b[offset]) != 0 {
|
||||||
|
return a[offset] as int - b[offset] as int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(a) < len(b) {
|
|
||||||
return -1
|
|
||||||
} else if len(a) > len(b) {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,26 +158,24 @@ __string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Allocation_Mode :: type enum {
|
Allocation_Mode :: enum {
|
||||||
ALLOC,
|
ALLOC,
|
||||||
DEALLOC,
|
DEALLOC,
|
||||||
DEALLOC_ALL,
|
DEALLOC_ALL,
|
||||||
RESIZE,
|
RESIZE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocation_Mode,
|
Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocation_Mode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr
|
old_memory: rawptr, old_size: int, flags: u64) -> rawptr
|
||||||
|
|
||||||
Allocator :: type struct {
|
Allocator :: struct {
|
||||||
procedure: Allocator_Proc;
|
procedure: Allocator_Proc;
|
||||||
data: rawptr
|
data: rawptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Context :: type struct {
|
Context :: struct {
|
||||||
thread_ptr: rawptr
|
thread_ptr: rawptr
|
||||||
|
|
||||||
user_data: rawptr
|
user_data: rawptr
|
||||||
|
|||||||
+3
-3
@@ -42,7 +42,7 @@ INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE
|
|||||||
|
|
||||||
WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
|
WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
|
||||||
|
|
||||||
WNDCLASSEXA :: type struct {
|
WNDCLASSEXA :: struct {
|
||||||
size, style: u32
|
size, style: u32
|
||||||
wnd_proc: WNDPROC
|
wnd_proc: WNDPROC
|
||||||
cls_extra, wnd_extra: i32
|
cls_extra, wnd_extra: i32
|
||||||
@@ -54,7 +54,7 @@ WNDCLASSEXA :: type struct {
|
|||||||
sm: HICON
|
sm: HICON
|
||||||
}
|
}
|
||||||
|
|
||||||
MSG :: type struct {
|
MSG :: struct {
|
||||||
hwnd: HWND
|
hwnd: HWND
|
||||||
message: u32
|
message: u32
|
||||||
wparam: WPARAM
|
wparam: WPARAM
|
||||||
@@ -191,7 +191,7 @@ PROC :: type proc()
|
|||||||
wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC
|
wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC
|
||||||
|
|
||||||
|
|
||||||
PIXELFORMATDESCRIPTOR :: type struct {
|
PIXELFORMATDESCRIPTOR :: struct {
|
||||||
size,
|
size,
|
||||||
version,
|
version,
|
||||||
flags: u32
|
flags: u32
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
+41
-14
@@ -150,6 +150,8 @@ enum BuiltinProcId {
|
|||||||
BuiltinProc_max,
|
BuiltinProc_max,
|
||||||
BuiltinProc_abs,
|
BuiltinProc_abs,
|
||||||
|
|
||||||
|
BuiltinProc_type_info,
|
||||||
|
|
||||||
BuiltinProc_Count,
|
BuiltinProc_Count,
|
||||||
};
|
};
|
||||||
struct BuiltinProc {
|
struct BuiltinProc {
|
||||||
@@ -188,6 +190,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
|||||||
{STR_LIT("min"), 2, false, Expr_Expr},
|
{STR_LIT("min"), 2, false, Expr_Expr},
|
||||||
{STR_LIT("max"), 2, false, Expr_Expr},
|
{STR_LIT("max"), 2, false, Expr_Expr},
|
||||||
{STR_LIT("abs"), 1, false, Expr_Expr},
|
{STR_LIT("abs"), 1, false, Expr_Expr},
|
||||||
|
|
||||||
|
{STR_LIT("type_info"), 1, false, Expr_Expr},
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CheckerContext {
|
struct CheckerContext {
|
||||||
@@ -197,13 +201,14 @@ struct CheckerContext {
|
|||||||
|
|
||||||
// NOTE(bill): Symbol tables
|
// NOTE(bill): Symbol tables
|
||||||
struct CheckerInfo {
|
struct CheckerInfo {
|
||||||
Map<TypeAndValue> types; // Key: AstNode * | Expression -> Type (and value)
|
Map<TypeAndValue> types; // Key: AstNode * | Expression -> Type (and value)
|
||||||
Map<Entity *> definitions; // Key: AstNode * | Identifier -> Entity
|
Map<Entity *> definitions; // Key: AstNode * | Identifier -> Entity
|
||||||
Map<Entity *> uses; // Key: AstNode * | Identifier -> Entity
|
Map<Entity *> uses; // Key: AstNode * | Identifier -> Entity
|
||||||
Map<Scope *> scopes; // Key: AstNode * | Node -> Scope
|
Map<Scope *> scopes; // Key: AstNode * | Node -> Scope
|
||||||
Map<ExpressionInfo> untyped; // Key: AstNode * | Expression -> ExpressionInfo
|
Map<ExpressionInfo> untyped; // Key: AstNode * | Expression -> ExpressionInfo
|
||||||
Map<DeclInfo *> entities; // Key: Entity *
|
Map<DeclInfo *> entities; // Key: Entity *
|
||||||
Map<Entity *> foreign_procs; // Key: String
|
Map<Entity *> foreign_procs; // Key: String
|
||||||
|
Map<Type *> type_info_types; // Key: Type *
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Checker {
|
struct Checker {
|
||||||
@@ -383,6 +388,26 @@ void add_global_constant(gbAllocator a, String name, Type *type, ExactValue valu
|
|||||||
add_global_entity(entity);
|
add_global_entity(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Type *t_type_info = NULL;
|
||||||
|
Type *t_type_info_ptr = NULL;
|
||||||
|
|
||||||
|
Type *t_type_info_named = NULL;
|
||||||
|
Type *t_type_info_integer = NULL;
|
||||||
|
Type *t_type_info_float = NULL;
|
||||||
|
Type *t_type_info_string = NULL;
|
||||||
|
Type *t_type_info_boolean = NULL;
|
||||||
|
Type *t_type_info_pointer = NULL;
|
||||||
|
Type *t_type_info_procedure = NULL;
|
||||||
|
Type *t_type_info_array = NULL;
|
||||||
|
Type *t_type_info_slice = NULL;
|
||||||
|
Type *t_type_info_vector = NULL;
|
||||||
|
Type *t_type_info_struct = NULL;
|
||||||
|
Type *t_type_info_union = NULL;
|
||||||
|
Type *t_type_info_raw_union = NULL;
|
||||||
|
Type *t_type_info_enum = NULL;
|
||||||
|
|
||||||
|
|
||||||
void init_universal_scope(void) {
|
void init_universal_scope(void) {
|
||||||
// NOTE(bill): No need to free these
|
// NOTE(bill): No need to free these
|
||||||
gbAllocator a = gb_heap_allocator();
|
gbAllocator a = gb_heap_allocator();
|
||||||
@@ -425,13 +450,14 @@ void init_universal_scope(void) {
|
|||||||
|
|
||||||
void init_checker_info(CheckerInfo *i) {
|
void init_checker_info(CheckerInfo *i) {
|
||||||
gbAllocator a = gb_heap_allocator();
|
gbAllocator a = gb_heap_allocator();
|
||||||
map_init(&i->types, a);
|
map_init(&i->types, a);
|
||||||
map_init(&i->definitions, a);
|
map_init(&i->definitions, a);
|
||||||
map_init(&i->uses, a);
|
map_init(&i->uses, a);
|
||||||
map_init(&i->scopes, a);
|
map_init(&i->scopes, a);
|
||||||
map_init(&i->entities, a);
|
map_init(&i->entities, a);
|
||||||
map_init(&i->untyped, a);
|
map_init(&i->untyped, a);
|
||||||
map_init(&i->foreign_procs, a);
|
map_init(&i->foreign_procs, a);
|
||||||
|
map_init(&i->type_info_types, a);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,6 +469,7 @@ void destroy_checker_info(CheckerInfo *i) {
|
|||||||
map_destroy(&i->entities);
|
map_destroy(&i->entities);
|
||||||
map_destroy(&i->untyped);
|
map_destroy(&i->untyped);
|
||||||
map_destroy(&i->foreign_procs);
|
map_destroy(&i->foreign_procs);
|
||||||
|
map_destroy(&i->type_info_types);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1900,6 +1900,42 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_type_info_type(Checker *c, Type *t) {
|
||||||
|
if (t == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t = default_type(t);
|
||||||
|
if (map_get(&c->info.type_info_types, hash_pointer(t)) != NULL) {
|
||||||
|
// Types have already been added
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
map_set(&c->info.type_info_types, hash_pointer(t), t);
|
||||||
|
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_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: {
|
||||||
|
switch (bt->Record.kind) {
|
||||||
|
case TypeRecord_Enum:
|
||||||
|
add_type_info_type(c, bt->Record.enum_base);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
for (isize i = 0; i < bt->Record.field_count; i++) {
|
||||||
|
Entity *f = bt->Record.fields[i];
|
||||||
|
add_type_info_type(c, f->type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
// TODO(bill): Type info for procedures and tuples
|
||||||
|
// TODO(bill): Remove duplicate identical types efficiently
|
||||||
|
}
|
||||||
|
|
||||||
b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) {
|
b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) {
|
||||||
GB_ASSERT(call->kind == AstNode_CallExpr);
|
GB_ASSERT(call->kind == AstNode_CallExpr);
|
||||||
ast_node(ce, CallExpr, call);
|
ast_node(ce, CallExpr, call);
|
||||||
@@ -2652,6 +2688,38 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
|||||||
operand->type = type;
|
operand->type = type;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
||||||
|
case BuiltinProc_type_info: {
|
||||||
|
if (t_type_info == NULL) {
|
||||||
|
String type_info_str = make_string("Type_Info");
|
||||||
|
Entity **found = map_get(&c->global_scope->elements, hash_string(type_info_str));
|
||||||
|
GB_ASSERT_MSG(found != NULL, "Internal Compiler Error: Could not find type declaration for `Type_Info`");
|
||||||
|
Entity *e = *found;
|
||||||
|
t_type_info = e->type;
|
||||||
|
t_type_info_ptr = make_type_pointer(c->allocator, t_type_info);
|
||||||
|
|
||||||
|
auto *record = &get_base_type(e->type)->Record;
|
||||||
|
GB_ASSERT(record->field_count == 15);
|
||||||
|
t_type_info_named = record->fields[ 1]->type;
|
||||||
|
t_type_info_integer = record->fields[ 2]->type;
|
||||||
|
t_type_info_float = record->fields[ 3]->type;
|
||||||
|
t_type_info_string = record->fields[ 4]->type;
|
||||||
|
t_type_info_boolean = record->fields[ 5]->type;
|
||||||
|
t_type_info_pointer = record->fields[ 6]->type;
|
||||||
|
t_type_info_procedure = record->fields[ 7]->type;
|
||||||
|
t_type_info_array = record->fields[ 8]->type;
|
||||||
|
t_type_info_slice = record->fields[ 9]->type;
|
||||||
|
t_type_info_vector = record->fields[10]->type;
|
||||||
|
t_type_info_struct = record->fields[11]->type;
|
||||||
|
t_type_info_union = record->fields[12]->type;
|
||||||
|
t_type_info_raw_union = record->fields[13]->type;
|
||||||
|
t_type_info_enum = record->fields[14]->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_type_info_type(c, operand->type);
|
||||||
|
operand->mode = Addressing_Value;
|
||||||
|
operand->type = t_type_info_ptr;
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+143
-21
@@ -31,27 +31,6 @@ b32 ssa_gen_init(ssaGen *s, Checker *c) {
|
|||||||
if (err != gbFileError_None)
|
if (err != gbFileError_None)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
#if 0
|
|
||||||
Map<i32> type_map; // Key: Type *
|
|
||||||
map_init(&type_map, gb_heap_allocator());
|
|
||||||
i32 index = 0;
|
|
||||||
gb_for_array(i, c->info.types.entries) {
|
|
||||||
TypeAndValue tav = c->info.types.entries[i].value;
|
|
||||||
Type *type = tav.type;
|
|
||||||
HashKey key = hash_pointer(type);
|
|
||||||
auto found = map_get(&type_map, key);
|
|
||||||
if (!found) {
|
|
||||||
map_set(&type_map, key, index);
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gb_for_array(i, type_map.entries) {
|
|
||||||
auto *e = &type_map.entries[i];
|
|
||||||
Type *t = cast(Type *)cast(uintptr)e->key.key;
|
|
||||||
gb_printf("%s\n", type_to_string(t));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,6 +178,149 @@ void ssa_gen_tree(ssaGen *s) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ // NOTE(bill): Setup type_info data
|
||||||
|
ssaValue **found = map_get(&proc->module->members, hash_string(make_string("__type_info_data")));
|
||||||
|
GB_ASSERT(found != NULL);
|
||||||
|
ssaValue *type_info_data = *found;
|
||||||
|
CheckerInfo *info = proc->module->info;
|
||||||
|
|
||||||
|
|
||||||
|
Type *t_int_ptr = make_type_pointer(a, t_int);
|
||||||
|
Type *t_bool_ptr = make_type_pointer(a, t_bool);
|
||||||
|
Type *t_string_ptr = make_type_pointer(a, t_string);
|
||||||
|
Type *t_type_info_ptr_ptr = make_type_pointer(a, t_type_info_ptr);
|
||||||
|
|
||||||
|
auto get_type_info_ptr = [](ssaProcedure *proc, ssaValue *type_info_data, Type *type) -> ssaValue * {
|
||||||
|
auto *info = proc->module->info;
|
||||||
|
MapFindResult fr = map__find(&info->type_info_types, hash_pointer(type));
|
||||||
|
GB_ASSERT(fr.entry_index >= 0);
|
||||||
|
return ssa_emit_struct_gep(proc, type_info_data, fr.entry_index, t_type_info_ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
gb_for_array(entry_index, info->type_info_types.entries) {
|
||||||
|
auto *entry = &info->type_info_types.entries[entry_index];
|
||||||
|
Type *t = entry->value;
|
||||||
|
|
||||||
|
ssaValue *tag = NULL;
|
||||||
|
|
||||||
|
switch (t->kind) {
|
||||||
|
case Type_Named: {
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_named);
|
||||||
|
|
||||||
|
ssaValue *gsa = ssa_add_global_string_array(proc, make_exact_value_string(t->Named.name));
|
||||||
|
ssaValue *elem = ssa_array_elem(proc, gsa);
|
||||||
|
ssaValue *len = ssa_array_len(proc, ssa_emit_load(proc, gsa));
|
||||||
|
ssaValue *name = ssa_emit_string(proc, elem, len);
|
||||||
|
|
||||||
|
ssaValue *gep = get_type_info_ptr(proc, type_info_data, t->Named.base);
|
||||||
|
|
||||||
|
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_zero, t_string_ptr), name);
|
||||||
|
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_one32, t_type_info_ptr), gep);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Type_Basic:
|
||||||
|
switch (t->Basic.kind) {
|
||||||
|
case Basic_bool:
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_boolean);
|
||||||
|
break;
|
||||||
|
case Basic_i8:
|
||||||
|
case Basic_i16:
|
||||||
|
case Basic_i32:
|
||||||
|
case Basic_i64:
|
||||||
|
case Basic_i128:
|
||||||
|
case Basic_u8:
|
||||||
|
case Basic_u16:
|
||||||
|
case Basic_u32:
|
||||||
|
case Basic_u64:
|
||||||
|
case Basic_u128:
|
||||||
|
case Basic_int:
|
||||||
|
case Basic_uint: {
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_integer);
|
||||||
|
b32 is_unsigned = (basic_types[t->Basic.kind].flags & BasicFlag_Unsigned) != 0;
|
||||||
|
ssaValue *bits = ssa_make_value_constant(a, t_int, make_exact_value_integer(8*type_size_of(m->sizes, a, t)));
|
||||||
|
ssaValue *is_signed = ssa_make_value_constant(a, t_bool, make_exact_value_bool(!is_unsigned));
|
||||||
|
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_zero32, t_int_ptr), bits);
|
||||||
|
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_one32, t_bool_ptr), is_signed);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Basic_f32:
|
||||||
|
case Basic_f64: {
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_float);
|
||||||
|
ssaValue *bits = ssa_make_value_constant(a, t_int, make_exact_value_integer(8*type_size_of(m->sizes, a, t)));
|
||||||
|
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_zero32, t_int_ptr), bits);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Basic_rawptr:
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_pointer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Basic_string:
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_string);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Type_Pointer: {
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_pointer);
|
||||||
|
ssaValue *gep = get_type_info_ptr(proc, type_info_data, t->Pointer.elem);
|
||||||
|
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_zero32, t_type_info_ptr_ptr), gep);
|
||||||
|
} break;
|
||||||
|
case Type_Array: {
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_array);
|
||||||
|
ssaValue *gep = get_type_info_ptr(proc, type_info_data, t->Array.elem);
|
||||||
|
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_zero32, t_type_info_ptr_ptr), gep);
|
||||||
|
} break;
|
||||||
|
case Type_Slice: {
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_slice);
|
||||||
|
ssaValue *gep = get_type_info_ptr(proc, type_info_data, t->Slice.elem);
|
||||||
|
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_zero32, t_type_info_ptr_ptr), gep);
|
||||||
|
} break;
|
||||||
|
case Type_Vector: {
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_vector);
|
||||||
|
ssaValue *gep = get_type_info_ptr(proc, type_info_data, t->Vector.elem);
|
||||||
|
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_zero32, t_type_info_ptr_ptr), gep);
|
||||||
|
} break;
|
||||||
|
case Type_Record: {
|
||||||
|
switch (t->Record.kind) {
|
||||||
|
// TODO(bill): Record members for `Type_Info`
|
||||||
|
case TypeRecord_Struct:
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_struct);
|
||||||
|
break;
|
||||||
|
case TypeRecord_Union:
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_union);
|
||||||
|
break;
|
||||||
|
case TypeRecord_RawUnion:
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_raw_union);
|
||||||
|
break;
|
||||||
|
case TypeRecord_Enum: {
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_enum);
|
||||||
|
Type *enum_base = t->Record.enum_base;
|
||||||
|
if (enum_base == NULL) {
|
||||||
|
enum_base = t_int;
|
||||||
|
}
|
||||||
|
ssaValue *gep = get_type_info_ptr(proc, type_info_data, enum_base);
|
||||||
|
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_zero32, t_type_info_ptr_ptr), gep);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Type_Tuple:
|
||||||
|
// TODO(bill): Type_Info for tuples
|
||||||
|
break;
|
||||||
|
case Type_Proc:
|
||||||
|
// TODO(bill): Type_Info for procedures
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag != NULL) {
|
||||||
|
ssaValue *gep = ssa_emit_struct_gep(proc, type_info_data, entry_index, t_type_info_ptr);
|
||||||
|
ssaValue *val = ssa_emit_conv(proc, ssa_emit_load(proc, tag), t_type_info);
|
||||||
|
ssa_emit_store(proc, gep, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ssa_end_procedure_body(proc);
|
ssa_end_procedure_body(proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ
|
|||||||
|
|
||||||
void ssa_print_block_name(ssaFileBuffer *f, ssaBlock *b) {
|
void ssa_print_block_name(ssaFileBuffer *f, ssaBlock *b) {
|
||||||
ssa_print_escape_string(f, b->label, false);
|
ssa_print_escape_string(f, b->label, false);
|
||||||
ssa_fprintf(f, "..%d", b->id);
|
ssa_fprintf(f, "-%d", b->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type_hint) {
|
void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type_hint) {
|
||||||
@@ -352,7 +352,9 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
|
|||||||
|
|
||||||
switch (instr->kind) {
|
switch (instr->kind) {
|
||||||
case ssaInstr_StartupRuntime: {
|
case ssaInstr_StartupRuntime: {
|
||||||
ssa_fprintf(f, "call void @." SSA_STARTUP_RUNTIME_PROC_NAME "()\n");
|
ssa_fprintf(f, "call void ");
|
||||||
|
ssa_print_encoded_global(f, make_string(SSA_STARTUP_RUNTIME_PROC_NAME));
|
||||||
|
ssa_fprintf(f, "()\n");
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case ssaInstr_Comment:
|
case ssaInstr_Comment:
|
||||||
@@ -642,20 +644,6 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
|
|||||||
ssa_fprintf(f, "\n");
|
ssa_fprintf(f, "\n");
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case ssaInstr_MemCopy: {
|
|
||||||
ssa_fprintf(f, "call void @.memory_move");
|
|
||||||
ssa_fprintf(f, "(i8* ");
|
|
||||||
ssa_print_value(f, m, instr->CopyMemory.dst, t_rawptr);
|
|
||||||
ssa_fprintf(f, ", i8* ");
|
|
||||||
ssa_print_value(f, m, instr->CopyMemory.src, t_rawptr);
|
|
||||||
ssa_fprintf(f, ", ");
|
|
||||||
ssa_print_type(f, m->sizes, t_int);
|
|
||||||
ssa_fprintf(f, " ");
|
|
||||||
ssa_print_value(f, m, instr->CopyMemory.len, t_int);
|
|
||||||
ssa_fprintf(f, ")\n");
|
|
||||||
} break;
|
|
||||||
|
|
||||||
|
|
||||||
case ssaInstr_ExtractElement: {
|
case ssaInstr_ExtractElement: {
|
||||||
Type *vt = ssa_type(instr->ExtractElement.vector);
|
Type *vt = ssa_type(instr->ExtractElement.vector);
|
||||||
ssa_fprintf(f, "%%%d = extractelement ", value->id);
|
ssa_fprintf(f, "%%%d = extractelement ", value->id);
|
||||||
|
|||||||
+64
-46
@@ -85,7 +85,6 @@ struct ssaProcedure {
|
|||||||
SSA_INSTR_KIND(Unreachable), \
|
SSA_INSTR_KIND(Unreachable), \
|
||||||
SSA_INSTR_KIND(BinaryOp), \
|
SSA_INSTR_KIND(BinaryOp), \
|
||||||
SSA_INSTR_KIND(Call), \
|
SSA_INSTR_KIND(Call), \
|
||||||
SSA_INSTR_KIND(MemCopy), \
|
|
||||||
SSA_INSTR_KIND(NoOp), \
|
SSA_INSTR_KIND(NoOp), \
|
||||||
SSA_INSTR_KIND(ExtractElement), \
|
SSA_INSTR_KIND(ExtractElement), \
|
||||||
SSA_INSTR_KIND(InsertElement), \
|
SSA_INSTR_KIND(InsertElement), \
|
||||||
@@ -198,13 +197,6 @@ struct ssaInstr {
|
|||||||
ssaValue **args;
|
ssaValue **args;
|
||||||
isize arg_count;
|
isize arg_count;
|
||||||
} Call;
|
} Call;
|
||||||
struct {
|
|
||||||
ssaValue *dst, *src;
|
|
||||||
ssaValue *len;
|
|
||||||
i32 align;
|
|
||||||
b32 is_volatile;
|
|
||||||
} CopyMemory;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
ssaValue *vector;
|
ssaValue *vector;
|
||||||
ssaValue *index;
|
ssaValue *index;
|
||||||
@@ -315,6 +307,25 @@ void ssa_module_init(ssaModule *m, Checker *c) {
|
|||||||
|
|
||||||
map_init(&m->values, gb_heap_allocator());
|
map_init(&m->values, gb_heap_allocator());
|
||||||
map_init(&m->members, gb_heap_allocator());
|
map_init(&m->members, gb_heap_allocator());
|
||||||
|
|
||||||
|
{
|
||||||
|
// Add type info data
|
||||||
|
ssaValue *ssa_make_value_global(gbAllocator a, Entity *e, ssaValue *value);
|
||||||
|
|
||||||
|
|
||||||
|
String name = make_string("__type_info_data");
|
||||||
|
Token token = {};
|
||||||
|
token.kind = Token_Identifier;
|
||||||
|
token.string = name;
|
||||||
|
|
||||||
|
|
||||||
|
isize count = gb_array_count(c->info.type_info_types.entries);
|
||||||
|
Entity *e = make_entity_variable(m->allocator, NULL, token, make_type_array(m->allocator, t_type_info, count));
|
||||||
|
ssaValue *g = ssa_make_value_global(m->allocator, e, NULL);
|
||||||
|
g->Global.is_private = true;
|
||||||
|
map_set(&m->values, hash_pointer(e), g);
|
||||||
|
map_set(&m->members, hash_string(name), g);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssa_module_destroy(ssaModule *m) {
|
void ssa_module_destroy(ssaModule *m) {
|
||||||
@@ -356,9 +367,6 @@ Type *ssa_type(ssaInstr *instr) {
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
} break;
|
} break;
|
||||||
case ssaInstr_MemCopy:
|
|
||||||
return t_int;
|
|
||||||
|
|
||||||
case ssaInstr_ExtractElement: {
|
case ssaInstr_ExtractElement: {
|
||||||
Type *vt = ssa_type(instr->ExtractElement.vector);
|
Type *vt = ssa_type(instr->ExtractElement.vector);
|
||||||
Type *bt = base_vector_type(get_base_type(vt));
|
Type *bt = base_vector_type(get_base_type(vt));
|
||||||
@@ -545,16 +553,6 @@ ssaValue *ssa_make_instr_call(ssaProcedure *p, ssaValue *value, ssaValue **args,
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssaValue *ssa_make_instr_copy_memory(ssaProcedure *p, ssaValue *dst, ssaValue *src, ssaValue *len, i32 align, b32 is_volatile) {
|
|
||||||
ssaValue *v = ssa_alloc_instr(p, ssaInstr_MemCopy);
|
|
||||||
v->Instr.CopyMemory.dst = dst;
|
|
||||||
v->Instr.CopyMemory.src = src;
|
|
||||||
v->Instr.CopyMemory.len = len;
|
|
||||||
v->Instr.CopyMemory.align = align;
|
|
||||||
v->Instr.CopyMemory.is_volatile = is_volatile;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssaValue *ssa_make_instr_conv(ssaProcedure *p, ssaConvKind kind, ssaValue *value, Type *from, Type *to) {
|
ssaValue *ssa_make_instr_conv(ssaProcedure *p, ssaConvKind kind, ssaValue *value, Type *from, Type *to) {
|
||||||
ssaValue *v = ssa_alloc_instr(p, ssaInstr_Conv);
|
ssaValue *v = ssa_alloc_instr(p, ssaInstr_Conv);
|
||||||
v->Instr.Conv.kind = kind;
|
v->Instr.Conv.kind = kind;
|
||||||
@@ -925,7 +923,6 @@ void ssa_end_procedure_body(ssaProcedure *proc) {
|
|||||||
case ssaInstr_Br:
|
case ssaInstr_Br:
|
||||||
case ssaInstr_Ret:
|
case ssaInstr_Ret:
|
||||||
case ssaInstr_Unreachable:
|
case ssaInstr_Unreachable:
|
||||||
case ssaInstr_MemCopy:
|
|
||||||
case ssaInstr_StartupRuntime:
|
case ssaInstr_StartupRuntime:
|
||||||
continue;
|
continue;
|
||||||
case ssaInstr_Call:
|
case ssaInstr_Call:
|
||||||
@@ -2008,11 +2005,13 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
|||||||
make_exact_value_integer(size_of_elem));
|
make_exact_value_integer(size_of_elem));
|
||||||
ssaValue *byte_count = ssa_emit_arith(proc, mul, len, elem_size, t_int);
|
ssaValue *byte_count = ssa_emit_arith(proc, mul, len, elem_size, t_int);
|
||||||
|
|
||||||
|
ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 3);
|
||||||
|
args[0] = dst;
|
||||||
|
args[1] = src;
|
||||||
|
args[2] = byte_count;
|
||||||
|
|
||||||
i32 align = cast(i32)type_align_of(proc->module->sizes, proc->module->allocator, elem_type);
|
ssa_emit_global_call(proc, "memory_move", args, 3);
|
||||||
b32 is_volatile = false;
|
|
||||||
|
|
||||||
ssa_emit(proc, ssa_make_instr_copy_memory(proc, dst, src, byte_count, align, is_volatile));
|
|
||||||
return len;
|
return len;
|
||||||
} break;
|
} break;
|
||||||
case BuiltinProc_append: {
|
case BuiltinProc_append: {
|
||||||
@@ -2056,7 +2055,12 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
|||||||
item = ssa_emit_ptr_offset(proc, item, v_zero);
|
item = ssa_emit_ptr_offset(proc, item, v_zero);
|
||||||
item = ssa_emit_conv(proc, item, t_rawptr, true);
|
item = ssa_emit_conv(proc, item, t_rawptr, true);
|
||||||
|
|
||||||
ssa_emit(proc, ssa_make_instr_copy_memory(proc, offset, item, byte_count, 1, false));
|
ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 3);
|
||||||
|
args[0] = offset;
|
||||||
|
args[1] = item;
|
||||||
|
args[2] = byte_count;
|
||||||
|
|
||||||
|
ssa_emit_global_call(proc, "memory_move", args, 3);
|
||||||
|
|
||||||
// Increment slice length
|
// Increment slice length
|
||||||
Token add = {Token_Add};
|
Token add = {Token_Add};
|
||||||
@@ -2172,6 +2176,22 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
|||||||
ssaValue *cond = ssa_emit_comp(proc, lt, x, v_zero);
|
ssaValue *cond = ssa_emit_comp(proc, lt, x, v_zero);
|
||||||
return ssa_emit_select(proc, cond, neg_x, x);
|
return ssa_emit_select(proc, cond, neg_x, x);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
||||||
|
case BuiltinProc_type_info: {
|
||||||
|
ssaValue **found = map_get(&proc->module->members, hash_string(make_string("__type_info_data")));
|
||||||
|
GB_ASSERT(found != NULL);
|
||||||
|
ssaValue *type_info_data = *found;
|
||||||
|
ssaValue *x = ssa_build_expr(proc, ce->arg_list);
|
||||||
|
Type *t = default_type(type_of_expr(proc->module->info, ce->arg_list));
|
||||||
|
MapFindResult fr = map__find(&proc->module->info->type_info_types, hash_pointer(t));
|
||||||
|
GB_ASSERT(fr.entry_index >= 0);
|
||||||
|
// Zero is null and void
|
||||||
|
isize offset = fr.entry_index;
|
||||||
|
|
||||||
|
ssaValue *gep = ssa_emit_struct_gep(proc, type_info_data, offset, t_type_info_ptr);
|
||||||
|
return gep;
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3153,11 +3173,16 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
|||||||
Type *union_type = type_deref(ssa_type(parent));
|
Type *union_type = type_deref(ssa_type(parent));
|
||||||
GB_ASSERT(is_type_union(union_type));
|
GB_ASSERT(is_type_union(union_type));
|
||||||
|
|
||||||
|
ssa_emit_comment(proc, make_string("get union's tag"));
|
||||||
ssaValue *tag_index = ssa_emit_struct_gep(proc, parent, v_one32, make_type_pointer(allocator, t_int));
|
ssaValue *tag_index = ssa_emit_struct_gep(proc, parent, v_one32, make_type_pointer(allocator, t_int));
|
||||||
tag_index = ssa_emit_load(proc, tag_index);
|
tag_index = ssa_emit_load(proc, tag_index);
|
||||||
|
|
||||||
ssaValue *data = ssa_emit_conv(proc, parent, t_rawptr);
|
ssaValue *data = ssa_emit_conv(proc, parent, t_rawptr);
|
||||||
|
|
||||||
|
ssaBlock *start_block = ssa_add_block(proc, node, make_string("type-match.case.first"));
|
||||||
|
ssa_emit_jump(proc, start_block);
|
||||||
|
proc->curr_block = start_block;
|
||||||
|
|
||||||
ssaBlock *done = ssa__make_block(proc, node, make_string("type-match.done")); // NOTE(bill): Append later
|
ssaBlock *done = ssa__make_block(proc, node, make_string("type-match.done")); // NOTE(bill): Append later
|
||||||
|
|
||||||
ast_node(body, BlockStmt, ms->body);
|
ast_node(body, BlockStmt, ms->body);
|
||||||
@@ -3173,30 +3198,22 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
|||||||
for (AstNode *clause = body->list;
|
for (AstNode *clause = body->list;
|
||||||
clause != NULL;
|
clause != NULL;
|
||||||
clause = clause->next, i++) {
|
clause = clause->next, i++) {
|
||||||
ssaBlock *body = NULL;
|
|
||||||
b32 append_body = false;
|
|
||||||
|
|
||||||
ast_node(cc, CaseClause, clause);
|
ast_node(cc, CaseClause, clause);
|
||||||
|
|
||||||
if (body == NULL) {
|
|
||||||
append_body = true;
|
|
||||||
if (cc->list == NULL) {
|
|
||||||
body = ssa__make_block(proc, clause, make_string("type-match.dflt.body"));
|
|
||||||
} else {
|
|
||||||
body = ssa__make_block(proc, clause, make_string("type-match.case.body"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (cc->list == NULL) {
|
if (cc->list == NULL) {
|
||||||
// default case
|
// default case
|
||||||
default_stmts = cc->stmts;
|
default_stmts = cc->stmts;
|
||||||
default_block = body;
|
default_block = ssa__make_block(proc, clause, make_string("type-match.dflt.body"));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssaBlock *body = ssa__make_block(proc, clause, make_string("type-match.case.body"));
|
||||||
|
|
||||||
|
|
||||||
Scope *scope = *map_get(&proc->module->info->scopes, hash_pointer(clause));
|
Scope *scope = *map_get(&proc->module->info->scopes, hash_pointer(clause));
|
||||||
Entity *tag_var_entity = current_scope_lookup_entity(scope, tag_var_name);
|
Entity *tag_var_entity = current_scope_lookup_entity(scope, tag_var_name);
|
||||||
|
GB_ASSERT(tag_var_entity != NULL);
|
||||||
ssaValue *tag_var = ssa_add_local(proc, tag_var_entity);
|
ssaValue *tag_var = ssa_add_local(proc, tag_var_entity);
|
||||||
ssaValue *data_ptr = ssa_emit_conv(proc, data, tag_var_entity->type);
|
ssaValue *data_ptr = ssa_emit_conv(proc, data, tag_var_entity->type);
|
||||||
ssa_emit_store(proc, tag_var, data_ptr);
|
ssa_emit_store(proc, tag_var, data_ptr);
|
||||||
@@ -3205,10 +3222,13 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
|||||||
|
|
||||||
Type *base_type = type_deref(tag_var_entity->type);
|
Type *base_type = type_deref(tag_var_entity->type);
|
||||||
ssaValue *index = NULL;
|
ssaValue *index = NULL;
|
||||||
for (isize i = 0; i < get_base_type(union_type)->Record.field_count; i++) {
|
Type *ut = get_base_type(union_type);
|
||||||
Entity *f = get_base_type(union_type)->Record.fields[i];
|
GB_ASSERT(ut->Record.kind == TypeRecord_Union);
|
||||||
|
for (isize field_index = 1; field_index < ut->Record.field_count; field_index++) {
|
||||||
|
Entity *f = get_base_type(union_type)->Record.fields[field_index];
|
||||||
if (are_types_identical(f->type, base_type)) {
|
if (are_types_identical(f->type, base_type)) {
|
||||||
index = ssa_make_value_constant(allocator, t_int, make_exact_value_integer(i));
|
index = ssa_make_value_constant(allocator, t_int, make_exact_value_integer(field_index));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GB_ASSERT(index != NULL);
|
GB_ASSERT(index != NULL);
|
||||||
@@ -3220,9 +3240,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
|||||||
gb_array_append(proc->blocks, next_cond);
|
gb_array_append(proc->blocks, next_cond);
|
||||||
proc->curr_block = next_cond;
|
proc->curr_block = next_cond;
|
||||||
|
|
||||||
if (append_body) {
|
gb_array_append(proc->blocks, body);
|
||||||
gb_array_append(proc->blocks, body);
|
|
||||||
}
|
|
||||||
proc->curr_block = body;
|
proc->curr_block = body;
|
||||||
ssa_push_target_list(proc, done, NULL, NULL);
|
ssa_push_target_list(proc, done, NULL, NULL);
|
||||||
ssa_build_stmt_list(proc, cc->stmts);
|
ssa_build_stmt_list(proc, cc->stmts);
|
||||||
|
|||||||
+10
-2
@@ -41,6 +41,7 @@ i32 win32_exec_command_line_app(char *fmt, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
#define INIT_TIMER() u64 start_time, end_time = 0, total_time = 0; start_time = gb_utc_time_now()
|
#define INIT_TIMER() u64 start_time, end_time = 0, total_time = 0; start_time = gb_utc_time_now()
|
||||||
#define PRINT_TIMER(section) do { \
|
#define PRINT_TIMER(section) do { \
|
||||||
u64 diff; \
|
u64 diff; \
|
||||||
@@ -54,6 +55,11 @@ i32 win32_exec_command_line_app(char *fmt, ...) {
|
|||||||
#define PRINT_ACCUMULATION() do { \
|
#define PRINT_ACCUMULATION() do { \
|
||||||
gb_printf_err("Total compilation time: %lld ms\n", total_time/1000); \
|
gb_printf_err("Total compilation time: %lld ms\n", total_time/1000); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define INIT_TIMER()
|
||||||
|
#define PRINT_TIMER(section)
|
||||||
|
#define PRINT_ACCUMULATION()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
@@ -117,8 +123,10 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
|
|
||||||
i32 exit_code = 0;
|
i32 exit_code = 0;
|
||||||
|
// For more passes arguments: http://llvm.org/docs/Passes.html
|
||||||
exit_code = win32_exec_command_line_app(
|
exit_code = win32_exec_command_line_app(
|
||||||
"../misc/llvm-bin/opt %s -o %.*s.bc "
|
// "../misc/llvm-bin/opt %s -o %.*s.bc "
|
||||||
|
"opt %s -o %.*s.bc "
|
||||||
"-memcpyopt "
|
"-memcpyopt "
|
||||||
"-mem2reg "
|
"-mem2reg "
|
||||||
"-die -dse "
|
"-die -dse "
|
||||||
@@ -144,7 +152,7 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exit_code = win32_exec_command_line_app(
|
exit_code = win32_exec_command_line_app(
|
||||||
"clang %.*s.bc -o %.*s.o "
|
"clang %.*s.bc -o %.*s.exe "
|
||||||
"-O0 "
|
"-O0 "
|
||||||
"-Wno-override-module "
|
"-Wno-override-module "
|
||||||
"%s",
|
"%s",
|
||||||
|
|||||||
+13
-4
@@ -2063,8 +2063,15 @@ AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) {
|
|||||||
declaration_kind = Declaration_Immutable;
|
declaration_kind = Declaration_Immutable;
|
||||||
next_token(f);
|
next_token(f);
|
||||||
|
|
||||||
if (f->cursor[0].kind == Token_type) {
|
if (f->cursor[0].kind == Token_type ||
|
||||||
Token token = expect_token(f, Token_type);
|
f->cursor[0].kind == Token_struct ||
|
||||||
|
f->cursor[0].kind == Token_enum ||
|
||||||
|
f->cursor[0].kind == Token_union ||
|
||||||
|
f->cursor[0].kind == Token_raw_union) {
|
||||||
|
Token token = f->cursor[0];
|
||||||
|
if (token.kind == Token_type) {
|
||||||
|
next_token(f);
|
||||||
|
}
|
||||||
if (name_count != 1) {
|
if (name_count != 1) {
|
||||||
ast_file_err(f, ast_node_token(name_list), "You can only declare one type at a time");
|
ast_file_err(f, ast_node_token(name_list), "You can only declare one type at a time");
|
||||||
return make_bad_decl(f, name_list->Ident, token);
|
return make_bad_decl(f, name_list->Ident, token);
|
||||||
@@ -2290,9 +2297,9 @@ AstNode *parse_match_stmt(AstFile *f) {
|
|||||||
Token open, close;
|
Token open, close;
|
||||||
|
|
||||||
if (allow_token(f, Token_type)) {
|
if (allow_token(f, Token_type)) {
|
||||||
tag = parse_expr(f, true);
|
|
||||||
expect_token(f, Token_ArrowRight);
|
|
||||||
AstNode *var = parse_identifier(f);
|
AstNode *var = parse_identifier(f);
|
||||||
|
expect_token(f, Token_Colon);
|
||||||
|
tag = parse_simple_stmt(f);
|
||||||
|
|
||||||
open = expect_token(f, Token_OpenBrace);
|
open = expect_token(f, Token_OpenBrace);
|
||||||
AstNode *list = NULL;
|
AstNode *list = NULL;
|
||||||
@@ -2307,6 +2314,8 @@ AstNode *parse_match_stmt(AstFile *f) {
|
|||||||
|
|
||||||
close = expect_token(f, Token_CloseBrace);
|
close = expect_token(f, Token_CloseBrace);
|
||||||
body = make_block_stmt(f, list, list_count, open, close);
|
body = make_block_stmt(f, list, list_count, open, close);
|
||||||
|
|
||||||
|
tag = convert_stmt_to_expr(f, tag, make_string("type match expression"));
|
||||||
return make_type_match_stmt(f, token, tag, var, body);
|
return make_type_match_stmt(f, token, tag, var, body);
|
||||||
} else {
|
} else {
|
||||||
if (f->cursor[0].kind != Token_OpenBrace) {
|
if (f->cursor[0].kind != Token_OpenBrace) {
|
||||||
|
|||||||
Reference in New Issue
Block a user