# mers syntax cheat sheet ## Types - `bool` - `int` - `float` - `string` - tuple: `[<type1> <type2> <type3> <...>]` - list: `[<type> ...]` - function: `fn(<input-output-map>)` (might change? depends on implementation of generics) - thread: `thread(<return_type>)` - reference: `&<type>` or `&(<type1>/<type2>/<...>)` - enum: `EnumName(<type>)` - one of multiple types: `<type1>/<type2>/<type3>` ## Values - bool + `true` or `false` - int + decimal: `2`, `+2`, `-5`, `0`, ... - float + decimal: `1.5`, `0.5`, `-5.2`, `2.0`, ... (this is recommended for compatability and clarity) + whole numbers: `1.0`, `1.`, ... (may break with future updates) + numbers from 0 to 1: `.5` would be ambiguous following tuples, so is not supported. - string + `"my string"` (double quotes) + `"it's called \"<insert name>\""` (escape inner double quotes with backslash) + all escape sequences * `\"` double quote character * `\\` backslash character * `\n` newline * `\r` carriage return * `\t` tab * `\0` null - tuple + `[<val1> <val2> <val3> <...>]` - list + `[<val1> <val2> <val3> <...> ...]` (like tuple, but `...]` instead of `]`) - function + `(<arg1> <arg2> <arg3> <...>) <statement>` where `<argn>` is `<namen> <typen>`. - thread + returned by the builtin function `thread()` - reference + to a variable: `&<varname>` + to something else: usually using `get()` or its equivalent on a reference to a container instead of the container itself: `&list.get()` instead of `list.get()` - enum + `<EnumName>: <statement>` ## Variables - declaration and initialization + `<var_name> := <statement>` + can shadow previous variables with the same name: `x := 5 { x := 10 debug(x) } debug(x)` prints `10` and then `5`. - assignment + `&<var_name> = <statement>` * modifies the value: `x := 5 { &x = 10 debug(x) } debug(x)` prints `10` and then `10`. + `<statement_left> = <statement_right>` * assigns the value returned by `<statement_right>` to the value behind the reference returned by `<statement_left>`. * if `<statement_right>` returns `<type>`, `<statement_left>` has to return `&<type>`. * this is why `&<var_name> = <statement>` is the way it is. + `***<statement_left> = <statement_right>` * same as before, but performs dereferences: `&&&&int` becomes `&int` (minus 3 references because 3 `*`s), so a value of type `int` can be assigned to it. - destructuring + values can be destructured into tuples or lists (as of right now): + `[a, b] := [10, "some text"]` is effectively the same as `a := 10, b := "some text"` ## Statements - value + `10`, `true`, `"text"`, `"[]"`, etc - tuple + `[<statement1> <statement2> <...>]` - list + `[<statement1> <statement2> <...> ...]` - variable + `<var_name>` (if the name of the variable isn't a value or some other kind of statement) - function call + `<fn_name>(<arg1> <arg2> <...>)` + `<fn_name>(<arg1>, <arg2>, <...>)` + `<arg1>.<fn_name>(<arg2>, <...>)` - function definition + `fn <fn_name>(<arg1> <arg2> <...>) <statement>` where `<argn>` is `<namen> <typen>` - block + `{ <statement1> <statement2> <...> }` - if + `if <condition> <statement>` (`if true println("test")`) + `if <condition> <statement> else <statement>` (`if false println("test") else println("value was false")`) - loop + `loop <statement>` + if the statement returns a value that matches, the loop will end and return the matched value + the loop's return type is the match of the return type of the statement - for loop + `for <assign_to> <iterator> <statement>` + in each iteration, the variable will be initialized with a value from the iterator. + iterators can be lists, tuples, or functions. + for function iterators, as long as the returned value matches, the matched value will be used. if the value doesn't match, the loop ends. + if the statement returns a value that matches, the loop will end and return the matched value + the loop's return type is the match of the return type of the statement or `[]` (if the loop ends because the iterator ended) - switch + `switch <value> { <arm1> <arm2> <...> }` * where `<armn>` is `<typen> <assign_to> <statementn>` * if the variable's value is of type `<typen>`, `<statementn>` will be executed with `<value>` assigned to `<assign_to>`. * if the variables type is included multiple times, only the first match will be executed. * within the statement of an arm, the variables type is that specified in `<typen>`, and not its original type (which may be too broad to work with) + `switch! <var_name> { <arm1> <arm2> <...> }` * same as above, but all types the variable could have must be covered * the additional `[]` in the return type isn't added here since it is impossible not to run the statement of one of the arms. - match + `match { <arm1> <arm2> <...> }` * where `<armn>` is `<(condition) statement> <assign_to> <(action) statement>` * each arm has a condition statement, something that the matched value will be assigned to, and an action statement. * if the value returned by the condition statement matches, the matched value is assigned to `<assign_to>` and the action statement is executed. * only the first matching arm will be executed. if no arm was executed, `[]` is returned. - fixed-indexing + `<statement>.n` where `n` is a fixed number (not a variable, just `0`, `1`, `2`, ...) + `<statement>` must return a tuple or a reference to one. `<statement>.n` then refers to the nth value in that tuple. + for references to a tuple, references to the inner values are returned. - enum + `<EnumName>: <statement>` - type definition + `type <name> <type>` (`type Message [string string]`) - macros + `!(<macro_type> <...>)` + `!(mers { <code> })` * compiles and runs the code at compile-time, then returns the computed value at runtime. + `!(mers <file_path>)` or `!(mers "<file path with spaces and \" double quotes>")` * same as above, but reads code from a file instead * path can be relative ## Matching - values that don't match + `[]` + `false` - values that match + `[v]` -> `v` + `v` -> `v` unless otherwise specified - invalid + `[v1 v2]` or any tuple whose length isn't `0` or `1`