diff options
| author | gingerBill <bill@gingerbill.org> | 2019-11-17 10:30:37 -0800 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2019-11-17 10:30:37 -0800 |
| commit | d22e5b697db24e943d2500e69cc98acda63434e3 (patch) | |
| tree | 4550d2c67922cfe3473d9b2f2619ca8a828728de /examples | |
| parent | 301ee664e9f10bb47993b9ccf395628606052a64 (diff) | |
Add new #soa and #vector syntax
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/demo/demo.odin | 1038 | ||||
| -rw-r--r-- | examples/hms2019/basic.odin | 2 | ||||
| -rw-r--r-- | examples/hms2019/eca.odin | 96 | ||||
| -rw-r--r-- | examples/hms2019/hms2019.odin | 4 |
4 files changed, 757 insertions, 383 deletions
diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 8dc5340c9..5a01df440 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -6,170 +6,530 @@ import "core:os" import "core:reflect" import "intrinsics" -when os.OS == "windows" { - import "core:thread" -} - /* - The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals: - * simplicity - * high performance - * built for modern systems - * joy of programming - - # Installing Odin - Getting Started - https://odin-lang.org/docs/install/ - Instructions for downloading and install the Odin compiler and libraries. - - # Learning Odin - Overview of Odin - https://odin-lang.org/docs/overview/ - An overview of the Odin programming language. - Frequently Asked Questions (FAQ) - https://odin-lang.org/docs/faq/ - Answers to common questions about Odin. + The Odin programming language is fast, concise, readable, pragmatic and open sourced. + It is designed with the intent of replacing C with the following goals: + * simplicity + * high performance + * built for modern systems + * joy of programming + + # Installing Odin + Getting Started - https://odin-lang.org/docs/install/ + Instructions for downloading and install the Odin compiler and libraries. + + # Learning Odin + Overview of Odin - https://odin-lang.org/docs/overview/ + An overview of the Odin programming language. + Frequently Asked Questions (FAQ) - https://odin-lang.org/docs/faq/ + Answers to common questions about Odin. */ -@(link_name="extra_general_stuff") -extra_general_stuff :: proc() { - fmt.println("# extra_general_stuff"); - { // `do` for inline statements rather than block - foo :: proc() do fmt.println("Foo!"); - if false do foo(); - for false do foo(); - when false do foo(); +the_basics :: proc() { + fmt.println("\n# the basics"); - if false do foo(); - else do foo(); - } + { // The Basics + fmt.println("Hellope"); - { // Removal of `++` and `--` (again) - x: int; - x += 1; - x -= 1; - } - { // Casting syntaxes - i := i32(137); - ptr := &i; + // Lexical elements and literals + // A comment - _ = (^f32)(ptr); // Call-based syntax - // ^f32(ptr) == ^(f32(ptr)) - _ = cast(^f32)ptr; // Operator-based syntax + my_integer_variable: int; // A comment for documentaton - _ = (^f32)(ptr)^; - _ = (cast(^f32)ptr)^; - } + // Multi-line comments begin with /* and end with */. Multi-line comments can + // also be nested (unlike in C): + /* + You can have any text or code here and + have it be commented. + /* + NOTE: comments can be nested! + */ + */ - /* - * Remove *_val_of built-in procedures - * size_of, align_of, offset_of - * type_of, type_info_of, typeid_of - */ + // String literals are enclosed in double quotes and character literals in single quotes. + // Special characters are escaped with a backslash \ - { // `expand_to_tuple` built-in procedure - Foo :: struct { - x: int, - b: bool, - }; - f := Foo{137, true}; - x, b := expand_to_tuple(f); - fmt.println(f); - fmt.println(x, b); - fmt.println(expand_to_tuple(f)); - } + some_string := "This is a string"; + _ = 'A'; // unicode codepoint literal + _ = '\n'; + _ = "C:\\Windows\\notepad.exe"; + // Raw string literals are enclosed with single back ticks + _ = `C:\Windows\notepad.exe`; - { - // .. open range - // ..< half-closed range + // The length of a string in bytes can be found using the built-in `len` procedure: + _ = len("Foo"); + _ = len(some_string); - for in 0..2 {} // 0, 1, 2 - for in 0..<2 {} // 0, 1 - } - { // Multiple sized booleans + // Numbers - x0: bool; // default - x1: b8 = true; - x2: b16 = false; - x3: b32 = true; - x4: b64 = false; + // Numerical literals are written similar to most other programming languages. + // A useful feature in Odin is that underscores are allowed for better + // readability: 1_000_000_000 (one billion). A number that contains a dot is a + // floating point literal: 1.0e9 (one billion). If a number literal is suffixed + // with i, is an imaginary number literal: 2i (2 multiply the square root of -1). - fmt.printf("x0: %T = %v;\n", x0, x0); - fmt.printf("x1: %T = %v;\n", x1, x1); - fmt.printf("x2: %T = %v;\n", x2, x2); - fmt.printf("x3: %T = %v;\n", x3, x3); - fmt.printf("x4: %T = %v;\n", x4, x4); + // Binary literals are prefixed with 0b, octal literals with 0o, and hexadecimal + // literals 0x. A leading zero does not produce an octal constant (unlike C). - // Having specific sized booleans is very useful when dealing with foreign code - // and to enforce specific alignment for a boolean, especially within a struct - } + // In Odin, if a number constant is possible to be represented by a type without + // precision loss, it will automatically convert to that type. - { // `distinct` types - // Originally, all type declarations would create a distinct type unless #type_alias was present. - // Now the behaviour has been reversed. All type declarations create a type alias unless `distinct` is present. - // If the type expression is `struct`, `union`, `enum`, `proc`, or `bit_field`, the types will always been distinct. + x: int = 1.0; // A float literal but it can be represented by an integer without precision loss + // Constant literals are “untyped” which means that they can implicitly convert to a type. - Int32 :: i32; - #assert(Int32 == i32); + y: int; // `y` is typed of type `int` + y = 1; // `1` is an untyped integer literal which can implicitly convert to `int` - My_Int32 :: distinct i32; - #assert(My_Int32 != i32); + z: f64; // `z` is typed of type `f64` (64-bit floating point number) + z = 1; // `1` is an untyped integer literals which can be implicity conver to `f64` + // No need for any suffixes or decimal places like in other languages + // CONSTANTS JUST WORK!!! - My_Struct :: struct{x: int}; - #assert(My_Struct != struct{x: int}); - My_Struct2 :: My_Struct; - #assert(My_Struct2 == My_Struct); + // Assignment statements + h: int = 123; // declares a new variable `h` with type `int` and assigns a value to it + h = 637; // assigns a new value to `h` + + // `=` is the assignment operator + + // You can assign multiple variables with it: + a, b := 1, "hello"; // declares `a` and `b` and infers the types from the assignments + b, a = "byte", 0; + + // Note: `:=` is two tokens, `:` and `=`. The follow are equivalent + /* + i: int = 123; + i: = 123; + i := 123 + */ + + // Constant declarations + // Constants are entities (symbols) which have an assigned value. + // The constant’s value cannot be changed. + // The constant’s value must be able to be evaluated at compile time: + X :: "what"; // constant `X` has the untyped string value "what" + + // Constants can be explicitly typed like a variable declaration: + Y : int : 123; + Z :: Y + 7; // constant computations are possible } +} - { - X :: 123; - when #defined(X) { - fmt.println("X is defined"); - } else { - fmt.println("X is not defined"); +control_flow :: proc() { + fmt.println("\n# control flow"); + { // Control flow + // For loop + // Odin has only one loop statement, the `for` loop + + // Basic for loop + for i := 0; i < 10; i += 1 { + fmt.println(i); + } + + // NOTE: Unlike other languages like C, there are no parentheses `( )` surrounding the three components. + // Braces `{ }` or a `do` are always required> + for i := 0; i < 10; i += 1 { } + for i := 0; i < 10; i += 1 do fmt.print(); + + // The initial and post statements are optional + i := 0; + for ; i < 10; { + i += 1; + } + + // These semicolons can be dropped. This `for` loop is equivalent to C's `while` loop + i = 0; + for i < 10 { + i += 1; + } + + // If the condition is omitted, this produces an infinite loop: + for { + break; + } + + // Range-based for loop + // The basic for loop + for i := 0; i < 10; i += 1 { + fmt.println(i); + } + // can also be written + for i in 0..<10 { + fmt.println(i); + } + for i in 0..9 { + fmt.println(i); + } + + // Certain built-in types can be iterated over + some_string := "Hello, 世界"; + for character in some_string { // Strings are assumed to be UTF-8 + fmt.println(character); + } + + some_array := [3]int{1, 4, 9}; + for value in some_array { + fmt.println(value); + } + + some_slice := []int{1, 4, 9}; + for value in some_slice { + fmt.println(value); + } + + some_dynamic_array := [dynamic]int{1, 4, 9}; + defer delete(some_dynamic_array); + for value in some_dynamic_array { + fmt.println(value); + } + + + some_map := map[string]int{"A" = 1, "C" = 9, "B" = 4}; + defer delete(some_map); + for key in some_map { + fmt.println(key); + } + + // Alternatively a second index value can be added + for character, index in some_string { + fmt.println(index, character); + } + for value, index in some_array { + fmt.println(index, value); + } + for value, index in some_slice { + fmt.println(index, value); + } + for value, index in some_dynamic_array { + fmt.println(index, value); + } + for key, value in some_map { + fmt.println(key, value); + } + + // The iterated values are copies and cannot be written to. + // The following idiom is useful for iterating over a container in a by-reference manner: + for _, i in some_slice { + some_slice[i] = (i+1)*(i+1); } - when #defined(Y) { - fmt.println("Y is defined"); + + + // If statements + x := 123; + if x >= 0 { + fmt.println("x is positive"); + } + + if y := -34; y < 0 { + fmt.println("y is negative"); + } + + if y := 123; y < 0 { + fmt.println("y is negative"); + } else if y == 0 { + fmt.println("y is zero"); } else { - fmt.println("Y is not defined"); + fmt.println("y is positive"); + } + + // Switch statement + // A switch statement is another way to write a sequence of if-else statements. + // In Odin, the default case is denoted as a case without any expression. + + switch arch := ODIN_ARCH; arch { + case "386": + fmt.println("32-bit"); + case "amd64": + fmt.println("64-bit"); + case: // default + fmt.println("Unsupported architecture"); + } + + // Odin’s `switch` is like one in C or C++, except that Odin only runs the selected case. + // This means that a `break` statement is not needed at the end of each case. + // Another important difference is that the case values need not be integers nor constants. + + // To achieve a C-like fall through into the next case block, the keyword `fallthrough` can be used. + one_angry_dwarf :: proc() -> int { + fmt.println("one_angry_dwarf was called"); + return 1; + } + + switch i := 0; i { + case 0: + case one_angry_dwarf(): + } + + // A switch statement without a condition is the same as `switch true`. + // This can be used to write a clean and long if-else chain and have the + // ability to break if needed + + switch { + case x < 0: + fmt.println("x is negative"); + case x == 0: + fmt.println("x is zero"); + case: + fmt.println("x is positive"); + } + + // A `switch` statement can also use ranges like a range-based loop: + switch c := 'j'; c { + case 'A'..'Z', 'a'..'z', '0'..'9': + fmt.println("c is alphanumeric"); + } + + switch x { + case 0..<10: + fmt.println("units"); + case 10..<13: + fmt.println("pre-teens"); + case 13..<20: + fmt.println("teens"); + case 20..<30: + fmt.println("twenties"); } } - { // Labelled control blocks - block: { - if true { - fmt.println("break block;"); - break block; + { // Defer statement + // A defer statement defers the execution of a statement until the end of + // the scope it is in. + + // The following will print 4 then 234: + { + x := 123; + defer fmt.println(x); + { + defer x = 4; + x = 2; } + fmt.println(x); + + x = 234; } + // You can defer an entire block too: { - branch: if true { - fmt.println("break branch;"); - break branch; + bar :: proc() {} + + defer { + fmt.println("1"); + fmt.println("2"); } - } + cond := false; + defer if cond { + bar(); + } + } + + // Defer statements are executed in the reverse order that they were declared: { - loop: for true { - fmt.println("break loop;"); - break loop; + defer fmt.println("1"); + defer fmt.println("2"); + defer fmt.println("3"); + } + // Will print 3, 2, and then 1. + + if false { + f, err := os.open("my_file.txt"); + if err != 0 { + // handle error } + defer os.close(f); + // rest of code } + } - { - cases: switch { + { // When statement + /* + The when statement is almost identical to the if statement but with some differences: + + * Each condition must be a constant expression as a when + statement is evaluated at compile time. + * The statements within a branch do not create a new scope + * The compiler checks the semantics and code only for statements + that belong to the first condition that is true + * An initial statement is not allowed in a when statement + * when statements are allowed at file scope + */ + + // Example + when ODIN_ARCH == "386" { + fmt.println("32 bit"); + } else when ODIN_ARCH == "amd64" { + fmt.println("64 bit"); + } else { + fmt.println("Unsupported architecture"); + } + // The when statement is very useful for writing platform specific code. + // This is akin to the #if construct in C’s preprocessor however, in Odin, + // it is type checked. + } + + { // Branch statements + cond, cond1, cond2 := false, false, false; + one_step :: proc() { fmt.println("one_step"); } + beyond :: proc() { fmt.println("beyond"); } + + // Break statement + for cond { + switch { case: - fmt.println("break cases;"); - break cases; + if cond { + break; // break out of the `switch` statement + } + } + + break; // break out of the `for` statement + } + + loop: for cond1 { + for cond2 { + break loop; // leaves both loops } } + // Continue statement + for cond { + if cond2 { + continue; + } + fmt.println("Hellope"); + } + + // Fallthrough statement + + // Odin’s switch is like one in C or C++, except that Odin only runs the selected + // case. This means that a break statement is not needed at the end of each case. + // Another important difference is that the case values need not be integers nor + // constants. + + // fallthrough can be used to explicitly fall through into the next case block: + + switch i := 0; i { + case 0: + one_step(); + fallthrough; + case 1: + beyond(); + } + } +} + + +named_proc_return_parameters :: proc() { + fmt.println("\n# named proc return parameters"); + + foo0 :: proc() -> int { + return 123; + } + foo1 :: proc() -> (a: int) { + a = 123; + return; + } + foo2 :: proc() -> (a, b: int) { + // Named return values act like variables within the scope + a = 321; + b = 567; + return b, a; + } + fmt.println("foo0 =", foo0()); // 123 + fmt.println("foo1 =", foo1()); // 123 + fmt.println("foo2 =", foo2()); // 567 321 +} + + +explicit_procedure_overloading :: proc() { + fmt.println("\n# explicit procedure overloading"); + + add_ints :: proc(a, b: int) -> int { + x := a + b; + fmt.println("add_ints", x); + return x; + } + add_floats :: proc(a, b: f32) -> f32 { + x := a + b; + fmt.println("add_floats", x); + return x; + } + add_numbers :: proc(a: int, b: f32, c: u8) -> int { + x := int(a) + int(b) + int(c); + fmt.println("add_numbers", x); + return x; + } + + add :: proc{add_ints, add_floats, add_numbers}; + + add(int(1), int(2)); + add(f32(1), f32(2)); + add(int(1), f32(2), u8(3)); + + add(1, 2); // untyped ints coerce to int tighter than f32 + add(1.0, 2.0); // untyped floats coerce to f32 tighter than int + add(1, 2, 3); // three parameters + + // Ambiguous answers + // add(1.0, 2); + // add(1, 2.0); +} + +struct_type :: proc() { + fmt.println("\n# struct type"); + // A struct is a record type in Odin. It is a collection of fields. + // Struct fields are accessed by using a dot: + { + Vector2 :: struct { + x: f32, + y: f32, + }; + v := Vector2{1, 2}; + v.x = 4; + fmt.println(v.x); + + // Struct fields can be accessed through a struct pointer: + + v = Vector2{1, 2}; + p := &v; + p.x = 1335; + fmt.println(v); + + // We could write p^.x, however, it is to nice abstract the ability + // to not explicitly dereference the pointer. This is very useful when + // refactoring code to use a pointer rather than a value, and vice versa. } + { + // A struct literal can be denoted by providing the struct’s type + // followed by {}. A struct literal must either provide all the + // arguments or none: + Vector3 :: struct { + x, y, z: f32, + }; + v: Vector3; + v = Vector3{}; // Zero value + v = Vector3{1, 4, 9}; + + // You can list just a subset of the fields if you specify the + // field by name (the order of the named fields does not matter): + v = Vector3{z=1, y=2}; + assert(v.x == 0); + assert(v.y == 2); + assert(v.z == 1); + } + { + // Structs can tagged with different memory layout and alignment requirements: + + a :: struct #align 4 {}; // align to 4 bytes + b :: struct #packed {}; // remove padding between fields + c :: struct #raw_union {}; // all fields share the same offset (0). This is the same as C's union + } + } union_type :: proc() { - fmt.println("\n# union_type"); + fmt.println("\n# union type"); { val: union{int, bool}; val = 137; @@ -342,8 +702,141 @@ union_type :: proc() { } } +using_statement :: proc() { + fmt.println("\n# using statement"); + // using can used to bring entities declared in a scope/namespace + // into the current scope. This can be applied to import declarations, + // import names, struct fields, procedure fields, and struct values. + + Vector3 :: struct{x, y, z: f32}; + { + Entity :: struct { + position: Vector3, + orientation: quaternion128, + }; + + // It can used like this: + foo0 :: proc(entity: ^Entity) { + fmt.println(entity.position.x, entity.position.y, entity.position.z); + } + + // The entity members can be brought into the procedure scope by using it: + foo1 :: proc(entity: ^Entity) { + using entity; + fmt.println(position.x, position.y, position.z); + } + + // The using can be applied to the parameter directly: + foo2 :: proc(using entity: ^Entity) { + fmt.println(position.x, position.y, position.z); + } + + // It can also be applied to sub-fields: + foo3 :: proc(entity: ^Entity) { + using entity.position; + fmt.println(x, y, z); + } + } + { + // We can also apply the using statement to the struct fields directly, + // making all the fields of position appear as if they on Entity itself: + Entity :: struct { + using position: Vector3, + orientation: quaternion128, + }; + foo :: proc(entity: ^Entity) { + fmt.println(entity.x, entity.y, entity.z); + } + + + // Subtype polymorphism + // It is possible to get subtype polymorphism, similar to inheritance-like + // functionality in C++, but without the requirement of vtables or unknown + // struct layout: + + Colour :: struct {r, g, b, a: u8}; + Frog :: struct { + ribbit_volume: f32, + using entity: Entity, + colour: Colour, + }; + + frog: Frog; + // Both work + foo(&frog.entity); + foo(&frog); + frog.x = 123; + + // Note: using can be applied to arbitrarily many things, which allows + // the ability to have multiple subtype polymorphism (but also its issues). + + // Note: using’d fields can still be referred by name. + } + { // using on an enum declaration + + using Foo :: enum {A, B, C}; + + f0 := A; + f1 := B; + f2 := C; + fmt.println(f0, f1, f2); + fmt.println(len(Foo)); + } +} + + +implicit_context_system :: proc() { + fmt.println("\n# implicit context system"); + // In each scope, there is an implicit value named context. This + // context variable is local to each scope and is implicitly passed + // by pointer to any procedure call in that scope (if the procedure + // has the Odin calling convention). + + // The main purpose of the implicit context system is for the ability + // to intercept third-party code and libraries and modify their + // functionality. One such case is modifying how a library allocates + // something or logs something. In C, this was usually achieved with + // the library defining macros which could be overridden so that the + // user could define what he wanted. However, not many libraries + // supported this in many languages by default which meant intercepting + // third-party code to see what it does and to change how it does it is + // not possible. + + c := context; // copy the current scope's context + + context.user_index = 456; + { + context.allocator = my_custom_allocator(); + context.user_index = 123; + what_a_fool_believes(); // the `context` for this scope is implicitly passed to `what_a_fool_believes` + } + + // `context` value is local to the scope it is in + assert(context.user_index == 456); + + what_a_fool_believes :: proc() { + c := context; // this `context` is the same as the parent procedure that it was called from + // From this example, context.user_index == 123 + // An context.allocator is assigned to the return value of `my_custom_allocator()` + assert(context.user_index == 123); + + // The memory management procedure use the `context.allocator` by + // default unless explicitly specified otherwise + china_grove := new(int); + free(china_grove); + } + + my_custom_allocator :: mem.nil_allocator; + + // By default, the context value has default values for its parameters which is + // decided in the package runtime. What the defaults are are compiler specific. + + // To see what the implicit context value contains, please see the following + // definition in package runtime. +} + parametric_polymorphism :: proc() { - fmt.println("\n# parametric_polymorphism"); + fmt.println("\n# parametric polymorphism"); print_value :: proc(value: $T) { fmt.printf("print_value: %T %v\n", value, value); @@ -589,60 +1082,8 @@ parametric_polymorphism :: proc() { } - - -prefix_table := [?]string{ - "White", - "Red", - "Green", - "Blue", - "Octarine", - "Black", -}; - -threading_example :: proc() { - when os.OS == "windows" { - fmt.println("\n# threading_example"); - - worker_proc :: proc(t: ^thread.Thread) -> int { - for iteration in 1..5 { - fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration); - fmt.printf("`%s`: iteration %d\n", prefix_table[t.user_index], iteration); - // win32.sleep(1); - } - return 0; - } - - threads := make([dynamic]^thread.Thread, 0, len(prefix_table)); - defer delete(threads); - - for in prefix_table { - if t := thread.create(worker_proc); t != nil { - t.init_context = context; - t.use_init_context = true; - t.user_index = len(threads); - append(&threads, t); - thread.start(t); - } - } - - for len(threads) > 0 { - for i := 0; i < len(threads); /**/ { - if t := threads[i]; thread.is_done(t) { - fmt.printf("Thread %d is done\n", t.user_index); - thread.destroy(t); - - ordered_remove(&threads, i); - } else { - i += 1; - } - } - } - } -} - array_programming :: proc() { - fmt.println("\n# array_programming"); + fmt.println("\n# array programming"); { a := [3]f32{1, 2, 3}; b := [3]f32{5, 6, 7}; @@ -686,92 +1127,23 @@ array_programming :: proc() { } } -named_proc_return_parameters :: proc() { - fmt.println("\n# named proc return parameters"); - - foo0 :: proc() -> int { - return 123; - } - foo1 :: proc() -> (a: int) { - a = 123; - return; - } - foo2 :: proc() -> (a, b: int) { - // Named return values act like variables within the scope - a = 321; - b = 567; - return b, a; - } - fmt.println("foo0 =", foo0()); // 123 - fmt.println("foo1 =", foo1()); // 123 - fmt.println("foo2 =", foo2()); // 567 321 -} - - -using_enum :: proc() { - fmt.println("\n# using enum"); - - using Foo :: enum {A, B, C}; - - f0 := A; - f1 := B; - f2 := C; - fmt.println(f0, f1, f2); - fmt.println(len(Foo)); -} - map_type :: proc() { fmt.println("\n# map type"); - // enums of type u16, u32, i16 & i32 also work - Enum_u8 :: enum u8 { - A = 0, - B = 1 << 8 - 1, - }; - Enum_u64 :: enum u64 { - A = 0, - B = 1 << 64 - 1, - }; - Enum_i8 :: enum i8 { - A = 0, - B = -(1 << 7), - }; - Enum_i64 :: enum i64 { - A = 0, - B = -(1 << 63), - }; - - map_u8: map[Enum_u8]u8; - map_u8[Enum_u8.A] = u8(Enum_u8.B); - assert(map_u8[Enum_u8.A] == u8(Enum_u8.B)); - fmt.println(map_u8); + m := make(map[string]int); + defer delete(m); - map_u64: map[Enum_u64]u64; - map_u64[Enum_u64.A] = u64(Enum_u64.B); - assert(map_u64[Enum_u64.A] == u64(Enum_u64.B)); - fmt.println(map_u64); + m["Bob"] = 2; + m["Ted"] = 5; + fmt.println(m["Bob"]); - map_i8: map[Enum_i8]i8; - map_i8[Enum_i8.A] = i8(Enum_i8.B); - assert(map_i8[Enum_i8.A] == i8(Enum_i8.B)); - fmt.println(map_i8); - - map_i64: map[Enum_i64]i64; - map_i64[Enum_i64.A] = i64(Enum_i64.B); - assert(map_i64[Enum_i64.A] == i64(Enum_i64.B)); - fmt.println(map_i64); - - demo_struct :: struct { - member: Enum_i64, - }; + delete_key(&m, "Ted"); - map_string: map[string]demo_struct; - map_string["Hellope!"] = demo_struct{Enum_i64.B}; - assert(map_string["Hellope!"].member == Enum_i64.B); - assert("Hellope?" notin map_string); - fmt.println(map_string); - fmt.println("Hellope! in map_string:", "Hellope!" in map_string); - fmt.println("Hellope? in map_string:", "Hellope?" in map_string); + // If an element of a key does not exist, the zero value of the + // element will be returned. To check to see if an element exists + // can be done in two ways: + elem, ok := m["Bob"]; + exists := "Bob" in m; } @@ -781,6 +1153,7 @@ implicit_selector_expression :: proc() { Foo :: enum {A, B, C}; f: Foo; + f = Foo.A; f = .A; BAR :: bit_set[Foo]{.B, .C}; @@ -803,61 +1176,25 @@ implicit_selector_expression :: proc() { fmt.println(my_map[.A] + my_map[Foo.B] + my_map[.C]); } -explicit_procedure_overloading :: proc() { - fmt.println("\n# explicit procedure overloading"); - - add_ints :: proc(a, b: int) -> int { - x := a + b; - fmt.println("add_ints", x); - return x; - } - add_floats :: proc(a, b: f32) -> f32 { - x := a + b; - fmt.println("add_floats", x); - return x; - } - add_numbers :: proc(a: int, b: f32, c: u8) -> int { - x := int(a) + int(b) + int(c); - fmt.println("add_numbers", x); - return x; - } - - add :: proc{add_ints, add_floats, add_numbers}; - - add(int(1), int(2)); - add(f32(1), f32(2)); - add(int(1), f32(2), u8(3)); - - add(1, 2); // untyped ints coerce to int tighter than f32 - add(1.0, 2.0); // untyped floats coerce to f32 tighter than int - add(1, 2, 3); // three parameters - - // Ambiguous answers - // add(1.0, 2); - // add(1, 2.0); -} complete_switch :: proc() { fmt.println("\n# complete_switch"); { // enum - using Foo :: enum { + Foo :: enum { A, B, C, D, }; - b := Foo.B; f := Foo.A; #complete switch f { - case A: fmt.println("A"); - case B: fmt.println("B"); - case C: fmt.println("C"); - case D: fmt.println("D"); - case: fmt.println("?"); + case .A: fmt.println("A"); + case .B: fmt.println("B"); + case .C: fmt.println("C"); + case .D: fmt.println("D"); + case: fmt.println("?"); } - - _ = b; } { // union Foo :: union {int, bool}; @@ -890,21 +1227,8 @@ cstring_example :: proc() { // cast(string)cstring is O(N) } -deprecated_attribute :: proc() { - @(deprecated="Use foo_v2 instead") - foo_v1 :: proc(x: int) { - fmt.println("foo_v1"); - } - foo_v2 :: proc(x: int) { - fmt.println("foo_v2"); - } - - // NOTE: Uncomment to see the warning messages - // foo_v1(1); -} - bit_set_type :: proc() { - fmt.println("\n# bit_set_type"); + fmt.println("\n# bit_set type"); { using Day :: enum { @@ -966,19 +1290,8 @@ bit_set_type :: proc() { } } -diverging_procedures :: proc() { - fmt.println("\n# diverging_procedures"); - - // Diverging procedures may never return - foo :: proc() -> ! { - fmt.println("I'm a diverging procedure"); - } - - foo(); -} - deferred_procedure_associations :: proc() { - fmt.println("\n# deferred_procedure_associations"); + fmt.println("\n# deferred procedure associations"); @(deferred_out=closure) open :: proc(s: string) -> bool { @@ -1031,6 +1344,7 @@ reflection :: proc() { } quaternions :: proc() { + // Not just an April Fool's Joke any more, but a fully working thing! fmt.println("\n# quaternions"); { // Quaternion operations @@ -1117,7 +1431,7 @@ where_clauses :: proc() { { // Sanity checks simple_sanity_check :: proc(x: [2]int) where len(x) > 1, - type_of(x) == [2]int { + type_of(x) == [2]int { fmt.println(x); } } @@ -1158,7 +1472,7 @@ where_clauses :: proc() { bar :: proc(x: [$N]int) -> bool where 0 < N, - N <= 2 { + N <= 2 { fmt.println(#procedure, "was called with the parameter", x); return false; } @@ -1176,7 +1490,7 @@ where_clauses :: proc() { { // Record types Foo :: struct(T: typeid, N: int) where intrinsics.type_is_integer(T), - N > 2 { + N > 2 { x: [N]T, y: [N-2]T, }; @@ -1188,6 +1502,48 @@ where_clauses :: proc() { } } + +when ODIN_OS == "windows" do foreign import kernel32 "system:kernel32.lib" + +foreign_system :: proc() { + fmt.println("\n#foreign system"); + when ODIN_OS == "windows" { + // It is sometimes necessarily to interface with foreign code, + // such as a C library. In Odin, this is achieved through the + // foreign system. You can “import” a library into the code + // using the same semantics as a normal import declaration. + + // This foreign import declaration will create a + // “foreign import name” which can then be used to associate + // entities within a foreign block. + + foreign kernel32 { + ExitProcess :: proc "stdcall" (exit_code: u32) --- + } + + // Foreign procedure declarations have the cdecl/c calling + // convention by default unless specified otherwise. Due to + // foreign procedures do not have a body declared within this + // code, you need append the --- symbol to the end to distinguish + // it as a procedure literal without a body and not a procedure type. + + // The attributes system can be used to change specific properties + // of entities declared within a block: + + @(default_calling_convention = "std") + foreign kernel32 { + @(link_name="GetLastError") get_last_error :: proc() -> i32 --- + } + + // Example using the link_prefix attribute + @(default_calling_convention = "std") + @(link_prefix = "Get") + foreign kernel32 { + LastError :: proc() -> i32 --- + } + } +} + ranged_fields_for_array_compound_literals :: proc() { fmt.println("\n#ranged fields for array compound literals"); { // Normal Array Literal @@ -1233,6 +1589,19 @@ ranged_fields_for_array_compound_literals :: proc() { } } +deprecated_attribute :: proc() { + @(deprecated="Use foo_v2 instead") + foo_v1 :: proc(x: int) { + fmt.println("foo_v1"); + } + foo_v2 :: proc(x: int) { + fmt.println("foo_v2"); + } + + // NOTE: Uncomment to see the warning messages + // foo_v1(1); +} + range_statements_with_multiple_return_values :: proc() { // IMPORTANT NOTE(bill, 2019-11-02): This feature is subject to be changed/removed fmt.println("\n#range statements with multiple return values"); @@ -1281,6 +1650,7 @@ range_statements_with_multiple_return_values :: proc() { soa_struct_layout :: proc() { // IMPORTANT NOTE(bill, 2019-11-03): This feature is subject to be changed/removed + // NOTE(bill): Most likely #soa [N]T fmt.println("\n#SOA Struct Layout"); { @@ -1302,7 +1672,7 @@ soa_struct_layout :: proc() { fmt.println(v_aos[1]); fmt.println(v_aos); - v_soa: intrinsics.soa_struct(N, Vector3); + v_soa: #soa[N]Vector3; v_soa[0].x = 1; v_soa[0].y = 4; @@ -1313,6 +1683,7 @@ soa_struct_layout :: proc() { fmt.println(len(v_soa)); fmt.println(v_soa[0]); fmt.println(v_soa[0].x); + fmt.println(&v_soa[0].x); v_soa[1] = {0, 3, 4}; v_soa[1].x = 2; fmt.println(v_soa[1]); @@ -1341,7 +1712,7 @@ soa_struct_layout :: proc() { v_aos[0].y = 4; v_aos[0].z = 9; - v_soa: intrinsics.soa_struct(N, Vector3); + v_soa: #soa[N]Vector3; v_soa[0].x = 1; v_soa[0].y = 4; @@ -1349,29 +1720,32 @@ soa_struct_layout :: proc() { } } + main :: proc() { when true { - extra_general_stuff(); + the_basics(); + control_flow(); + named_proc_return_parameters(); + explicit_procedure_overloading(); + struct_type(); union_type(); + using_statement(); + implicit_context_system(); parametric_polymorphism(); - threading_example(); array_programming(); - named_proc_return_parameters(); - using_enum(); map_type(); implicit_selector_expression(); - explicit_procedure_overloading(); complete_switch(); cstring_example(); - deprecated_attribute(); bit_set_type(); - diverging_procedures(); deferred_procedure_associations(); reflection(); quaternions(); inline_for_statement(); where_clauses(); + foreign_system(); ranged_fields_for_array_compound_literals(); + deprecated_attribute(); range_statements_with_multiple_return_values(); soa_struct_layout(); } diff --git a/examples/hms2019/basic.odin b/examples/hms2019/basic.odin index e3a41694e..4c4a4eff0 100644 --- a/examples/hms2019/basic.odin +++ b/examples/hms2019/basic.odin @@ -3,5 +3,5 @@ package basic import "core:fmt" main :: proc() { - fmt.println("Hellope!") + fmt.println("Hellope!"); }
\ No newline at end of file diff --git a/examples/hms2019/eca.odin b/examples/hms2019/eca.odin index 2a5036ce7..eaefeeb9b 100644 --- a/examples/hms2019/eca.odin +++ b/examples/hms2019/eca.odin @@ -6,62 +6,62 @@ import "core:time" import "intrinsics" elementary_cellular_automata :: proc(state: $T, rule: u8, generations: int, pause: time.Duration = 0) - where intrinsics.type_is_integer(T), - intrinsics.type_is_unsigned(T) { - N :: 8*size_of(state); + where intrinsics.type_is_integer(T), + intrinsics.type_is_unsigned(T) { + N :: 8*size_of(state); - output :: proc(state: T) { - buf: [N]byte; - for i in 0..<T(N) { - // c := byte('#'); - c := byte(rand.int_max(26) + 'A' + ('a'-'A')*rand.int_max(2)); - buf[N-1-i] = state & (1<<i) != 0 ? c : ' '; - } - fmt.println(string(buf[:])); - } + output :: proc(state: T) { + buf: [N]byte; + for i in 0..<T(N) { + c := byte('#'); + // c := byte(rand.int_max(26) + 'A' + ('a'-'A')*rand.int_max(2)); + buf[N-1-i] = state & (1<<i) != 0 ? c : ' '; + } + fmt.println(string(buf[:])); + } - bit :: proc(x, i: T) -> T { - return (x >> i) & 0x1; - } - set :: proc(x: ^T, cell, k: T, rule: u8) { - x^ &~= 1<<cell; - if rule>>k&1 != 0 { - x^ |= 1<<cell; - } - } + bit :: proc(x, i: T) -> T { + return (x >> i) & 0x1; + } + set :: proc(x: ^T, cell, k: T, rule: u8) { + x^ &~= 1<<cell; + if rule>>k&1 != 0 { + x^ |= 1<<cell; + } + } - a := state; - a1 := T(0); + a := state; + a1 := T(0); - output(a); + output(a); - last := T(N-1); - for r in 0..<generations { - if pause > 0 do time.sleep(pause); - + last := T(N-1); + for r in 0..<generations { + if pause > 0 do time.sleep(pause); + - k := bit(a, last) | bit(a, 0)<<1 | bit(a, 1)<<2; - set(&a1, 0, k, rule); - a1 |= (1<<0) * T(rule>>k&1); - for c in 1..<last { - k = k>>1 | bit(a, c+1)<<2; - set(&a1, c, k, rule); - } - set(&a1, last, k>>1|bit(a, 0)<<2, rule); - a, a1 = a1, a; - output(a); - if a == a1 { - return; - } - } + k := bit(a, last) | bit(a, 0)<<1 | bit(a, 1)<<2; + set(&a1, 0, k, rule); + a1 |= (1<<0) * T(rule>>k&1); + for c in 1..<last { + k = k>>1 | bit(a, c+1)<<2; + set(&a1, c, k, rule); + } + set(&a1, last, k>>1|bit(a, 0)<<2, rule); + a, a1 = a1, a; + output(a); + if a == a1 { + return; + } + } } main :: proc() { - elementary_cellular_automata( - state=rand.uint128(), - rule=30, - generations=100, - pause=100*time.Millisecond, - ); + elementary_cellular_automata( + state=rand.uint128(), + rule=30, + generations=5000, + pause=100*time.Millisecond, + ); }
\ No newline at end of file diff --git a/examples/hms2019/hms2019.odin b/examples/hms2019/hms2019.odin index e6530ba50..2c4712631 100644 --- a/examples/hms2019/hms2019.odin +++ b/examples/hms2019/hms2019.odin @@ -1674,7 +1674,7 @@ soa_struct_layout :: proc() { fmt.println(v_aos[1]); fmt.println(v_aos); - v_soa: intrinsics.soa_struct(N, Vector3); + v_soa: #soa[N]Vector3; v_soa[0].x = 1; v_soa[0].y = 4; @@ -1713,7 +1713,7 @@ soa_struct_layout :: proc() { v_aos[0].y = 4; v_aos[0].z = 9; - v_soa: intrinsics.soa_struct(N, Vector3); + v_soa: #soa[N]Vector3; v_soa[0].x = 1; v_soa[0].y = 4; |