diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..59f209d1 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,12 @@ +version: 2 +build: + os: ubuntu-22.04 + tools: + python: "3.13" + +sphinx: + configuration: next/conf.py + +python: + install: + - requirements: next/requirements.txt \ No newline at end of file diff --git a/next/.gitignore b/next/.gitignore new file mode 100644 index 00000000..a41cafda --- /dev/null +++ b/next/.gitignore @@ -0,0 +1,3 @@ +_build +*.mo +__pycache__ \ No newline at end of file diff --git a/next/Makefile b/next/Makefile new file mode 100644 index 00000000..d4bb2cbb --- /dev/null +++ b/next/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/next/README b/next/README new file mode 100644 index 00000000..f1500f2b --- /dev/null +++ b/next/README @@ -0,0 +1,46 @@ +# (WIP) Next gen moonbit-docs + +A new MoonBit docs framework based on Sphinx. + +## Develop + +### Install + +```bash +python3 -m venv .env +source .env/bin/activate +pip install -r requirements.txt +``` + +For building PDF using Latex, `latexmk` needs to be installed: +- MacOS: + - install [Mactex](https://www.tug.org/mactex/) + - install `latexmk` using TeX Live Utility + +### Build + +```bash +make html +python3 -m http.server -d _build/html +``` + +For Chinese version: + +```bash +make -e SPHINXOPTS="-D language='zh_CN'" html +python3 -m http.server -d _build/html +``` + +For PDF: + +```bash +PATH=$PATH:/usr/local/texlive/2024/bin/universal-darwin/ make latexpdf +open ./_build/latex/moonbitdocument.pdf +``` + +### Update translation template + +```bash +make gettext +sphinx-intl update -p _build/gettext -l zh_CN +``` \ No newline at end of file diff --git a/next/_ext/lexer.py b/next/_ext/lexer.py new file mode 100644 index 00000000..2d0ba0d3 --- /dev/null +++ b/next/_ext/lexer.py @@ -0,0 +1,37 @@ +from pygments.lexer import RegexLexer, words +import pygments.token as token +from sphinx.application import Sphinx +from sphinx.util.typing import ExtensionMetadata + +def setup(app: Sphinx) -> ExtensionMetadata: + app.add_lexer("moonbit", MoonBitLexer) + app.add_lexer("mbt", MoonBitLexer) + return { + "version": "0.1.0", + "parallel_read_safe": True, + "parallel_write_safe": True, + } + +class MoonBitLexer(RegexLexer): + name = "MoonBit" + + tokens = { + 'root': [ + (r"//.*$", token.Comment), + (r"#\|.*$", token.String), + (r"\$\|.*$", token.String), + (r"\'.*\'", token.Literal), + (r"\"((\\\")|[^\"])*\"", token.String), + (r"-?\d+(.\d+)?", token.Number), + (words(('type', 'type!', 'enum', 'struct', 'trait'), suffix="\s"), token.Keyword), + (words(('fn', 'if', 'else', 'while', 'for', 'loop', 'match', 'let', 'mut', 'impl', 'with', 'derive'), suffix="\s"), token.Keyword), + (words(('return', 'break', 'continue'), suffix="\s"), token.Keyword), + (words(('try', 'catch', 'raise'), suffix="[\s{]"), token.Keyword), + (words(('pub', 'priv', 'pub\\(all\\)', 'pub\\(readonly\\)', 'pub\\(open\\)', 'test'), suffix="\s"), token.Keyword), + (words(('true', 'false'), suffix='[?!,\\)\s]'), token.Keyword), + (words(('Array', 'FixedArray', 'Int', 'Int64', 'UInt', 'UInt64', 'Option', 'Result', 'Byte', 'Bool', 'Unit', 'String', 'Show', 'Eq', 'Self'), suffix='[?!,\\)\s]'), token.Keyword), + (r"(=>)|(\|>)|(->)|(<<)|(>>)|(==)|(&&)|(\|\|)|[\(\)\{\}\[\]:,\.=+\-*/%!?~<>;@&\|]", token.Punctuation), + (r"[a-zA-Z_][a-zA-Z0-9_]*", token.Name), + (r"[\s]", token.Whitespace), + ] + } \ No newline at end of file diff --git a/next/conf.py b/next/conf.py new file mode 100644 index 00000000..1062c5da --- /dev/null +++ b/next/conf.py @@ -0,0 +1,44 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'MoonBit Document' +copyright = '2024, International Digital Economy Academy' +author = 'International Digital Economy Academy' +release = 'v0.1.20241125' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +import sys +from pathlib import Path +sys.path.append(str(Path("_ext").resolve())) + +extensions = ['myst_parser', 'lexer'] + +templates_path = ['_templates'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', ".env", '.venv', "README"] + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'alabaster' +html_static_path = ['_static'] + +# -- Options for LaTeX output ------------------------------------------------ +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-latex-output +latex_engine = 'xelatex' +latex_elements = { + 'preamble': r"\usepackage{xeCJK}", + 'fvset': "\\fvset{formatcom={\\CJKsetecglue{}}}" # avoid having spaces around text in code blocks +} + +# -- Options for myst_parser ------------------------------------------------- +myst_heading_anchors = 3 + +# -- Options for gettext ----------------------------------------------------- +gettext_additional_targets = ["literal-block"] \ No newline at end of file diff --git a/next/imgs/add-deps.png b/next/imgs/add-deps.png new file mode 100644 index 00000000..d43604c4 Binary files /dev/null and b/next/imgs/add-deps.png differ diff --git a/next/imgs/import.png b/next/imgs/import.png new file mode 100644 index 00000000..4257da45 Binary files /dev/null and b/next/imgs/import.png differ diff --git a/next/imgs/moon-new.png b/next/imgs/moon-new.png new file mode 100644 index 00000000..1e7b96b7 Binary files /dev/null and b/next/imgs/moon-new.png differ diff --git a/next/imgs/moon-update.png b/next/imgs/moon-update.png new file mode 100644 index 00000000..b5e7bf85 Binary files /dev/null and b/next/imgs/moon-update.png differ diff --git a/next/imgs/reverse-array.png b/next/imgs/reverse-array.png new file mode 100644 index 00000000..fe751325 Binary files /dev/null and b/next/imgs/reverse-array.png differ diff --git a/next/imgs/runtime-installation.png b/next/imgs/runtime-installation.png new file mode 100644 index 00000000..e20e996c Binary files /dev/null and b/next/imgs/runtime-installation.png differ diff --git a/next/imgs/smile_face_with_log.png b/next/imgs/smile_face_with_log.png new file mode 100644 index 00000000..9cc39414 Binary files /dev/null and b/next/imgs/smile_face_with_log.png differ diff --git a/next/index.md b/next/index.md new file mode 100644 index 00000000..b4bdd534 --- /dev/null +++ b/next/index.md @@ -0,0 +1,20 @@ +# MoonBit Documentation + +MoonBit is an end-to-end programming language toolchain for cloud and edge computing using WebAssembly. + +The IDE environment is available at [https://try.moonbitlang.com](https://try.moonbitlang.com) without any installation; it does not reply on any server either. + +**Get started** + +- [Tutorials](./tutorial/index.md): Follow tutorials to start your journey + +- [Language](./language/index.md): Introduction to detailed language specifications + +- [Toolchains](./toolchain/index.md): Introduction to all the toolchains making developing MoonBit a unique experience. + +```{toctree} +:maxdepth: 2 +:caption: Contents: +language/index +tutorial/index +toolchain/index \ No newline at end of file diff --git a/next/language/error-handling.md b/next/language/error-handling.md new file mode 100644 index 00000000..1657c087 --- /dev/null +++ b/next/language/error-handling.md @@ -0,0 +1,259 @@ +# Error handling in MoonBit + +Error handling has always been at core of our language design. In the following +we'll be explaining how error handling is done in MoonBit. We assume +you have some prior knowledge of MoonBit, if not, please checkout [A tour of MoonBit](../tutorial/tour.md). + +## Example: Division by Zero + +We'll write a small example to demonstrate the basics of MoonBit's error +handling system. Consider the following `div` function which'll raise an error +on division by zero: + +```moonbit +type! DivisionByZeroError String +fn div(x : Int, y : Int) -> Int!DivisionByZeroError { + if y == 0 { + raise DivisionByZeroError("division by zero") + } + x / y +} +``` + +In before, we would typically use `type` to define a wrapper type which wraps +around some existing foreign type. Here however, we append `type` with `!` to +define a error type `DivisionByZeroError` which wraps around `String`. + +> `type! E S` construct a error type `E` from `S` + +Just like `type`, `type!` may have a payload like the above `DivisionByZeroError`, or may not, or may even have multiple constructors like a normal `enum`: + +```moonbit +type! ConnectionError { + BrokenPipe(Int,String) + ConnectionReset + ConnectionAbort + ConnectionRefused +} +``` + +To utilize `DivisionByZeroError` type, we would usually define a function which may raise +error by denoting its return type like `T ! E` in the signature, with `T` being +the actual return type and `E` being the error type. In this case, it's +`Int!DivisionByZeroError`. The error can be thrown using +`raise e` where `e` is an instance of `E` which can be constructed using the +default constructor of `S`. + +Any instance of an error is a second class object. Meaning it may only appear in +the return value. And if it does appear, the function signature has to be +adjusted to match with the return type. + +The `test` block in MoonBit may also be seen as a function, with a return type +of Unit!Error. + +## Calling an error-able function + +an error-able function is usually called in 2 manners: `f!(...)` and `f?(...)`. + +### As-is calling + +`f!(...)` calls the function directly. The possible error must be dealt in the +function that calls `f`. We can either re-raising it without actually dealing +with the error: + +```moonbit -e1001 -e1002 +// We have to match the error type of `div2` with `div` +fn div2(x : Int, y : Int) -> Int!DivisionByZeroError { + div!(x,y) +} +``` + +or use `try...catch` block like in many other languages: + +```moonbit +fn div3(x : Int, y : Int) -> Unit { + try { + div!(x, y) + } catch { // `catch` and `except` works the same. + DivisionByZeroError(e) => println("inf: \{e}") + } else { + v => println(v) + } +} +``` + +The `catch...` clause has similar semantics like pattern matching. We can unwrap +the error to retrieve the underlying `String` and print it. Additionally, +there's an `else` clause to handle the value of `try...` block. + +```moonbit +fn test_try() -> Result[Int, Error] { + // compiler can figure out the type of a local error-able function. + fn f() -> _!_ { + raise Failure("err") + } + + try Ok(f!()) { err => Err(err) } +} +``` + +Curly braces may be omitted if the body of try is a one-liner (expression). The +`catch` keyword can also be omitted as well. In the case where a `try` body would raise different errors, +the special `catch!` can be used to catch some of the errors, while re-raising other uncaught errors: + +```moonbit +type! E1 +type! E2 +fn f1() -> Unit!E1 { raise E1 } +fn f2() -> Unit!E2 { raise E2 } +fn f() -> Unit! { + try { + f1!() + f2!() + } catch! { + E1 => println("E1") + // E2 gets re-raised. + } +} +``` + +### Convert to Result + +#### Extracting values + +A object of type `Result` is a first class value in MoonBit. `Result` has 2 constructors: `Ok(...)` and `Err(...)` where the former accept a first class object and the latter accept a error object. + +With `f?(...)`, the return type `T!E` is turned into `Result[T,E]`. We may use pattern matching to extract value from it: + +```moonbit enclose +let res = div?(10, 0) +match res { + Ok(x) => println(x) + Err(DivisionByZeroError(e)) => println(e) +} +``` + +the `f?()` is basically a syntactic sugar for + +```moonbit enclose +let res = try { + Ok(div!(10, 0)) +} catch { + s => Err(s) +} +``` + +> Note the difference between `T?` and `f?(...)`: `T` is a type and `T?` is +> equivalent to `Option[T]` whereas `f?(...)` is a call to an error-able function +> `f`. + +Besides pattern matching, `Result` provides some useful methods to deal with possible error: + +```moonbit no-check +let res1: Result[Int, String] = Err("error") +let value = res1.or(0) // 0 + +let res2: Result[Int, String] = Ok(42) +let value = res2.unwrap() // 42 +``` + +- `or` returns the value if the result is `Ok` or a default value if it is `Err` +- `unwrap` panics if the result is `Err` and return the value if it is `Ok` + +#### Mapping values + +```moonbit no-check +let res1: Result[Int, String] = Ok(42) +let new_result = res1.map(fn(x) { x + 1 }) // Ok(43) + +let res2: Result[Int, String] = Err("error") +let new_result = res2.map_err(fn(x) { x + "!" }) // Err("error!") +``` + +- `map` applies a function to the value within, except it doesn't nothing if result is `Err`. +- `map_error` does the opposite. + +Unlike some languages, MoonBit treats error-able and nullable value differently. Although one might treat them analogously, as an `Err` result contains no value, only the error, which is like `null`. MoonBit knows that. + +- `to_option` converts a `Result` to `Option`. + +```moonbit no-check +let res1: Result[Int, String] = Ok(42) +let option = res1.to_option() // Some(42) + +let res2: Result[Int, String] = Err("error") +let option1 = res2.to_option() // None +``` + +## Built-in error type and functions + +In MoonBit, `Error` is a generalized error type: + +```moonbit no-check +// These signatures are equivalent. They all raise Error. +fn f() -> Unit! { .. } +fn f!() -> Unit { .. } +fn f() -> Unit!Error { .. } + +fn test_error() -> Result[Int, Error] { + fn f() -> _!_ { + raise DivisionByZeroError("err") + } + + try { + Ok(f!()) + } catch { + err => Err(err) + } +} +``` + +Although the constructor `Err` expects a type of `Error`, we may +still pass an error of type `DivisionByZeroError` to it. + +But `Error` can't be constructed directly. It's meant to be passed around, not used directly: + +```moonbit +type! ArithmeticError + +fn what_error_is_this(e : Error) -> Unit { + match e { + DivisionByZeroError(_) => println("DivisionByZeroError") + ArithmeticError => println("ArithmeticError") + ... => println("...") + _ => println("Error") + } +} +``` + +`Error` is typically used where concrete error type is not needed, +or simply act as a catch-all for all kinds of sub-errors. + +As `Error` includes multiple error types, partial matching is not allowed here. We have to do exhaustive matching by providing a catch-all/wildcard case `_`. + +We usually use the builtin `Failure` error type for a generalized error, and by +generalized we mean using it for trivial errors that doesn't need a new error type. + +```moonbit +fn div_trivial(x : Int, y : Int) -> Int!Failure { + if y == 0 { + raise Failure("division by zero") + } + x / y +} +``` + +Besides using the constructor directly, the function `fail!` provides a +shorthand to construct a `Failure`. And if we take a look at the source code: + +```moonbit +pub fn fail[T](msg : String, ~loc : SourceLoc = _) -> T!Failure { + raise Failure("FAILED: \{loc} \{msg}") +} +``` + +We can see that `fail` is merely a constructor with a pre-defined output +template for showing both the error and the source location. In practice, `fail!` +is always preferred over `Failure`. + +Other functions used to break control flow are `abort` and `panic`. They are equivalent. An `panic` at any place will manually crash the program at that place, and prints out stack trace. diff --git a/next/language/ffi-and-wasm-host.md b/next/language/ffi-and-wasm-host.md new file mode 100644 index 00000000..36d14118 --- /dev/null +++ b/next/language/ffi-and-wasm-host.md @@ -0,0 +1,336 @@ +# Foreign Function Interface(FFI) + +You can use foreign function in MoonBit through FFI to interact with the hosting runtime when embedded inside the browser or command line applications through [Wasmtime](https://wasmtime.dev/) or similar projects. + +⚠ Warning: MoonBit is still in early stage, so the content may be outdated. + +## FFI + +### Declare Foreign Reference + +You can declare a foreign reference type like this: + +```moonbit +type Canvas_ctx +``` + +This will be a type that represents a reference to a foreign object, a `CanvasRenderingContext2D` object held by the hosting JavaScript runtime in this example. + +### Declare Foreign Function + +You can declare a foreign function like this: + +```moonbit +fn cos(d : Double) -> Double = "Math" "cos" +``` + +It's similar to a normal function definition except that the function body is replaced with two strings. + +For WasmGC backend, these two strings are used to identify the specific function from a Wasm import object, the first string is the module name, and the second string is the function name. For JS backend, these two strings are used to call a static function in the global namespace. The example above becomes similar to `const cos = (d) => Math.cos(d)`. + +You can also declare inline functions where the function body is replaced with one string. + +For WasmGC backend, you may declare it as a Wasm function without name (which will be generated afterwards): + +```moonbit +extern "wasm" fn abs(d : Double) -> Double = + #|(func (param f64) (result f64)) +``` + +and for JS backend, you may declare it as a lambda expression: + +```moonbit +extern "js" fn abs(d : Double) -> Double = + #|(d) => Math.abs(d) +``` + +After declaration, you can use foreign functions like regular functions. + +For multi-backend project, you may implement backend specific code in the files that ends with `.wasm.mbt` `.wasm-gc.mbt` and `.js.mbt`. + +You may also declare a foreign function that will be invoked upon a foreign object by using the foreign reference type like this: + +```moonbit +fn begin_path(self: Canvas_ctx) = "canvas" "begin_path" +``` + +and apply it to a previously owned reference normally such as `context.begin_path()`. + +### Exported functions + +Functions that are not methods nor polymorphic functions can be exported if they are public and if the link configuration appears in the `moon.pkg.json` of the package: + +```json +{ + "link": { + "wasm": { + "exports": [ + "add", + "fib:test" + ] + }, + "wasm-gc": { + "exports": [ + "add", + "fib:test" + ] + }, + "js": { + "exports": [ + "add", + "fib:test" + ], + "format": "esm" + } + } +} +``` + +Each backend has a separate definition. For JS backend, a `format` option is used to specify whether the generated JavaScript file should be released as an ES Module (`esm`), a CommonJS module (`cjs`), or an immediately invoked function expression (`iife`). + +The example above will export function `add` and `fib`, and the function `fib` will be exported with the name of `test`. + +For WasmGC backend, the `_start` function should always be called to initialize all the global instances defined in MoonBit program. + +### Use compiled Wasm + +To use the compiled Wasm, you need to initialize the Wasm module with the host functions so as to meet the needs of the foreign functions, and then use the exported functions provided by the Wasm module. + +#### Provide host functions + +To use the compiled Wasm, you must provide **All** declared foreign functions in Wasm import object. + +For example, to use wasm compiled from above code snippet in JavaScript: + +```js +WebAssembly.instantiateStreaming(fetch("xxx.wasm"), { + Math: { + cos: (d) => Math.cos(d), + }, +}); +``` + +Check out the documentation such as [MDN](https://developer.mozilla.org/en-US/docs/WebAssembly) or the manual of runtime that you're using to embed the Wasm. + +## Example: Smiling face + +Let's walk through a full example to draw a smiling face using Canvas API in MoonBit. Suppose you created a new project with `moon new draw` + +```moonbit title="lib/draw.mbt" +// We first declare a type representing the context of canvas +type Canvas_ctx + +// We then declare the foreign function interfaces +fn begin_path(self : Canvas_ctx) = "canvas" "beginPath" +fn arc(self : Canvas_ctx, x : Int, y : Int, radius : Int, start_angle : Double, + end_angle : Double, counterclockwise : Bool) = "canvas" "arc" +fn move_to(self : Canvas_ctx, x : Int, y : Int) = "canvas" "moveTo" +fn stroke(self : Canvas_ctx) = "canvas" "stroke" + +fn get_pi() -> Double = "math" "PI" +let pi : Double = get_pi() + +// We then apply these functions to define the drawing function upon the context +pub fn draw(self : Canvas_ctx) -> Unit { + self.begin_path() + self.arc(75, 75, 50, 0.0, pi * 2.0, true) // Outer circle + self.move_to(110, 75) + self.arc(75, 75, 35, 0.0, pi, false) // Mouth (clockwise) + self.move_to(65, 65) + self.arc(60, 65, 5, 0.0, pi * 2.0, true) // Left eye + self.move_to(95, 65) + self.arc(90, 65, 5, 0.0, pi * 2.0, true) // Right eye + self.stroke() +} + +// We also demonstrate the `println` functionality here +pub fn display_pi() -> Unit { + println("PI: \{pi}") +} +``` + +```json title="lib/moon.pkg.json" +{ + "link": { + "wasm": { + "exports": ["draw", "display_pi"] + }, + "wasm-gc": { + "exports": ["draw", "display_pi"] + } + } +} +``` + +Build the project using `moon build`. We recommend using Wasm with GC integration whenever possible (which is the default). If the environment does not support the GC feature, use the `--target wasm` option instead. + +We now can use it from JavaScript. + +```html title="./index.html" + + + + + + +``` + +For import object, we need to provide all the FFI used in the previously defined program: the canvas rendering API, the math API and finally, an API for printing to the console used by the `println` or `print` function. + +As of the canvas rendering API and the math API, we can use the following code to convert the methods of objects into function calls that accept the object as the first parameter, and convert the constant properties of objects into functions that returns the value: + +```javascript +function prototype_to_ffi(prototype) { + return Object.fromEntries( + Object.entries(Object.getOwnPropertyDescriptors(prototype)) + .filter(([_key, value]) => value.value) + .map(([key, value]) => { + if (typeof value.value == 'function') + return [key, Function.prototype.call.bind(value.value)] + // TODO: it is also possible to convert properties into getters and setters + else + return [key, () => value.value] + }) + ); +} + +const importObject = { + canvas: prototype_to_ffi(CanvasRenderingContext2D.prototype), + math: prototype_to_ffi(Math), + // ... +} +``` + +As of the printing service, we can provide the following closure so that it buffers the bytes of string until it needs to be logged to the console: + +```javascript +const [log, flush] = (() => { + var buffer = []; + function flush() { + if (buffer.length > 0) { + console.log(new TextDecoder("utf-16").decode(new Uint16Array(buffer).valueOf())); + buffer = []; + } + } + function log(ch) { + if (ch == '\n'.charCodeAt(0)) { flush(); } + else if (ch == '\r'.charCodeAt(0)) { /* noop */ } + else { buffer.push(ch); } + } + return [log, flush] +})(); + +const importObject = { + // ... + spectest: { + print_char: log + }, +} + +// ... +WebAssembly.instantiateStreaming(fetch("target/wasm-gc/release/build/lib/lib.wasm"), importObject).then( + (obj) => { + obj.instance.exports._start(); + // ... + flush() + } +); +``` + +Now, we put them together, so this is our final complete `index.html`: + +```html title="./index.html + + + + + + + + + + + +``` + +Make sure that `draw.wasm` and `index.html` are in the same folder, then start a http server at this folder. For example, using Python: + +```bash +python3 -m http.server 8080 +``` + +Goto [http://localhost:8080](http://localhost:8080) in your browser, there should be a smile face on the screen and an output on the console: + +![A smile face webpage with browser devtools open](../imgs/smile_face_with_log.png) diff --git a/next/language/index.md b/next/language/index.md new file mode 100644 index 00000000..99dff145 --- /dev/null +++ b/next/language/index.md @@ -0,0 +1,14 @@ +# Language + +Here are the topics about the programming syntax. + +- [MoonBit](./language.md): almost everything you need to know about the MoonBit grammar. +- [Error handling](./error-handling.md): the error handling mechanism in MoonBit. +- [Foreign Function Interface](./ffi-and-wasm-host.md): how MoonBit interacts with the real world using different backends. + +```{toctree} +:maxdepth: 2 +:caption: Contents: +language +error-handling +ffi-and-wasm-host \ No newline at end of file diff --git a/next/language/language.md b/next/language/language.md new file mode 100644 index 00000000..5e91cef0 --- /dev/null +++ b/next/language/language.md @@ -0,0 +1,2317 @@ +# MoonBit + +MoonBit is an end-to-end programming language toolchain for cloud and edge computing using WebAssembly. The IDE environment is available at [https://try.moonbitlang.com](https://try.moonbitlang.com) without any installation; it does not rely on any server either. + +## Status and aimed timeline + +MoonBit is currently in beta-preview. We expect to reach beta in 2024/11/22, and 1.0 in 2025. + +When MoonBit reaches beta, it means any backwards-incompatible changes will be seriously evaluated and MoonBit _can_ be used in production(very rare compiler bugs). MoonBit is developed by a talented full time team who had extensive experience in building language toolchains, so we will grow much faster than the typical language ecosystem, you won't wait long to use MoonBit in your production. + +## Main advantages + +- Generate significantly smaller WASM output than any existing solutions. +- Much faster runtime performance. +- State of the art compile-time performance. +- Simple but practical, data-oriented language design. + +## Overview + +A MoonBit program consists of type definitions, function definitions, and variable bindings. + +### 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. + +```moonbit live +fn main { + let x = 1 + // x // fail + println(x) // success +} +``` + +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. +Only packages that are `main` packages can define such `main` function. Check out [build system tutorial](https://moonbitlang.github.io/moon/) for detail. + +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: + +```moonbit +fn foo() -> Int { + let x = 1 + x + 1 // OK +} + +fn bar() -> Int { + let x = 1 + x + 1 // fail + x + 2 +} +``` + +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`) +- Variables and (capitalized) enum constructors +- Anonymous local function definitions +- `match` and `if` expressions + +Statements include: + +- Named local function definitions +- Local variable bindings +- Assignments +- `return` statements +- Any expression whose return type is `Unit` + +## Functions + +Functions take arguments and produce a result. In MoonBit, functions are first-class, which means that functions can be arguments or return values of other functions. MoonBit's naming convention requires that function names should not begin with uppercase letters (A-Z). Compare for constructors in the `enum` section below. + +### Top-Level Functions + +Functions can be defined as top-level or local. We can use the `fn` keyword to define a top-level function that sums three integers and returns the result, as follows: + +```moonbit +fn add3(x: Int, y: Int, z: Int)-> Int { + x + y + z +} +``` + +Note that the arguments and return value of top-level functions require explicit type annotations. + +### Local Functions + +Local functions can be named or anonymous. Type annotations can be omitted for local function definitions: they can be automatically inferred in most cases. For example: + +```moonbit live +fn foo() -> Int { + fn inc(x) { x + 1 } // named as `inc` + fn (x) { x + inc(2) } (6) // anonymous, instantly applied to integer literal 6 +} + +fn main { + println(foo()) +} +``` + +Functions, whether named or anonymous, are _lexical closures_: any identifiers without a local binding must refer to bindings from a surrounding lexical scope. For example: + +```moonbit live +let y = 3 +fn foo(x: Int) -> Unit { + fn inc() { x + 1 } // OK, will return x + 1 + fn four() { y + 1 } // Ok, will return 4 + println(inc()) + println(four()) +} + +fn main { + foo(2) +} +``` + +### Function Applications + +A function can be applied to a list of arguments in parentheses: + +```moonbit +add3(1, 2, 7) +``` + +This works whether `add3` is a function defined with a name (as in the previous example), or a variable bound to a function value, as shown below: + +```moonbit live +fn main { + let add3 = fn(x, y, z) { x + y + z } + println(add3(1, 2, 7)) +} +``` + +The expression `add3(1, 2, 7)` returns `10`. Any expression that evaluates to a function value is applicable: + +```moonbit live +fn main { + let f = fn (x) { x + 1 } + let g = fn (x) { x + 2 } + println((if true { f } else { g })(3)) // OK +} +``` + +### Labelled arguments + +Functions can declare labelled argument with the syntax `label~ : Type`. `label` will also serve as parameter name inside function body: + +```moonbit +fn labelled(arg1~ : Int, arg2~ : Int) -> Int { + arg1 + arg2 +} +``` + +Labelled arguments can be supplied via the syntax `label=arg`. `label=label` can be abbreviated as `label~`: + +```moonbit +fn init { + let arg1 = 1 + println(labelled(arg2=2, arg1~)) // 3 +} +``` + +Labelled function can be supplied in any order. The evaluation order of arguments is the same as the order of parameters in function declaration. + +### Optional arguments + +A labelled argument can be made optional by supplying a default expression with the syntax `label~ : Type = default_expr`. If this argument is not supplied at call site, the default expression will be used: + +```moonbit live +fn optional(opt~ : Int = 42) -> Int { + opt +} + +fn main { + println(optional()) // 42 + println(optional(opt=0)) // 0 +} +``` + +The default expression will be evaluated every time it is used. And the side effect in the default expression, if any, will also be triggered. For example: + +```moonbit live +fn incr(counter~ : Ref[Int] = { val: 0 }) -> Ref[Int] { + counter.val = counter.val + 1 + counter +} + +fn main { + println(incr()) // 1 + println(incr()) // still 1, since a new reference is created every time default expression is used + let counter : Ref[Int] = { val: 0 } + println(incr(counter~)) // 1 + println(incr(counter~)) // 2, since the same counter is used +} +``` + +If you want to share the result of default expression between different function calls, you can lift the default expression to a toplevel `let` declaration: + +```moonbit live +let default_counter : Ref[Int] = { val: 0 } + +fn incr(counter~ : Ref[Int] = default_counter) -> Int { + counter.val = counter.val + 1 + counter.val +} + +fn main { + println(incr()) // 1 + println(incr()) // 2 +} +``` + +Default expression can depend on the value of previous arguments. For example: + +```moonbit +fn sub_array[X](xs : Array[X], offset~ : Int, len~ : Int = xs.length() - offset) -> Array[X] { + ... // take a sub array of [xs], starting from [offset] with length [len] +} + +fn init { + println(sub_array([1, 2, 3], offset=1)) // [2, 3] + println(sub_array([1, 2, 3], offset=1, len=1)) // [2] +} +``` + +#### Automatically insert `Some` when supplying optional arguments + +It is quite often optional arguments have type `T?` with `None` as default value. +In this case, passing the argument explicitly requires wrapping a `Some`: + +```moonbit +fn image(width~ : Int? = None, height~ : Int? = None) -> Image { ... } +fn main { + let img = image(width=Some(1920), height=Some(1080)) // ugly! + ... +} +``` + +Fortunately, MoonBit provides a special kind of optional arguments to solve this problem. +Optional arguments declared with `label? : T` has type `T?` and `None` as default value. +When supplying this kind of optional argument directly, MoonBit will automatically insert a `Some`: + +```moonbit +fn image(width? : Int, height? : Int) -> Image { ... } +fn main { + let img = image(width=1920, height=1080) // much better! + ... +} +``` + +Sometimes, it is also useful to pass a value of type `T?` directly, +for example when forwarding optional argument. +MoonBit provides a syntax `label?=value` for this, with `label?` being an abbreviation of `label?=label`: + +```moonbit +fn image(width? : Int, height? : Int) -> Image { ... } +fn fixed_width_image(height? : Int) -> Image { + image(width=1920, height?) +} +``` + +### Autofill arguments + +MoonBit supports filling specific types of arguments automatically at different call site, such as the source location of a function call. +To declare an autofill argument, simply declare an optional argument with `_` as default value. +Now if the argument is not explicitly supplied, MoonBit will automatically fill it at the call site. + +Currently MoonBit supports two types of autofill arguments, `SourceLoc`, which is the source location of the whole function call, +and `ArgsLoc`, which is a array containing the source location of each argument, if any: + +```moonbit +fn f(_x : Int, _y : Int, loc~ : SourceLoc = _, args_loc~ : ArgsLoc = _) -> Unit { + println("loc of whole function call: \{loc}") + println("loc of arguments: \{args_loc}") +} + +fn main { + f(1, 2) + // loc of whole function call: :7:3-7:10 + // loc of arguments: [Some(:7:5-7:6), Some(:7:8-7:9), None, None] +} +``` + +Autofill arguments are very useful for writing debugging and testing utilities. + +## Control Structures + +### Conditional Expressions + +A conditional expression consists of a condition, a consequent, and an optional else clause. + +```moonbit +if x == y { + expr1 +} else { + expr2 +} + +if x == y { + expr1 +} +``` + +The else clause can also contain another if-else expression: + +```moonbit +if x == y { + expr1 +} else if z == k { + expr2 +} +``` + +Curly brackets are used to group multiple expressions in the consequent or the else clause. + +Note that a conditional expression always returns a value in MoonBit, and the return values of the consequent and the else clause must be of the same type. Here is an example: + +```moonbit +let initial = if size < 1 { 1 } else { size } +``` + +### While loop + +In MoonBit, `while` loop can be used to execute a block of code repeatedly as long as a condition is true. The condition is evaluated before executing the block of code. The `while` loop is defined using the `while` keyword, followed by a condition and the loop body. The loop body is a sequence of statements. The loop body is executed as long as the condition is true. + +```moonbit +let mut i = 5 +while i > 0 { + println(i) + i = i - 1 +} +``` + +The loop body supports `break` and `continue`. Using `break` allows you to exit the current loop, while using `continue` skips the remaining part of the current iteration and proceeds to the next iteration. + +```moonbit live +fn main { + let mut i = 5 + while i > 0 { + i = i - 1 + if i == 4 { continue } + if i == 1 { break } + println(i) + } +} +``` + +The `while` loop also supports an optional `else` clause. When the loop condition becomes false, the `else` clause will be executed, and then the loop will end. + +```moonbit live +fn main { + let mut i = 2 + while i > 0 { + println(i) + i = i - 1 + } else { + println(i) + } +} +``` + +When there is an `else` clause, the `while` loop can also return a value. The return value is the evaluation result of the `else` clause. In this case, if you use `break` to exit the loop, you need to provide a return value after `break`, which should be of the same type as the return value of the `else` clause. + +```moonbit + let mut i = 10 + let r1 = + while i > 0 { + i = i - 1 + if i % 2 == 0 { break 5 } // break with 5 + } else { + 7 + } + println(r1) //output: 5 +``` + +```moonbit + let mut i = 10 + let r2 = + while i > 0 { + i = i - 1 + } else { + 7 + } + println(r2) //output: 7 +``` + +### For Loop + +MoonBit also supports C-style For loops. The keyword `for` is followed by variable initialization clauses, loop conditions, and update clauses separated by semicolons. They do not need to be enclosed in parentheses. +For example, the code below creates a new variable binding `i`, which has a scope throughout the entire loop and is immutable. This makes it easier to write clear code and reason about it: + +```moonbit +for i = 0; i < 5; i = i + 1 { + println(i) +} +// output: +// 0 +// 1 +// 2 +``` + +The variable initialization clause can create multiple bindings: + +```moonbit +for i = 0, j = 0; i + j < 100; i = i + 1, j = j + 1 { + println(i) +} +``` + +It should be noted that in the update clause, when there are multiple binding variables, the semantics are to update them simultaneously. In other words, in the example above, the update clause does not execute `i = i + 1`, `j = j + 1` sequentially, but rather increments `i` and `j` at the same time. Therefore, when reading the values of the binding variables in the update clause, you will always get the values updated in the previous iteration. + +Variable initialization clauses, loop conditions, and update clauses are all optional. For example, the following two are infinite loops: + +```moonbit +for i=1;; i=i+1 { + println(i) // loop forever! +} +``` + +```moonbit +for { + println("loop forever!") +} +``` + +The `for` loop also supports `continue`, `break`, and `else` clauses. Like the `while` loop, the `for` loop can also return a value using the `break` and `else` clauses. + +The `continue` statement skips the remaining part of the current iteration of the `for` loop (including the update clause) and proceeds to the next iteration. The `continue` statement can also update the binding variables of the `for` loop, as long as it is followed by expressions that match the number of binding variables, separated by commas. + +For example, the following program calculates the sum of even numbers from 1 to 6: + +```moonbit live +fn main { + let sum = + for i = 1, acc = 0; i <= 6; i = i + 1 { + if i % 2 == 0 { + println("even: \{i}") + continue i + 1, acc + i + } + } else { + acc + } + println(sum) +} +``` + +### `for .. in` loop + +MoonBit supports traversing elements of different data structures and sequences via the `for .. in` loop syntax: + +```moonbit +for x in [ 1, 2, 3 ] { + println(x) +} +``` + +`for .. in` loop is translated to the use of `Iter` in MoonBit's standard library. Any type with a method `.iter() : Iter[T]` can be traversed using `for .. in`. +For more information of the `Iter` type, see [Iterator](#iterator) below. + +In addition to sequences of a single value, MoonBit also supports traversing sequences of two values, such as `Map`, via the `Iter2` type in MoonBit's standard library. +Any type with method `.iter2() : Iter2[A, B]` can be traversed using `for .. in` with two loop variables: + +```moonbit +for k, v in { "x": 1, "y": 2, "z": 3 } { + println("\{k} => \{v}") +} +``` + +Another example of `for .. in` with two loop variables is traversing an array while keeping track of array index: + +```moonbit +for index, elem in [ 4, 5, 6 ] { + let i = index + 1 + println("The \{i}-th element of the array is \{elem}") +} +``` + +Control flow operations such as `return`, `break` and error handling are supported in the body of `for .. in` loop: + +```moonbit +test "map test" { + let map = { "x": 1, "y": 2, "z": 3 } + for k, v in map { + assert_eq!(map[k], Some(v)) + } +} +``` + +If a loop variable is unused, it can be ignored with `_`. + +### Functional loop + +Functional loop is a powerful feature in MoonBit that enables you to write loops in a functional style. + +A functional loop consumes arguments and returns a value. It is defined using the `loop` keyword, followed by its arguments and the loop body. The loop body is a sequence of clauses, each of which consists of a pattern and an expression. The clause whose pattern matches the input will be executed, and the loop will return the value of the expression. If no pattern matches, the loop will panic. Use the `continue` keyword with arguments to start the next iteration of the loop. Use the `break` keyword with arguments to return a value from the loop. The `break` keyword can be omitted if the value is the last expression in the loop body. + +```moonbit live +fn sum(xs: @immut/list.T[Int]) -> Int { + loop xs, 0 { + Nil, acc => break acc // break can be omitted + Cons(x, rest), acc => continue rest, x + acc + } +} + +fn main { + println(sum(Cons(1, Cons(2, Cons(3, Nil))))) +} +``` + +### Guard Statement + +The `guard` statement is used to check a specified invariant. +If the condition of the invariant is satisfied, the program continues executing +the subsequent statements and returns. If the condition is not satisfied (i.e., false), +the code in the `else` block is executed and its evaluation result is returned (the subsequent statements are skipped). + +```moonbit +guard index >= 0 && index < len else { + abort("Index out of range") +} +``` + +The `guard` statement also supports pattern matching: in the following example, +`getProcessedText` assumes that the input `path` points to resources that are all plain text, +and it uses the `guard` statement to ensure this invariant. Compared to using +a `match` statement, the subsequent processing of `text` can have one less level of indentation. + +```moonbit +enum Resource { + Folder(Array[String]) + PlainText(String) + JsonConfig(Json) +} + +fn getProcessedText(resources : Map[String, Resource], path : String) -> String!Error { + guard let Some(PlainText(text)) = resources[path] else { + None => fail!("\{path} not found") + Some(Folder(_)) => fail!("\{path} is a folder") + Some(JsonConfig(_)) => fail!("\{path} is a json config") + } + ... + process(text) +} +``` + +When the `else` part is omitted, the program terminates if the condition specified +in the `guard` statement is not true or cannot be matched. + +```moonbit +guard condition // equivalent to `guard condition else { panic() }` +guard let Some(x) = expr // equivalent to `guard let Some(x) = expr else { _ => panic() }` +``` + +## Iterator + +An iterator is an object that traverse through a sequence while providing access +to its elements. Traditional OO languages like Java's `Iterator` use `next()` +`hasNext()` to step through the iteration process, whereas functional languages +(JavaScript's `forEach`, Lisp's `mapcar`) provides a high-order function which +takes an operation and a sequence then consumes the sequence with that operation +being applied to the sequence. The former is called _external iterator_ (visible +to user) and the latter is called _internal iterator_ (invisible to user). + +The built-in type `Iter[T]` is MoonBit's internal iterator implementation. +Almost all built-in sequential data structures have implemented `Iter`: + +```moonbit +fn filter_even(l : Array[Int]) -> Array[Int] { + let l_iter : Iter[Int] = l.iter() + l_iter.filter(fn { x => (x & 1) == 1 }).collect() +} + +fn fact(n : Int) -> Int { + let start = 1 + start.until(n).fold(Int::op_mul, init=start) +} +``` + +Commonly used methods include: + +- `each`: Iterates over each element in the iterator, applying some function to each element. +- `fold`: Folds the elements of the iterator using the given function, starting with the given initial value. +- `collect`: Collects the elements of the iterator into an array. + +- `filter`: _lazy_ Filters the elements of the iterator based on a predicate function. +- `map`: _lazy_ Transforms the elements of the iterator using a mapping function. +- `concat`: _lazy_ Combines two iterators into one by appending the elements of the second iterator to the first. + +Methods like `filter` `map` are very common on a sequence object e.g. Array. +But what makes `Iter` special is that any method that constructs a new `Iter` is +_lazy_ (i.e. iteration doesn't start on call because it's wrapped inside a +function), as a result of no allocation for intermediate value. That's what +makes `Iter` superior for traversing through sequence: no extra cost. MoonBit +encourages user to pass an `Iter` across functions instead of the sequence +object itself. + +Pre-defined sequence structures like `Array` and its iterators should be +enough to use. But to take advantages of these methods when used with a custom +sequence with elements of type `S`, we will need to implement `Iter`, namely, a function that returns +an `Iter[S]`. Take `Bytes` as an example: + +```moonbit +fn iter(data : Bytes) -> Iter[Byte] { + Iter::new( + fn(yield) { + // The code that actually does the iteration + ///////////////////////////////////////////// + for i = 0, len = data.length(); i < len; i = i + 1 { + if yield(data[i]) == IterEnd { + break IterEnd + } + ///////////////////////////////////////////// + } else { + IterContinue + } + }, + ) +} +``` + +Almost all `Iter` implementations are identical to that of `Bytes`, the only +main difference being the code block that actually does the iteration. + +### Implementation details + +The type `Iter[T]` is basically a type alias for `((T) -> IterResult) -> IterResult`, +a higher-order function that takes an operation and `IterResult` is an enum +object that tracks the state of current iteration which consists any of the 2 +states: + +- `IterEnd`: marking the end of an iteration +- `IterContinue`: marking the end of an iteration is yet to be reached, implying the iteration will still continue at this state. + +To put it simply, `Iter[T]` takes a function `(T) -> IterResult` and use it to +transform `Iter[T]` itself to a new state of type `IterResult`. Whether that +state being `IterEnd` `IterContinue` depends on the function. + +Iterator provides a unified way to iterate through data structures, and they +can be constructed at basically no cost: as long as `fn(yield)` doesn't +execute, the iteration process doesn't start. + +Internally a `Iter::run()` is used to trigger the iteration. Chaining all sorts +of `Iter` methods might be visually pleasing, but do notice the heavy work +underneath the abstraction. + +Thus, unlike an external iterator, once the iteration starts +there's no way to stop unless the end is reached. Methods such as `count()` +which counts the number of elements in a iterator looks like an `O(1)` operation +but actually has linear time complexity. Carefully use iterators or +performance issue might occur. + +## Built-in Data Structures + +### Boolean + +MoonBit has a built-in boolean type, which has two values: `true` and `false`. The boolean type is used in conditional expressions and control structures. + +```moonbit +let a = true +let b = false +let c = a && b +let d = a || b +let e = not(a) +``` + +### Number + +MoonBit have integer type and floating point type: + +| type | description | example | +| -------- | ------------------------------------------------- | -------------------------- | +| `Int` | 32-bit signed integer | `42` | +| `Int64` | 64-bit signed integer | `1000L` | +| `UInt` | 32-bit unsigned integer | `14U` | +| `UInt64` | 64-bit unsigned integer | `14UL` | +| `Double` | 64-bit floating point, defined by IEEE754 | `3.14` | +| `Float` | 32-bit floating point | `(3.14 : Float)` | +| `BigInt` | represents numeric values larger than other types | `10000000000000000000000N` | + +MoonBit also supports numeric literals, including decimal, binary, octal, and hexadecimal numbers. + +To improve readability, you may place underscores in the middle of numeric literals such as `1_000_000`. Note that underscores can be placed anywhere within a number, not just every three digits. + +- There is nothing surprising about decimal numbers. + + ```moonbit + let a = 1234 + let b = 1_000_000 + a + let large_num = 9_223_372_036_854_775_807L // Integers of the Int64 type must have an 'L' as a suffix + let unsigned_num = 4_294_967_295U // Integers of the UInt type must have an 'U' suffix + ``` + +- A binary number has a leading zero followed by a letter "B", i.e. `0b`/`0B`. + Note that the digits after `0b`/`0B` must be `0` or `1`. + + ```moonbit + let bin = 0b110010 + let another_bin = 0B110010 + ``` + +- An octal number has a leading zero followed by a letter "O", i.e. `0o`/`0O`. + Note that the digits after `0o`/`0O` must be in the range from `0` through `7`: + + ```moonbit + let octal = 0o1234 + let another_octal = 0O1234 + ``` + +- A hexadecimal number has a leading zero followed by a letter "X", i.e. `0x`/`0X`. + Note that the digits after the `0x`/`0X` must be in the range `0123456789ABCDEF`. + + ```moonbit + let hex = 0XA + let another_hex = 0xA + ``` + +#### Overloaded int literal + +When the expected type is known, MoonBit can automatically overload integer literal, and there is no need to specify the type of number via letter postfix: + +```moonbit +let int : Int = 42 +let uint : UInt = 42 +let int64 : Int64 = 42 +let double : Double = 42 +let float : Float = 42 +let bigint : BigInt = 42 +``` + +### String + +`String` holds a sequence of UTF-16 code units. You can use double quotes to create a string, or use `#|` to write a multi-line string. + +```moonbit +let a = "兔rabbit" +println(a[0]) // output: 兔 +println(a[1]) // output: r +``` + +```moonbit +let b = + #| Hello + #| MoonBit + #| +``` + +In double quotes string, a backslash followed by certain special characters forms an escape sequence: + +| escape sequences | description | +| -------------------- | ---------------------------------------------------- | +| `\n`,`\r`,`\t`,`\b` | New line, Carriage return, Horizontal tab, Backspace | +| `\\` | Backslash | +| `\x41` | Hexadecimal escape sequence | +| `\o102` | Octal escape sequence | +| `\u5154`,`\u{1F600}` | Unicode escape sequence | + +MoonBit supports string interpolation. It enables you to substitute variables within interpolated strings. This feature simplifies the process of constructing dynamic strings by directly embedding variable values into the text. Variables used for string interpolation must support the `to_string` method. + +```moonbit +let x = 42 +println("The answer is \{x}") +``` + +Multi-line strings do not support interpolation by default, but you can enable interpolation for a specific line by changing the leading `#|` to `$|`: + +```moonbit +let lang = "MoonBit" +let str = + #| Hello + #| --- + $| \{lang}\n + #| --- +println(str) +``` + +Output: + +``` + Hello + --- + MoonBit + + --- +``` + +### Char + +`Char` is an integer representing a Unicode code point. + +```moonbit +let a : Char = 'A' +let b = '\x41' +let c = '兔' +let zero = '\u{30}' +let zero = '\u0030' +``` + +### Byte(s) + +A byte literal in MoonBit is either a single ASCII character or a single escape enclosed in single quotes `'`, and preceded by the character `b`. Byte literals are of type `Byte`. For example: + +```moonbit live +fn main { + let b1 : Byte = b'a' + println(b1.to_int()) + let b2 = b'\xff' + println(b2.to_int()) +} +``` + +A `Bytes` is a sequence of bytes. Similar to byte, bytes literals have the form of `b"..."`. For example: + +```moonbit live +fn main { + let b1 : Bytes = b"abcd" + let b2 = b"\x61\x62\x63\x64" + println(b1 == b2) // true +} +``` + +### Tuple + +A tuple is a collection of finite values constructed using round brackets `()` with the elements separated by commas `,`. The order of elements matters; for example, `(1,true)` and `(true,1)` have different types. Here's an example: + +```moonbit +fn pack(a: Bool, b: Int, c: String, d: Double) -> (Bool, Int, String, Double) { + (a, b, c, d) +} +fn init { + let quad = pack(false, 100, "text", 3.14) + let (bool_val, int_val, str, float_val) = quad + println("\{bool_val} \{int_val} \{str} \{float_val}") +} +``` + +Tuples can be accessed via pattern matching or index: + +```moonbit live +fn f(t : (Int, Int)) -> Unit { + let (x1, y1) = t // access via pattern matching + // access via index + let x2 = t.0 + let y2 = t.1 + if (x1 == x2 && y1 == y2) { + println("yes") + } else { + println("no") + } +} + +fn main { + f((1, 2)) +} +``` + +### Array + +An array is a finite sequence of values constructed using square brackets `[]`, with elements separated by commas `,`. For example: + +```moonbit +let numbers = [1, 2, 3, 4] +``` + +You can use `numbers[x]` to refer to the xth element. The index starts from zero. + +```moonbit live +fn main { + let numbers = [1, 2, 3, 4] + let a = numbers[2] + numbers[3] = 5 + let b = a + numbers[3] + println(b) // prints 8 +} +``` + +### Map + +MoonBit provides a hash map data structure that preserves insertion orde called `Map` in its standard library. +`Map`s can be created via a convenient literal syntax: + +```moonbit +let map : Map[String, Int] = { "x": 1, "y": 2, "z": 3 } +``` + +Currently keys in map literal syntax must be constant. `Map`s can also be destructed elegantly with pattern matching, see [Map Pattern](#map-pattern). + +## Json literal + +MoonBit supports convenient json handling by overloading literals. +When the expected type of an expression is `Json`, number, string, array and map literals can be directly used to create json data: + +```moonbit +let moon_pkg_json_example : Json = { + "import": [ "moonbitlang/core/builtin", "moonbitlang/core/coverage" ], + "test-import": [ "moonbitlang/core/random" ] +} +``` + +Json values can be pattern matched too, see [Json Pattern](#json-pattern). + +## 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. + +```moonbit live +let zero = 0 + +fn main { + let mut i = 10 + i = 20 + println(i + zero) +} +``` + +## Data Types + +There are two ways to create new data types: `struct` and `enum`. + +### Struct + +In MoonBit, structs are similar to tuples, but their fields are indexed by field names. A struct can be constructed using a struct literal, which is composed of a set of labeled values and delimited with curly brackets. The type of a struct literal can be automatically inferred if its fields exactly match the type definition. A field can be accessed using the dot syntax `s.f`. If a field is marked as mutable using the keyword `mut`, it can be assigned a new value. + +```moonbit live +struct User { + id: Int + name: String + mut email: String +} + +fn main { + let u = { id: 0, name: "John Doe", email: "john@doe.com" } + u.email = "john@doe.name" + println(u.id) + println(u.name) + println(u.email) +} +``` + +#### Constructing Struct with Shorthand + +If you already have some variable like `name` and `email`, it's redundant to repeat those names when constructing a struct: + +```moonbit +fn main { + let name = "john" + let email = "john@doe.com" + let u = { id: 0, name: name, email: email } +} +``` + +You can use shorthand instead, it behaves exactly the same. + +```moonbit +fn main { + let name = "john" + let email = "john@doe.com" + let u = { id: 0, name, email } +} +``` + +#### Struct Update Syntax + +It's useful to create a new struct based on an existing one, but with some fields updated. + +```moonbit live +struct User { + id: Int + name: String + email: String +} derive(Show) + +fn main { + let user = { id: 0, name: "John Doe", email: "john@doe.com" } + let updated_user = { ..user, email: "john@doe.name" } + println(user) // output: { id: 0, name: "John Doe", email: "john@doe.com" } + println(updated_user) // output: { id: 0, name: "John Doe", email: "john@doe.name" } +} +``` + +### Enum + +Enum types are similar to algebraic data types in functional languages. Users familiar with C/C++ may prefer calling it tagged union. + +An enum can have a set of cases (constructors). Constructor names must start with capitalized letter. You can use these names to construct corresponding cases of an enum, or checking which branch an enum value belongs to in pattern matching: + +```moonbit live +// An enum type that represents the ordering relation between two values, +// with three cases "Smaller", "Greater" and "Equal" +enum Relation { + Smaller + Greater + Equal +} + +// compare the ordering relation between two integers +fn compare_int(x: Int, y: Int) -> Relation { + if x < y { + // when creating an enum, if the target type is known, you can write the constructor name directly + Smaller + } else if x > y { + // but when the target type is not known, + // you can always use `TypeName::Constructor` to create an enum unambiguously + Relation::Greater + } else { + Equal + } +} + +// output a value of type `Relation` +fn print_relation(r: Relation) -> Unit { + // use pattern matching to decide which case `r` belongs to + match r { + // during pattern matching, if the type is known, writing the name of constructor is sufficient + Smaller => println("smaller!") + // but you can use the `TypeName::Constructor` syntax for pattern matching as well + Relation::Greater => println("greater!") + Equal => println("equal!") + } +} + +fn main { + print_relation(compare_int(0, 1)) // smaller! + print_relation(compare_int(1, 1)) // equal! + print_relation(compare_int(2, 1)) // greater! +} +``` + +Enum cases can also carry payload data. Here's an example of defining an integer list type using enum: + +```moonbit live +enum List { + Nil + // constructor `Cons` carries additional payload: the first element of the list, + // and the remaining parts of the list + Cons (Int, List) +} + +fn main { + // when creating values using `Cons`, the payload of by `Cons` must be provided + let l: List = Cons(1, Cons(2, Nil)) + println(is_singleton(l)) + print_list(l) +} + +fn print_list(l: List) -> Unit { + // when pattern-matching an enum with payload, + // in additional to deciding which case a value belongs to + // you can extract the payload data inside that case + match l { + Nil => println("nil") + // Here `x` and `xs` are defining new variables instead of referring to existing variables, + // if `l` is a `Cons`, then the payload of `Cons` (the first element and the rest of the list) + // will be bind to `x` and `xs + Cons(x, xs) => { + println(x) + println(",") + print_list(xs) + } + } +} + +// In addition to binding payload to variables, +// you can also continue matching payload data inside constructors. +// Here's a function that decides if a list contains only one element +fn is_singleton(l: List) -> Bool { + match l { + // This branch only matches values of shape `Cons(_, Nil)`, i.e. lists of length 1 + Cons(_, Nil) => true + // Use `_` to match everything else + _ => false + } +} +``` + +#### Constructor with labelled arguments + +Enum constructors can have labelled argument: + +```moonbit live +enum E { + // `x` and `y` are labelled argument + C(x~ : Int, y~ : Int) +} + +// pattern matching constructor with labelled arguments +fn f(e : E) -> Unit { + match e { + // `label=pattern` + C(x=0, y=0) => println("0!") + // `x~` is an abbreviation for `x=x` + // Unmatched labelled arguments can be omitted via `..` + C(x~, ..) => println(x) + } +} + +// creating constructor with labelled arguments +fn main { + f(C(x=0, y=0)) // `label=value` + let x = 0 + f(C(x~, y=1)) // `~x` is an abbreviation for `x=x` +} +``` + +It is also possible to access labelled arguments of constructors like accessing struct fields in pattern matching: + +```moonbit +enum Object { + Point(x~ : Double, y~ : Double) + Circle(x~ : Double, y~ : Double, radius~ : Double) +} + +type! NotImplementedError derive(Show) + +fn distance_with(self : Object, other : Object) -> Double!NotImplementedError { + match (self, other) { + // For variables defined via `Point(..) as p`, + // the compiler knows it must be of constructor `Point`, + // so you can access fields of `Point` directly via `p.x`, `p.y` etc. + (Point(_) as p1, Point(_) as p2) => { + let dx = p2.x - p1.x + let dy = p2.y - p1.y + (dx * dx + dy * dy).sqrt() + } + (Point(_), Circle(_)) | (Circle(_), Point(_)) | (Circle(_), Circle(_)) => + raise NotImplementedError + } +} + +fn main { + let p1 : Object = Point(x=0, y=0) + let p2 : Object = Point(x=3, y=4) + let c1 : Object = Circle(x=0, y=0, radius=2) + try { + println(p1.distance_with!(p2)) // 5.0 + println(p1.distance_with!(c1)) + } catch { + e => println(e) + } +} +``` + +#### Constructor with mutable fields + +It is also possible to define mutable fields for constructor. This is especially useful for defining imperative data structures: + +```moonbit +// A mutable binary search tree with parent pointer +enum Tree[X] { + Nil + // only labelled arguments can be mutable + Node(mut value~ : X, mut left~ : Tree[X], mut right~ : Tree[X], mut parent~ : Tree[X]) +} + +// A set implemented using mutable binary search tree. +struct Set[X] { + mut root : Tree[X] +} + +fn Set::insert[X : Compare](self : Set[X], x : X) -> Unit { + self.root = self.root.insert(x, parent=Nil) +} + +// In-place insert a new element to a binary search tree. +// Return the new tree root +fn Tree::insert[X : Compare](self : Tree[X], x : X, parent~ : Tree[X]) -> Tree[X] { + match self { + Nil => Node(value=x, left=Nil, right=Nil, parent~) + Node(_) as node => { + let order = x.compare(node.value) + if order == 0 { + // mutate the field of a constructor + node.value = x + } else if order < 0 { + // cycle between `node` and `node.left` created here + node.left = node.left.insert(x, parent=node) + } else { + node.right = node.right.insert(x, parent=node) + } + // The tree is non-empty, so the new root is just the original tree + node + } + } +} +``` + +### Newtype + +MoonBit supports a special kind of enum called newtype: + +```moonbit +// `UserId` is a fresh new type different from `Int`, and you can define new methods for `UserId`, etc. +// But at the same time, the internal representation of `UserId` is exactly the same as `Int` +type UserId Int +type UserName String +``` + +Newtypes are similar to enums with only one constructor (with the same name as the newtype itself). So, you can use the constructor to create values of newtype, or use pattern matching to extract the underlying representation of a newtype: + +```moonbit +fn init { + let id: UserId = UserId(1) + let name: UserName = UserName("John Doe") + let UserId(uid) = id // the type of `uid` is `Int` + let UserName(uname) = name // the type of `uname` is `String` + println(uid) + println(uname) +} +``` + +Besides pattern matching, you can also use `._` to extract the internal representation of newtypes: + +```moonbit +fn init { + let id: UserId = UserId(1) + let uid: Int = id._ + println(uid) +} +``` + +### Type alias +MoonBit supports type alias via the syntax `typealias Name = TargetType`: + +```moonbit +pub typealias Index = Int +// type alias are private by default +typealias MapString[X] = Map[String, X] +``` + +unlike all other kinds of type declaration above, type alias does not define a new type, +it is merely a type macro that behaves exactly the same as its definition. +So for example one cannot define new methods or implement traits for a type alias. + +Type alias can be used to perform incremental code refactor. +For example, if you want to move a type `T` from `@pkgA` to `@pkgB`, +you can leave a type alias `typealias T = @pkgB.T` in `@pkgA`, and **incrementally** port uses of `@pkgA.T` to `@pkgB.T`. +The type alias can be removed after all uses of `@pkgA.T` is migrated to `@pkgB.T`. + +## Pattern Matching + +We have shown a use case of pattern matching for enums, but pattern matching is not restricted to enums. For example, we can also match expressions against Boolean values, numbers, characters, strings, tuples, arrays, and struct literals. Since there is only one case for those types other than enums, we can pattern match them using `let` binding instead of `match` expressions. Note that the scope of bound variables in `match` is limited to the case where the variable is introduced, while `let` binding will introduce every variable to the current scope. Furthermore, we can use underscores `_` as wildcards for the values we don't care about, use `..` to ignore remaining fields of struct or elements of array. + +```moonbit +let id = match u { + { id: id, name: _, email: _ } => id +} +// is equivalent to +let { id: id, name: _, email: _ } = u +// or +let { id: id, ..} = u +``` + +```moonbit +let ary = [1,2,3,4] +let [a, b, ..] = ary // a = 1, b = 2 +let [.., a, b] = ary // a = 3, b = 4 +``` + +There are some other useful constructs in pattern matching. For example, we can use `as` to give a name to some pattern, and we can use `|` to match several cases at once. A variable name can only be bound once in a single pattern, and the same set of variables should be bound on both sides of `|` patterns. + +```moonbit +match expr { + Lit(n) as a => ... + Add(e1, e2) | Mul(e1, e2) => ... + _ => ... +} +``` + +### Range Pattern +For builtin integer types and `Char`, MoonBit allows matching whether the value falls in a specific range. +Range patterns have the form `a.. Int { + match x { + _.. -1 + Zero => 0 + 1..<_ => 1 + } +} + +fn classify_char(c : Char) -> String { + match c { + 'a'..='z' => "lowercase" + 'A'..='Z' => "uppercase" + '0'..='9' => "digit" + _ => "other" + } +} +``` + +### Map Pattern + +MoonBit allows convenient matching on map-like data structures. +Inside a map pattern, the `key : value` syntax will match if `key` exists in the map, and match the value of `key` with pattern `value`. +The `key? : value` syntax will match no matter `key` exists or not, and `value` will be matched against `map[key]` (an optional). + +```moonbit +match map { + // matches if any only if "b" exists in `map` + { "b": _ } => .. + // matches if and only if "b" does not exist in `map` and "a" exists in `map`. + // When matches, bind the value of "a" in `map` to `x` + { "b"? : None, "a": x } => .. + // compiler reports missing case: { "b"? : None, "a"? : None } +} +``` + +- To match a data type `T` using map pattern, `T` must have a method `op_get(Self, K) -> Option[V]` for some type `K` and `V`. +- Currently, the key part of map pattern must be a constant +- Map patterns are always open: unmatched keys are silently ignored +- Map pattern will be compiled to efficient code: every key will be fetched at most once + +### Json Pattern + +When the matched value has type `Json`, literal patterns can be used directly: + +```moonbit +match json { + { "version": "1.0.0", "import": [..] as imports } => ... + _ => ... +} +``` + +## Operators + +### Operator Overloading + +MoonBit supports operator overloading of builtin operators via methods. The method name corresponding to a operator `` is `op_`. For example: + +```moonbit live +struct T { + x:Int +} derive(Show) + +fn op_add(self: T, other: T) -> T { + { x: self.x + other.x } +} + +fn main { + let a = { x: 0 } + let b = { x: 2 } + println(a + b) +} +``` + +Another example about `op_get` and `op_set`: + +```moonbit live +struct Coord { + mut x: Int + mut y: Int +} derive(Show) + +fn op_get(self: Coord, key: String) -> Int { + match key { + "x" => self.x + "y" => self.y + } +} + +fn op_set(self: Coord, key: String, val: Int) -> Unit { + match key { + "x" => self.x = val + "y" => self.y = val + } +} + +fn main { + let c = { x: 1, y: 2 } + println(c) + println(c["y"]) + c["x"] = 23 + println(c) + println(c["x"]) +} +``` + +Currently, the following operators can be overloaded: + +| Operator Name | Method Name | +| --------------------- | ------------ | +| `+` | `op_add` | +| `-` | `op_sub` | +| `*` | `op_mul` | +| `/` | `op_div` | +| `%` | `op_mod` | +| `=` | `op_equal` | +| `<<` | `op_shl` | +| `>>` | `op_shr` | +| `-` (unary) | `op_neg` | +| `_[_]` (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: + +```moonbit +fn init { + x |> f // equivalent to f(x) + x |> f(y) // equivalent to f(x, y) + + // Chain calls at multiple lines + arg_val + |> f1 // equivalent to f1(arg_val) + |> f2(other_args) // equivalent to f2(f1(arg_val), other_args) +} +``` + +### Cascade Operator + +The cascade operator `..` is used to perform a series of mutable operations on +the same value consecutively. The syntax is as follows: + +```moonbit +x..f() +``` + +`x..f()..g()` is equivalent to `{x.f(); x.g(); x}`. + +Consider the following scenario: for a `MyStringBuilder` type that has methods +like `add_string`, `add_char`, `add_int`, etc., we often need to perform +a series of operations on the same `MyStringBuilder` value: + +```moonbit +let builder = MyStringBuilder::new() +builder.add_char('a') +builder.add_char('a') +builder.add_int(1001) +builder.add_string("abcdef") +let result = builder.to_string() +``` + +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. + +```moonbit +let result = + MyStringBuilder::new() + ..add_char('a') + ..add_char('a') + ..add_int(1001) + ..add_string("abcdef") + .to_string() +``` + +### Bitwise Operator + +MoonBit supports C-Style bitwise operators. + +| Operator | Perform | +| -------- | ------- | +| `&` | `land` | +| `\|` | `lor` | +| `^` | `lxor` | +| `<<` | `op_shl` | +| `>>` | `op_shr` | + +## Error Handling + +### Error types + +The error values used in MoonBit must have an error type. An error type can be +defined in the following forms: + +```moonbit +type! E1 Int // error type E1 has one constructor E1 with an Int payload +type! E2 // error type E2 has one constructor E2 with no payload +type! E3 { // error type E3 has three constructors like a normal enum type + A + B(Int, x~ : String) + C(mut x~ : String, Char, y~ : Bool) +} +``` + +The return type of a function can include an error type to indicate that the +function might return an error. For example, the following function `div` might +return an error of type `DivError`: + +```moonbit +type! DivError String +fn div(x: Int, y: Int) -> Int!DivError { + if y == 0 { + raise DivError("division by zero") + } + x / y +} +``` + +Here, the keyword `raise` is used to interrupt the function execution and return +an error. + +### The Default Error Type + +MoonBit provides a default error type `Error` that can be used when the concrete +error type is not important. For convenience, you can annotate the function name +or the return type with the suffix `!` to indicate that the `Error` type is +used. For example, the following function signatures are equivalent: + +```moonbit +fn f() -> Unit! { .. } +fn f!() -> Unit { .. } +fn f() -> Unit!Error { .. } +``` + +For anonymous function and matrix function, you can annotate the keyword `fn` +with the `!` suffix to achieve that. For example, + +```moonbit +type! IntError Int +fn h(f: (x: Int) -> Int!, x: Int) -> Unit { .. } + +fn main { + let _ = h(fn! { x => raise(IntError(x)) }, 0) // matrix function + let _ = h(fn! (x) { x => raise(IntError(x)) }, 0) // anonymous function +} +``` + +As shown in the above example, the error types defined by `type!` can be used as +value of the type `Error` when the error is raised. + +Note that only error types or the type `Error` can be used as errors. For +functions that are generic in the error type, you can use the `Error` bound to +do that. For example, + +```moonbit +pub fn unwrap_or_error[T, E : Error](self : Result[T, E]) -> T!E { + match self { + Ok(x) => x + Err(e) => raise e + } +} +``` + +Since the type `Error` can include multiple error types, pattern matching on the +`Error` type must use the wildcard `_` to match all error types. For example, + +```moonbit +type! E1 +type! E2 +fn f(e: Error) -> Unit { + match e { + E1 => println("E1") + E2 => println("E2") + _ => println("unknown error") + } +} +``` + +### Handling Errors + +There are three ways to handle errors: + +- Append `!` after the function name in a function application to rethrow the + error directly in case of an error, for example: + +```moonbit +fn div_reraise(x: Int, y: Int) -> Int!DivError { + div!(x, y) // Rethrow the error if `div` raised an error +} +``` + +- Append `?` after the function name to convert the result into a first-class + value of the `Result` type, for example: + +```moonbit +test { + let res = div?(6, 3) + inspect!(res, content="Ok(2)") + let res = div?(6, 0) + inspect!(res, content="Err(division by zero)") +} +``` + +- Use `try` and `catch` to catch and handle errors, for example: + +```moonbit +fn main { + try { + div!(42, 0) + } catch { + DivError(s) => println(s) + } else { + v => println(v) + } +} +``` + +Here, `try` is used to call a function that might throw an error, and `catch` is +used to match and handle the caught error. If no error is caught, the catch +block will not be executed and the `else` block will be executed instead. + +The `else` block can be omitted if no action is needed when no error is caught. +For example: + +```moonbit +fn main { + try { + println(div!(42, 0)) + } catch { + _ => println("Error") + } +} +``` + +The `catch` keyword is optional, and when the body of `try` is a simple +expression, the curly braces can be omitted. For example: + +```moonbit +fn main { + let a = try div!(42, 0) { _ => 0 } + println(a) +} +``` + +The `!` and `?` attributes can also be used on method invocation and pipe +operator. For example: + +```moonbit live +type T Int +type! E Int derive(Show) +fn f(self: T) -> Unit!E { raise E(self._) } +fn main { + let x = T(42) + try f!(x) { e => println(e) } + try x.f!() { e => println(e) } + try x |> f!() { e => println(e) } +} +``` + +However for infix operators such as `+` `*` that may raise an error, +the original form has to be used, e.g. `x.op_add!(y)`, `x.op_mul!(y)`. + +Additionally, if the return type of a function includes an error type, the +function call must use `!` or `?` for error handling, otherwise the compiler +will report an error. + +### Error Inference + +Within a `try` block, several different kinds of errors can be raised. When that +happens, the compiler will use the type `Error` as the common error type. +Accordingly, the handler must use the wildcard `_` to make sure all errors are +caught. For example, + +```moonbit live +type! E1 +type! E2 +fn f1() -> Unit!E1 { raise E1 } +fn f2() -> Unit!E2 { raise E2 } +fn main { + try { + f1!() + f2!() + } catch { + E1 => println("E1") + E2 => println("E2") + _ => println("unknown error") + } +} +``` + +You can also use `catch!` to rethrow the uncaught errors for convenience. This +is useful when you only want to handle a specific error and rethrow others. For +example, + +```moonbit +type! E1 +type! E2 +fn f1() -> Unit!E1 { raise E1 } +fn f2() -> Unit!E2 { raise E2 } +fn f() -> Unit! { + try { + f1!() + f2!() + } catch! { + E1 => println("E1") + } +} +``` + +## Generics + +Generics are supported in top-level function and data type definitions. Type parameters can be introduced within square brackets. We can rewrite the aforementioned data type `List` to add a type parameter `T` to obtain a generic version of lists. We can then define generic functions over lists like `map` and `reduce`. + +```moonbit +enum List[T] { + Nil + Cons(T, List[T]) +} + +fn map[S, T](self: List[S], f: (S) -> T) -> List[T] { + match self { + Nil => Nil + Cons(x, xs) => Cons(f(x), map(xs, f)) + } +} + +fn reduce[S, T](self: List[S], op: (T, S) -> T, init: T) -> T { + match self { + Nil => init + Cons(x, xs) => reduce(xs, op, op(init, x)) + } +} +``` + +## Access Control + +By default, all function definitions and variable bindings are _invisible_ to other packages. +You can use the `pub` modifier before toplevel `let`/`fn` to make them public. + +There are four different kinds of visibility for types in MoonBit: + +- private type, declared with `priv`, completely invisible to the outside world +- abstract type, which is the default visibility for types. Only the name of an abstract type is visible outside, the internal representation of the type is hidden +- readonly types, declared with `pub(readonly)`. The internal representation of readonly types are visible outside, +but users can only read the values of these types from outside, construction and mutation are not allowed +- fully public types, declared with `pub(all)`. The outside world can freely construct, modify and read values of these types + +Currently, the semantic of `pub` is `pub(all)`. But in the future, the meaning of `pub` will be ported to `pub(readonly)`. +In addition to the visibility of the type itself, the fields of a public `struct` can be annotated with `priv`, +which will hide the field from the outside world completely. +Note that `struct`s with private fields cannot be constructed directly outside, +but you can update the public fields using the functional struct update syntax. + +Readonly types is a very useful feature, inspired by [private types](https://v2.ocaml.org/manual/privatetypes.html) in OCaml. In short, values of `pub(readonly)` types can be destructed by pattern matching and the dot syntax, but cannot be constructed or mutated in other packages. Note that there is no restriction within the same package where `pub(readonly)` types are defined. + +```moonbit +// Package A +pub(readonly) struct RO { + field: Int +} +fn init { + let r = { field: 4 } // OK + let r = { ..r, field: 8 } // OK +} + +// Package B +fn println(r : RO) -> Unit { + println("{ field: ") + println(r.field) // OK + println(" }") +} +fn init { + let r : RO = { field: 4 } // ERROR: Cannot create values of the public read-only type RO! + let r = { ..r, field: 8 } // ERROR: Cannot mutate a public read-only field! +} +``` + +Access control in MoonBit adheres to the principle that a `pub` type, function, or variable cannot be defined in terms of a private type. This is because the private type may not be accessible everywhere that the `pub` entity is used. MoonBit incorporates sanity checks to prevent the occurrence of use cases that violate this principle. + +```moonbit +pub struct S { + x: T1 // OK + y: T2 // OK + z: T3 // ERROR: public field has private type `T3`! +} + +// ERROR: public function has private parameter type `T3`! +pub fn f1(_x: T3) -> T1 { T1::A(0) } +// ERROR: public function has private return type `T3`! +pub fn f2(_x: T1) -> T3 { T3::A(0) } +// OK +pub fn f3(_x: T1) -> T1 { T1::A(0) } + +pub let a: T3 // ERROR: public variable has private type `T3`! +``` + +## Method system + +MoonBit supports methods in a different way from traditional object-oriented languages. A method in MoonBit is just a toplevel function associated with a type constructor. Methods can be defined using the syntax `fn TypeName::method_name(...) -> ...`: + +```moonbit +enum MyList[X] { + Nil + Cons(X, MyList[X]) +} + +fn MyList::map[X, Y](xs: MyList[X], f: (X) -> Y) -> MyList[Y] { ... } +fn MyList::concat[X](xs: MyList[MyList[X]]) -> MyList[X] { ... } +``` + +As a convenient shorthand, when the first parameter of a function is named `self`, MoonBit automatically defines the function as a method of the type of `self`: + +```moonbit +fn map[X, Y](self: MyList[X], f: (X) -> Y) -> List[Y] { ... } +// equivalent to +fn MyList::map[X, Y](xs: MyList[X], f: (X) -> Y) -> List[Y] { ... } +``` + +Methods are just regular functions owned by a type constructor. So when there is no ambiguity, methods can be called using regular function call syntax directly: + +```moonbit +fn init { + let xs: MyList[MyList[_]] = ... + let ys = concat(xs) +} +``` + +Unlike regular functions, methods support overloading: different types can define methods of the same name. If there are multiple methods of the same name (but for different types) in scope, one can still call them by explicitly adding a `TypeName::` prefix: + +```moonbit +struct T1 { x1: Int } +fn T1::default() -> { { x1: 0 } } + +struct T2 { x2: Int } +fn T2::default() -> { { x2: 0 } } + +fn init { + // default() is ambiguous! + let t1 = T1::default() // ok + let t2 = T2::default() // ok +} +``` + +When the first parameter of a method is also the type it belongs to, methods can be called using dot syntax `x.method(...)`. MoonBit automatically finds the correct method based on the type of `x`, there is no need to write the type name and even the package name of the method: + +```moonbit +// a package named @list +enum List[X] { ... } +fn List::length[X](xs: List[X]) -> Int { ... } + +// another package that uses @list +fn init { + let xs: @list.List[_] = ... + println(xs.length()) // always work + println(@list.List::length(xs)) // always work, but verbose + println(@list.length(xs)) // simpler, but only possible when there is no ambiguity in @list +} +``` + +## View + +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. + +```moonbit +fn init { + let xs = [0,1,2,3,4,5] + let s1 : ArrayView[Int] = xs[2:] + print_array_view(s1) //output: 2345 + xs[:4] |> print_array_view() //output: 0123 + xs[2:5] |> print_array_view() //output: 234 + xs[:] |> print_array_view() //output: 012345 + + // create a view of another view + xs[2:5][1:] |> print_array_view() //output: 34 +} + +fn print_array_view[T : Show](view : ArrayView[T]) -> Unit { + for i=0; i Int { + self.elems.length() +} + +pub fn op_as_view[A](self : MyList[A], start~ : Int, end~ : Int) -> MyListView[A] { + println("op_as_view: [\{start},\{end})") + if start < 0 || end > self.length() { abort("index out of bounds") } + { ls: self, start, end } +} + +fn init { + let ls = { elems: [1,2,3,4,5] } + ls[:] |> ignore() + ls[1:] |> ignore() + ls[:2] |> ignore() + ls[1:2] |> ignore() +} +``` + +Output: + +```plaintext +op_as_view: [0,5) +op_as_view: [1,5) +op_as_view: [0,2) +op_as_view: [1,2) +``` + +## Trait system + +MoonBit features a structural trait system for overloading/ad-hoc polymorphism. Traits declare a list of operations, which must be supplied when a type wants to implement the trait. Traits can be declared as follows: + +```moonbit +trait I { + method(...) -> ... +} +``` + +In the body of a trait definition, a special type `Self` is used to refer to the type that implements the trait. + +To implement a trait, a type must provide all the methods required by the trait. +Implementation for trait methods can be provided via the syntax `impl Trait for Type with method_name(...) { ... }`, for example: + +```moonbit +trait Show { + to_string(Self) -> String +} + +struct MyType { ... } +impl Show for MyType with to_string(self) { ... } + +// trait implementation with type parameters. +// `[X : Show]` means the type parameter `X` must implement `Show`, +// this will be covered later. +impl[X : Show] Show for Array[X] with to_string(self) { ... } +``` + +Type annotation can be omitted for trait `impl`: MoonBit will automatically infer the type based on the signature of `Trait::method` and the self type. + +The author of the trait can also define default implementations for some methods in the trait, for example: + +```moonbit +trait I { + f(Self) -> Unit + f_twice(Self) -> Unit +} + +impl I with f_twice(self) { + self.f() + self.f() +} +``` + +Implementers of trait `I` don't have to provide an implementation for `f_twice`: to implement `I`, only `f` is necessary. +They can always override the default implementation with an explicit `impl I for Type with f_twice`, if desired, though. + +If an explicit `impl` or default implementation is not found, trait method resolution falls back to regular methods. +This allows types to implement a trait implicitly, hence allowing different packages to work together without seeing or depending on each other. +For example, the following trait is automatically implemented for builtin number types such as `Int` and `Double`: + +```moonbit +trait Number { + op_add(Self, Self) -> Self + op_mul(Self, Self) -> Self +} +``` + +When declaring a generic function, the type parameters can be annotated with the traits they should implement, allowing the definition of constrained generic functions. For example: + +```moonbit +trait Number { + op_add(Self, Self) -> Self + op_mul(Self, Self) -> Self +} + +fn square[N: Number](x: N) -> N { + x * x // same as `x.op_mul(x)` +} +``` + +Without the `Number` requirement, the expression `x * x` in `square` will result in a method/operator not found error. Now, the function `square` can be called with any type that implements `Number`, for example: + +```moonbit +fn main { + println(square(2)) // 4 + println(square(1.5)) // 2.25 + println(square({ x: 2, y: 3 })) // {x: 4, y: 9} +} + +trait Number { + op_add(Self, Self) -> Self + op_mul(Self, Self) -> Self +} + +fn square[N: Number](x: N) -> N { + x * x // same as `x.op_mul(x)` +} + +struct Point { + x: Int + y: Int +} derive(Show) + +impl Number for Point with op_add(p1, p2) { + { x: p1.x + p2.x, y: p1.y + p2.y } +} + +impl Number for Point with op_mul(p1, p2) { + { x: p1.x * p2.x, y: p1.y * p2.y } +} +``` + +MoonBit provides the following useful builtin traits: + +```moonbit +trait Eq { + op_equal(Self, Self) -> Bool +} + +trait Compare { + // `0` for equal, `-1` for smaller, `1` for greater + op_equal(Self, Self) -> Int +} + +trait Hash { + hash(Self) -> Int +} + +trait Show { + // writes a string representation of `Self` into a `Logger` + output(Self, Logger) -> Unit + to_string(Self) -> String +} + +trait Default { + default() -> Self +} +``` + +### Involke trait methods directly +Methods of a trait can be called directly via `Trait::method`. MoonBit will infer the type of `Self` and check if `Self` indeed implements `Trait`, for example: + +```moonbit live +fn main { + println(Show::to_string(42)) + println(Compare::compare(1.0, 2.5)) +} +``` + +Trait implementations can also be involked via dot syntax, with the following restrictions: + +1. if a regular method is present, the regular method is always favored when using dot syntax +2. only trait implementations that are located in the package of the self type can be involked via dot syntax + - if there are multiple trait methods (from different traits) with the same name available, an ambiguity error is reported +3. if neither of the above two rules apply, trait `impl`s in current package will also be searched for dot syntax. + This allows extending a foreign type locally. + - these `impl`s can only be called via dot syntax locally, even if they are public. + +The above rules ensures that MoonBit's dot syntax enjoys good property while being flexible. +For example, adding a new dependency never break existing code with dot syntax due to ambiguity. +These rules also make name resolution of MoonBit extremely simple: +the method called via dot syntax must always come from current package or the package of the type! + +Here's an example of calling trait `impl` with dot syntax: + +```moonbit +struct MyType { ... } + +impl Show for MyType with ... + +fn main { + let x : MyType = ... + println(x.to_string()) // ok +} +``` + +## Access control of methods and trait implementations + +To make the trait system coherent (i.e. there is a globally unique implementation for every `Type: Trait` pair), +and prevent third-party packages from modifying behavior of existing programs by accident, +MoonBit employs the following restrictions on who can define methods/implement traits for types: + +- _only the package that defines a type can define methods for it_. So one cannot define new methods or override old methods for builtin and foreign types. +- _only the package of the type or the package of the trait can define an implementation_. + For example, only `@pkg1` and `@pkg2` are allowed to write `impl @pkg1.Trait for @pkg2.Type`. + +The second rule above allows one to add new functionality to a foreign type by defining a new trait and implementing it. +This makes MoonBit's trait & method system flexible while enjoying good coherence property. + +## Visibility of traits and sealed traits +There are four visibility for traits, just like `struct` and `enum`: private, abstract, readonly and fully public. +Private traits are declared with `priv trait`, and they are completely invisible from outside. +Abstract trait is the default visibility. Only the name of the trait is visible from outside, and the methods in the trait are not exposed. +Readonly traits are declared with `pub(readonly) trait`, their methods can be involked from outside, but only the current package can add new implementation for readonly traits. +Finally, fully public traits are declared with `pub(open) trait`, they are open to new implementations outside current package, and their methods can be freely used. +Currently, `pub trait` defaults to `pub(open) trait`. But in the future, the semantic of `pub trait` will be ported to `pub(readonly)`. + +Abstract and readonly traits are sealed, because only the package defining the trait can implement them. +Implementing a sealed (abstract or readonly) trait outside its package result in compiler error. +If you are the owner of a sealed trait, and you want to make some implementation available to users of your package, +make sure there is at least one declaration of the form `impl Trait for Type with ...` in your package. +Implementations with only regular method and default implementations will not be available outside. + +Here's an example of abstract trait: + +```moonbit +trait Number { + op_add(Self, Self) -> Self + op_sub(Self, Self) -> Self +} + +fn add[N : Number](x : X, y: X) -> X { + Number::op_add(x, y) +} + +fn sub[N : Number](x : X, y: X) -> X { + Number::op_sub(x, y) +} + +impl Number for Int with op_add(x, y) { x + y } +impl Number for Int with op_sub(x, y) { x - y } + +impl Number for Double with op_add(x, y) { x + y } +impl Number for Double with op_sub(x, y) { x - y } +``` + +From outside this package, users can only see the following: + +```moonbit +trait Number + +fn op_add[N : Number](x : N, y : N) -> N +fn op_sub[N : Number](x : N, y : N) -> N + +impl Number for Int +impl Number for Double +``` + +The author of `Number` can make use of the fact that only `Int` and `Double` can ever implement `Number`, +because new implementations are not allowed outside. + +## Automatically derive builtin traits + +MoonBit can automatically derive implementations for some builtin traits: + +```moonbit live +struct T { + x: Int + y: Int +} derive(Eq, Compare, Show, Default) + +fn main { + let t1 = T::default() + let t2 = { x: 1, y: 1 } + println(t1) // {x: 0, y: 0} + println(t2) // {x: 1, y: 1} + println(t1 == t2) // false + println(t1 < t2) // true +} +``` + +## Trait objects + +MoonBit supports runtime polymorphism via trait objects. +If `t` is of type `T`, which implements trait `I`, +one can pack the methods of `T` that implements `I`, together with `t`, +into a runtime object via `t as I`. +Trait object erases the concrete type of a value, +so objects created from different concrete types can be put in the same data structure and handled uniformly: + +```moonbit live +trait Animal { + speak(Self) -> Unit +} + +type Duck String +fn Duck::make(name: String) -> Duck { Duck(name) } +fn speak(self: Duck) -> Unit { + println(self._ + ": quack!") +} + +type Fox String +fn Fox::make(name: String) -> Fox { Fox(name) } +fn Fox::speak(_self: Fox) -> Unit { + println("What does the fox say?") +} + +fn main { + let duck1 = Duck::make("duck1") + let duck2 = Duck::make("duck2") + let fox1 = Fox::make("fox1") + let animals = [ duck1 as Animal, duck2 as Animal, fox1 as Animal ] + let mut i = 0 + while i < animals.length() { + animals[i].speak() + i = i + 1 + } +} +``` + +Not all traits can be used to create objects. +"object-safe" traits' methods must satisfy the following conditions: + +- `Self` must be the first parameter of a method +- There must be only one occurrence of `Self` in the type of the method (i.e. the first parameter) + +Users can define new methods for trait objects, just like defining new methods for structs and enums: + +```moonbit +trait Logger { + write_string(Self, String) -> Unit +} + +trait CanLog { + log(Self, Logger) -> Unit +} + +fn Logger::write_object[Obj : CanLog](self : Logger, obj : Obj) -> Unit { + obj.log(self) +} + +// use the new method to simplify code +impl[A : CanLog, B : CanLog] CanLog for (A, B) with log(self, logger) { + let (a, b) = self + logger + ..write_string("(") + ..write_object(a) + ..write_string(", ") + ..write_object(b) + .write_string(")") +} +``` + +## Test Blocks + +MoonBit provides the test code block for writing test cases. For example: + +```moonbit +test "test_name" { + assert_eq!(1 + 1, 2) + assert_eq!(2 + 2, 4) +} +``` + +A test code block is essentially a function that returns a `Unit` but may throws a `String` on error, or `Unit!String` as one would see in its signature at the position of return type. It is called during the execution of `moon test` and outputs a test report through the build system. The `assert_eq` function is from the standard library; if the assertion fails, it prints an error message and terminates the test. The string `"test_name"` is used to identify the test case and is optional. If it starts with `"panic"`, it indicates that the expected behavior of the test is to trigger a panic, and the test will only pass if the panic is triggered. For example: + +```moonbit +test "panic_test" { + let _ : Int = Option::None.unwrap() +} +``` + +## Doc Comments + +Doc comments are comments prefix with `///` in each line in the leading of toplevel structure like `fn`,`let`,`enum`,`struct`,`type`. The doc comments contains a markdown text and several pragmas. + +````moonbit +/// Return a new array with reversed elements. +/// +/// # Example +/// +/// ``` +/// reverse([1,2,3,4]) |> println() +/// ``` +fn reverse[T](xs : Array[T]) -> Array[T] { + ... +} +```` + +### Pragmas + +Pragmas are annotations inside doc comments. They all take the form `/// @word ...`. The _word_ indicates the type of pragma and is followed optionally by several _word_ or string literals. Pragmas do not normally affect the meaning of programs. Unrecognized pragmas will be reported as warnings. + +- Alert Pragmas + + Alert pragmas in doc comments of functions will be reported when those functions are referenced. This mechanism is a generalized way to mark functions as `deprecated` or `unsafe`. + + It takes the form `@alert category "alert message..."`. + + The category can be an arbitrary identifier. It allows configuration to decide which alerts are enabled or turned into errors. + + ```moonbit + /// @alert deprecated "Use foo2 instead" + pub fn foo() -> Unit { ... } + + /// @alert unsafe "Div will cause an error when y is zero" + pub fn div(x: Int, y: Int) -> Int { ... } + + fn main { + foo() // warning: Use foo2 instead + div(x, y) |> ignore // warning: Div will cause an error when y is zero + } + ``` + +## Special Syntax + +### 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: + +```moonbit +fn todo_in_func() -> Int { + ... +} +``` \ No newline at end of file diff --git a/next/locales/zh_CN/LC_MESSAGES/index.po b/next/locales/zh_CN/LC_MESSAGES/index.po new file mode 100644 index 00000000..e2312028 --- /dev/null +++ b/next/locales/zh_CN/LC_MESSAGES/index.po @@ -0,0 +1,72 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2024, International Digital Economy Academy +# This file is distributed under the same license as the MoonBit Document +# package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: MoonBit Document \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-11-27 13:11+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.16.0\n" + +#: ../../index.md:15 +msgid "Contents:" +msgstr "目录:" + +#: ../../index.md:1 +msgid "MoonBit Documentation" +msgstr "MoonBit 文档" + +#: ../../index.md:3 +msgid "" +"MoonBit is an end-to-end programming language toolchain for cloud and " +"edge computing using WebAssembly." +msgstr "MoonBit 是一个端到端的编程语言工具链,用于云和边缘计算,使用 WebAssembly。" + +#: ../../index.md:5 +msgid "" +"The IDE environment is available at " +"[https://try.moonbitlang.com](https://try.moonbitlang.com) without any " +"installation; it does not reply on any server either." +msgstr "" +"IDE 环境可在 [https://try.moonbitlang.cn](https://try.moonbitlang.cn) " +"试用;无需安装,也不依赖任何服务器" + +#: ../../index.md:7 +#, fuzzy +msgid "**Get started**" +msgstr "开始使用" + +#: ../../index.md:9 +msgid "[Tutorials](./tutorial/index.md): Follow tutorials to start your journey" +msgstr "[教程](./tutorial/index.md): 跟随教程开始你的旅程" + +#: ../../index.md:11 +msgid "" +"[Language](./language/index.md): Introduction to detailed language " +"specifications" +msgstr "[语言](./language/index.md): 详细语言规范介绍" + +#: ../../index.md:13 +msgid "" +"[Toolchains](./toolchain/index.md): Introduction to all the toolchains " +"making developing MoonBit a unique experience." +msgstr "[工具链](./toolchain/index.md): 介绍所有工具链,使 MoonBit 的开发成为独特体验。" + +#~ msgid "" +#~ "[Toolchains](./toolchains/index.md): Introduction to " +#~ "all the toolchains making developing " +#~ "MoonBit a unique experience." +#~ msgstr "" + diff --git a/next/locales/zh_CN/LC_MESSAGES/language.po b/next/locales/zh_CN/LC_MESSAGES/language.po new file mode 100644 index 00000000..41fed6cd --- /dev/null +++ b/next/locales/zh_CN/LC_MESSAGES/language.po @@ -0,0 +1,4860 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2024, International Digital Economy Academy +# This file is distributed under the same license as the MoonBit Document +# package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: MoonBit Document \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-11-27 13:35+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.16.0\n" + +#: ../../language/error-handling.md:1 +msgid "Error handling in MoonBit" +msgstr "MoonBit 中的错误处理" + +#: ../../language/error-handling.md:3 +msgid "" +"Error handling has always been at core of our language design. In the " +"following we'll be explaining how error handling is done in MoonBit. We " +"assume you have some prior knowledge of MoonBit, if not, please checkout " +"[A tour of MoonBit](../tutorial/tour.md)." +msgstr "" +"错误处理一直是我们语言设计的核心。接下来我们将解释 MoonBit 中的错误处理。我们假设您对 MoonBit 有一些了解,如果没有,请查看 " +"[MoonBit 之旅](../tutorial/tour.md)。" + +#: ../../language/error-handling.md:7 +msgid "Example: Division by Zero" +msgstr "示例:除零" + +#: ../../language/error-handling.md:9 +msgid "" +"We'll write a small example to demonstrate the basics of MoonBit's error " +"handling system. Consider the following `div` function which'll raise an " +"error on division by zero:" +msgstr "我们将编写一个小例子来演示 MoonBit 错误处理系统的基础知识。考虑以下 `div` 函数,它将在除零时引发错误:" + +#: ../../language/error-handling.md:13 +msgid "" +"type! DivisionByZeroError String\n" +"fn div(x : Int, y : Int) -> Int!DivisionByZeroError {\n" +" if y == 0 {\n" +" raise DivisionByZeroError(\"division by zero\")\n" +" }\n" +" x / y\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:23 +msgid "" +"In before, we would typically use `type` to define a wrapper type which " +"wraps around some existing foreign type. Here however, we append `type` " +"with `!` to define a error type `DivisionByZeroError` which wraps around " +"`String`." +msgstr "" +"在以前,我们通常使用 `type` 来定义一个包装器类型,该类型包装了某些现有的外部类型。然而,在这里,我们使用 `!` 将 `type` 附加到" +" `DivisionByZeroError`,以定义一个错误类型,该类型包装了 `String`。" + +#: ../../language/error-handling.md:27 +msgid "`type! E S` construct a error type `E` from `S`" +msgstr "`type! E S` 从 `S` 构造一个错误类型 `E`" + +#: ../../language/error-handling.md:29 +msgid "" +"Just like `type`, `type!` may have a payload like the above " +"`DivisionByZeroError`, or may not, or may even have multiple constructors" +" like a normal `enum`:" +msgstr "" +"就像 `type` 一样,`type!` 可能有一个像上面的 `DivisionByZeroError` 那样的数据,也可能没有,甚至可能像普通的" +" `enum` 一样有多个构造器:" + +#: ../../language/error-handling.md:31 +msgid "" +"type! ConnectionError {\n" +" BrokenPipe(Int,String)\n" +" ConnectionReset\n" +" ConnectionAbort\n" +" ConnectionRefused\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:40 +msgid "" +"To utilize `DivisionByZeroError` type, we would usually define a function" +" which may raise error by denoting its return type like `T ! E` in the " +"signature, with `T` being the actual return type and `E` being the error " +"type. In this case, it's `Int!DivisionByZeroError`. The error can be " +"thrown using `raise e` where `e` is an instance of `E` which can be " +"constructed using the default constructor of `S`." +msgstr "" +"要使用 `DivisionByZeroError` 类型,我们通常会定义一个函数,该函数通过在签名中定义返回类型为 `T ! E` " +"来表示它会引发错误,其中 `T` 是实际的返回类型,`E` 是错误类型。在这个例子中,它是 " +"`Int!DivisionByZeroError`。错误可以使用 `raise e` 抛出,其中 `e` 是 `E` 的实例,可以使用 `S` " +"的默认构造函数构造。" + +#: ../../language/error-handling.md:47 +msgid "" +"Any instance of an error is a second class object. Meaning it may only " +"appear in the return value. And if it does appear, the function signature" +" has to be adjusted to match with the return type." +msgstr "任何错误的实例都是一个二等公民对象。这意味着它只能出现在返回值中。如果返回值包含错误,函数签名必须调整以匹配返回类型。" + +#: ../../language/error-handling.md:51 +msgid "" +"The `test` block in MoonBit may also be seen as a function, with a return" +" type of Unit!Error." +msgstr "MoonBit 中的 `test` 块也可以看作是一个函数,返回类型为 Unit!Error。" + +#: ../../language/error-handling.md:54 +msgid "Calling an error-able function" +msgstr "调用一个可出错的函数" + +#: ../../language/error-handling.md:56 +msgid "" +"an error-able function is usually called in 2 manners: `f!(...)` and " +"`f?(...)`." +msgstr "一个可出错的函数通常有两种调用方式:`f!(...)` 和 `f?(...)`。" + +#: ../../language/error-handling.md:58 +msgid "As-is calling" +msgstr "直接调用" + +#: ../../language/error-handling.md:60 +msgid "" +"`f!(...)` calls the function directly. The possible error must be dealt " +"in the function that calls `f`. We can either re-raising it without " +"actually dealing with the error:" +msgstr "`f!(...)` 直接调用函数。可能的错误必须在调用 `f` 的函数中处理。我们可以重新抛出它,而不实际处理错误:" + +#: ../../language/error-handling.md:64 +msgid "" +"// We have to match the error type of `div2` with `div`\n" +"fn div2(x : Int, y : Int) -> Int!DivisionByZeroError {\n" +" div!(x,y)\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:71 +msgid "or use `try...catch` block like in many other languages:" +msgstr "或者像其他许多语言一样使用 `try...catch` 块:" + +#: ../../language/error-handling.md:73 +msgid "" +"fn div3(x : Int, y : Int) -> Unit {\n" +" try {\n" +" div!(x, y)\n" +" } catch { // `catch` and `except` works the same.\n" +" DivisionByZeroError(e) => println(\"inf: \\{e}\")\n" +" } else {\n" +" v => println(v)\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:85 +msgid "" +"The `catch...` clause has similar semantics like pattern matching. We can" +" unwrap the error to retrieve the underlying `String` and print it. " +"Additionally, there's an `else` clause to handle the value of `try...` " +"block." +msgstr "" +"`catch...` 子句的语义类似于模式匹配。我们可以解包错误以检索底层的 `String` 并打印它。此外,还有一个 `else` 子句来处理" +" `try...` 块的值。" + +#: ../../language/error-handling.md:89 +msgid "" +"fn test_try() -> Result[Int, Error] {\n" +" // compiler can figure out the type of a local error-able function.\n" +" fn f() -> _!_ {\n" +" raise Failure(\"err\")\n" +" }\n" +"\n" +" try Ok(f!()) { err => Err(err) }\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:100 +msgid "" +"Curly braces may be omitted if the body of try is a one-liner " +"(expression). The `catch` keyword can also be omitted as well. In the " +"case where a `try` body would raise different errors, the special " +"`catch!` can be used to catch some of the errors, while re-raising other " +"uncaught errors:" +msgstr "" +"如果 `try` 的主体是一行代码(表达式),则大括号可以省略。`catch` 关键字也可以省略。在 `try` " +"主体可能引发不同错误的情况下,可以使用特殊的 `catch!` 来捕获一些错误,同时重新抛出其他未捕获的错误:" + +#: ../../language/error-handling.md:104 +msgid "" +"type! E1\n" +"type! E2\n" +"fn f1() -> Unit!E1 { raise E1 }\n" +"fn f2() -> Unit!E2 { raise E2 }\n" +"fn f() -> Unit! {\n" +" try {\n" +" f1!()\n" +" f2!()\n" +" } catch! {\n" +" E1 => println(\"E1\")\n" +" // E2 gets re-raised.\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:120 +msgid "Convert to Result" +msgstr "转换为 Result" + +#: ../../language/error-handling.md:122 +msgid "Extracting values" +msgstr "提取值" + +#: ../../language/error-handling.md:124 +msgid "" +"A object of type `Result` is a first class value in MoonBit. `Result` has" +" 2 constructors: `Ok(...)` and `Err(...)` where the former accept a first" +" class object and the latter accept a error object." +msgstr "" +"`Result` 类型的对象是 MoonBit 中的一等公民。`Result` 有 2 个构造器:`Ok(...)` 和 " +"`Err(...)`,前者接受一个一等公民对象,后者接受一个错误对象。" + +#: ../../language/error-handling.md:126 +msgid "" +"With `f?(...)`, the return type `T!E` is turned into `Result[T,E]`. We " +"may use pattern matching to extract value from it:" +msgstr "使用 `f?(...)`,返回类型 `T!E` 被转换为 `Result[T,E]`。我们可以使用模式匹配从中提取值:" + +#: ../../language/error-handling.md:128 +msgid "" +"let res = div?(10, 0)\n" +"match res {\n" +" Ok(x) => println(x)\n" +" Err(DivisionByZeroError(e)) => println(e)\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:136 +msgid "the `f?()` is basically a syntactic sugar for" +msgstr "`f?()` 基本上是一个语法糖,等价于" + +#: ../../language/error-handling.md:138 +msgid "" +"let res = try {\n" +" Ok(div!(10, 0))\n" +"} catch {\n" +" s => Err(s)\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:146 +msgid "" +"Note the difference between `T?` and `f?(...)`: `T` is a type and `T?` is" +" equivalent to `Option[T]` whereas `f?(...)` is a call to an error-able " +"function `f`." +msgstr "" +"注意 `T?` 和 `f?(...)` 之间的区别:`T` 是一个类型,`T?` 等价于 `Option[T]`,而 `f?(...)` " +"是对可出错函数 `f` 的调用。" + +#: ../../language/error-handling.md:150 +msgid "" +"Besides pattern matching, `Result` provides some useful methods to deal " +"with possible error:" +msgstr "除了模式匹配,`Result` 还提供了一些有用的方法来处理可能的错误:" + +#: ../../language/error-handling.md:152 +msgid "" +"let res1: Result[Int, String] = Err(\"error\")\n" +"let value = res1.or(0) // 0\n" +"\n" +"let res2: Result[Int, String] = Ok(42)\n" +"let value = res2.unwrap() // 42\n" +msgstr "" + +#: ../../language/error-handling.md:160 +msgid "" +"`or` returns the value if the result is `Ok` or a default value if it is " +"`Err`" +msgstr "`or` 如果结果是 `Ok`,则返回值,如果是 `Err`,则返回默认值" + +#: ../../language/error-handling.md:161 +msgid "`unwrap` panics if the result is `Err` and return the value if it is `Ok`" +msgstr "`unwrap` 如果结果是 `Err`,则会崩溃,如果是 `Ok`,则返回值" + +#: ../../language/error-handling.md:163 +msgid "Mapping values" +msgstr "映射值" + +#: ../../language/error-handling.md:165 +msgid "" +"let res1: Result[Int, String] = Ok(42)\n" +"let new_result = res1.map(fn(x) { x + 1 }) // Ok(43)\n" +"\n" +"let res2: Result[Int, String] = Err(\"error\")\n" +"let new_result = res2.map_err(fn(x) { x + \"!\" }) // Err(\"error!\")\n" +msgstr "" + +#: ../../language/error-handling.md:173 +msgid "" +"`map` applies a function to the value within, except it doesn't nothing " +"if result is `Err`." +msgstr "`map` 将函数应用于内部的值;如果结果是 `Err`,则不执行任何操作。" + +#: ../../language/error-handling.md:174 +msgid "`map_error` does the opposite." +msgstr "`map_error` 则相反。" + +#: ../../language/error-handling.md:176 +msgid "" +"Unlike some languages, MoonBit treats error-able and nullable value " +"differently. Although one might treat them analogously, as an `Err` " +"result contains no value, only the error, which is like `null`. MoonBit " +"knows that." +msgstr "" +"与一些语言不同,MoonBit 对可出错值和可空值进行了区分。尽管有些人可能将它们类比对待,因为一个不包含值的 `Err` 对象就像 " +"`null`。MoonBit 知道这一点。" + +#: ../../language/error-handling.md:178 +msgid "`to_option` converts a `Result` to `Option`." +msgstr "`to_option` 将 `Result` 转换为 `Option`。" + +#: ../../language/error-handling.md:180 +msgid "" +"let res1: Result[Int, String] = Ok(42)\n" +"let option = res1.to_option() // Some(42)\n" +"\n" +"let res2: Result[Int, String] = Err(\"error\")\n" +"let option1 = res2.to_option() // None\n" +msgstr "" + +#: ../../language/error-handling.md:188 +msgid "Built-in error type and functions" +msgstr "内置错误类型和相关函数" + +#: ../../language/error-handling.md:190 +msgid "In MoonBit, `Error` is a generalized error type:" +msgstr "在 MoonBit 中,`Error` 是一个通用的错误类型:" + +#: ../../language/error-handling.md:192 +msgid "" +"// These signatures are equivalent. They all raise Error.\n" +"fn f() -> Unit! { .. }\n" +"fn f!() -> Unit { .. }\n" +"fn f() -> Unit!Error { .. }\n" +"\n" +"fn test_error() -> Result[Int, Error] {\n" +" fn f() -> _!_ {\n" +" raise DivisionByZeroError(\"err\")\n" +" }\n" +"\n" +" try {\n" +" Ok(f!())\n" +" } catch {\n" +" err => Err(err)\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:211 +msgid "" +"Although the constructor `Err` expects a type of `Error`, we may still " +"pass an error of type `DivisionByZeroError` to it." +msgstr "尽管构造函数 `Err` 期望一个 `Error` 类型,我们仍然可以将 `DivisionByZeroError` 类型的错误传递给它。" + +#: ../../language/error-handling.md:214 +msgid "" +"But `Error` can't be constructed directly. It's meant to be passed " +"around, not used directly:" +msgstr "但是 `Error` 不能直接构造。它是用来传递的,而不是直接使用:" + +#: ../../language/error-handling.md:216 +msgid "" +"type! ArithmeticError\n" +"\n" +"fn what_error_is_this(e : Error) -> Unit {\n" +" match e {\n" +" DivisionByZeroError(_) => println(\"DivisionByZeroError\")\n" +" ArithmeticError => println(\"ArithmeticError\")\n" +" ... => println(\"...\")\n" +" _ => println(\"Error\")\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:229 +msgid "" +"`Error` is typically used where concrete error type is not needed, or " +"simply act as a catch-all for all kinds of sub-errors." +msgstr "`Error` 通常用于不需要具体错误类型的情况,或者简单地用来捕获所有的子错误。" + +#: ../../language/error-handling.md:232 +msgid "" +"As `Error` includes multiple error types, partial matching is not allowed" +" here. We have to do exhaustive matching by providing a catch-" +"all/wildcard case `_`." +msgstr "由于 `Error` 包含多种错误类型,这里不允许部分匹配。我们必须通过提供一个通配符 `_` 来进行兜底匹配。" + +#: ../../language/error-handling.md:234 +msgid "" +"We usually use the builtin `Failure` error type for a generalized error, " +"and by generalized we mean using it for trivial errors that doesn't need " +"a new error type." +msgstr "我们通常使用内置的 `Failure` 错误类型来表示通用错误:通用意味着它用于不值得单独定义类型的错误。" + +#: ../../language/error-handling.md:237 +msgid "" +"fn div_trivial(x : Int, y : Int) -> Int!Failure {\n" +" if y == 0 {\n" +" raise Failure(\"division by zero\")\n" +" }\n" +" x / y\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:246 +msgid "" +"Besides using the constructor directly, the function `fail!` provides a " +"shorthand to construct a `Failure`. And if we take a look at the source " +"code:" +msgstr "除了直接使用构造函数,函数 `fail!` 提供了一个快捷方式来构造 `Failure`。如果我们查看源代码:" + +#: ../../language/error-handling.md:249 +msgid "" +"pub fn fail[T](msg : String, ~loc : SourceLoc = _) -> T!Failure {\n" +" raise Failure(\"FAILED: \\{loc} \\{msg}\")\n" +"}\n" +msgstr "" + +#: ../../language/error-handling.md:255 +msgid "" +"We can see that `fail` is merely a constructor with a pre-defined output " +"template for showing both the error and the source location. In practice," +" `fail!` is always preferred over `Failure`." +msgstr "我们可以看到 `fail` 只是一个带有预定义输出模板的构造函数,用于显示错误和源位置。在实践中,`fail!` 总是比 `Failure`更常用。" + +#: ../../language/error-handling.md:259 +msgid "" +"Other functions used to break control flow are `abort` and `panic`. They " +"are equivalent. An `panic` at any place will manually crash the program " +"at that place, and prints out stack trace." +msgstr "" +"其他用于打破控制流的函数有 `abort` 和 `panic`。它们是等效的。在任何地方的 `panic` " +"都会手动在那个地方崩溃程序,并打印出堆栈跟踪。" + +#: ../../language/ffi-and-wasm-host.md:1 +msgid "Foreign Function Interface(FFI)" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:3 +msgid "" +"You can use foreign function in MoonBit through FFI to interact with the " +"hosting runtime when embedded inside the browser or command line " +"applications through [Wasmtime](https://wasmtime.dev/) or similar " +"projects." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:5 +msgid "" +"⚠ Warning: MoonBit is still in early stage, so the content may be " +"outdated." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:7 +msgid "FFI" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:9 +msgid "Declare Foreign Reference" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:11 +msgid "You can declare a foreign reference type like this:" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:13 +msgid "type Canvas_ctx\n" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:17 +msgid "" +"This will be a type that represents a reference to a foreign object, a " +"`CanvasRenderingContext2D` object held by the hosting JavaScript runtime " +"in this example." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:19 +msgid "Declare Foreign Function" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:21 +msgid "You can declare a foreign function like this:" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:23 +msgid "fn cos(d : Double) -> Double = \"Math\" \"cos\"\n" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:27 +msgid "" +"It's similar to a normal function definition except that the function " +"body is replaced with two strings." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:29 +msgid "" +"For WasmGC backend, these two strings are used to identify the specific " +"function from a Wasm import object, the first string is the module name, " +"and the second string is the function name. For JS backend, these two " +"strings are used to call a static function in the global namespace. The " +"example above becomes similar to `const cos = (d) => Math.cos(d)`." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:31 +msgid "" +"You can also declare inline functions where the function body is replaced" +" with one string." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:33 +msgid "" +"For WasmGC backend, you may declare it as a Wasm function without name " +"(which will be generated afterwards):" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:35 +msgid "" +"extern \"wasm\" fn abs(d : Double) -> Double =\n" +" #|(func (param f64) (result f64))\n" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:40 +msgid "and for JS backend, you may declare it as a lambda expression:" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:42 +msgid "" +"extern \"js\" fn abs(d : Double) -> Double =\n" +" #|(d) => Math.abs(d)\n" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:47 +msgid "After declaration, you can use foreign functions like regular functions." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:49 +msgid "" +"For multi-backend project, you may implement backend specific code in the" +" files that ends with `.wasm.mbt` `.wasm-gc.mbt` and `.js.mbt`." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:51 +msgid "" +"You may also declare a foreign function that will be invoked upon a " +"foreign object by using the foreign reference type like this:" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:53 +msgid "fn begin_path(self: Canvas_ctx) = \"canvas\" \"begin_path\"\n" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:57 +msgid "" +"and apply it to a previously owned reference normally such as " +"`context.begin_path()`." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:59 +msgid "Exported functions" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:61 +msgid "" +"Functions that are not methods nor polymorphic functions can be exported " +"if they are public and if the link configuration appears in the " +"`moon.pkg.json` of the package:" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:63 +msgid "" +"{\n" +" \"link\": {\n" +" \"wasm\": {\n" +" \"exports\": [\n" +" \"add\",\n" +" \"fib:test\"\n" +" ]\n" +" },\n" +" \"wasm-gc\": {\n" +" \"exports\": [\n" +" \"add\",\n" +" \"fib:test\"\n" +" ]\n" +" },\n" +" \"js\": {\n" +" \"exports\": [\n" +" \"add\",\n" +" \"fib:test\"\n" +" ],\n" +" \"format\": \"esm\"\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:89 +msgid "" +"Each backend has a separate definition. For JS backend, a `format` option" +" is used to specify whether the generated JavaScript file should be " +"released as an ES Module (`esm`), a CommonJS module (`cjs`), or an " +"immediately invoked function expression (`iife`)." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:91 +msgid "" +"The example above will export function `add` and `fib`, and the function " +"`fib` will be exported with the name of `test`." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:93 +msgid "" +"For WasmGC backend, the `_start` function should always be called to " +"initialize all the global instances defined in MoonBit program." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:95 +msgid "Use compiled Wasm" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:97 +msgid "" +"To use the compiled Wasm, you need to initialize the Wasm module with the" +" host functions so as to meet the needs of the foreign functions, and " +"then use the exported functions provided by the Wasm module." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:99 +msgid "Provide host functions" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:101 +msgid "" +"To use the compiled Wasm, you must provide **All** declared foreign " +"functions in Wasm import object." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:103 +msgid "For example, to use wasm compiled from above code snippet in JavaScript:" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:105 +msgid "" +"WebAssembly.instantiateStreaming(fetch(\"xxx.wasm\"), {\n" +" Math: {\n" +" cos: (d) => Math.cos(d),\n" +" },\n" +"});\n" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:113 +msgid "" +"Check out the documentation such as [MDN](https://developer.mozilla.org" +"/en-US/docs/WebAssembly) or the manual of runtime that you're using to " +"embed the Wasm." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:115 +msgid "Example: Smiling face" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:117 +msgid "" +"Let's walk through a full example to draw a smiling face using Canvas API" +" in MoonBit. Suppose you created a new project with `moon new draw`" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:119 +msgid "" +"// We first declare a type representing the context of canvas\n" +"type Canvas_ctx\n" +"\n" +"// We then declare the foreign function interfaces\n" +"fn begin_path(self : Canvas_ctx) = \"canvas\" \"beginPath\"\n" +"fn arc(self : Canvas_ctx, x : Int, y : Int, radius : Int, start_angle : " +"Double,\n" +" end_angle : Double, counterclockwise : Bool) = \"canvas\" \"arc\"\n" +"fn move_to(self : Canvas_ctx, x : Int, y : Int) = \"canvas\" \"moveTo\"\n" +"fn stroke(self : Canvas_ctx) = \"canvas\" \"stroke\"\n" +"\n" +"fn get_pi() -> Double = \"math\" \"PI\"\n" +"let pi : Double = get_pi()\n" +"\n" +"// We then apply these functions to define the drawing function upon the " +"context\n" +"pub fn draw(self : Canvas_ctx) -> Unit {\n" +" self.begin_path()\n" +" self.arc(75, 75, 50, 0.0, pi * 2.0, true) // Outer circle\n" +" self.move_to(110, 75)\n" +" self.arc(75, 75, 35, 0.0, pi, false) // Mouth (clockwise)\n" +" self.move_to(65, 65)\n" +" self.arc(60, 65, 5, 0.0, pi * 2.0, true) // Left eye\n" +" self.move_to(95, 65)\n" +" self.arc(90, 65, 5, 0.0, pi * 2.0, true) // Right eye\n" +" self.stroke()\n" +"}\n" +"\n" +"// We also demonstrate the `println` functionality here\n" +"pub fn display_pi() -> Unit {\n" +" println(\"PI: \\{pi}\")\n" +"}\n" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:152 +msgid "" +"{\n" +" \"link\": {\n" +" \"wasm\": {\n" +" \"exports\": [\"draw\", \"display_pi\"]\n" +" },\n" +" \"wasm-gc\": {\n" +" \"exports\": [\"draw\", \"display_pi\"]\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:165 +msgid "" +"Build the project using `moon build`. We recommend using Wasm with GC " +"integration whenever possible (which is the default). If the environment " +"does not support the GC feature, use the `--target wasm` option instead." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:167 +msgid "We now can use it from JavaScript." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:169 +msgid "" +"\n" +" \n" +" \n" +" \n" +" \n" +"\n" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:198 +msgid "" +"For import object, we need to provide all the FFI used in the previously " +"defined program: the canvas rendering API, the math API and finally, an " +"API for printing to the console used by the `println` or `print` " +"function." +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:200 +msgid "" +"As of the canvas rendering API and the math API, we can use the following" +" code to convert the methods of objects into function calls that accept " +"the object as the first parameter, and convert the constant properties of" +" objects into functions that returns the value:" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:202 +msgid "" +"function prototype_to_ffi(prototype) {\n" +" return Object.fromEntries(\n" +" Object.entries(Object.getOwnPropertyDescriptors(prototype))\n" +" .filter(([_key, value]) => value.value)\n" +" .map(([key, value]) => {\n" +" if (typeof value.value == 'function')\n" +" return [key, Function.prototype.call.bind(value.value)]\n" +" // TODO: it is also possible to convert properties into getters " +"and setters\n" +" else\n" +" return [key, () => value.value]\n" +" })\n" +" );\n" +"}\n" +"\n" +"const importObject = {\n" +" canvas: prototype_to_ffi(CanvasRenderingContext2D.prototype),\n" +" math: prototype_to_ffi(Math),\n" +" // ...\n" +"}\n" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:224 +msgid "" +"As of the printing service, we can provide the following closure so that " +"it buffers the bytes of string until it needs to be logged to the " +"console:" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:226 +msgid "" +"const [log, flush] = (() => {\n" +" var buffer = [];\n" +" function flush() {\n" +" if (buffer.length > 0) {\n" +" console.log(new TextDecoder(\"utf-16\").decode(new " +"Uint16Array(buffer).valueOf()));\n" +" buffer = [];\n" +" }\n" +" }\n" +" function log(ch) {\n" +" if (ch == '\\n'.charCodeAt(0)) { flush(); }\n" +" else if (ch == '\\r'.charCodeAt(0)) { /* noop */ }\n" +" else { buffer.push(ch); }\n" +" }\n" +" return [log, flush]\n" +"})();\n" +"\n" +"const importObject = {\n" +" // ...\n" +" spectest: {\n" +" print_char: log\n" +" },\n" +"}\n" +"\n" +"// ...\n" +"WebAssembly.instantiateStreaming(fetch(\"target/wasm-" +"gc/release/build/lib/lib.wasm\"), importObject).then(\n" +" (obj) => {\n" +" obj.instance.exports._start();\n" +" // ...\n" +" flush()\n" +" }\n" +");\n" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:260 +msgid "Now, we put them together, so this is our final complete `index.html`:" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:262 +msgid "" +"\n" +"\n" +"\n" +"\n" +"\n" +"\n" +" \n" +" \n" +"\n" +"\n" +"\n" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:328 +msgid "" +"Make sure that `draw.wasm` and `index.html` are in the same folder, then " +"start a http server at this folder. For example, using Python:" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:330 +msgid "python3 -m http.server 8080\n" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:334 +msgid "" +"Goto [http://localhost:8080](http://localhost:8080) in your browser, " +"there should be a smile face on the screen and an output on the console:" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:336 +msgid "" +"![A smile face webpage with browser devtools " +"open](../imgs/smile_face_with_log.png)" +msgstr "" + +#: ../../language/ffi-and-wasm-host.md:336 +msgid "A smile face webpage with browser devtools open" +msgstr "" + +#: ../../language/index.md:9 +msgid "Contents:" +msgstr "" + +#: ../../language/index.md:1 +msgid "Language" +msgstr "" + +#: ../../language/index.md:3 +msgid "Here are the topics about the programming syntax." +msgstr "" + +#: ../../language/index.md:5 +msgid "" +"[MoonBit](./language.md): almost everything you need to know about the " +"MoonBit grammar." +msgstr "" + +#: ../../language/index.md:6 +msgid "" +"[Error handling](./error-handling.md): the error handling mechanism in " +"MoonBit." +msgstr "" + +#: ../../language/index.md:7 +msgid "" +"[Foreign Function Interface](./ffi-and-wasm-host.md): how MoonBit " +"interacts with the real world using different backends." +msgstr "" + +#: ../../language/language.md:1 +msgid "MoonBit" +msgstr "" + +#: ../../language/language.md:3 +msgid "" +"MoonBit is an end-to-end programming language toolchain for cloud and " +"edge computing using WebAssembly. The IDE environment is available at " +"[https://try.moonbitlang.com](https://try.moonbitlang.com) without any " +"installation; it does not rely on any server either." +msgstr "" + +#: ../../language/language.md:5 +msgid "Status and aimed timeline" +msgstr "" + +#: ../../language/language.md:7 +msgid "" +"MoonBit is currently in beta-preview. We expect to reach beta in " +"2024/11/22, and 1.0 in 2025." +msgstr "" + +#: ../../language/language.md:9 +msgid "" +"When MoonBit reaches beta, it means any backwards-incompatible changes " +"will be seriously evaluated and MoonBit _can_ be used in production(very " +"rare compiler bugs). MoonBit is developed by a talented full time team " +"who had extensive experience in building language toolchains, so we will " +"grow much faster than the typical language ecosystem, you won't wait long" +" to use MoonBit in your production." +msgstr "" + +#: ../../language/language.md:11 +msgid "Main advantages" +msgstr "" + +#: ../../language/language.md:13 +msgid "Generate significantly smaller WASM output than any existing solutions." +msgstr "" + +#: ../../language/language.md:14 +msgid "Much faster runtime performance." +msgstr "" + +#: ../../language/language.md:15 +msgid "State of the art compile-time performance." +msgstr "" + +#: ../../language/language.md:16 +msgid "Simple but practical, data-oriented language design." +msgstr "" + +#: ../../language/language.md:18 +msgid "Overview" +msgstr "" + +#: ../../language/language.md:20 +msgid "" +"A MoonBit program consists of type definitions, function definitions, and" +" variable bindings." +msgstr "" + +#: ../../language/language.md:22 +msgid "Program entrance" +msgstr "" + +#: ../../language/language.md:24 +msgid "" +"There is a specialized function called `init` function. The `init` " +"function is special in two aspects:" +msgstr "" + +#: ../../language/language.md:26 +msgid "There can be multiple `init` functions in the same package." +msgstr "" + +#: ../../language/language.md:27 +msgid "" +"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." +msgstr "" + +#: ../../language/language.md:29 +msgid "" +"fn main {\n" +" let x = 1\n" +" // x // fail\n" +" println(x) // success\n" +"}\n" +msgstr "" + +#: ../../language/language.md:37 +msgid "" +"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." +msgstr "" + +#: ../../language/language.md:40 +msgid "" +"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. Only packages that are `main` packages " +"can define such `main` function. Check out [build system " +"tutorial](https://moonbitlang.github.io/moon/) for detail." +msgstr "" + +#: ../../language/language.md:43 +msgid "" +"The two functions above need to drop the parameter list and the return " +"type." +msgstr "" + +#: ../../language/language.md:45 +msgid "Expressions and Statements" +msgstr "" + +#: ../../language/language.md:47 +msgid "" +"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:" +msgstr "" + +#: ../../language/language.md:49 +msgid "" +"fn foo() -> Int {\n" +" let x = 1\n" +" x + 1 // OK\n" +"}\n" +"\n" +"fn bar() -> Int {\n" +" let x = 1\n" +" x + 1 // fail\n" +" x + 2\n" +"}\n" +msgstr "" + +#: ../../language/language.md:62 +msgid "Expressions include:" +msgstr "" + +#: ../../language/language.md:64 +msgid "" +"Value literals (e.g. Boolean values, numbers, characters, strings, " +"arrays, tuples, structs)" +msgstr "" + +#: ../../language/language.md:65 +msgid "Arithmetical, logical, or comparison operations" +msgstr "" + +#: ../../language/language.md:66 +msgid "" +"Accesses to array elements (e.g. `a[0]`) or struct fields (e.g `r.x`) or " +"tuple components (e.g. `t.0`)" +msgstr "" + +#: ../../language/language.md:67 +msgid "Variables and (capitalized) enum constructors" +msgstr "" + +#: ../../language/language.md:68 +msgid "Anonymous local function definitions" +msgstr "" + +#: ../../language/language.md:69 +msgid "`match` and `if` expressions" +msgstr "" + +#: ../../language/language.md:71 +msgid "Statements include:" +msgstr "" + +#: ../../language/language.md:73 +msgid "Named local function definitions" +msgstr "" + +#: ../../language/language.md:74 +msgid "Local variable bindings" +msgstr "" + +#: ../../language/language.md:75 +msgid "Assignments" +msgstr "" + +#: ../../language/language.md:76 +msgid "`return` statements" +msgstr "" + +#: ../../language/language.md:77 +msgid "Any expression whose return type is `Unit`" +msgstr "" + +#: ../../language/language.md:79 +msgid "Functions" +msgstr "" + +#: ../../language/language.md:81 +msgid "" +"Functions take arguments and produce a result. In MoonBit, functions are " +"first-class, which means that functions can be arguments or return values" +" of other functions. MoonBit's naming convention requires that function " +"names should not begin with uppercase letters (A-Z). Compare for " +"constructors in the `enum` section below." +msgstr "" + +#: ../../language/language.md:83 +msgid "Top-Level Functions" +msgstr "" + +#: ../../language/language.md:85 +msgid "" +"Functions can be defined as top-level or local. We can use the `fn` " +"keyword to define a top-level function that sums three integers and " +"returns the result, as follows:" +msgstr "" + +#: ../../language/language.md:87 +msgid "" +"fn add3(x: Int, y: Int, z: Int)-> Int {\n" +" x + y + z\n" +"}\n" +msgstr "" + +#: ../../language/language.md:93 +msgid "" +"Note that the arguments and return value of top-level functions require " +"explicit type annotations." +msgstr "" + +#: ../../language/language.md:95 +msgid "Local Functions" +msgstr "" + +#: ../../language/language.md:97 +msgid "" +"Local functions can be named or anonymous. Type annotations can be " +"omitted for local function definitions: they can be automatically " +"inferred in most cases. For example:" +msgstr "" + +#: ../../language/language.md:99 +msgid "" +"fn foo() -> Int {\n" +" fn inc(x) { x + 1 } // named as `inc`\n" +" fn (x) { x + inc(2) } (6) // anonymous, instantly applied to integer " +"literal 6\n" +"}\n" +"\n" +"fn main {\n" +" println(foo())\n" +"}\n" +msgstr "" + +#: ../../language/language.md:110 +msgid "" +"Functions, whether named or anonymous, are _lexical closures_: any " +"identifiers without a local binding must refer to bindings from a " +"surrounding lexical scope. For example:" +msgstr "" + +#: ../../language/language.md:112 +msgid "" +"let y = 3\n" +"fn foo(x: Int) -> Unit {\n" +" fn inc() { x + 1 } // OK, will return x + 1\n" +" fn four() { y + 1 } // Ok, will return 4\n" +" println(inc())\n" +" println(four())\n" +"}\n" +"\n" +"fn main {\n" +" foo(2)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:126 +msgid "Function Applications" +msgstr "" + +#: ../../language/language.md:128 +msgid "A function can be applied to a list of arguments in parentheses:" +msgstr "" + +#: ../../language/language.md:130 +msgid "add3(1, 2, 7)\n" +msgstr "" + +#: ../../language/language.md:134 +msgid "" +"This works whether `add3` is a function defined with a name (as in the " +"previous example), or a variable bound to a function value, as shown " +"below:" +msgstr "" + +#: ../../language/language.md:136 +msgid "" +"fn main {\n" +" let add3 = fn(x, y, z) { x + y + z }\n" +" println(add3(1, 2, 7))\n" +"}\n" +msgstr "" + +#: ../../language/language.md:143 +msgid "" +"The expression `add3(1, 2, 7)` returns `10`. Any expression that " +"evaluates to a function value is applicable:" +msgstr "" + +#: ../../language/language.md:145 +msgid "" +"fn main {\n" +" let f = fn (x) { x + 1 }\n" +" let g = fn (x) { x + 2 }\n" +" println((if true { f } else { g })(3)) // OK\n" +"}\n" +msgstr "" + +#: ../../language/language.md:153 +msgid "Labelled arguments" +msgstr "" + +#: ../../language/language.md:155 +msgid "" +"Functions can declare labelled argument with the syntax `label~ : Type`. " +"`label` will also serve as parameter name inside function body:" +msgstr "" + +#: ../../language/language.md:157 +msgid "" +"fn labelled(arg1~ : Int, arg2~ : Int) -> Int {\n" +" arg1 + arg2\n" +"}\n" +msgstr "" + +#: ../../language/language.md:163 +msgid "" +"Labelled arguments can be supplied via the syntax `label=arg`. " +"`label=label` can be abbreviated as `label~`:" +msgstr "" + +#: ../../language/language.md:165 +msgid "" +"fn init {\n" +" let arg1 = 1\n" +" println(labelled(arg2=2, arg1~)) // 3\n" +"}\n" +msgstr "" + +#: ../../language/language.md:172 +msgid "" +"Labelled function can be supplied in any order. The evaluation order of " +"arguments is the same as the order of parameters in function declaration." +msgstr "" + +#: ../../language/language.md:174 +msgid "Optional arguments" +msgstr "" + +#: ../../language/language.md:176 +msgid "" +"A labelled argument can be made optional by supplying a default " +"expression with the syntax `label~ : Type = default_expr`. If this " +"argument is not supplied at call site, the default expression will be " +"used:" +msgstr "" + +#: ../../language/language.md:178 +msgid "" +"fn optional(opt~ : Int = 42) -> Int {\n" +" opt\n" +"}\n" +"\n" +"fn main {\n" +" println(optional()) // 42\n" +" println(optional(opt=0)) // 0\n" +"}\n" +msgstr "" + +#: ../../language/language.md:189 +msgid "" +"The default expression will be evaluated every time it is used. And the " +"side effect in the default expression, if any, will also be triggered. " +"For example:" +msgstr "" + +#: ../../language/language.md:191 +msgid "" +"fn incr(counter~ : Ref[Int] = { val: 0 }) -> Ref[Int] {\n" +" counter.val = counter.val + 1\n" +" counter\n" +"}\n" +"\n" +"fn main {\n" +" println(incr()) // 1\n" +" println(incr()) // still 1, since a new reference is created every time" +" default expression is used\n" +" let counter : Ref[Int] = { val: 0 }\n" +" println(incr(counter~)) // 1\n" +" println(incr(counter~)) // 2, since the same counter is used\n" +"}\n" +msgstr "" + +#: ../../language/language.md:206 +msgid "" +"If you want to share the result of default expression between different " +"function calls, you can lift the default expression to a toplevel `let` " +"declaration:" +msgstr "" + +#: ../../language/language.md:208 +msgid "" +"let default_counter : Ref[Int] = { val: 0 }\n" +"\n" +"fn incr(counter~ : Ref[Int] = default_counter) -> Int {\n" +" counter.val = counter.val + 1\n" +" counter.val\n" +"}\n" +"\n" +"fn main {\n" +" println(incr()) // 1\n" +" println(incr()) // 2\n" +"}\n" +msgstr "" + +#: ../../language/language.md:222 +msgid "" +"Default expression can depend on the value of previous arguments. For " +"example:" +msgstr "" + +#: ../../language/language.md:224 +msgid "" +"fn sub_array[X](xs : Array[X], offset~ : Int, len~ : Int = xs.length() - " +"offset) -> Array[X] {\n" +" ... // take a sub array of [xs], starting from [offset] with length " +"[len]\n" +"}\n" +"\n" +"fn init {\n" +" println(sub_array([1, 2, 3], offset=1)) // [2, 3]\n" +" println(sub_array([1, 2, 3], offset=1, len=1)) // [2]\n" +"}\n" +msgstr "" + +#: ../../language/language.md:235 +msgid "Automatically insert `Some` when supplying optional arguments" +msgstr "" + +#: ../../language/language.md:237 +msgid "" +"It is quite often optional arguments have type `T?` with `None` as " +"default value. In this case, passing the argument explicitly requires " +"wrapping a `Some`:" +msgstr "" + +#: ../../language/language.md:240 +msgid "" +"fn image(width~ : Int? = None, height~ : Int? = None) -> Image { ... }\n" +"fn main {\n" +" let img = image(width=Some(1920), height=Some(1080)) // ugly!\n" +" ...\n" +"}\n" +msgstr "" + +#: ../../language/language.md:248 +msgid "" +"Fortunately, MoonBit provides a special kind of optional arguments to " +"solve this problem. Optional arguments declared with `label? : T` has " +"type `T?` and `None` as default value. When supplying this kind of " +"optional argument directly, MoonBit will automatically insert a `Some`:" +msgstr "" + +#: ../../language/language.md:252 +msgid "" +"fn image(width? : Int, height? : Int) -> Image { ... }\n" +"fn main {\n" +" let img = image(width=1920, height=1080) // much better!\n" +" ...\n" +"}\n" +msgstr "" + +#: ../../language/language.md:260 +msgid "" +"Sometimes, it is also useful to pass a value of type `T?` directly, for " +"example when forwarding optional argument. MoonBit provides a syntax " +"`label?=value` for this, with `label?` being an abbreviation of " +"`label?=label`:" +msgstr "" + +#: ../../language/language.md:264 +msgid "" +"fn image(width? : Int, height? : Int) -> Image { ... }\n" +"fn fixed_width_image(height? : Int) -> Image {\n" +" image(width=1920, height?)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:271 +msgid "Autofill arguments" +msgstr "" + +#: ../../language/language.md:273 +msgid "" +"MoonBit supports filling specific types of arguments automatically at " +"different call site, such as the source location of a function call. To " +"declare an autofill argument, simply declare an optional argument with " +"`_` as default value. Now if the argument is not explicitly supplied, " +"MoonBit will automatically fill it at the call site." +msgstr "" + +#: ../../language/language.md:277 +msgid "" +"Currently MoonBit supports two types of autofill arguments, `SourceLoc`, " +"which is the source location of the whole function call, and `ArgsLoc`, " +"which is a array containing the source location of each argument, if any:" +msgstr "" + +#: ../../language/language.md:280 +msgid "" +"fn f(_x : Int, _y : Int, loc~ : SourceLoc = _, args_loc~ : ArgsLoc = _) " +"-> Unit {\n" +" println(\"loc of whole function call: \\{loc}\")\n" +" println(\"loc of arguments: \\{args_loc}\")\n" +"}\n" +"\n" +"fn main {\n" +" f(1, 2)\n" +" // loc of whole function call: :7:3-7:10\n" +" // loc of arguments: [Some(:7:5-7:6), " +"Some(:7:8-7:9), None, None]\n" +"}\n" +msgstr "" + +#: ../../language/language.md:293 +msgid "" +"Autofill arguments are very useful for writing debugging and testing " +"utilities." +msgstr "" + +#: ../../language/language.md:295 +msgid "Control Structures" +msgstr "" + +#: ../../language/language.md:297 +msgid "Conditional Expressions" +msgstr "" + +#: ../../language/language.md:299 +msgid "" +"A conditional expression consists of a condition, a consequent, and an " +"optional else clause." +msgstr "" + +#: ../../language/language.md:301 +msgid "" +"if x == y {\n" +" expr1\n" +"} else {\n" +" expr2\n" +"}\n" +"\n" +"if x == y {\n" +" expr1\n" +"}\n" +msgstr "" + +#: ../../language/language.md:313 +msgid "The else clause can also contain another if-else expression:" +msgstr "" + +#: ../../language/language.md:315 +msgid "" +"if x == y {\n" +" expr1\n" +"} else if z == k {\n" +" expr2\n" +"}\n" +msgstr "" + +#: ../../language/language.md:323 +msgid "" +"Curly brackets are used to group multiple expressions in the consequent " +"or the else clause." +msgstr "" + +#: ../../language/language.md:325 +msgid "" +"Note that a conditional expression always returns a value in MoonBit, and" +" the return values of the consequent and the else clause must be of the " +"same type. Here is an example:" +msgstr "" + +#: ../../language/language.md:327 +msgid "let initial = if size < 1 { 1 } else { size }\n" +msgstr "" + +#: ../../language/language.md:331 +msgid "While loop" +msgstr "" + +#: ../../language/language.md:333 +msgid "" +"In MoonBit, `while` loop can be used to execute a block of code " +"repeatedly as long as a condition is true. The condition is evaluated " +"before executing the block of code. The `while` loop is defined using the" +" `while` keyword, followed by a condition and the loop body. The loop " +"body is a sequence of statements. The loop body is executed as long as " +"the condition is true." +msgstr "" + +#: ../../language/language.md:335 +msgid "" +"let mut i = 5\n" +"while i > 0 {\n" +" println(i)\n" +" i = i - 1\n" +"}\n" +msgstr "" + +#: ../../language/language.md:343 +msgid "" +"The loop body supports `break` and `continue`. Using `break` allows you " +"to exit the current loop, while using `continue` skips the remaining part" +" of the current iteration and proceeds to the next iteration." +msgstr "" + +#: ../../language/language.md:345 +msgid "" +"fn main {\n" +" let mut i = 5\n" +" while i > 0 {\n" +" i = i - 1\n" +" if i == 4 { continue }\n" +" if i == 1 { break }\n" +" println(i)\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:357 +msgid "" +"The `while` loop also supports an optional `else` clause. When the loop " +"condition becomes false, the `else` clause will be executed, and then the" +" loop will end." +msgstr "" + +#: ../../language/language.md:359 +msgid "" +"fn main {\n" +" let mut i = 2\n" +" while i > 0 {\n" +" println(i)\n" +" i = i - 1\n" +" } else {\n" +" println(i)\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:371 +msgid "" +"When there is an `else` clause, the `while` loop can also return a value." +" The return value is the evaluation result of the `else` clause. In this " +"case, if you use `break` to exit the loop, you need to provide a return " +"value after `break`, which should be of the same type as the return value" +" of the `else` clause." +msgstr "" + +#: ../../language/language.md:373 +msgid "" +" let mut i = 10\n" +" let r1 =\n" +" while i > 0 {\n" +" i = i - 1\n" +" if i % 2 == 0 { break 5 } // break with 5\n" +" } else {\n" +" 7\n" +" }\n" +" println(r1) //output: 5\n" +msgstr "" + +#: ../../language/language.md:385 +msgid "" +" let mut i = 10\n" +" let r2 =\n" +" while i > 0 {\n" +" i = i - 1\n" +" } else {\n" +" 7\n" +" }\n" +" println(r2) //output: 7\n" +msgstr "" + +#: ../../language/language.md:396 +msgid "For Loop" +msgstr "" + +#: ../../language/language.md:398 +msgid "" +"MoonBit also supports C-style For loops. The keyword `for` is followed by" +" variable initialization clauses, loop conditions, and update clauses " +"separated by semicolons. They do not need to be enclosed in parentheses. " +"For example, the code below creates a new variable binding `i`, which has" +" a scope throughout the entire loop and is immutable. This makes it " +"easier to write clear code and reason about it:" +msgstr "" + +#: ../../language/language.md:401 +msgid "" +"for i = 0; i < 5; i = i + 1 {\n" +" println(i)\n" +"}\n" +"// output:\n" +"// 0\n" +"// 1\n" +"// 2\n" +msgstr "" + +#: ../../language/language.md:411 +msgid "The variable initialization clause can create multiple bindings:" +msgstr "" + +#: ../../language/language.md:413 +msgid "" +"for i = 0, j = 0; i + j < 100; i = i + 1, j = j + 1 {\n" +" println(i)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:419 +msgid "" +"It should be noted that in the update clause, when there are multiple " +"binding variables, the semantics are to update them simultaneously. In " +"other words, in the example above, the update clause does not execute `i " +"= i + 1`, `j = j + 1` sequentially, but rather increments `i` and `j` at " +"the same time. Therefore, when reading the values of the binding " +"variables in the update clause, you will always get the values updated in" +" the previous iteration." +msgstr "" + +#: ../../language/language.md:421 +msgid "" +"Variable initialization clauses, loop conditions, and update clauses are " +"all optional. For example, the following two are infinite loops:" +msgstr "" + +#: ../../language/language.md:423 +msgid "" +"for i=1;; i=i+1 {\n" +" println(i) // loop forever!\n" +"}\n" +msgstr "" + +#: ../../language/language.md:429 +msgid "" +"for {\n" +" println(\"loop forever!\")\n" +"}\n" +msgstr "" + +#: ../../language/language.md:435 +msgid "" +"The `for` loop also supports `continue`, `break`, and `else` clauses. " +"Like the `while` loop, the `for` loop can also return a value using the " +"`break` and `else` clauses." +msgstr "" + +#: ../../language/language.md:437 +msgid "" +"The `continue` statement skips the remaining part of the current " +"iteration of the `for` loop (including the update clause) and proceeds to" +" the next iteration. The `continue` statement can also update the binding" +" variables of the `for` loop, as long as it is followed by expressions " +"that match the number of binding variables, separated by commas." +msgstr "" + +#: ../../language/language.md:439 +msgid "" +"For example, the following program calculates the sum of even numbers " +"from 1 to 6:" +msgstr "" + +#: ../../language/language.md:441 +msgid "" +"fn main {\n" +" let sum =\n" +" for i = 1, acc = 0; i <= 6; i = i + 1 {\n" +" if i % 2 == 0 {\n" +" println(\"even: \\{i}\")\n" +" continue i + 1, acc + i\n" +" }\n" +" } else {\n" +" acc\n" +" }\n" +" println(sum)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:456 +msgid "`for .. in` loop" +msgstr "" + +#: ../../language/language.md:458 +msgid "" +"MoonBit supports traversing elements of different data structures and " +"sequences via the `for .. in` loop syntax:" +msgstr "" + +#: ../../language/language.md:460 +msgid "" +"for x in [ 1, 2, 3 ] {\n" +" println(x)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:466 +msgid "" +"`for .. in` loop is translated to the use of `Iter` in MoonBit's standard" +" library. Any type with a method `.iter() : Iter[T]` can be traversed " +"using `for .. in`. For more information of the `Iter` type, see " +"[Iterator](#iterator) below." +msgstr "" + +#: ../../language/language.md:469 +msgid "" +"In addition to sequences of a single value, MoonBit also supports " +"traversing sequences of two values, such as `Map`, via the `Iter2` type " +"in MoonBit's standard library. Any type with method `.iter2() : Iter2[A, " +"B]` can be traversed using `for .. in` with two loop variables:" +msgstr "" + +#: ../../language/language.md:472 +msgid "" +"for k, v in { \"x\": 1, \"y\": 2, \"z\": 3 } {\n" +" println(\"\\{k} => \\{v}\")\n" +"}\n" +msgstr "" + +#: ../../language/language.md:478 +msgid "" +"Another example of `for .. in` with two loop variables is traversing an " +"array while keeping track of array index:" +msgstr "" + +#: ../../language/language.md:480 +msgid "" +"for index, elem in [ 4, 5, 6 ] {\n" +" let i = index + 1\n" +" println(\"The \\{i}-th element of the array is \\{elem}\")\n" +"}\n" +msgstr "" + +#: ../../language/language.md:487 +msgid "" +"Control flow operations such as `return`, `break` and error handling are " +"supported in the body of `for .. in` loop:" +msgstr "" + +#: ../../language/language.md:489 +msgid "" +"test \"map test\" {\n" +" let map = { \"x\": 1, \"y\": 2, \"z\": 3 }\n" +" for k, v in map {\n" +" assert_eq!(map[k], Some(v))\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:498 +msgid "If a loop variable is unused, it can be ignored with `_`." +msgstr "" + +#: ../../language/language.md:500 +msgid "Functional loop" +msgstr "" + +#: ../../language/language.md:502 +msgid "" +"Functional loop is a powerful feature in MoonBit that enables you to " +"write loops in a functional style." +msgstr "" + +#: ../../language/language.md:504 +msgid "" +"A functional loop consumes arguments and returns a value. It is defined " +"using the `loop` keyword, followed by its arguments and the loop body. " +"The loop body is a sequence of clauses, each of which consists of a " +"pattern and an expression. The clause whose pattern matches the input " +"will be executed, and the loop will return the value of the expression. " +"If no pattern matches, the loop will panic. Use the `continue` keyword " +"with arguments to start the next iteration of the loop. Use the `break` " +"keyword with arguments to return a value from the loop. The `break` " +"keyword can be omitted if the value is the last expression in the loop " +"body." +msgstr "" + +#: ../../language/language.md:506 +msgid "" +"fn sum(xs: @immut/list.T[Int]) -> Int {\n" +" loop xs, 0 {\n" +" Nil, acc => break acc // break can be omitted\n" +" Cons(x, rest), acc => continue rest, x + acc\n" +" }\n" +"}\n" +"\n" +"fn main {\n" +" println(sum(Cons(1, Cons(2, Cons(3, Nil)))))\n" +"}\n" +msgstr "" + +#: ../../language/language.md:519 +msgid "Guard Statement" +msgstr "" + +#: ../../language/language.md:521 +msgid "" +"The `guard` statement is used to check a specified invariant. If the " +"condition of the invariant is satisfied, the program continues executing " +"the subsequent statements and returns. If the condition is not satisfied " +"(i.e., false), the code in the `else` block is executed and its " +"evaluation result is returned (the subsequent statements are skipped)." +msgstr "" + +#: ../../language/language.md:526 +msgid "" +"guard index >= 0 && index < len else {\n" +" abort(\"Index out of range\")\n" +"}\n" +msgstr "" + +#: ../../language/language.md:532 +msgid "" +"The `guard` statement also supports pattern matching: in the following " +"example, `getProcessedText` assumes that the input `path` points to " +"resources that are all plain text, and it uses the `guard` statement to " +"ensure this invariant. Compared to using a `match` statement, the " +"subsequent processing of `text` can have one less level of indentation." +msgstr "" + +#: ../../language/language.md:537 +msgid "" +"enum Resource {\n" +" Folder(Array[String])\n" +" PlainText(String)\n" +" JsonConfig(Json)\n" +"}\n" +"\n" +"fn getProcessedText(resources : Map[String, Resource], path : String) -> " +"String!Error {\n" +" guard let Some(PlainText(text)) = resources[path] else {\n" +" None => fail!(\"\\{path} not found\")\n" +" Some(Folder(_)) => fail!(\"\\{path} is a folder\")\n" +" Some(JsonConfig(_)) => fail!(\"\\{path} is a json config\")\n" +" }\n" +" ...\n" +" process(text)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:555 +msgid "" +"When the `else` part is omitted, the program terminates if the condition " +"specified in the `guard` statement is not true or cannot be matched." +msgstr "" + +#: ../../language/language.md:558 +msgid "" +"guard condition // equivalent to `guard condition else { panic() }`\n" +"guard let Some(x) = expr // equivalent to `guard let Some(x) = expr else " +"{ _ => panic() }`\n" +msgstr "" + +#: ../../language/language.md:563 +msgid "Iterator" +msgstr "" + +#: ../../language/language.md:565 +msgid "" +"An iterator is an object that traverse through a sequence while providing" +" access to its elements. Traditional OO languages like Java's " +"`Iterator` use `next()` `hasNext()` to step through the iteration " +"process, whereas functional languages (JavaScript's `forEach`, Lisp's " +"`mapcar`) provides a high-order function which takes an operation and a " +"sequence then consumes the sequence with that operation being applied to " +"the sequence. The former is called _external iterator_ (visible to user) " +"and the latter is called _internal iterator_ (invisible to user)." +msgstr "" + +#: ../../language/language.md:573 +msgid "" +"The built-in type `Iter[T]` is MoonBit's internal iterator " +"implementation. Almost all built-in sequential data structures have " +"implemented `Iter`:" +msgstr "" + +#: ../../language/language.md:576 +msgid "" +"fn filter_even(l : Array[Int]) -> Array[Int] {\n" +" let l_iter : Iter[Int] = l.iter()\n" +" l_iter.filter(fn { x => (x & 1) == 1 }).collect()\n" +"}\n" +"\n" +"fn fact(n : Int) -> Int {\n" +" let start = 1\n" +" start.until(n).fold(Int::op_mul, init=start)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:588 +msgid "Commonly used methods include:" +msgstr "" + +#: ../../language/language.md:590 +msgid "" +"`each`: Iterates over each element in the iterator, applying some " +"function to each element." +msgstr "" + +#: ../../language/language.md:591 +msgid "" +"`fold`: Folds the elements of the iterator using the given function, " +"starting with the given initial value." +msgstr "" + +#: ../../language/language.md:592 +msgid "`collect`: Collects the elements of the iterator into an array." +msgstr "" + +#: ../../language/language.md:594 +msgid "" +"`filter`: _lazy_ Filters the elements of the iterator based on a " +"predicate function." +msgstr "" + +#: ../../language/language.md:595 +msgid "" +"`map`: _lazy_ Transforms the elements of the iterator using a mapping " +"function." +msgstr "" + +#: ../../language/language.md:596 +msgid "" +"`concat`: _lazy_ Combines two iterators into one by appending the " +"elements of the second iterator to the first." +msgstr "" + +#: ../../language/language.md:598 +msgid "" +"Methods like `filter` `map` are very common on a sequence object e.g. " +"Array. But what makes `Iter` special is that any method that constructs a" +" new `Iter` is _lazy_ (i.e. iteration doesn't start on call because it's " +"wrapped inside a function), as a result of no allocation for intermediate" +" value. That's what makes `Iter` superior for traversing through " +"sequence: no extra cost. MoonBit encourages user to pass an `Iter` across" +" functions instead of the sequence object itself." +msgstr "" + +#: ../../language/language.md:606 +msgid "" +"Pre-defined sequence structures like `Array` and its iterators should be " +"enough to use. But to take advantages of these methods when used with a " +"custom sequence with elements of type `S`, we will need to implement " +"`Iter`, namely, a function that returns an `Iter[S]`. Take `Bytes` as an " +"example:" +msgstr "" + +#: ../../language/language.md:611 +msgid "" +"fn iter(data : Bytes) -> Iter[Byte] {\n" +" Iter::new(\n" +" fn(yield) {\n" +" // The code that actually does the iteration\n" +" /////////////////////////////////////////////\n" +" for i = 0, len = data.length(); i < len; i = i + 1 {\n" +" if yield(data[i]) == IterEnd {\n" +" break IterEnd\n" +" }\n" +" /////////////////////////////////////////////\n" +" } else {\n" +" IterContinue\n" +" }\n" +" },\n" +" )\n" +"}\n" +msgstr "" + +#: ../../language/language.md:630 +msgid "" +"Almost all `Iter` implementations are identical to that of `Bytes`, the " +"only main difference being the code block that actually does the " +"iteration." +msgstr "" + +#: ../../language/language.md:633 +msgid "Implementation details" +msgstr "" + +#: ../../language/language.md:635 +msgid "" +"The type `Iter[T]` is basically a type alias for `((T) -> IterResult) -> " +"IterResult`, a higher-order function that takes an operation and " +"`IterResult` is an enum object that tracks the state of current iteration" +" which consists any of the 2 states:" +msgstr "" + +#: ../../language/language.md:640 +msgid "`IterEnd`: marking the end of an iteration" +msgstr "" + +#: ../../language/language.md:641 +msgid "" +"`IterContinue`: marking the end of an iteration is yet to be reached, " +"implying the iteration will still continue at this state." +msgstr "" + +#: ../../language/language.md:643 +msgid "" +"To put it simply, `Iter[T]` takes a function `(T) -> IterResult` and use " +"it to transform `Iter[T]` itself to a new state of type `IterResult`. " +"Whether that state being `IterEnd` `IterContinue` depends on the " +"function." +msgstr "" + +#: ../../language/language.md:647 +msgid "" +"Iterator provides a unified way to iterate through data structures, and " +"they can be constructed at basically no cost: as long as `fn(yield)` " +"doesn't execute, the iteration process doesn't start." +msgstr "" + +#: ../../language/language.md:651 +msgid "" +"Internally a `Iter::run()` is used to trigger the iteration. Chaining all" +" sorts of `Iter` methods might be visually pleasing, but do notice the " +"heavy work underneath the abstraction." +msgstr "" + +#: ../../language/language.md:655 +msgid "" +"Thus, unlike an external iterator, once the iteration starts there's no " +"way to stop unless the end is reached. Methods such as `count()` which " +"counts the number of elements in a iterator looks like an `O(1)` " +"operation but actually has linear time complexity. Carefully use " +"iterators or performance issue might occur." +msgstr "" + +#: ../../language/language.md:661 +msgid "Built-in Data Structures" +msgstr "" + +#: ../../language/language.md:663 +msgid "Boolean" +msgstr "" + +#: ../../language/language.md:665 +msgid "" +"MoonBit has a built-in boolean type, which has two values: `true` and " +"`false`. The boolean type is used in conditional expressions and control " +"structures." +msgstr "" + +#: ../../language/language.md:667 +msgid "" +"let a = true\n" +"let b = false\n" +"let c = a && b\n" +"let d = a || b\n" +"let e = not(a)\n" +msgstr "" + +#: ../../language/language.md:675 +msgid "Number" +msgstr "" + +#: ../../language/language.md:677 +msgid "MoonBit have integer type and floating point type:" +msgstr "" + +#: ../../language/language.md +msgid "type" +msgstr "" + +#: ../../language/language.md +msgid "description" +msgstr "" + +#: ../../language/language.md +msgid "example" +msgstr "" + +#: ../../language/language.md +msgid "`Int`" +msgstr "" + +#: ../../language/language.md +msgid "32-bit signed integer" +msgstr "" + +#: ../../language/language.md +msgid "`42`" +msgstr "" + +#: ../../language/language.md +msgid "`Int64`" +msgstr "" + +#: ../../language/language.md +msgid "64-bit signed integer" +msgstr "" + +#: ../../language/language.md +msgid "`1000L`" +msgstr "" + +#: ../../language/language.md +msgid "`UInt`" +msgstr "" + +#: ../../language/language.md +msgid "32-bit unsigned integer" +msgstr "" + +#: ../../language/language.md +msgid "`14U`" +msgstr "" + +#: ../../language/language.md +msgid "`UInt64`" +msgstr "" + +#: ../../language/language.md +msgid "64-bit unsigned integer" +msgstr "" + +#: ../../language/language.md +msgid "`14UL`" +msgstr "" + +#: ../../language/language.md +msgid "`Double`" +msgstr "" + +#: ../../language/language.md +msgid "64-bit floating point, defined by IEEE754" +msgstr "" + +#: ../../language/language.md +msgid "`3.14`" +msgstr "" + +#: ../../language/language.md +msgid "`Float`" +msgstr "" + +#: ../../language/language.md +msgid "32-bit floating point" +msgstr "" + +#: ../../language/language.md +msgid "`(3.14 : Float)`" +msgstr "" + +#: ../../language/language.md +msgid "`BigInt`" +msgstr "" + +#: ../../language/language.md +msgid "represents numeric values larger than other types" +msgstr "" + +#: ../../language/language.md +msgid "`10000000000000000000000N`" +msgstr "" + +#: ../../language/language.md:689 +msgid "" +"MoonBit also supports numeric literals, including decimal, binary, octal," +" and hexadecimal numbers." +msgstr "" + +#: ../../language/language.md:691 +msgid "" +"To improve readability, you may place underscores in the middle of " +"numeric literals such as `1_000_000`. Note that underscores can be placed" +" anywhere within a number, not just every three digits." +msgstr "" + +#: ../../language/language.md:693 +msgid "There is nothing surprising about decimal numbers." +msgstr "" + +#: ../../language/language.md:695 +msgid "" +"let a = 1234\n" +"let b = 1_000_000 + a\n" +"let large_num = 9_223_372_036_854_775_807L // Integers of the Int64 type " +"must have an 'L' as a suffix\n" +"let unsigned_num = 4_294_967_295U // Integers of the UInt type must have " +"an 'U' suffix\n" +msgstr "" + +#: ../../language/language.md:702 +msgid "" +"A binary number has a leading zero followed by a letter \"B\", i.e. " +"`0b`/`0B`. Note that the digits after `0b`/`0B` must be `0` or `1`." +msgstr "" + +#: ../../language/language.md:705 +msgid "" +"let bin = 0b110010\n" +"let another_bin = 0B110010\n" +msgstr "" + +#: ../../language/language.md:710 +msgid "" +"An octal number has a leading zero followed by a letter \"O\", i.e. " +"`0o`/`0O`. Note that the digits after `0o`/`0O` must be in the range from" +" `0` through `7`:" +msgstr "" + +#: ../../language/language.md:713 +msgid "" +"let octal = 0o1234\n" +"let another_octal = 0O1234\n" +msgstr "" + +#: ../../language/language.md:718 +msgid "" +"A hexadecimal number has a leading zero followed by a letter \"X\", i.e. " +"`0x`/`0X`. Note that the digits after the `0x`/`0X` must be in the range " +"`0123456789ABCDEF`." +msgstr "" + +#: ../../language/language.md:721 +msgid "" +"let hex = 0XA\n" +"let another_hex = 0xA\n" +msgstr "" + +#: ../../language/language.md:726 +msgid "Overloaded int literal" +msgstr "" + +#: ../../language/language.md:728 +msgid "" +"When the expected type is known, MoonBit can automatically overload " +"integer literal, and there is no need to specify the type of number via " +"letter postfix:" +msgstr "" + +#: ../../language/language.md:730 +msgid "" +"let int : Int = 42\n" +"let uint : UInt = 42\n" +"let int64 : Int64 = 42\n" +"let double : Double = 42\n" +"let float : Float = 42\n" +"let bigint : BigInt = 42\n" +msgstr "" + +#: ../../language/language.md:739 +msgid "String" +msgstr "" + +#: ../../language/language.md:741 +msgid "" +"`String` holds a sequence of UTF-16 code units. You can use double quotes" +" to create a string, or use `#|` to write a multi-line string." +msgstr "" + +#: ../../language/language.md:743 +msgid "" +"let a = \"兔rabbit\"\n" +"println(a[0]) // output: 兔\n" +"println(a[1]) // output: r\n" +msgstr "" + +#: ../../language/language.md:749 +msgid "" +"let b =\n" +" #| Hello\n" +" #| MoonBit\n" +" #|\n" +msgstr "" + +#: ../../language/language.md:756 +msgid "" +"In double quotes string, a backslash followed by certain special " +"characters forms an escape sequence:" +msgstr "" + +#: ../../language/language.md +msgid "escape sequences" +msgstr "" + +#: ../../language/language.md +msgid "`\\n`,`\\r`,`\\t`,`\\b`" +msgstr "" + +#: ../../language/language.md +msgid "New line, Carriage return, Horizontal tab, Backspace" +msgstr "" + +#: ../../language/language.md +msgid "`\\\\`" +msgstr "" + +#: ../../language/language.md +msgid "Backslash" +msgstr "" + +#: ../../language/language.md +msgid "`\\x41`" +msgstr "" + +#: ../../language/language.md +msgid "Hexadecimal escape sequence" +msgstr "" + +#: ../../language/language.md +msgid "`\\o102`" +msgstr "" + +#: ../../language/language.md +msgid "Octal escape sequence" +msgstr "" + +#: ../../language/language.md +msgid "`\\u5154`,`\\u{1F600}`" +msgstr "" + +#: ../../language/language.md +msgid "Unicode escape sequence" +msgstr "" + +#: ../../language/language.md:766 +msgid "" +"MoonBit supports string interpolation. It enables you to substitute " +"variables within interpolated strings. This feature simplifies the " +"process of constructing dynamic strings by directly embedding variable " +"values into the text. Variables used for string interpolation must " +"support the `to_string` method." +msgstr "" + +#: ../../language/language.md:768 +msgid "" +"let x = 42\n" +"println(\"The answer is \\{x}\")\n" +msgstr "" + +#: ../../language/language.md:773 +msgid "" +"Multi-line strings do not support interpolation by default, but you can " +"enable interpolation for a specific line by changing the leading `#|` to " +"`$|`:" +msgstr "" + +#: ../../language/language.md:775 +msgid "" +"let lang = \"MoonBit\"\n" +"let str = \n" +" #| Hello\n" +" #| ---\n" +" $| \\{lang}\\n\n" +" #| ---\n" +"println(str)\n" +msgstr "" + +#: ../../language/language.md:785 +msgid "Output:" +msgstr "" + +#: ../../language/language.md:787 +msgid "" +" Hello\n" +" ---\n" +" MoonBit\n" +"\n" +" ---\n" +msgstr "" + +#: ../../language/language.md:795 +msgid "Char" +msgstr "" + +#: ../../language/language.md:797 +msgid "`Char` is an integer representing a Unicode code point." +msgstr "" + +#: ../../language/language.md:799 +msgid "" +"let a : Char = 'A'\n" +"let b = '\\x41'\n" +"let c = '兔'\n" +"let zero = '\\u{30}'\n" +"let zero = '\\u0030'\n" +msgstr "" + +#: ../../language/language.md:807 +msgid "Byte(s)" +msgstr "" + +#: ../../language/language.md:809 +msgid "" +"A byte literal in MoonBit is either a single ASCII character or a single " +"escape enclosed in single quotes `'`, and preceded by the character `b`. " +"Byte literals are of type `Byte`. For example:" +msgstr "" + +#: ../../language/language.md:811 +msgid "" +"fn main {\n" +" let b1 : Byte = b'a'\n" +" println(b1.to_int())\n" +" let b2 = b'\\xff'\n" +" println(b2.to_int())\n" +"}\n" +msgstr "" + +#: ../../language/language.md:820 +msgid "" +"A `Bytes` is a sequence of bytes. Similar to byte, bytes literals have " +"the form of `b\"...\"`. For example:" +msgstr "" + +#: ../../language/language.md:822 +msgid "" +"fn main {\n" +" let b1 : Bytes = b\"abcd\"\n" +" let b2 = b\"\\x61\\x62\\x63\\x64\"\n" +" println(b1 == b2) // true\n" +"}\n" +msgstr "" + +#: ../../language/language.md:830 +msgid "Tuple" +msgstr "" + +#: ../../language/language.md:832 +msgid "" +"A tuple is a collection of finite values constructed using round brackets" +" `()` with the elements separated by commas `,`. The order of elements " +"matters; for example, `(1,true)` and `(true,1)` have different types. " +"Here's an example:" +msgstr "" + +#: ../../language/language.md:834 +msgid "" +"fn pack(a: Bool, b: Int, c: String, d: Double) -> (Bool, Int, String, " +"Double) {\n" +" (a, b, c, d)\n" +"}\n" +"fn init {\n" +" let quad = pack(false, 100, \"text\", 3.14)\n" +" let (bool_val, int_val, str, float_val) = quad\n" +" println(\"\\{bool_val} \\{int_val} \\{str} \\{float_val}\")\n" +"}\n" +msgstr "" + +#: ../../language/language.md:845 +msgid "Tuples can be accessed via pattern matching or index:" +msgstr "" + +#: ../../language/language.md:847 +msgid "" +"fn f(t : (Int, Int)) -> Unit {\n" +" let (x1, y1) = t // access via pattern matching\n" +" // access via index\n" +" let x2 = t.0\n" +" let y2 = t.1\n" +" if (x1 == x2 && y1 == y2) {\n" +" println(\"yes\")\n" +" } else {\n" +" println(\"no\")\n" +" }\n" +"}\n" +"\n" +"fn main {\n" +" f((1, 2))\n" +"}\n" +msgstr "" + +#: ../../language/language.md:865 +msgid "Array" +msgstr "" + +#: ../../language/language.md:867 +msgid "" +"An array is a finite sequence of values constructed using square brackets" +" `[]`, with elements separated by commas `,`. For example:" +msgstr "" + +#: ../../language/language.md:869 +msgid "let numbers = [1, 2, 3, 4]\n" +msgstr "" + +#: ../../language/language.md:873 +msgid "" +"You can use `numbers[x]` to refer to the xth element. The index starts " +"from zero." +msgstr "" + +#: ../../language/language.md:875 +msgid "" +"fn main {\n" +" let numbers = [1, 2, 3, 4]\n" +" let a = numbers[2]\n" +" numbers[3] = 5\n" +" let b = a + numbers[3]\n" +" println(b) // prints 8\n" +"}\n" +msgstr "" + +#: ../../language/language.md:885 +msgid "Map" +msgstr "" + +#: ../../language/language.md:887 +msgid "" +"MoonBit provides a hash map data structure that preserves insertion orde " +"called `Map` in its standard library. `Map`s can be created via a " +"convenient literal syntax:" +msgstr "" + +#: ../../language/language.md:890 +msgid "let map : Map[String, Int] = { \"x\": 1, \"y\": 2, \"z\": 3 }\n" +msgstr "" + +#: ../../language/language.md:894 +msgid "" +"Currently keys in map literal syntax must be constant. `Map`s can also be" +" destructed elegantly with pattern matching, see [Map Pattern](#map-" +"pattern)." +msgstr "" + +#: ../../language/language.md:896 +msgid "Json literal" +msgstr "" + +#: ../../language/language.md:898 +msgid "" +"MoonBit supports convenient json handling by overloading literals. When " +"the expected type of an expression is `Json`, number, string, array and " +"map literals can be directly used to create json data:" +msgstr "" + +#: ../../language/language.md:901 +msgid "" +"let moon_pkg_json_example : Json = {\n" +" \"import\": [ \"moonbitlang/core/builtin\", " +"\"moonbitlang/core/coverage\" ],\n" +" \"test-import\": [ \"moonbitlang/core/random\" ]\n" +"}\n" +msgstr "" + +#: ../../language/language.md:908 +msgid "Json values can be pattern matched too, see [Json Pattern](#json-pattern)." +msgstr "" + +#: ../../language/language.md:910 +msgid "Variable Binding" +msgstr "" + +#: ../../language/language.md:912 +msgid "" +"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." +msgstr "" + +#: ../../language/language.md:914 +msgid "" +"let zero = 0\n" +"\n" +"fn main {\n" +" let mut i = 10\n" +" i = 20\n" +" println(i + zero)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:924 +msgid "Data Types" +msgstr "" + +#: ../../language/language.md:926 +msgid "There are two ways to create new data types: `struct` and `enum`." +msgstr "" + +#: ../../language/language.md:928 +msgid "Struct" +msgstr "" + +#: ../../language/language.md:930 +msgid "" +"In MoonBit, structs are similar to tuples, but their fields are indexed " +"by field names. A struct can be constructed using a struct literal, which" +" is composed of a set of labeled values and delimited with curly " +"brackets. The type of a struct literal can be automatically inferred if " +"its fields exactly match the type definition. A field can be accessed " +"using the dot syntax `s.f`. If a field is marked as mutable using the " +"keyword `mut`, it can be assigned a new value." +msgstr "" + +#: ../../language/language.md:932 +msgid "" +"struct User {\n" +" id: Int\n" +" name: String\n" +" mut email: String\n" +"}\n" +"\n" +"fn main {\n" +" let u = { id: 0, name: \"John Doe\", email: \"john@doe.com\" }\n" +" u.email = \"john@doe.name\"\n" +" println(u.id)\n" +" println(u.name)\n" +" println(u.email)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:948 +msgid "Constructing Struct with Shorthand" +msgstr "" + +#: ../../language/language.md:950 +msgid "" +"If you already have some variable like `name` and `email`, it's redundant" +" to repeat those names when constructing a struct:" +msgstr "" + +#: ../../language/language.md:952 +msgid "" +"fn main {\n" +" let name = \"john\"\n" +" let email = \"john@doe.com\"\n" +" let u = { id: 0, name: name, email: email }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:960 +msgid "You can use shorthand instead, it behaves exactly the same." +msgstr "" + +#: ../../language/language.md:962 +msgid "" +"fn main {\n" +" let name = \"john\"\n" +" let email = \"john@doe.com\"\n" +" let u = { id: 0, name, email }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:970 +msgid "Struct Update Syntax" +msgstr "" + +#: ../../language/language.md:972 +msgid "" +"It's useful to create a new struct based on an existing one, but with " +"some fields updated." +msgstr "" + +#: ../../language/language.md:974 +msgid "" +"struct User {\n" +" id: Int\n" +" name: String\n" +" email: String\n" +"} derive(Show)\n" +"\n" +"fn main {\n" +" let user = { id: 0, name: \"John Doe\", email: \"john@doe.com\" }\n" +" let updated_user = { ..user, email: \"john@doe.name\" }\n" +" println(user) // output: { id: 0, name: \"John Doe\", email: " +"\"john@doe.com\" }\n" +" println(updated_user) // output: { id: 0, name: \"John Doe\", email: " +"\"john@doe.name\" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:989 +msgid "Enum" +msgstr "" + +#: ../../language/language.md:991 +msgid "" +"Enum types are similar to algebraic data types in functional languages. " +"Users familiar with C/C++ may prefer calling it tagged union." +msgstr "" + +#: ../../language/language.md:993 +msgid "" +"An enum can have a set of cases (constructors). Constructor names must " +"start with capitalized letter. You can use these names to construct " +"corresponding cases of an enum, or checking which branch an enum value " +"belongs to in pattern matching:" +msgstr "" + +#: ../../language/language.md:995 +msgid "" +"// An enum type that represents the ordering relation between two values," +"\n" +"// with three cases \"Smaller\", \"Greater\" and \"Equal\"\n" +"enum Relation {\n" +" Smaller\n" +" Greater\n" +" Equal\n" +"}\n" +"\n" +"// compare the ordering relation between two integers\n" +"fn compare_int(x: Int, y: Int) -> Relation {\n" +" if x < y {\n" +" // when creating an enum, if the target type is known, you can write " +"the constructor name directly\n" +" Smaller\n" +" } else if x > y {\n" +" // but when the target type is not known,\n" +" // you can always use `TypeName::Constructor` to create an enum " +"unambiguously\n" +" Relation::Greater\n" +" } else {\n" +" Equal\n" +" }\n" +"}\n" +"\n" +"// output a value of type `Relation`\n" +"fn print_relation(r: Relation) -> Unit {\n" +" // use pattern matching to decide which case `r` belongs to\n" +" match r {\n" +" // during pattern matching, if the type is known, writing the name of" +" constructor is sufficient\n" +" Smaller => println(\"smaller!\")\n" +" // but you can use the `TypeName::Constructor` syntax for pattern " +"matching as well\n" +" Relation::Greater => println(\"greater!\")\n" +" Equal => println(\"equal!\")\n" +" }\n" +"}\n" +"\n" +"fn main {\n" +" print_relation(compare_int(0, 1)) // smaller!\n" +" print_relation(compare_int(1, 1)) // equal!\n" +" print_relation(compare_int(2, 1)) // greater!\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1037 +msgid "" +"Enum cases can also carry payload data. Here's an example of defining an " +"integer list type using enum:" +msgstr "" + +#: ../../language/language.md:1039 +msgid "" +"enum List {\n" +" Nil\n" +" // constructor `Cons` carries additional payload: the first element of " +"the list,\n" +" // and the remaining parts of the list\n" +" Cons (Int, List)\n" +"}\n" +"\n" +"fn main {\n" +" // when creating values using `Cons`, the payload of by `Cons` must be " +"provided\n" +" let l: List = Cons(1, Cons(2, Nil))\n" +" println(is_singleton(l))\n" +" print_list(l)\n" +"}\n" +"\n" +"fn print_list(l: List) -> Unit {\n" +" // when pattern-matching an enum with payload,\n" +" // in additional to deciding which case a value belongs to\n" +" // you can extract the payload data inside that case\n" +" match l {\n" +" Nil => println(\"nil\")\n" +" // Here `x` and `xs` are defining new variables instead of referring " +"to existing variables,\n" +" // if `l` is a `Cons`, then the payload of `Cons` (the first element " +"and the rest of the list)\n" +" // will be bind to `x` and `xs\n" +" Cons(x, xs) => {\n" +" println(x)\n" +" println(\",\")\n" +" print_list(xs)\n" +" }\n" +" }\n" +"}\n" +"\n" +"// In addition to binding payload to variables,\n" +"// you can also continue matching payload data inside constructors.\n" +"// Here's a function that decides if a list contains only one element\n" +"fn is_singleton(l: List) -> Bool {\n" +" match l {\n" +" // This branch only matches values of shape `Cons(_, Nil)`, i.e. " +"lists of length 1\n" +" Cons(_, Nil) => true\n" +" // Use `_` to match everything else\n" +" _ => false\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1084 +msgid "Constructor with labelled arguments" +msgstr "" + +#: ../../language/language.md:1086 +msgid "Enum constructors can have labelled argument:" +msgstr "" + +#: ../../language/language.md:1088 +msgid "" +"enum E {\n" +" // `x` and `y` are labelled argument\n" +" C(x~ : Int, y~ : Int)\n" +"}\n" +"\n" +"// pattern matching constructor with labelled arguments\n" +"fn f(e : E) -> Unit {\n" +" match e {\n" +" // `label=pattern`\n" +" C(x=0, y=0) => println(\"0!\")\n" +" // `x~` is an abbreviation for `x=x`\n" +" // Unmatched labelled arguments can be omitted via `..`\n" +" C(x~, ..) => println(x)\n" +" }\n" +"}\n" +"\n" +"// creating constructor with labelled arguments\n" +"fn main {\n" +" f(C(x=0, y=0)) // `label=value`\n" +" let x = 0\n" +" f(C(x~, y=1)) // `~x` is an abbreviation for `x=x`\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1113 +msgid "" +"It is also possible to access labelled arguments of constructors like " +"accessing struct fields in pattern matching:" +msgstr "" + +#: ../../language/language.md:1115 +msgid "" +"enum Object {\n" +" Point(x~ : Double, y~ : Double)\n" +" Circle(x~ : Double, y~ : Double, radius~ : Double)\n" +"}\n" +"\n" +"type! NotImplementedError derive(Show)\n" +"\n" +"fn distance_with(self : Object, other : Object) -> " +"Double!NotImplementedError {\n" +" match (self, other) {\n" +" // For variables defined via `Point(..) as p`,\n" +" // the compiler knows it must be of constructor `Point`,\n" +" // so you can access fields of `Point` directly via `p.x`, `p.y` etc." +"\n" +" (Point(_) as p1, Point(_) as p2) => {\n" +" let dx = p2.x - p1.x\n" +" let dy = p2.y - p1.y\n" +" (dx * dx + dy * dy).sqrt()\n" +" }\n" +" (Point(_), Circle(_)) | (Circle(_), Point(_)) | (Circle(_), " +"Circle(_)) =>\n" +" raise NotImplementedError\n" +" }\n" +"}\n" +"\n" +"fn main {\n" +" let p1 : Object = Point(x=0, y=0)\n" +" let p2 : Object = Point(x=3, y=4)\n" +" let c1 : Object = Circle(x=0, y=0, radius=2)\n" +" try {\n" +" println(p1.distance_with!(p2)) // 5.0\n" +" println(p1.distance_with!(c1))\n" +" } catch {\n" +" e => println(e)\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1151 +msgid "Constructor with mutable fields" +msgstr "" + +#: ../../language/language.md:1153 +msgid "" +"It is also possible to define mutable fields for constructor. This is " +"especially useful for defining imperative data structures:" +msgstr "" + +#: ../../language/language.md:1155 +msgid "" +"// A mutable binary search tree with parent pointer\n" +"enum Tree[X] {\n" +" Nil\n" +" // only labelled arguments can be mutable\n" +" Node(mut value~ : X, mut left~ : Tree[X], mut right~ : Tree[X], mut " +"parent~ : Tree[X])\n" +"}\n" +"\n" +"// A set implemented using mutable binary search tree.\n" +"struct Set[X] {\n" +" mut root : Tree[X]\n" +"}\n" +"\n" +"fn Set::insert[X : Compare](self : Set[X], x : X) -> Unit {\n" +" self.root = self.root.insert(x, parent=Nil)\n" +"}\n" +"\n" +"// In-place insert a new element to a binary search tree.\n" +"// Return the new tree root\n" +"fn Tree::insert[X : Compare](self : Tree[X], x : X, parent~ : Tree[X]) ->" +" Tree[X] {\n" +" match self {\n" +" Nil => Node(value=x, left=Nil, right=Nil, parent~)\n" +" Node(_) as node => {\n" +" let order = x.compare(node.value)\n" +" if order == 0 {\n" +" // mutate the field of a constructor\n" +" node.value = x\n" +" } else if order < 0 {\n" +" // cycle between `node` and `node.left` created here\n" +" node.left = node.left.insert(x, parent=node)\n" +" } else {\n" +" node.right = node.right.insert(x, parent=node)\n" +" }\n" +" // The tree is non-empty, so the new root is just the original tree" +"\n" +" node\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1195 +msgid "Newtype" +msgstr "" + +#: ../../language/language.md:1197 +msgid "MoonBit supports a special kind of enum called newtype:" +msgstr "" + +#: ../../language/language.md:1199 +msgid "" +"// `UserId` is a fresh new type different from `Int`, and you can define " +"new methods for `UserId`, etc.\n" +"// But at the same time, the internal representation of `UserId` is " +"exactly the same as `Int`\n" +"type UserId Int\n" +"type UserName String\n" +msgstr "" + +#: ../../language/language.md:1206 +msgid "" +"Newtypes are similar to enums with only one constructor (with the same " +"name as the newtype itself). So, you can use the constructor to create " +"values of newtype, or use pattern matching to extract the underlying " +"representation of a newtype:" +msgstr "" + +#: ../../language/language.md:1208 +msgid "" +"fn init {\n" +" let id: UserId = UserId(1)\n" +" let name: UserName = UserName(\"John Doe\")\n" +" let UserId(uid) = id // the type of `uid` is `Int`\n" +" let UserName(uname) = name // the type of `uname` is `String`\n" +" println(uid)\n" +" println(uname)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1219 +msgid "" +"Besides pattern matching, you can also use `._` to extract the internal " +"representation of newtypes:" +msgstr "" + +#: ../../language/language.md:1221 +msgid "" +"fn init {\n" +" let id: UserId = UserId(1)\n" +" let uid: Int = id._\n" +" println(uid)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1229 +msgid "Type alias" +msgstr "" + +#: ../../language/language.md:1230 +msgid "MoonBit supports type alias via the syntax `typealias Name = TargetType`:" +msgstr "" + +#: ../../language/language.md:1232 +msgid "" +"pub typealias Index = Int\n" +"// type alias are private by default\n" +"typealias MapString[X] = Map[String, X]\n" +msgstr "" + +#: ../../language/language.md:1238 +msgid "" +"unlike all other kinds of type declaration above, type alias does not " +"define a new type, it is merely a type macro that behaves exactly the " +"same as its definition. So for example one cannot define new methods or " +"implement traits for a type alias." +msgstr "" + +#: ../../language/language.md:1242 +msgid "" +"Type alias can be used to perform incremental code refactor. For example," +" if you want to move a type `T` from `@pkgA` to `@pkgB`, you can leave a " +"type alias `typealias T = @pkgB.T` in `@pkgA`, and **incrementally** port" +" uses of `@pkgA.T` to `@pkgB.T`. The type alias can be removed after all " +"uses of `@pkgA.T` is migrated to `@pkgB.T`." +msgstr "" + +#: ../../language/language.md:1247 +msgid "Pattern Matching" +msgstr "" + +#: ../../language/language.md:1249 +msgid "" +"We have shown a use case of pattern matching for enums, but pattern " +"matching is not restricted to enums. For example, we can also match " +"expressions against Boolean values, numbers, characters, strings, tuples," +" arrays, and struct literals. Since there is only one case for those " +"types other than enums, we can pattern match them using `let` binding " +"instead of `match` expressions. Note that the scope of bound variables in" +" `match` is limited to the case where the variable is introduced, while " +"`let` binding will introduce every variable to the current scope. " +"Furthermore, we can use underscores `_` as wildcards for the values we " +"don't care about, use `..` to ignore remaining fields of struct or " +"elements of array." +msgstr "" + +#: ../../language/language.md:1251 +msgid "" +"let id = match u {\n" +" { id: id, name: _, email: _ } => id\n" +"}\n" +"// is equivalent to\n" +"let { id: id, name: _, email: _ } = u\n" +"// or\n" +"let { id: id, ..} = u\n" +msgstr "" + +#: ../../language/language.md:1261 +msgid "" +"let ary = [1,2,3,4]\n" +"let [a, b, ..] = ary // a = 1, b = 2\n" +"let [.., a, b] = ary // a = 3, b = 4\n" +msgstr "" + +#: ../../language/language.md:1267 +msgid "" +"There are some other useful constructs in pattern matching. For example, " +"we can use `as` to give a name to some pattern, and we can use `|` to " +"match several cases at once. A variable name can only be bound once in a " +"single pattern, and the same set of variables should be bound on both " +"sides of `|` patterns." +msgstr "" + +#: ../../language/language.md:1269 +msgid "" +"match expr {\n" +" Lit(n) as a => ...\n" +" Add(e1, e2) | Mul(e1, e2) => ...\n" +" _ => ...\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1277 +msgid "Range Pattern" +msgstr "" + +#: ../../language/language.md:1278 +msgid "" +"For builtin integer types and `Char`, MoonBit allows matching whether the" +" value falls in a specific range. Range patterns have the form `a.. Int {\n" +" match x {\n" +" _.. -1\n" +" Zero => 0\n" +" 1..<_ => 1\n" +" }\n" +"}\n" +"\n" +"fn classify_char(c : Char) -> String {\n" +" match c {\n" +" 'a'..='z' => \"lowercase\"\n" +" 'A'..='Z' => \"uppercase\"\n" +" '0'..='9' => \"digit\"\n" +" _ => \"other\"\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1308 +msgid "Map Pattern" +msgstr "" + +#: ../../language/language.md:1310 +msgid "" +"MoonBit allows convenient matching on map-like data structures. Inside a " +"map pattern, the `key : value` syntax will match if `key` exists in the " +"map, and match the value of `key` with pattern `value`. The `key? : " +"value` syntax will match no matter `key` exists or not, and `value` will " +"be matched against `map[key]` (an optional)." +msgstr "" + +#: ../../language/language.md:1314 +msgid "" +"match map {\n" +" // matches if any only if \"b\" exists in `map`\n" +" { \"b\": _ } => ..\n" +" // matches if and only if \"b\" does not exist in `map` and \"a\" " +"exists in `map`.\n" +" // When matches, bind the value of \"a\" in `map` to `x`\n" +" { \"b\"? : None, \"a\": x } => ..\n" +" // compiler reports missing case: { \"b\"? : None, \"a\"? : None }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1325 +msgid "" +"To match a data type `T` using map pattern, `T` must have a method " +"`op_get(Self, K) -> Option[V]` for some type `K` and `V`." +msgstr "" + +#: ../../language/language.md:1326 +msgid "Currently, the key part of map pattern must be a constant" +msgstr "" + +#: ../../language/language.md:1327 +msgid "Map patterns are always open: unmatched keys are silently ignored" +msgstr "" + +#: ../../language/language.md:1328 +msgid "" +"Map pattern will be compiled to efficient code: every key will be fetched" +" at most once" +msgstr "" + +#: ../../language/language.md:1330 +msgid "Json Pattern" +msgstr "" + +#: ../../language/language.md:1332 +msgid "" +"When the matched value has type `Json`, literal patterns can be used " +"directly:" +msgstr "" + +#: ../../language/language.md:1334 +msgid "" +"match json {\n" +" { \"version\": \"1.0.0\", \"import\": [..] as imports } => ...\n" +" _ => ...\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1341 +msgid "Operators" +msgstr "" + +#: ../../language/language.md:1343 +msgid "Operator Overloading" +msgstr "" + +#: ../../language/language.md:1345 +msgid "" +"MoonBit supports operator overloading of builtin operators via methods. " +"The method name corresponding to a operator `` is `op_`. For " +"example:" +msgstr "" + +#: ../../language/language.md:1347 +msgid "" +"struct T {\n" +" x:Int\n" +"} derive(Show)\n" +"\n" +"fn op_add(self: T, other: T) -> T {\n" +" { x: self.x + other.x }\n" +"}\n" +"\n" +"fn main {\n" +" let a = { x: 0 }\n" +" let b = { x: 2 }\n" +" println(a + b)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1363 +msgid "Another example about `op_get` and `op_set`:" +msgstr "" + +#: ../../language/language.md:1365 +msgid "" +"struct Coord {\n" +" mut x: Int\n" +" mut y: Int\n" +"} derive(Show)\n" +"\n" +"fn op_get(self: Coord, key: String) -> Int {\n" +" match key {\n" +" \"x\" => self.x\n" +" \"y\" => self.y\n" +" }\n" +"}\n" +"\n" +"fn op_set(self: Coord, key: String, val: Int) -> Unit {\n" +" match key {\n" +" \"x\" => self.x = val\n" +" \"y\" => self.y = val\n" +" }\n" +"}\n" +"\n" +"fn main {\n" +" let c = { x: 1, y: 2 }\n" +" println(c)\n" +" println(c[\"y\"])\n" +" c[\"x\"] = 23\n" +" println(c)\n" +" println(c[\"x\"])\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1395 +msgid "Currently, the following operators can be overloaded:" +msgstr "" + +#: ../../language/language.md +msgid "Operator Name" +msgstr "" + +#: ../../language/language.md +msgid "Method Name" +msgstr "" + +#: ../../language/language.md +msgid "`+`" +msgstr "" + +#: ../../language/language.md +msgid "`op_add`" +msgstr "" + +#: ../../language/language.md +msgid "`-`" +msgstr "" + +#: ../../language/language.md +msgid "`op_sub`" +msgstr "" + +#: ../../language/language.md +msgid "`*`" +msgstr "" + +#: ../../language/language.md +msgid "`op_mul`" +msgstr "" + +#: ../../language/language.md +msgid "`/`" +msgstr "" + +#: ../../language/language.md +msgid "`op_div`" +msgstr "" + +#: ../../language/language.md +msgid "`%`" +msgstr "" + +#: ../../language/language.md +msgid "`op_mod`" +msgstr "" + +#: ../../language/language.md +msgid "`=`" +msgstr "" + +#: ../../language/language.md +msgid "`op_equal`" +msgstr "" + +#: ../../language/language.md +msgid "`<<`" +msgstr "" + +#: ../../language/language.md +msgid "`op_shl`" +msgstr "" + +#: ../../language/language.md +msgid "`>>`" +msgstr "" + +#: ../../language/language.md +msgid "`op_shr`" +msgstr "" + +#: ../../language/language.md +msgid "`-` (unary)" +msgstr "" + +#: ../../language/language.md +msgid "`op_neg`" +msgstr "" + +#: ../../language/language.md +msgid "`_[_]` (get item)" +msgstr "" + +#: ../../language/language.md +msgid "`op_get`" +msgstr "" + +#: ../../language/language.md +msgid "`_[_] = _` (set item)" +msgstr "" + +#: ../../language/language.md +msgid "`op_set`" +msgstr "" + +#: ../../language/language.md +msgid "`_[_:_]` (view)" +msgstr "" + +#: ../../language/language.md +msgid "`op_as_view`" +msgstr "" + +#: ../../language/language.md:1412 +msgid "Pipe operator" +msgstr "" + +#: ../../language/language.md:1414 +msgid "" +"MoonBit provides a convenient pipe operator `|>`, which can be used to " +"chain regular function calls:" +msgstr "" + +#: ../../language/language.md:1416 +msgid "" +"fn init {\n" +" x |> f // equivalent to f(x)\n" +" x |> f(y) // equivalent to f(x, y)\n" +"\n" +" // Chain calls at multiple lines\n" +" arg_val\n" +" |> f1 // equivalent to f1(arg_val)\n" +" |> f2(other_args) // equivalent to f2(f1(arg_val), other_args)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1428 +msgid "Cascade Operator" +msgstr "" + +#: ../../language/language.md:1430 +msgid "" +"The cascade operator `..` is used to perform a series of mutable " +"operations on the same value consecutively. The syntax is as follows:" +msgstr "" + +#: ../../language/language.md:1433 +msgid "x..f()\n" +msgstr "" + +#: ../../language/language.md:1437 +msgid "`x..f()..g()` is equivalent to `{x.f(); x.g(); x}`." +msgstr "" + +#: ../../language/language.md:1439 +msgid "" +"Consider the following scenario: for a `MyStringBuilder` type that has " +"methods like `add_string`, `add_char`, `add_int`, etc., we often need to " +"perform a series of operations on the same `MyStringBuilder` value:" +msgstr "" + +#: ../../language/language.md:1443 +msgid "" +"let builder = MyStringBuilder::new()\n" +"builder.add_char('a')\n" +"builder.add_char('a')\n" +"builder.add_int(1001)\n" +"builder.add_string(\"abcdef\")\n" +"let result = builder.to_string()\n" +msgstr "" + +#: ../../language/language.md:1452 +msgid "" +"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." +msgstr "" + +#: ../../language/language.md:1458 +msgid "" +"let result =\n" +" MyStringBuilder::new()\n" +" ..add_char('a')\n" +" ..add_char('a')\n" +" ..add_int(1001)\n" +" ..add_string(\"abcdef\")\n" +" .to_string()\n" +msgstr "" + +#: ../../language/language.md:1468 +msgid "Bitwise Operator" +msgstr "" + +#: ../../language/language.md:1470 +msgid "MoonBit supports C-Style bitwise operators." +msgstr "" + +#: ../../language/language.md +msgid "Operator" +msgstr "" + +#: ../../language/language.md +msgid "Perform" +msgstr "" + +#: ../../language/language.md +msgid "`&`" +msgstr "" + +#: ../../language/language.md +msgid "`land`" +msgstr "" + +#: ../../language/language.md +msgid "`|`" +msgstr "" + +#: ../../language/language.md +msgid "`lor`" +msgstr "" + +#: ../../language/language.md +msgid "`^`" +msgstr "" + +#: ../../language/language.md +msgid "`lxor`" +msgstr "" + +#: ../../language/language.md:1480 +msgid "Error Handling" +msgstr "" + +#: ../../language/language.md:1482 +msgid "Error types" +msgstr "" + +#: ../../language/language.md:1484 +msgid "" +"The error values used in MoonBit must have an error type. An error type " +"can be defined in the following forms:" +msgstr "" + +#: ../../language/language.md:1487 +msgid "" +"type! E1 Int // error type E1 has one constructor E1 with an Int payload" +"\n" +"type! E2 // error type E2 has one constructor E2 with no payload\n" +"type! E3 { // error type E3 has three constructors like a normal enum " +"type\n" +" A\n" +" B(Int, x~ : String)\n" +" C(mut x~ : String, Char, y~ : Bool)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1497 +msgid "" +"The return type of a function can include an error type to indicate that " +"the function might return an error. For example, the following function " +"`div` might return an error of type `DivError`:" +msgstr "" + +#: ../../language/language.md:1501 +msgid "" +"type! DivError String\n" +"fn div(x: Int, y: Int) -> Int!DivError {\n" +" if y == 0 {\n" +" raise DivError(\"division by zero\")\n" +" }\n" +" x / y\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1511 +msgid "" +"Here, the keyword `raise` is used to interrupt the function execution and" +" return an error." +msgstr "" + +#: ../../language/language.md:1514 +msgid "The Default Error Type" +msgstr "" + +#: ../../language/language.md:1516 +msgid "" +"MoonBit provides a default error type `Error` that can be used when the " +"concrete error type is not important. For convenience, you can annotate " +"the function name or the return type with the suffix `!` to indicate that" +" the `Error` type is used. For example, the following function signatures" +" are equivalent:" +msgstr "" + +#: ../../language/language.md:1521 +msgid "" +"fn f() -> Unit! { .. }\n" +"fn f!() -> Unit { .. }\n" +"fn f() -> Unit!Error { .. }\n" +msgstr "" + +#: ../../language/language.md:1527 +msgid "" +"For anonymous function and matrix function, you can annotate the keyword " +"`fn` with the `!` suffix to achieve that. For example," +msgstr "" + +#: ../../language/language.md:1530 +msgid "" +"type! IntError Int\n" +"fn h(f: (x: Int) -> Int!, x: Int) -> Unit { .. }\n" +"\n" +"fn main {\n" +" let _ = h(fn! { x => raise(IntError(x)) }, 0) // matrix function\n" +" let _ = h(fn! (x) { x => raise(IntError(x)) }, 0) // anonymous function" +"\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1540 +msgid "" +"As shown in the above example, the error types defined by `type!` can be " +"used as value of the type `Error` when the error is raised." +msgstr "" + +#: ../../language/language.md:1543 +msgid "" +"Note that only error types or the type `Error` can be used as errors. For" +" functions that are generic in the error type, you can use the `Error` " +"bound to do that. For example," +msgstr "" + +#: ../../language/language.md:1547 +msgid "" +"pub fn unwrap_or_error[T, E : Error](self : Result[T, E]) -> T!E {\n" +" match self {\n" +" Ok(x) => x\n" +" Err(e) => raise e\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1556 +msgid "" +"Since the type `Error` can include multiple error types, pattern matching" +" on the `Error` type must use the wildcard `_` to match all error types. " +"For example," +msgstr "" + +#: ../../language/language.md:1559 +msgid "" +"type! E1\n" +"type! E2\n" +"fn f(e: Error) -> Unit {\n" +" match e {\n" +" E1 => println(\"E1\")\n" +" E2 => println(\"E2\")\n" +" _ => println(\"unknown error\")\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1571 +msgid "Handling Errors" +msgstr "" + +#: ../../language/language.md:1573 +msgid "There are three ways to handle errors:" +msgstr "" + +#: ../../language/language.md:1575 +msgid "" +"Append `!` after the function name in a function application to rethrow " +"the error directly in case of an error, for example:" +msgstr "" + +#: ../../language/language.md:1578 +msgid "" +"fn div_reraise(x: Int, y: Int) -> Int!DivError {\n" +" div!(x, y) // Rethrow the error if `div` raised an error\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1584 +msgid "" +"Append `?` after the function name to convert the result into a first-" +"class value of the `Result` type, for example:" +msgstr "" + +#: ../../language/language.md:1587 +msgid "" +"test {\n" +" let res = div?(6, 3)\n" +" inspect!(res, content=\"Ok(2)\")\n" +" let res = div?(6, 0)\n" +" inspect!(res, content=\"Err(division by zero)\")\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1596 +msgid "Use `try` and `catch` to catch and handle errors, for example:" +msgstr "" + +#: ../../language/language.md:1598 +msgid "" +"fn main {\n" +" try {\n" +" div!(42, 0)\n" +" } catch {\n" +" DivError(s) => println(s)\n" +" } else {\n" +" v => println(v)\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1610 +msgid "" +"Here, `try` is used to call a function that might throw an error, and " +"`catch` is used to match and handle the caught error. If no error is " +"caught, the catch block will not be executed and the `else` block will be" +" executed instead." +msgstr "" + +#: ../../language/language.md:1614 +msgid "" +"The `else` block can be omitted if no action is needed when no error is " +"caught. For example:" +msgstr "" + +#: ../../language/language.md:1617 +msgid "" +"fn main {\n" +" try {\n" +" println(div!(42, 0))\n" +" } catch {\n" +" _ => println(\"Error\")\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1627 +msgid "" +"The `catch` keyword is optional, and when the body of `try` is a simple " +"expression, the curly braces can be omitted. For example:" +msgstr "" + +#: ../../language/language.md:1630 +msgid "" +"fn main {\n" +" let a = try div!(42, 0) { _ => 0 }\n" +" println(a)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1637 +msgid "" +"The `!` and `?` attributes can also be used on method invocation and pipe" +" operator. For example:" +msgstr "" + +#: ../../language/language.md:1640 +msgid "" +"type T Int\n" +"type! E Int derive(Show)\n" +"fn f(self: T) -> Unit!E { raise E(self._) }\n" +"fn main {\n" +" let x = T(42)\n" +" try f!(x) { e => println(e) }\n" +" try x.f!() { e => println(e) }\n" +" try x |> f!() { e => println(e) }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1652 +msgid "" +"However for infix operators such as `+` `*` that may raise an error, the " +"original form has to be used, e.g. `x.op_add!(y)`, `x.op_mul!(y)`." +msgstr "" + +#: ../../language/language.md:1655 +msgid "" +"Additionally, if the return type of a function includes an error type, " +"the function call must use `!` or `?` for error handling, otherwise the " +"compiler will report an error." +msgstr "" + +#: ../../language/language.md:1659 +msgid "Error Inference" +msgstr "" + +#: ../../language/language.md:1661 +msgid "" +"Within a `try` block, several different kinds of errors can be raised. " +"When that happens, the compiler will use the type `Error` as the common " +"error type. Accordingly, the handler must use the wildcard `_` to make " +"sure all errors are caught. For example," +msgstr "" + +#: ../../language/language.md:1666 +msgid "" +"type! E1\n" +"type! E2\n" +"fn f1() -> Unit!E1 { raise E1 }\n" +"fn f2() -> Unit!E2 { raise E2 }\n" +"fn main {\n" +" try {\n" +" f1!()\n" +" f2!()\n" +" } catch {\n" +" E1 => println(\"E1\")\n" +" E2 => println(\"E2\")\n" +" _ => println(\"unknown error\")\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1683 +msgid "" +"You can also use `catch!` to rethrow the uncaught errors for convenience." +" This is useful when you only want to handle a specific error and rethrow" +" others. For example," +msgstr "" + +#: ../../language/language.md:1687 +msgid "" +"type! E1\n" +"type! E2\n" +"fn f1() -> Unit!E1 { raise E1 }\n" +"fn f2() -> Unit!E2 { raise E2 }\n" +"fn f() -> Unit! {\n" +" try {\n" +" f1!()\n" +" f2!()\n" +" } catch! {\n" +" E1 => println(\"E1\")\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1702 +msgid "Generics" +msgstr "" + +#: ../../language/language.md:1704 +msgid "" +"Generics are supported in top-level function and data type definitions. " +"Type parameters can be introduced within square brackets. We can rewrite " +"the aforementioned data type `List` to add a type parameter `T` to obtain" +" a generic version of lists. We can then define generic functions over " +"lists like `map` and `reduce`." +msgstr "" + +#: ../../language/language.md:1706 +msgid "" +"enum List[T] {\n" +" Nil\n" +" Cons(T, List[T])\n" +"}\n" +"\n" +"fn map[S, T](self: List[S], f: (S) -> T) -> List[T] {\n" +" match self {\n" +" Nil => Nil\n" +" Cons(x, xs) => Cons(f(x), map(xs, f))\n" +" }\n" +"}\n" +"\n" +"fn reduce[S, T](self: List[S], op: (T, S) -> T, init: T) -> T {\n" +" match self {\n" +" Nil => init\n" +" Cons(x, xs) => reduce(xs, op, op(init, x))\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1727 +msgid "Access Control" +msgstr "" + +#: ../../language/language.md:1729 +msgid "" +"By default, all function definitions and variable bindings are " +"_invisible_ to other packages. You can use the `pub` modifier before " +"toplevel `let`/`fn` to make them public." +msgstr "" + +#: ../../language/language.md:1732 +msgid "There are four different kinds of visibility for types in MoonBit:" +msgstr "" + +#: ../../language/language.md:1734 +msgid "" +"private type, declared with `priv`, completely invisible to the outside " +"world" +msgstr "" + +#: ../../language/language.md:1735 +msgid "" +"abstract type, which is the default visibility for types. Only the name " +"of an abstract type is visible outside, the internal representation of " +"the type is hidden" +msgstr "" + +#: ../../language/language.md:1736 +msgid "" +"readonly types, declared with `pub(readonly)`. The internal " +"representation of readonly types are visible outside, but users can only " +"read the values of these types from outside, construction and mutation " +"are not allowed" +msgstr "" + +#: ../../language/language.md:1738 +msgid "" +"fully public types, declared with `pub(all)`. The outside world can " +"freely construct, modify and read values of these types" +msgstr "" + +#: ../../language/language.md:1740 +msgid "" +"Currently, the semantic of `pub` is `pub(all)`. But in the future, the " +"meaning of `pub` will be ported to `pub(readonly)`. In addition to the " +"visibility of the type itself, the fields of a public `struct` can be " +"annotated with `priv`, which will hide the field from the outside world " +"completely. Note that `struct`s with private fields cannot be constructed" +" directly outside, but you can update the public fields using the " +"functional struct update syntax." +msgstr "" + +#: ../../language/language.md:1746 +msgid "" +"Readonly types is a very useful feature, inspired by [private " +"types](https://v2.ocaml.org/manual/privatetypes.html) in OCaml. In short," +" values of `pub(readonly)` types can be destructed by pattern matching " +"and the dot syntax, but cannot be constructed or mutated in other " +"packages. Note that there is no restriction within the same package where" +" `pub(readonly)` types are defined." +msgstr "" + +#: ../../language/language.md:1748 +msgid "" +"// Package A\n" +"pub(readonly) struct RO {\n" +" field: Int\n" +"}\n" +"fn init {\n" +" let r = { field: 4 } // OK\n" +" let r = { ..r, field: 8 } // OK\n" +"}\n" +"\n" +"// Package B\n" +"fn println(r : RO) -> Unit {\n" +" println(\"{ field: \")\n" +" println(r.field) // OK\n" +" println(\" }\")\n" +"}\n" +"fn init {\n" +" let r : RO = { field: 4 } // ERROR: Cannot create values of the public" +" read-only type RO!\n" +" let r = { ..r, field: 8 } // ERROR: Cannot mutate a public read-only " +"field!\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1770 +msgid "" +"Access control in MoonBit adheres to the principle that a `pub` type, " +"function, or variable cannot be defined in terms of a private type. This " +"is because the private type may not be accessible everywhere that the " +"`pub` entity is used. MoonBit incorporates sanity checks to prevent the " +"occurrence of use cases that violate this principle." +msgstr "" + +#: ../../language/language.md:1772 +msgid "" +"pub struct S {\n" +" x: T1 // OK\n" +" y: T2 // OK\n" +" z: T3 // ERROR: public field has private type `T3`!\n" +"}\n" +"\n" +"// ERROR: public function has private parameter type `T3`!\n" +"pub fn f1(_x: T3) -> T1 { T1::A(0) }\n" +"// ERROR: public function has private return type `T3`!\n" +"pub fn f2(_x: T1) -> T3 { T3::A(0) }\n" +"// OK\n" +"pub fn f3(_x: T1) -> T1 { T1::A(0) }\n" +"\n" +"pub let a: T3 // ERROR: public variable has private type `T3`!\n" +msgstr "" + +#: ../../language/language.md:1789 +msgid "Method system" +msgstr "" + +#: ../../language/language.md:1791 +msgid "" +"MoonBit supports methods in a different way from traditional object-" +"oriented languages. A method in MoonBit is just a toplevel function " +"associated with a type constructor. Methods can be defined using the " +"syntax `fn TypeName::method_name(...) -> ...`:" +msgstr "" + +#: ../../language/language.md:1793 +msgid "" +"enum MyList[X] {\n" +" Nil\n" +" Cons(X, MyList[X])\n" +"}\n" +"\n" +"fn MyList::map[X, Y](xs: MyList[X], f: (X) -> Y) -> MyList[Y] { ... }\n" +"fn MyList::concat[X](xs: MyList[MyList[X]]) -> MyList[X] { ... }\n" +msgstr "" + +#: ../../language/language.md:1803 +msgid "" +"As a convenient shorthand, when the first parameter of a function is " +"named `self`, MoonBit automatically defines the function as a method of " +"the type of `self`:" +msgstr "" + +#: ../../language/language.md:1805 +msgid "" +"fn map[X, Y](self: MyList[X], f: (X) -> Y) -> List[Y] { ... }\n" +"// equivalent to\n" +"fn MyList::map[X, Y](xs: MyList[X], f: (X) -> Y) -> List[Y] { ... }\n" +msgstr "" + +#: ../../language/language.md:1811 +msgid "" +"Methods are just regular functions owned by a type constructor. So when " +"there is no ambiguity, methods can be called using regular function call " +"syntax directly:" +msgstr "" + +#: ../../language/language.md:1813 +msgid "" +"fn init {\n" +" let xs: MyList[MyList[_]] = ...\n" +" let ys = concat(xs)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1820 +msgid "" +"Unlike regular functions, methods support overloading: different types " +"can define methods of the same name. If there are multiple methods of the" +" same name (but for different types) in scope, one can still call them by" +" explicitly adding a `TypeName::` prefix:" +msgstr "" + +#: ../../language/language.md:1822 +msgid "" +"struct T1 { x1: Int }\n" +"fn T1::default() -> { { x1: 0 } }\n" +"\n" +"struct T2 { x2: Int }\n" +"fn T2::default() -> { { x2: 0 } }\n" +"\n" +"fn init {\n" +" // default() is ambiguous!\n" +" let t1 = T1::default() // ok\n" +" let t2 = T2::default() // ok\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1836 +msgid "" +"When the first parameter of a method is also the type it belongs to, " +"methods can be called using dot syntax `x.method(...)`. MoonBit " +"automatically finds the correct method based on the type of `x`, there is" +" no need to write the type name and even the package name of the method:" +msgstr "" + +#: ../../language/language.md:1838 +msgid "" +"// a package named @list\n" +"enum List[X] { ... }\n" +"fn List::length[X](xs: List[X]) -> Int { ... }\n" +"\n" +"// another package that uses @list\n" +"fn init {\n" +" let xs: @list.List[_] = ...\n" +" println(xs.length()) // always work\n" +" println(@list.List::length(xs)) // always work, but verbose\n" +" println(@list.length(xs)) // simpler, but only possible when there is " +"no ambiguity in @list\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1852 +msgid "View" +msgstr "" + +#: ../../language/language.md:1854 +msgid "" +"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." +msgstr "" + +#: ../../language/language.md:1859 +msgid "" +"fn init {\n" +" let xs = [0,1,2,3,4,5]\n" +" let s1 : ArrayView[Int] = xs[2:]\n" +" print_array_view(s1) //output: 2345\n" +" xs[:4] |> print_array_view() //output: 0123\n" +" xs[2:5] |> print_array_view() //output: 234\n" +" xs[:] |> print_array_view() //output: 012345\n" +"\n" +" // create a view of another view\n" +" xs[2:5][1:] |> print_array_view() //output: 34\n" +"}\n" +"\n" +"fn print_array_view[T : Show](view : ArrayView[T]) -> Unit {\n" +" for i=0; i Int {\n" +" self.elems.length()\n" +"}\n" +"\n" +"pub fn op_as_view[A](self : MyList[A], start~ : Int, end~ : Int) -> " +"MyListView[A] {\n" +" println(\"op_as_view: [\\{start},\\{end})\")\n" +" if start < 0 || end > self.length() { abort(\"index out of bounds\") }\n" +" { ls: self, start, end }\n" +"}\n" +"\n" +"fn init {\n" +" let ls = { elems: [1,2,3,4,5] }\n" +" ls[:] |> ignore()\n" +" ls[1:] |> ignore()\n" +" ls[:2] |> ignore()\n" +" ls[1:2] |> ignore()\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1912 +msgid "Output:" +msgstr "" + +#: ../../language/language.md:1914 +msgid "" +"op_as_view: [0,5)\n" +"op_as_view: [1,5)\n" +"op_as_view: [0,2)\n" +"op_as_view: [1,2)\n" +msgstr "" + +#: ../../language/language.md:1921 +msgid "Trait system" +msgstr "" + +#: ../../language/language.md:1923 +msgid "" +"MoonBit features a structural trait system for overloading/ad-hoc " +"polymorphism. Traits declare a list of operations, which must be supplied" +" when a type wants to implement the trait. Traits can be declared as " +"follows:" +msgstr "" + +#: ../../language/language.md:1925 +msgid "" +"trait I {\n" +" method(...) -> ...\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1931 +msgid "" +"In the body of a trait definition, a special type `Self` is used to refer" +" to the type that implements the trait." +msgstr "" + +#: ../../language/language.md:1933 +msgid "" +"To implement a trait, a type must provide all the methods required by the" +" trait. Implementation for trait methods can be provided via the syntax " +"`impl Trait for Type with method_name(...) { ... }`, for example:" +msgstr "" + +#: ../../language/language.md:1936 +msgid "" +"trait Show {\n" +" to_string(Self) -> String\n" +"}\n" +"\n" +"struct MyType { ... }\n" +"impl Show for MyType with to_string(self) { ... }\n" +"\n" +"// trait implementation with type parameters.\n" +"// `[X : Show]` means the type parameter `X` must implement `Show`,\n" +"// this will be covered later.\n" +"impl[X : Show] Show for Array[X] with to_string(self) { ... }\n" +msgstr "" + +#: ../../language/language.md:1950 +msgid "" +"Type annotation can be omitted for trait `impl`: MoonBit will " +"automatically infer the type based on the signature of `Trait::method` " +"and the self type." +msgstr "" + +#: ../../language/language.md:1952 +msgid "" +"The author of the trait can also define default implementations for some " +"methods in the trait, for example:" +msgstr "" + +#: ../../language/language.md:1954 +msgid "" +"trait I {\n" +" f(Self) -> Unit\n" +" f_twice(Self) -> Unit\n" +"}\n" +"\n" +"impl I with f_twice(self) {\n" +" self.f()\n" +" self.f()\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1966 +msgid "" +"Implementers of trait `I` don't have to provide an implementation for " +"`f_twice`: to implement `I`, only `f` is necessary. They can always " +"override the default implementation with an explicit `impl I for Type " +"with f_twice`, if desired, though." +msgstr "" + +#: ../../language/language.md:1969 +msgid "" +"If an explicit `impl` or default implementation is not found, trait " +"method resolution falls back to regular methods. This allows types to " +"implement a trait implicitly, hence allowing different packages to work " +"together without seeing or depending on each other. For example, the " +"following trait is automatically implemented for builtin number types " +"such as `Int` and `Double`:" +msgstr "" + +#: ../../language/language.md:1973 +msgid "" +"trait Number {\n" +" op_add(Self, Self) -> Self\n" +" op_mul(Self, Self) -> Self\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1980 +msgid "" +"When declaring a generic function, the type parameters can be annotated " +"with the traits they should implement, allowing the definition of " +"constrained generic functions. For example:" +msgstr "" + +#: ../../language/language.md:1982 +msgid "" +"trait Number {\n" +" op_add(Self, Self) -> Self\n" +" op_mul(Self, Self) -> Self\n" +"}\n" +"\n" +"fn square[N: Number](x: N) -> N {\n" +" x * x // same as `x.op_mul(x)`\n" +"}\n" +msgstr "" + +#: ../../language/language.md:1993 +msgid "" +"Without the `Number` requirement, the expression `x * x` in `square` will" +" result in a method/operator not found error. Now, the function `square` " +"can be called with any type that implements `Number`, for example:" +msgstr "" + +#: ../../language/language.md:1995 +msgid "" +"fn main {\n" +" println(square(2)) // 4\n" +" println(square(1.5)) // 2.25\n" +" println(square({ x: 2, y: 3 })) // {x: 4, y: 9}\n" +"}\n" +"\n" +"trait Number {\n" +" op_add(Self, Self) -> Self\n" +" op_mul(Self, Self) -> Self\n" +"}\n" +"\n" +"fn square[N: Number](x: N) -> N {\n" +" x * x // same as `x.op_mul(x)`\n" +"}\n" +"\n" +"struct Point {\n" +" x: Int\n" +" y: Int\n" +"} derive(Show)\n" +"\n" +"impl Number for Point with op_add(p1, p2) {\n" +" { x: p1.x + p2.x, y: p1.y + p2.y }\n" +"}\n" +"\n" +"impl Number for Point with op_mul(p1, p2) {\n" +" { x: p1.x * p2.x, y: p1.y * p2.y }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:2025 +msgid "MoonBit provides the following useful builtin traits:" +msgstr "" + +#: ../../language/language.md:2027 +msgid "" +"trait Eq {\n" +" op_equal(Self, Self) -> Bool\n" +"}\n" +"\n" +"trait Compare {\n" +" // `0` for equal, `-1` for smaller, `1` for greater\n" +" op_equal(Self, Self) -> Int\n" +"}\n" +"\n" +"trait Hash {\n" +" hash(Self) -> Int\n" +"}\n" +"\n" +"trait Show {\n" +" // writes a string representation of `Self` into a `Logger`\n" +" output(Self, Logger) -> Unit\n" +" to_string(Self) -> String\n" +"}\n" +"\n" +"trait Default {\n" +" default() -> Self\n" +"}\n" +msgstr "" + +#: ../../language/language.md:2052 +msgid "Involke trait methods directly" +msgstr "" + +#: ../../language/language.md:2053 +msgid "" +"Methods of a trait can be called directly via `Trait::method`. MoonBit " +"will infer the type of `Self` and check if `Self` indeed implements " +"`Trait`, for example:" +msgstr "" + +#: ../../language/language.md:2055 +msgid "" +"fn main {\n" +" println(Show::to_string(42))\n" +" println(Compare::compare(1.0, 2.5))\n" +"}\n" +msgstr "" + +#: ../../language/language.md:2062 +msgid "" +"Trait implementations can also be involked via dot syntax, with the " +"following restrictions:" +msgstr "" + +#: ../../language/language.md:2064 +msgid "" +"if a regular method is present, the regular method is always favored when" +" using dot syntax" +msgstr "" + +#: ../../language/language.md:2065 +msgid "" +"only trait implementations that are located in the package of the self " +"type can be involked via dot syntax" +msgstr "" + +#: ../../language/language.md:2066 +msgid "" +"if there are multiple trait methods (from different traits) with the same" +" name available, an ambiguity error is reported" +msgstr "" + +#: ../../language/language.md:2067 +msgid "" +"if neither of the above two rules apply, trait `impl`s in current package" +" will also be searched for dot syntax. This allows extending a foreign " +"type locally." +msgstr "" + +#: ../../language/language.md:2069 +msgid "" +"these `impl`s can only be called via dot syntax locally, even if they are" +" public." +msgstr "" + +#: ../../language/language.md:2071 +msgid "" +"The above rules ensures that MoonBit's dot syntax enjoys good property " +"while being flexible. For example, adding a new dependency never break " +"existing code with dot syntax due to ambiguity. These rules also make " +"name resolution of MoonBit extremely simple: the method called via dot " +"syntax must always come from current package or the package of the type!" +msgstr "" + +#: ../../language/language.md:2076 +msgid "Here's an example of calling trait `impl` with dot syntax:" +msgstr "" + +#: ../../language/language.md:2078 +msgid "" +"struct MyType { ... }\n" +"\n" +"impl Show for MyType with ...\n" +"\n" +"fn main {\n" +" let x : MyType = ...\n" +" println(x.to_string()) // ok\n" +"}\n" +msgstr "" + +#: ../../language/language.md:2089 +msgid "Access control of methods and trait implementations" +msgstr "" + +#: ../../language/language.md:2091 +msgid "" +"To make the trait system coherent (i.e. there is a globally unique " +"implementation for every `Type: Trait` pair), and prevent third-party " +"packages from modifying behavior of existing programs by accident, " +"MoonBit employs the following restrictions on who can define " +"methods/implement traits for types:" +msgstr "" + +#: ../../language/language.md:2095 +msgid "" +"_only the package that defines a type can define methods for it_. So one " +"cannot define new methods or override old methods for builtin and foreign" +" types." +msgstr "" + +#: ../../language/language.md:2096 +msgid "" +"_only the package of the type or the package of the trait can define an " +"implementation_. For example, only `@pkg1` and `@pkg2` are allowed to " +"write `impl @pkg1.Trait for @pkg2.Type`." +msgstr "" + +#: ../../language/language.md:2099 +msgid "" +"The second rule above allows one to add new functionality to a foreign " +"type by defining a new trait and implementing it. This makes MoonBit's " +"trait & method system flexible while enjoying good coherence property." +msgstr "" + +#: ../../language/language.md:2102 +msgid "Visibility of traits and sealed traits" +msgstr "" + +#: ../../language/language.md:2103 +msgid "" +"There are four visibility for traits, just like `struct` and `enum`: " +"private, abstract, readonly and fully public. Private traits are declared" +" with `priv trait`, and they are completely invisible from outside. " +"Abstract trait is the default visibility. Only the name of the trait is " +"visible from outside, and the methods in the trait are not exposed. " +"Readonly traits are declared with `pub(readonly) trait`, their methods " +"can be involked from outside, but only the current package can add new " +"implementation for readonly traits. Finally, fully public traits are " +"declared with `pub(open) trait`, they are open to new implementations " +"outside current package, and their methods can be freely used. Currently," +" `pub trait` defaults to `pub(open) trait`. But in the future, the " +"semantic of `pub trait` will be ported to `pub(readonly)`." +msgstr "" + +#: ../../language/language.md:2110 +msgid "" +"Abstract and readonly traits are sealed, because only the package " +"defining the trait can implement them. Implementing a sealed (abstract or" +" readonly) trait outside its package result in compiler error. If you are" +" the owner of a sealed trait, and you want to make some implementation " +"available to users of your package, make sure there is at least one " +"declaration of the form `impl Trait for Type with ...` in your package. " +"Implementations with only regular method and default implementations will" +" not be available outside." +msgstr "" + +#: ../../language/language.md:2116 +msgid "Here's an example of abstract trait:" +msgstr "" + +#: ../../language/language.md:2118 +msgid "" +"trait Number {\n" +" op_add(Self, Self) -> Self\n" +" op_sub(Self, Self) -> Self\n" +"}\n" +"\n" +"fn add[N : Number](x : X, y: X) -> X {\n" +" Number::op_add(x, y)\n" +"}\n" +"\n" +"fn sub[N : Number](x : X, y: X) -> X {\n" +" Number::op_sub(x, y)\n" +"}\n" +"\n" +"impl Number for Int with op_add(x, y) { x + y }\n" +"impl Number for Int with op_sub(x, y) { x - y }\n" +"\n" +"impl Number for Double with op_add(x, y) { x + y }\n" +"impl Number for Double with op_sub(x, y) { x - y }\n" +msgstr "" + +#: ../../language/language.md:2139 +msgid "From outside this package, users can only see the following:" +msgstr "" + +#: ../../language/language.md:2141 +msgid "" +"trait Number\n" +"\n" +"fn op_add[N : Number](x : N, y : N) -> N\n" +"fn op_sub[N : Number](x : N, y : N) -> N\n" +"\n" +"impl Number for Int\n" +"impl Number for Double\n" +msgstr "" + +#: ../../language/language.md:2151 +msgid "" +"The author of `Number` can make use of the fact that only `Int` and " +"`Double` can ever implement `Number`, because new implementations are not" +" allowed outside." +msgstr "" + +#: ../../language/language.md:2154 +msgid "Automatically derive builtin traits" +msgstr "" + +#: ../../language/language.md:2156 +msgid "MoonBit can automatically derive implementations for some builtin traits:" +msgstr "" + +#: ../../language/language.md:2158 +msgid "" +"struct T {\n" +" x: Int\n" +" y: Int\n" +"} derive(Eq, Compare, Show, Default)\n" +"\n" +"fn main {\n" +" let t1 = T::default()\n" +" let t2 = { x: 1, y: 1 }\n" +" println(t1) // {x: 0, y: 0}\n" +" println(t2) // {x: 1, y: 1}\n" +" println(t1 == t2) // false\n" +" println(t1 < t2) // true\n" +"}\n" +msgstr "" + +#: ../../language/language.md:2174 +msgid "Trait objects" +msgstr "" + +#: ../../language/language.md:2176 +msgid "" +"MoonBit supports runtime polymorphism via trait objects. If `t` is of " +"type `T`, which implements trait `I`, one can pack the methods of `T` " +"that implements `I`, together with `t`, into a runtime object via `t as " +"I`. Trait object erases the concrete type of a value, so objects created " +"from different concrete types can be put in the same data structure and " +"handled uniformly:" +msgstr "" + +#: ../../language/language.md:2183 +msgid "" +"trait Animal {\n" +" speak(Self) -> Unit\n" +"}\n" +"\n" +"type Duck String\n" +"fn Duck::make(name: String) -> Duck { Duck(name) }\n" +"fn speak(self: Duck) -> Unit {\n" +" println(self._ + \": quack!\")\n" +"}\n" +"\n" +"type Fox String\n" +"fn Fox::make(name: String) -> Fox { Fox(name) }\n" +"fn Fox::speak(_self: Fox) -> Unit {\n" +" println(\"What does the fox say?\")\n" +"}\n" +"\n" +"fn main {\n" +" let duck1 = Duck::make(\"duck1\")\n" +" let duck2 = Duck::make(\"duck2\")\n" +" let fox1 = Fox::make(\"fox1\")\n" +" let animals = [ duck1 as Animal, duck2 as Animal, fox1 as Animal ]\n" +" let mut i = 0\n" +" while i < animals.length() {\n" +" animals[i].speak()\n" +" i = i + 1\n" +" }\n" +"}\n" +msgstr "" + +#: ../../language/language.md:2213 +msgid "" +"Not all traits can be used to create objects. \"object-safe\" traits' " +"methods must satisfy the following conditions:" +msgstr "" + +#: ../../language/language.md:2216 +msgid "`Self` must be the first parameter of a method" +msgstr "" + +#: ../../language/language.md:2217 +msgid "" +"There must be only one occurrence of `Self` in the type of the method " +"(i.e. the first parameter)" +msgstr "" + +#: ../../language/language.md:2219 +msgid "" +"Users can define new methods for trait objects, just like defining new " +"methods for structs and enums:" +msgstr "" + +#: ../../language/language.md:2221 +msgid "" +"trait Logger {\n" +" write_string(Self, String) -> Unit\n" +"}\n" +"\n" +"trait CanLog {\n" +" log(Self, Logger) -> Unit\n" +"}\n" +"\n" +"fn Logger::write_object[Obj : CanLog](self : Logger, obj : Obj) -> Unit {" +"\n" +" obj.log(self)\n" +"}\n" +"\n" +"// use the new method to simplify code\n" +"impl[A : CanLog, B : CanLog] CanLog for (A, B) with log(self, logger) {\n" +" let (a, b) = self\n" +" logger\n" +" ..write_string(\"(\")\n" +" ..write_object(a)\n" +" ..write_string(\", \")\n" +" ..write_object(b)\n" +" .write_string(\")\")\n" +"}\n" +msgstr "" + +#: ../../language/language.md:2246 +msgid "Test Blocks" +msgstr "" + +#: ../../language/language.md:2248 +msgid "MoonBit provides the test code block for writing test cases. For example:" +msgstr "" + +#: ../../language/language.md:2250 +msgid "" +"test \"test_name\" {\n" +" assert_eq!(1 + 1, 2)\n" +" assert_eq!(2 + 2, 4)\n" +"}\n" +msgstr "" + +#: ../../language/language.md:2257 +msgid "" +"A test code block is essentially a function that returns a `Unit` but may" +" throws a `String` on error, or `Unit!String` as one would see in its " +"signature at the position of return type. It is called during the " +"execution of `moon test` and outputs a test report through the build " +"system. The `assert_eq` function is from the standard library; if the " +"assertion fails, it prints an error message and terminates the test. The " +"string `\"test_name\"` is used to identify the test case and is optional." +" If it starts with `\"panic\"`, it indicates that the expected behavior " +"of the test is to trigger a panic, and the test will only pass if the " +"panic is triggered. For example:" +msgstr "" + +#: ../../language/language.md:2259 +msgid "" +"test \"panic_test\" {\n" +" let _ : Int = Option::None.unwrap()\n" +"}\n" +msgstr "" + +#: ../../language/language.md:2265 +msgid "Doc Comments" +msgstr "" + +#: ../../language/language.md:2267 +msgid "" +"Doc comments are comments prefix with `///` in each line in the leading " +"of toplevel structure like `fn`,`let`,`enum`,`struct`,`type`. The doc " +"comments contains a markdown text and several pragmas." +msgstr "" + +#: ../../language/language.md:2269 +msgid "" +"/// Return a new array with reversed elements.\n" +"///\n" +"/// # Example\n" +"///\n" +"/// ```\n" +"/// reverse([1,2,3,4]) |> println()\n" +"/// ```\n" +"fn reverse[T](xs : Array[T]) -> Array[T] {\n" +" ...\n" +"}\n" +msgstr "" + +#: ../../language/language.md:2282 +msgid "Pragmas" +msgstr "" + +#: ../../language/language.md:2284 +msgid "" +"Pragmas are annotations inside doc comments. They all take the form `/// " +"@word ...`. The _word_ indicates the type of pragma and is followed " +"optionally by several _word_ or string literals. Pragmas do not normally " +"affect the meaning of programs. Unrecognized pragmas will be reported as " +"warnings." +msgstr "" + +#: ../../language/language.md:2286 +msgid "Alert Pragmas" +msgstr "" + +#: ../../language/language.md:2288 +msgid "" +"Alert pragmas in doc comments of functions will be reported when those " +"functions are referenced. This mechanism is a generalized way to mark " +"functions as `deprecated` or `unsafe`." +msgstr "" + +#: ../../language/language.md:2290 +msgid "It takes the form `@alert category \"alert message...\"`." +msgstr "" + +#: ../../language/language.md:2292 +msgid "" +"The category can be an arbitrary identifier. It allows configuration to " +"decide which alerts are enabled or turned into errors." +msgstr "" + +#: ../../language/language.md:2294 +msgid "" +"/// @alert deprecated \"Use foo2 instead\"\n" +"pub fn foo() -> Unit { ... }\n" +"\n" +"/// @alert unsafe \"Div will cause an error when y is zero\"\n" +"pub fn div(x: Int, y: Int) -> Int { ... }\n" +"\n" +"fn main {\n" +" foo() // warning: Use foo2 instead\n" +" div(x, y) |> ignore // warning: Div will cause an error when y is zero\n" +"}\n" +msgstr "" + +#: ../../language/language.md:2307 +msgid "Special Syntax" +msgstr "" + +#: ../../language/language.md:2309 +msgid "TODO syntax" +msgstr "" + +#: ../../language/language.md:2311 +msgid "" +"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:" +msgstr "" + +#: ../../language/language.md:2313 +msgid "" +"fn todo_in_func() -> Int {\n" +" ...\n" +"}\n" +msgstr "" + +#~ msgid "Grammar" +#~ msgstr "" + +#~ msgid "Here's some MoonBit grammar:" +#~ msgstr "" + diff --git a/next/locales/zh_CN/LC_MESSAGES/toolchain.po b/next/locales/zh_CN/LC_MESSAGES/toolchain.po new file mode 100644 index 00000000..81106ce7 --- /dev/null +++ b/next/locales/zh_CN/LC_MESSAGES/toolchain.po @@ -0,0 +1,2690 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2024, International Digital Economy Academy +# This file is distributed under the same license as the MoonBit Document +# package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: MoonBit Document \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-11-27 13:35+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.16.0\n" + +#: ../../toolchain/index.md:9 ../../toolchain/moon/index.md:3 +msgid "Contents:" +msgstr "" + +#: ../../toolchain/index.md:1 +msgid "Toolchains" +msgstr "" + +#: ../../toolchain/index.md:3 +msgid "" +"Here are some manuals that may help you use the toolchains of the " +"programming language:" +msgstr "" + +#: ../../toolchain/index.md:5 +msgid "" +"[MoonBit's Build System](./moon/index.md): full manual of `moon` build " +"system." +msgstr "" + +#: ../../toolchain/index.md:6 +msgid "VSCode extension" +msgstr "" + +#: ../../toolchain/index.md:7 +msgid "..." +msgstr "" + +#: ../../toolchain/moon/commands.md:1 +msgid "Command-Line Help for `moon`" +msgstr "" + +#: ../../toolchain/moon/commands.md:3 +msgid "" +"This document contains the help content for the `moon` command-line " +"program." +msgstr "" + +#: ../../toolchain/moon/commands.md:5 +msgid "**Command Overview:**" +msgstr "" + +#: ../../toolchain/moon/commands.md:7 +msgid "[`moon`↴](#moon)" +msgstr "" + +#: ../../toolchain/moon/commands.md:8 +msgid "[`moon new`↴](#moon-new)" +msgstr "" + +#: ../../toolchain/moon/commands.md:9 +msgid "[`moon build`↴](#moon-build)" +msgstr "" + +#: ../../toolchain/moon/commands.md:10 +msgid "[`moon check`↴](#moon-check)" +msgstr "" + +#: ../../toolchain/moon/commands.md:11 +msgid "[`moon run`↴](#moon-run)" +msgstr "" + +#: ../../toolchain/moon/commands.md:12 +msgid "[`moon test`↴](#moon-test)" +msgstr "" + +#: ../../toolchain/moon/commands.md:13 +msgid "[`moon clean`↴](#moon-clean)" +msgstr "" + +#: ../../toolchain/moon/commands.md:14 +msgid "[`moon fmt`↴](#moon-fmt)" +msgstr "" + +#: ../../toolchain/moon/commands.md:15 +msgid "[`moon doc`↴](#moon-doc)" +msgstr "" + +#: ../../toolchain/moon/commands.md:16 +msgid "[`moon info`↴](#moon-info)" +msgstr "" + +#: ../../toolchain/moon/commands.md:17 +msgid "[`moon add`↴](#moon-add)" +msgstr "" + +#: ../../toolchain/moon/commands.md:18 +msgid "[`moon remove`↴](#moon-remove)" +msgstr "" + +#: ../../toolchain/moon/commands.md:19 +msgid "[`moon install`↴](#moon-install)" +msgstr "" + +#: ../../toolchain/moon/commands.md:20 +msgid "[`moon tree`↴](#moon-tree)" +msgstr "" + +#: ../../toolchain/moon/commands.md:21 +msgid "[`moon login`↴](#moon-login)" +msgstr "" + +#: ../../toolchain/moon/commands.md:22 +msgid "[`moon register`↴](#moon-register)" +msgstr "" + +#: ../../toolchain/moon/commands.md:23 +msgid "[`moon publish`↴](#moon-publish)" +msgstr "" + +#: ../../toolchain/moon/commands.md:24 +msgid "[`moon package`↴](#moon-package)" +msgstr "" + +#: ../../toolchain/moon/commands.md:25 +msgid "[`moon update`↴](#moon-update)" +msgstr "" + +#: ../../toolchain/moon/commands.md:26 +msgid "[`moon coverage`↴](#moon-coverage)" +msgstr "" + +#: ../../toolchain/moon/commands.md:27 +msgid "[`moon coverage report`↴](#moon-coverage-report)" +msgstr "" + +#: ../../toolchain/moon/commands.md:28 +msgid "[`moon coverage clean`↴](#moon-coverage-clean)" +msgstr "" + +#: ../../toolchain/moon/commands.md:29 +msgid "[`moon generate-build-matrix`↴](#moon-generate-build-matrix)" +msgstr "" + +#: ../../toolchain/moon/commands.md:30 +msgid "[`moon upgrade`↴](#moon-upgrade)" +msgstr "" + +#: ../../toolchain/moon/commands.md:31 +msgid "[`moon shell-completion`↴](#moon-shell-completion)" +msgstr "" + +#: ../../toolchain/moon/commands.md:32 +msgid "[`moon version`↴](#moon-version)" +msgstr "" + +#: ../../toolchain/moon/commands.md:34 +msgid "`moon`" +msgstr "" + +#: ../../toolchain/moon/commands.md:36 +msgid "**Usage:** `moon `" +msgstr "" + +#: ../../toolchain/moon/commands.md:38 ../../toolchain/moon/commands.md:376 +msgid "**Subcommands:**" +msgstr "" + +#: ../../toolchain/moon/commands.md:40 +msgid "`new` — Create a new MoonBit module" +msgstr "" + +#: ../../toolchain/moon/commands.md:41 +msgid "`build` — Build the current package" +msgstr "" + +#: ../../toolchain/moon/commands.md:42 +msgid "`check` — Check the current package, but don't build object files" +msgstr "" + +#: ../../toolchain/moon/commands.md:43 +msgid "`run` — Run a main package" +msgstr "" + +#: ../../toolchain/moon/commands.md:44 +msgid "`test` — Test the current package" +msgstr "" + +#: ../../toolchain/moon/commands.md:45 +msgid "`clean` — Remove the target directory" +msgstr "" + +#: ../../toolchain/moon/commands.md:46 +msgid "`fmt` — Format source code" +msgstr "" + +#: ../../toolchain/moon/commands.md:47 +msgid "`doc` — Generate documentation" +msgstr "" + +#: ../../toolchain/moon/commands.md:48 +msgid "" +"`info` — Generate public interface (`.mbti`) files for all packages in " +"the module" +msgstr "" + +#: ../../toolchain/moon/commands.md:49 +msgid "`add` — Add a dependency" +msgstr "" + +#: ../../toolchain/moon/commands.md:50 +msgid "`remove` — Remove a dependency" +msgstr "" + +#: ../../toolchain/moon/commands.md:51 +msgid "`install` — Install dependencies" +msgstr "" + +#: ../../toolchain/moon/commands.md:52 +msgid "`tree` — Display the dependency tree" +msgstr "" + +#: ../../toolchain/moon/commands.md:53 +msgid "`login` — Log in to your account" +msgstr "" + +#: ../../toolchain/moon/commands.md:54 +msgid "`register` — Register an account at mooncakes.io" +msgstr "" + +#: ../../toolchain/moon/commands.md:55 +msgid "`publish` — Publish the current module" +msgstr "" + +#: ../../toolchain/moon/commands.md:56 +msgid "`package` — Package the current module" +msgstr "" + +#: ../../toolchain/moon/commands.md:57 +msgid "`update` — Update the package registry index" +msgstr "" + +#: ../../toolchain/moon/commands.md:58 +msgid "`coverage` — Code coverage utilities" +msgstr "" + +#: ../../toolchain/moon/commands.md:59 +msgid "" +"`generate-build-matrix` — Generate build matrix for benchmarking (legacy " +"feature)" +msgstr "" + +#: ../../toolchain/moon/commands.md:60 +msgid "`upgrade` — Upgrade toolchains" +msgstr "" + +#: ../../toolchain/moon/commands.md:61 +msgid "" +"`shell-completion` — Generate shell completion for " +"bash/elvish/fish/pwsh/zsh to stdout" +msgstr "" + +#: ../../toolchain/moon/commands.md:62 +msgid "`version` — Print version information and exit" +msgstr "" + +#: ../../toolchain/moon/commands.md:66 +msgid "`moon new`" +msgstr "" + +#: ../../toolchain/moon/commands.md:68 +msgid "Create a new MoonBit module" +msgstr "" + +#: ../../toolchain/moon/commands.md:70 +msgid "**Usage:** `moon new [OPTIONS] [PACKAGE_NAME]`" +msgstr "" + +#: ../../toolchain/moon/commands.md:72 ../../toolchain/moon/commands.md:122 +#: ../../toolchain/moon/commands.md:156 ../../toolchain/moon/commands.md:234 +#: ../../toolchain/moon/commands.md:287 ../../toolchain/moon/commands.md:299 +#: ../../toolchain/moon/commands.md:389 +msgid "**Arguments:**" +msgstr "" + +#: ../../toolchain/moon/commands.md:74 +msgid "`` — The name of the package" +msgstr "" + +#: ../../toolchain/moon/commands.md:76 ../../toolchain/moon/commands.md:95 +#: ../../toolchain/moon/commands.md:126 ../../toolchain/moon/commands.md:161 +#: ../../toolchain/moon/commands.md:188 ../../toolchain/moon/commands.md:238 +#: ../../toolchain/moon/commands.md:255 ../../toolchain/moon/commands.md:274 +#: ../../toolchain/moon/commands.md:343 ../../toolchain/moon/commands.md:355 +#: ../../toolchain/moon/commands.md:393 ../../toolchain/moon/commands.md:413 +#: ../../toolchain/moon/commands.md:430 ../../toolchain/moon/commands.md:575 +#: ../../toolchain/moon/commands.md:592 +msgid "**Options:**" +msgstr "" + +#: ../../toolchain/moon/commands.md:78 +msgid "`--lib` — Create a library package instead of an executable" +msgstr "" + +#: ../../toolchain/moon/commands.md:79 +msgid "`--path ` — Output path of the package" +msgstr "" + +#: ../../toolchain/moon/commands.md:80 +msgid "`--user ` — The user name of the package" +msgstr "" + +#: ../../toolchain/moon/commands.md:81 +msgid "`--name ` — The name part of the package" +msgstr "" + +#: ../../toolchain/moon/commands.md:82 +msgid "`--license ` — The license of the package" +msgstr "" + +#: ../../toolchain/moon/commands.md:84 +msgid "Default value: `Apache-2.0`" +msgstr "" + +#: ../../toolchain/moon/commands.md:85 +msgid "`--no-license` — Do not set a license for the package" +msgstr "" + +#: ../../toolchain/moon/commands.md:89 +msgid "`moon build`" +msgstr "" + +#: ../../toolchain/moon/commands.md:91 +msgid "Build the current package" +msgstr "" + +#: ../../toolchain/moon/commands.md:93 +msgid "**Usage:** `moon build [OPTIONS]`" +msgstr "" + +#: ../../toolchain/moon/commands.md:97 ../../toolchain/moon/commands.md:128 +#: ../../toolchain/moon/commands.md:163 ../../toolchain/moon/commands.md:190 +msgid "`--std` — Enable the standard library (default)" +msgstr "" + +#: ../../toolchain/moon/commands.md:98 ../../toolchain/moon/commands.md:129 +#: ../../toolchain/moon/commands.md:164 ../../toolchain/moon/commands.md:191 +msgid "`--nostd` — Disable the standard library" +msgstr "" + +#: ../../toolchain/moon/commands.md:99 ../../toolchain/moon/commands.md:130 +#: ../../toolchain/moon/commands.md:165 ../../toolchain/moon/commands.md:192 +msgid "`-g`, `--debug` — Emit debug information" +msgstr "" + +#: ../../toolchain/moon/commands.md:100 ../../toolchain/moon/commands.md:131 +#: ../../toolchain/moon/commands.md:166 ../../toolchain/moon/commands.md:193 +msgid "`--release` — Compile in release mode" +msgstr "" + +#: ../../toolchain/moon/commands.md:101 ../../toolchain/moon/commands.md:132 +#: ../../toolchain/moon/commands.md:167 ../../toolchain/moon/commands.md:194 +msgid "`--target ` — Select output target" +msgstr "" + +#: ../../toolchain/moon/commands.md:103 ../../toolchain/moon/commands.md:134 +#: ../../toolchain/moon/commands.md:169 ../../toolchain/moon/commands.md:196 +msgid "Possible values: `wasm`, `wasm-gc`, `js`, `native`, `all`" +msgstr "" + +#: ../../toolchain/moon/commands.md:105 ../../toolchain/moon/commands.md:136 +#: ../../toolchain/moon/commands.md:171 ../../toolchain/moon/commands.md:198 +msgid "`--serial` — Handle the selected targets sequentially" +msgstr "" + +#: ../../toolchain/moon/commands.md:106 ../../toolchain/moon/commands.md:137 +#: ../../toolchain/moon/commands.md:172 ../../toolchain/moon/commands.md:199 +msgid "`--enable-coverage` — Enable coverage instrumentation" +msgstr "" + +#: ../../toolchain/moon/commands.md:107 ../../toolchain/moon/commands.md:138 +#: ../../toolchain/moon/commands.md:173 ../../toolchain/moon/commands.md:200 +#: ../../toolchain/moon/commands.md:241 +msgid "`--sort-input` — Sort input files" +msgstr "" + +#: ../../toolchain/moon/commands.md:108 ../../toolchain/moon/commands.md:139 +#: ../../toolchain/moon/commands.md:174 ../../toolchain/moon/commands.md:201 +msgid "`--output-wat` — Output WAT instead of WASM" +msgstr "" + +#: ../../toolchain/moon/commands.md:109 ../../toolchain/moon/commands.md:140 +#: ../../toolchain/moon/commands.md:175 ../../toolchain/moon/commands.md:202 +msgid "`-d`, `--deny-warn` — Treat all warnings as errors" +msgstr "" + +#: ../../toolchain/moon/commands.md:110 ../../toolchain/moon/commands.md:141 +#: ../../toolchain/moon/commands.md:176 ../../toolchain/moon/commands.md:203 +msgid "" +"`--no-render` — Don't render diagnostics from moonc (don't pass '-error-" +"format json' to moonc)" +msgstr "" + +#: ../../toolchain/moon/commands.md:111 ../../toolchain/moon/commands.md:143 +#: ../../toolchain/moon/commands.md:177 ../../toolchain/moon/commands.md:211 +#: ../../toolchain/moon/commands.md:264 ../../toolchain/moon/commands.md:276 +#: ../../toolchain/moon/commands.md:345 ../../toolchain/moon/commands.md:357 +msgid "" +"`--frozen` — Do not sync dependencies, assuming local dependencies are " +"up-to-date" +msgstr "" + +#: ../../toolchain/moon/commands.md:112 +msgid "" +"`-w`, `--watch` — Monitor the file system and automatically build " +"artifacts" +msgstr "" + +#: ../../toolchain/moon/commands.md:116 +msgid "`moon check`" +msgstr "" + +#: ../../toolchain/moon/commands.md:118 +msgid "Check the current package, but don't build object files" +msgstr "" + +#: ../../toolchain/moon/commands.md:120 +msgid "**Usage:** `moon check [OPTIONS] [PACKAGE_PATH]`" +msgstr "" + +#: ../../toolchain/moon/commands.md:124 +msgid "`` — The package(and it's deps) to check" +msgstr "" + +#: ../../toolchain/moon/commands.md:142 +msgid "`--output-json` — Output in json format" +msgstr "" + +#: ../../toolchain/moon/commands.md:144 +msgid "`-w`, `--watch` — Monitor the file system and automatically check files" +msgstr "" + +#: ../../toolchain/moon/commands.md:145 +msgid "" +"`--patch-file ` — The patch file to check, Only valid when " +"checking specified package" +msgstr "" + +#: ../../toolchain/moon/commands.md:146 +msgid "" +"`--no-mi` — Whether to skip the mi generation, Only valid when checking " +"specified package" +msgstr "" + +#: ../../toolchain/moon/commands.md:150 +msgid "`moon run`" +msgstr "" + +#: ../../toolchain/moon/commands.md:152 +msgid "Run a main package" +msgstr "" + +#: ../../toolchain/moon/commands.md:154 +msgid "**Usage:** `moon run [OPTIONS] [ARGS]...`" +msgstr "" + +#: ../../toolchain/moon/commands.md:158 +msgid "`` — The package or .mbt file to run" +msgstr "" + +#: ../../toolchain/moon/commands.md:159 +msgid "`` — The arguments provided to the program to be run" +msgstr "" + +#: ../../toolchain/moon/commands.md:178 +msgid "`--build-only` — Only build, do not run the code" +msgstr "" + +#: ../../toolchain/moon/commands.md:182 +msgid "`moon test`" +msgstr "" + +#: ../../toolchain/moon/commands.md:184 +msgid "Test the current package" +msgstr "" + +#: ../../toolchain/moon/commands.md:186 +msgid "**Usage:** `moon test [OPTIONS]`" +msgstr "" + +#: ../../toolchain/moon/commands.md:204 +msgid "`-p`, `--package ` — Run test in the specified package" +msgstr "" + +#: ../../toolchain/moon/commands.md:205 +msgid "" +"`-f`, `--file ` — Run test in the specified file. Only valid when " +"`--package` is also specified" +msgstr "" + +#: ../../toolchain/moon/commands.md:206 +msgid "" +"`-i`, `--index ` — Run only the index-th test in the file. Only " +"valid when `--file` is also specified" +msgstr "" + +#: ../../toolchain/moon/commands.md:207 +msgid "`-u`, `--update` — Update the test snapshot" +msgstr "" + +#: ../../toolchain/moon/commands.md:208 +msgid "" +"`-l`, `--limit ` — Limit of expect test update passes to run, in " +"order to avoid infinite loops" +msgstr "" + +#: ../../toolchain/moon/commands.md:210 +msgid "Default value: `256`" +msgstr "" + +#: ../../toolchain/moon/commands.md:212 +msgid "`--build-only` — Only build, do not run the tests" +msgstr "" + +#: ../../toolchain/moon/commands.md:213 +msgid "`--no-parallelize` — Run the tests in a target backend sequentially" +msgstr "" + +#: ../../toolchain/moon/commands.md:214 +msgid "`--test-failure-json` — Print failure message in JSON format" +msgstr "" + +#: ../../toolchain/moon/commands.md:215 +msgid "`--patch-file ` — Path to the patch file" +msgstr "" + +#: ../../toolchain/moon/commands.md:216 +msgid "`--doc` — Run doc test" +msgstr "" + +#: ../../toolchain/moon/commands.md:220 +msgid "`moon clean`" +msgstr "" + +#: ../../toolchain/moon/commands.md:222 +msgid "Remove the target directory" +msgstr "" + +#: ../../toolchain/moon/commands.md:224 +msgid "**Usage:** `moon clean`" +msgstr "" + +#: ../../toolchain/moon/commands.md:228 +msgid "`moon fmt`" +msgstr "" + +#: ../../toolchain/moon/commands.md:230 +msgid "Format source code" +msgstr "" + +#: ../../toolchain/moon/commands.md:232 +msgid "**Usage:** `moon fmt [OPTIONS] [ARGS]...`" +msgstr "" + +#: ../../toolchain/moon/commands.md:236 +msgid "``" +msgstr "" + +#: ../../toolchain/moon/commands.md:240 +msgid "`--check` — Check only and don't change the source code" +msgstr "" + +#: ../../toolchain/moon/commands.md:242 +msgid "`--block-style ` — Add separator between each segments" +msgstr "" + +#: ../../toolchain/moon/commands.md:244 +msgid "Possible values: `false`, `true`" +msgstr "" + +#: ../../toolchain/moon/commands.md:249 +msgid "`moon doc`" +msgstr "" + +#: ../../toolchain/moon/commands.md:251 +msgid "Generate documentation" +msgstr "" + +#: ../../toolchain/moon/commands.md:253 +msgid "**Usage:** `moon doc [OPTIONS]`" +msgstr "" + +#: ../../toolchain/moon/commands.md:257 +msgid "`--serve` — Start a web server to serve the documentation" +msgstr "" + +#: ../../toolchain/moon/commands.md:258 +msgid "`-b`, `--bind ` — The address of the server" +msgstr "" + +#: ../../toolchain/moon/commands.md:260 +msgid "Default value: `127.0.0.1`" +msgstr "" + +#: ../../toolchain/moon/commands.md:261 +msgid "`-p`, `--port ` — The port of the server" +msgstr "" + +#: ../../toolchain/moon/commands.md:263 +msgid "Default value: `3000`" +msgstr "" + +#: ../../toolchain/moon/commands.md:268 +msgid "`moon info`" +msgstr "" + +#: ../../toolchain/moon/commands.md:270 +msgid "Generate public interface (`.mbti`) files for all packages in the module" +msgstr "" + +#: ../../toolchain/moon/commands.md:272 +msgid "**Usage:** `moon info [OPTIONS]`" +msgstr "" + +#: ../../toolchain/moon/commands.md:277 +msgid "`--no-alias` — Do not use alias to shorten package names in the output" +msgstr "" + +#: ../../toolchain/moon/commands.md:281 +msgid "`moon add`" +msgstr "" + +#: ../../toolchain/moon/commands.md:283 +msgid "Add a dependency" +msgstr "" + +#: ../../toolchain/moon/commands.md:285 +msgid "**Usage:** `moon add `" +msgstr "" + +#: ../../toolchain/moon/commands.md:289 +msgid "`` — The package path to add" +msgstr "" + +#: ../../toolchain/moon/commands.md:293 +msgid "`moon remove`" +msgstr "" + +#: ../../toolchain/moon/commands.md:295 +msgid "Remove a dependency" +msgstr "" + +#: ../../toolchain/moon/commands.md:297 +msgid "**Usage:** `moon remove `" +msgstr "" + +#: ../../toolchain/moon/commands.md:301 +msgid "`` — The package path to remove" +msgstr "" + +#: ../../toolchain/moon/commands.md:305 +msgid "`moon install`" +msgstr "" + +#: ../../toolchain/moon/commands.md:307 +msgid "Install dependencies" +msgstr "" + +#: ../../toolchain/moon/commands.md:309 +msgid "**Usage:** `moon install`" +msgstr "" + +#: ../../toolchain/moon/commands.md:313 +msgid "`moon tree`" +msgstr "" + +#: ../../toolchain/moon/commands.md:315 +msgid "Display the dependency tree" +msgstr "" + +#: ../../toolchain/moon/commands.md:317 +msgid "**Usage:** `moon tree`" +msgstr "" + +#: ../../toolchain/moon/commands.md:321 +msgid "`moon login`" +msgstr "" + +#: ../../toolchain/moon/commands.md:323 +msgid "Log in to your account" +msgstr "" + +#: ../../toolchain/moon/commands.md:325 +msgid "**Usage:** `moon login`" +msgstr "" + +#: ../../toolchain/moon/commands.md:329 +msgid "`moon register`" +msgstr "" + +#: ../../toolchain/moon/commands.md:331 +msgid "Register an account at mooncakes.io" +msgstr "" + +#: ../../toolchain/moon/commands.md:333 +msgid "**Usage:** `moon register`" +msgstr "" + +#: ../../toolchain/moon/commands.md:337 +msgid "`moon publish`" +msgstr "" + +#: ../../toolchain/moon/commands.md:339 +msgid "Publish the current module" +msgstr "" + +#: ../../toolchain/moon/commands.md:341 +msgid "**Usage:** `moon publish [OPTIONS]`" +msgstr "" + +#: ../../toolchain/moon/commands.md:349 +msgid "`moon package`" +msgstr "" + +#: ../../toolchain/moon/commands.md:351 +msgid "Package the current module" +msgstr "" + +#: ../../toolchain/moon/commands.md:353 +msgid "**Usage:** `moon package [OPTIONS]`" +msgstr "" + +#: ../../toolchain/moon/commands.md:358 +msgid "`--list`" +msgstr "" + +#: ../../toolchain/moon/commands.md:362 +msgid "`moon update`" +msgstr "" + +#: ../../toolchain/moon/commands.md:364 +msgid "Update the package registry index" +msgstr "" + +#: ../../toolchain/moon/commands.md:366 +msgid "**Usage:** `moon update`" +msgstr "" + +#: ../../toolchain/moon/commands.md:370 +msgid "`moon coverage`" +msgstr "" + +#: ../../toolchain/moon/commands.md:372 +msgid "Code coverage utilities" +msgstr "" + +#: ../../toolchain/moon/commands.md:374 +msgid "**Usage:** `moon coverage `" +msgstr "" + +#: ../../toolchain/moon/commands.md:378 +msgid "`report` — Generate code coverage report" +msgstr "" + +#: ../../toolchain/moon/commands.md:379 +msgid "`clean` — Clean up coverage artifacts" +msgstr "" + +#: ../../toolchain/moon/commands.md:383 +msgid "`moon coverage report`" +msgstr "" + +#: ../../toolchain/moon/commands.md:385 +msgid "Generate code coverage report" +msgstr "" + +#: ../../toolchain/moon/commands.md:387 +msgid "**Usage:** `moon coverage report [args]... [COMMAND]`" +msgstr "" + +#: ../../toolchain/moon/commands.md:391 +msgid "`` — Arguments to pass to the coverage utility" +msgstr "" + +#: ../../toolchain/moon/commands.md:395 +msgid "`-h`, `--help` — Show help for the coverage utility" +msgstr "" + +#: ../../toolchain/moon/commands.md:399 +msgid "`moon coverage clean`" +msgstr "" + +#: ../../toolchain/moon/commands.md:401 +msgid "Clean up coverage artifacts" +msgstr "" + +#: ../../toolchain/moon/commands.md:403 +msgid "**Usage:** `moon coverage clean`" +msgstr "" + +#: ../../toolchain/moon/commands.md:407 +msgid "`moon generate-build-matrix`" +msgstr "" + +#: ../../toolchain/moon/commands.md:409 +msgid "Generate build matrix for benchmarking (legacy feature)" +msgstr "" + +#: ../../toolchain/moon/commands.md:411 +msgid "**Usage:** `moon generate-build-matrix [OPTIONS] --output-dir `" +msgstr "" + +#: ../../toolchain/moon/commands.md:415 +msgid "" +"`-n ` — Set all of `drow`, `dcol`, `mrow`, `mcol` to the same " +"value" +msgstr "" + +#: ../../toolchain/moon/commands.md:416 +msgid "`--drow ` — Number of directory rows" +msgstr "" + +#: ../../toolchain/moon/commands.md:417 +msgid "`--dcol ` — Number of directory columns" +msgstr "" + +#: ../../toolchain/moon/commands.md:418 +msgid "`--mrow ` — Number of module rows" +msgstr "" + +#: ../../toolchain/moon/commands.md:419 +msgid "`--mcol ` — Number of module columns" +msgstr "" + +#: ../../toolchain/moon/commands.md:420 +msgid "`-o`, `--output-dir ` — The output directory" +msgstr "" + +#: ../../toolchain/moon/commands.md:424 +msgid "`moon upgrade`" +msgstr "" + +#: ../../toolchain/moon/commands.md:426 +msgid "Upgrade toolchains" +msgstr "" + +#: ../../toolchain/moon/commands.md:428 +msgid "**Usage:** `moon upgrade [OPTIONS]`" +msgstr "" + +#: ../../toolchain/moon/commands.md:432 +msgid "`-f`, `--force` — Force upgrade" +msgstr "" + +#: ../../toolchain/moon/commands.md:436 +msgid "`moon shell-completion`" +msgstr "" + +#: ../../toolchain/moon/commands.md:438 +msgid "Generate shell completion for bash/elvish/fish/pwsh/zsh to stdout" +msgstr "" + +#: ../../toolchain/moon/commands.md:440 +msgid "**Usage:** `moon shell-completion [OPTIONS]`" +msgstr "" + +#: ../../toolchain/moon/commands.md:443 +msgid "" +"Discussion: Enable tab completion for Bash, Elvish, Fish, Zsh, or " +"PowerShell The script is output on `stdout`, allowing one to re-direct " +"the output to the file of their choosing. Where you place the file will " +"depend on which shell, and which operating system you are using. Your " +"particular configuration may also determine where these scripts need to " +"be placed." +msgstr "" + +#: ../../toolchain/moon/commands.md:451 +msgid "" +"The completion scripts won't update itself, so you may need to " +"periodically run this command to get the latest completions. Or you may " +"put `eval \"$(moon shell-completion --shell )\"` in your shell's " +"rc file to always load newest completions on startup. Although it's " +"considered not as efficient as having the completions script installed." +msgstr "" + +#: ../../toolchain/moon/commands.md:458 +msgid "" +"Here are some common set ups for the three supported shells under Unix " +"and similar operating systems (such as GNU/Linux)." +msgstr "" + +#: ../../toolchain/moon/commands.md:461 +msgid "Bash:" +msgstr "" + +#: ../../toolchain/moon/commands.md:463 +msgid "" +"Completion files are commonly stored in `/etc/bash_completion.d/` for " +"system-wide commands, but can be stored in `~/.local/share/bash-" +"completion/completions` for user-specific commands. Run the command:" +msgstr "" + +#: ../../toolchain/moon/commands.md:468 +msgid "" +"$ mkdir -p ~/.local/share/bash-completion/completions\n" +"$ moon shell-completion --shell bash >> ~/.local/share/bash-" +"completion/completions/moon\n" +msgstr "" + +#: ../../toolchain/moon/commands.md:471 ../../toolchain/moon/commands.md:490 +msgid "" +"This installs the completion script. You may have to log out and log back" +" in to your shell session for the changes to take effect." +msgstr "" + +#: ../../toolchain/moon/commands.md:474 +msgid "Bash (macOS/Homebrew):" +msgstr "" + +#: ../../toolchain/moon/commands.md:476 +msgid "" +"Homebrew stores bash completion files within the Homebrew directory. With" +" the `bash-completion` brew formula installed, run the command:" +msgstr "" + +#: ../../toolchain/moon/commands.md:479 +msgid "" +"$ mkdir -p $(brew --prefix)/etc/bash_completion.d\n" +"$ moon shell-completion --shell bash > $(brew " +"--prefix)/etc/bash_completion.d/moon.bash-completion\n" +msgstr "" + +#: ../../toolchain/moon/commands.md:482 +msgid "Fish:" +msgstr "" + +#: ../../toolchain/moon/commands.md:484 +msgid "" +"Fish completion files are commonly stored in " +"`$HOME/.config/fish/completions`. Run the command:" +msgstr "" + +#: ../../toolchain/moon/commands.md:487 +msgid "" +"$ mkdir -p ~/.config/fish/completions\n" +"$ moon shell-completion --shell fish > " +"~/.config/fish/completions/moon.fish\n" +msgstr "" + +#: ../../toolchain/moon/commands.md:493 +msgid "Elvish:" +msgstr "" + +#: ../../toolchain/moon/commands.md:495 +msgid "" +"Elvish completions are commonly stored in a single `completers` module. A" +" typical module search path is `~/.config/elvish/lib`, and running the " +"command:" +msgstr "" + +#: ../../toolchain/moon/commands.md:499 +msgid "" +"$ moon shell-completion --shell elvish >> " +"~/.config/elvish/lib/completers.elv\n" +msgstr "" + +#: ../../toolchain/moon/commands.md:501 +msgid "" +"will install the completions script. Note that use `>>` (append) instead" +" of `>` (overwrite) to prevent overwriting the existing completions for " +"other commands. Then prepend your rc.elv with:" +msgstr "" + +#: ../../toolchain/moon/commands.md:505 +msgid "`use completers`\n" +msgstr "" + +#: ../../toolchain/moon/commands.md:507 +msgid "to load the `completers` module and enable completions." +msgstr "" + +#: ../../toolchain/moon/commands.md:509 +msgid "Zsh:" +msgstr "" + +#: ../../toolchain/moon/commands.md:511 +msgid "" +"ZSH completions are commonly stored in any directory listed in your " +"`$fpath` variable. To use these completions, you must either add the " +"generated script to one of those directories, or add your own to this " +"list." +msgstr "" + +#: ../../toolchain/moon/commands.md:516 +msgid "" +"Adding a custom directory is often the safest bet if you are unsure of " +"which directory to use. First create the directory; for this example " +"we'll create a hidden directory inside our `$HOME` directory:" +msgstr "" + +#: ../../toolchain/moon/commands.md:521 +msgid "$ mkdir ~/.zfunc\n" +msgstr "" + +#: ../../toolchain/moon/commands.md:523 +msgid "Then add the following lines to your `.zshrc` just before `compinit`:" +msgstr "" + +#: ../../toolchain/moon/commands.md:526 +msgid "fpath+=~/.zfunc\n" +msgstr "" + +#: ../../toolchain/moon/commands.md:528 +msgid "Now you can install the completions script using the following command:" +msgstr "" + +#: ../../toolchain/moon/commands.md:531 +msgid "$ moon shell-completion --shell zsh > ~/.zfunc/_moon\n" +msgstr "" + +#: ../../toolchain/moon/commands.md:533 +msgid "You must then open a new zsh session, or simply run" +msgstr "" + +#: ../../toolchain/moon/commands.md:535 +msgid "$ . ~/.zshrc\n" +msgstr "" + +#: ../../toolchain/moon/commands.md:537 +msgid "for the new completions to take effect." +msgstr "" + +#: ../../toolchain/moon/commands.md:539 +msgid "Custom locations:" +msgstr "" + +#: ../../toolchain/moon/commands.md:541 +msgid "" +"Alternatively, you could save these files to the place of your choosing, " +"such as a custom directory inside your $HOME. Doing so will require you " +"to add the proper directives, such as `source`ing inside your login " +"script. Consult your shells documentation for how to add such directives." +msgstr "" + +#: ../../toolchain/moon/commands.md:547 +msgid "PowerShell:" +msgstr "" + +#: ../../toolchain/moon/commands.md:549 +msgid "" +"The powershell completion scripts require PowerShell v5.0+ (which comes " +"with Windows 10, but can be downloaded separately for windows 7 or 8.1)." +msgstr "" + +#: ../../toolchain/moon/commands.md:553 +msgid "First, check if a profile has already been set" +msgstr "" + +#: ../../toolchain/moon/commands.md:555 +msgid "PS C:\\> Test-Path $profile\n" +msgstr "" + +#: ../../toolchain/moon/commands.md:557 +msgid "If the above command returns `False` run the following" +msgstr "" + +#: ../../toolchain/moon/commands.md:559 +msgid "PS C:\\> New-Item -path $profile -type file -force\n" +msgstr "" + +#: ../../toolchain/moon/commands.md:561 +msgid "" +"Now open the file provided by `$profile` (if you used the `New-Item` " +"command it will be " +"`${env:USERPROFILE}\\Documents\\WindowsPowerShell\\Microsoft.PowerShell_profile.ps1`" +msgstr "" + +#: ../../toolchain/moon/commands.md:565 +msgid "" +"Next, we either save the completions file into our profile, or into a " +"separate file and source it inside our profile. To save the completions " +"into our profile simply use" +msgstr "" + +#: ../../toolchain/moon/commands.md:569 +msgid "" +"PS C:\\> moon shell-completion --shell powershell >>\n" +"${env:USERPROFILE}\\Documents\\WindowsPowerShell\\Microsoft.PowerShell_profile.ps1" +"\n" +msgstr "" + +#: ../../toolchain/moon/commands.md:572 +msgid "" +"This discussion is taken from `rustup completions` command with some " +"changes." +msgstr "" + +#: ../../toolchain/moon/commands.md:577 +msgid "`--shell ` — The shell to generate completion for" +msgstr "" + +#: ../../toolchain/moon/commands.md:579 +msgid "Default value: ``" +msgstr "" + +#: ../../toolchain/moon/commands.md:581 +msgid "Possible values: `bash`, `elvish`, `fish`, `powershell`, `zsh`" +msgstr "" + +#: ../../toolchain/moon/commands.md:586 +msgid "`moon version`" +msgstr "" + +#: ../../toolchain/moon/commands.md:588 +msgid "Print version information and exit" +msgstr "" + +#: ../../toolchain/moon/commands.md:590 +msgid "**Usage:** `moon version [OPTIONS]`" +msgstr "" + +#: ../../toolchain/moon/commands.md:594 +msgid "`--all` — Print all version information" +msgstr "" + +#: ../../toolchain/moon/commands.md:595 +msgid "`--json` — Print version information in JSON format" +msgstr "" + +#: ../../toolchain/moon/commands.md:596 +msgid "`--no-path` — Do not print the path" +msgstr "" + +#: ../../toolchain/moon/commands.md:602 +msgid "" +" This document was generated automatically by clap-" +"markdown. " +msgstr "" + +#: ../../toolchain/moon/index.md:1 +msgid "Moon Build System" +msgstr "" + +#: ../../toolchain/moon/module.md:1 +msgid "Module Configuration" +msgstr "" + +#: ../../toolchain/moon/module.md:3 +msgid "moon uses the `moon.mod.json` file to identify and describe a module." +msgstr "" + +#: ../../toolchain/moon/module.md:5 ../../toolchain/moon/package.md:5 +msgid "Name" +msgstr "" + +#: ../../toolchain/moon/module.md:7 +msgid "" +"The `name` field is used to specify the name of the module, and it is " +"required." +msgstr "" + +#: ../../toolchain/moon/module.md:9 +msgid "" +"{\n" +" \"name\": \"example\",\n" +" ...\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/module.md:16 +msgid "The module name can contain letters, numbers, `_`, `-`, and `/`." +msgstr "" + +#: ../../toolchain/moon/module.md:18 +msgid "" +"For modules published to [mooncakes.io](https://mooncakes.io), the module" +" name must begin with the username. For example:" +msgstr "" + +#: ../../toolchain/moon/module.md:20 +msgid "" +"{\n" +" \"name\": \"moonbitlang/core\",\n" +" ...\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/module.md:27 +msgid "Version" +msgstr "" + +#: ../../toolchain/moon/module.md:29 +msgid "The `version` field is used to specify the version of the module." +msgstr "" + +#: ../../toolchain/moon/module.md:31 +msgid "" +"This field is optional. For modules published to " +"[mooncakes.io](https://mooncakes.io), the version number must follow the " +"[Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html) " +"specification." +msgstr "" + +#: ../../toolchain/moon/module.md:33 +msgid "" +"{\n" +" \"name\": \"example\",\n" +" \"version\": \"0.1.0\",\n" +" ...\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/module.md:41 +msgid "Deps" +msgstr "" + +#: ../../toolchain/moon/module.md:43 +msgid "The `deps` field is used to specify the dependencies of the module." +msgstr "" + +#: ../../toolchain/moon/module.md:45 +msgid "It is automatically managed by commands like `moon add` and `moon remove`." +msgstr "" + +#: ../../toolchain/moon/module.md:47 +msgid "" +"{\n" +" \"name\": \"username/hello\",\n" +" \"deps\": {\n" +" \"moonbitlang/x\": \"0.4.6\"\n" +" }\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/module.md:56 +msgid "README" +msgstr "" + +#: ../../toolchain/moon/module.md:58 +msgid "" +"The `readme` field is used to specify the path to the module's README " +"file." +msgstr "" + +#: ../../toolchain/moon/module.md:60 +msgid "Repository" +msgstr "" + +#: ../../toolchain/moon/module.md:62 +msgid "" +"The `repository` field is used to specify the URL of the module's " +"repository." +msgstr "" + +#: ../../toolchain/moon/module.md:64 +msgid "License" +msgstr "" + +#: ../../toolchain/moon/module.md:66 +msgid "" +"The `license` field is used to specify the license of the module. The " +"license type must comply with the [SPDX License " +"List](https://spdx.org/licenses/)." +msgstr "" + +#: ../../toolchain/moon/module.md:68 +msgid "" +"{\n" +" \"license\": \"MIT\"\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/module.md:74 +msgid "Keywords" +msgstr "" + +#: ../../toolchain/moon/module.md:76 +msgid "The `keywords` field is used to specify the keywords for the module." +msgstr "" + +#: ../../toolchain/moon/module.md:78 +msgid "" +"{\n" +" \"keywords\": [\"example\", \"test\"]\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/module.md:84 +msgid "Description" +msgstr "" + +#: ../../toolchain/moon/module.md:86 +msgid "The `description` field is used to specify the description of the module." +msgstr "" + +#: ../../toolchain/moon/module.md:88 +msgid "" +"{\n" +" \"description\": \"This is a description of the module.\"\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/module.md:94 +msgid "Source directory" +msgstr "" + +#: ../../toolchain/moon/module.md:96 +msgid "The `source` field is used to specify the source directory of the module." +msgstr "" + +#: ../../toolchain/moon/module.md:98 +msgid "" +"It must be a subdirectory of the directory where the `moon.mod.json` file" +" is located and must be a relative path." +msgstr "" + +#: ../../toolchain/moon/module.md:100 +msgid "" +"When creating a module using the `moon new` command, a `src` directory " +"will be automatically generated, and the default value of the `source` " +"field will be `src`." +msgstr "" + +#: ../../toolchain/moon/module.md:102 +msgid "" +"{\n" +" \"source\": \"src\"\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/module.md:108 +msgid "" +"When the `source` field does not exist, or its value is `null` or an " +"empty string `\"\"`, it is equivalent to setting `\"source\": \".\"`. " +"This means that the source directory is the same as the directory where " +"the `moon.mod.json` file is located." +msgstr "" + +#: ../../toolchain/moon/module.md:110 +msgid "" +"{\n" +" \"source\": null\n" +"}\n" +"{\n" +" \"source\": \"\"\n" +"}\n" +"{\n" +" \"source\": \".\"\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/module.md:122 ../../toolchain/moon/package.md:224 +msgid "Warning List" +msgstr "" + +#: ../../toolchain/moon/module.md:124 ../../toolchain/moon/package.md:226 +msgid "This is used to disable specific preset compiler warning numbers." +msgstr "" + +#: ../../toolchain/moon/module.md:126 ../../toolchain/moon/package.md:228 +msgid "" +"For example, in the following configuration, `-2` disables the warning " +"number 2 (Unused variable)." +msgstr "" + +#: ../../toolchain/moon/module.md:128 ../../toolchain/moon/package.md:230 +msgid "" +"{\n" +" \"warn-list\": \"-2\",\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/module.md:134 ../../toolchain/moon/package.md:236 +msgid "" +"You can use `moonc build-package -warn-help` to see the list of preset " +"compiler warning numbers." +msgstr "" + +#: ../../toolchain/moon/module.md:136 ../../toolchain/moon/package.md:238 +msgid "" +"$ moonc -v \n" +"v0.1.20240914+b541585d3\n" +"\n" +"$ moonc build-package -warn-help\n" +"Available warnings: \n" +" 1 Unused function.\n" +" 2 Unused variable.\n" +" 3 Unused type declaration.\n" +" 4 Redundant case in a pattern matching (unused match case).\n" +" 5 Unused function argument.\n" +" 6 Unused constructor.\n" +" 7 Unused module declaration.\n" +" 8 Unused struct field.\n" +" 10 Unused generic type variable.\n" +" 11 Partial pattern matching.\n" +" 12 Unreachable code.\n" +" 13 Unresolved type variable.\n" +" 14 Lowercase type name.\n" +" 15 Unused mutability.\n" +" 16 Parser inconsistency.\n" +" 18 Useless loop expression.\n" +" 19 Top-level declaration is not left aligned.\n" +" 20 Invalid pragma\n" +" 21 Some arguments of constructor are omitted in pattern.\n" +" 22 Ambiguous block.\n" +" 23 Useless try expression.\n" +" 24 Useless error type.\n" +" 26 Useless catch all.\n" +" A all warnings\n" +msgstr "" + +#: ../../toolchain/moon/module.md:168 ../../toolchain/moon/package.md:270 +msgid "Alert List" +msgstr "" + +#: ../../toolchain/moon/module.md:170 ../../toolchain/moon/package.md:272 +msgid "Disable user preset alerts." +msgstr "" + +#: ../../toolchain/moon/module.md:172 ../../toolchain/moon/package.md:274 +msgid "" +"{\n" +" \"alert-list\": \"-alert_1-alert_2\"\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/package.md:1 +msgid "Package Configuration" +msgstr "" + +#: ../../toolchain/moon/package.md:3 +msgid "moon uses the `moon.pkg.json` file to identify and describe a package." +msgstr "" + +#: ../../toolchain/moon/package.md:7 +msgid "" +"The package name is not configurable; it is determined by the directory " +"name of the package." +msgstr "" + +#: ../../toolchain/moon/package.md:9 +msgid "is-main" +msgstr "" + +#: ../../toolchain/moon/package.md:11 +msgid "" +"The `is-main` field is used to specify whether a package needs to be " +"linked into an executable file." +msgstr "" + +#: ../../toolchain/moon/package.md:13 +msgid "" +"The output of the linking process depends on the backend. When this field" +" is set to `true`:" +msgstr "" + +#: ../../toolchain/moon/package.md:15 +msgid "" +"For the `wasm` and `wasm-gc` backends, a standalone WebAssembly module " +"will be generated." +msgstr "" + +#: ../../toolchain/moon/package.md:16 +msgid "For the `js` backend, a standalone JavaScript file will be generated." +msgstr "" + +#: ../../toolchain/moon/package.md:18 +msgid "import" +msgstr "" + +#: ../../toolchain/moon/package.md:20 +msgid "" +"The `import` field is used to specify other packages that a package " +"depends on." +msgstr "" + +#: ../../toolchain/moon/package.md:22 +msgid "test-import" +msgstr "" + +#: ../../toolchain/moon/package.md:24 +msgid "" +"The `test-import` field is used to specify other packages that the black-" +"box test package of this package depends on." +msgstr "" + +#: ../../toolchain/moon/package.md:26 +msgid "wbtest-import" +msgstr "" + +#: ../../toolchain/moon/package.md:28 +msgid "" +"The `wbtest-import` field is used to specify other packages that the " +"white-box test package of this package depends on." +msgstr "" + +#: ../../toolchain/moon/package.md:30 +msgid "Conditional Compilation" +msgstr "" + +#: ../../toolchain/moon/package.md:32 +msgid "The smallest unit of conditional compilation is a file." +msgstr "" + +#: ../../toolchain/moon/package.md:34 +msgid "" +"In a conditional compilation expression, three logical operators are " +"supported: `and`, `or`, and `not`, where the `or` operator can be " +"omitted." +msgstr "" + +#: ../../toolchain/moon/package.md:36 +msgid "" +"For example, `[\"or\", \"wasm\", \"wasm-gc\"]` can be simplified to " +"`[\"wasm\", \"wasm-gc\"]`." +msgstr "" + +#: ../../toolchain/moon/package.md:38 +msgid "" +"Conditions in the expression can be categorized into backends and " +"optimization levels:" +msgstr "" + +#: ../../toolchain/moon/package.md:40 +msgid "**Backend conditions**: `\"wasm\"`, `\"wasm-gc\"`, and `\"js\"`" +msgstr "" + +#: ../../toolchain/moon/package.md:41 +msgid "**Optimization level conditions**: `\"debug\"` and `\"release\"`" +msgstr "" + +#: ../../toolchain/moon/package.md:43 +msgid "Conditional expressions support nesting." +msgstr "" + +#: ../../toolchain/moon/package.md:45 +msgid "" +"If a file is not listed in `\"targets\"`, it will be compiled under all " +"conditions by default." +msgstr "" + +#: ../../toolchain/moon/package.md:47 +msgid "Example:" +msgstr "" + +#: ../../toolchain/moon/package.md:49 +msgid "" +"{\n" +" \"targets\": {\n" +" \"only_js.mbt\": [\"js\"],\n" +" \"only_wasm.mbt\": [\"wasm\"],\n" +" \"only_wasm_gc.mbt\": [\"wasm-gc\"],\n" +" \"all_wasm.mbt\": [\"wasm\", \"wasm-gc\"],\n" +" \"not_js.mbt\": [\"not\", \"js\"],\n" +" \"only_debug.mbt\": [\"debug\"],\n" +" \"js_and_release.mbt\": [\"and\", [\"js\"], [\"release\"]],\n" +" \"js_only_test.mbt\": [\"js\"],\n" +" \"js_or_wasm.mbt\": [\"js\", \"wasm\"],\n" +" \"wasm_release_or_js_debug.mbt\": [\"or\", [\"and\", \"wasm\", " +"\"release\"], [\"and\", \"js\", \"debug\"]]\n" +" }\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/package.md:66 +msgid "Link Options" +msgstr "" + +#: ../../toolchain/moon/package.md:68 +msgid "" +"By default, moon only links packages where `is-main` is set to `true`. If" +" you need to link other packages, you can specify this with the `link` " +"option." +msgstr "" + +#: ../../toolchain/moon/package.md:70 +msgid "" +"The `link` option is used to specify link options, and its value can be " +"either a boolean or an object." +msgstr "" + +#: ../../toolchain/moon/package.md:72 +msgid "" +"When the `link` value is `true`, it indicates that the package should be " +"linked. The output will vary depending on the backend specified during " +"the build." +msgstr "" + +#: ../../toolchain/moon/package.md:74 +msgid "" +"{\n" +" \"link\": true\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/package.md:80 +msgid "" +"When the `link` value is an object, it indicates that the package should " +"be linked, and you can specify link options. For detailed configuration, " +"please refer to the subpage for the corresponding backend." +msgstr "" + +#: ../../toolchain/moon/package.md:82 +msgid "Wasm Backend Link Options" +msgstr "" + +#: ../../toolchain/moon/package.md:84 ../../toolchain/moon/package.md:152 +msgid "Configurable Options" +msgstr "" + +#: ../../toolchain/moon/package.md:86 +msgid "" +"The `exports` option is used to specify the function names exported by " +"the `wasm` backend." +msgstr "" + +#: ../../toolchain/moon/package.md:88 +msgid "" +"For example, in the following configuration, the `hello` function from " +"the current package is exported as the `hello` function in the `wasm` " +"module, and the `foo` function is exported as the `bar` function in the " +"`wasm` module. In the `wasm` host, the `hello` and `bar` functions can be" +" called to invoke the `hello` and `foo` functions from the current " +"package." +msgstr "" + +#: ../../toolchain/moon/package.md:90 +msgid "" +"{\n" +" \"link\": {\n" +" \"wasm\": {\n" +" \"exports\": [\n" +" \"hello\",\n" +" \"foo:bar\"\n" +" ]\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/package.md:103 +msgid "" +"The `heap-start-address` option is used to specify the starting address " +"of the linear memory that can be used when compiling to the `wasm` " +"backend." +msgstr "" + +#: ../../toolchain/moon/package.md:105 +msgid "" +"For example, the following configuration sets the starting address of the" +" linear memory to 1024." +msgstr "" + +#: ../../toolchain/moon/package.md:107 +msgid "" +"{\n" +" \"link\": {\n" +" \"wasm\": {\n" +" \"heap-start-address\": 1024\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/package.md:117 +msgid "" +"The `import-memory` option is used to specify the linear memory imported " +"by the `wasm` module." +msgstr "" + +#: ../../toolchain/moon/package.md:119 +msgid "" +"For example, the following configuration specifies that the linear memory" +" imported by the `wasm` module is the `memory` variable from the `env` " +"module." +msgstr "" + +#: ../../toolchain/moon/package.md:121 +msgid "" +"{\n" +" \"link\": {\n" +" \"wasm\": {\n" +" \"import-memory\": {\n" +" \"module\": \"env\",\n" +" \"name\": \"memory\"\n" +" }\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/package.md:134 +msgid "" +"The `export-memory-name` option is used to specify the name of the linear" +" memory exported by the `wasm` module." +msgstr "" + +#: ../../toolchain/moon/package.md:136 +msgid "" +"{\n" +" \"link\": {\n" +" \"wasm\": {\n" +" \"export-memory-name\": \"memory\"\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/package.md:146 +msgid "Wasm GC Backend Link Options" +msgstr "" + +#: ../../toolchain/moon/package.md:148 +msgid "" +"The link options for the `wasm-gc` backend are similar to those for the " +"`wasm` backend, except there is no `heap-start-address` option." +msgstr "" + +#: ../../toolchain/moon/package.md:150 +msgid "JS Backend Link Options" +msgstr "" + +#: ../../toolchain/moon/package.md:154 +msgid "" +"The `exports` option is used to specify the function names to export in " +"the JavaScript module." +msgstr "" + +#: ../../toolchain/moon/package.md:156 +msgid "" +"For example, in the following configuration, the `hello` function from " +"the current package is exported as the `hello` function in the JavaScript" +" module. In the JavaScript host, the `hello` function can be called to " +"invoke the `hello` function from the current package." +msgstr "" + +#: ../../toolchain/moon/package.md:158 +msgid "" +"{\n" +" \"link\": {\n" +" \"js\": {\n" +" \"exports\": [\n" +" \"hello\"\n" +" ]\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/package.md:170 +msgid "" +"The `format` option is used to specify the output format of the " +"JavaScript module." +msgstr "" + +#: ../../toolchain/moon/package.md:172 +msgid "The currently supported formats are:" +msgstr "" + +#: ../../toolchain/moon/package.md:173 +msgid "`esm`" +msgstr "" + +#: ../../toolchain/moon/package.md:174 +msgid "`cjs`" +msgstr "" + +#: ../../toolchain/moon/package.md:175 +msgid "`iife`" +msgstr "" + +#: ../../toolchain/moon/package.md:177 +msgid "" +"For example, the following configuration sets the output format of the " +"current package to ES Module." +msgstr "" + +#: ../../toolchain/moon/package.md:179 +msgid "" +"{\n" +" \"link\": {\n" +" \"js\": {\n" +" \"format\": \"esm\"\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/package.md:189 +msgid "Pre-build" +msgstr "" + +#: ../../toolchain/moon/package.md:191 +msgid "" +"The `\"pre-build\"` field is used to specify pre-build commands, which " +"will be executed before build commands such as `moon check|build|test`." +msgstr "" + +#: ../../toolchain/moon/package.md:193 +msgid "" +"`\"pre-build\"` is an array, where each element is an object containing " +"`input`, `output`, and `command` fields. The `input` and `output` fields " +"can be strings or arrays of strings, while the `command` field is a " +"string. In the `command`, you can use any shell commands, as well as the " +"`$input` and `$output` variables, which represent the input and output " +"files, respectively. If these fields are arrays, they will be joined with" +" spaces by default." +msgstr "" + +#: ../../toolchain/moon/package.md:195 +msgid "" +"Currently, there is a built-in special command `:embed`, which converts " +"files into MoonBit source code. The `--text` parameter is used to embed " +"text files, and `--binary` is used for binary files. `--text` is the " +"default and can be omitted. The `--name` parameter is used to specify the" +" generated variable name, with `resource` being the default. The command " +"is executed in the directory where the `moon.pkg.json` file is located." +msgstr "" + +#: ../../toolchain/moon/package.md:197 +msgid "" +"{\n" +" \"pre-build\": [\n" +" {\n" +" \"input\": \"a.txt\",\n" +" \"output\": \"a.mbt\",\n" +" \"command\": \":embed -i $input -o $output\"\n" +" }\n" +" ]\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/package.md:209 +msgid "If the content of `a.txt` in the current package directory is:" +msgstr "" + +#: ../../toolchain/moon/package.md:210 +msgid "" +"hello,\n" +"world\n" +msgstr "" + +#: ../../toolchain/moon/package.md:215 +msgid "" +"After running `moon build`, the following `a.mbt` file will be generated " +"in the directory where the `moon.pkg.json` is located:" +msgstr "" + +#: ../../toolchain/moon/package.md:217 +msgid "" +"let resource : String =\n" +" #|hello,\n" +" #|world\n" +" #|\n" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:1 +msgid "MoonBit's Package Manager Tutorial" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:3 +msgid "Overview" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:5 +msgid "" +"MoonBit's build system seamlessly integrates package management and " +"documentation generation tools, allowing users to easily fetch " +"dependencies from mooncakes.io, access module documentation, and publish " +"new modules." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:7 +msgid "" +"[mooncakes.io](https://mooncakes.io/) is a centralized package management" +" platform. Each module has a corresponding configuration file " +"`moon.mod.json`, which is the smallest unit for publishing. Under the " +"module's path, there can be multiple packages, each corresponding to a " +"`moon.pkg.json` configuration file. The `.mbt` files at the same level as" +" `moon.pkg.json` belong to this package." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:9 +msgid "" +"Before getting started, make sure you have installed " +"[moon](https://www.moonbitlang.com/download/)." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:11 +msgid "Setup mooncakes.io account" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:13 +msgid "**Note: If you don't need to publishing, you can skip this step.**" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:15 +msgid "" +"If you don't have an account on mooncakes.io, run `moon register` and " +"follow the guide. If you have previously registered an account, you can " +"use `moon login` to log in." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:17 +msgid "" +"When you see the following message, it means you have successfully logged" +" in:" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:19 +msgid "API token saved to ~/.moon/credentials.json\n" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:23 +msgid "Update index" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:25 +msgid "Use `moon update` to update the mooncakes.io index." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:27 +msgid "![moon update cli](/imgs/moon-update.png)" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:27 +msgid "moon update cli" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:29 +msgid "Setup MoonBit project" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:31 +msgid "Open an existing project or create a new project via `moon new`:" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:33 +msgid "![moon new](/imgs/moon-new.png)" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:33 +msgid "moon new" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:35 +msgid "Add dependencies" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:37 +msgid "" +"You can browse all available modules on mooncakes.io. Use `moon add` to " +"add the dependencies you need, or manually edit the `deps` field in " +"`moon.mod.json`." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:39 +msgid "" +"For example, to add the latest version of the `Yoorkin/example/list` " +"module:" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:41 +msgid "![add deps](/imgs/add-deps.png)" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:41 +msgid "add deps" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:43 +msgid "Import packages from module" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:45 +msgid "" +"Modify the configuration file `moon.pkg.json` and declare the packages " +"that need to be imported in the `import` field." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:47 +msgid "" +"For example, in the image below, the `hello/main/moon.pkg.json` file is " +"modified to declare the import of `Yoorkin/example/list` in the `main` " +"package. Now, you can call the functions of the third-party package in " +"the `main` package using `@list`." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:49 +msgid "![import package](/imgs/import.png)" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:49 +msgid "import package" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:51 +msgid "You can also give an alias to the imported package:" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:53 +msgid "" +"{\n" +" \"is_main\": true,\n" +" \"import\": [\n" +" { \"path\": \"Yoorkin/example/list\", \"alias\": \"ls\" }\n" +" ]\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:62 +msgid "" +"Read the documentation of this module on mooncakes.io, we can use its " +"`of_array` and `reverse` functions to implement a new function " +"`reverse_array`." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:64 +msgid "![reverse array](/imgs/reverse-array.png)" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:64 +msgid "reverse array" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:66 +msgid "Remove dependencies" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:68 +msgid "You can remove dependencies via `moon remove `." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:70 +msgid "Publish your module" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:72 +msgid "" +"If you are ready to share your module, use `moon publish` to push a " +"module to mooncakes.io. There are some important considerations to keep " +"in mind before publishing:" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:75 +msgid "Semantic versioning convention" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:77 +msgid "" +"MoonBit's package management follows the convention of [Semantic " +"Versioning](https://semver.org/). Each module must define a version " +"number in the format `MAJOR.MINOR.PATCH`. With each push, the module must" +" increment the:" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:79 +msgid "MAJOR version when you make incompatible API changes" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:80 +msgid "MINOR version when you add functionality in a backward compatible manner" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:81 +msgid "PATCH version when you make backward compatible bug fixes" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:83 +msgid "" +"Additional labels for pre-release and build metadata are available as " +"extensions to the `MAJOR.MINOR.PATCH` format." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:85 +msgid "" +"moon implements the [minimal version " +"selection](https://research.swtch.com/vgo-mvs), which automatically " +"handles and installs dependencies based on the module's semantic " +"versioning information. Minimal version selection assumes that each " +"module declares its own dependency requirements and follows semantic " +"versioning convention, aiming to make the user's dependency graph as " +"close as possible to the author's development-time dependencies." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:87 +msgid "Readme & metadata" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:89 +msgid "Metadata in `moon.mod.json` and `README.md` will be shown in mooncakes.io." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:91 +msgid "Metadata consist of the following sections:" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:93 +msgid "" +"`license`: license of this module, it following the " +"[SPDX](https://spdx.dev/about/overview/) convention" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:94 +msgid "`keywords`: keywords of this module" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:95 +msgid "`repository`: URL of the package source repository" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:96 +msgid "`description`: short description to this module" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:97 +msgid "`homepage`: URL of the module homepage" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:99 +msgid "Moondoc" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:101 +msgid "mooncakes.io will generate documentation for each modules automatically." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:103 +msgid "" +"The leading `///` comments of each toplevel will be recognized as " +"documentation. You can write markdown inside." +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:106 +msgid "" +"/// Get the largest element of a non-empty `Array`.\n" +"///\n" +"/// # Example\n" +"///\n" +"/// ```\n" +"/// maximum([1,2,3,4,5,6]) = 6\n" +"/// ```\n" +"///\n" +"/// # Panics\n" +"///\n" +"/// Panics if the `xs` is empty.\n" +"///\n" +"pub fn maximum[T : Compare](xs : Array[T]) -> T {\n" +" // TODO ...\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/package-manage-tour.md:124 +msgid "" +"You can also use `moon doc --serve` to generate and view documentation in" +" local." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:1 +msgid "MoonBit's Build System Tutorial" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:3 +msgid "" +"Moon is the build system for the MoonBit language, currently based on the" +" [n2](https://github.com/evmar/n2) project. Moon supports parallel and " +"incremental builds. Additionally, moon also supports managing and " +"building third-party packages on [mooncakes.io](https://mooncakes.io/)" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:5 +msgid "Prerequisites" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:7 +msgid "" +"Before you begin with this tutorial, make sure you have installed the " +"following:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:9 +msgid "" +"**MoonBit CLI Tools**: Download it from the " +". This command line tool is needed" +" for creating and managing MoonBit projects." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:11 +msgid "Use `moon help` to view the usage instructions." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:13 +msgid "" +"$ moon help\n" +"...\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:18 +msgid "" +"**MoonBit Language** plugin in Visual Studio Code: You can install it " +"from the VS Code marketplace. This plugin provides a rich development " +"environment for MoonBit, including functionalities like syntax " +"highlighting, code completion, and more." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:20 +msgid "" +"Once you have these prerequisites fulfilled, let's start by creating a " +"new MoonBit module." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:22 +msgid "Creating a New Module" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:24 +msgid "" +"To create a new module, enter the `moon new` command in the terminal, and" +" you will see the module creation wizard. By using all the default " +"values, you can create a new module named `username/hello` in the `my-" +"project` directory." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:26 +msgid "" +"$ moon new\n" +"Enter the path to create the project (. for current directory): my-" +"project\n" +"Select the create mode: exec\n" +"Enter your username: username\n" +"Enter your project name: hello\n" +"Enter your license: Apache-2.0\n" +"Created my-project\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:36 +msgid "" +"If you want use all default values, you can use `moon new my-project` to " +"create a new module named `username/hello` in the `my-project` directory." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:38 +msgid "Understanding the Module Directory Structure" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:40 +msgid "" +"After creating the new module, your directory structure should resemble " +"the following:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:42 +msgid "" +"my-project\n" +"├── LICENSE\n" +"├── README.md\n" +"├── moon.mod.json\n" +"└── src\n" +" ├── lib\n" +" │   ├── hello.mbt\n" +" │   ├── hello_test.mbt\n" +" │   └── moon.pkg.json\n" +" └── main\n" +" ├── main.mbt\n" +" └── moon.pkg.json\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:57 +msgid "Here's a brief explanation of the directory structure:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:59 +msgid "" +"`moon.mod.json` is used to identify a directory as a MoonBit module. It " +"contains the module's metadata, such as the module name, version, etc. " +"`source` specifies the source directory of the module. The default value " +"is `src`." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:61 +msgid "" +"{\n" +" \"name\": \"username/hello\",\n" +" \"version\": \"0.1.0\",\n" +" \"readme\": \"README.md\",\n" +" \"repository\": \"\",\n" +" \"license\": \"Apache-2.0\",\n" +" \"keywords\": [],\n" +" \"description\": \"\",\n" +" \"source\": \"src\"\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:74 +msgid "" +"`lib` and `main` directories: These are the packages within the module. " +"Each package can contain multiple `.mbt` files, which are the source code" +" files for the MoonBit language. However, regardless of how many `.mbt` " +"files a package has, they all share a common `moon.pkg.json` file. " +"`lib/*_test.mbt` are separate test files in the `lib` package, these " +"files are for blackbox test, so private members of the `lib` package " +"cannot be accessed directly." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:76 +msgid "" +"`moon.pkg.json` is package descriptor. It defines the properties of the " +"package, such as whether it is the main package and the packages it " +"imports." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:78 +msgid "`main/moon.pkg.json`:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:80 ../../toolchain/moon/tutorial.md:157 +msgid "" +"{\n" +" \"is_main\": true,\n" +" \"import\": [\n" +" \"username/hello/lib\"\n" +" ]\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:89 +msgid "" +"Here, `\"is_main: true\"` declares that the package needs to be linked by" +" the build system into a wasm file." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:91 +msgid "`lib/moon.pkg.json`:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:93 ../../toolchain/moon/tutorial.md:210 +msgid "{}\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:97 +msgid "" +"This file is empty. Its purpose is simply to inform the build system that" +" this folder is a package." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:99 +msgid "Working with Packages" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:101 +msgid "" +"Our `username/hello` module contains two packages: `username/hello/lib` " +"and `username/hello/main`." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:103 +msgid "" +"The `username/hello/lib` package contains `hello.mbt` and " +"`hello_test.mbt` files:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:105 +msgid "`hello.mbt`" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:107 +msgid "" +"pub fn hello() -> String {\n" +" \"Hello, world!\"\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:113 +msgid "`hello_test.mbt`" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:115 +msgid "" +"test \"hello\" {\n" +" if @lib.hello() != \"Hello, world!\" {\n" +" fail!(\"@lib.hello() != \\\"Hello, world!\\\"\")\n" +" }\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:123 +msgid "The `username/hello/main` package contains a `main.mbt` file:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:125 +msgid "" +"fn main {\n" +" println(@lib.hello())\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:131 +msgid "" +"To execute the program, specify the file system's path to the " +"`username/hello/main` package in the `moon run` command:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:133 +msgid "" +"$ moon run ./src/main\n" +"Hello, world!\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:138 +msgid "You can also omit `./`" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:140 +msgid "" +"$ moon run src/main\n" +"Hello, world!\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:145 +msgid "You can test using the `moon test` command:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:147 +msgid "" +"$ moon test\n" +"Total tests: 1, passed: 1, failed: 0.\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:152 +msgid "Package Importing" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:154 +msgid "" +"In the MoonBit's build system, a module's name is used to reference its " +"internal packages. To import the `username/hello/lib` package in " +"`src/main/main.mbt`, you need to specify it in `src/main/moon.pkg.json`:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:166 +msgid "" +"Here, `username/hello/lib` specifies importing the `username/hello/lib` " +"package from the `username/hello` module, so you can use `@lib.hello()` " +"in `main/main.mbt`." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:168 +msgid "" +"Note that the package name imported in `src/main/moon.pkg.json` is " +"`username/hello/lib`, and `@lib` is used to refer to this package in " +"`src/main/main.mbt`. The import here actually generates a default alias " +"for the package name `username/hello/lib`. In the following sections, you" +" will learn how to customize the alias for a package." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:170 +msgid "Creating and Using a New Package" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:172 +msgid "First, create a new directory named `fib` under `lib`:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:174 +msgid "mkdir src/lib/fib\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:178 +msgid "Now, you can create new files under `src/lib/fib`:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:180 +msgid "`a.mbt`:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:182 +msgid "" +"pub fn fib(n : Int) -> Int {\n" +" match n {\n" +" 0 => 0\n" +" 1 => 1\n" +" _ => fib(n - 1) + fib(n - 2)\n" +" }\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:192 +msgid "`b.mbt`:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:194 +msgid "" +"pub fn fib2(num : Int) -> Int {\n" +" fn aux(n, acc1, acc2) {\n" +" match n {\n" +" 0 => acc1\n" +" 1 => acc2\n" +" _ => aux(n - 1, acc2, acc1 + acc2)\n" +" }\n" +" }\n" +"\n" +" aux(num, 0, 1)\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:208 +msgid "`moon.pkg.json`:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:214 +msgid "" +"After creating these files, your directory structure should look like " +"this:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:216 +msgid "" +"my-project\n" +"├── LICENSE\n" +"├── README.md\n" +"├── moon.mod.json\n" +"└── src\n" +" ├── lib\n" +" │ ├── fib\n" +" │ │ ├── a.mbt\n" +" │ │ ├── b.mbt\n" +" │ │ └── moon.pkg.json\n" +" │ ├── hello.mbt\n" +" │ ├── hello_test.mbt\n" +" │ └── moon.pkg.json\n" +" └── main\n" +" ├── main.mbt\n" +" └── moon.pkg.json\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:235 +msgid "" +"In the `src/main/moon.pkg.json` file, import the `username/hello/lib/fib`" +" package and customize its alias to `my_awesome_fibonacci`:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:237 +msgid "" +"{\n" +" \"is_main\": true,\n" +" \"import\": [\n" +" \"username/hello/lib\",\n" +" {\n" +" \"path\": \"username/hello/lib/fib\",\n" +" \"alias\": \"my_awesome_fibonacci\"\n" +" }\n" +" ]\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:250 +msgid "" +"This line imports the `fib` package, which is part of the `lib` package " +"in the `hello` module. After doing this, you can use the `fib` package in" +" `main/main.mbt`. Replace the file content of `main/main.mbt` to:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:252 +msgid "" +"fn main {\n" +" let a = @my_awesome_fibonacci.fib(10)\n" +" let b = @my_awesome_fibonacci.fib2(11)\n" +" println(\"fib(10) = \\{a}, fib(11) = \\{b}\")\n" +"\n" +" println(@lib.hello())\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:262 +msgid "To execute your program, specify the path to the `main` package:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:264 +msgid "" +"$ moon run ./src/main\n" +"fib(10) = 55, fib(11) = 89\n" +"Hello, world!\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:270 +msgid "Adding Tests" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:272 +msgid "" +"Let's add some tests to verify our fib implementation. Add the following " +"content in `src/lib/fib/a.mbt`:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:274 +msgid "`src/lib/fib/a.mbt`" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:276 +msgid "" +"test {\n" +" assert_eq!(fib(1), 1)\n" +" assert_eq!(fib(2), 1)\n" +" assert_eq!(fib(3), 2)\n" +" assert_eq!(fib(4), 3)\n" +" assert_eq!(fib(5), 5)\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:286 +msgid "" +"This code tests the first five terms of the Fibonacci sequence. `test { " +"... }` defines an inline test block. The code inside an inline test block" +" is executed in test mode." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:288 +msgid "" +"Inline test blocks are discarded in non-test compilation modes (`moon " +"build` and `moon run`), so they won't cause the generated code size to " +"bloat." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:290 +msgid "Stand-alone test files for blackbox tests" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:292 +msgid "" +"Besides inline tests, MoonBit also supports stand-alone test files. " +"Source files ending in `_test.mbt` are considered test files for blackbox" +" tests. For example, inside the `src/lib/fib` directory, create a file " +"named `fib_test.mbt` and paste the following code:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:294 +msgid "`src/lib/fib/fib_test.mbt`" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:296 +msgid "" +"test {\n" +" assert_eq!(@fib.fib(1), 1)\n" +" assert_eq!(@fib.fib2(2), 1)\n" +" assert_eq!(@fib.fib(3), 2)\n" +" assert_eq!(@fib.fib2(4), 3)\n" +" assert_eq!(@fib.fib(5), 5)\n" +"}\n" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:306 +msgid "" +"Notice that the test code uses `@fib` to refer to the " +"`username/hello/lib/fib` package. The build system automatically creates " +"a new package for blackbox tests by using the files that end with " +"`_test.mbt`. This new package will import the current package " +"automatically, allowing you to use `@lib` in the test code." +msgstr "" + +#: ../../toolchain/moon/tutorial.md:308 +msgid "" +"Finally, use the `moon test` command, which scans the entire project, " +"identifies, and runs all inline tests as well as files ending with " +"`_test.mbt`. If everything is normal, you will see:" +msgstr "" + +#: ../../toolchain/moon/tutorial.md:310 +msgid "" +"$ moon test\n" +"Total tests: 3, passed: 3, failed: 0.\n" +"$ moon test -v\n" +"test username/hello/lib/hello_test.mbt::hello ok\n" +"test username/hello/lib/fib/a.mbt::0 ok\n" +"test username/hello/lib/fib/fib_test.mbt::0 ok\n" +"Total tests: 3, passed: 3, failed: 0.\n" +msgstr "" + diff --git a/next/locales/zh_CN/LC_MESSAGES/tutorial.po b/next/locales/zh_CN/LC_MESSAGES/tutorial.po new file mode 100644 index 00000000..677ee3e8 --- /dev/null +++ b/next/locales/zh_CN/LC_MESSAGES/tutorial.po @@ -0,0 +1,807 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2024, International Digital Economy Academy +# This file is distributed under the same license as the MoonBit Document +# package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: MoonBit Document \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-11-27 13:35+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.16.0\n" + +#: ../../tutorial/index.md:7 +msgid "Contents:" +msgstr "目录:" + +#: ../../tutorial/index.md:1 +msgid "Tutorial" +msgstr "教程" + +#: ../../tutorial/index.md:3 +msgid "Here are some tutorials that may help you learn the programming language:" +msgstr "以下是一些可能帮助您学习编程语言的教程:" + +#: ../../tutorial/index.md:5 +msgid "[Tour for Beginners](./tour.md)" +msgstr "[新手之旅](./tour.md)" + +#: ../../tutorial/tour.md:1 +msgid "A Tour of MoonBit for Beginners" +msgstr "MoonBit:新手之旅" + +#: ../../tutorial/tour.md:3 +msgid "" +"This guide is intended for newcomers, and it's not meant to be a 5-minute" +" quick tour. This article tries to be a succinct yet easy to understand " +"guide for those who haven't programmed in a way that MoonBit enables them" +" to, that is, in a more modern, functional way." +msgstr "" +"这一文档针对不熟悉语言的新手用户所写,并不打算作为一个几分钟就能读完的小文章。本文希望为那些对 MoonBit 的编程思路 " +"(更加现代化,函数式的) 不甚了解的用户提供一个简洁而不失易懂性的指南。" + +#: ../../tutorial/tour.md:6 +msgid "" +"See [the General Introduction](../language/index.md) if you want to " +"straight delve into the language." +msgstr "如果您想直接深入了解语言,请参阅[总体介绍](../language/index.md)。" + +#: ../../tutorial/tour.md:8 +msgid "Installation" +msgstr "安装" + +#: ../../tutorial/tour.md:10 +msgid "the Extension" +msgstr "语言扩展" + +#: ../../tutorial/tour.md:12 +msgid "" +"Currently, MoonBit development support are through VS Code extension. " +"Navigate to [VS Code " +"Marketplace](https://marketplace.visualstudio.com/items?itemName=moonbit" +".moonbit-lang) to download MoonBit language support." +msgstr "" +"目前,MoonBit 的开发支持是通过 VS Code 扩展实现的。请前往[VS Code " +"Marketplace](https://marketplace.visualstudio.com/items?itemName=moonbit" +".moonbit-lang)下载 MoonBit 语言支持。" + +#: ../../tutorial/tour.md:15 +msgid "the toolchain" +msgstr "工具链" + +#: ../../tutorial/tour.md:17 +msgid "" +"(Recommended) If you've installed the extension above, the runtime can be" +" directly installed by running 'Install moonbit toolchain' in the action " +"menu and you may skip this part: ![runtime-installation](/imgs/runtime-" +"installation.png)" +msgstr "" +"(推荐) 如果您已安装了上面的扩展,运行操作菜单中的 “Install moonbit toolchain” " +"即可直接安装运行时并跳过这部分介绍:![安装运行时](/imgs/runtime-installation.png)" + +#: ../../tutorial/tour.md:17 +msgid "runtime-installation" +msgstr "安装运行时" + +#: ../../tutorial/tour.md:20 +msgid "" +"We also provide an installation script: Linux & macOS users can install " +"via" +msgstr "我们还提供了一个安装脚本:Linux 和 macOS 用户可以通过以下方式安装:" + +#: ../../tutorial/tour.md:22 +msgid "curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash\n" +msgstr "" + +#: ../../tutorial/tour.md:26 +msgid "For Windows users, powershell is used:" +msgstr "对于 Windows 用户,使用 Powershell:" + +#: ../../tutorial/tour.md:28 +msgid "" +"Set-ExecutionPolicy RemoteSigned -Scope CurrentUser; irm " +"https://cli.moonbitlang.com/install/powershell.ps1 | iex\n" +msgstr "" + +#: ../../tutorial/tour.md:32 +msgid "" +"This automatically installs MoonBit in `$HOME/.moon` and adds it to your " +"`PATH`." +msgstr "这将自动安装 MoonBit 到 `$HOME/.moon` 并将其添加到您的 `PATH`。" + +#: ../../tutorial/tour.md:34 +msgid "" +"If you encounter `moon` not found after installation, try restarting your" +" terminal or vscode to let the environment variable take effect." +msgstr "如果安装后遇到 `moon` 未找到的情况,请尝试重新启动终端或 VSCode 以使环境变量生效。" + +#: ../../tutorial/tour.md:36 +msgid "" +"Do notice that MoonBit is not production-ready at the moment, it's under " +"active development. To update MoonBit, just run the commands above again." +msgstr "请注意,目前 MoonBit 还不适用于生产环境:它正在积极开发中。要更新 MoonBit,只需再次运行上面的命令即可。" + +#: ../../tutorial/tour.md:38 +msgid "" +"Running `moon help` gives us a bunch of subcommands. But right now the " +"only commands we need are `build` `run` and `new`." +msgstr "运行 `moon help` 可以看到一堆子命令。但是现在我们只需要 `build` `run` 和 `new` 这三个命令。" + +#: ../../tutorial/tour.md:40 +msgid "" +"To create a project (or module, more formally), run `moon new`. You will " +"be greeted with a creation wizard, filling up all the info and we get" +msgstr "要创建一个项目(或模块,更正式地说),运行 `moon new`。您将看到一个创建向导,填写所有信息后我们会得到:" + +#: ../../tutorial/tour.md:42 +msgid "" +"my-project\n" +"├── LICENSE\n" +"├── moon.mod.json\n" +"├── README.md\n" +"└── src\n" +" ├── lib\n" +" │ ├── hello.mbt\n" +" │ ├── hello_test.mbt\n" +" │ └── moon.pkg.json\n" +" └── main\n" +" ├── main.mbt\n" +" └── moon.pkg.json\n" +msgstr "" + +#: ../../tutorial/tour.md:57 +msgid "" +"This resembles a typical MoonBit module structure. Try running `moon run " +"src/main`." +msgstr "这是一个典型的 MoonBit 模块结构。尝试运行 `moon run src/main`。" + +#: ../../tutorial/tour.md:59 +msgid "Now, we can get started." +msgstr "现在,我们可以开始了。" + +#: ../../tutorial/tour.md:61 +msgid "Start Writing" +msgstr "开始编写" + +#: ../../tutorial/tour.md:63 +msgid "" +"In our tour, we will write all of the codes below in `main.mbt`. As you " +"may have guessed, the `main` function within the `main` package is the " +"main entrance of a program. For a thorough introduction, please take a " +"look at our [build system tutorial](../toolchain/moon/tutorial.md)." +msgstr "" +"在我们的新手之旅中,我们将在 `main.mbt` 中编写下面的所有代码。正如您可能猜到的那样,`main` 包中的 `main` " +"函数是程序的主入口。要进行全面的介绍,请查看我们的[构建系统教程](../toolchain/moon/tutorial.md)。" + +#: ../../tutorial/tour.md:66 +msgid "Variables" +msgstr "变量" + +#: ../../tutorial/tour.md:68 +msgid "Variables are defined with `let`:" +msgstr "变量使用 `let` 定义:" + +#: ../../tutorial/tour.md:70 +msgid "" +"let e = 2.718281828459045 // double\n" +"let int_min = -2147483648 // int\n" +"let int_max : Int = 2147483647 // explicit type annotation\n" +"let tuple = (1, 2) // 2-tuple\n" +msgstr "" +"let e = 2.718281828459045 // double\n" +"let int_min = -2147483648 // int\n" +"let int_max : Int = 2147483647 // 显示类型标注\n" +"let tuple = (1, 2) // 2-tuple\n" + +#: ../../tutorial/tour.md:77 +msgid "" +"fn init {\n" +" let array = [1, 2, 3, 4, 5]\n" +" // array = [4, 5, 6, 7, 8] // WRONG: let creates immutable bindings\n" +" let mut mut_array = [1, 2, 3, 4, 5]\n" +" mut_array = [4, 5, 6, 7, 8]\n" +" println(mut_array)\n" +"}\n" +msgstr "" +"fn init {\n" +" let array = [1, 2, 3, 4, 5]\n" +" // array = [4, 5, 6, 7, 8] // 错误:let 创建的是不可变绑定\n" +" let mut mut_array = [1, 2, 3, 4, 5]\n" +" mut_array = [4, 5, 6, 7, 8]\n" +" println(mut_array)\n" +"}\n" + +#: ../../tutorial/tour.md:87 +msgid "" +"MoonBit is a strictly typed language with type inference. In the example " +"above, `let` binds (we prefer the word _bind_ to assign) a symbol to a " +"value. The symbol is inferred to have the same type as the value. Hover " +"over any of the symbols to check its type." +msgstr "" +"MoonBit 是一种严格类型的语言,具有类型推断。在上面的示例中,`let` 将一个符号绑定(我们更喜欢使用 _绑定_ 这个词而不是 " +"赋值)到一个值。该符号被推断为与该值具有相同的类型。将鼠标悬停在任何符号上以检查其类型。" + +#: ../../tutorial/tour.md:91 +msgid "" +"By default, the `let` - binding creates an immutable reference to a " +"value. That is, you cannot change the symbol to reference something else " +"without rebinding it (using `let`). Otherwise one should use `let mut`." +msgstr "" +"默认情况下,`let` - 绑定会创建一个不可变的引用到一个值。也就是说,您不能更改符号以引用其他内容而不重新绑定它(使用 " +"`let`)。否则,应该使用 `let mut`。" + +#: ../../tutorial/tour.md:93 +msgid "Function" +msgstr "函数" + +#: ../../tutorial/tour.md:95 +msgid "" +"Function is just a piece of code that takes some inputs and produce a " +"result. We may define a function using the keyword `fn` (function name in" +" MoonBit should not begin with uppercase letters A-Z):" +msgstr "" +"函数只是一段代码,它接受一些输入并产生一个结果。我们可以使用关键字 `fn` 定义一个函数(MoonBit 中的函数名不应以大写字母 A-Z " +"开头):" + +#: ../../tutorial/tour.md:97 +msgid "" +"fn identity[T](x : T) -> T {\n" +" // `Identity` won't work as it violates naming convention\n" +" x\n" +"}\n" +msgstr "" +"fn identity[T](x : T) -> T {\n" +" // `Identity` 不符合命名规范\n" +" x\n" +"}\n" + +#: ../../tutorial/tour.md:104 +msgid "" +"In this example, we provide types explicitly. Notice how it differs from " +"traditional C-like languages which uses prefix type notation `T x`, here " +"we use postfix type notation `x: T` (Formally, we call it _type " +"annotation_)." +msgstr "" +"在这个例子中,我们显式地提供了类型。请注意它与传统的类 C 语言的区别,传统的类 C 语言使用前缀类型表示法 `T " +"x`,而这里我们使用后缀类型表示法 `x: T`(正式地,我们称之为 _类型标注_)。" + +#: ../../tutorial/tour.md:107 +msgid "" +"We write a arrow `->` before the return type to show the nature of a " +"function: a map from some types to some other types. Formally, we call " +"this syntax _trailing return type_ (languages such as C++, Rust, Swift, " +"etc have this syntax as well)." +msgstr "" +"我们在返回类型之前写一个箭头 `->` 来显示函数的本质:从某些类型到某些其他类型的映射。正式地,我们称这种语法为 _尾随返回类型_ (诸如 " +"C++、Rust、Swift 等语言也有这种语法)。" + +#: ../../tutorial/tour.md:109 +msgid "" +"The word _expression_ is loosely used. Intuitively, An expression is " +"something with a value we care about." +msgstr "术语 _表达式_ 被宽泛地使用。直观地说,表达式是我们关心的具有值的东西。" + +#: ../../tutorial/tour.md:111 +msgid "" +"Consequently, a function type is denoted `(S) -> T` where `S` (within " +"parenthesis) is the parameter type and `T` is the return type. Functions " +"in MoonBit are first-class, meaning it's always possible to pass " +"functions around if you get the type right:" +msgstr "" +"因此,函数类型表示为 `(S) -> T`,其中 `S`(在括号内)是参数类型,`T` 是返回类型。MoonBit " +"中的函数是头等公民,这意味着如果您的类型正确,则始终可以传递函数:" + +#: ../../tutorial/tour.md:115 +msgid "" +"fn compose[S, T, U](f : (T) -> U, g : (S) -> T) -> (S) -> U {\n" +" let composition = fn(x : S) { f(g(x)) } // returns a composition of `f`" +" and `g`\n" +"\n" +" // moonbit also provides the pipe `|>` operator,\n" +" // similar to a lot of functional languages.\n" +" fn(x : S) { g(x) |> f } // equivalent\n" +"}\n" +msgstr "" +"fn compose[S, T, U](f : (T) -> U, g : (S) -> T) -> (S) -> U {\n" +" let composition = fn(x : S) { f(g(x)) } // 定义 `f` 和 `g` 的复合函数\n" +"\n" +" // 和其他函数式语言类似\n" +" // MoonBit 提供管道运算符 `|>`\n" +" fn(x : S) { g(x) |> f } // 等价写法\n" +"}\n" + +#: ../../tutorial/tour.md:125 +msgid "" +"Languages nowadays have something called _lambda expression_. Most " +"languages implement it as a mere syntactic sugar. A lambda expression is " +"really just a anonymous closure, this, is resembled in our MoonBit's " +"syntax:" +msgstr "" +"现在的语言中有一种叫做 _lambda 表达式_ 的东西。大多数语言将其实现为一种纯粹的语法糖。lambda " +"表达式实际上只是一个匿名闭包,这在我们 MoonBit 的语法中体现为:" + +#: ../../tutorial/tour.md:127 +msgid "" +"a closure only captures variables in its surroundings, together with its " +"bound variable, that is, having the same indentation level (suppose we've" +" formatted the code already)." +msgstr "闭包只捕获其周围的变量,以及其绑定变量,即具有相同缩进级别(假设我们已经格式化了代码)。" + +#: ../../tutorial/tour.md:129 +msgid "" +"fn foo() -> Int {\n" +" fn inc(x) { x + 1 } // named as `inc`\n" +" (fn (x) { x + inc(2) })(6) // anonymous, a so-called 'lambda " +"expression'\n" +" // function automatically captures the result of the last expression\n" +"}\n" +msgstr "" +"fn foo() -> Int {\n" +" fn inc(x) { x + 1 } // 命名为 `inc`\n" +" (fn (x) { x + inc(2) })(6) // 匿名函数,即 lambda 表达式\n" +" // 函数会自动捕捉最后一个表达式的值并返回\n" +"}\n" + +#: ../../tutorial/tour.md:137 +msgid "foo() // => 9\n" +msgstr "" + +#: ../../tutorial/tour.md:141 +msgid "Now we've learned the very basic, let's learn the rest by coding." +msgstr "现在我们已经学习了最基本的内容,让我们通过编码来学习其他内容。" + +#: ../../tutorial/tour.md:143 +msgid "Implementing List" +msgstr "实现列表" + +#: ../../tutorial/tour.md:145 +msgid "enum type" +msgstr "枚举类型" + +#: ../../tutorial/tour.md:147 +msgid "" +"A linked list is a series of node whose right cell is a reference to its " +"successor node. Sounds recursive? Because it is. Let's define it that way" +" using MoonBit:" +msgstr "链表是一系列节点,其右侧单元是对其后继节点的引用。听起来像是递归?因为它确实是。让我们使用 MoonBit 来定义它:" + +#: ../../tutorial/tour.md:149 +msgid "" +"enum List[T] {\n" +" Nil // base case: empty list\n" +" Cons(T, List[T]) // an recursive definition\n" +"}\n" +msgstr "" +"enum List[T] {\n" +" Nil // 基本情况:空表\n" +" Cons(T, List[T]) // 递归定义\n" +"}\n" + +#: ../../tutorial/tour.md:156 +msgid "" +"The `enum` type works like any `enum` from traditional OO languages. " +"However, let's refrain from using the OO-term `case`, we'll use " +"_constructor_ from now on. We may read the above code as" +msgstr "" +"`enum` 类型的工作方式类似于传统面向对象语言中的任何 `enum`。但是,让我们避免使用面向对象术语 `case`,从现在开始我们将使用 " +"_构造器_。我们可以将上面的代码理解为:" + +#: ../../tutorial/tour.md:158 +msgid "" +"the type `List[T]` can be constructed from the constructor `Nil` or " +"`Cons`, the former represents an empty list; the latter carries some data" +" of type `T` and the rest of the list." +msgstr "类型 `List[T]` 可以从构造器 `Nil` 或 `Cons` 构造,前者表示一个空列表;后者携带类型 `T` 的一些数据和列表的其余部分。" + +#: ../../tutorial/tour.md:160 +msgid "" +"The square bracket used here denotes a _polymorphic_ (generic) " +"definition, meaning a list of something of type `T`. Should we " +"_instantiate_ `T` with a concrete type like `Int`, we define a list " +"containing integers." +msgstr "这里使用的方括号表示 _多态_(泛型)定义,意味着一个类型为 `T` 的东西的列表。如果我们使用具体类型(如 `Int`)_实例化_ `T`," + +#: ../../tutorial/tour.md:162 +msgid "" +"Another datatype frequently used in MoonBit is our good old `Struct`, " +"which works like you would expect. Let's create a list of `User` using " +"the definition above and `Struct`:" +msgstr "" +"在 MoonBit 中经常使用的另一种数据类型是我们熟悉的 `Struct`,它的工作方式与您期望的一样。让我们使用上面的定义和 `Struct`" +" 创建一个 `User` 列表:" + +#: ../../tutorial/tour.md:164 +msgid "" +"struct User {\n" +" id : Int\n" +" name : String\n" +" // by default the properties/fields of a struct is immutable.\n" +" // the `mut` keyword works exactly the way we've mentioned before.\n" +" mut email : String\n" +"} derive(Show)\n" +"\n" +"// a method of User is defined by passing a object of type User as self " +"first.\n" +"// just like what you would do in Python.\n" +"// Note that methods may only be defined within the same package the type" +" is in.\n" +"// We may not define methods for foreign types directly\n" +"fn greetUser(self : User) -> String { // a method of struct/type/class " +"`User`\n" +" let id = self.id\n" +" let name = self.name\n" +" \"Greetings, \\{name} of id \\{id}\" // string interpolation\n" +"}\n" +"// construct a User object.\n" +"let evan : User = { id: 0, name: \"Evan\", email: \"someone@example.com\"" +" }\n" +"// we use a shorthand by duplicating evan's information\n" +"// and replacing w/ someone elses' email.\n" +"let listOfUser : List[User] = Cons(evan, Cons({ ..evan, email: " +"\"someoneelse@example.com\" }, Nil))\n" +msgstr "" +"struct User {\n" +" id : Int\n" +" name : String\n" +" // 默认情况下 Struct 的属性/字段是不可变的\n" +" // `mut` 关键字就和我们之前说的一样\n" +" mut email : String\n" +"} derive(Show)\n" +"\n" +"// 我们通过把函数第一个参数定义为 `self : User` 来给该Struct定义一个方法\n" +"// 写法和 Python 类似\n" +"// 注意:只有类型所在的包能为其定义方法。不能直接为外部类型定义方法。\n" +"fn greetUser(self : User) -> String { // `User`的一个方法\n" +" let id = self.id\n" +" let name = self.name\n" +" \"Greetings, \\{name} of id \\{id}\" // 字符串插值写法\n" +"}\n" +"// 构造 User 对象\n" +"let evan : User = { id: 0, name: \"Evan\", email: \"someone@example.com\"" +" }\n" +"// 可以用一个语法糖将 evan 的属性复制一遍\n" +"// 并将其 email 属性换成其他的值,构建一个新的对象\n" +"let listOfUser : List[User] = Cons(evan, Cons({ ..evan, email: " +"\"someoneelse@example.com\" }, Nil))\n" + +#: ../../tutorial/tour.md:189 +#, fuzzy +msgid "" +"Another datatype is `type`, a specific case of `enum` type. `type` can be" +" thought as a wrapper around an existing type, allowing additional " +"methods to be defined. Through this we extends the method definition of a" +" foreign type without actually modifying it. Consider the type of `name` " +"in `User`, we may define it as" +msgstr "" +"另一种数据类型是 `type`,是 `enum` 类型的特殊情况。`type` 可以被视为对现有类型的包装器,保留 `String` " +"的方法,但允许定义额外的方法。通过这种方式,我们可以扩展外部类型的方法定义,而无需实际修改它。考虑 `User` 中的 `name` " +"的类型,我们可以将其定义为:" + +#: ../../tutorial/tour.md:195 +msgid "" +"type UserName String // a newtype `UserName` based on `String`\n" +"\n" +"// defining a method for UserName is allowed but not String.\n" +"fn is_blank(self : UserName) -> Bool {\n" +" // use `._` to access its basetype String\n" +" // iter() creates a *internal iterator*\n" +" // which provides a functional way to iterate on sequences.\n" +" // find_first short circuits on the first `true` i.e. non-blank " +"character\n" +" let res = self._.iter().find_first(\n" +" fn(c) { if c == ' ' { false } else { true } },\n" +" )\n" +" match res {\n" +" Some(_) => false\n" +" // found NO non-blank character, thus it's a blank string.\n" +" None => true\n" +" }\n" +"}\n" +msgstr "" +"type UserName String // 一个新类型 UserName,基于 String\n" +"\n" +"// 可以为 UserName 定义方法,String 则不行\n" +"fn is_blank(self : UserName) -> Bool {\n" +" // 通过 `._` 访问其内部类型(String)\n" +" // iter() 创建一个内部迭代器(internal iterator)\n" +" // 并借此以函数式的风格在某个序列结构上迭代\n" +" // find_first 遇到第一个 true(即非空字符)就短路\n" +" let res = self._.iter().find_first(\n" +" fn(c) { if c == ' ' { false } else { true } },\n" +" )\n" +" match res {\n" +" Some(_) => false\n" +" // 找不到非空字符,所以是只由空格组成的字符串\n" +" None => true\n" +" }\n" +"}\n" + +#: ../../tutorial/tour.md:215 +msgid "" +"`enum`, `struct` and `newtype` are the 3 ways to define a datatype. There" +" isn't `class` in MoonBit, nor does it need that." +msgstr "`enum`、`struct` 和 `newtype` 是定义数据类型的 3 种方式。MoonBit 中没有 `class`,也不需要。" + +#: ../../tutorial/tour.md:218 +msgid "" +"the `derive` keyword is like Java's `implements`. Here `Show` is a " +"_trait_ which indicates a type is printable. So what is a trait?" +msgstr "" +"`derive` 关键字类似于 Java 的 `implements`。这里的 `Show` 是一个 " +"_trait_,表示一个类型是可打印的。那么什么是 trait?" + +#: ../../tutorial/tour.md:221 +msgid "Trait" +msgstr "特征" + +#: ../../tutorial/tour.md:223 +msgid "" +"A trait (or type trait) is what we would call an `interface` in " +"traditional OO-languages. `println(evan)` would print `{id: 0, name: " +"\"Evan\", email: \"someone@example.com\"}`. As `User` consists of builtin" +" types `Int` `String`, which already implements `Show`. Therefore we do " +"not need to implement it explicitly. Let's implement our own trait " +"`Printable` by implementing `to_string()`:" +msgstr "" +"特征(或类型特征)是我们在传统面向对象语言中称为 `interface` 的东西。`println(evan)` 将打印 `{id: 0, " +"name: \"Evan\", email: \"someone@example.com\"}`。由于 `User` 由内置类型 `Int` " +"`String` 组成,这些类型已经实现了 `Show`。因此我们不需要显式实现它。让我们通过实现 `to_string()` " +"来实现我们自己的特征 `Printable`:" + +#: ../../tutorial/tour.md:229 +msgid "" +"trait Printable {\n" +" to_string(Self) -> String\n" +"}\n" +"\n" +"fn to_string(self : User) -> String {\n" +" (self.id, self.name, self.email).to_string()\n" +"} // now `Printable` is implemented\n" +"\n" +"fn to_string[T : Printable](self : List[T]) -> String {\n" +" let string_aux = to_string_aux(self)\n" +" // function arguments can have label\n" +" \"[\" + string_aux.substring(end=string_aux.length() - 1) + \"]\"\n" +"}\n" +"\n" +"// polymorphic functions have to be toplevel.\n" +"fn to_string_aux[T : Printable](self : List[T]) -> String {\n" +" match self {\n" +" Nil => \"\"\n" +" Cons(x, xs) => \"\\{x} \" + to_string_aux(xs)\n" +" }\n" +"}\n" +msgstr "" +"trait Printable {\n" +" to_string(Self) -> String\n" +"}\n" +"\n" +"fn to_string(self : User) -> String {\n" +" (self.id, self.name, self.email).to_string()\n" +"} 这样就实现了`Printable`\n" +"\n" +"fn to_string[T : Printable](self : List[T]) -> String {\n" +" let string_aux = to_string_aux(self)\n" +" // 函数参数可以有标签\n" +" \"[\" + string_aux.substring(end=string_aux.length() - 1) + \"]\"\n" +"}\n" +"\n" +"// 多态函数一定是顶层函数\n" +"fn to_string_aux[T : Printable](self : List[T]) -> String {\n" +" match self {\n" +" Nil => \"\"\n" +" Cons(x, xs) => \"\\{x} \" + to_string_aux(xs)\n" +" }\n" +"}\n" + +#: ../../tutorial/tour.md:253 +msgid "" +"listOfUser.to_string()\n" +"// => [(0, Evan, someone@example.com) (0, Evan, someoneelse@example.com)]" +"\n" +msgstr "" + +#: ../../tutorial/tour.md:258 +msgid "" +"We use `` in Java to constrain the type of list " +"element to make sure objects of type `T` can be printed, similarly, in " +"MoonBit we would write `[T: Printable]`." +msgstr "" +"我们在 Java 中使用 `` 来约束列表元素的类型,以确保类型为 `T` 的对象可以被打印,同样,在 " +"MoonBit 中我们会写 `[T: Printable]`。" + +#: ../../tutorial/tour.md:261 +msgid "Pattern Matching" +msgstr "模式匹配" + +#: ../../tutorial/tour.md:263 +msgid "" +"In the example above we use the `match` expression, a core feature of " +"MoonBit (and many other functional programming languages.) In short, we " +"use pattern matching to _destructure_ (to strip the encapsulation of) a " +"structure." +msgstr "" +"在上面的示例中,我们使用了 `match` 表达式,这是 MoonBit(以及许多其他函数式编程语言)的核心特性。简而言之,我们使用模式匹配来 " +"_解构_(剥离封装)一个结构。" + +#: ../../tutorial/tour.md:267 +msgid "We may express the above `match` code as" +msgstr "我们可以将上面的 `match` 代码表示为:" + +#: ../../tutorial/tour.md:269 +msgid "" +"if `self` is constructed with `Nil` (an empty list), we return `\"\"`; " +"otherwise if `self` is constructed with `Cons(x,xs)` (a non-empty list) " +"we print `x` and rest of the list. Where `x` is the head of the `self` " +"and `xs` being the rest." +msgstr "" +"如果 `self` 是用 `Nil`(空列表)构造的,我们返回 `\"\"`;否则,如果 `self` 是用 " +"`Cons(x,xs)`(非空列表)构造的,我们打印 `x` 和列表的其余部分。其中 `x` 是 `self` 的头部,`xs` 是其余部分。" + +#: ../../tutorial/tour.md:274 +msgid "" +"Intuitively, we extract `x` and `xs` (they are bound in situ) from `self`" +" using pattern matching. Let's implement typical list operations such as " +"`map` `reduce` `zip`:" +msgstr "" +"直观地说,我们使用模式匹配从 `self` 中提取 `x` 和 `xs`(它们在原地绑定)。让我们实现典型的列表操作,如 `map` " +"`reduce` `zip`:" + +#: ../../tutorial/tour.md:277 +msgid "" +"fn map[S, T](self : List[S], f : (S) -> T) -> List[T] {\n" +" match self {\n" +" Nil => Nil\n" +" Cons(x, xs) => Cons(f(x), map(xs, f))\n" +" }\n" +"}\n" +"\n" +"fn reduce[S, T](self : List[S], op : (T, S) -> T, init : T) -> T {\n" +" match self {\n" +" Nil => init\n" +" Cons(x, xs) => reduce(xs, op, op(init, x))\n" +" }\n" +"}\n" +"\n" +"fn zip[T](self : List[T], other : List[T]) -> List[T] {\n" +" match (self, other) {\n" +" (Nil, _) => Nil // we use underscore to ignore the value we don't " +"care\n" +" (_, Nil) => Nil\n" +" (Cons(x, xs), Cons(y, ys)) => Cons(x, Cons(y, zip(xs, ys)))\n" +" }\n" +"}\n" +msgstr "" +"fn map[S, T](self : List[S], f : (S) -> T) -> List[T] {\n" +" match self {\n" +" Nil => Nil\n" +" Cons(x, xs) => Cons(f(x), map(xs, f))\n" +" }\n" +"}\n" +"\n" +"fn reduce[S, T](self : List[S], op : (T, S) -> T, init : T) -> T {\n" +" match self {\n" +" Nil => init\n" +" Cons(x, xs) => reduce(xs, op, op(init, x))\n" +" }\n" +"}\n" +"\n" +"fn zip[T](self : List[T], other : List[T]) -> List[T] {\n" +" match (self, other) {\n" +" (Nil, _) => Nil // 我们用下划线表示我们不关心的值\n" +" (_, Nil) => Nil\n" +" (Cons(x, xs), Cons(y, ys)) => Cons(x, Cons(y, zip(xs, ys)))\n" +" }\n" +"}\n" + +#: ../../tutorial/tour.md:301 +msgid "" +"Now we have a somewhat usable `List` type. Realistically, we always " +"prefer the builtin `Array` which is much more efficient." +msgstr "现在我们有了一个可以使用的 `List` 类型。实际上,我们总是更喜欢内置的 `Array`,它更高效。" + +#: ../../tutorial/tour.md:304 +msgid "" +"Pattern matching can be used in `let` as well. In `greetUser()`, instead " +"of writing 2 `let`'s, we may write" +msgstr "模式匹配也可以在 `let` 中使用。在 `greetUser()` 中,我们可以把两个`let`绑定改写成:" + +#: ../../tutorial/tour.md:307 +msgid "" +"fn greetUserAlt(self : User) -> String {\n" +" // extract `id` `name` from `self` of type User. ignores email.\n" +" let { id: id, name: name, email: _ } = self\n" +" // equivalent, but ignores the rest.\n" +" let { id, name, .. } = self\n" +" \"Greetings, \\{name} of id \\{id}\"\n" +"}\n" +msgstr "" +"fn greetUserAlt(self : User) -> String {\n" +" // 从 self 中提取 id name 字段,忽略 email\n" +" let { id: id, name: name, email: _ } = self\n" +" // 等价写法,但是忽略 id name 以外的所有字段\n" +" let { id, name, .. } = self\n" +" \"Greetings, \\{name} of id \\{id}\"\n" +"}\n" + +#: ../../tutorial/tour.md:317 +msgid "Iteration" +msgstr "迭代" + +#: ../../tutorial/tour.md:319 +msgid "" +"Finally, let's talk about the major point of every OO-language: looping. " +"Although we've been using recursion most of the times, MoonBit is " +"designed to be multi-paradigm, thus it retains C-style imperative `for` " +"`while` loop." +msgstr "" +"最后,让我们谈谈每种面向对象语言的主要特点:循环。尽管我们大多数时候都在使用递归,但 MoonBit 被设计为多范式,因此它保留了类 C " +"风格的命令式 `for` `while` 循环。" + +#: ../../tutorial/tour.md:324 +msgid "" +"Additionally, MoonBit provides a more interesting loop construct, the " +"functional loop. For example the Fibonacci number can be calculated by" +msgstr "此外,MoonBit 还提供了一个更有趣的循环结构,即函数式循环。例如,可以通过以下方式计算斐波那契数:" + +#: ../../tutorial/tour.md:327 +msgid "" +"fn fib(n : Int) -> Int {\n" +" loop n, 0, 1 { // introduces 3 loop variables: `n` `a = 0` `b = 1`\n" +" // pattern matching is available in `loop`\n" +" 0, a, b => a // what can be constructed from 0 -- Only 0 it self!\n" +" // assign `b` to `a`, `(a + b)` to `b`, decrease counter `n`\n" +" n, a, b => continue n - 1, b, a + b\n" +" }\n" +"}\n" +msgstr "" +"fn fib(n : Int) -> Int {\n" +" loop n, 0, 1 { // 引入了三个循环变量 `n` `a = 0` `b = 1`\n" +" // `loop` 中也可以使用模式匹配\n" +" 0, a, b => a // 只有 0 能从 0 构造出来\n" +" // 将 `b` 赋值给 `a`, `(a + b)` 赋值给 `b`,循环计数器 `n - 1`\n" +" n, a, b => continue n - 1, b, a + b\n" +" }\n" +"}\n" + +#: ../../tutorial/tour.md:338 +msgid "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(fib) // => [1,1,2,3,5,8,13,21,34,55]\n" +msgstr "" + +#: ../../tutorial/tour.md:342 +msgid "" +"Semantic-wise, the `loop` construct focuses more on the transition of " +"each state, providing better readability, preserving recursive flavor and" +" same performance without writing [tail-" +"recursion](https://en.wikipedia.org/wiki/Tail_call) explicitly." +msgstr "" +"从语义上讲,`loop` 结构更注重每个状态的转换,提供更好的可读性,保留递归风格,并在不显式编写 " +"[尾递归](https://baike.baidu.com/item/尾递归/554682) 的情况下保持相同的性能。" + +#: ../../tutorial/tour.md:345 +msgid "Closing" +msgstr "结束语" + +#: ../../tutorial/tour.md:347 +msgid "" +"At this point, we've learned about the very basic and most not-so-trivial" +" features of MoonBit, yet MoonBit is a feature-rich, multi-paradigm " +"programming language. After making sure that you are comfortable with the" +" basics of MoonBit, we suggest that you look into some [interesting " +"examples](https://github.com/moonbitlang/moonbit-" +"docs/tree/main/legacy/examples) to get a better hold of MoonBit." +msgstr "" +"到目前为止,我们已经了解了 MoonBit 的基本特性和一些不那么简单的特性,但 MoonBit 是一种功能丰富的多范式编程语言。在确保您对 " +"MoonBit 的基础知识感到满意后,我们建议您查看一些[有趣的示例](https://github.com/moonbitlang" +"/moonbit-docs/tree/main/legacy/examples) 以更好地掌握 MoonBit。" + diff --git a/next/make.bat b/next/make.bat new file mode 100644 index 00000000..32bb2452 --- /dev/null +++ b/next/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/next/requirements.txt b/next/requirements.txt new file mode 100644 index 00000000..b7c62043 --- /dev/null +++ b/next/requirements.txt @@ -0,0 +1,29 @@ +alabaster==1.0.0 +babel==2.16.0 +certifi==2024.8.30 +charset-normalizer==3.4.0 +click==8.1.7 +docutils==0.21.2 +idna==3.10 +imagesize==1.4.1 +Jinja2==3.1.4 +markdown-it-py==3.0.0 +MarkupSafe==3.0.2 +mdit-py-plugins==0.4.2 +mdurl==0.1.2 +myst-parser==4.0.0 +packaging==24.2 +Pygments==2.18.0 +PyYAML==6.0.2 +requests==2.32.3 +setuptools==75.5.0 +snowballstemmer==2.2.0 +Sphinx==8.1.3 +sphinx-intl==2.3.0 +sphinxcontrib-applehelp==2.0.0 +sphinxcontrib-devhelp==2.0.0 +sphinxcontrib-htmlhelp==2.1.0 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==2.0.0 +sphinxcontrib-serializinghtml==2.0.0 +urllib3==2.2.3 diff --git a/next/toolchain/index.md b/next/toolchain/index.md new file mode 100644 index 00000000..4469bcc3 --- /dev/null +++ b/next/toolchain/index.md @@ -0,0 +1,12 @@ +# Toolchains + +Here are some manuals that may help you use the toolchains of the programming language: + +- [MoonBit's Build System](./moon/index.md): full manual of `moon` build system. +- VSCode extension +- ... + +```{toctree} +:maxdepth: 2 +:caption: Contents: +moon/index \ No newline at end of file diff --git a/next/toolchain/moon/commands.md b/next/toolchain/moon/commands.md new file mode 100644 index 00000000..f37e1ead --- /dev/null +++ b/next/toolchain/moon/commands.md @@ -0,0 +1,605 @@ +# Command-Line Help for `moon` + +This document contains the help content for the `moon` command-line program. + +**Command Overview:** + +* [`moon`↴](#moon) +* [`moon new`↴](#moon-new) +* [`moon build`↴](#moon-build) +* [`moon check`↴](#moon-check) +* [`moon run`↴](#moon-run) +* [`moon test`↴](#moon-test) +* [`moon clean`↴](#moon-clean) +* [`moon fmt`↴](#moon-fmt) +* [`moon doc`↴](#moon-doc) +* [`moon info`↴](#moon-info) +* [`moon add`↴](#moon-add) +* [`moon remove`↴](#moon-remove) +* [`moon install`↴](#moon-install) +* [`moon tree`↴](#moon-tree) +* [`moon login`↴](#moon-login) +* [`moon register`↴](#moon-register) +* [`moon publish`↴](#moon-publish) +* [`moon package`↴](#moon-package) +* [`moon update`↴](#moon-update) +* [`moon coverage`↴](#moon-coverage) +* [`moon coverage report`↴](#moon-coverage-report) +* [`moon coverage clean`↴](#moon-coverage-clean) +* [`moon generate-build-matrix`↴](#moon-generate-build-matrix) +* [`moon upgrade`↴](#moon-upgrade) +* [`moon shell-completion`↴](#moon-shell-completion) +* [`moon version`↴](#moon-version) + +## `moon` + +**Usage:** `moon ` + +###### **Subcommands:** + +* `new` — Create a new MoonBit module +* `build` — Build the current package +* `check` — Check the current package, but don't build object files +* `run` — Run a main package +* `test` — Test the current package +* `clean` — Remove the target directory +* `fmt` — Format source code +* `doc` — Generate documentation +* `info` — Generate public interface (`.mbti`) files for all packages in the module +* `add` — Add a dependency +* `remove` — Remove a dependency +* `install` — Install dependencies +* `tree` — Display the dependency tree +* `login` — Log in to your account +* `register` — Register an account at mooncakes.io +* `publish` — Publish the current module +* `package` — Package the current module +* `update` — Update the package registry index +* `coverage` — Code coverage utilities +* `generate-build-matrix` — Generate build matrix for benchmarking (legacy feature) +* `upgrade` — Upgrade toolchains +* `shell-completion` — Generate shell completion for bash/elvish/fish/pwsh/zsh to stdout +* `version` — Print version information and exit + + + +## `moon new` + +Create a new MoonBit module + +**Usage:** `moon new [OPTIONS] [PACKAGE_NAME]` + +###### **Arguments:** + +* `` — The name of the package + +###### **Options:** + +* `--lib` — Create a library package instead of an executable +* `--path ` — Output path of the package +* `--user ` — The user name of the package +* `--name ` — The name part of the package +* `--license ` — The license of the package + + Default value: `Apache-2.0` +* `--no-license` — Do not set a license for the package + + + +## `moon build` + +Build the current package + +**Usage:** `moon build [OPTIONS]` + +###### **Options:** + +* `--std` — Enable the standard library (default) +* `--nostd` — Disable the standard library +* `-g`, `--debug` — Emit debug information +* `--release` — Compile in release mode +* `--target ` — Select output target + + Possible values: `wasm`, `wasm-gc`, `js`, `native`, `all` + +* `--serial` — Handle the selected targets sequentially +* `--enable-coverage` — Enable coverage instrumentation +* `--sort-input` — Sort input files +* `--output-wat` — Output WAT instead of WASM +* `-d`, `--deny-warn` — Treat all warnings as errors +* `--no-render` — Don't render diagnostics from moonc (don't pass '-error-format json' to moonc) +* `--frozen` — Do not sync dependencies, assuming local dependencies are up-to-date +* `-w`, `--watch` — Monitor the file system and automatically build artifacts + + + +## `moon check` + +Check the current package, but don't build object files + +**Usage:** `moon check [OPTIONS] [PACKAGE_PATH]` + +###### **Arguments:** + +* `` — The package(and it's deps) to check + +###### **Options:** + +* `--std` — Enable the standard library (default) +* `--nostd` — Disable the standard library +* `-g`, `--debug` — Emit debug information +* `--release` — Compile in release mode +* `--target ` — Select output target + + Possible values: `wasm`, `wasm-gc`, `js`, `native`, `all` + +* `--serial` — Handle the selected targets sequentially +* `--enable-coverage` — Enable coverage instrumentation +* `--sort-input` — Sort input files +* `--output-wat` — Output WAT instead of WASM +* `-d`, `--deny-warn` — Treat all warnings as errors +* `--no-render` — Don't render diagnostics from moonc (don't pass '-error-format json' to moonc) +* `--output-json` — Output in json format +* `--frozen` — Do not sync dependencies, assuming local dependencies are up-to-date +* `-w`, `--watch` — Monitor the file system and automatically check files +* `--patch-file ` — The patch file to check, Only valid when checking specified package +* `--no-mi` — Whether to skip the mi generation, Only valid when checking specified package + + + +## `moon run` + +Run a main package + +**Usage:** `moon run [OPTIONS] [ARGS]...` + +###### **Arguments:** + +* `` — The package or .mbt file to run +* `` — The arguments provided to the program to be run + +###### **Options:** + +* `--std` — Enable the standard library (default) +* `--nostd` — Disable the standard library +* `-g`, `--debug` — Emit debug information +* `--release` — Compile in release mode +* `--target ` — Select output target + + Possible values: `wasm`, `wasm-gc`, `js`, `native`, `all` + +* `--serial` — Handle the selected targets sequentially +* `--enable-coverage` — Enable coverage instrumentation +* `--sort-input` — Sort input files +* `--output-wat` — Output WAT instead of WASM +* `-d`, `--deny-warn` — Treat all warnings as errors +* `--no-render` — Don't render diagnostics from moonc (don't pass '-error-format json' to moonc) +* `--frozen` — Do not sync dependencies, assuming local dependencies are up-to-date +* `--build-only` — Only build, do not run the code + + + +## `moon test` + +Test the current package + +**Usage:** `moon test [OPTIONS]` + +###### **Options:** + +* `--std` — Enable the standard library (default) +* `--nostd` — Disable the standard library +* `-g`, `--debug` — Emit debug information +* `--release` — Compile in release mode +* `--target ` — Select output target + + Possible values: `wasm`, `wasm-gc`, `js`, `native`, `all` + +* `--serial` — Handle the selected targets sequentially +* `--enable-coverage` — Enable coverage instrumentation +* `--sort-input` — Sort input files +* `--output-wat` — Output WAT instead of WASM +* `-d`, `--deny-warn` — Treat all warnings as errors +* `--no-render` — Don't render diagnostics from moonc (don't pass '-error-format json' to moonc) +* `-p`, `--package ` — Run test in the specified package +* `-f`, `--file ` — Run test in the specified file. Only valid when `--package` is also specified +* `-i`, `--index ` — Run only the index-th test in the file. Only valid when `--file` is also specified +* `-u`, `--update` — Update the test snapshot +* `-l`, `--limit ` — Limit of expect test update passes to run, in order to avoid infinite loops + + Default value: `256` +* `--frozen` — Do not sync dependencies, assuming local dependencies are up-to-date +* `--build-only` — Only build, do not run the tests +* `--no-parallelize` — Run the tests in a target backend sequentially +* `--test-failure-json` — Print failure message in JSON format +* `--patch-file ` — Path to the patch file +* `--doc` — Run doc test + + + +## `moon clean` + +Remove the target directory + +**Usage:** `moon clean` + + + +## `moon fmt` + +Format source code + +**Usage:** `moon fmt [OPTIONS] [ARGS]...` + +###### **Arguments:** + +* `` + +###### **Options:** + +* `--check` — Check only and don't change the source code +* `--sort-input` — Sort input files +* `--block-style ` — Add separator between each segments + + Possible values: `false`, `true` + + + + +## `moon doc` + +Generate documentation + +**Usage:** `moon doc [OPTIONS]` + +###### **Options:** + +* `--serve` — Start a web server to serve the documentation +* `-b`, `--bind ` — The address of the server + + Default value: `127.0.0.1` +* `-p`, `--port ` — The port of the server + + Default value: `3000` +* `--frozen` — Do not sync dependencies, assuming local dependencies are up-to-date + + + +## `moon info` + +Generate public interface (`.mbti`) files for all packages in the module + +**Usage:** `moon info [OPTIONS]` + +###### **Options:** + +* `--frozen` — Do not sync dependencies, assuming local dependencies are up-to-date +* `--no-alias` — Do not use alias to shorten package names in the output + + + +## `moon add` + +Add a dependency + +**Usage:** `moon add ` + +###### **Arguments:** + +* `` — The package path to add + + + +## `moon remove` + +Remove a dependency + +**Usage:** `moon remove ` + +###### **Arguments:** + +* `` — The package path to remove + + + +## `moon install` + +Install dependencies + +**Usage:** `moon install` + + + +## `moon tree` + +Display the dependency tree + +**Usage:** `moon tree` + + + +## `moon login` + +Log in to your account + +**Usage:** `moon login` + + + +## `moon register` + +Register an account at mooncakes.io + +**Usage:** `moon register` + + + +## `moon publish` + +Publish the current module + +**Usage:** `moon publish [OPTIONS]` + +###### **Options:** + +* `--frozen` — Do not sync dependencies, assuming local dependencies are up-to-date + + + +## `moon package` + +Package the current module + +**Usage:** `moon package [OPTIONS]` + +###### **Options:** + +* `--frozen` — Do not sync dependencies, assuming local dependencies are up-to-date +* `--list` + + + +## `moon update` + +Update the package registry index + +**Usage:** `moon update` + + + +## `moon coverage` + +Code coverage utilities + +**Usage:** `moon coverage ` + +###### **Subcommands:** + +* `report` — Generate code coverage report +* `clean` — Clean up coverage artifacts + + + +## `moon coverage report` + +Generate code coverage report + +**Usage:** `moon coverage report [args]... [COMMAND]` + +###### **Arguments:** + +* `` — Arguments to pass to the coverage utility + +###### **Options:** + +* `-h`, `--help` — Show help for the coverage utility + + + +## `moon coverage clean` + +Clean up coverage artifacts + +**Usage:** `moon coverage clean` + + + +## `moon generate-build-matrix` + +Generate build matrix for benchmarking (legacy feature) + +**Usage:** `moon generate-build-matrix [OPTIONS] --output-dir ` + +###### **Options:** + +* `-n ` — Set all of `drow`, `dcol`, `mrow`, `mcol` to the same value +* `--drow ` — Number of directory rows +* `--dcol ` — Number of directory columns +* `--mrow ` — Number of module rows +* `--mcol ` — Number of module columns +* `-o`, `--output-dir ` — The output directory + + + +## `moon upgrade` + +Upgrade toolchains + +**Usage:** `moon upgrade [OPTIONS]` + +###### **Options:** + +* `-f`, `--force` — Force upgrade + + + +## `moon shell-completion` + +Generate shell completion for bash/elvish/fish/pwsh/zsh to stdout + +**Usage:** `moon shell-completion [OPTIONS]` + + +Discussion: +Enable tab completion for Bash, Elvish, Fish, Zsh, or PowerShell +The script is output on `stdout`, allowing one to re-direct the +output to the file of their choosing. Where you place the file +will depend on which shell, and which operating system you are +using. Your particular configuration may also determine where +these scripts need to be placed. + +The completion scripts won't update itself, so you may need to +periodically run this command to get the latest completions. +Or you may put `eval "$(moon shell-completion --shell )"` +in your shell's rc file to always load newest completions on startup. +Although it's considered not as efficient as having the completions +script installed. + +Here are some common set ups for the three supported shells under +Unix and similar operating systems (such as GNU/Linux). + +Bash: + +Completion files are commonly stored in `/etc/bash_completion.d/` for +system-wide commands, but can be stored in +`~/.local/share/bash-completion/completions` for user-specific commands. +Run the command: + + $ mkdir -p ~/.local/share/bash-completion/completions + $ moon shell-completion --shell bash >> ~/.local/share/bash-completion/completions/moon + +This installs the completion script. You may have to log out and +log back in to your shell session for the changes to take effect. + +Bash (macOS/Homebrew): + +Homebrew stores bash completion files within the Homebrew directory. +With the `bash-completion` brew formula installed, run the command: + + $ mkdir -p $(brew --prefix)/etc/bash_completion.d + $ moon shell-completion --shell bash > $(brew --prefix)/etc/bash_completion.d/moon.bash-completion + +Fish: + +Fish completion files are commonly stored in +`$HOME/.config/fish/completions`. Run the command: + + $ mkdir -p ~/.config/fish/completions + $ moon shell-completion --shell fish > ~/.config/fish/completions/moon.fish + +This installs the completion script. You may have to log out and +log back in to your shell session for the changes to take effect. + +Elvish: + +Elvish completions are commonly stored in a single `completers` module. +A typical module search path is `~/.config/elvish/lib`, and +running the command: + + $ moon shell-completion --shell elvish >> ~/.config/elvish/lib/completers.elv + +will install the completions script. Note that use `>>` (append) +instead of `>` (overwrite) to prevent overwriting the existing completions +for other commands. Then prepend your rc.elv with: + + `use completers` + +to load the `completers` module and enable completions. + +Zsh: + +ZSH completions are commonly stored in any directory listed in +your `$fpath` variable. To use these completions, you must either +add the generated script to one of those directories, or add your +own to this list. + +Adding a custom directory is often the safest bet if you are +unsure of which directory to use. First create the directory; for +this example we'll create a hidden directory inside our `$HOME` +directory: + + $ mkdir ~/.zfunc + +Then add the following lines to your `.zshrc` just before +`compinit`: + + fpath+=~/.zfunc + +Now you can install the completions script using the following +command: + + $ moon shell-completion --shell zsh > ~/.zfunc/_moon + +You must then open a new zsh session, or simply run + + $ . ~/.zshrc + +for the new completions to take effect. + +Custom locations: + +Alternatively, you could save these files to the place of your +choosing, such as a custom directory inside your $HOME. Doing so +will require you to add the proper directives, such as `source`ing +inside your login script. Consult your shells documentation for +how to add such directives. + +PowerShell: + +The powershell completion scripts require PowerShell v5.0+ (which +comes with Windows 10, but can be downloaded separately for windows 7 +or 8.1). + +First, check if a profile has already been set + + PS C:\> Test-Path $profile + +If the above command returns `False` run the following + + PS C:\> New-Item -path $profile -type file -force + +Now open the file provided by `$profile` (if you used the +`New-Item` command it will be +`${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1` + +Next, we either save the completions file into our profile, or +into a separate file and source it inside our profile. To save the +completions into our profile simply use + + PS C:\> moon shell-completion --shell powershell >> + ${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 + +This discussion is taken from `rustup completions` command with some changes. + + +###### **Options:** + +* `--shell ` — The shell to generate completion for + + Default value: `` + + Possible values: `bash`, `elvish`, `fish`, `powershell`, `zsh` + + + + +## `moon version` + +Print version information and exit + +**Usage:** `moon version [OPTIONS]` + +###### **Options:** + +* `--all` — Print all version information +* `--json` — Print version information in JSON format +* `--no-path` — Do not print the path + + + +
+ + + This document was generated automatically by + clap-markdown. + \ No newline at end of file diff --git a/next/toolchain/moon/index.md b/next/toolchain/moon/index.md new file mode 100644 index 00000000..e08a1877 --- /dev/null +++ b/next/toolchain/moon/index.md @@ -0,0 +1,10 @@ +# Moon Build System + +```{toctree} +:maxdepth: 2 +:caption: Contents: +tutorial +package-manage-tour +commands +module +package \ No newline at end of file diff --git a/next/toolchain/moon/module.md b/next/toolchain/moon/module.md new file mode 100644 index 00000000..9fe8a7c6 --- /dev/null +++ b/next/toolchain/moon/module.md @@ -0,0 +1,176 @@ +# Module Configuration + +moon uses the `moon.mod.json` file to identify and describe a module. + +## Name + +The `name` field is used to specify the name of the module, and it is required. + +```json +{ + "name": "example", + ... +} +``` + +The module name can contain letters, numbers, `_`, `-`, and `/`. + +For modules published to [mooncakes.io](https://mooncakes.io), the module name must begin with the username. For example: + +```json +{ + "name": "moonbitlang/core", + ... +} +``` + +## Version + +The `version` field is used to specify the version of the module. + +This field is optional. For modules published to [mooncakes.io](https://mooncakes.io), the version number must follow the [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html) specification. + +```json +{ + "name": "example", + "version": "0.1.0", + ... +} +``` + +## Deps + +The `deps` field is used to specify the dependencies of the module. + +It is automatically managed by commands like `moon add` and `moon remove`. + +```json +{ + "name": "username/hello", + "deps": { + "moonbitlang/x": "0.4.6" + } +} +``` + +## README + +The `readme` field is used to specify the path to the module's README file. + +## Repository + +The `repository` field is used to specify the URL of the module's repository. + +## License + +The `license` field is used to specify the license of the module. The license type must comply with the [SPDX License List](https://spdx.org/licenses/). + +```json +{ + "license": "MIT" +} +``` + +## Keywords + +The `keywords` field is used to specify the keywords for the module. + +```json +{ + "keywords": ["example", "test"] +} +``` + +## Description + +The `description` field is used to specify the description of the module. + +```json +{ + "description": "This is a description of the module." +} +``` + +## Source directory + +The `source` field is used to specify the source directory of the module. + +It must be a subdirectory of the directory where the `moon.mod.json` file is located and must be a relative path. + +When creating a module using the `moon new` command, a `src` directory will be automatically generated, and the default value of the `source` field will be `src`. + +```json +{ + "source": "src" +} +``` + +When the `source` field does not exist, or its value is `null` or an empty string `""`, it is equivalent to setting `"source": "."`. This means that the source directory is the same as the directory where the `moon.mod.json` file is located. + +```json +{ + "source": null +} +{ + "source": "" +} +{ + "source": "." +} +``` + +## Warning List + +This is used to disable specific preset compiler warning numbers. + +For example, in the following configuration, `-2` disables the warning number 2 (Unused variable). + +```json +{ + "warn-list": "-2", +} +``` + +You can use `moonc build-package -warn-help` to see the list of preset compiler warning numbers. + +``` +$ moonc -v +v0.1.20240914+b541585d3 + +$ moonc build-package -warn-help +Available warnings: + 1 Unused function. + 2 Unused variable. + 3 Unused type declaration. + 4 Redundant case in a pattern matching (unused match case). + 5 Unused function argument. + 6 Unused constructor. + 7 Unused module declaration. + 8 Unused struct field. + 10 Unused generic type variable. + 11 Partial pattern matching. + 12 Unreachable code. + 13 Unresolved type variable. + 14 Lowercase type name. + 15 Unused mutability. + 16 Parser inconsistency. + 18 Useless loop expression. + 19 Top-level declaration is not left aligned. + 20 Invalid pragma + 21 Some arguments of constructor are omitted in pattern. + 22 Ambiguous block. + 23 Useless try expression. + 24 Useless error type. + 26 Useless catch all. + A all warnings +``` + +## Alert List + +Disable user preset alerts. + +```json +{ + "alert-list": "-alert_1-alert_2" +} +``` \ No newline at end of file diff --git a/next/toolchain/moon/package-manage-tour.md b/next/toolchain/moon/package-manage-tour.md new file mode 100644 index 00000000..94e266a9 --- /dev/null +++ b/next/toolchain/moon/package-manage-tour.md @@ -0,0 +1,124 @@ +# MoonBit's Package Manager Tutorial + +## Overview + +MoonBit's build system seamlessly integrates package management and documentation generation tools, allowing users to easily fetch dependencies from mooncakes.io, access module documentation, and publish new modules. + +[mooncakes.io](https://mooncakes.io/) is a centralized package management platform. Each module has a corresponding configuration file `moon.mod.json`, which is the smallest unit for publishing. Under the module's path, there can be multiple packages, each corresponding to a `moon.pkg.json` configuration file. The `.mbt` files at the same level as `moon.pkg.json` belong to this package. + +Before getting started, make sure you have installed [moon](https://www.moonbitlang.com/download/). + +## Setup mooncakes.io account + +**Note: If you don't need to publishing, you can skip this step.** + +If you don't have an account on mooncakes.io, run `moon register` and follow the guide. If you have previously registered an account, you can use `moon login` to log in. + +When you see the following message, it means you have successfully logged in: + +``` +API token saved to ~/.moon/credentials.json +``` + +## Update index + +Use `moon update` to update the mooncakes.io index. + +![moon update cli](/imgs/moon-update.png) + +## Setup MoonBit project + +Open an existing project or create a new project via `moon new`: + +![moon new](/imgs/moon-new.png) + +## Add dependencies + +You can browse all available modules on mooncakes.io. Use `moon add` to add the dependencies you need, or manually edit the `deps` field in `moon.mod.json`. + +For example, to add the latest version of the `Yoorkin/example/list` module: + +![add deps](/imgs/add-deps.png) + +## Import packages from module + +Modify the configuration file `moon.pkg.json` and declare the packages that need to be imported in the `import` field. + +For example, in the image below, the `hello/main/moon.pkg.json` file is modified to declare the import of `Yoorkin/example/list` in the `main` package. Now, you can call the functions of the third-party package in the `main` package using `@list`. + +![import package](/imgs/import.png) + +You can also give an alias to the imported package: + +```json +{ + "is_main": true, + "import": [ + { "path": "Yoorkin/example/list", "alias": "ls" } + ] +} +``` + +Read the documentation of this module on mooncakes.io, we can use its `of_array` and `reverse` functions to implement a new function `reverse_array`. + +![reverse array](/imgs/reverse-array.png) + +## Remove dependencies + +You can remove dependencies via `moon remove `. + +## Publish your module + +If you are ready to share your module, use `moon publish` to push a module to +mooncakes.io. There are some important considerations to keep in mind before publishing: + +### Semantic versioning convention + +MoonBit's package management follows the convention of [Semantic Versioning](https://semver.org/). Each module must define a version number in the format `MAJOR.MINOR.PATCH`. With each push, the module must increment the: + +- MAJOR version when you make incompatible API changes +- MINOR version when you add functionality in a backward compatible manner +- PATCH version when you make backward compatible bug fixes + +Additional labels for pre-release and build metadata are available as extensions to the `MAJOR.MINOR.PATCH` format. + +moon implements the [minimal version selection](https://research.swtch.com/vgo-mvs), which automatically handles and installs dependencies based on the module's semantic versioning information. Minimal version selection assumes that each module declares its own dependency requirements and follows semantic versioning convention, aiming to make the user's dependency graph as close as possible to the author's development-time dependencies. + +### Readme & metadata + +Metadata in `moon.mod.json` and `README.md` will be shown in mooncakes.io. + +Metadata consist of the following sections: + +- `license`: license of this module, it following the [SPDX](https://spdx.dev/about/overview/) convention +- `keywords`: keywords of this module +- `repository`: URL of the package source repository +- `description`: short description to this module +- `homepage`: URL of the module homepage + +### Moondoc + +mooncakes.io will generate documentation for each modules automatically. + +The leading `///` comments of each toplevel will be recognized as documentation. +You can write markdown inside. + +```moonbit +/// Get the largest element of a non-empty `Array`. +/// +/// # Example +/// +/// ``` +/// maximum([1,2,3,4,5,6]) = 6 +/// ``` +/// +/// # Panics +/// +/// Panics if the `xs` is empty. +/// +pub fn maximum[T : Compare](xs : Array[T]) -> T { + // TODO ... +} +``` + +You can also use `moon doc --serve` to generate and view documentation in local. diff --git a/next/toolchain/moon/package.md b/next/toolchain/moon/package.md new file mode 100644 index 00000000..1e2d01b2 --- /dev/null +++ b/next/toolchain/moon/package.md @@ -0,0 +1,278 @@ +# Package Configuration + +moon uses the `moon.pkg.json` file to identify and describe a package. + +## Name + +The package name is not configurable; it is determined by the directory name of the package. + +## is-main + +The `is-main` field is used to specify whether a package needs to be linked into an executable file. + +The output of the linking process depends on the backend. When this field is set to `true`: + +- For the `wasm` and `wasm-gc` backends, a standalone WebAssembly module will be generated. +- For the `js` backend, a standalone JavaScript file will be generated. + +## import + +The `import` field is used to specify other packages that a package depends on. + +## test-import + +The `test-import` field is used to specify other packages that the black-box test package of this package depends on. + +## wbtest-import + +The `wbtest-import` field is used to specify other packages that the white-box test package of this package depends on. + +## Conditional Compilation + +The smallest unit of conditional compilation is a file. + +In a conditional compilation expression, three logical operators are supported: `and`, `or`, and `not`, where the `or` operator can be omitted. + +For example, `["or", "wasm", "wasm-gc"]` can be simplified to `["wasm", "wasm-gc"]`. + +Conditions in the expression can be categorized into backends and optimization levels: + +- **Backend conditions**: `"wasm"`, `"wasm-gc"`, and `"js"` +- **Optimization level conditions**: `"debug"` and `"release"` + +Conditional expressions support nesting. + +If a file is not listed in `"targets"`, it will be compiled under all conditions by default. + +Example: + +```json +{ + "targets": { + "only_js.mbt": ["js"], + "only_wasm.mbt": ["wasm"], + "only_wasm_gc.mbt": ["wasm-gc"], + "all_wasm.mbt": ["wasm", "wasm-gc"], + "not_js.mbt": ["not", "js"], + "only_debug.mbt": ["debug"], + "js_and_release.mbt": ["and", ["js"], ["release"]], + "js_only_test.mbt": ["js"], + "js_or_wasm.mbt": ["js", "wasm"], + "wasm_release_or_js_debug.mbt": ["or", ["and", "wasm", "release"], ["and", "js", "debug"]] + } +} +``` + +## Link Options + +By default, moon only links packages where `is-main` is set to `true`. If you need to link other packages, you can specify this with the `link` option. + +The `link` option is used to specify link options, and its value can be either a boolean or an object. + +- When the `link` value is `true`, it indicates that the package should be linked. The output will vary depending on the backend specified during the build. + + ```json + { + "link": true + } + ``` + +- When the `link` value is an object, it indicates that the package should be linked, and you can specify link options. For detailed configuration, please refer to the subpage for the corresponding backend. + +### Wasm Backend Link Options + +#### Configurable Options + +- The `exports` option is used to specify the function names exported by the `wasm` backend. + + For example, in the following configuration, the `hello` function from the current package is exported as the `hello` function in the `wasm` module, and the `foo` function is exported as the `bar` function in the `wasm` module. In the `wasm` host, the `hello` and `bar` functions can be called to invoke the `hello` and `foo` functions from the current package. + + ```json + { + "link": { + "wasm": { + "exports": [ + "hello", + "foo:bar" + ] + } + } + } + ``` + +- The `heap-start-address` option is used to specify the starting address of the linear memory that can be used when compiling to the `wasm` backend. + + For example, the following configuration sets the starting address of the linear memory to 1024. + + ```json + { + "link": { + "wasm": { + "heap-start-address": 1024 + } + } + } + ``` + +- The `import-memory` option is used to specify the linear memory imported by the `wasm` module. + + For example, the following configuration specifies that the linear memory imported by the `wasm` module is the `memory` variable from the `env` module. + + ```json + { + "link": { + "wasm": { + "import-memory": { + "module": "env", + "name": "memory" + } + } + } + } + ``` + +- The `export-memory-name` option is used to specify the name of the linear memory exported by the `wasm` module. + + ```json + { + "link": { + "wasm": { + "export-memory-name": "memory" + } + } + } + ``` + +### Wasm GC Backend Link Options + +The link options for the `wasm-gc` backend are similar to those for the `wasm` backend, except there is no `heap-start-address` option. + +### JS Backend Link Options + +#### Configurable Options + +- The `exports` option is used to specify the function names to export in the JavaScript module. + + For example, in the following configuration, the `hello` function from the current package is exported as the `hello` function in the JavaScript module. In the JavaScript host, the `hello` function can be called to invoke the `hello` function from the current package. + + ```json + { + "link": { + "js": { + "exports": [ + "hello" + ] + } + } + } + ``` + +- The `format` option is used to specify the output format of the JavaScript module. + + The currently supported formats are: + - `esm` + - `cjs` + - `iife` + + For example, the following configuration sets the output format of the current package to ES Module. + + ```json + { + "link": { + "js": { + "format": "esm" + } + } + } + ``` + +## Pre-build + +The `"pre-build"` field is used to specify pre-build commands, which will be executed before build commands such as `moon check|build|test`. + +`"pre-build"` is an array, where each element is an object containing `input`, `output`, and `command` fields. The `input` and `output` fields can be strings or arrays of strings, while the `command` field is a string. In the `command`, you can use any shell commands, as well as the `$input` and `$output` variables, which represent the input and output files, respectively. If these fields are arrays, they will be joined with spaces by default. + +Currently, there is a built-in special command `:embed`, which converts files into MoonBit source code. The `--text` parameter is used to embed text files, and `--binary` is used for binary files. `--text` is the default and can be omitted. The `--name` parameter is used to specify the generated variable name, with `resource` being the default. The command is executed in the directory where the `moon.pkg.json` file is located. + +```json +{ + "pre-build": [ + { + "input": "a.txt", + "output": "a.mbt", + "command": ":embed -i $input -o $output" + } + ] +} +``` + +If the content of `a.txt` in the current package directory is: +``` +hello, +world +``` + +After running `moon build`, the following `a.mbt` file will be generated in the directory where the `moon.pkg.json` is located: + +``` +let resource : String = + #|hello, + #|world + #| +``` + +## Warning List + +This is used to disable specific preset compiler warning numbers. + +For example, in the following configuration, `-2` disables the warning number 2 (Unused variable). + +```json +{ + "warn-list": "-2", +} +``` + +You can use `moonc build-package -warn-help` to see the list of preset compiler warning numbers. + +``` +$ moonc -v +v0.1.20240914+b541585d3 + +$ moonc build-package -warn-help +Available warnings: + 1 Unused function. + 2 Unused variable. + 3 Unused type declaration. + 4 Redundant case in a pattern matching (unused match case). + 5 Unused function argument. + 6 Unused constructor. + 7 Unused module declaration. + 8 Unused struct field. + 10 Unused generic type variable. + 11 Partial pattern matching. + 12 Unreachable code. + 13 Unresolved type variable. + 14 Lowercase type name. + 15 Unused mutability. + 16 Parser inconsistency. + 18 Useless loop expression. + 19 Top-level declaration is not left aligned. + 20 Invalid pragma + 21 Some arguments of constructor are omitted in pattern. + 22 Ambiguous block. + 23 Useless try expression. + 24 Useless error type. + 26 Useless catch all. + A all warnings +``` + +## Alert List + +Disable user preset alerts. + +```json +{ + "alert-list": "-alert_1-alert_2" +} +``` \ No newline at end of file diff --git a/next/toolchain/moon/tutorial.md b/next/toolchain/moon/tutorial.md new file mode 100644 index 00000000..6120d417 --- /dev/null +++ b/next/toolchain/moon/tutorial.md @@ -0,0 +1,318 @@ +# MoonBit's Build System Tutorial + +Moon is the build system for the MoonBit language, currently based on the [n2](https://github.com/evmar/n2) project. Moon supports parallel and incremental builds. Additionally, moon also supports managing and building third-party packages on [mooncakes.io](https://mooncakes.io/) + +## Prerequisites + +Before you begin with this tutorial, make sure you have installed the following: + +1. **MoonBit CLI Tools**: Download it from the . This command line tool is needed for creating and managing MoonBit projects. + + Use `moon help` to view the usage instructions. + + ```bash + $ moon help + ... + ``` + +2. **MoonBit Language** plugin in Visual Studio Code: You can install it from the VS Code marketplace. This plugin provides a rich development environment for MoonBit, including functionalities like syntax highlighting, code completion, and more. + +Once you have these prerequisites fulfilled, let's start by creating a new MoonBit module. + +## Creating a New Module + +To create a new module, enter the `moon new` command in the terminal, and you will see the module creation wizard. By using all the default values, you can create a new module named `username/hello` in the `my-project` directory. + +```bash +$ moon new +Enter the path to create the project (. for current directory): my-project +Select the create mode: exec +Enter your username: username +Enter your project name: hello +Enter your license: Apache-2.0 +Created my-project +``` + +> If you want use all default values, you can use `moon new my-project` to create a new module named `username/hello` in the `my-project` directory. + +## Understanding the Module Directory Structure + +After creating the new module, your directory structure should resemble the following: + +```bash +my-project +├── LICENSE +├── README.md +├── moon.mod.json +└── src + ├── lib + │   ├── hello.mbt + │   ├── hello_test.mbt + │   └── moon.pkg.json + └── main + ├── main.mbt + └── moon.pkg.json +``` + +Here's a brief explanation of the directory structure: + +- `moon.mod.json` is used to identify a directory as a MoonBit module. It contains the module's metadata, such as the module name, version, etc. `source` specifies the source directory of the module. The default value is `src`. + + ```json + { + "name": "username/hello", + "version": "0.1.0", + "readme": "README.md", + "repository": "", + "license": "Apache-2.0", + "keywords": [], + "description": "", + "source": "src" + } + ``` + +- `lib` and `main` directories: These are the packages within the module. Each package can contain multiple `.mbt` files, which are the source code files for the MoonBit language. However, regardless of how many `.mbt` files a package has, they all share a common `moon.pkg.json` file. `lib/*_test.mbt` are separate test files in the `lib` package, these files are for blackbox test, so private members of the `lib` package cannot be accessed directly. + +- `moon.pkg.json` is package descriptor. It defines the properties of the package, such as whether it is the main package and the packages it imports. + + - `main/moon.pkg.json`: + + ```json + { + "is_main": true, + "import": [ + "username/hello/lib" + ] + } + ``` + + Here, `"is_main: true"` declares that the package needs to be linked by the build system into a wasm file. + + - `lib/moon.pkg.json`: + + ```json + {} + ``` + + This file is empty. Its purpose is simply to inform the build system that this folder is a package. + +## Working with Packages + +Our `username/hello` module contains two packages: `username/hello/lib` and `username/hello/main`. + +The `username/hello/lib` package contains `hello.mbt` and `hello_test.mbt` files: + + `hello.mbt` + + ```moonbit + pub fn hello() -> String { + "Hello, world!" + } + ``` + + `hello_test.mbt` + + ```moonbit + test "hello" { + if @lib.hello() != "Hello, world!" { + fail!("@lib.hello() != \"Hello, world!\"") + } + } + ``` + +The `username/hello/main` package contains a `main.mbt` file: + + ```moonbit + fn main { + println(@lib.hello()) + } + ``` + +To execute the program, specify the file system's path to the `username/hello/main` package in the `moon run` command: + +```bash +$ moon run ./src/main +Hello, world! +``` + +You can also omit `./` + +```bash +$ moon run src/main +Hello, world! +``` + +You can test using the `moon test` command: + +```bash +$ moon test +Total tests: 1, passed: 1, failed: 0. +``` + +## Package Importing + +In the MoonBit's build system, a module's name is used to reference its internal packages. +To import the `username/hello/lib` package in `src/main/main.mbt`, you need to specify it in `src/main/moon.pkg.json`: + +```json +{ + "is_main": true, + "import": [ + "username/hello/lib" + ] +} +``` + +Here, `username/hello/lib` specifies importing the `username/hello/lib` package from the `username/hello` module, so you can use `@lib.hello()` in `main/main.mbt`. + +Note that the package name imported in `src/main/moon.pkg.json` is `username/hello/lib`, and `@lib` is used to refer to this package in `src/main/main.mbt`. The import here actually generates a default alias for the package name `username/hello/lib`. In the following sections, you will learn how to customize the alias for a package. + +## Creating and Using a New Package + +First, create a new directory named `fib` under `lib`: + +```bash +mkdir src/lib/fib +``` + +Now, you can create new files under `src/lib/fib`: + +`a.mbt`: + +```moonbit +pub fn fib(n : Int) -> Int { + match n { + 0 => 0 + 1 => 1 + _ => fib(n - 1) + fib(n - 2) + } +} +``` + +`b.mbt`: + +```moonbit +pub fn fib2(num : Int) -> Int { + fn aux(n, acc1, acc2) { + match n { + 0 => acc1 + 1 => acc2 + _ => aux(n - 1, acc2, acc1 + acc2) + } + } + + aux(num, 0, 1) +} +``` + +`moon.pkg.json`: + +```json +{} +``` + +After creating these files, your directory structure should look like this: + +```bash +my-project +├── LICENSE +├── README.md +├── moon.mod.json +└── src + ├── lib + │ ├── fib + │ │ ├── a.mbt + │ │ ├── b.mbt + │ │ └── moon.pkg.json + │ ├── hello.mbt + │ ├── hello_test.mbt + │ └── moon.pkg.json + └── main + ├── main.mbt + └── moon.pkg.json +``` + +In the `src/main/moon.pkg.json` file, import the `username/hello/lib/fib` package and customize its alias to `my_awesome_fibonacci`: + +```json +{ + "is_main": true, + "import": [ + "username/hello/lib", + { + "path": "username/hello/lib/fib", + "alias": "my_awesome_fibonacci" + } + ] +} +``` + +This line imports the `fib` package, which is part of the `lib` package in the `hello` module. After doing this, you can use the `fib` package in `main/main.mbt`. Replace the file content of `main/main.mbt` to: + +```moonbit +fn main { + let a = @my_awesome_fibonacci.fib(10) + let b = @my_awesome_fibonacci.fib2(11) + println("fib(10) = \{a}, fib(11) = \{b}") + + println(@lib.hello()) +} +``` + +To execute your program, specify the path to the `main` package: + +```bash +$ moon run ./src/main +fib(10) = 55, fib(11) = 89 +Hello, world! +``` + +## Adding Tests + +Let's add some tests to verify our fib implementation. Add the following content in `src/lib/fib/a.mbt`: + +`src/lib/fib/a.mbt` + +```moonbit +test { + assert_eq!(fib(1), 1) + assert_eq!(fib(2), 1) + assert_eq!(fib(3), 2) + assert_eq!(fib(4), 3) + assert_eq!(fib(5), 5) +} +``` + +This code tests the first five terms of the Fibonacci sequence. `test { ... }` defines an inline test block. The code inside an inline test block is executed in test mode. + +Inline test blocks are discarded in non-test compilation modes (`moon build` and `moon run`), so they won't cause the generated code size to bloat. + +## Stand-alone test files for blackbox tests + +Besides inline tests, MoonBit also supports stand-alone test files. Source files ending in `_test.mbt` are considered test files for blackbox tests. For example, inside the `src/lib/fib` directory, create a file named `fib_test.mbt` and paste the following code: + +`src/lib/fib/fib_test.mbt` + +```moonbit +test { + assert_eq!(@fib.fib(1), 1) + assert_eq!(@fib.fib2(2), 1) + assert_eq!(@fib.fib(3), 2) + assert_eq!(@fib.fib2(4), 3) + assert_eq!(@fib.fib(5), 5) +} +``` + +Notice that the test code uses `@fib` to refer to the `username/hello/lib/fib` package. The build system automatically creates a new package for blackbox tests by using the files that end with `_test.mbt`. This new package will import the current package automatically, allowing you to use `@lib` in the test code. + +Finally, use the `moon test` command, which scans the entire project, identifies, and runs all inline tests as well as files ending with `_test.mbt`. If everything is normal, you will see: + +```bash +$ moon test +Total tests: 3, passed: 3, failed: 0. +$ moon test -v +test username/hello/lib/hello_test.mbt::hello ok +test username/hello/lib/fib/a.mbt::0 ok +test username/hello/lib/fib/fib_test.mbt::0 ok +Total tests: 3, passed: 3, failed: 0. +``` \ No newline at end of file diff --git a/next/tutorial/index.md b/next/tutorial/index.md new file mode 100644 index 00000000..26940c7a --- /dev/null +++ b/next/tutorial/index.md @@ -0,0 +1,10 @@ +# Tutorial + +Here are some tutorials that may help you learn the programming language: + +- [Tour for Beginners](./tour.md) + +```{toctree} +:maxdepth: 2 +:caption: Contents: +tour \ No newline at end of file diff --git a/next/tutorial/tour.md b/next/tutorial/tour.md new file mode 100644 index 00000000..79fbff97 --- /dev/null +++ b/next/tutorial/tour.md @@ -0,0 +1,350 @@ +# A Tour of MoonBit for Beginners + +This guide is intended for newcomers, and it's not meant to be a 5-minute quick tour. This article tries to be a succinct yet easy to understand guide +for those who haven't programmed in a way that MoonBit enables them to, that is, in a more modern, functional way. + +See [the General Introduction](../language/index.md) if you want to straight delve into the language. + +## Installation + +### the Extension + +Currently, MoonBit development support are through VS Code extension. Navigate to +[VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=moonbit.moonbit-lang) to download MoonBit language support. + +### the toolchain + +> (Recommended) If you've installed the extension above, the runtime can be directly installed by running 'Install moonbit toolchain' in the action menu and you may skip this part: +> ![runtime-installation](/imgs/runtime-installation.png) + +We also provide an installation script: Linux & macOS users can install via + +```bash +curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash +``` + +For Windows users, powershell is used: + +```powershell +Set-ExecutionPolicy RemoteSigned -Scope CurrentUser; irm https://cli.moonbitlang.com/install/powershell.ps1 | iex +``` + +This automatically installs MoonBit in `$HOME/.moon` and adds it to your `PATH`. + +If you encounter `moon` not found after installation, try restarting your terminal or vscode to let the environment variable take effect. + +Do notice that MoonBit is not production-ready at the moment, it's under active development. To update MoonBit, just run the commands above again. + +Running `moon help` gives us a bunch of subcommands. But right now the only commands we need are `build` `run` and `new`. + +To create a project (or module, more formally), run `moon new`. You will be greeted with a creation wizard, filling up all the info and we get + +``` +my-project +├── LICENSE +├── moon.mod.json +├── README.md +└── src + ├── lib + │ ├── hello.mbt + │ ├── hello_test.mbt + │ └── moon.pkg.json + └── main + ├── main.mbt + └── moon.pkg.json +``` + +This resembles a typical MoonBit module structure. Try running `moon run src/main`. + +Now, we can get started. + +## Start Writing + +In our tour, we will write all of the codes below in `main.mbt`. As you may have guessed, the `main` function within the `main` package is the main entrance of a program. +For a thorough introduction, please take a look at our [build system tutorial](../toolchain/moon/tutorial.md). + +### Variables + +Variables are defined with `let`: + +```moonbit +let e = 2.718281828459045 // double +let int_min = -2147483648 // int +let int_max : Int = 2147483647 // explicit type annotation +let tuple = (1, 2) // 2-tuple +``` + +```moonbit +fn init { + let array = [1, 2, 3, 4, 5] + // array = [4, 5, 6, 7, 8] // WRONG: let creates immutable bindings + let mut mut_array = [1, 2, 3, 4, 5] + mut_array = [4, 5, 6, 7, 8] + println(mut_array) +} +``` + +MoonBit is a strictly typed language with type inference. In the example above, `let` +binds (we prefer the word _bind_ to assign) a symbol to a value. The symbol is inferred +to have the same type as the value. Hover over any of the symbols to check its type. + +By default, the `let` - binding creates an immutable reference to a value. That is, you cannot change the symbol to reference something else without rebinding it (using `let`). Otherwise one should use `let mut`. + +### Function + +Function is just a piece of code that takes some inputs and produce a result. We may define a function using the keyword `fn` (function name in MoonBit should not begin with uppercase letters A-Z): + +```moonbit +fn identity[T](x : T) -> T { + // `Identity` won't work as it violates naming convention + x +} +``` + +In this example, we provide types explicitly. Notice how it differs from traditional C-like languages +which uses prefix type notation `T x`, here we use postfix type notation `x: T` (Formally, we call it _type annotation_). + +We write a arrow `->` before the return type to show the nature of a function: a map from some types to some other types. Formally, we call this syntax _trailing return type_ (languages such as C++, Rust, Swift, etc have this syntax as well). + +> The word _expression_ is loosely used. Intuitively, An expression is something with a value we care about. + +Consequently, a function type is denoted `(S) -> T` where `S` (within parenthesis) is the parameter type and `T` is the return type. +Functions in MoonBit are first-class, meaning it's always possible to pass functions around if you +get the type right: + +```moonbit +fn compose[S, T, U](f : (T) -> U, g : (S) -> T) -> (S) -> U { + let composition = fn(x : S) { f(g(x)) } // returns a composition of `f` and `g` + + // moonbit also provides the pipe `|>` operator, + // similar to a lot of functional languages. + fn(x : S) { g(x) |> f } // equivalent +} +``` + +Languages nowadays have something called _lambda expression_. Most languages implement it as a mere syntactic sugar. A lambda expression is really just a anonymous closure, this, is resembled in our MoonBit's syntax: + +> a closure only captures variables in its surroundings, together with its bound variable, that is, having the same indentation level (suppose we've formatted the code already). + +```moonbit +fn foo() -> Int { + fn inc(x) { x + 1 } // named as `inc` + (fn (x) { x + inc(2) })(6) // anonymous, a so-called 'lambda expression' + // function automatically captures the result of the last expression +} +``` + +```moonbit expr +foo() // => 9 +``` + +Now we've learned the very basic, let's learn the rest by coding. + +## Implementing List + +### enum type + +A linked list is a series of node whose right cell is a reference to its successor node. Sounds recursive? Because it is. Let's define it that way using MoonBit: + +```moonbit +enum List[T] { + Nil // base case: empty list + Cons(T, List[T]) // an recursive definition +} +``` + +The `enum` type works like any `enum` from traditional OO languages. However, let's refrain from using the OO-term `case`, we'll use _constructor_ from now on. We may read the above code as + +> the type `List[T]` can be constructed from the constructor `Nil` or `Cons`, the former represents an empty list; the latter carries some data of type `T` and the rest of the list. + +The square bracket used here denotes a _polymorphic_ (generic) definition, meaning a list of something of type `T`. Should we _instantiate_ `T` with a concrete type like `Int`, we define a list containing integers. + +Another datatype frequently used in MoonBit is our good old `Struct`, which works like you would expect. Let's create a list of `User` using the definition above and `Struct`: + +```moonbit +struct User { + id : Int + name : String + // by default the properties/fields of a struct is immutable. + // the `mut` keyword works exactly the way we've mentioned before. + mut email : String +} derive(Show) + +// a method of User is defined by passing a object of type User as self first. +// just like what you would do in Python. +// Note that methods may only be defined within the same package the type is in. +// We may not define methods for foreign types directly +fn greetUser(self : User) -> String { // a method of struct/type/class `User` + let id = self.id + let name = self.name + "Greetings, \{name} of id \{id}" // string interpolation +} +// construct a User object. +let evan : User = { id: 0, name: "Evan", email: "someone@example.com" } +// we use a shorthand by duplicating evan's information +// and replacing w/ someone elses' email. +let listOfUser : List[User] = Cons(evan, Cons({ ..evan, email: "someoneelse@example.com" }, Nil)) +``` + +Another datatype is `type`, a specific case of `enum` type. `type` can be thought as a wrapper +around an existing type, allowing additional methods to be defined. +Through this we extends the method definition of a foreign type without actually +modifying it. Consider the type of `name` in `User`, +we may define it as + +```moonbit no-check +type UserName String // a newtype `UserName` based on `String` + +// defining a method for UserName is allowed but not String. +fn is_blank(self : UserName) -> Bool { + // use `._` to access its basetype String + // iter() creates a *internal iterator* + // which provides a functional way to iterate on sequences. + // find_first short circuits on the first `true` i.e. non-blank character + let res = self._.iter().find_first( + fn(c) { if c == ' ' { false } else { true } }, + ) + match res { + Some(_) => false + // found NO non-blank character, thus it's a blank string. + None => true + } +} +``` + +`enum`, `struct` and `newtype` are the 3 ways to define a datatype. +There isn't `class` in MoonBit, nor does it need that. + +the `derive` keyword is like Java's `implements`. Here `Show` is a _trait_ which +indicates a type is printable. So what is a trait? + +### Trait + +A trait (or type trait) is what we would call an `interface` in traditional OO-languages. +`println(evan)` would print `{id: 0, name: "Evan", email: "someone@example.com"}`. As `User` consists +of builtin types `Int` `String`, which already implements `Show`. +Therefore we do not need to implement it explicitly. Let's implement our own +trait `Printable` by implementing `to_string()`: + +```moonbit +trait Printable { + to_string(Self) -> String +} + +fn to_string(self : User) -> String { + (self.id, self.name, self.email).to_string() +} // now `Printable` is implemented + +fn to_string[T : Printable](self : List[T]) -> String { + let string_aux = to_string_aux(self) + // function arguments can have label + "[" + string_aux.substring(end=string_aux.length() - 1) + "]" +} + +// polymorphic functions have to be toplevel. +fn to_string_aux[T : Printable](self : List[T]) -> String { + match self { + Nil => "" + Cons(x, xs) => "\{x} " + to_string_aux(xs) + } +} +``` + +```moonbit expr +listOfUser.to_string() +// => [(0, Evan, someone@example.com) (0, Evan, someoneelse@example.com)] +``` + +We use `` in Java to constrain the type of list element to make sure objects of type +`T` can be printed, similarly, in MoonBit we would write `[T: Printable]`. + +### Pattern Matching + +In the example above we use the `match` expression, a core feature of MoonBit +(and many other functional programming languages.) In short, we use pattern matching +to _destructure_ (to strip the encapsulation of) a structure. + +We may express the above `match` code as + +> if `self` is constructed with `Nil` (an empty list), we return `""`; +> otherwise if `self` is constructed with `Cons(x,xs)` (a non-empty list) +> we print `x` and rest of the list. +> Where `x` is the head of the `self` and `xs` being the rest. + +Intuitively, we extract `x` and `xs` (they are bound in situ) from `self` using pattern matching. +Let's implement typical list operations such as `map` `reduce` `zip`: + +```moonbit +fn map[S, T](self : List[S], f : (S) -> T) -> List[T] { + match self { + Nil => Nil + Cons(x, xs) => Cons(f(x), map(xs, f)) + } +} + +fn reduce[S, T](self : List[S], op : (T, S) -> T, init : T) -> T { + match self { + Nil => init + Cons(x, xs) => reduce(xs, op, op(init, x)) + } +} + +fn zip[T](self : List[T], other : List[T]) -> List[T] { + match (self, other) { + (Nil, _) => Nil // we use underscore to ignore the value we don't care + (_, Nil) => Nil + (Cons(x, xs), Cons(y, ys)) => Cons(x, Cons(y, zip(xs, ys))) + } +} +``` + +Now we have a somewhat usable `List` type. Realistically, we always prefer the builtin `Array` +which is much more efficient. + +Pattern matching can be used in `let` as well. In `greetUser()`, instead of writing +2 `let`'s, we may write + +```moonbit +fn greetUserAlt(self : User) -> String { + // extract `id` `name` from `self` of type User. ignores email. + let { id: id, name: name, email: _ } = self + // equivalent, but ignores the rest. + let { id, name, .. } = self + "Greetings, \{name} of id \{id}" +} +``` + +## Iteration + +Finally, let's talk about the major point of every OO-language: looping. +Although we've been using recursion most of the times, +MoonBit is designed to be multi-paradigm, +thus it retains C-style imperative `for` `while` loop. + +Additionally, MoonBit provides a more interesting loop construct, the functional loop. +For example the Fibonacci number can be calculated by + +```moonbit +fn fib(n : Int) -> Int { + loop n, 0, 1 { // introduces 3 loop variables: `n` `a = 0` `b = 1` + // pattern matching is available in `loop` + 0, a, b => a // what can be constructed from 0 -- Only 0 it self! + // assign `b` to `a`, `(a + b)` to `b`, decrease counter `n` + n, a, b => continue n - 1, b, a + b + } +} +``` + +```moonbit expr +[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(fib) // => [1,1,2,3,5,8,13,21,34,55] +``` + +Semantic-wise, the `loop` construct focuses more on the transition of each state, providing +better readability, preserving recursive flavor and same performance without writing [tail-recursion](https://en.wikipedia.org/wiki/Tail_call) explicitly. + +## Closing + +At this point, we've learned about the very basic and most not-so-trivial features of MoonBit, +yet MoonBit is a feature-rich, multi-paradigm programming language. +After making sure that you are comfortable with the basics of MoonBit, +we suggest that you look into some [interesting examples](https://github.com/moonbitlang/moonbit-docs/tree/main/legacy/examples) to get a better hold of MoonBit.