mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
update readme, docs, site, and version to 0.2.0.
This commit is contained in:
parent
db0be51fa4
commit
8c6f8c17f1
@ -21,7 +21,7 @@ mers has...
|
|||||||
+ many strings: `[string ...]` (a list)
|
+ many strings: `[string ...]` (a list)
|
||||||
+ Either a string or nothing (Rust's `Option<String>`): `string/[]`
|
+ 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)`)
|
+ 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?
|
## 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)
|
[intro](docs/intro.md)
|
||||||
|
|
||||||
[builtins](docs/builtins.md)
|
[builtins](docs/builtins.md)
|
||||||
|
|
||||||
|
[statements](docs/statements.md)
|
||||||
|
@ -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... */ {
|
if 10 != 15 /* pretend this actually meant something... */ {
|
||||||
// does something
|
// does something
|
||||||
} else {
|
} 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.")
|
println("Hello! Please enter your name.")
|
||||||
username := read_line()
|
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.
|
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 := ""
|
username := ""
|
||||||
loop {
|
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 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
|
||||||
|
|
||||||
Match statements let you define multiple conditions in a row.
|
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 {
|
number := match {
|
||||||
input.parse_int() n n
|
input.parse_int() n n
|
||||||
input.parse_float() n n
|
input.parse_float() n n
|
||||||
[true] [] []
|
[true] [] Err: "couldn't parse"
|
||||||
}
|
}
|
||||||
number.debug()
|
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`.
|
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 `[]`.
|
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.
|
This is where the magic happens: the `match` statement.
|
||||||
Between the `{` and the `}`, you can put as many "match arms" as you want.
|
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 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.
|
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.
|
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/[]`.
|
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.
|
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/string`.
|
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.
|
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 `12.3`, it outputs `int/float/Err(string) :: float :: 12.3`.
|
||||||
If we input `9`, it outputs `int/float/[] :: int :: 9`.
|
If we input `9`, it outputs `int/float/Err(string) :: int :: 9`.
|
||||||
|
|
||||||
# Switch statements
|
# Switch statements
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
This is the documentation for mers statements.
|
This is the documentation for mers statements.
|
||||||
In code, statements are represented by `SStatement`, `SStatementEnum`, `RStatement`, and `RStatementEnum`.
|
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).
|
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
|
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
|
# Different statements
|
||||||
|
|
||||||
## Value
|
## Value
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<section class="container">
|
<section class="container">
|
||||||
<section class="container_left2 code-border">
|
<section class="container_left2 code-border">
|
||||||
<pre><code class="mers-code-snippet">
|
<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> &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> &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>
|
||||||
<section class="container_right">
|
<section class="container_right">
|
||||||
<image
|
<image
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mers"
|
name = "mers"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
@ -35,7 +35,6 @@ switch! answer {
|
|||||||
// wait one second
|
// wait one second
|
||||||
sleep(1)
|
sleep(1)
|
||||||
|
|
||||||
|
|
||||||
// function that returns an anonymous function (function object).
|
// function that returns an anonymous function (function object).
|
||||||
// anonymous functions can be used as iterators in for-loops.
|
// anonymous functions can be used as iterators in for-loops.
|
||||||
fn square_numbers() {
|
fn square_numbers() {
|
||||||
|
Loading…
Reference in New Issue
Block a user