mirror of
				https://github.com/Dummi26/mers.git
				synced 2025-10-31 11:46:15 +01:00 
			
		
		
		
	mers_lib to 0.5.0, readme updated
This commit is contained in:
		
							parent
							
								
									0c87c69743
								
							
						
					
					
						commit
						cc4a4366c9
					
				
							
								
								
									
										111
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								README.md
									
									
									
									
									
								
							| @ -1,93 +1,68 @@ | |||||||
| # mers | # mers | ||||||
| 
 | 
 | ||||||
| Mers is a high-level programming language. | See [mers/README.md] | ||||||
| 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") | "Hello, World!".println | ||||||
| list.sum.println |  | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Type-safety for functions is different from what you might expect. | > `Hello, Variable!` | ||||||
| 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 -> { | my_var := "Hello, Variable!" | ||||||
|   one := iter.sum | my_var.println | ||||||
|   (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: | > `Hello, Variable!` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
| 
 | 
 | ||||||
| ``` | ``` | ||||||
| (1, 2, "3").sum_doubled.println | (1, 2, 3, 4).sum.println | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| But mers will catch this and show an error, because the call to `sum` inside of `sum_doubled` would fail. | > `10` | ||||||
| 
 | 
 | ||||||
| ### 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 | (1, "2", 3, 4).sum.println | ||||||
| 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(( | (1, 2, 3, 4).as_list.debug | ||||||
|   (s, stdout, stderr) -> stdout.println, |  | ||||||
|   error -> error.println, |  | ||||||
| )) |  | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## docs | > `List<Int> :: [1, 2, 3, 4]` | ||||||
| 
 | 
 | ||||||
| docs will be available in some time. for now, check mers_lib/src/program/configs/* | --- | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | (1.0, 2.0).as_list.debug | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | > `List<Float> :: [1, 2]` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | (1, 2, 3.5).as_list.debug | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | > `List<Int/Float> :: [1, 2, 3.5]` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | int_list := (1, 2, 3).as_list | ||||||
|  | float_list := (4.5, 6.0).as_list | ||||||
|  | int_list.chain(float_list).as_list.debug | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | > `List<Int/Float> :: [1, 2, 3, 4.5, 6]` | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| [package] | [package] | ||||||
| name = "mers_lib" | name = "mers_lib" | ||||||
| version = "0.4.0" | version = "0.5.0" | ||||||
| edition = "2021" | edition = "2021" | ||||||
| license = "MIT OR Apache-2.0" | license = "MIT OR Apache-2.0" | ||||||
| description = "library to use the mers language in other projects" | description = "library to use the mers language in other projects" | ||||||
|  | |||||||
| @ -3,5 +3,47 @@ | |||||||
| The library behind [mers](https://github.com/Dummi26/mers). | The library behind [mers](https://github.com/Dummi26/mers). | ||||||
| 
 | 
 | ||||||
| With this, you can parse, compile, check and run mers code. | With this, you can parse, compile, check and run mers code. | ||||||
| 
 |  | ||||||
| You can also add your own functions and types which can then be used from mers, if you really want to. | You can also add your own functions and types which can then be used from mers, if you really want to. | ||||||
|  | 
 | ||||||
|  | ## Running mers | ||||||
|  | 
 | ||||||
|  | There are four steps to running mers code. | ||||||
|  | The examples show you how to actually implement them, | ||||||
|  | this readme only explains what they do any why. | ||||||
|  | 
 | ||||||
|  | ### 1. Parsing | ||||||
|  | 
 | ||||||
|  | This first step converts the source code, a string, to a parsed mers statement. | ||||||
|  | 
 | ||||||
|  | In this step, syntax errors and unknown variables are caught. | ||||||
|  | 
 | ||||||
|  | ### 2. Compiling | ||||||
|  | 
 | ||||||
|  | This converts a parsed mers statement to a compiled one. It almost never produces an error. | ||||||
|  | 
 | ||||||
|  | ### 3. Checking | ||||||
|  | 
 | ||||||
|  | This step is optional. If you parse and compile your source code, you can (try to) run it. | ||||||
|  | However, mers assumes that all mers code you run is actually valid, | ||||||
|  | so if you don't check your codes validity, mers will probably panic while running your code. | ||||||
|  | 
 | ||||||
|  | This step performs all the type-checking and determines the output type of your code, if it is valid. | ||||||
|  | 
 | ||||||
|  | For example, the following code is valid and has the return type `Int/Float`: | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | my_condition := true | ||||||
|  | 
 | ||||||
|  | if my_condition { | ||||||
|  |   5 | ||||||
|  | } else { | ||||||
|  |   1.4 | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### 4. Running | ||||||
|  | 
 | ||||||
|  | This step assumes that the code it is running is actually valid, so it never returns an error. | ||||||
|  | As long as `check` didn't return an error in Step 3, it is safe to assume that this will return the value produced by the code. | ||||||
|  | We can also assume that the return value has a type which is included in that determined by `check`. | ||||||
|  | If `check` returned an error, this will likely panic. | ||||||
|  | |||||||
| @ -35,23 +35,14 @@ fn main() -> Result<(), CheckError> { | |||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// example 00
 | ||||||
| fn parse_compile_check_run(src: String) -> Result<(Type, Data), CheckError> { | fn parse_compile_check_run(src: String) -> Result<(Type, Data), CheckError> { | ||||||
|     // prepare the string for parsing
 |  | ||||||
|     let mut source = Source::new_from_string(src); |     let mut source = Source::new_from_string(src); | ||||||
|     // this is used for error messages
 |  | ||||||
|     let srca = Arc::new(source.clone()); |     let srca = Arc::new(source.clone()); | ||||||
|     // parse the code
 |  | ||||||
|     let parsed = parse(&mut source, &srca)?; |     let parsed = parse(&mut source, &srca)?; | ||||||
|     // get infos
 |  | ||||||
|     let (mut i1, mut i2, mut i3) = Config::new().bundle_std().infos(); |     let (mut i1, mut i2, mut i3) = Config::new().bundle_std().infos(); | ||||||
|     // compile
 |  | ||||||
|     let compiled = parsed.compile(&mut i1, CompInfo::default())?; |     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)?; |     let output_type = compiled.check(&mut i3, None)?; | ||||||
|     // run
 |  | ||||||
|     let output_value = compiled.run(&mut i2); |     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)) |     Ok((output_type, output_value)) | ||||||
| } | } | ||||||
|  | |||||||
| @ -23,6 +23,18 @@ pub struct Function { | |||||||
|     )>, |     )>, | ||||||
| } | } | ||||||
| impl Function { | impl Function { | ||||||
|  |     pub fn new( | ||||||
|  |         out: impl Fn(&Type) -> Result<Type, CheckError> + Send + Sync + 'static, | ||||||
|  |         run: impl Fn(Data) -> Data + Send + Sync + 'static, | ||||||
|  |     ) -> Self { | ||||||
|  |         Self { | ||||||
|  |             info: Arc::new(crate::info::Info::neverused()), | ||||||
|  |             info_check: Arc::new(Mutex::new(crate::info::Info::neverused())), | ||||||
|  |             out: Arc::new(move |a, _| out(a)), | ||||||
|  |             run: Arc::new(move |a, _| run(a)), | ||||||
|  |             inner_statements: None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|     pub fn with_info_run(&self, info: Arc<Info>) -> Self { |     pub fn with_info_run(&self, info: Arc<Info>) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             info, |             info, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Mark
						Mark