文書の出典
- 出典
- Lua 5.5.1 Documentation
- 上流バージョン
- Lua 5.5.1
- 文書状態
- 翻訳
3.3 – 文
Luaは、他の一般的な言語と同様の、ほぼ従来どおりの文の集合をサポートする。この集合には、ブロック、代入、制御構造、関数呼び出し、変数宣言が含まれる。
3.3.1 – ブロック
ブロックは、順番に実行される文のリストである。
block ::= {stat}Luaには空文があり、文をセミコロンで区切る、ブロックをセミコロンで始める、または2つのセミコロンを連続して記述できる。
stat ::= ‘;’関数呼び出しと代入はいずれも開き括弧から始められる。この可能性により、Luaの文法には曖昧さが生じる。次の断片を考える。
a = b + c
(print or io.write)('done')文法上、この断片は次の2通りに解釈できる。
a = b + c(print or io.write)('done')
a = b + c; (print or io.write)('done')現在のパーサーは、このような構造を常に最初の方法で解釈し、開き括弧を呼び出しの引数の開始とみなす。この曖昧さを避けるため、括弧から始まる文の前には常にセミコロンを置くのがよい慣行である。
;(print or io.write)('done')ブロックを明示的に区切って、単一の文にできる。
stat ::= do block end明示的なブロックは、変数宣言のスコープを制御するのに役立つ。また、別のブロックの途中にreturn文を追加するために使われる場合もある(§3.3.4を参照)。
3.3.2 – チャンク
Luaのコンパイル単位はチャンクと呼ばれる。構文上、チャンクは単なるブロックである。
chunk ::= blockLuaはチャンクを可変個の引数を持つ無名関数の本体として扱う(§3.4.11を参照)。そのため、チャンクはローカル変数を定義し、引数を受け取り、値を返すことができる。さらに、この無名関数は_ENVという外部ローカル変数のスコープ内でコンパイルされる(§2.2を参照)。生成される関数は、その変数を使用しない場合でも、唯一の外部変数として常に_ENVを持つ。
チャンクは、ファイルまたはホストプログラム内の文字列へ格納できる。チャンクを実行するため、Luaは最初にチャンクを読み込み、そのコードを仮想マシン用の命令へプリコンパイルする。その後、仮想マシンのインタープリターでコンパイル済みコードを実行する。
チャンクはバイナリー形式へプリコンパイルすることもできる。詳細はプログラムluacと関数string.dumpを参照すること。ソース形式とコンパイル済み形式のプログラムは交換可能であり、Luaはファイル形式を自動的に検出して適切に動作する(loadを参照)。ソースコードとは異なり、悪意をもって細工されたバイナリーチャンクはインタープリターをクラッシュさせる可能性があることに注意すること。
3.3.3 – 代入
Luaは多重代入を許可する。そのため、代入の構文では、左辺に変数のリスト、右辺に式のリストを定義する。両方のリストの要素はコンマで区切る。
stat ::= varlist ‘=’ explist
varlist ::= var {‘,’ var}
explist ::= exp {‘,’ exp}式については§3.4で説明する。
代入の前に、値のリストは変数のリストの長さへ調整される(§3.4.12を参照)。
多重代入内で同じ変数への代入と読み取りが行われる場合、Luaはすべての読み取りが代入前の変数値を取得することを保証する。したがって、次のコードは
i = 3
i, a[i] = i+1, 20a[4]へ影響を与えずにa[3]を20へ設定する。これは、a[i]内のiが4を代入される前に(3として)評価されるためである。同様に、次の行は
x, y = y, xxとyの値を交換し、次の行は
x, y, z = y, z, xx、y、zの値を循環的に並べ替える。
この保証は、代入文の構文内にあるアクセスだけを対象とすることに注意すること。代入中に呼び出された関数またはメタメソッドが変数の値を変更する場合、Luaはそのアクセス順序について何も保証しない。
グローバル名への代入x = valは、代入_ENV.x = valと等価である(§2.2を参照)。
テーブルフィールドとグローバル変数(実際にはこれもテーブルフィールド)への代入の意味は、メタテーブルを介して変更できる(§2.4を参照)。
3.3.4 – 制御構造
制御構造if、while、repeatは、通常の意味と馴染みのある構文を持つ。
stat ::= while exp do block end
stat ::= repeat block until exp
stat ::= if exp then block {elseif exp then block} [else block] endLuaには2つの形式のfor文もある(§3.3.5を参照)。
制御構造の条件式は、任意の値を返せる。falseとnilはいずれも偽と判定される。nilおよびfalse以外の値はすべて真と判定される。特に、数値0と空文字列も真と判定される。
repeat–untilループでは、内側のブロックはuntilキーワードで終了せず、条件の後で初めて終了する。そのため、条件はループブロック内で宣言されたローカル変数を参照できる。
goto文は、プログラムの制御をラベルへ移す。構文上の理由により、Luaではラベルも文とみなされる。
stat ::= goto Name
stat ::= label
label ::= ‘::’ Name ‘::’ラベルは、ネストした関数内を除き、そのラベルが定義されたブロック全体から見える。gotoは、変数宣言のスコープ内へ入らない限り、見える任意のラベルへジャンプできる。同名の先行ラベルが見える場所では、その別のラベルが外側のブロックで宣言されている場合でも、ラベルを宣言するべきではない。
break文は、while、repeat、forループの実行を終了し、ループ直後の文へ移る。
stat ::= breakbreakは、それを囲む最も内側のループを終了する。
return文は、関数またはチャンク(無名関数として扱われる)から値を返すために使用する。関数は複数の値を返せるため、return文の構文は次のようになる。
stat ::= return [explist] [‘;’]return文は、ブロックの最後の文としてだけ記述できる。ブロックの途中でreturnする必要がある場合は、do return endというイディオムのように、明示的な内側のブロックを使用できる。これにより、returnはその(内側の)ブロックの最後の文となる。
3.3.5 – for文
for文には、数値形式と汎用形式の2つがある。
数値forループ
数値forループは、制御変数が等差数列をたどる間、コードのブロックを繰り返す。構文は次のとおりである。
stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end指定された識別子(Name)は、ループ本体(block)のローカルにある、新しい読み取り専用(const)変数である制御変数を定義する。
ループは、3つの制御式をそれぞれ1回評価することで開始する。その値は順に初期値、制限値、ステップと呼ばれる。ステップを省略した場合、デフォルト値は1となる。
初期値とステップが両方とも整数の場合、ループは整数で実行される。制限値は整数でなくてもよいことに注意すること。それ以外の場合、3つの値は浮動小数点数へ変換され、ループも浮動小数点数で実行される。この場合は浮動小数点数の精度に注意すること。
この初期化の後、制御変数の値が、初期値から始まりステップを公差とする等差数列をたどる間、ループ本体が繰り返される。負のステップは減少数列を作り、ステップが0の場合はエラーが発生する。値が制限値以下(負のステップでは制限値以上)の間、ループは続く。初期値がすでに制限値より大きい場合(ステップが負なら小さい場合)、本体は実行されない。
整数ループでは、制御変数がラップアラウンドすることはない。代わりに、オーバーフローが発生するとループが終了する。
汎用forループ
汎用for文は、イテレーターと呼ばれる関数に対して動作する。各反復でイテレーター関数が呼び出されて新しい値を生成し、その新しい値がnilになると停止する。汎用forループの構文は次のとおりである。
stat ::= for namelist in explist do block end
namelist ::= Name {‘,’ Name}次のようなfor文は
for var_1, ···, var_n in explist do body end次のように動作する。
名前var_iは、ループ本体のローカルにあるループ変数を宣言する。これらの変数のうち最初のものが制御変数であり、読み取り専用(const)変数となる。
ループは、explistを評価して4つの値、すなわちイテレーター関数、状態、制御変数の初期値、クローズ値を生成することで開始する。
その後、各反復でLuaは状態と制御変数という2つの引数を指定してイテレーター関数を呼び出す。この呼び出しの結果は、多重代入の規則(§3.3.3を参照)に従ってループ変数へ代入される。制御変数がnilになるとループが終了する。それ以外の場合、本体が実行され、ループは次の反復へ進む。
クローズ値はクローズ対象変数のように動作し(§3.3.8を参照)、ループ終了時にリソースを解放するために使用できる。それ以外の点では、ループへ干渉しない。
3.3.6 – 文としての関数呼び出し
起こり得る副作用を許可するため、関数呼び出しは文として実行できる。
stat ::= functioncallこの場合、返されたすべての値は破棄される。関数呼び出しについては§3.4.10で説明する。
3.3.7 – 変数宣言
ローカル変数とグローバル変数は、ブロック内の任意の場所で宣言できる。宣言には初期化を含められる。
stat ::= local attnamelist [‘=’ explist]
stat ::= global attnamelist [‘=’ explist]初期化がない場合、ローカル変数はnilで初期化され、グローバル変数は変更されない。それ以外の場合、初期化には多重代入と同じ調整が行われる(§3.3.3を参照)。さらに、グローバル変数では、変数がすでに定義されている、すなわちnilでない値を持つ場合、初期化によって実行時エラーが発生する。
名前のリストの前に属性(山括弧で囲んだ名前)を置くことができ、各変数名の後ろにも属性を置ける。
attnamelist ::= [attrib] Name [attrib] {‘,’ Name [attrib]}
attrib ::= ‘<’ Name ‘>’前置属性はリスト内のすべての名前へ適用され、後置属性はその特定の名前へ適用される。指定できる属性は2つある。constは定数または読み取り専用変数、すなわち代入の左辺に使用できない変数を宣言し、closeはクローズ対象変数を宣言する(§3.3.8を参照)。close属性を持てるのはローカル変数だけである。変数のリストに含められるクローズ対象変数は最大1つである。
Luaは、グローバル変数の一括宣言も提供する。
stat ::= global [attrib] ‘*’この特殊形式は、それ以前に明示的に宣言されていないすべての名前を、暗黙にグローバルとして宣言する。特に、global<const> *は、それ以前に明示的に宣言されていないすべての名前を、読み取り専用グローバルとして暗黙に宣言する。次の例を参照すること。
global X
global<const> *
print(math.pi) -- Ok, 'print' and 'math' are read-only
X = 1 -- Ok, declared as read-write
Y = 1 -- Error, Y is read-only§2.2で述べたように、すべてのチャンクは暗黙の宣言global *で始まるが、この冒頭の宣言は、他のglobal宣言のスコープ内では無効となる。したがって、グローバル宣言を使用せずglobal *でも始まらないプログラムは、任意のグローバルへ自由に読み書きできる。global<const> *で始まるプログラムは、任意のグローバルを自由に読み取れる。その他のグローバル宣言(例:global none)で始まるプログラムは、宣言済み変数だけを参照できる。
グローバル変数では、どの宣言の効果も、省略可能な代入を除いて構文上のものだけであることに注意すること。
global X <const>, _G
X = 1 -- ERROR
_ENV.X = 1 -- Ok
_G.print(X) -- Ok
foo() -- 'foo' can freely change any globalチャンクもブロックであるため(§3.3.2を参照)、明示的なブロックの外側にあるチャンク内でも変数を宣言できる。
変数宣言の可視性規則は§2.2で説明する。
3.3.8 – クローズ対象変数
クローズ対象変数は定数ローカル変数のように動作するが、通常のブロック終了、break/goto/returnによるブロックからの脱出、エラーによる脱出を含め、変数がスコープから外れるたびにその値がクローズされる点が異なる。
ここで値をクローズするとは、その__closeメタメソッドを呼び出すことを意味する。メタメソッドを呼び出す際、値自体が第1引数として渡される。エラーがあった場合、脱出の原因となったエラーオブジェクトが第2引数として渡され、それ以外の場合は第2引数がない。
クローズ対象変数へ代入する値は、__closeメタメソッドを持つか、偽値でなければならない。(nilとfalseはクローズ対象の値として無視される。)
複数のクローズ対象変数が同じイベントでスコープから外れる場合、宣言された順序と逆の順序でクローズされる。
クローズメソッドの実行中にエラーが発生した場合、そのエラーは、変数が定義された通常のコード内のエラーと同様に処理される。エラーの後も、保留中の他のクローズメソッドは呼び出される。
コルーチンがyieldし、その後二度と再開されない場合、一部の変数はスコープから外れず、クローズされない可能性がある。(該当するのは、コルーチン内で作成され、そのコルーチンがyieldした時点でスコープ内にある変数である。)同様に、コルーチンがエラーで終了した場合、スタックを巻き戻さないため、どの変数もクローズしない。どちらの場合も、ファイナライザーを使用するか、coroutine.closeを呼び出して変数をクローズできる。ただし、コルーチンがcoroutine.wrapを介して作成された場合、対応する関数はエラー発生時にコルーチンを閉じる。