update readme, docs, site, and version to 0.2.0.

This commit is contained in:
mark 2023-06-04 21:59:38 +02:00
parent db0be51fa4
commit 8c6f8c17f1
6 changed files with 28 additions and 15 deletions

View File

@ -21,7 +21,7 @@ mers has...
+ many strings: `[string ...]` (a list)
+ Either a string or nothing (Rust's `Option<String>`): `string/[]`
+ Either an int or an error: (Rust's `Result<isize, String>`): `int/string` (better: `int/Err(string)`)
- compile-time execution through (explicit) macro syntax
- compile-time execution through (explicit) macro syntax: `!(mers {<code>})` or `!(mers "file")`
## How mers?
@ -36,3 +36,5 @@ Now, create a new text file (or choose one from the examples) and run it: `mers
[intro](docs/intro.md)
[builtins](docs/builtins.md)
[statements](docs/statements.md)

View File

@ -14,10 +14,10 @@ To write a comment that spans multiple lines or ends before the end of the line,
if 10 != 15 /* pretend this actually meant something... */ {
// does something
} else {
// TODO: implement this!
// do something else
}
To declare a new variable, `:=` is used.
To declare a new variable, use `:=`.
println("Hello! Please enter your name.")
username := read_line()
@ -79,7 +79,7 @@ By adding `else <what to do>` after an if statement, we can define what should h
Let's force the user to give us their name.
For this, we'll do what any not-insane person would do: Ask them repeatedly until they listen to us.
For this, we'll do what any not-insane person would do: Ask them repeatedly until they answer.
username := ""
loop {
@ -136,6 +136,8 @@ Since the value we want to get out of the loop is the `username`, not just `true
If the input isn't empty, we return it from the loop since a value of type `string` will match. The value is then assigned to `username` and printed.
If the input was still empty, `input.len() > 0` will return `false`, causing the `if` statement to return `[]`, which doesn't match, so the loop will continue.
# Match statements
Match statements let you define multiple conditions in a row.
@ -146,7 +148,7 @@ One of my favorite examples for mers' strength is this:
number := match {
input.parse_int() n n
input.parse_float() n n
[true] [] []
[true] [] Err: "couldn't parse"
}
number.debug()
@ -155,7 +157,7 @@ Unfortunately, this needs quite a lengthy explanation.
First, `parse_int()` and `parse_float()`. These are functions that take a string as their argument and return `[]/int` or `[]/float`.
They try to read a number from the text and return it. If this fails, they return `[]`.
Conveniently (except not - this is obviously on purpose), `[]` doesn't match while `int` and `float` values do.
Conveniently, `[]` doesn't match while `int` and `float` values do.
This is where the magic happens: the `match` statement.
Between the `{` and the `}`, you can put as many "match arms" as you want.
@ -167,16 +169,16 @@ The three statements here are `input.parse_int()` (condition), `n` (assign_to),
If the input isn't a number, `input.parse_int()` will return `[]`. Since this doesn't match, the second match arm (`input.parse_float()`) will try to parse it to a float instead.
If the input is a number, `input.parse_int()` will return an `int`. Since this matches, the match arm will be executed.
First, the matched value - the `int` - will be assigned to `n`. the assign_to part behaves like the left side of a `:=` expression, with the matched `int` in the right.
First, the matched value - the `int` - will be assigned to `n`. the assign_to part behaves like the left side of a `:=` expression (it supports destructuring and will declare new variables).
Finally, the action statement uses our new variable `n` which contains the number we have parsed and returns it from the match statement.
Since the two arms in the match statement return `int` and `float`, the match statement will return `int/float/[]`.
To get rid of the `[]`, we need to add a third arm: `[true] [] "default value"`. `[true]` is a value that the compiler knows will always match - a tuple of length 1. Assigning something to an empty tuple `[]` just gets rid of the value.
The return type is now `int/float/string`.
To get rid of the `[]`, we need to add a third arm: `[true] [] Err: "couldn't parse"`. `[true]` is a value that the compiler knows will always match - a tuple of length 1. Assigning something to an empty tuple `[]` just gets rid of the value.
The return type is now `int/float/Err(string)`.
Finally, we `debug()` the variable. Debug is a builtin function that prints the expected type (statically determined at compile-time), the actual type, and the value.
If we input `12.3`, it outputs `int/float/[] :: float :: 12.3`.
If we input `9`, it outputs `int/float/[] :: int :: 9`.
If we input `12.3`, it outputs `int/float/Err(string) :: float :: 12.3`.
If we input `9`, it outputs `int/float/Err(string) :: int :: 9`.
# Switch statements

View File

@ -3,7 +3,7 @@
This is the documentation for mers statements.
In code, statements are represented by `SStatement`, `SStatementEnum`, `RStatement`, and `RStatementEnum`.
## statement prefixes
## Statement prefixes
A statement can be prefixed with any number of stars `*`. This is called dereferencing and turns a reference to a value into the value itself. Modifying the value after a dereference leaves the value the reference was pointing to untouched (the data will be cloned to achieve this).
@ -16,6 +16,16 @@ In combination with functions, this is similar to rust's syntax:
a + b
}
## Assignment
Statements can assign their value instead of returning it.
The syntax for this is `<ref_statement> = <statement>` or `<assign_to> := <statement>`.
If just `=` is used, the left side must return a reference to some value which will then be changed to the value generated on the right.
If `:=` is used, new variables can be declared on the left.
Destructuring is possible too: `[a, b] := [12, 15]`.
# Different statements
## Value

View File

@ -9,7 +9,7 @@
<section class="container">
<section class="container_left2 code-border">
<pre><code class="mers-code-snippet">
fn get_number_input(question string) {<br> println(question)<br> input := read_line()<br> // try to parse to an int, then a float.<br> in := match {<br> input.parse_int() n n<br> input.parse_float() n n<br> }<br> // 'in' has type int/float/[] because of the match statement<br> switch! in {<br> int/float in in<br> // replace [] with an appropriate error before returning<br> [] [] Err: "input was not a number."<br> }<br> // return type is int/float/Err(string)<br>}<br><br>answer := get_number_input("What is your favorite number?")<br><br>answer.debug() // type: int/float/Err(string)<br>// switch can be used to branch based on a variables type.<br>// switch! indicates that every possible type must be handled.<br>switch! answer {<br> int num {<br> println("Entered an integer")<br> num.debug() // type: int<br> }<br> float num {<br> println("Entered a decimal number")<br> num.debug() // type: float<br> }<br> Err(string) [] println("Input was not a number!")<br>}<br><br>// wait one second<br>sleep(1)<br><br><br>// function that returns an anonymous function (function object).<br>// anonymous functions can be used as iterators in for-loops.<br>fn square_numbers() {<br> i := 0<br> () {<br> &amp;i = i + 1<br> i * i<br> }<br>}<br><br>for num square_numbers() {<br> println(num.to_string())<br> // once num is greater than 60, the loop stops.<br> num.gt(50)<br>}<br></code></pre>
fn get_number_input(question string) {<br> println(question)<br> input := read_line()<br> // try to parse to an int, then a float.<br> in := match {<br> input.parse_int() n n<br> input.parse_float() n n<br> }<br> // 'in' has type int/float/[] because of the match statement<br> switch! in {<br> int/float in in<br> // replace [] with an appropriate error before returning<br> [] [] Err: "input was not a number."<br> }<br> // return type is int/float/Err(string)<br>}<br><br>answer := get_number_input("What is your favorite number?")<br><br>answer.debug() // type: int/float/Err(string)<br>// switch can be used to branch based on a variables type.<br>// switch! indicates that every possible type must be handled.<br>switch! answer {<br> int num {<br> println("Entered an integer")<br> num.debug() // type: int<br> }<br> float num {<br> println("Entered a decimal number")<br> num.debug() // type: float<br> }<br> Err(string) [] println("Input was not a number!")<br>}<br><br>// wait one second<br>sleep(1)<br><br>// function that returns an anonymous function (function object).<br>// anonymous functions can be used as iterators in for-loops.<br>fn square_numbers() {<br> i := 0<br> () {<br> &amp;i = i + 1<br> i * i<br> }<br>}<br><br>for num square_numbers() {<br> println(num.to_string())<br> // once num is greater than 60, the loop stops.<br> num.gt(50)<br>}<br></code></pre>
</section>
<section class="container_right">
<image

View File

@ -1,6 +1,6 @@
[package]
name = "mers"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -35,7 +35,6 @@ switch! answer {
// wait one second
sleep(1)
// function that returns an anonymous function (function object).
// anonymous functions can be used as iterators in for-loops.
fn square_numbers() {