added struct and enum examples
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 13 Jan 2021 23:26:54 +0000 (17:26 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 13 Jan 2021 23:26:54 +0000 (17:26 -0600)
examples/07_structs.onyx
examples/08_enums.onyx
onyx.exe

index b8d94c49f13a1d6e23a8d7b55df96f6faa18fbf1..bacf8d67b0a03b95a10c4b6692a7cf952c3daac5 100644 (file)
@@ -1,6 +1,167 @@
+// Structured data is the backbone of most modern programming languages.
+// It allows the programmer to think in terms of higher level data structures
+// that otherwise would be very hard to talk about otherwise.
+
+// 'structs' in Onyx are very similar to structs in C and C++, with a couple
+// of additional capabilities to make using them even easier.
+
 #load "core/std/wasi"
 
 use package core
 
 main :: proc (args: [] cstr) {
+
+    // This is the basic struct syntax. Members are declared just like
+    // local variables in procedures.
+    Person :: struct {
+        name   : str;
+        age    : u32;
+        height : u32;
+    }
+
+    // Structs can be passed by value to procedures.
+    print_person :: proc (person: Person) {
+        printf("Person(%s, %i, %i)\n", person.name, person.age, person.height);
+    }
+
+    // This is the verbose way to declare a local variable with a struct
+    // type and initialize its values.
+    person : Person;
+    person.name = "Joe";
+    person.age = 37;
+    person.height = 168;
+
+    print_person(person);
+
+    // A quicker way to write the same thing as above is to use struct literals.
+    // Like array literals, the struct name goes before the '.', and then the
+    // members are listed off in the order that the appear in the struct definition.
+    other_person := Person.{ "Joe", 37, 168 };
+    print_person(other_person);
+
+    // You can also name the members in the struct literal, if a different order makes
+    // sense in a particular situtation.
+    one_more_person := Person.{ age = 37, height = 168, name = "Joe" };
+    print_person(one_more_person);
+
+
+    print_spacer();
+
+    // One capability that Onyx structs have is default values for struct members.
+    // These are only used when a member is omitted from a struct literal at the
+    // moment. This means that the following example does NOT initialize the members
+    // to their defaults:
+    //
+    //          vec : Vector2f;
+    //
+    Vector2f :: struct {
+        x : f32 = 12;
+        y : f32 = 34;
+    }
+
+    print_vector2f :: proc (vec: Vector2f) {
+        printf("Vector2f(%f, %f)", vec.x, vec.y);
+    }
+
+    // This does initialize the members to their defaults.
+    vec := Vector2f.{};
+    print_vector2f(vec);
+    print("\n");
+
+
+
+
+    print_spacer();
+
+    // Structs in Onyx can behave like C unions, simply by usings the '#union' directive.
+    FloatIntUnion :: struct #union {
+        i : i32;
+        f : f32;
+    }
+
+    fiu : FloatIntUnion;
+    fiu.f = 0.5f;
+    printf("Integer representation of 0.5: %p\n", fiu.i);
+
+
+
+    print_spacer();
+
+    // Onyx does not support "inheritance" in structures because it is trying to stay
+    // away from that OOP mindset. Instead, Onyx supports a composition way of structuring data.
+    // The 'use' keyword can be applied to any struct member that is of struct type, and it
+    // will automatically bring in all of the members from the other struct into the current struct.
+    // For example,
+
+    // We define two dummy structs that will be composed.
+    ComponentOne :: struct {
+        name     : str;
+        position : Vector2f;
+    }
+
+    ComponentTwo :: struct {
+        velocity     : Vector2f;
+        acceleration : Vector2f;
+    }
+
+    // `Thing` is a composition of two different structs. All of the members from ComponentOne
+    // and ComponentTwo can be used directly, without needing to say something like,
+    // '.component_one.name'.
+    Thing :: struct {
+        use component_one : ComponentOne;
+        use component_two : ComponentTwo;
+
+        another_data_member : i32;
+    }
+
+    thing := Thing.{
+        component_one = ComponentOne.{ "Player", Vector2f.{ 0, 0 } },
+        component_two = ComponentTwo.{ Vector2f.{ 10, 10 }, Vector2f.{ 0, 0 } },
+
+        another_data_member = 1234,
+    };
+
+    printf("%s, (%f, %f)\n", thing.name, thing.velocity.x, thing.velocity.y);
+
+    // This is very useful in many different situtations. Another useful feature is an implicit
+    // pointer conversion between two structs, A and B, if A is the first member of B, and is used.
+    // For example, we can pass `thing` to this procedure, even though it is not a ComponentOne.
+    // The first member is a ComponentOne and is used, so a implicit pointer conversion is always safe.
+    do_something_with_component_one :: proc (c: ^ComponentOne) {
+        printf("ComponentOne's name is %s.\n", c.name);
+    }
+
+    do_something_with_component_one(^thing);
+
+
+
+    print_spacer();
+
+    // One final thing to talk about is structs with parameters, or parameterized structs.
+    // Structs in Onyx can take in compile-time known values as arguments, and use them in the struct body.
+    // For exmaple,
+    ParamStruct :: struct (T: type_expr, N: i32) {
+        t_member   : T;
+        array_of_T : [N] T;
+    }
+
+    // This struct takes in two parameters: A type expression T (which is only valid for struct parameters,
+    // not procedure parameters at the moment), and an integer N. It has two members. The first being of
+    // type T, and the second being an N dimensional array of type T.
+
+    // To use a struct with parameters, simply pass them in the type.
+    param_struct_instance : ParamStruct(f32, 10);
+    param_struct_instance.t_member = 3.14159;
+    param_struct_instance.array_of_T = f32.[ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ];
+
+    println("param_struct_instance values:");
+    println(param_struct_instance.t_member);
+    for elem: param_struct_instance.array_of_T do printf("%f ", elem);
+    print("\n");
+
+
+
+
+    print_spacer :: proc () do println("\n===========================================");
 }
+
index b8d94c49f13a1d6e23a8d7b55df96f6faa18fbf1..64fbd39defc3fcae1b9cc4e4a54710ed7e58b2bb 100644 (file)
@@ -1,6 +1,48 @@
+// Enumerations (or enums for short) in Onyx work very similar to how they do
+// in C and C++.
+
 #load "core/std/wasi"
 
 use package core
 
 main :: proc (args: [] cstr) {
+    // To declare a simple, use the enum keyword.
+    SimpleEnum :: enum {
+        Value1; Value2; Value3;
+    }
+
+    println(cast(i32) SimpleEnum.Value1);
+    println(cast(i32) SimpleEnum.Value2);
+    println(cast(i32) SimpleEnum.Value3);
+    print("\n");
+
+
+    // Values can be given explicitly for some of the elements.
+    OutOfOrder :: enum {
+        Value1; // Defaults to 0
+        Value2 :: 10;
+        Value3; // Defaults to 11
+    }
+
+    println(cast(i32) OutOfOrder.Value1);
+    println(cast(i32) OutOfOrder.Value2);
+    println(cast(i32) OutOfOrder.Value3);
+    print("\n");
+
+
+    // One common thing you might want to do in C is have an enum that
+    // represents bit-wise flags. This is easy in Onyx by using the
+    // #flags directive.
+    FlaggedEnum :: enum #flags {
+        Value1; // Defaults to 1;
+        Value2; // Defaults to 2;
+        Value3; // Defaults to 4;
+        Value4; // Defaults to 8;
+    }
+
+    println(cast(i32) FlaggedEnum.Value1);
+    println(cast(i32) FlaggedEnum.Value2);
+    println(cast(i32) FlaggedEnum.Value3);
+    println(cast(i32) FlaggedEnum.Value4);
+    print("\n");
 }
index 003fe740b02990f84878d8b64c8dc960d25eb13a..2ff42df1cedcfc7d81d6fccb832c5c3b3d3ac1ee 100644 (file)
Binary files a/onyx.exe and b/onyx.exe differ