© 2020 arata-nvm.
Visket は静的型付けのコンパイラ言語です。
Visket Playground でサンプルコードが編集、実行できるようになっています。
言語の開発は GitHub 上でオープンに行われています。詳細についてはリポジトリを参照してください。
Visket には以下の基本型が存在します。型のサイズはプラットフォームに依存せず、常に一定です。
- bool
- int
- float
- string
- array
ブーリアン型です。以下の 2 値のみをとります。
false
true
符号あり 32 ビットの整数型です。
-2,147,483,648
~ 2,147,483,647
の値を表現できます。
42
-473982
単精度浮動小数点数です。
3.14
2.178
文字列型です。エスケープシーケンスとして以下が使用できます。
'\a' '\b' '\f' '\n' '\r' '\t' '\v' '\"' '\\'
"Hello World!"
"\r\n"
配列型です。この型は要素数と要素の型から構成され、要素数が異なる配列は異なる型と判断されます。
異なる型の値を同じ配列に格納することはできません。また、初期化節は未実装であるため使用できません。
[3]string
// 以下は異なる型
[4]int
[2]int
以下のキーワードは予約されているため、名前に使用できません。
fun struct module import
include var return if else
while for in new ref val
グローバル変数とローカル変数が使用できます。関数の外で宣言した場合にはグローバル変数として、関数の中で宣言した場合にはローカル変数として扱われます。
初期値を指定しなかった場合にもデフォルトでゼロ初期化が行われます。
変数の宣言は以下のように行います。
// 変数"i"をint型で宣言する
// 同時に0で初期化が行われる
var i: int
// 変数"i"をint型で宣言、10で初期化する
var i: int = 10
// 初期値を指定する場合は型名を省略できる
var i = 10
var
の代わりにval
を使用することで定数として宣言できます。
// ok
var i = 10
i = 0
// ng
val i = 10
i = 0
import
文を使用することで一部の処理を他のファイルに記述できます。
import
文の対象として指定できるのはファイルのみで、モジュール単位・関数単位でのインポートはできません。
// カレントディレクトリの"std.sl"をインポートする
import "std"
関数は以下の構文によって宣言できます。
オーバーロードが未実装であるため同じ名前の関数は同時に宣言できません。同じ名前の関数を使用したい場合にはモジュールについての説明を参照してください。
// 何もしない関数
fun i_am_a_neet() {
}
// int型を2つ引数にとりint型の値を返す関数"add"を宣言する
fun add(a: int, b: int): int {
return a + b
}
// 引数で同じ型が続く場合は省略できる
fun add(a, b: int): int {
return a + b
}
デフォルトでは値渡しが用いられますが、キーワードref
を使用することで参照渡しが可能です。
// 値渡し
fun clear(i: int) {
i = 0
}
fun main() {
var i = 1
clear(i)
i // 1
}
// 参照渡し
fun clear(ref i: int) {
i = 0
}
fun main() {
var i = 1
clear(i)
i // 0
}
構造体は以下の構文によって宣言できます。
// "Name", "Sex", "Age"をメンバに持つ構造体"Person"を宣言する
struct Person {
Name: string
Sex: string
Age: int
}
宣言した構造体は基本型と同じように扱うことができ、メンバへのアクセスは.
演算子によって行います。基本的な操作を以下に示します。
// インスタンスの作成
var person: Person
// メンバへの代入
person.Name = "John"
// メンバの参照
person.Name
fun greet(person: Person) {
println(person.Name)
}
また、構造体はメンバ関数を持つことができませんが、後に説明する UFCS を使用することで擬似的なメンバ関数を宣言できます。
関数の宣言は原則としてトップレベルの名前空間で行われるため、関数名が衝突するする場合があります。そのような場合にモジュールを使用できます。
ファイル単位で自動的にモジュールが設定されることはなく、モジュールの使用には明示的な宣言が必要となります。
モジュールのネストはできません。
構文は以下の通りです。
// 関数"abs", "cos"を持つモジュール"Math"を宣言する
module Math {
fun abs(x: int): int {
// (略)
}
fun cos(x: float): float {
// (略)
}
}
モジュール内の関数を呼び出す際は::
演算子を使用します。
Math::abs(10) //10
Math::abs(-35) // 35
条件式を評価しその結果によって分岐します。条件式は bool 型の値を返すものである必要があります。 括弧は必要ありません。
var i = 1
if i > 0 {
i = 0
} else if i == 0 {
i = 1
} else {
i = 2
}
i // 0
条件が満たされている間処理を繰り返し実行します。
// 0から9まで10回ループする
var i = 0
while i < 10 {
i += 1
}
C 言語や Java などで使用される古典的な for 文が使用できます。
// 0から9まで10回ループする
for var i = 0; i < 10; i += 1 {
}
// 7h15 15 4 br0w53r cr45h3r
for ;; {}
また、 int 型のループについては Ruby-like の構文が使用できます。
// 0から9まで10回ループする
for i in 0..9 {
}
Visket では以下の算術演算をサポートしています。
- +: 加算
- -: 減算
- *: 乗算
- /: 除算
- %: 剰余
Visket では以下の論理演算をサポートしています。
- ==: 等しい
- !=: 等しくない
- < : より小さい
- <=: 以下
- > : より大きい
- >=: 以上
これらの演算は常にfalse
かtrue
の値を返します。
関数の呼び出しより前に関数を宣言する必要はありません。呼び出しより後に関数が宣言される場合にも問題なく呼び出しを行うことができます。
fun main() {
do_nothing() // ok
}
fun do_nothing() {}
UFCS による関数呼び出しに対応しています。
fun add(a, b: int): int {
return a + b
}
// 呼び出し例
1.add(1) // 2
var i = 10
i.add(5) // 15
この仕組みは関数の呼び出しがネストするときや、擬似的なメンバ関数を宣言したいときに活用できます。
fun add(a, b: int): int {
return a + b
}
// 以下は同じ意味を持つ
add(add(i, 2), 3)
i.add(2).add(3)