跳到主要内容

weekly-05-13

· 阅读需 4 分钟

MoonBit更新

  • 支持了构造器的 payload 中出现 mutable field,使用方式如下:
enum E {
C(mut ~x : Int, mut ~y : Int)
} derive(Debug)


fn swap_xy(x : E) -> Unit {
match x {
// `~y` 会绑定模式匹配前 `C` 中的 `y` 字段的值
// 当看到 `C(..) as c` 这种模式时,编译器知道 `c` 一定是构造器 `C`,
// 所以可以在分支内部用 `c.x`、`c.y` 直接访问 `C` 的字段
C(~y, ..) as c => {
// `c.x` 和 `c.y` 可以用于修改/读取 `C` 中最新的值
c.y = c.x
c.x = y
}
}
}

fn init {
let e : E = C(x=1, y=2)
debug(e) // C(x=1, y=2)
swap_xy(e)
debug(e) // C(x=2, y=1)
}

这个例子中的 swap_xy 函数对构造器 Cxy 两个 field 的值进行了交换,并且这个交换是 in-place 的,没有引入额外的内存分配

  • **数组字面量默认构建 vector。**对 Array literal 语法进行了重载,现在 Array literal 可以用来构造 Vector 或者 Array,具体的类型通过上下文决定,当上下文中类型信息不明确时,默认使用 Vector,比如
fn init {
let v = [1, 2, 3] // v has type @vec.Vec[Int]
let a : Array[_] = [1, 2, 3] // a has type Array[Int]
}
  • 报错信息中添加了错误代码,例如
./vec/sort.mbt:68:16-68:23 [E4021] The value identifier minimum is unbound.
./vec/sort_by.mbt:90:16-90:23 [E4021] The value identifier minimum is unbound.
./vec/vec.mbt:962:37-962:50 [E4020] Package "iter" not found in the loaded packages.
./vec/vec.mbt:963:3-963:13 [E4024] The type/trait @iter.Iter is not found.

IDE更新

  • 对构造器中的 labeled field 的 label 支持了 gotodef/gotoref/rename 等功能,例如 label.PNG

构建系统更新

  • 支持在 package 级别配置 warn list 与alert list
    • moon.pkg.json 中如下配置,可在编译时关闭对应的 warn 与 alter【其中 2alter_1alert_2 分别为编译器预设的 warn id (对于 Unused variable) 与用户自定义的 alert id】
{
"warn_list": "-2",
"alert_list": "-alert_1-alert_2"
}
  • -代表关闭对应 id 的 warn 与 alter,可用 moonc build-package -warn-help 查看预设的 warn

  • moon check|build|run|test 的默认后端由wasm切换为wasm-gc

  • moon test 默认执行模式由 release 修改为 debug

  • moon check|build|run|test支持自动安装依赖,而无需手动执行 moon install

  • moon doc --serve 支持指定地址与端口

-b, --bind <BIND> [default: 127.0.0.1]
-p, --port <PORT> [default: 3000]
  • 优化 moon 体积
平台优化前优化后
macOS arm647.3 MiB3.6 MiB
macOS x86_648.2 MiB4.1 MiB
Ubuntu x86_6414.0 MiB9.6 MiB
Windows x86_649.4 MiB4.9 MiB

工具链更新

  • moonrun 支持打印 backtrace, 使用样例: 使用 moon new hello 创建一个新项目,将 main/main.mbt 的内容替换为:
  fn bar() -> Unit {
abort("")
}

fn foo() -> Unit {
bar()
}

fn main {
foo()
}

执行 moon run main --debug,可观察到输出类似:

error: RuntimeError: unreachable
at $username/hello/main.bar.fn/1 (wasm://wasm/6fe99e5e:wasm-function[3]:0xe6)
at $username/hello/main.foo.fn/2 (wasm://wasm/6fe99e5e:wasm-function[4]:0xea)
at *init*/3 (wasm://wasm/6fe99e5e:wasm-function[5]:0xef)
at <anonymous>:9:22

weekly-04-30

· 阅读需 6 分钟

MoonBit 更新

  • 新增JavaScript后端

目前MoonBit已新增对JavaScript的支持并带来前所未有的性能提升,在JS后端实现了超出Json5近8倍性能的优势。更详细的介绍可以看一下这篇文章:IDEA研究院编程语言MoonBit发布JavaScript后端,速度提升25倍

如果你想自己体验一下,可以点击:https://github.com/moonbit-community/benchmark-202404/tree/master/bench_json5

  • 现在MoonBit允许传递回调函数至FFI。但回调函数的参数和返回值类型目前只能是简单类型,如Int等。例子:

    // 使用示例:传递回调函数至外部
    fn set_callback(f : () -> Int) = "ffi" "set_callback"

    // 使用示例
    fn use_callback() -> Int = "ffi" "use_callback"

    test {
    let i = { val : 0 }
    set_callback(fn () {
    i.val += 1
    i.val
    })
    inspect(use_callback(), content="1")?
    inspect(use_callback(), content="2")?
    inspect(use_callback(), content="3")?
    inspect(use_callback(), content="4")?
    }

    let f

    export default {
    // 必要外部接口:将闭包转换为JS函数。其他运行时根据语言不同实现方式不同
    'moonbit:ffi': {
    make_closure: (funcref, context) => funcref.bind(null, context)
    },
    // 使用示例
    ffi: {
    set_callback: (func) => {
    f = func
    }, // 设置回调函数
    use_callback: () => f() // 使用回调函数
    }
    }
  • 修改显式实现 trait(extension method)的语法,允许显式写出要给哪个类型实现 trait

    // 为 `Trait` 的方法 `method` 提供默认实现
    impl Trait with method(...) { ... }

    // 给类型 `Type` 实现 `Trait` 的方法 `method`
    impl Trait for Type with method(...) { ... }

    // 带类型参数的情况
    impl[X] Trait for Array[X] with method(...) { ... }

    和之前的 fn Trait::method(...) 语法相比,新的语法允许显式写出实现 trait 的类型,签名信息更丰富、更清晰。由于写出了类型,编译器可以自动推断出方法的参数和返回值类型,不需要手动标注:

    trait MyTrait {
    f(Self) -> Option[Int]
    }

    // 无需标注 `self` 和返回值的类型
    impl MyTrait for Int with f(self) {
    // 编译器能自动推断出返回值的类型是 `Option[Int]`
    Some(self)
    }

  • 支持Bytes字面量

    Bytes字面量b"..." 会将双引号内的ASCII字符串转换为Bytes类型,字符串内支持十六进制和八进制转义。

     let b1 : Bytes = b"ASCII"
    let b2 : Bytes = b"\xFF\o000"

  • { x } 的二义性问题修复

现在{ x }会解析成只有一个x字段的struct,相当于{ x: x }。对于这种容易造成混淆的写法,编译器会发出警告。

IDE更新

  • 插件新增moonbit.autoUpdate的选项控制是否开启自动更新的提示
  • 插件支持多后端开发
    • 用户可以在vscode里选择不同的后端
    • 非当前后端的代码对比度会变低

plugins.gif

构建系统更新

  • 支持后端特定文件,这些文件的拓展名以 .wasm|wasm-gc|js.mbt结尾,例如:foo.wasm.mbtfoo.wasm-gc.mbtfoo.js.mbt。例如在 moon build --target js 中,只有普通的 .mbt 文件与 .js.mbt 才会参与构建。相应地,moon check|build|test、以及moonbitlang/core的链接修改为与后端相关。

  • moon.pkg.json 中的 ["link"]["js"]中新增 format 字段,用于指定输出的JavaScript模块格式,可能的值为 esm|cjs|iife,默认为 esm

    • esm模式下,使用export { x as y }语句导出
    • cjs模式下,使用exports.y = x导出
    • iife模式下,使用globalThis.y = x导出

    moon.pkg.json样例:

    {
"link": {
"js": {
"exports": [
"hello"
],
"format": "cjs"
}
}
}

  • moon test -u支持自动更新测试块中的多个inspect函数,以及添加 -limit 选项用于限制自动更新的最大迭代次数。

工具链更新

  • moonrun由wasmtime切换到v8,现在支持wasm-gc后端
    moon new hello
cd hello
moon run main --target wasm-gc
  • moon info 的更新
    • 支持对方法进行分组,方便对比不同数据结构的实现
    • 支持带标签的参数、默认参数和自动填充参数
type Map
impl Map {
debug_write[K : Debug, V : Debug](Self[K, V], Buffer) -> Unit
elems[K, V](Self[K, V]) -> List[V]
fold[K, V, T](Self[K, V], (T, V) -> T, ~init : T) -> T
from_array[K : Compare + Eq, V](Array[Tuple[K, V]]) -> Self[K, V]
// ...
}

weekly-04-22

· 阅读需 5 分钟

MoonBit更新

  • 标准库里添加了 Iter 类型,该类型可以高效地对容器中的元素的进行访问,并且将访问过程优化成循环,使用方式比如:
test "iter" {
let sum = Iter::[1, 2, 3, 4, 5, 6]
.filter(fn { x => x % 2 == 1 })
.take(2)
.map(fn { x => x * x})
.reduce(fn (x, y) { x + y }, 0)
inspect(sum, content="10")?
}
  • 标准库里添加了VecView类型,可以使用如下方式对 Vec[T] 类型的值取它的 VecView[T]
test "view" {
let v = Vec::[1, 2, 3, 4, 5]
let vv1 = v[..]
let vv2 = v[1..]
let vv3 = v[..4]
let vv4 = v[1..4]
inspect(vv1, content="VecView::[1, 2, 3, 4, 5]")?
inspect(vv2, content="VecView::[2, 3, 4, 5]")?
inspect(vv3, content="VecView::[1, 2, 3, 4]")?
inspect(vv4, content="VecView::[2, 3, 4]")?
}
  • array pattern支持 [a, .. as rest, b]形式,其中 rest 会绑定到一个VecView,例如:
test "view_pattern" {
fn is_palindrome(s: VecView[Int]) -> Bool {
match s {
[] => true
[_] => true
[x, .. as rest, y] => x == y && is_palindrome(rest)
}
}
let v1 = Vec::[1, 2, 3, 4, 5]
@assertion.assert_false(is_palindrome(v1[..]))?
let v2 = Vec::[1, 2, 3, 2, 1]
@assertion.assert_true(is_palindrome(v2[..]))?
}
  • 标签参数调用时允许省略标签里的波浪线 ~,例如:
inspect(1, content="1")
  • 构造器支持带标签的参数:
pub enum Tree[X] {
Nil
Branch(X, ~left : Tree[X], ~right : Tree[X])
}

pub fn leftmost[X](self : Tree[X]) -> Option[X] {
loop self {
Nil => None
// 使用 `label=pattern` 来匹配构造器的带标签参数
Branch(top, left=Nil, right=Nil) => Some(top)
// `label=label` 可以简写成 `~label`
Branch(_, left=Nil, ~right) => continue right
// 可以用 `..` 来忽略所有剩余的带标签参数
Branch(_, ~left, ..) => continue left
}
}

fn init {
// 创建带标签的构造器的语法和调用带标签的函数一样
let t: Tree[Int] = Branch(0, right=Nil, left=Branch(1, left=Nil, right=Nil))
println(t.leftmost()) // `Some(1)`
}
  • 可选参数的默认值可以依赖前面的参数,例如:
fn f(~x: Int = 1, ~y: Int = x) -> Int {
x + y
}
  • Byte字面量支持八进制转义。

Byte.PNG

IDE更新

  • IDE 支持本地环境的 test codelens;支持expect test的自动更新。

test-codelens.GIF

  • 修复在线 IDE 在 Windows 上找不到 core 的问题。

  • 支持识别 test_import*_test.mbt 文件。

工具链更新

  • moonfmt

    • 修复了StringChar字面量中的转义序列没有被正确格式化的问题;
    • 调整针对{ ..record }的格式化。
  • moon infomoon coverage 现已支持 Windows。

  • moon info 支持在不引起歧义时缩短类型名称,使得生成结果更加干净:

    • 在没有同名类型定义的时候隐藏 builtin 的包名前缀;
    • 在没有歧义时使用包名的最后一部分代替完整的包名。 更新前:
package moonbitlang/core/map

// -- snip --

type Map
fn Map::debug_write[K : @moonbitlang/core/builtin.Debug, V : @moonbitlang/core/builtin.Debug](Map[K, V], @moonbitlang/core/builtin.Buffer) -> Unit
fn Map::keys_set[K : @moonbitlang/core/builtin.Compare + @moonbitlang/core/builtin.Eq, V](Map[K, V]) -> @moonbitlang/core/immutable_set.ImmutableSet[K]
fn Map::lookup[K : @moonbitlang/core/builtin.Compare + @moonbitlang/core/builtin.Eq, V](Map[K, V], K) -> Option[V]
fn Map::to_vec[K, V](Map[K, V]) -> @moonbitlang/core/vec.Vec[Tuple[K, V]]

更新后:

package moonbitlang/core/map

alias @moonbitlang/core/immutable_set as @immutable_set
alias @moonbitlang/core/vec as @vec

// -- snip --

type Map
fn Map::debug_write[K : Debug, V : Debug](Map[K, V], Buffer) -> Unit
fn Map::keys_set[K : Compare + Eq, V](Map[K, V]) -> @immutable_set.ImmutableSet[K]
fn Map::lookup[K : Compare + Eq, V](Map[K, V], K) -> Option[V]
fn Map::to_vec[K, V](Map[K, V]) -> @vec.Vec[Tuple[K, V]]

构建系统更新

  • moon test 添加测试过滤相关选项:
-p, --package <PACKAGE_NAME>  Run test in the specified package
-f, --file <FILE> Run test in the specified file, only valid when --package is specified
-i, --index <INDEX> Run the index-nth test in the specified file, only valid when --file is specified

命令示例:moon test -p username/hello/A -f hello.mbt -i 0 (运行 username/hello/A 包中 hello.mbt 文件中的第 0 个 test block);-f-i 分别在指定 -p-f 时才有效;如果不指定 -f 则运行 -p 指定包中所有测试,不指定 -i 则运行 -f 指定文件中所有测试。

  • moon check|build|test 添加 --sort-input 选项,用于生成稳定的构建顺序。

  • expect test 生成的 ~content= 省略 ~,变更为 content=

weekly-04-15

· 阅读需 2 分钟

MoonBit is a Rust-like language (with GC support) and toolchain optimized for WebAssembly experience. This is our recent update:

Core Update

We have received 221 Repositories to MoonBit core since its open source in March, with 26 excellent contributors contributing about 10,000 lines of code of high quality. Thanks a lot for your passion and support for MoonBit!

0.PNG

Language Update

  • Expanded array patterns in pattern matching.

    • Support the vec type in the standard library.
    • Support for generic types [a, .., b].
    fn main {
    let xs = @vec.from_array([1, 2, 3])
    match xs {
    [1, .., 3] => { println("ok")}
    _ => println("not ok")
    }
    // Output: ok
    }

IDE Update

  • Changed the printing output of the online IDE from the Output channel to the terminal. Fixed the issue where the printing output was occasionally truncated in Firefox browsers. ANSI escape sequences can be used in browser code, for example:

1.PNG

  • Support autocompletion in the form of x |> @pkg.

1.5.PNG

  • Disabled inlay hint for matrix functions.

Before

2.PNG

After

3.PNG

Toolchain Update

  • Added (experimental) test coverage tools. (*Windows is not supported at the moment)

    • Added -enable-coverage option to moon test for enabling coverage during runtime.
    • Added moon coverage command for reading and processing coverage data.
      • After testing, moon coverage report -f <format> can be used to output coverage data. Supported output formats include:
        • bisect (default output format of OCaml Bisect tool)
        • html (output result webpage)
        • coveralls (JSON format suitable for CodeCov and Coveralls tool upload)
        • summary (output summary in the terminal) More functionalities can be viewed through moon coverage report -h.
      • moon coverage clean command can be used to clean up previous coverage data output.
  • The build system has added the moon info command for generating public interface files of software packages. (*Windows is not supported at the moment) Example:

    $ moon new hello
    $ cd hello
    $ moon info
    $ cat lib/lib.mbti
    package username/hello/lib

    // Values
    fn hello() -> String

    // Types and methods

    // Traits

    // Extension Methods
    ```

  • Fixed the issue where the annotation was misaligned caused by trailing commas in moonfmt.

  • Fixed the issue where file paths cannot contain spaces in moon.

weekly-04-08

· 阅读需 2 分钟

MoonBit更新

  • 支持 array.iter intrinsic 并且已经对标准库中的函数进行标注,从而可以在特定情况下将循环进行内联,以提升运行效率

    /// @intrinsic %array.iter
    pub fn iter[T](self : Array[T], f : (T) -> Unit) -> Unit {
    for i = 0; i < self.length(); i = i + 1 {
    f(self[i])
    }
    }

工具链更新

  • 支持实验性的测试覆盖率统计工具
    • 工具已经实验性支持 MoonBit Core CI
    • 我们正在优化面向用户的接口

image

image

  • 默认关闭Alerts pragmas 中 unsafe/throw/raise 类别的警告,启用了 deprecated alert。
  • moonfmt
    • 修复带负号的字面量打印后注释错位的问题
    • 修复带负号字面量打印后括号消失的问题
  • 修复变量高亮
  • moonrun 支持 UTF-16 字符串的打印

构建系统更新

  • expect test 支持处理 Unicode 字符

image

weekly-04-01

· 阅读需 5 分钟

MoonBit 更新

1. expect 测试添加 inspect 函数

expect 测试添加针对 Show 接口的 inspect 函数,签名如下:

pub fn inspect(
obj: Show,
~content: String = "",
~loc: SourceLoc = _,
~args_loc: ArgsLoc = _
) -> Result[Unit, String]

⚠️ 此API暂不稳定,在未来可能会更改为 expect 函数

使用 inspect 可以更方便编写测试,例如对于如下代码:

fn add(x: Int, y: Int) -> Int {
x + y
}

test {
inspect(add(1, 2))?
}

test {
(add(3, 4) |> inspect)?
}

执行 moon test -u 之后,文件被自动更新为:

fn add(x: Int, y: Int) -> Int {
x + y
}

test {
inspect(add(1, 2), ~content="3")?
}

test {
(add(3, 4) |> inspect(~content="7"))?
}

2.编译器内置函数迁移到标准库

把原本的在编译器内部的一些基础的 MoonBit 定义迁移到了标准库中。在线IDE上也可以使用标准库了

3. 支持 alert pragam

MoonBit 现在支持在顶层的文档注释中书写多个 pragam。所有的 pragam 以@开头,并且独占一行。

Untitled

目前支持函数和方法的 alert pragma,当被标记了 alert 的函数和方法被使用时会产生警告。这个机制可以用来标记已经弃用或者不安全的函数。alert pragma 的格式为@alert id "explain string",其中id可以是任意的标识符。

Untitled

4. 支持在 pragma 中标注 intrinsic

比如标准库中的如下代码在被标注 intrinsic 之后,在 JavaScript 后端会使用 String(..) 函数来将浮点数转化为字符串,后续会加入更多函数的 intrinsic 支持。

/// @intrinsic %f64.to_string
pub fn to_string(self : Double) -> String {
double_to_string(self)
}

5. 生成代码性能和体积的改进

  • 引入了消除局部 alias 的优化,从而避免生成无用的局部变量
  • 引入了常量传播的优化
  • 优化了生成的 wasm 代码中类型声明的部分,减少了冗余的类型声明

https://picx.zhimg.com/80/v2-18712f8e289e2548fdafcd3775aa060e_1440w.jpg?source=d16d100b

6. moonfmt 改进

  • 调整 function for loop 的打印格式,特殊情况不再打印分号
  • 针对 if/match 这种可读性差的嵌套的情况,格式化后加上额外的括号。格式化前和格式化后的效果:

格式化前:

Untitled

格式化后:

Untitled

7. 改进模式匹配完备性检查

8. 调整字符串的编码为UTF-16

构建系统更新

moon.pkg.json 中支持自定义函数导出名称

moon.pkg.json 中支持使用 ["link"][BACKEND]["exports] 字段自定义函数导出名称,并且默认不再导出所有的 pub 函数,必须要在 exports 中显式指定。此外,现在支持通过设置 link 字段链接非 main 包。

例如使用 moon new hello 创建一个新项目,其目录结构为:

.
├── README.md
├── lib
│ ├── hello.mbt
│ ├── hello_test.mbt
│ └── moon.pkg.json
├── main
│ ├── main.mbt
│ └── moon.pkg.json
└── moon.mod.json

在过去,执行 moon build,只有 main 包会生成 wasm 文件。

现在,在 moon.pkg.json 中支持 link 字段,可以对非 main 包生成 wasm 文件。link 字段的内容可以是一个布尔值:

{
"link": true // 表示当前包需要被链接
}

或者是一个对象,可以给不同的后端如 wasm 或者 wasm-gc ,设定链接选项。目前只支持 exports 选项,exports 是一个字符串数组,包含需要导出的函数及其需要导出的名称:

{
"link": {
"wasm": {
"exports": [
"hello" // 这里将函数 hello 导出为 hello,
]
},
"wasm-gc": {
"exports": [
"hello:hello_wasm_gc" // 这里将函数 hello 导出为 hello_wasm_gc
]
}
}
}

如果将 lib/moon.pkg.json 中的内容修改为:

{
"link": {
"wasm": {
"exports": [
"hello"
]
}
}
}

然后执行 moon build --output-wat,可以观察到输出的 target/wasm/release/build/lib/lib.wat 中包含如下内容:

(func $$username/hello/lib.hello.fn/1 (export "hello") (result i32)
(i32.const 10000))

其中的 (export "hello") 表示配置生效了。

IDE 更新

vscode 插件支持安装或更新 MoonBit工具链。

Untitled

weekly-03-25

· 阅读需 3 分钟

构建系统更新

1. 支持 expect testing

a. 使用 moon new 新建一个 MoonBit 项目。

b. 在 lib/hello.mbt中写入:

pub fn hello() -> String {
"Hello, world!"
}

test {
let buf = Buffer::make(10)
buf.write_string(hello())
buf.expect()?
}

c. 然后运行 moon test --update或者 moon test -u:

$ moon test --update
expect test failed at lib/hello.mbt:8:3-8:15
Diff:
----
Hello, world!
----

Total tests: 1, passed: 0, failed: 1.

Auto updating expect tests and retesting ...

Total tests: 1, passed: 1, failed: 0.

d. 再次打开 lib/hello.mbt 文件,可以看到已经将测试结果 promote 到源码中。

pub fn hello() -> String {
"Hello, world!"
}

test {
let buf = Buffer::make(10)
buf.write_string(hello())
buf.expect(~content="Hello, world!")?
// ^~~~~~~~~~~~~~~~~~~~~~~~ 测试结果更新
}

2. moon run 不再支持 --output-wat选项。

MoonBit 更新

1. 支持多参数构造器的后端代码生成

支持多参数构造器(multi-argument constructor)的后端代码生成。现在构造一个泛型类型的值的时候,如果泛型参数为元组的话必须要写括号,即:

enum A[X] {
A(X)
}

fn init {
// Error, expecting 1 arg, getting 2
A::A(1, 2) |> ignore

// Ok
A::A((1, 2)) |> ignore
}

多参数构造器 unbox 了参数,能够提高生成的代码的性能,也允许程序员对数据的内存布局有了更多的掌控。

2. 调整了Int64的lsl, lsr, asr方法

现在移位参数不再是Int64,而是Int。同时调整了clz, ctz, popcnt方法,现在返回类型不再是Int64,而是Int。此项改变有助于我们在不支持原生Int64的平台上生成更高效的代码。

IDE 更新

1. 支持带标签参数的重命名。

2. VSCode 插件支持自动安装或者更新 MoonBit

a. 更新插件后,如果没有安装 moon 或者 moon 不是最新的时候,VSCode 右下角弹出自动安装/升级的提示。

Untitled

b. 点击 "yes", 来执行自动安装任务。任务完成后就可以用了。

Untitled

weekly-03-18

· 阅读需 3 分钟

语言更新

1. 实验性地添加对 trait 实现默认方法的功能

trait MyShow {
repr(Self) -> String
str (Self) -> String // it has a default implementation
}

impl MyShow::str(self : Self) -> String {
// default implementation of str
self.repr()
}

type MyInt Int
fn repr(self:MyInt) -> String {
self.0.to_string()
}
// Now MyInt implements MyShow now

2. 允许类型定义的类型参数为 _

_可以用来定义 phantom type,来限制一些程序逻辑上非法的操作。例如我们希望不同单位的长度不能够相加:

type Length[_] Int

type Kilometer
type Mile

fn add[T](x: Length[T], y:Length[T]) -> Length[T] {
Length::Length(x.0 + y.0)
}

let d_km: Length[Kilometer] = Length(10)
let d_mile: Length[Mile] = Length(16)

此时,两个单位不同的长度并不能够直接相加:

fn init {
add(d_km, d_mile) |> ignore
// ^~~~~~ Error: Expr Type Mismatch
}

而两个单位相同的长度可以相加:

fn init {
add(d_km, d_km) |> ignore
// OK
}

3. 现在 Toplevel 函数没有标记返回值的行为改成报错

Toplevel 函数没有标记返回值的行为从之前的默认设置为 Unit 改成报错。

fn print_hello() {
// ^~~~~~~~~~~ Error:
// Missing type annotation for the return value.
println("Hello!")
}

4. 添加了按位取反的操作符

fn main {
println((1).lnot())
}

输出:

-2

5. 改进 List::to_string/debug_write 的输出

fn main {
let l = List::Cons(1, Cons(2, Cons(3, Nil)))
println(l)
}

输出:

List::[1, 2, 3]

6. 添加了 Byte 类型

byte 字面量由 b 作为前缀,使用方式如下:

fn init {
let b1 = b'a'
println(b1.to_int())
let b2 = b'\xff'
println(b2.to_int())
}

更多关于 Byte 的功能还在完善中

IDE更新

1.支持对 moonbitlang/core 的补全

2. 格式化的更新和修复:

  • 调整空的 struct、enum、trait,避免出现空行。

之前:

struct A {

}

之后:

struct A {}
  • 修复 continue 的错误缩进。
  • 修复多行语句格式化后出现分号的问题。

构建系统更新

1. moon.mod.json 添加了 test_import 字段

test_import这个字段中用到的依赖只会在测试的时候被用到。

2. 优化 moon test 输出

默认只输出失败的测试用例信息,如果需要完整输出可使用moon test -v命令。

weekly-03-11

· 阅读需 6 分钟

01 MoonBit 更新

1. moonbitlang/core 开源

moonbitlang/core(MoonBit标准库)现已开源。我们很高兴收到社区的积极反馈,想了解更多与moonbitlang/core开源的详情,可点击这里查看:国人自主研发的编程语言 MoonBit Core 开源啦!

Github链接:

https://github.com/moonbitlang/core

2. 支持带标签/可选参数

支持带标签参数(labelled argument)和可选参数(optional argument)。带标签参数有助于区分相同类型,不同功能的函数:

fn greeting(~name: String, ~location: String) {
println("Hi, \\(name) from \\(location)!")
}

fn init {
greeting(~name="somebody", ~location="some city")
let name = "someone else"
let location = "another city"
greeting(~name, ~location)// `~label=label` 可以简写成 `~label`
}

可选参数必须带标签,并且指定默认值。在函数调用的时候,如果没有手动指定参数,则取默认值。注意:默认值在每次调用的时候都会被重新求值:

fn greeting(~name: String, ~location: Option[String] = None) {
match location {
Some(location) => println("Hi, \\(name)!")
None => println("Hi, \\(name) from \\(location)!")
}
}

fn init {
greeting(~name="A")// Hi, A!
greeting(~name="B", ~location=Some("X")// Hi, B from X!
}

3. 提供了内建类型 SourceLoc

SourceLoc,表示源码中的位置。假如某个函数声明了一个类型为 SourceLoc、默认值为 _ 的可选参数,那么每次调用这个函数时,MoonBit 会自动插入调用处的位置作为这个参数的默认值:

fn f(~loc : SourceLoc = _) {
println("called at \\(loc)")
}

fn g(~loc : SourceLoc = _) {
f()// 显示 `g` 内部的位置
f(~loc)// 自动注入的参数也可以手动覆盖。这一次调用会显示 `g` 的调用者的位置
}

test "source loc" {
g()
}

try.moonbitlang.cn 新建一个名为 test.mbt 的文件,放入上述代码,并运行代码中的测试,可以得到如下的输出:

test source loc ...
called at memfs:/sample-folder/test.mbt:6:3-6:6
called at memfs:/sample-folder/test.mbt:11:3-11:6

SourceLoc 可以用于编写测试相关的函数,用于在测试失败时输出有用的位置信息:

fn assert_eq[X: Eq + Show](result: X, expect: X, ~loc : SourceLoc = _) -> Result[Unit, String] {
if (result == expect) {
Ok(())
} else {
Err("\\(loc): Assertion failed: \\(result) != \\(expect)")
}
}

test "1 =? 2" {
assert_eq(1, 2)?
}
running 1 tests
test 1 =? 2 ... FAILED memfs:/sample-folder/test.mbt:10:3-10:18: Assertion failed: 1 != 2

test result: 0 passed; 1 failed

4. === 已经弃用,可以使用 physical_equal 作为代替

5. 添加新的内置类型 UnsafeMaybeUninit[T]

添加新的内置类型 UnsafeMaybeUninit[T] 和对于该类型的一些相关操作,用以在 MoonBit Core 中实现 Vector 等数据结构,因为其不安全性,普通的 MoonBit 程序中应尽可能避免使用该类型。

02构建系统更新

1. 支持 JavaScript 后端

可以通过 --target js 来生成后端代码。例如:

a. 通过 moon new hello 新建一个名为 hello 的项目

b. 在 main/main.mbt 中写入:

fn main {
println("Hello from JavaScript!")
}

c. 在命令行中构建生成 JavaScript 代码,并使用 Node 运行。

$ moon build --target js
moon: ran 2 tasks, now up to date
$ node target/js/release/build/main/main.js
Hello from JavaScript!

d. 你也可以方便地通过 moon run main --target js 来编译并运行编译到 JavaScript 的 MoonBit 代码。

$ moon run main --target js
Hello from JavaScript!

2. 修复了一些 moonbuild 的问题

a. 修复了 Windows 上 moon upgrade 失败的问题。

b. 修复了 moon add 添加新版本没有移除旧版本的问题。

c. 修复了本地 moon check 失败仍然能够 publish 的问题。

IDE更新

1. 线上 IDE 支持通过 CodeLens 的方式运行测试

ide更新|306x168

2. 大幅度改善 moonfmt 的对于包含注释的源代码的处理。

3. 提升 IDE 和 VSCode 插件的稳定性和用户体验

a. VSCode插件现在是在文件更改的时候调用moon check而非启动moon check -w

b. 提升了多行字符串和文档注释(docstring)的输入体验。现在在多行字符串/文档注释内部换行会自动补上 #| 或者 /// 的前缀。

c. 修复了 hover、moon.pkg.json 出错,空文件等导致 lsp 报错的问题。

工具链更新

Markdown linter 支持 expr 标签

举个例子:

```moonbit expr
1 * 2 + 3

可以在运行 mdlint 的时候看到对应的输出:

5

weekly-03-04

· 阅读需 5 分钟

一、MoonBit更新

1. 添加了 += 系列语句

包括+=、-=、*=、/=,支持运算符重载:

fn init {
let array = [1,2,3,4]
array[2] *= 10
println(array) // [1, 2, 30, 4]
}

fn init {
let mut a = 1
a += 20
println(a) // 21
}
struct Foo {
data : Array[Int]
} derive(Debug)

fn op_set(self : Foo, index : Int, value : Int) {
self.data[index] = value
}

fn op_get(self : Foo, index : Int) -> Int {
self.data[index]
}

fn init {
let foo : Foo = { data: [0,0,0,0] }
foo[2] -= 10
debug(foo) // {data: [0, 0, -10, 0]}
}

2. 现在 toplevel 如果没有顶格会报错

如下图所示:

image|690x204

3. 引入 super-trait 机制

Super-trait 通过如下的语法指定:

trait A {
// ...
}

trait B : A { // A is a super trait of B, B is a sub trait of A
// ...
}

可以通过 + 来指定多个 Super-trait,表示该 sub-trait 依赖这几个 super-trait:

// ...

trait B: A + Compare + Debug {
// ^~~ B is a sub-trait of A *and* Compare *and* Debug
// ...
}

在使用上,可以将 sub-trait 当作 super trait 使用,但是不能够将 super-trait 当作 sub-trait 使用。目前Compare是Eq的 sub-trait,意味着实现了Compare的类型能够在要求Eq的情况下使用,所以以这两个代码为例:

trait Eq {
op_equal(Self, Self) -> Bool
}

trait Compare: Eq {
compare(Self, Self) -> Int
}

fn eq[X: Compare](this: X, that: X) -> Bool {
this == that
}
fn compare[X: Eq](this: X, that: X) -> Int {
this.compare(that)
// ^~~~~~~ Type X has no method compare.
}

4. 添加T::[x, y, ...]的语法

这种语法结构会被解糖成T::from_array([x, y, ...])的形式。这种语法使得列表等线性数据结构的初始化更加易读。

enum List[X] {
Nil
Cons(X, List[X])
} derive(Show, Debug)

fn List::from_array[X](array: Array[X]) -> List[X] {
let mut list = List::Nil
for i = array.length() - 1; i >= 0; i = i - 1 {
list = Cons(array[i], list)
}
list
}

fn main {
println(List::[1, 2, 3])
}

输出:

Cons(1, Cons(2, Cons(3, Nil)))

5. 调整自动生成的 Show 的实现的逻辑

现在它会调用 Debug 作为实现。这意味着,现在 derive(Show) 之前需要先 derive 或自行实现 Debug。Debug 的输出是 MoonBit 语法下合法的值,而 Show 可以用于输出更美观的内容。这修复了之前 derive(Show) 在有 String 的结构体上的错误行为:

struct T {
x: String
} derive(Show, Debug)

fn init {
println({ x: "1, y: 2" })
// 之前: {x: 1, y: 2}
// 现在: {x: "1, y: 2"}
}

6. 目前已不支持fn hello() = "xx"的语法

fn hello() = "xx"的语法目前已经不适用了。我们建议用户这样写:

extern "wasm" fn hello () =
#| ...

现在 inline stubs 只支持 wasmgc,不支持 wasm1。

7. 现在丢弃非 Unit 的值会直接报错,如果需要丢弃需要显式使用 ignore。

fn f() -> Int {
ignore(3) // Ok.
3 |> ignore // Ok.
3 // Err: Expr Type Mismatch: has type Int, wanted Unit
3 // Ok, as this value is returned, not dropped
}

8. 移除了test作为标识符使用的支持

二、IDE更新

1. 提供更好的线上 IDE Markdown 支持

  • 可以在线上 IDE 中使用 Marp 插件来查看之前现代编程思想课的内容了。

image|690x481

  • Markdown 中内嵌的 MoonBit 的代码块支持语法高亮。

image|690x475

  • 针对内嵌有 MoonBit 代码的 Markdown 文本开发了语法检查的程序,开源在:GitHub链接。使用方法可以参考项目的 README。

三、构建系统更新

1. 添加 main 函数的支持

  • main只能写在main包(is_main: true的包)里
  • main 包中应当有且仅有一个main 函数
  • main函数的执行顺序在所有init函数之后
  • main包中不能有test

2. 目前可以通过 moon upgrade 升级 MoonBit 工具链的版本了。

p.s. 但是在使用之前,必须再用安装脚本安装一次:-)

3. moon check|build|run 现在默认链接到 moonbitlang/core。