mirror of
				https://github.com/Dummi26/mers.git
				synced 2025-11-03 21:16:16 +01:00 
			
		
		
		
	add examples, prepare for new readme
This commit is contained in:
		
							parent
							
								
									d124bff77f
								
							
						
					
					
						commit
						0c87c69743
					
				@ -1,93 +0,0 @@
 | 
				
			|||||||
# mers
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Mers is a high-level programming language.
 | 
					 | 
				
			||||||
It is designed to be safe (it doesn't crash at runtime) and as simple as possible.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Install from *crates.io*:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```sh
 | 
					 | 
				
			||||||
cargo install mers
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
See also:
 | 
					 | 
				
			||||||
[Quickstart](Quickstart.md)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## what makes it special
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Simplicity
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Mers is simple. There are only few expressions:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Values (`1`, `"my string"`, ...)
 | 
					 | 
				
			||||||
- Blocks (`{}`)
 | 
					 | 
				
			||||||
- Tuples (`()`) and Objects (`{}`)
 | 
					 | 
				
			||||||
- Assignments (`=`)
 | 
					 | 
				
			||||||
- Variable initializations (`:=`)
 | 
					 | 
				
			||||||
- Variables (`my_var`, `&my_var`)
 | 
					 | 
				
			||||||
- If statements (`if <condition> <then> [else <else>]`)
 | 
					 | 
				
			||||||
- Functions (`arg -> <do something>`)
 | 
					 | 
				
			||||||
- Function calls `arg.function` or `arg1.function(arg2, arg3)` (= `(arg1, arg2, arg3).function`)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Everything else is implemented as a function.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Types and Safety
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Mers is built around a type-system where a value could be one of multiple types.
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
x := if condition { 12 } else { "something went wrong" }
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
In mers, the compiler tracks all the types in your program,
 | 
					 | 
				
			||||||
and it will catch every possible crash before the program even runs:
 | 
					 | 
				
			||||||
If we tried to use `x` as an int, the compiler would complain since it might be a string, so this **does not compile**:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
list := (1, 2, if true 3 else "not an int")
 | 
					 | 
				
			||||||
list.sum.println
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Type-safety for functions is different from what you might expect.
 | 
					 | 
				
			||||||
You don't need to tell mers what type your function's argument has - you just use it however you want as if mers was a dynamically typed language:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
sum_doubled := iter -> {
 | 
					 | 
				
			||||||
  one := iter.sum
 | 
					 | 
				
			||||||
  (one, one).sum
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
(1, 2, 3).sum_doubled.println
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
We could try to use the function improperly by passing a string instead of an int:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
(1, 2, "3").sum_doubled.println
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
But mers will catch this and show an error, because the call to `sum` inside of `sum_doubled` would fail.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Error Handling
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Errors in mers are normal values.
 | 
					 | 
				
			||||||
For example, `("ls", ("/")).run_command` has the return type `({Int/()}, String, String)/RunCommandError`.
 | 
					 | 
				
			||||||
This means it either returns the result of the command (exit code, stdout, stderr) or an error (a value of type `RunCommandError`).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
So, if we want to print the programs stdout, we could try
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
(s, stdout, stderr) := ("ls", ("/")).run_command
 | 
					 | 
				
			||||||
stdout.println
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
But if we encountered a `RunCommandError`, mers wouldn't be able to assign the value to `(s, stdout, stderr)`, so this doesn't compile.
 | 
					 | 
				
			||||||
Instead, we need to handle the error case, using the `try` function:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
("ls", ("/")).run_command.try((
 | 
					 | 
				
			||||||
  (s, stdout, stderr) -> stdout.println,
 | 
					 | 
				
			||||||
  error -> error.println,
 | 
					 | 
				
			||||||
))
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## docs
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
docs will be available in some time. for now, check mers_lib/src/program/configs/*
 | 
					 | 
				
			||||||
@ -1,93 +1,7 @@
 | 
				
			|||||||
# mers
 | 
					# mers-lib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Mers is a high-level programming language.
 | 
					The library behind [mers](https://github.com/Dummi26/mers).
 | 
				
			||||||
It is designed to be safe (it doesn't crash at runtime) and as simple as possible.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Install from *crates.io*:
 | 
					With this, you can parse, compile, check and run mers code.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```sh
 | 
					You can also add your own functions and types which can then be used from mers, if you really want to.
 | 
				
			||||||
cargo install mers
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
See also:
 | 
					 | 
				
			||||||
[Quickstart](Quickstart.md)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## what makes it special
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Simplicity
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Mers is simple. There are only few expressions:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Values (`1`, `"my string"`, ...)
 | 
					 | 
				
			||||||
- Blocks (`{}`)
 | 
					 | 
				
			||||||
- Tuples (`()`) and Objects (`{}`)
 | 
					 | 
				
			||||||
- Assignments (`=`)
 | 
					 | 
				
			||||||
- Variable initializations (`:=`)
 | 
					 | 
				
			||||||
- Variables (`my_var`, `&my_var`)
 | 
					 | 
				
			||||||
- If statements (`if <condition> <then> [else <else>]`)
 | 
					 | 
				
			||||||
- Functions (`arg -> <do something>`)
 | 
					 | 
				
			||||||
- Function calls `arg.function` or `arg1.function(arg2, arg3)` (= `(arg1, arg2, arg3).function`)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Everything else is implemented as a function.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Types and Safety
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Mers is built around a type-system where a value could be one of multiple types.
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
x := if condition { 12 } else { "something went wrong" }
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
In mers, the compiler tracks all the types in your program,
 | 
					 | 
				
			||||||
and it will catch every possible crash before the program even runs:
 | 
					 | 
				
			||||||
If we tried to use `x` as an int, the compiler would complain since it might be a string, so this **does not compile**:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
list := (1, 2, if true 3 else "not an int")
 | 
					 | 
				
			||||||
list.sum.println
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Type-safety for functions is different from what you might expect.
 | 
					 | 
				
			||||||
You don't need to tell mers what type your function's argument has - you just use it however you want as if mers was a dynamically typed language:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
sum_doubled := iter -> {
 | 
					 | 
				
			||||||
  one := iter.sum
 | 
					 | 
				
			||||||
  (one, one).sum
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
(1, 2, 3).sum_doubled.println
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
We could try to use the function improperly by passing a string instead of an int:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
(1, 2, "3").sum_doubled.println
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
But mers will catch this and show an error, because the call to `sum` inside of `sum_doubled` would fail.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Error Handling
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Errors in mers are normal values.
 | 
					 | 
				
			||||||
For example, `("ls", ("/")).run_command` has the return type `({Int/()}, String, String)/RunCommandError`.
 | 
					 | 
				
			||||||
This means it either returns the result of the command (exit code, stdout, stderr) or an error (a value of type `RunCommandError`).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
So, if we want to print the programs stdout, we could try
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
(s, stdout, stderr) := ("ls", ("/")).run_command
 | 
					 | 
				
			||||||
stdout.println
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
But if we encountered a `RunCommandError`, mers wouldn't be able to assign the value to `(s, stdout, stderr)`, so this doesn't compile.
 | 
					 | 
				
			||||||
Instead, we need to handle the error case, using the `try` function:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
("ls", ("/")).run_command.try((
 | 
					 | 
				
			||||||
  (s, stdout, stderr) -> stdout.println,
 | 
					 | 
				
			||||||
  error -> error.println,
 | 
					 | 
				
			||||||
))
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## docs
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
docs will be available in some time. for now, check mers_lib/src/program/configs/*
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,58 +0,0 @@
 | 
				
			|||||||
# mers documentation
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## ISSUES
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
when storing a reference, then reinitializing a variable of the same name, the reference may get the new value although
 | 
					 | 
				
			||||||
it would be expected for it to be a reference to the value before it was reinitialized.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## parsing
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
syntax:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- `// <comment>`
 | 
					 | 
				
			||||||
- `/* <comment> */`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
operators:
 | 
					 | 
				
			||||||
- `<target> := <source>` init
 | 
					 | 
				
			||||||
- `<target> = <source>` assign (`<target>` must be a reference)
 | 
					 | 
				
			||||||
- `+`
 | 
					 | 
				
			||||||
- `-`
 | 
					 | 
				
			||||||
- `*`
 | 
					 | 
				
			||||||
- `/`
 | 
					 | 
				
			||||||
- `%`
 | 
					 | 
				
			||||||
- `&`
 | 
					 | 
				
			||||||
- `|`
 | 
					 | 
				
			||||||
- `&&`
 | 
					 | 
				
			||||||
- `||`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
keywords (must be between whitespace):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- `if <condition> <statement>`
 | 
					 | 
				
			||||||
- `else <statement>` (after `if`)
 | 
					 | 
				
			||||||
- `loop <statement>`
 | 
					 | 
				
			||||||
- `switch { <arms> }`
 | 
					 | 
				
			||||||
- `<arg> -> <statement>`
 | 
					 | 
				
			||||||
- `def <name> <: for types, = for comptime> <_>` for compile-time stuff (types, macros, ...)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## details
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### functions
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
A function takes an argument and returns some data:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    func := input -> input + 2
 | 
					 | 
				
			||||||
    3.func.println // 5
 | 
					 | 
				
			||||||
    (list, 0).get // first element
 | 
					 | 
				
			||||||
    (val, match -> match.println, [] -> "doesn't match".println).match
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### switch
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    switch <val> {
 | 
					 | 
				
			||||||
        <type> <func>
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    switch something {
 | 
					 | 
				
			||||||
        int num -> {"int: " + num}.println
 | 
					 | 
				
			||||||
        float num -> {"float: " + num}.println
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
							
								
								
									
										50
									
								
								mers_lib/examples/00_parse_compile_check_run.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								mers_lib/examples/00_parse_compile_check_run.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					use std::sync::Arc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use mers_lib::{
 | 
				
			||||||
 | 
					    data::{Data, MersType, Type},
 | 
				
			||||||
 | 
					    errors::CheckError,
 | 
				
			||||||
 | 
					    prelude_compile::{parse, CompInfo, Config, Source},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() {
 | 
				
			||||||
 | 
					    show("1.sum(2)".to_owned());
 | 
				
			||||||
 | 
					    show("1.sum(2).println".to_owned());
 | 
				
			||||||
 | 
					    show("1.sum(2.5)".to_owned());
 | 
				
			||||||
 | 
					    show("if true { 1 } else { 0.5 }".to_owned());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Tries to parse, compile, check and run `src`,
 | 
				
			||||||
 | 
					/// then prints an error or the returned value and output type to stderr.
 | 
				
			||||||
 | 
					/// Note: The output type is not the type of the value but the one determined by `.check()` before the code even runs.
 | 
				
			||||||
 | 
					fn show(src: String) {
 | 
				
			||||||
 | 
					    eprintln!(
 | 
				
			||||||
 | 
					        "-{}",
 | 
				
			||||||
 | 
					        " -".repeat(src.lines().map(|l| l.len()).max().unwrap_or(0) / 2)
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    eprintln!("{src}");
 | 
				
			||||||
 | 
					    match parse_compile_check_run(src) {
 | 
				
			||||||
 | 
					        Err(e) => eprintln!("{e}"),
 | 
				
			||||||
 | 
					        Ok((t, v)) => eprintln!("Returned `{}` :: `{t}`", v.get()),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn parse_compile_check_run(src: String) -> Result<(Type, Data), CheckError> {
 | 
				
			||||||
 | 
					    // prepare the string for parsing
 | 
				
			||||||
 | 
					    let mut source = Source::new_from_string(src);
 | 
				
			||||||
 | 
					    // this is used for error messages
 | 
				
			||||||
 | 
					    let srca = Arc::new(source.clone());
 | 
				
			||||||
 | 
					    // parse the code
 | 
				
			||||||
 | 
					    let parsed = parse(&mut source, &srca)?;
 | 
				
			||||||
 | 
					    // get infos
 | 
				
			||||||
 | 
					    let (mut i1, mut i2, mut i3) = Config::new().bundle_std().infos();
 | 
				
			||||||
 | 
					    // compile
 | 
				
			||||||
 | 
					    let compiled = parsed.compile(&mut i1, CompInfo::default())?;
 | 
				
			||||||
 | 
					    // check (this step is optional, but if it is skipped when it would have returned an error, `run` will likely panic)
 | 
				
			||||||
 | 
					    let output_type = compiled.check(&mut i3, None)?;
 | 
				
			||||||
 | 
					    // run
 | 
				
			||||||
 | 
					    let output_value = compiled.run(&mut i2);
 | 
				
			||||||
 | 
					    // check that the predicted output type was correct
 | 
				
			||||||
 | 
					    assert!(output_value.get().as_type().is_included_in(&output_type));
 | 
				
			||||||
 | 
					    // return the produced value
 | 
				
			||||||
 | 
					    Ok((output_type, output_value))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										57
									
								
								mers_lib/examples/01_user_scripts.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								mers_lib/examples/01_user_scripts.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					use std::sync::Arc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use mers_lib::{
 | 
				
			||||||
 | 
					    data::{self, Data, MersType, Type},
 | 
				
			||||||
 | 
					    errors::CheckError,
 | 
				
			||||||
 | 
					    prelude_compile::{parse, CompInfo, Config, Source},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() -> Result<(), CheckError> {
 | 
				
			||||||
 | 
					    let (_, func) = parse_compile_check_run(
 | 
				
			||||||
 | 
					        // The `[(String -> String)]` type annotation ensures that decorate.mers returns a `String -> String` function.
 | 
				
			||||||
 | 
					        "[(String -> String)] #include \"examples/decorate.mers\"".to_owned(),
 | 
				
			||||||
 | 
					    )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // We can unwrap the downcasts because mers has type-checked that `func` is a `(String -> String)`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let func = func.get();
 | 
				
			||||||
 | 
					    let func = func
 | 
				
			||||||
 | 
					        .as_any()
 | 
				
			||||||
 | 
					        .downcast_ref::<data::function::Function>()
 | 
				
			||||||
 | 
					        .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // use the function to decorate these 3 test strings
 | 
				
			||||||
 | 
					    for input in ["my test string", "Main Menu", "O.o"] {
 | 
				
			||||||
 | 
					        let result = func.run(Data::new(data::string::String(input.to_owned())));
 | 
				
			||||||
 | 
					        let result = result.get();
 | 
				
			||||||
 | 
					        let result = &result
 | 
				
			||||||
 | 
					            .as_any()
 | 
				
			||||||
 | 
					            .downcast_ref::<data::string::String>()
 | 
				
			||||||
 | 
					            .unwrap()
 | 
				
			||||||
 | 
					            .0;
 | 
				
			||||||
 | 
					        eprintln!("{result}");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn parse_compile_check_run(src: String) -> Result<(Type, Data), CheckError> {
 | 
				
			||||||
 | 
					    // prepare the string for parsing
 | 
				
			||||||
 | 
					    let mut source = Source::new_from_string(src);
 | 
				
			||||||
 | 
					    // this is used for error messages
 | 
				
			||||||
 | 
					    let srca = Arc::new(source.clone());
 | 
				
			||||||
 | 
					    // parse the code
 | 
				
			||||||
 | 
					    let parsed = parse(&mut source, &srca)?;
 | 
				
			||||||
 | 
					    // get infos
 | 
				
			||||||
 | 
					    let (mut i1, mut i2, mut i3) = Config::new().bundle_std().infos();
 | 
				
			||||||
 | 
					    // compile
 | 
				
			||||||
 | 
					    let compiled = parsed.compile(&mut i1, CompInfo::default())?;
 | 
				
			||||||
 | 
					    // check (this step is optional, but if it is skipped when it would have returned an error, `run` will likely panic)
 | 
				
			||||||
 | 
					    let output_type = compiled.check(&mut i3, None)?;
 | 
				
			||||||
 | 
					    // run
 | 
				
			||||||
 | 
					    let output_value = compiled.run(&mut i2);
 | 
				
			||||||
 | 
					    // check that the predicted output type was correct
 | 
				
			||||||
 | 
					    assert!(output_value.get().as_type().is_included_in(&output_type));
 | 
				
			||||||
 | 
					    // return the produced value
 | 
				
			||||||
 | 
					    Ok((output_type, output_value))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2
									
								
								mers_lib/examples/decorate.mers
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								mers_lib/examples/decorate.mers
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					// return a function that adds "-= ... =-" decorations to the given text
 | 
				
			||||||
 | 
					text -> ("-= ", text, " =-").concat
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user