「これからXtalを触ってみたいけどどんな言語なのかさっぱりわからんちん」みたいな人を対象としています。細部にこだわらず、「とりあえず使える気がする」ぐらいまでもっていくのを目指したものです。Xtal触ろうと思う人ならC++多少は知ってるよね、みたいな部分が有るかもしれないし無いかもしれない……
公式のクイックチュートリアルを多分に参考にしています。
.pとつけることで「良い感じに」出力できます。
出力したくなったら気にせずに.pとつけます。
// 文字列だって "Hello World".p; // 数字だって 100.p;
C++と同じコメント記法が使えます。
// 実行されない /* ここも 実行されない */
変数は”:“で定義し、”=“で代入します。
// 定義 foo : 100; bar : 200; // 使用 (foo + bar).p; // 代入 foo = 10.0; bar = 20.0; (foo + bar).p;
constは言語仕様に存在しません。
また、enumも言語仕様に存在していません。
しかし、言語仕様的に存在していないだけで「定数としてみなすことはできる」程度の書き方はあります。
singleton ConstTable{ Value1 : 1; Value2 : 2; Value3 : 3; }
このように書くと、再定義・代入が禁止されているために実質定数とみなすことができます。
「C++で関数とよばれるもの」はXtalでは”fun”と呼ばれます。
int,float,boolは値渡しで、残りは全て参照渡しとなります。
fun square(x){ return x * x; } fun add(x, y){ return x + y; } square(2.5).p; add(2.5, square(2.5)).p;
中断可能な関数です。中断したのちに再度呼び出すと再開されます。
yieldで中断することができ、そのとき戻り値を返すことができます。
returnは終了を表し、そのときのreturn文の値は戻り値とはなりません。
fib : fiber(){ "first call".p; yield 0; "second call".p; yield 1; "last call".p; return 2; } fib().p; fib().p; fib().p;
カンマで区切られた複数の値のことです。関数から複数の値を返すときなどに役に立ちます
// 多値は複数の変数で受ける a, b, c : 1, "foo", null; fun multiReturn(x, y){ return x+x, x-x, x*x, x/x; } add, sub, mul, div : multiReturn(12.0, 3.5); // 多値そのものとして扱うこともできる multiReturn(12.0, 3.5).p;
Xtalには基本的なデータ型が用意されています。
スクリプトの中で数値リテラルを使うときはこの型のどちらかになります。 お互いは .to_i, .to_f で変換することができます。
i : 10; // 整数型 f : 10.5; // 浮動小数点数型 i2 : f.to_i // 整数型(10) f2 : i.to_f // 浮動小数点数型(10.0)
true/falseです。
t : true; // 真 b1 : 10 == 20; b2 : 10 == 10; b1.p; b2.p;
” ” で囲まれた部分は文字列型と認識されます。他の型からto_sによって変換することもできます。
str : "This is string"; str2 : 200.to_s; str.p; str2.p;
[]で囲まれたリストは配列になります。
ary : []; // 空配列 ary2 : [1, 2, 3, 4, 5]; ary2[0].p; // インデックスは0から始まる ary2[0] = 0; // 代入もできる ary2.p;
[:]で連想配列を作ることができます。連想配列とは、キーと値のペアの集合です。配列のインデックスになんでも入れられるようになったものと考えることができます。
map : [:]; // 空連想配列 // []のなかにはどんなものでも入れることができます map[0] = "foo"; map["bar"] = 10; // 取り出す map["bar"].p; map[0].p; // まとめて初期化することもできます map2 : ["hoge": 0, "fuga": 2]; map2.p;
C/C++的なfor, while の他に、Ruby的なブロック構文を使うことができます。
for (i : 0; i < 10; ++i){ i.p; } count : 0; while (count < 10){ count.p; ++count; } // ブロック構文 // 配列に順番にアクセスできる array : [1, 2, 3, 5, 8, 13]; array{ // "it"という変数が勝手に定義されて使えるようになる it.p; // 代入もできる it = it*2; }
if/else, switch, 三項演算子を使って条件分岐を書くことができます。
Xtalにおいては、偽として扱われるのはfalse,undefined,nullだけです。Int(0)も真として扱われます。
// if, else if, else はC++式 x : 10; if (x == 0) { "zero".p; } else if ((x % 2) == 0){ "even".p; } else { "odd".p; } // switch-caseはC++と比べて少し特殊 y : 3; z : ""; switch (y){ case (0){ z = "zero"; } case (1){ z = "one"; } case (2){ z = "two"; } default { z = "bigger than two"; } } z.p; // 三項演算子 w : (10 >= 0)? "positive or zero": "negative"; w.p;
あらかじめ用意されているクラスのほか、自分でクラスを定義することもできます。
ClassName(); とすることでインスタンスを作ることができます。
// クラスを定義 class Foo{ _bar; // メンバ変数は最初に"_"をつける + _hoge; // 最初に+をつけることで外から***.hogeみたいにアクセスできるようにする // クラスインスタンス生成時に呼び出される // Foo(10); と生成されたときはbar=10となる initialize(bar){ _bar = bar; } // メソッド(メンバ関数) print(){ _bar.p; _hoge.p; } } // C++と違って最後に";"がいりません // クラスを使う foo : Foo("bar!"); foo.hoge = "hoge?"; foo.print();
global:: をつけることでグローバル変数やグローバル関数を定義、アクセスすることができます。
global::var : "this is global variable"; fun global::function(){ "global function called".p; global::var.p; } global::function(); global::var : "this is changed global variable"; global::function();
グローバル変数と言っても、代入不可能なので、値を変更する際には再定義することになります。
まあそもそもグローバル変数なんて使ってんなぁ! ということで一つ。