👍

Zig で簡単な JSON パーサを書いてみた。

2022/07/11に公開

はじめに

最近あたらしいプログラミング言語を覚えてないなと思ったので、Zig を触ってみる事にした。

と言っても随分前から気になっていて ziglings もやっていたんだけど、ちょっと飽きてしまった。

JSON パーサ

昔から新しいプログラミング言語で遊ぶ時には JSON パーサか Lisp インタプリタを書く様にしているけど、今回は JSON パーサにした。

https://github.com/mattn/zig-json
※ 実用的な物ではありません

といっても単純にパースして Value 構造体に納めるまでしか実装してないし、シリアライザも無い。 気が向いたら続きを作る。

触感

ziglings を触っていたのである程度、触感はあったのだけど JSON パーサを実装してみて Zig がだいたいどんな言語なのか分かってきた。一言で言うなれば

「Rust ぽいC言語」

別の言い回しをするなら

「Result と Optional のあるC言語」

といった所だと思う。

個人的な Zig のオススメどころ

何がすごいって、ReleaseSmall だと思う。fizzbuzz をC言語と Rust、それと Zig でビルドしてみた。

言語 オプション サイズ(b)
C言語 -Os 42496
Rust strip 129536
Zig -Drelease-small 8192
コード
#include <stdio.h>

int
main(int argc, char* argv[]) {
  int i;
  for (i = 1; i <= 100; i++) {
    if (i % 15 == 0) puts("FizzBuzz");
    else if (i % 15 == 0) puts("FizzBuzz");
    else if (i % 3 == 0) puts("Fizz");
    else if (i % 5 == 0) puts("Buzz");
    else printf("%d\n", i);
  }
  return 0;
}
fn main() {
    let mut x = 1;

    while x <= 100 {
        if x % 15 == 0 {
            println!("FizzBuzz");
        } else if x % 3 == 0 {
            println!("Fizz");
        } else if x % 5 == 0 {
            println!("Buzz");
        } else {
            println!("{}", x);
        }
        x += 1;
    }
}
const std = @import("std");

fn fizzbuzz(writer: anytype, i: u32) !void {
    if (i % 15 == 0) {
        try writer.print("{s}\n", .{"FizzBuzz"});
    } else if (i % 3 == 0) {
        try writer.print("{s}\n", .{"Fizz"});
    } else if (i % 5 == 0) {
        try writer.print("{s}\n", .{"Buzz"});
    } else {
        try writer.print("{}\n", .{i});
    }
}

pub fn main() anyerror!void {
    const stdout = std.io.getStdOut().writer();
    var i: u32 = 1;
    while (i <= 100) : (i += 1) {
        try fizzbuzz(stdout, i);
    }
}

ちょっとビックリする。サイズだけの話でもないが、個人的な感想で間違いを恐れずに言ってしまうと、Linux に組み込むなら正直 Rust より Zig の方が向いてると思ってる。(個人的な感想)

また LLVM で最適化されたコードを吐くのでケースによっては Rust より速い事もある。

https://programming-language-benchmarks.vercel.app/rust-vs-zig

さらに wasm と連携する仕組みもそこそこ整ってきていると思っていて、現在では簡単に wasm を生成できる様になっている。

https://twitter.com/mattn_jp/status/1533411673637556226

先日見付けたのだけど、3年前に既に Zig から DOM を生成し、イベントハンドラを書いて wasm 側から alert を表示するサンプルも動いている。

https://github.com/shritesh/zig-wasm-dom

wasm に限らずだがクロスコンパイルに長けている。通常 GitHub Actions では amd64 のバイナリしか生成する事ができず、QEMU を使って頑張ったりするのだけど、setup-zig で Zig コンパイラをインストールし、環境変数 CC を設定してあげれば amd64 上で arm64 のバイナリを簡単に生成できる。とても便利。先日、deno の拡張を作ったけど、arm64 バイナリは Zig で生成している。

おわりに

Zig で JSON パーサを書いて遊んでみました。めっちゃ速い JavaScript ランタイムの bun も Zig で書かれているし、これから Zig が目立ち始めるんじゃないかと思っています。

追記

Lisp インタプリタも書いてみたのでこちらもどうぞ。

https://zenn.dev/mattn/articles/7a4b7d5b069d1f

Discussion