= 制御構造
* MK SCriptの制御構造は、条件分岐、繰り返し、ノードオブジェクト(旧名パラメータ付きノード)の3種類が存在します。
* さらに、繰り返しは前置条件型と後置条件型の2つから成り立ちます。
== 条件分岐
* 条件式として記載された内容が真の場合、内部ブロックの処理を実行し、条件分岐構造全体の評価を終了します。
* 条件式が偽の場合、次の条件式の評価に移ります。
* すべての条件式が偽の場合、else 節が存在すれば、else節内部ブロックの処理を実行し、条件分岐構造全体の評価を終了します。
* else節が存在しない場合は、その時点で条件分岐構造全体の評価を終了します。
* 表記法
{{{
if <条件式> then
内部ブロック
[
elseif <条件式> then
内部ブロック
]* # 0 回以上記載
[
else
内部ブロック
]? # 0もしくは1回記載
end
}}}
* 例
{{{
if x == 10 then
Console << "x == " << x << "\n"
elseif x < 10 then
Console << "x < " << 10 << "\n"
else
Console << "x > " << 10 << "\n"
end
}}}
== 後置条件句
* 右辺の条件式が真の時のみ左辺の式を実行します。
* 左辺には、単一式のみ記載することが可能です。
* 左辺式の実行結果を取得することはできません(return節で呼び出し元に値を返す場合を除く)
{{{
Console.println( "error" ) if x < 0
return -1 if x < 0
raise MyException.new() if x < 0
break if x > 5
continue if x % 2 == 0
}}}
== 繰り返し
* 繰り返しは、条件式が真の間、内部ブロックが繰り返し実行されます。
* 前置条件型は、最初に条件評価を行い、条件式が真であった場合のみ、内部ブロックを実行します。
* 後置条件型は、内部ブロックを一度実行したのち、最初の条件式評価を行います。
* 繰り返しの内部ブロック内では、break、continue を記述することができます。
* breakは、最も内側の繰り返し内部ブロックから脱出します。
* continueは、最も内側の繰り返し構造の先頭にジャンプします。前置条件型の場合、条件式を再評価します。
* 表記法
{{{
# 前置条件型
while <条件式>
内部ブロック
end
# 後置条件型
do
内部ブロック
end while 条件式
}}}
* 例
{{{
# 前置条件型
while x != 10
x = x + 1
end
while x != 10
if x == 5 then
break # breakで繰り返し内部ブロックを抜ける
end
x = x + 1
end
while x != 10
x = x + 1
if x == 5 then
continue # continueで、繰り返し構造の先頭(条件評価)から処理をやり直します。
end
y = y + 1
end
# 後置条件型
do
x = x + 1
end while x != 10
}}}
{{{
do
x = x + 1
if x == 5 then
continue # continueで、繰り返し構造の先頭(内部ブロックの先頭)から処理をやり直します。
end
y = y + 1
end while x != 10
}}}
== ノードオブジェクト
* ノードオブジェクトは、制御構造を抽象化したオブジェクトです。
* ノードオブジェクトを使用すると、メソッド、ブロック構造、式をオブジェクトとして保持し、後で必要なときに呼び出すことができるようになります。
* ノードオブジェクトは、内部定義クラス Node にカプセル化されます。
=== メソッドのオブジェクト化
* メソッドをオブジェクト化するには、メソッド名を変数に代入します。
* インスタンスメソッドの場合には、右辺のメソッド名に[@]を付加します。
* クラスメソッドの場合には、右辺のメソッド名に[@@]を付加します。
{{{
def method1( )
end
x = @method1
def class.method2( )
end
x = @@method2
}}}
* 別オブジェクトのインスタンスメソッドや、クラスメソッドをオブジェクト化するには、対象オブジェクトを . 左辺に記載します。
{{{
class C0
def class.method()
end
def instance_method( )
end
end
p = C0.new()
x = p.@instance_method
y = C0.@@method
}}}
* オブジェクト化されたメソッドを呼び出すには、ノードオブジェクトに定義されている invoke メソッドを呼び出すか、メソッドオブジェクトに直接パラメータを渡します。
{{{
def method( )
end
x = @method
x.invoke( ) # method( ) の呼び出し
x( ) # これも method の呼び出し
def method_2( a, b, c )
return a + b + c
end
x = @method_2
Console << x.invoke( 1, 2, 3 ) << "\n" # method_2( 1, 2, 3 )の呼び出し
Console << x( 1, 2, 3 ) << "\n" # これもmethod_2( 1, 2, 3 )の呼び出し
}}}
=== ブロックのオブジェクト化
* ブロックのオブジェクト化は無名関数と似ています。
* 違いは、ブロックが宣言されたスコープのローカル変数へのアクセスが可能なことです。
* return を使用して、値を返すことも可能です。
* ブロックオブジェクトは、block ... end で囲まれたブロック構造を変数に代入することで宣言します。
{{{
x = block
if mode = 1 then
return method_1( )
elseif mode == 2 then
return method_2( )
end
end
}}}
* ブロックオブジェクト呼び出し時にパラメータを渡すことも可能です。
* パラメータ付きでブロックオブジェクトを宣言するには、| param1, param2 ... | block ... end のように、| | で括りブロック定義前にパラメータリストを定義します。
{{{
y = |a, b, c| block
if mode = 1 then
Console << a
elseif mode == 2 then
Console << b
else
Console << c
end
end
}}}
* ブロックは、宣言されたスコープとローカル変数を共有します。
* ブロック内で初めて参照された変数のスコープは、ブロック内部のみとなります。
* パラメータとして渡された変数のスコープは、ブロック内部のみとなります。
* 宣言スコープ内のパラメータ名と同名変数を参照するために owner. を使用することができます。
* 上記以外の変数は宣言されたスコープの変数参照となります。
{{{
c = 10
y = |a,b| block
return a + b + c
end
z = |a,b,c| block
return a + b + c + owner.c
end
}}}
* 呼び出しは、メソッドオブジェクトと同様に行えます。
{{{
x = block
if mode = 1 then
method_1( )
elseif mode == 2 then
method_2( )
end
end
x( ) # x に代入されたブロックを呼び出す
x.invoke( )
y = |a, b, c| block
if mode = 1 then
Console << a
elseif mode == 2 then
Console << b
else
Console << c
end
end
y( 1, 2, 3 ) # ブロック引数として、1, 2, 3 を渡し、ブロックを呼び出す。
y.invoke( 1, 2, 3 )
}}}
* 宣言と同時に呼び出すことも可能です。ただしこの場合、invokeを明示的に記載します。
{{{
|a, b, c| block
if mode = 1 then
Console << a
elseif mode == 2 then
Console << b
else
Console << c
end.invoke( 1, 2, 3 )
}}}
* ブロック内での returnは、呼び出されたブロックから抜けるだけです。呼び出し元メソッドから抜けることはありません。
* break, continue はブロック呼び出しをまたぐことはできません。
=== エクスプレッション(式)オブジェクト
* 式オブジェクトは、評価式を{ } で括る事で宣言します。
* パラメータ付きで式オブジェクトを宣言するには、| param1, param2 ... | block ... end のように、| | で括り式定義前にパラメータリストを定義します。
{{{
a = 1
b = 2
x = { a + b + c }
y = | a, b | { a + b + owner.a + owner.b }
}}}
* 呼び出しは、メソッドオブジェクト、ブロックオブジェクトと同様に行えます。
{{{
a = 1
b = 2
x = { a + b + c }
y = | a, b | { a + b + owner.a + owner.b }
x()
y(3,4)
}}}