制御フロー
point/warpto文
WapLで最も基本となる制御フローはpoint/warpto文です。これは多くの言語でのgoto文に近い概念で非常に自由度の高い処理が書けます。pointでラベルをつけてブロックを作り、warptoでそこまでジャンプします。warptoは
fn main():i32{
warpto(skip);
point skipped;
println("この行は飛ばされるよ");
warpto(skip);
point skip;
println("skipに飛んだよ");
return 0s;
}
skipに飛んだよ
これではskippedとskipというラベルでブロックを作り、warpto(skip)でskipに飛びます。すべてのブロックがreturnかwarpto/warptoifのどれかで終わる必要があります。
warptoif文
warptoifはwarptoに条件を付けて真のときと偽のときで飛ぶ先を選択するものでwarptoif(条件, 真のとき, 偽のとき)となります。
fn main():i32{
#=(cond, true, bool);
warptoif(cond, then, else);
point then;
println("then");
warpto(end);
point else;
println("else");
warpto(end);
point end;
return 0s;
}
このようにして条件分岐を作ることもできますし、後述するloopifも内部ではpoint/warpto/warptoifと同じようなことがされています。
loopif文
loopifは他の多くの言語で存在するwhileのようなもので、名前を付けたりwarpto/warptoifにも対応しています。
fn main():i32{
#=(i,0,i64);
loopif:(<(i,10)){
println(format("%d",i))
=(i,+(i,1));
}
=(i,0)
loopif:LOOP1(<(i,10)){
println(format("LOOP1:%d",i))
=(i,+(i,1));
warptoif(<(i,5),continue-LOOP1,break-LOOP1);
}
return 0s
}
0
1
2
3
4
5
6
7
8
9
LOOP1:0
LOOP1:1
LOOP1:2
LOOP1:3
LOOP1:4
このようにloopifは名前ありでも名前なしでも作ることができ、ループを抜けたいときはbreak-名前に飛ぶことで抜けることができ、以下の処理をせずに条件の評価に戻りたいときはcontinue-名前に飛ぶことでできる。
if文(0.1.13以降)
多くの言語で見られるif文。言語によってはif文とif式は同じ文法で記述できるものもありますが、WapLでは異なるキーワードを使っています。
if文は以下のように使うことができます
fn main():i32{
if (true){
println("True");
}
if (false){
println("False");
}
return 0s;
}
True
このようにifのあとの()の中にbool型で条件を書き、trueのときには{}の中の処理が実行されます。
elifとelse
if文で前の条件がfalseであるときにfalse側でも処理をしたいときに毎回ifで前の条件がfalseであるときを指定するのはめんどくさいです。そこで使えるのがelifとelseです。
fn main():i32{
#=(x, 7, i64);
if (>(x, 10)){
println(format("%lld > 10",x));
}elif (>(x, 5)){
println(format("5 < %lld <= 10",x));
}else{
println(format("%lld <= 5",x));
}
return 0s;
}
5 < 7 <= 10
このように前の条件がfalseであることを前提にして条件を書いたり、その他の場合を記述できます。
?演算子
これはif式に相当する演算子です。中には文は書けないのでもし文を書きたい場合は関数を作ってその関数を呼ぶようにしてください。
fn main():i32{
#=(x, ?(false,10,5), i64);
println(format("x = %lld", x));
return 0s;
}
x = 5
このように第1引数に条件を書き、続けてtrueのときの値、falseのときの値を書きます。このとき値の型は一致していてさらにvoidであってはいけません。
fn Hello(){
println("Hello");
}
fn Bye(){
println("Bye");
}
fn main():i32{
?(true,Hello(),Bye());
return 0s;
}
src/main.ll:56:1: error: expected instruction opcode
56 | if.merge: ; No predecessors!
| ^
1 error generated.
このようにvoidの場合エラーが出ます。これを回避するためには以下のようにして意味がなくとも戻り値を持たせる必要があります。
fn Hello():i32{
println("Hello");
return 0s;
}
fn Bye():i32{
println("Bye");
return 0s;
}
fn main():i32{
?(true,Hello(),Bye());
return 0s;
}
Hello
choose
?演算と似たようなものとしてchooseがあります。違いとしては?は片方しか評価しない一方chooseは両方を評価してから条件に合う値を返します。先ほどのHelloとByeの?をchooseに書き変えて試してみましょう。
fn Hello():i32{
println("Hello");
return 0s;
}
fn Bye():i32{
println("Bye");
return 0s;
}
fn main():i32{
choose(true,Hello(),Bye());
return 0s;
}
Hello
Bye
このようにHello/Byeともに実行されたことが確認できます。