From 5a69042ae9668beb46f2715e6251353153663955 Mon Sep 17 00:00:00 2001 From: zihang Date: Mon, 9 Dec 2024 16:25:37 +0800 Subject: [PATCH] doc: improvements - Reorganize introduction and introduce test block - Separate operator introduction and operator overloading - Add missing array pattern - Fix if introduction - Add missing for..in loop a..`, which can be used to chain regular function calls: + +```{literalinclude} /sources/language/src/operator/top.mbt +:language: moonbit +:dedent: +:start-after: start operator 4 +:end-before: end operator 4 +``` + +### Cascade Operator + +The cascade operator `..` is used to perform a series of mutable operations on +the same value consecutively. The syntax is as follows: + +```{literalinclude} /sources/language/src/operator/top.mbt +:language: moonbit +:dedent: +:start-after: start operator 5 +:end-before: end operator 5 +``` + +`x..f()..g()` is equivalent to `{x.f(); x.g(); x}`. + +Consider the following scenario: for a `StringBuilder` type that has methods +like `write_string`, `write_char`, `write_object`, etc., we often need to perform +a series of operations on the same `StringBuilder` value: + +```{literalinclude} /sources/language/src/operator/top.mbt +:language: moonbit +:dedent: +:start-after: start operator 6 +:end-before: end operator 6 +``` + +To avoid repetitive typing of `builder`, its methods are often designed to +return `self` itself, allowing operations to be chained using the `.` operator. +To distinguish between immutable and mutable operations, in MoonBit, +for all methods that return `Unit`, cascade operator can be used for +consecutive operations without the need to modify the return type of the methods. + +```{literalinclude} /sources/language/src/operator/top.mbt +:language: moonbit +:dedent: +:start-after: start operator 7 +:end-before: end operator 7 +``` + ### TODO syntax The `todo` syntax (`...`) is a special construct used to mark sections of code that are not yet implemented or are placeholders for future functionality. For example: diff --git a/next/language/introduction.md b/next/language/introduction.md index 3269c4ad..a2d8fc6d 100644 --- a/next/language/introduction.md +++ b/next/language/introduction.md @@ -7,46 +7,6 @@ A MoonBit program consists of top-level definitions including: - constant definitions and variable bindings - `init` functions, `main` function and/or `test` blocks. -## Program entrance - -There is a specialized function called `init` function. The `init` function is special in two aspects: - -1. There can be multiple `init` functions in the same package. -2. An `init` function can't be explicitly called or referred to by other functions. Instead, all `init` functions will be implicitly called when initializing a package. Therefore, `init` functions should only consist of statements. - -```{literalinclude} /sources/language/src/main/top.mbt -:language: moonbit -:start-after: start init -:end-before: end init -``` - -For WebAssembly backend, it means that it will be executed **before** the instance is available, meaning that the FFIs that relies on the instance's exportations can not be used at this stage; -for JavaScript backend, it means that it will be executed during the importation stage. - -There is another specialized function called `main` function. The `main` function is the main entrance of the program, and it will be executed after the initialization stage. - -```{literalinclude} /sources/language/src/main/top.mbt -:language: moonbit -:start-after: start main -:end-before: end main -``` - -The previous two code snippets will print the following at runtime: - -```bash -1 -2 -``` - -Only packages that are `main` packages can define such `main` function. Check out [build system tutorial](/toolchain/moon/tutorial) for detail. - -```{literalinclude} /sources/language/src/main/moon.pkg.json -:language: json -:caption: moon.pkg.json -``` - -The two functions above need to drop the parameter list and the return type. - ## Expressions and Statements MoonBit distinguishes between statements and expressions. In a function body, only the last clause should be an expression, which serves as a return value. For example: @@ -61,10 +21,10 @@ Expressions include: - Value literals (e.g. Boolean values, numbers, characters, strings, arrays, tuples, structs) - Arithmetical, logical, or comparison operations -- Accesses to array elements (e.g. `a[0]`) or struct fields (e.g `r.x`) or tuple components (e.g. `t.0`) +- Accesses to array elements (e.g. `a[0]`), struct fields (e.g `r.x`), tuple components (e.g. `t.0`), etc. - Variables and (capitalized) enum constructors - Anonymous local function definitions -- `match` and `if` expressions +- `match`, `if`, `loop` expressions, etc. Statements include: @@ -72,12 +32,16 @@ Statements include: - Local variable bindings - Assignments - `return` statements -- Any expression whose return type is `Unit` +- Any expression whose return type is `Unit`, (e.g. `ignore`) + +A code block can contain multiple statements and one expression, and the value of the expression is the value of the code block. ## Variable Binding A variable can be declared as mutable or immutable using `let mut` or `let`, respectively. A mutable variable can be reassigned to a new value, while an immutable one cannot. +A constant can only be declared at top level and cannot be changed. + ```{literalinclude} /sources/language/src/variable/top.mbt :language: moonbit ``` @@ -88,4 +52,56 @@ Variables, functions should start with lowercase letters `a-z` and can contain l It is recommended to name them with snake_case. Constants, types should start with uppercase letters `A-Z` and can contain letters, numbers, and other non-ascii unicode chars. -It is recommended to name them with PascalCase or SCREAMING_SNAKE_CASE. \ No newline at end of file +It is recommended to name them with PascalCase or SCREAMING_SNAKE_CASE. + +## Program entrance + +### `init` and `main` +There is a specialized function called `init` function. The `init` function is special: + +1. It has no parameter list nor return type. +2. There can be multiple `init` functions in the same package. +3. An `init` function can't be explicitly called or referred to by other functions. +Instead, all `init` functions will be implicitly called when initializing a package. Therefore, `init` functions should only consist of statements. + +```{literalinclude} /sources/language/src/main/top.mbt +:language: moonbit +:start-after: start init +:end-before: end init +``` + +There is another specialized function called `main` function. The `main` function is the main entrance of the program, and it will be executed after the initialization stage. + +Same as the `init` function, it has no parameter list nor return type. + +```{literalinclude} /sources/language/src/main/top.mbt +:language: moonbit +:start-after: start main +:end-before: end main +``` + +The previous two code snippets will print the following at runtime: + +```bash +1 +2 +``` + +Only packages that are `main` packages can define such `main` function. Check out [build system tutorial](/toolchain/moon/tutorial) for detail. + +```{literalinclude} /sources/language/src/main/moon.pkg.json +:language: json +:caption: moon.pkg.json +``` + +### `test` + +There's also a top-level structure called `test` block. A `test` block defines inline tests, such as: + +```{literalinclude} /sources/language/src/test/top.mbt +:language: moonbit +:start-after: start test 1 +:end-before: end test 1 +``` + +The following contents will use `test` block and `main` function to demonstrate the execution result. \ No newline at end of file diff --git a/next/language/methods.md b/next/language/methods.md index e9d9206d..d385b2ef 100644 --- a/next/language/methods.md +++ b/next/language/methods.md @@ -110,84 +110,14 @@ Currently, the following operators can be overloaded: | `_[_]` (get item) | `op_get` | | `_[_] = _` (set item) | `op_set` | | `_[_:_]` (view) | `op_as_view` | - -### Pipe operator - -MoonBit provides a convenient pipe operator `|>`, which can be used to chain regular function calls: - -```{literalinclude} /sources/language/src/operator/top.mbt -:language: moonbit -:dedent: -:start-after: start operator 4 -:end-before: end operator 4 -``` - -### Cascade Operator - -The cascade operator `..` is used to perform a series of mutable operations on -the same value consecutively. The syntax is as follows: - -```{literalinclude} /sources/language/src/operator/top.mbt -:language: moonbit -:dedent: -:start-after: start operator 5 -:end-before: end operator 5 -``` - -`x..f()..g()` is equivalent to `{x.f(); x.g(); x}`. - -Consider the following scenario: for a `StringBuilder` type that has methods -like `write_string`, `write_char`, `write_object`, etc., we often need to perform -a series of operations on the same `StringBuilder` value: - -```{literalinclude} /sources/language/src/operator/top.mbt -:language: moonbit -:dedent: -:start-after: start operator 6 -:end-before: end operator 6 -``` - -To avoid repetitive typing of `builder`, its methods are often designed to -return `self` itself, allowing operations to be chained using the `.` operator. -To distinguish between immutable and mutable operations, in MoonBit, -for all methods that return `Unit`, cascade operator can be used for -consecutive operations without the need to modify the return type of the methods. - -```{literalinclude} /sources/language/src/operator/top.mbt -:language: moonbit -:dedent: -:start-after: start operator 7 -:end-before: end operator 7 -``` - -### Bitwise Operator - -MoonBit supports C-Style bitwise operators. - -| Operator | Perform | -| -------- | ------- | | `&` | `land` | | `\|` | `lor` | | `^` | `lxor` | | `<<` | `op_shl` | | `>>` | `op_shr` | -### View Operator - - - -Analogous to `slice` in other languages, the view is a reference to a -specific segment of collections. You can use `data[start:end]` to create a -view of array `data`, referencing elements from `start` to `end` (exclusive). -Both `start` and `end` indices can be omitted. - -```{literalinclude} /sources/language/src/operator/top.mbt -:language: moonbit -:start-after: start view 1 -:end-before: end view 1 -``` -By implementing `op_as_view` method, you can also create a view for a user-defined type. Here is an example: +By implementing `op_as_view` method, you can create a view for a user-defined type. Here is an example: ```{literalinclude} /sources/language/src/operator/top.mbt :language: moonbit diff --git a/next/sources/language/src/builtin/top.mbt b/next/sources/language/src/builtin/top.mbt index 66b4fa38..be7b7525 100644 --- a/next/sources/language/src/builtin/top.mbt +++ b/next/sources/language/src/builtin/top.mbt @@ -160,6 +160,31 @@ test { } // end array 2 +// start array 3 +let fixed_array_1 : FixedArray[Int] = [1, 2, 3] +let fixed_array_2 = ([1, 2, 3] : FixedArray[Int]) +let array_3 = [1, 2, 3] // Array[Int] +// end array 3 + +// start array pitfall +test { + let two_dimension_array = FixedArray::make(10, FixedArray::make(10, 0)) + two_dimension_array[0][5] = 10 + assert_eq!(two_dimension_array[5][5], 10) +} +// end array pitfall + +// start array pitfall solution +test { + let two_dimension_array = FixedArray::makei( + 10, + fn (_i) { FixedArray::make(10, 0) } + ) + two_dimension_array[0][5] = 10 + assert_eq!(two_dimension_array[5][5], 0) +} +// end array pitfall solution + // start map 1 let map : Map[String, Int] = { "x": 1, "y": 2, "z": 3 } // end map 1 diff --git a/next/sources/language/src/controls/top.mbt b/next/sources/language/src/controls/top.mbt index cbc6a2b1..465b4ced 100644 --- a/next/sources/language/src/controls/top.mbt +++ b/next/sources/language/src/controls/top.mbt @@ -1,28 +1,21 @@ fn a() -> Int { let x = 1 let y = 1 + let z = 1 let expr1 = 1 let expr2 = 1 + let expr3 = 1 // start conditional expressions 1 if x == y { expr1 - } else { + } else if x == z { expr2 + } else { + expr3 } // end conditional expressions 1 } -fn b() -> Unit { - let x = 1 - let y = 1 - let expr1 = () - // start conditional expressions 2 - if x == y { - expr1 - } - // end conditional expressions 2 -} - fn c() -> Unit { let size = 0 // start conditional expressions 3 @@ -211,6 +204,22 @@ test { } // end for loop 9 +// start for loop 10 +test { + let mut i = 0 + for j in 0..<10 { + i += j + } + assert_eq!(i, 45) + + let mut k = 0 + for l in 0..=10 { + k += l + } + assert_eq!(k, 55) +} +// end for loop 10 + fn f() -> Unit { let index = 1 let len = 10 diff --git a/next/sources/language/src/functions/top.mbt b/next/sources/language/src/functions/top.mbt index 4713bb57..f5371c2e 100644 --- a/next/sources/language/src/functions/top.mbt +++ b/next/sources/language/src/functions/top.mbt @@ -6,7 +6,7 @@ fn foo() -> Int { fn bar() -> Int { let x = 1 - // x + 1 // fail + //! x + 1 x + 2 } // end expression @@ -38,7 +38,7 @@ fn local_1() -> Int { fn inc(x) { // named as `inc` x + 1 } - // anonymous, instantly appplied to integer literal 6 + // anonymous, instantly applied to integer literal 6 (fn(x) { x + inc(2) })(6) } diff --git a/next/sources/language/src/test/top.mbt b/next/sources/language/src/test/top.mbt index 4e7d3454..a0a34184 100644 --- a/next/sources/language/src/test/top.mbt +++ b/next/sources/language/src/test/top.mbt @@ -2,6 +2,7 @@ test "test_name" { assert_eq!(1 + 1, 2) assert_eq!(2 + 2, 4) + inspect!([1, 2, 3], content="[1, 2, 3]") } // end test 1 diff --git a/next/sources/language/src/variable/top.mbt b/next/sources/language/src/variable/top.mbt index 0172ee78..93980140 100644 --- a/next/sources/language/src/variable/top.mbt +++ b/next/sources/language/src/variable/top.mbt @@ -1,7 +1,10 @@ let zero = 0 +const ZERO = 0 + fn main { + //! const ZERO = 0 let mut i = 10 i = 20 - println(i + zero) + println(i + zero + ZERO) }