From: Brendan Hansen Date: Sat, 16 Jan 2021 02:15:38 +0000 (-0600) Subject: added more examples X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=93c76d25023bf898f05e3761e41e273c83d87468;p=onyx.git added more examples --- diff --git a/core/map.onyx b/core/map.onyx index 5d05c0da..1712c837 100644 --- a/core/map.onyx +++ b/core/map.onyx @@ -18,11 +18,11 @@ MapEntry :: struct (K: type_expr, V: type_expr) { value : V; } -init :: proc (use map: ^Map($K, $V), dv: V = ~~0, hash_count: i32 = 16) { +init :: proc (use map: ^Map($K, $V), default: V = ~~0, hash_count: i32 = 16) { array.init(^hashes, hash_count); array.init(^entries, 4); - default_value = dv; + default_value = default; for i: 0 .. hash_count do array.push(^hashes, -1); } diff --git a/examples/09_for_loops.onyx b/examples/09_for_loops.onyx index b8d94c49..17d495d5 100644 --- a/examples/09_for_loops.onyx +++ b/examples/09_for_loops.onyx @@ -1,6 +1,50 @@ +// Looping over data structures is a very common operation done in all programming +// practices. In fact, I'd argue 97% of all programming problems can be solved by +// putting information into an array and looping over it. For this reason, for loops +// in Onyx are extremely simple to use by design and should make programming very +// enjoyable. But I digress, let's look at some examples. + #load "core/std/wasi" use package core main :: proc (args: [] cstr) { + // Currently, for loops can iterate over four kinds of data structures in Onyx: + // * Ranges + // * Fixed arrays + // * Slices + // * Dynamic arrays + + // The syntax of for loops is very simple: + // for ^? : + + // For example, this will print out the numbers in the array literal: + for i: u32.[ 10, 20, 30, 40, 50 ] { + println(i); + } + print("\n\n"); + + + // You may have noticed the options caret (^) in the definition of the for loop + // syntax. When a caret is placed before the iteration variable, the iteration + // variable will be a *pointer* to the data inside the iterator. This is useful + // for iterating over larger data structures that don't need to be copied for + // every iteration, or when you want to modify the elements of the iterator, as + // so: + + primes := u32.[ 2, 3, 5, 7, 11, 13, 17 ]; + for ^prime: primes { + *prime *= 2; + } + + print("Doubled primes: "); + print_array(primes); + + // Currently, there is not support for defining custom iterators for for-loops. + // At the moment, this pattern is the best for that purpose: + // + // while it := iterator_create(...); !iterator_done(^it) { + // defer iterator_next(^it); + // ... + // } } diff --git a/examples/10_switch_statements.onyx b/examples/10_switch_statements.onyx index b8d94c49..c337300c 100644 --- a/examples/10_switch_statements.onyx +++ b/examples/10_switch_statements.onyx @@ -3,4 +3,63 @@ use package core main :: proc (args: [] cstr) { + x := 10 + 3 * 5; + + // The basic syntax of a switch statement: + switch x { + case 10 do println("x was 10."); + + case 25 { + println("x was 25."); + println("Multiple statments go between '{}'."); + } + + case #default { + println("Default case reached."); + } + } + println("\n"); + + // There are several semantic differences between Onyx switch statements and + // C/C++ switch statements. The most obvious one is that there is no implicit + // fallthrough to the next lexical case. This is more intuitive and less error + // prone. If you do with to fallthrough, the `fallthrough` keyword can be used + // as so: + + switch x { + case 10 do println("x was 10."); + + case 25 { + println("x was 25."); + println("Multiple statments go between '{}'."); + fallthrough; // Now we fallthrough + } + + case #default { + println("Default case reached."); + } + } + println("\n"); + + // The other semantic different is that each case introduces a lexical block where + // local variables can be defined, and statements can be deferred. Take this + // interesting example: + + switch 5 { + case 3 do println("This will never be reached."); + + case 5 { + x := math.max(20, 50); + defer printf("x in case '5' is %i.\n", x); + + if x >= 40 do fallthrough; + + println("This statement will never be reached."); + } + + case #default { + println("Default case reached."); + } + } + println("\n"); } diff --git a/examples/11_map.onyx b/examples/11_map.onyx index b8d94c49..1400db29 100644 --- a/examples/11_map.onyx +++ b/examples/11_map.onyx @@ -3,4 +3,56 @@ use package core main :: proc (args: [] cstr) { + // Onyx does not have map type built into the language semantics, + // but using polymorphic structs and overloaded procedures, it does + // provide an 'any-to-any' hash map in it's core libraries. + + // To use it, simply create one like so: + ages : map.Map(str, u32); + map.init(^ages, default=0, hash_count=16); + defer map.free(^ages); + + // The defer statement ensures that the map memory will be freed + // when this procedure exits, no matter through which way. The + // 'default' argument is used to specify what value should be + // returned when the map does not contain the requested key. The + // hash_count is an implementation detail that will go away in the + // near future. It is the maximum number of chains in the hash table. + + // To put an entry into the map, use the map.put procedure. + map.put(^ages, "Dwight", 32); + map.put(^ages, "Jim", 25); + map.put(^ages, "Pam", 24); + + // To retrieve an entry's value, use the map.get procedure. + print_age :: proc (ages: ^map.Map(str, u32), name: str) { + age := map.get(ages, name); + printf("%s's age is %i.\n", name, age); + } + + print_age(^ages, "Dwight"); + print_age(^ages, "Jim"); + print_age(^ages, "Pam"); + print_age(^ages, "Michael"); + + // You may noticed if you ran this program that it prints Michael's + // age is 0. This is because there was entry for the key 'Michael', + // and we provided the default of '0'. To ensure that a key is in the + // map, use the map.has procedure + + println(map.has(^ages, "Dwight")); + println(map.has(^ages, "Michael")); + + + + // Not now nor ever will Onyx support an "interface" concept to say + // which types can do which things. One thing that Onyx does have + // however is explicit overloaded procedures. They are talked about + // more in 14_overloaded_procs.onyx. For our purposes right now, we + // just need to know that Map uses two overloaded procedures to + // achieve its implementation: map.hash_function, map.cmp_function. + // To make Map work with any new datatype you come up with, simply + // define an overload for map.hash_function and map.cmp_function. + // If you want to see what this looks like, take a look at + // tests/aoc-2020/day17.onyx in this repository. }