Turbine: どんな言語?
Turbineは、以下のような特徴を持つ言語です。
- Markdownのような構文
- 静的型付け言語
- 組み込みデータ構造(
vec
、map
、set
、stack
、queue
) - 非オブジェクト指向
- C/C++との連携
なぜTurbineを作っているのか?
きっかけは、C/C++のプロジェクトでちょっとしたスクリプト機能がほしくなったことです。LuaやPythonは強力ですが、埋め込みのオーバーヘッドや学習コスト、構文の違和感を感じる場面もありました。
「もっと素直で読みやすく、埋め込みやすい言語があればいいのに」と思い、試しに作りはじめたのがTurbineです。
どんな文法?
Markdownから多数のアイデアやフィーリングの影響を受けています。 ただし、完全に目的の一致した文法ではありませんし、互換性があるわけではありません。 またブロック構造はインデントスタイルです。
Hello World
定番のHello world は次のようになります。
// "Hello, World"をコンソールに出力します。
# main(args vec{string}) int
print("Hello, World!")
return 0
-
main
はバーチャルマシンによって最初に呼び出される関数 - 関数定義は
# 関数名 (パラメータ名 型, ...) 戻り値型
-
C++スタイルコメント(
//
または/* ... */
) -
print()
は組み込み関数
変数定義
静的型付け言語なので、変数宣言とその型指定は必須です。ただし宣言と同時に初期値を与えると型指定は省略できます。(型推論)
# main(args vec{string}) int
- a int // int型の変数でデフォルト値はゼロ
- b = 42 // イニシャライザによるint型に推論
- c int = 77 // 型指定とイニシャライザ両方指定
print(a, b, c) // > 0 42 77
return 0
-
-
による宣言の開始 - 宣言できる変数は一行に1つ
- 初期値による型推論
- ブロックの任意の位置での宣言
プリミティブ型
基本的なデータ型はブール、整数、浮動小数点数、文字列です。
# main(args vec{string}) int
- b = false // ブール型
- i = 42 // 整数型
- f = 3.14 // 浮動小数点数
- s = "foo" // 文字列型
print(b, i, f, s) // > false 42 3.14 foo
return 0
- ブール型のリテラルは
true
かfalse
のみ - 整数は
0xFF
でも指定可能 - 浮動小数点数は
1e+4
も可能 - 文字列はダブルクオーテーションで囲む
コレクション型
コレクション型はC++のようにvec
、map
、set
、stack
、queue
が組み込み型として使えます。 コレクションの操作は組み込み関数を使います。len()
で全てのコレクションを扱うより明示性を優先しているので、関数名はvecやstackで始まります。
# main(args vec{string}) int
- v = vec{11, 22, 33} // 整数のベクタ
- m = map{"foo":42, "bar":99} // 文字列 => 整数のマップ
- s = set{212.09, 584.23, 927.32} // 浮動小数点数のセット
- k = stack{int} // 整数のスタック
- q = queue{string} // 文字列のキュー
print(v) // > {11, 22, 33}
print(m) // > {foo:42, bar:99}
print(s) // > {foo:42, bar:99}
print(k) // > {}
print(q) // > {}
return 0
- 型は
コレクション型名{要素の型}
-
main
関数の引数の型はvec{string}
- リテラルは
コレクション型名{要素, ...}
-
veclen()
やstrlen()
、stackpush()
など組み込み関数
構造体型
構造体は他の言語のように複数の変数をフィールドしてまとめて扱うためのデータ構造です。アクセス制限、メンバー関数はサポートしません。
## Point struct
- x float
- y float
# main(args vec{string}) int
- p = Point{x=11.1, y=22.2} // Point構造体
print(p) // > {11.1, 22.2}
return 0
-
## 構造体名 struct
で定義 - フィールドにアクセスする
.
演算子 - 構造体リテラルは
構造体名{フィールド=イニシャライザ, ...}
列挙体型
列挙体は定数に名前をつけること以外に、そのシンボルに任意のデータ型の定数を複数割り当てることができます。本質的には構造体変数の定数配列に似ていますが、フィールド(カラム)を最初の一行だけ書く、定数としてバイトコードに埋め込まれるなどの特徴があります。
## Month enum
: symbol , name , num
- Jan , "January" , 1
- Feb , "February" , 2
- Mar , "March" , 3
- Apr , "April" , 4
- May , "May" , 5
- Jun , "June" , 6
- Jul , "July" , 7
- Aug , "August" , 8
- Sep , "September" , 9
- Oct , "October" , 10
- Nov , "November" , 11
- Dec , "December" , 12
# main(args vec{string}) int
- m = Month.Oct // Month enum
print(m.symbol) // > Oct
print(m.name) // > October
print(m.num) // > 10
return 0
-
## 列挙体名 enum
で定義 -
:
でヘッダー行(フィールド名カラム)を指定 -
-
でそれぞれの列挙名を指定(列挙名ロー) -
列挙体名.シンボル
、もしくは列挙体型変数.フィールド名
でアクセス
モジュール
組み込みモジュールのほか、ユーザーが書いたmy_module.tu
ファイルもモジュールとなります。
> math
# main(args vec{string}) int
print(math._PI_) // > 3.14159
print(math.sqrt(25)) // > 5
return 0
-
>
でモジュール内のシンボルをインポート -
モジュール名.シンボル
でアクセス -
math
、file
、time
などの組み込みモジュール
リンク
現在は開発中で、仕様や文法を少しずつ固めています。
詳細や開発ログは以下で公開しています:
👉 GitHub
👉 ドキュメント(英語)
👉 Turbine 言語紹介(英語)(dev.to)
興味のある方へ
- 新しい言語の設計に興味がある方
- C/C++と相性の良い小さなスクリプト言語を探している方
- Markdown風の軽量な構文に興味がある方
ぜひコメントやフィードバックをいただけると嬉しいです!
今後も開発進捗や実装例などを投稿していく予定です。