diff --git a/README.md b/README.md index c4818ec..50c6225 100644 --- a/README.md +++ b/README.md @@ -13,3 +13,4 @@ with the language. itself. There's very few data structures, meaning there's minimal syntax. * [runtime](/doc/runtime.md) - How to structure your ginger data to be runnable by the ginger interpreter. Includes execution, variable definition, scope, and function definition. +* [pattern matching](/doc/pattern.md) - Deconstruction of data structures and case statements on them. diff --git a/doc/pattern.md b/doc/pattern.md new file mode 100644 index 0000000..7b3ee01 --- /dev/null +++ b/doc/pattern.md @@ -0,0 +1,138 @@ +# Pattern Matching + +Pattern matching in ginger is used both to assign variables and test for the contents of them. + +## Assignment + +The `=` function's job is to assign values to variables. In the simplest case: +``` +(= Foo 5) +``` + +Assigns the value `5` to the variable named `Foo`. We can assign more complicated values to variables +as well: +``` +(= Foo [1 2 3 4]) +``` + +### Deconstruction + +With pattern matching, we can deconstruct the value on the right side and assign its individual parts +to their own individual variables: +``` +[ + (= [Foo Bar [Baz Box] Bus] [1 a [3 4] [5 6]]) + (println Foo) + (println Bar) + (println Baz) + (println Box) + (println Bus) +] +``` + +The above would print out: +``` +1 +a +3 +4 +[5 6] +``` + +### No Match + +What happens if we try to pattern match a value that doesn't match the left side?: +``` +(= [Foo Bar Baz Box] [1 2 3]) ; => [error nomatch] +``` + +The value itself is a vector with three items, but we want a vector with four! This returns an error +and none of the variables were assigned. + +### Blanks + +If there's a variable we expect the right side to have, but we don't actually want to do anything with +it, we can use `_`: +``` +(= [Foo _ Baz] [1 2 3]) +``` + +The above would assign `1` to `Foo` and `2` to `Baz`. + +### Left-side checks + +The left side isn't exclusively used for assignment, it can also be used to check certain values on +the right: +``` +(= [1 Foo 2 Bar] [1 a 2 b]) ; => success +(= [1 Foo 2 Bar] [1 a 3 b]) ; => [error nomatch] +``` + +If a variable is already defined it can be used as a check as well: +``` +[ + (= Foo 1) + (= [Foo Foo Bar] [1 1 2]) ; => success + (= [Foo Foo Baz] [1 2 3]) ; => [error nomatch] +] +``` + +Finally, undefined variables on the left side that are used more than once are ensured that all +instances have the same value: +``` +[ + (= [Foo Foo Foo] [foo foo foo]) ; => success + (= [Bar Bar Bar] [foo bar bar]) ; => [error nomatch] +] +``` + +### Vectors + +What if we don't know the full length of the vector, but we only want to retrieve the first two values +from it?: +``` +(= [Foo Bar -] [1 2 3 4 5]) +``` + +The above would assign `1` to `Foo` and `2` to `Bar`. `-` is treated to mean "zero or more items in the sequence +that we don't care about". + +What if you want to match on the tail end of the vector?: +``` +(= [- Bar Foo] [1 2 3 4 5]) +``` + +The above would assign `4` to Bar and `5` to `Foo`. + +Can we do both?: +``` +(= [Foo - Bar] [1 2 3 4 5]) +``` + +The above would assign `1` to `Foo` and `5` to `Bar`. + +### Lists + +Everything that applies to vectors applies to lists, as far as pattern matching goes: +``` +(= (Foo Bar Baz -) (l (foo bar baz))) +``` + +In the above `foo` is assigned to `Foo`, `bar` to `Bar`, and `baz` to `Baz`. + +Note that the right side needs the `l` literal wrapper to prevent evaluation, while +the left side does not. Nothing on the left will ever be evaluated, if you want it +to be dynamically defined you'll have to use a macro. + +### Maps + +Pattern matching can be performed on maps as well: +``` +(= { Foo Bar } { a b }) ; => success +(= { Foo Bar } { a b c d }) ; => [error nomatch] +(= { Foo Bar - - } { a b c d }) ; => success +``` + +In the last case, the important thing is that the key is `-`. This tells the matcher +that you don't care about any other keys that may or may not exist. The value can be +anything, but `-` seems semantically more correct imo. diff --git a/doc/runtime.md b/doc/runtime.md index f894fa1..24d1dca 100644 --- a/doc/runtime.md +++ b/doc/runtime.md @@ -41,7 +41,7 @@ item in the vector. For (a trivial) example: The above example does a few things, but it repeats itself in the second part (with the `sub`). If we could save the result of the addition to a variable that would be awesomesauce. The `=` function does this! It makes it so that the first argument is equivalent to the evaluation of the second argument. Variables' can not be re-defined to be another -value, and their first letters must be upper-case, thisis how they're differentiated from raw string literals.The above +value, and their first letters must be upper-case, this is how they're differentiated from raw string literals.The above could be re-written as: ``` [ (= AdditionResult (add 1 2))