スクリプト言語 KINX/基本編（2） - 制御構造

# はじめに

[前回](https://qiita.com/Kray-G/items/f1f891fe799fcc757834)の続き。過去の解説は以下を参照。概要は以下の初回記事[「スクリプト言語 KINX（ご紹介）」](https://qiita.com/Kray-G/items/ca08b6fb40d15dd0ec76)を参照してください。

*   [スクリプト言語 KINX（ご紹介）](https://qiita.com/Kray-G/items/ca08b6fb40d15dd0ec76)
*   [Kinx 基本編（1） - プログラム基礎・データ型](https://qiita.com/Kray-G/items/f1f891fe799fcc757834)
*   Kinx 基本編（2） - 制御構造（今回）

「**見た目は JavaScript**、**頭脳(中身)は Ruby**、（**安定感は AC/DC**）」な**スクリプト言語 KINX**。オブジェクト指向と C 系シンタックスで **C 系プログラマになじむ触感** をお届け。

# Kinx 基本編（2）- 制御構造

## 文・制御構文

文（ステートメント）として、宣言、代入、`continue`、`break`、`return`、`throw`、`yield`、および制御構文として `if-else`、`while`、`do-while`、`for`、`switch-case`、`try-catch-finally` が、使用可能。`if-else` の接続はぶら下がり構文で使用する。

### 宣言文

`var` で宣言する。初期化子で初期化も可能、またカンマで区切って複数同時に宣言することも可能。

```javascript
var a;
var a = 0, b = 100;
```

型を指定する場合は変数名の後に記述する。が、ここで指定された型は現時点で `native` でしか使用されていない。逆に `native` では指定しなければ全て `int` と見なされる。

```javascript
var a:dbl;
var a:int = 0, b:dbl = 100.0;
native<dbl> test(a:dbl, b:dbl) {
    /* function body */
}
```

指定できる型は現状以下の範囲のみ。

*   `int` ... 整数。通常スクリプトの範囲では自動的に Big Integer へのプロモーションが行われるが、`native` 関数内では単にオーバーフローするので注意。
*   `dbl` ... 実数。`int` → `dbl`、`dbl` → `int` へのキャストはサポートできていない。
*   `native<type>` ... type は復帰値のタイプ（`int` or `dbl`）。`native< native<type> >` とかは未サポート。

### 代入文

代入文は普通の式文。代入は右辺から評価される。

```javascript
a = b = 10;
```

上記では `b = 10` が先に評価され、その結果が `a` に代入される。

### continue

ループ先頭に戻る。正確にはループ条件式の直前に戻る。ただし、`for` 文の場合は第三フィールド（カウンタ更新の部分、何て言うんだ?）の直前に戻る。

`continue` はラベル指定が可能。`continue LABEL` で `LABEL` の示すブロックの先頭（ブロックがループの場合は上記の場所）に制御が戻る。また、`continue` は if 修飾が可能。`continue if (expression)` の形で条件を指定することができる。

```javascript
continue;
continue LABEL;
```

### break

ループを抜ける。正確にはループ・ブロックの直後に進む。

`break` はラベル指定が可能。`break LABEL` で `LABEL` の示すブロックの末尾に制御が進む。また、`break` は if 修飾が可能。`break if (expression)` の形で条件を指定することができる。

```javascript
break;
break LABEL;
```

### return

関数を抜ける。正確にはスタックをクリアし、復帰値を設定して呼び出し元の次の命令に進む。

`return` のみを指定した場合は暗黙的に `null` が返る。また、`return` は if 修飾が可能。`return expression if (expression)` の形で条件を指定することができる。

また、関数が Fiber として定義されていたた場合、一旦リターンすると次の呼び出しで `FiberException` 例外が発生する。実は catch してもう一回呼ぶと再度最初から実行できるが、この仕様で良いのかはわからない。

```javascript
return; // same as `return null;`
return expression;
```

### throw

例外を送出する。例外システムは貧弱だが実用できないわけではない。

例外オブジェクトは `type()` と `what()` というメソッドを持ち、型とメッセージを取得できる。がしかし型によって捕捉する例外を区別したりできない。キャッチしてから `type()` で確認する感じ。今のところ、`SystemException`、`FiberException`、`RuntimeException` というのがあるが、ユーザーが一般に投げられる例外は `RuntimeException`。

型によって区別できた方が良いのかな。個人的には例外はあくまで「例外」であって、エラー処理が適切にできれば良いのだが、ご意見ご要望をお待ちしております。

また、`throw` も if 修飾が可能。`throw expression if (expression)` の形で条件を指定することができる。

ちなみに catch 節の中では `throw` 単独での利用が可能。この場合、catch した例外オブジェクトをそのまま再送出する。

```javascript
throw;
throw expression;
```

### yield

Fiber で一旦ホスト側に処理を戻すために使用。値を返すことも可能。ホスト側から再度 `resume(args)` 返ってきた値 `args` を受け取ることも可能。その際、引数は配列の形でまとまってくるので、個別に受信したい場合はスプレッド（レスト）演算子を使って以下のように受け取る。

```javascript
[a, ...b] = yield;
```

上記の例では最初の引数を `a` で受け取り、残りの引数を配列として `b` が受け取る。また、`yield` も if 修飾が可能。`yield expression if (expression)` の形で条件を指定することができる。

通常は以下の形式。

```javascript
yield;
yield expression;
```

`Fiber#resume(args)` の復帰値を受け取る場合は以下の形式。

```javascript
var fiber = new Fiber(&{
    a = yield;                  // a = [10, 20, 30]
    [a1] = yield expression;    // a1 = 10
})
fiber.resume(); // first call.
fiber.resume(10, 20, 30);
fiber.resume(10, 20, 30);
```

尚、今後触れるつもりだが、`&{...}` はブロックを渡しているように見えて実際は `&() => {...}` と同じ意味。具体的には引数無しの無名関数オブジェクトを簡潔に表現できるようにしたもの。ブロックを渡しているように見えていいなと勝手に思ってこうしてみた。

### if-else

`if (expression) block else block` の形で使用。複数条件を連続させる場合は以下のようにぶら下がり構文を使用する。

```javascript
if (expression) {
    /* block */
} else if (expression) {
    /* block */
} else {
    /* block */
}
```

### while

`while` は条件判断をループの最初で行うループ構造を示す。以下が例だが詳細は難しくないため省略。

```javascript
while (expression) {
    /* block */
}
```

### do-while

`do-while` は条件判断をループの最後で行うループ構造を示す。従って、必ず 1 度はループ・ブロックが処理される。詳細は省略。

```javascript
do {
    /* block */
} while (expression);
```

### for

`for` は「初期化」「条件式」「更新部」（それぞれ何て言うんだ?）の 3 つのフィールドを持つ制御構造。初期化部では `var` を指定して `for` ブロックのスコープ内だけで有効な変数の宣言が可能。詳細は省略。

```javascript
for (initialize; condition; update) {
    /* block */
};
```

JavaScript には `for-in` というのがあり、サポートするか検討中。しなくていいかな（すぐには）。通常は `Array.each()` があるのでそれを使うのが良い。キー一式を取得する `keySet()` もある。

> `for-in` 構文をサポートしました。詳しくは [**こちら**](https://qiita.com/Kray-G/items/821eeba150a86d93766d) をご参照ください。

### switch-case

`switch-case` は悪名高いフォールスルーだ。だが、C プログラマとしてはフォールスルーじゃないと逆に変な感じでムズムズする。想像してみよう。`break` が無いと逆に **「次に行く感」** を感じてしまうところに根本原因があると思う。ここは馴染んだ道具に合わせてフォールスルーだ。ちゃんと `break` 書こうぜ。

ちなみに C 言語同様、`default` は最後に置かなくてもいいんだ。さらに数値以外も `case` に書ける。こんな感じ。

```javascript
var array = [1,2,3,4,5,6,7,8,9,10];
function switchTest(n) {
    switch (n) {
    case 1:     System.println(n); break;
    case 2:     System.println(n); break;
    case 3:     System.println(n); break;
    case 4:     System.println(n); break;
    case 5:     System.println(n); break;
    case 6:     System.println(n); break;
    case 7:     System.print(n, ", "); /* fall through */
    case 8:     System.println(n); break;
    case 100:   System.println(n); break;

    default:
        System.println("default");
        break;
    case array.length():
        System.println("array-length:%{n}");
        break;
    case "aaa":
        System.println(n);
        break;
    case "bbb":
        System.println(n);
        break;
    }
}
0.upto(100, function(i) {
    System.print("%{i} => ");
    switchTest(i);
});
```

尚、`native` では `switch-case` をサポートしていない。これはやればできるので、やってないだけ...（優先順位の関係で）。

ただ、今利用している汎用アセンブラみたいなライブラリだとジャンプテーブル化はできなさそう。x64 だけとかならできるんだが。

### try-catch-finally

`try-catch-finally` は例外を扱うための構文。以下のように使用する。だいたい分かってもらえそうなので、詳細は省略。尚、`catch (e)` の `(e)` は省略できない。最近の JavaScript では省略できるっぽいので、できるようにするか検討中。

```javascript
try {
    /* block */
} catch (e) {
    /* block */
} finally {
    /* block */
}
```

`native` でもサポートしたが、実際の例外オブジェクトを投げることができない制約がある（Type Mismatch とか Divide By Zero とかがスローされる可能性があるのでソレ用）のと、スタックトレースが保持されないという制約がある。これらは何とかなりそうな気もするので、今後の検討課題。

# おわりに

誰かが期待してくれるのかはさっぱり不明だが、ご意見・ご要望は随時募集中。色々考えよう。

今回も地道に★が増えるといいな、と宣伝。

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