123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900 |
- // 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
- compile_assert(COND)
- // compile_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() }
|