スクリプト言語 KINX（ご紹介）

# はじめに

以前[こんなこと](https://qiita.com/Kray-G/items/7d1af238b46594ff78fe)（C言語系の構文を持つスクリプト言語が使いたいなー）を書いたのだが、やはり職人として自分の道具は自分で作るか、という誘惑に駆られ作ってみた。

*   https://github.com/Kray-G/kinx
    *   Looks like JavaScript, feels like Ruby, and it is a script language fitting in C programmers.

まあ、無い無い言っていても探せばどこかにある(ここでは言わない)ような代物だが、自己満足してても寂しいので、解説の足跡を残しておこう。(本記事を目次に使えるよう追加したら順次更新することにしよう)

<details><summary>目次（個別解説記事へのリンク）</summary><div>

*   [スクリプト言語 KINX（ご紹介）](https://qiita.com/Kray-G/items/ca08b6fb40d15dd0ec76) [本記事]
*   リリース記事
    * [Kinx プレビュー版リリース(最初の)](https://qiita.com/Kray-G/items/4c6011279d0bd3036da8)
    * [Kinx v1.0.0 正式リリース（プレ卒業）](https://qiita.com/Kray-G/items/4e3e9616b34bae68b1a0)
*   基礎文法最速マスター
    *   [Kinx 基礎文法最速マスター](https://qiita.com/Kray-G/items/e6d8087aba2ce84fc43c)
*   基本編
    *   [プログラム基礎・データ型](https://qiita.com/Kray-G/items/f1f891fe799fcc757834)
    *   [制御構造](https://qiita.com/Kray-G/items/926dffbf9ee52334f7d5)
    *   [Case-When/Switch-When](https://qiita.com/Kray-G/items/dcb6c77fe6eda19fb41c) 
*   要素編
    *   [関数とクロージャ](https://qiita.com/Kray-G/items/8e48b5b89203e2ec46af)
    *   [クラスとモジュール](https://qiita.com/Kray-G/items/20e8a0cc4ac1bfc66193)
    *   [演算子オーバーライド](https://qiita.com/Kray-G/items/31f07e2f94901affc61f)
*   ライブラリ編
    *   システム
        *   [Signal](https://qiita.com/Kray-G/items/74610fe6885f5227b0ac)
        *   [エスケープ・シーケンス](https://qiita.com/Kray-G/items/b1ac01a9eae722905079)
        *   [マルチスレッド(Isolate)](https://qiita.com/Kray-G/items/78cf553b65e286ea39c4)
        *   [Process](https://qiita.com/Kray-G/items/e44c39ddb2e17659a0a4)
        *   [REPL](https://qiita.com/Kray-G/items/15889e839d4c7812b3b2)
    *   プリミティブ
        *   [Integer](https://qiita.com/Kray-G/items/d74202dc7878731de916)
        *   [Double](https://qiita.com/Kray-G/items/bd1a134cc501d55a4aa3)
        *   [String](https://qiita.com/Kray-G/items/54aea3dec37fe395d9df)
        *   [Binary](https://qiita.com/Kray-G/items/e4e7183b64949683b780)
        *   [Array](https://qiita.com/Kray-G/items/1d48e22a661d57514de8)
    *   ユーティリティ
        *   [Getopt](https://qiita.com/Kray-G/items/5045230cd8484c6c5bf9)
        *   [Regex](https://qiita.com/Kray-G/items/213c73d38aa8cc709999)
        *   [Range, Enumerable, for-in](https://qiita.com/Kray-G/items/821eeba150a86d93766d)
        *   [DateTime](https://qiita.com/Kray-G/items/c3e5218c4061cb407d4f)
        *   [Math](https://qiita.com/Kray-G/items/be251d0a3c0bcaa5ba79)
        *   [File/Directory](https://qiita.com/Kray-G/items/47e2bf2743afc0ee5e95)
        *   [Database(SQLite3)](https://qiita.com/Kray-G/items/8d3a6e56d9b45d1b0221)
        *   [Zip](https://qiita.com/Kray-G/items/f8be2c7eabbfc8731ff5)
        *   [XML](https://qiita.com/Kray-G/items/2af84d7dfbf3d11853dd)
        *   [CSV Parser](https://qiita.com/Kray-G/items/6f83b07fca3b0b99967f)
        *   JIT コンパイラ・ライブラリ
            *   [JIT ライブラリ](https://qiita.com/Kray-G/items/a237f195630f3f0a91df)
            *   [JIT ライブラリ（番外編）](https://qiita.com/Kray-G/items/6d85d97b93d11c956b54)
        *   Parsek - パーサ・コンビネータ
            *   [パーサ・コンビネータ(1)](https://qiita.com/Kray-G/items/0224128078af7554fd08)
            *   [パーサ・コンビネータ(2)](https://qiita.com/Kray-G/items/e2b9c99a5052423455ef)
            *   [パーサ・コンビネータ(番外編)](https://qiita.com/Kray-G/items/f79898ac665cb2fe1f9e)
    *   ネットワーク
        *   [Http](https://qiita.com/Kray-G/items/588eb370cb3213466cc8)
    *   アルゴリズム
        *   ソート
            *   [クイックソート](https://qiita.com/Kray-G/items/d2305cd5e97e803af25c)
            *   [バブルソート](https://qiita.com/Kray-G/items/cc6b523ec8471041be92)
            *   [マージソート](https://qiita.com/Kray-G/items/553dfc282bed0a58cf6b)
            *   [ヒープソート](https://qiita.com/Kray-G/items/bbc1ee89d4bffd4dfe68)
            *   [挿入ソート](https://qiita.com/Kray-G/items/fe125ecbdeaf689f491c)
            *   [選択ソート](https://qiita.com/Kray-G/items/551d5496a49d96ac2a46)
        *   ゲーム・パズル
            *   [ライフゲーム](https://qiita.com/Kray-G/items/416b93c92c074e29c902)
            *   [エイト・クイーン](https://qiita.com/Kray-G/items/8f232b9ce68234df1f9b)
            *   [騎士巡回問題](https://qiita.com/Kray-G/items/d3450e032bae8ae52648)
            *   [宣教師と人食い人種](https://qiita.com/Kray-G/items/fcaaa827f794edb5074f)
            *   [ハノイの塔](https://qiita.com/Kray-G/items/85c9067ae82e30848c51)
*   Tips
    *   [Kinx Tips - UTF8 文字列のフォーマッティング](https://qiita.com/Kray-G/items/97913a37c46c86144357)
    *   [Kinx Tips - 実行形式ファイルを作る](https://qiita.com/Kray-G/items/ffc0a4462b57292f3ab7)
*   インサイド Kinx
    *   [Kinx 実現技術 - Yacc/Bison](https://qiita.com/Kray-G/items/f198a8b105b37fd43fab)
    *   [Kinx 実現技術 - Switch-Case](https://qiita.com/Kray-G/items/dfeed33544b9687717bb)
    *   [Kinx 実現技術 - VM (Virtual Machine)](https://qiita.com/Kray-G/items/034454f69dfa914f56c9)
    *   [Kinx 実現技術 - JIT コンパイル](https://qiita.com/Kray-G/items/66257e4cca0ad6dd7636)
    *   [Kinx 実現技術 - JIT: sljit の使い方](https://qiita.com/Kray-G/items/c0636ede884ef6094daa)
    *   [Kinx 実現技術 - Garbage Collection](https://qiita.com/Kray-G/items/1ee8710d2a70a037f861)
    *   [Kinx 実現技術 - Fiber](https://qiita.com/Kray-G/items/1ca831b69df8222bc7bf)
*   雑多な話題
	*   [KINX … ロゴ作った話と BDD 用テスティングフレームワークの話](https://qiita.com/Kray-G/items/30db83922268929e8cd0)
    *   [その後サポートした機能](https://qiita.com/Kray-G/items/3a17eebea0077b65b757)
    *   [map 派？ collect 派？](https://qiita.com/Kray-G/items/d47af62fb4bee6a5b2de)
    *   [Ruby の Range で ("b".."aa") が使えなかった件について](https://qiita.com/Kray-G/items/282e3c841a0b342fb20a)
    *   [Mandelbrot ベンチマーク(C, PHP, HHVM, Ruby, Python, and Kinx)](https://qiita.com/Kray-G/items/222e6936daf612673999)
    *   [Kinx Tiny Typesetting](https://qiita.com/Kray-G/items/7dca6f2abb538500092d)
        *   [KiTTy 自動組版](https://qiita.com/Kray-G/items/8d7f3f83bc0357627e35)
    *   [Kinx で湯婆婆を実装してみる](https://qiita.com/Kray-G/items/09b10e5553f3aa2edb3b)
    *   [Kinx で ModanShogi 実装してみた](https://qiita.com/Kray-G/items/ecb56650206968b85706)

</div></details>

> 地道に投稿してたら記事数がだいぶ増えた。

# 何？

手に馴染んでいる伝統的な C 言語系統の Syntax を受け継いだスクリプト言語。目指すは「**見た目は JavaScript**、**頭脳(中身)は Ruby**、**安定感は AC/DC(?)**」といったところ。

~~今はまだライブラリや基本メソッドが揃ってないので実用はまだ先だが、言語の基本的な部分は概ね動作する程度にはなった。~~ [バージョン1](https://qiita.com/Kray-G/items/4e3e9616b34bae68b1a0) をリリースしたし、もう実用できるようになったと言ってしまおう。

## 見た目は JavaScript

子供ではなく立派な大人。

C 系統で成功しているスクリプト言語と言えば JavaScript。ただし、デスクトップ向けとしてはいまいち。node.js は便利だがヘヴィ過ぎるし、挙動にクセがありすぎて。

一方で、Ruby の思想は好きなのだが、あの `end` がやたら目につく構文に抵抗がある。普通に通常のキーワードが埋もれるのだが…。

## 頭脳(中身)は Ruby

そうは言っても Ruby 的思考は嫌いではない。そう、見た目だけの問題なのだ。ならば違う見た目の Ruby になれば良い。

## 安定感は AC/DC

ブレない所を見習っていこうぜ。

# 名前の由来

深くは触れられない(?)が、[Red Warriors](https://ja.wikipedia.org/wiki/RED_WARRIORS) の名盤[「KING'S」](https://ja.wikipedia.org/wiki/KING'S)に遡るとだけ言っておこう。

現時点で「KINX」になったので、由来のほうを（[VAN HALEN](https://ja.wikipedia.org/wiki/ヴァン・ヘイレン) で有名な「[You Really Got Me](https://ja.wikipedia.org/wiki/ユー・リアリー・ガット・ミー)」のオリジナルである）[Kinks](https://ja.wikipedia.org/wiki/キンクス) に変えるといった「家系図捏造」的なことも視野に入れている。

# サンプル

詳しい解説はシリーズ化してお届けしよう。需要があるかは、気にしない。

> 今すぐ詳しい仕様が知りたいぜ、という方がもしいれば... [「ここ」](https://github.com/Kray-G/kinx/blob/master/docs/QuickReference.md)を参照してください。

## fibonacci

```javascript:fib.kx
function fib(n) {
    if (n < 3) return n;
    return fib(n-2) + fib(n-1);
}

System.println(fib($$[1].toInt()));
```

まず書くのはベンチマーク。見た目は JavaScript。

Ruby がかつて「スピードが目的じゃないぜ、楽しさなんだぜ？」とみんなを煽っていた懐かしいあの頃。YARV がリリースされてからのノリノリさ加減を見ると、あのスタンスはまさに「酸っぱいブドウ」だったことを目の当たりに…(いや、Ruby 好きなんですよ、見た目以外は)

早速ベンチマークしてみましょう。ついでに Ruby がライバル視している Python にも登場してもらいます。この辺りと比べておけば、だいたいの実力も推測できるというもの。ソースコードは以下の通り。Python3 は Python2 より遅いので 2 で。

```ruby:fib.rb
def fib(n)
  if n < 3
    return n;
  else
    return fib(n-2) + fib(n-1);
  end
end

puts fib(ARGV[0].to_i)
```

```python:fib.py
import sys

def fib(n):
    if n < 3:
        return n
    else:
        return fib(n-1) + fib(n-2)

print fib(int(sys.argv[1]))
```

### 結果

まず初めにバージョン表示。

```
$ ruby --version
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86-64-linux-gnu]
$ python --version
Python 2.7.15+
```

そして結果。単位は**「秒」**。`time` コマンドで `user` 時間の速い順。5回くらいやって一番速かったタイム。

|  言語      | `fib(34)` | `fib(38)` | `fib(39)` |
| ---------- | :-------: | :-------: | :-------: |
| **Ruby**   |   0.391   |   2.016   |   3.672   |
| **Kinx**   |   0.594   |   4.219   |   6.859   |
| **Python** |   0.750   |   5.539   |   9.109   |
|            |           |           |           |
| 値         |  9227465  |  63245986 | 102334155 |

Ruby 超速いな。遅い遅いはまさしく過去の話だ。むしろ速い部類に入るのではないかと思われるくらい。

Python には勝ったので、まぁこんなもん。スピードキングになろうとは思っていないので、実用的な速度であれば許容範囲としておこう。しかし、実は Kinx には `native` という必殺技があるのです。正直実用上どこまで役に立つのかはわからないが、可能性を感じて入れてみた。ソースコードは以下。`function` を `native` に変えただけ。

```javascript:nfib.kx
native fib(n) {
    if (n < 3) return n;
    return fib(n-2) + fib(n-1);
}

System.println(fib($$[1].toInt()));
```

この軽微な修正がどんな影響を与えるか、先ほどの表に追加して結果を示そう。

|       言語       | `fib(34)` | `fib(38)` | `fib(39)` |
| ---------------- | :-------: | :-------: | :-------: |
| **Kinx(native)** | **0.063** | **0.453** | **0.734** |
| **Ruby**         |   0.391   |   2.016   |   3.672   |
| **Kinx**         |   0.594   |   4.219   |   6.859   |
| **Python**       |   0.750   |   5.539   |   9.109   |
|                  |           |           |           |
| 値               |  9227465  |  63245986 | 102334155 |

キタ。

既に分かっているとは思うがあえて種明かしをすると、`native` キーワードが付いた関数はその名の通りマシン語コードにネイティブ・コンパイルし、JIT 実行させている、ということ。そら速いよね。ただし、出力されるアセンブリコードは最適化もレジスタ割当もしておらず全く美しくないが。実用上役に立つかわからない、というのは、色々と制限があるからです。後々触れると思うが、今日は触れない。詳しくは[「ここ」](https://github.com/Kray-G/kinx/blob/master/docs/spec/definition/native.md)を参照。

# その他の特徴

シリーズ化するので詳しい解説は今回はしないが、どんなことができるかだけ示しておこう。

## プロトタイプベース

JavaScript らしくプロトタイプベース。ただし `__proto__` みたいなのは無い。オブジェクト・プロパティに直接メソッドが括りついている。オーバーライドする場合は単に上書きする。`class` キーワードを用意してあり、クラスの定義ができる。こんな感じ。

```javascript
class ClassName {

    var privateVar_;

    private initialize() {
        privateVar_ = 0;
        this.publicVar = 0;
    }

    /* private method */
    private method1() { /* ... */ }
    private method2() { /* ... */ }

    /* public method */
    public method3() { /* ... */ }
    public method4() { /* ... */ }

}

var obj = new ClassName();
```

## ガベージコレクション

単純明快な Stop The World のマーク・アンド・スイープ。今のところ困ってない（困るようなほど使ってない）ので、問題無い。問題があったらその時考える。

## クロージャ

関数オブジェクトはレキシカル・スコープを持ち、クロージャを実現可能。JavaScript になる（ならないけど）なら当然の動作。こんな感じ。

```javascript
function newCounter() {
    var i = 0;          // a lexical variable.

    return function() { // an anonymous function.
        ++i;            // a reference to a lexical variable.
        return i;
    };
}

var c1 = newCounter();
System.println(c1()); // 1
System.println(c1()); // 2
System.println(c1()); // 3
System.println(c1()); // 4
System.println(c1()); // 5
```

## ラムダ

無名関数オブジェクトを簡潔に表記できる。ES6 でアロー関数が導入されたが全く同じではなく、先頭に `&` が必要。なぜかって？ Yacc でうまく書けなかったんですよ。コンフリクトが解消できず(すみません)。こんな感じ。

```javascript
function calc(x, y, func) {
    return func(x, y);
}

System.println("add = " + calc(10, 2, &(a, b) => a + b));
System.println("sub = " + calc(10, 2, &(a, b) => a - b));
System.println("mul = " + calc(10, 2, &(a, b) => a * b));
System.println("div = " + calc(10, 2, &(a, b) => a / b));
// add = 12
// sub = 8
// mul = 20
// div = 5
```

実はこうも書けるようにしました（追記）。

```javascript
System.println("add = " + calc(10, 2, { => _1 + _2 }));
System.println("sub = " + calc(10, 2, { => _1 - _2 }));
System.println("mul = " + calc(10, 2, { => _1 * _2 }));
System.println("div = " + calc(10, 2, { => _1 / _2 }));
```

こうしてもいいです（追記）。何が違うって？コールバックは引数の外側に出せるという感じです。

```javascript
System.println("add = " + calc(10, 2) { => _1 + _2 });
System.println("sub = " + calc(10, 2) { => _1 - _2 });
System.println("mul = " + calc(10, 2) { => _1 * _2 });
System.println("div = " + calc(10, 2) { => _1 / _2 });
```

## ファイバー

実はこの機能、私は使ったことが無い。ただ Ruby にあるし、便利そうなので実装。こうすればできるかなー、という軽い気持ちで試してみたら割と動いたので。`a = yield 10;` みたいな。尚、この時の `a` は呼び出し元の引数の配列が来る。簡単なサンプルはこんな感じ。

```javascript
var fiber = new Fiber {
    System.println("fiber 1");
    yield;
    System.println("fiber 2");
};

System.println("main 1");
fiber.resume();
System.println("main 2");
fiber.resume();
System.println("main 3");
// main 1
// fiber 1
// main 2
// fiber 2
// main 3
```

## スプレッド演算子

ES6 で導入された（んですよね？）スプレッド（レスト）演算子。そう、これ欲しかったんですよ。超便利。色々使い道はあるが、こんな感じ。

```javascript
function sample(a1, a2, ...a3) {
    // a1 = 1
    // a2 = 2
    // a3 = [3, 4, 5]
}

sample(1, 2, 3, 4, 5);
```

# 最後に

ここまで読んでくださってありがとうございます。まあ、気が向いたら使ってみてください。まだ実用的な使い道は無いと思いますが。

コントリビュートは大歓迎です。一番簡単なコントリビュートは「★」をクリックすることです。まだ全然少ないですが、増えるとモチベーション上がるよね。★が増えるといいな。

[ここ (https://github.com/Kray-G/kinx)](https://github.com/Kray-G/kinx)。