Open11

OnyxというWASMファーストの言語に触れる

大井さかな大井さかな

Onyxの哲学

ドキュメントを要約。

WASMの利点

  • クロスプラットフォームでの動作
  • サンドボックス環境で安全
  • Onyxは趣味のプロジェクトだから、難しいLLVMより扱いやすい (作者にとって)

など

Onyxの利点

他の言語の代替を目指すものではなく、WASMの可能性を広げるニッチなユースケースのための言語

向いていないユースケースとして、次の3つを挙げている

  • 高性能なデスクトップアプリケーション
  • ネイティブライブラリ
  • 組み込み環境

逆にどの場面に適しているかを挙げてほしい。。。

メモリ管理

ガベージコレクションなどは無く、割り当てと解放を考える必要がある。

ライフタイムは3つ。

  • Very short term: おそらく関数の終了まで
    • deferキーワードにより、割り当てと解放を並べて書くことができる。
  • Short term: メインループの終了まで
    • 一時アロケータを使用。
    • 個別解放はできない。通常、メインループの最初か最後に全解放される。
  • Infinte: 解放されない
  • 手動管理

長時間実行されるようなアプリケーション(ゲーム、ウェブサーバ、グラフィカルアプリケーション)ではメモリ管理が重要。

補足でhttpパッケージでのGCアロケータの話などが書いてあるが、ちょっとわからない。

https://docs.onyxlang.io/book/philosophy/philosophy.html

大井さかな大井さかな

環境構築

インストール

zsh
sh <(curl https://get.onyxlang.io -sSfL)

ランタイムを聞かれる。デフォルトのWasmerを選択。

パス設定のために~/.zshrcも更新してくれる。
ONYX_PATHがセットされてないよ!というエラーが出たので、source ~/.zshrcで読み込んであげた。

WASMランタイムが含まれているので、Node.jsやPythonのようにコマンド1つで実行できるのが便利。

https://onyxlang.io/docs/getting_started

拡張機能

VS Codeの場合、Onyx Programming Language拡張機能をインストールすることで利用できる。

シンタックスハイライトはできたが、文法チェックやフォーマットはうまくいかない。あとでやる

https://onyxlang.io/docs/setup

大井さかな大井さかな

動かしてみる

プロジェクト初期化

onyx pkg initで初期化できる

zsh
$ onyx pkg init
Creating new project manifest in ./onyx-pkg.kdl.

Package name: playground
Package description:              
Package url: 
Package author: 
Package version (0.0.1): 

onyx-pkg.kdlというファイルが生成される。kdlってなんだろう

onyx-pkg.kdl
package {
    name "playground" 
    author "" 
    url "" 
    description "" 
    version "0.0.1" 
}

config {
    dependency_source_path "./lib" 
    dependency_binary_path "./bin" 
}

プログラムの作成と実行

main.onyxを作成。

main.onyx
use core {printf}

main :: () {
    printf("Hello world!\n");
}

WASMランタイムがあるのでコマンド1つですぐに実行できる。

zsh
$ onyx run main.onyx
Hello world!

https://onyxlang.io/docs/getting_started

大井さかな大井さかな

文法

変数

x: i32 = 10;
y: i32;    // 初期値0になる
z := 10;   // 型の記述を省略できる。型推論によりi32型になる

プロシージャ (関数)

基本形

greet :: () -> void {
  printf("Hello!\n");
}
greet()

引数

add :: (x: i32, y: i32) -> void {
  printf("{}\n", x + y);
}

add(3, 5);         // 8
add(y = 8, x = 2); // 10

引数の初期値

say :: (msg: str = "名無し") -> void {
  printf("こんにちは{}さん\n", msg);
}
say("太郎"); // こんにちは太郎さん
say();      // こんにちは名無しさん

返り値

// 単一の値
add :: (x: i32, y: i32) -> i32 {
  return x + y;
}

// 複数の値
swap :: (x: i32, y: i32) -> (i32, i32) {
  return (y, x);
}

// 最初のreturn文から推測
sub :: (x: i32, y: i32) -> #auto {
  return x - y;
}

a := add(3, 5);  // 8
b, c := swap(10, 20); // b: 20, c: 20
d := sub(10, 7);  // 3
大井さかな大井さかな

パッケージ

スコープ

  • 何もないと、外部からアクセス可能
  • #packageディレクティブを直前におくとパッケージ内からのみアクセス可能
  • #localディレクティブを直前におくとファイル内からのみアクセス可能
package foo
use core {println}

greet1 :: () {
    println("Good morning!");
}

#package
greet2 :: () {
    println("Good afternoon!");
}

#local
greet3 :: () {
    println("Good evening!");
}

https://docs.onyxlang.io/book/structure/packages.html

パッケージの使用

core.encoding.base64からencodeプロシージャにアクセス

use core {printf}
use core.encoding.base64 {encode}

main :: () {
  msg := "Hello";
  encoded := encode(msg);
  printf("{} {}\n", msg, encoded);
}
大井さかな大井さかな

ビルドサイズ

シンプルなHello worldで実験。

main.onyx
use core {println}

main :: () {
  println("Hello world!");
}
  • onyx build main.onyx -r wasi: 163KB
  • onyx build main.onyx -r js: 113KB
  • onyx build main.onyx -r js --no-type-info: 58KB

--no-coreオプションを使用するとビルドができないので、使い道がまだわからない

`onyx build`のオプション
$ onyx help build
Onyx toolchain version v0.1.8
Built on Wed Nov 29 01:49:11 2023
Runtime: wasmer

The toolchain for the Onyx programming language, created by Brendan Hansen.

Usage:
        onyx build <input files> [-o target_file] OPTIONS

Required:
        <input files>           One or more Onyx files to include in the program.

Options:
        -o <target_file>        Specify the target file (default: out.wasm).
           --output <target_file>
        -I <dir>                Include a directory in the search path.
        --runtime, -r <runtime> Specifies the runtime. Can be: onyx, wasi, js, custom.
                                (default: onyx)
        --verbose, -V           Verbose output.
                   -VV          Very verbose output.
                   -VVV         Very very verbose output (to be used by compiler developers).
        --multi-threaded        Enables multi-threading for this compilation.
                                Automatically enabled for "onyx" runtime.
        --doc <doc_file>        Generates an O-DOC file, a.k.a an Onyx documentation file. Used by onyx-doc-gen.
        --tag                   Generates a C-Tag file.
        --syminfo <target_file> (DEPRECATED) Generates a symbol resolution information file. Used by onyx-lsp.
        --lspinfo <target_file> Generates an LSP information file. Used by onyx-lsp.
        --stack-trace           Enable dynamic stack trace.
        --no-core               Disable automatically including "core/module".
        --no-stale-code         Disables use of `#allow_stale_code` directive
        --no-type-info          Disables generating type information
        --generate-foreign-info Generate information for foreign blocks. Rarely needed, so disabled by default.
        --wasm-mvp              Use only WebAssembly MVP features.

Developer options:
        --no-colors               Disables colors in the error message.
        --no-file-contents        Disables '#file_contents' for security.
        --show-all-errors         Print all errors (can result in many consequencial errors from a single error)
        --print-function-mappings Prints a mapping from WASM function index to source location.
        --print-static-if-results Prints the conditional result of each #if statement. Useful for debugging.

wat形式にしてのぞいてみる

wasm2wat demoを使用する。残念ながらwasmの仕様に詳しくないので眺めることしかできない。

しかし、数学関数や日付まわりのテキストが含まれるのはわかった。
あと、ユーザー名が含まれるパスが何個も入っているのが気になる。





大井さかな大井さかな

ブラウザでの実行 (1)

単純な足し算。#export "名前" プロシージャの構文。

main.onyx
#export "add" (x, y: i32) -> i32 {
    return x + y;
}

main ::() {}

https://docs.onyxlang.io/book/directives/export.html

ビルド時には-r jsまたは--runtime jsの指定が必要

zsh
onyx build main.onyx -r js

下記のJavaScriptをhtmlに埋め込めばOK (wasmのロード方法覚えていないのでCopilotに書いてもらった)

main.js
fetch('out.wasm')
  .then((response) => response.arrayBuffer())
  .then((bytes) =>
    WebAssembly.instantiate(bytes, {
      host: {
        print_str: (obj) => console.log(obj),
        time: () => console.log('time'),
      },
    })
  )
  .then((results) => {
    const { add } = results.instance.exports;
    console.log(add(10, 20));
  });

instantiateの第二引数はよくわからないけど、とりあえずGitHubのIssueにあったコードをコピペしてきた。どこに仕様があるんだろう?
https://github.com/onyx-lang/onyx/issues/50

ブラウザで動かす

できた!

大井さかな大井さかな

ブラウザでの実行 (2)

もう少しいい方法があった。

まず、onyxのリポジトリ内にひっそり(?)置かれているonyx-loader.jsをダウンロードしてくる

そして、onyx-loader.jsと、wasmファイルを次のようにしてロードさせる。
script要素のtype属性がapplication/onyxであるとロードしてくれる仕様。

index.html
    <script type="application/onyx" src="out.wasm"></script>
    <script src="onyx-loader.js"></script>

シンプルな文字列の出力プログラムを作り、

main.onyx
use core {println}

main ::() {
  println("Good morning!");
}

onyx build main.onyx --runtime jsでコンパイルして、ブラウザを開くと、

できた!

謎のinstantiateの第二引数と戦う必要がなくなった

このonyx-loader.jsって、現状exportされたプロシージャ扱えるのか?そこだけ疑問
window.ONYX_INSTANCE経由で扱えそう