このページの内容

3.4 –

Luaの基本式は次のとおりである。

	exp ::= prefixexp
	exp ::= nil | false | true
	exp ::= Numeral
	exp ::= LiteralString
	exp ::= functiondef
	exp ::= tableconstructor
	exp ::=...
	exp ::= exp binop exp
	exp ::= unop exp
	prefixexp ::= var | functioncall | ‘(’ exp ‘)’

数値リテラルとリテラル文字列は§3.1、変数は§3.2、関数定義は§3.4.11、関数呼び出しは§3.4.10、テーブルコンストラクターは§3.4.9で説明する。3つのドット(‘...’)で表す可変長引数式は、可変長引数関数の直内でだけ使用でき、§3.4.11で説明する。

2項演算子には、算術演算子(§3.4.1)、ビット単位演算子(§3.4.2)、関係演算子(§3.4.4)、論理演算子(§3.4.5)、連結演算子(§3.4.6)がある。単項演算子には、単項マイナス(§3.4.1)、単項ビット単位NOT(§3.4.2)、単項論理not§3.4.5)、単項長さ演算子§3.4.7)がある。

3.4.1 – 算術演算子

Luaは次の算術演算子をサポートする。

  • + : 加算
  • - : 減算
  • * : 乗算
  • / : 浮動小数点除算
  • // : 切り捨て除算
  • % : 剰余
  • ^ : べき乗
  • - : 単項マイナス べき乗と浮動小数点除算を除き、算術演算子は次のように動作する。両方のオペランドが整数の場合、整数に対して操作を行い、結果も整数となる。それ以外で両方のオペランドが数値の場合、浮動小数点数へ変換し、機械の浮動小数点算術規則(通常はIEEE 754規格)に従って操作を行い、結果も浮動小数点数となる。(文字列ライブラリは、算術操作で文字列を数値へ型強制する。詳細は§3.4.3を参照。)

べき乗と浮動小数点除算(/)は常にオペランドを浮動小数点数へ変換し、結果も常に浮動小数点数となる。べき乗はISO C関数powを使用するため、整数でない指数に対しても動作する。

切り捨て除算(//)は、商を負の無限大へ丸め、オペランドの除算の床を結果とする除算である。

剰余は、商を負の無限大へ丸める除算(切り捨て除算)の余りとして定義される。

整数算術でオーバーフローが発生した場合、すべての操作はラップアラウンドする。

3.4.2 – ビット単位演算子

Luaは次のビット単位演算子をサポートする。

  • & : ビット単位AND
  • | : ビット単位OR
  • ~ : ビット単位排他的OR
  • >> : 右シフト
  • << : 左シフト
  • ~ : 単項ビット単位NOT すべてのビット単位操作は、オペランドを整数へ変換し(§3.4.3を参照)、その整数のすべてのビットに対して操作を行い、整数を結果とする。

右シフトと左シフトはいずれも、空いたビットをゼロで埋める。負の変位は反対方向へシフトする。絶対値が整数のビット数以上である変位は、すべてのビットがシフトで外へ出るため、結果がゼロとなる。

3.4.3 – 型強制と変換

Luaは実行時に、一部の型と表現の間でいくつかの自動変換を行う。ビット単位演算子は、浮動小数点オペランドを常に整数へ変換する。べき乗と浮動小数点除算は、整数オペランドを常に浮動小数点数へ変換する。整数と浮動小数点数が混在するその他の算術操作は、整数オペランドを浮動小数点数へ変換する。C APIも、必要に応じて整数を浮動小数点数へ、浮動小数点数を整数へ変換する。さらに、文字列連結は文字列だけでなく数値も引数として受け付ける。

整数から浮動小数点数への変換では、その整数値を浮動小数点数で正確に表現できる場合、それが結果となる。それ以外の場合は、表現可能な最も近い大きい値または小さい値へ変換される。この種の変換が失敗することはない。

浮動小数点数から整数への変換では、その値を整数として正確に表現できるか(すなわち、浮動小数点数が整数値を持ち、整数表現の範囲内にあるか)を検査する。表現できる場合はその表現が結果となり、それ以外の場合は変換に失敗する。

Luaのいくつかの場所では、必要に応じて文字列を数値へ型強制する。特に文字列ライブラリは、すべての算術操作で文字列から数値への型強制を試みるメタメソッドを設定する。変換に失敗すると、ライブラリはもう一方のオペランドのメタメソッドがあればそれを呼び出し、なければエラーを発生させる。ビット単位演算子はこの型強制を行わないことに注意すること。

文字列から数値への暗黙の型強制は常に適用されるわけではないため、これに依存しないのが常によい慣行である。特に、"1"==1は偽となり、"1"<1はエラーを発生させる(§3.4.4を参照)。これらの型強制は主に互換性のために存在し、将来の言語バージョンで削除される可能性がある。

文字列は、その構文とLua字句解析器の規則に従って整数または浮動小数点数へ変換される。文字列は先頭と末尾の空白、および符号を持つこともできる。文字列から数値へのすべての変換は、基数文字としてドットと現在のロケール記号の両方を受け付ける。(ただしLua字句解析器はドットだけを受け付ける。)文字列が有効な数値リテラルでない場合、変換は失敗する。必要であれば、この最初の段階の結果は、前述した浮動小数点数と整数の変換規則に従って、特定の数値サブタイプへ変換される。

数値から文字列への変換は、形式が規定されていない人間が読める表現を使用する。特定の形式で数値を文字列へ変換するには、関数string.formatを使用する。

3.4.4 – 関係演算子

Luaは次の関係演算子をサポートする。

  • == : 等価
  • ~= : 不等価
  • < : 未満
  • > : より大きい
  • <= : 以下
  • >= : 以上 これらの演算子は常にfalseまたはtrueを結果とする。

等価(==)は、最初にオペランドの型を比較する。型が異なる場合、結果はfalseとなる。それ以外の場合、オペランドの値を比較する。文字列は、同じバイト内容を持つ場合に等しい。数値は、同じ数学的な値を表す場合に等しい。

テーブル、ユーザーデータ、スレッドは参照によって比較される。2つのオブジェクトが等しいとみなされるのは、同じオブジェクトである場合だけである。新しいオブジェクト(テーブル、ユーザーデータ、スレッド)を作成するたびに、その新しいオブジェクトは以前から存在するどのオブジェクトとも異なる。関数は常にそれ自体と等しい。検出可能な違い(異なる動作、異なる定義)を持つ関数は常に異なる。異なる時点に作成されたが検出可能な違いがない関数は、内部キャッシュの詳細に応じて、等しいと分類される場合も、等しくないと分類される場合もある。

__eqメタメソッドを使うと、Luaがテーブルとユーザーデータを比較する方法を変更できる(§2.4を参照)。

等価比較では、文字列を数値へ、または数値を文字列へ変換しない。したがって、"0"==0falseと評価され、t[0]t["0"]はテーブル内の異なるエントリーを表す。

演算子~=は、等価(==)の否定と正確に同じである。

順序演算子は次のように動作する。両方の引数が数値の場合、サブタイプにかかわらず数学的な値に従って比較される。それ以外で両方の引数が文字列の場合、現在のロケールに従って値が比較される。それ以外の場合、Luaは__ltまたは__leメタメソッドの呼び出しを試みる(§2.4を参照)。比較a > bb < aへ、a >= bb <= aへ変換される。

IEEE 754規格に従い、特殊値NaNは、それ自身を含むどの値より小さいとも、等しいとも、大きいともみなされない。

3.4.5 – 論理演算子

Luaの論理演算子はandornotである。制御構造(§3.3.4を参照)と同様に、すべての論理演算子はfalsenilを偽とし、それ以外を真とする。

否定演算子notは常にfalseまたはtrueを返す。論理積演算子andは、第1引数がfalseまたはnilならその引数を返し、それ以外なら第2引数を返す。論理和演算子orは、第1引数がnilおよびfalse以外ならその引数を返し、それ以外なら第2引数を返す。andorはいずれも短絡評価を使用し、必要な場合にだけ第2オペランドを評価する。例を次に示す。

     10 or 20            --> 10
     10 or error()       --> 10
     nil or "a"          --> "a"
     nil and 10          --> nil
     false and error()   --> false
     false and nil       --> false
     false or nil        --> nil
     10 and 20           --> 20

3.4.6 – 連結

Luaの文字列連結演算子は2つのドット(‘..’)で表す。両方のオペランドが文字列または数値の場合、数値は規定されていない形式で文字列へ変換される(§3.4.3を参照)。それ以外の場合、__concatメタメソッドが呼び出される(§2.4を参照)。

3.4.7 – 長さ演算子

長さ演算子は、単項前置演算子#で表す。

文字列の長さは、そのバイト数である。(各文字が1バイトの場合、これは通常の文字列長の意味である。)

テーブルへ適用した長さ演算子は、そのテーブル内の境界を返す。テーブルt境界は、次の条件を満たす任意の非負整数である。

     (border == 0 or t[border] ~= nil) and
     (t[border + 1] == nil or border == math.maxinteger)

言い換えると、境界は、テーブル内に存在し、その直後のインデックスが存在しない任意の正整数インデックスに、2つの限界事例を加えたものである。インデックス1が存在しない場合のゼロと、整数の最大値にあたるインデックスが存在する場合のその最大値である。正整数でないキーは境界へ影響しないことに注意すること。

境界が正確に1つだけのテーブルをシーケンスと呼ぶ。たとえば、テーブル{10,20,30,40,50}は境界(5)を1つだけ持つためシーケンスである。テーブル{10,20,30,nil,50}は2つの境界(3と5)を持つため、シーケンスではない。(インデックス4のnilと呼ばれる。)テーブル{nil,20,30,nil,nil,60,nil}は3つの境界(0、3、6)を持つため、これもシーケンスではない。テーブル{}は境界0を持つシーケンスである。

tがシーケンスの場合、#tは唯一の境界を返し、これはシーケンスの長さという直感的な概念に対応する。tがシーケンスでない場合、#tはその境界のいずれかを返すことができる。(正確にどれを返すかはテーブルの内部表現の詳細に依存し、その内部表現はテーブルへ値を設定した方法や、数値でないキーのメモリアドレスに依存する可能性がある。)

テーブルの長さを計算する最悪時間は、nをテーブル内の最大整数キーとして、*O(log n)*であることが保証される。

プログラムは、文字列以外の任意の値に対する長さ演算子の動作を、__lenメタメソッドによって変更できる(§2.4を参照)。

3.4.8 – 優先順位

Luaの演算子の優先順位を、低いものから高いものの順に次の表へ示す。

     or
     and
     <     >     <=    >=    ~=    ==
     |
     ~
     &
     <<    >>
     ..
     +     -
     *     /     //    %
     unary operators (not   #     -     ~)
     ^

通常どおり、括弧を使って式の優先順位を変更できる。連結(‘..’)演算子とべき乗(‘^’)演算子は右結合である。その他の2項演算子はすべて左結合である。

3.4.9 – テーブルコンストラクター

テーブルコンストラクターは、テーブルを作成する式である。コンストラクターを評価するたびに、新しいテーブルが作成される。コンストラクターは、空のテーブルを作成する場合にも、テーブルを作成して一部のフィールドを初期化する場合にも使用できる。コンストラクターの一般的な構文は次のとおりである。

	tableconstructor ::= ‘{’ [fieldlist] ‘}’
	fieldlist ::= field {fieldsep field} [fieldsep]
	field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
	fieldsep ::= ‘,’ | ‘;’

[exp1] = exp2形式の各フィールドは、新しいテーブルへキーexp1、値exp2のエントリーを追加する。name = exp形式のフィールドは["name"] = expと等価である。exp形式のフィールドは[i] = expと等価であり、iは1から始まる連続した整数となる。他の形式のフィールドは、この数え方に影響しない。たとえば、

     a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }

は、次と等価である。

     do
       local t = {}
       t[f(1)] = g
       t[1] = "x"         -- 1st exp
       t[2] = "y"         -- 2nd exp
       t.x = 1            -- t["x"] = 1
       t[3] = f(x)        -- 3rd exp
       t[30] = 23
       t[4] = 45          -- 4th exp
       a = t
     end

コンストラクター内の代入順序は未定義である。(この順序が関係するのは、キーが重複している場合だけである。)

リストの最後のフィールドがexp形式であり、その式が複数結果式である場合、その式が返すすべての値が連続してリストへ入る(§3.4.12を参照)。

機械生成コードで便利なように、フィールドリストの末尾には省略可能な区切り文字を付けられる。

3.4.10 – 関数呼び出し

Luaの関数呼び出しは次の構文を持つ。

	functioncall ::= prefixexp args

関数呼び出しでは、最初にprefixexpとargsを評価する。prefixexpの値がfunction型の場合、指定された引数でその関数が呼び出される。それ以外の場合、prefixexpの__callメタメソッドがあれば呼び出される。その第1引数はprefixexpの値であり、元の呼び出し引数が後に続く(§2.4を参照)。

次の形式は、

	functioncall ::= prefixexp ‘:’ Name args

メソッドを模倣するために使用できる。呼び出しv:name(args)v.name(v, args)の構文糖であるが、vは1回だけ評価される。

引数は次の構文を持つ。

	args ::= ‘(’ [explist] ‘)’
	args ::= tableconstructor
	args ::= LiteralString

すべての引数式は呼び出し前に評価される。f{fields}形式の呼び出しはf({fields})の構文糖である。すなわち、引数リストは1つの新しいテーブルとなる。f'string'形式(またはf"string"f[[string]])の呼び出しはf('string')の構文糖である。すなわち、引数リストは1つのリテラル文字列となる。

クローズ対象変数のスコープ内にないreturn functioncall形式の呼び出しを末尾呼び出しと呼ぶ。Luaは正しい末尾呼び出し(または正しい末尾再帰)を実装している。末尾呼び出しでは、呼び出された関数が呼び出し元関数のスタックエントリーを再利用する。そのため、プログラムが実行できるネストした末尾呼び出しの数に制限はない。ただし、末尾呼び出しは呼び出し元関数に関するデバッグ情報をすべて消去する。末尾呼び出しが発生するのは、returnが1つの関数呼び出しだけを引数に持ち、クローズ対象変数のスコープ外にあるという特定の構文の場合だけであることに注意すること。この構文では、呼び出し元関数が途中の操作を行わず、呼び出された関数の戻り値を正確にそのまま返す。したがって、次の例はいずれも末尾呼び出しではない。

     return (f(x))        -- results adjusted to 1
     return 2 * f(x)      -- result multiplied by 2
     return x, f(x)       -- additional results
     f(x); return         -- results discarded
     return x or f(x)     -- results adjusted to 1

3.4.11 – 関数定義

関数定義の構文は次のとおりである。

	functiondef ::= function funcbody
	funcbody ::= ‘(’ [parlist] ‘)’ block end

次の構文糖は関数定義を簡潔にする。

	stat ::= function funcname funcbody
	stat ::= local function Name funcbody
	stat ::= global function Name funcbody
	funcname ::= Name {‘.’ Name} [‘:’ Name]

     function f () body end

は、次へ変換される。

     f = function () body end

     function t.a.b.c.f () body end

は、次へ変換される。

     t.a.b.c.f = function () body end

     local function f () body end

は、次へ変換され、

     local f; f = function () body end

次には変換されない。

     local f = function () body end

(この違いが生じるのは、関数本体がfへの再帰参照を含む場合だけである。)同様に、文

     global function f () body end

は、次へ変換される。

     global f; global f = function () body end

2つ目のglobalは代入を初期化とするため、そのグローバルがすでに定義されている場合はエラーが発生する。

コロン構文はメソッドを模倣するために使用し、暗黙の追加引数selfを関数へ加える。したがって、文

     function t.a.b.c:f (params) body end

は、次の構文糖である。

     t.a.b.c.f = function (self, params) body end

関数定義は実行可能な式であり、その値はfunction型である。Luaがチャンクをプリコンパイルするとき、すべての関数本体もプリコンパイルされるが、まだ作成はされない。その後、Luaが関数定義を実行するたびに、関数がインスタンス化(またはクローズ)される。この関数インスタンス、すなわちクロージャが式の最終的な値となる。

結果はreturn文を使って返す(§3.3.4を参照)。return文に到達せず、制御が関数の終端へ達した場合、その関数は結果なしで戻る。

関数が返せる値の数にはシステム依存の制限がある。この制限は少なくとも1000であることが保証される。

引数

引数は、引数値で初期化されるローカル変数として動作する。

	parlist ::= namelist [‘,’ varargparam] | varargparam
	varargparam ::=...’ [Name]

Lua関数が呼び出されるとき、可変長引数関数でない限り、引数リストを仮引数リストの長さへ調整する(§3.4.12を参照)。可変長引数関数は、仮引数リストの末尾に3つのドット(‘...’)を置いて示す。可変長引数関数は引数リストを調整せず、代わりにすべての追加引数を収集し、可変長引数テーブルを介して関数へ提供する。このテーブルでは、インデックス1、2、以下同様の値が追加引数であり、インデックス「n」の値が追加引数の数となる。

例として、次の定義を考える。

     function f(a, b) end
     function g(a, b, ...) end
     function r() return 1,2,3 end

この場合、引数から仮引数および可変長引数テーブルへの対応は次のようになる。

     CALL             PARAMETERS
     
     f(3)             a=3, b=nil
     f(3, 4)          a=3, b=4
     f(3, 4, 5)       a=3, b=4
     f(r(), 10)       a=1, b=10
     f(r())           a=1, b=2
     
     g(3)             a=3, b=nil, va. table ->  {n = 0}
     g(3, 4)          a=3, b=4,   va. table ->  {n = 0}
     g(3, 4, 5, 8)    a=3, b=4,   va. table ->  {5, 8, n = 2}
     g(5, r())        a=5, b=1,   va. table ->  {2, 3, n = 2}

可変長引数関数内の可変長引数テーブルは、3つのドットの後に指定する省略可能な名前を持つことができる。名前がある場合、その名前は可変長引数テーブルを参照する読み取り専用のローカル変数を表す。可変長引数テーブルに名前がない場合、可変長引数式を介してだけアクセスできる。

可変長引数式も3つのドットで記述し、その値は、可変長引数テーブルのインデックス1からインデックス「n」の整数値までにある値のリストとなる。(したがって、コードが可変長引数テーブルを変更しない場合、このリストは関数呼び出しの追加引数に対応する。)このリストは、複数の結果を持つ関数の結果と同様に動作する(§3.4.12を参照)。

最適化として、可変長引数テーブルがいくつかの条件を満たす場合、コードは実際のテーブルを作成せず、インデックス式と可変長引数式を内部の可変長引数データへのアクセスへ変換する。条件は次のとおりである。可変長引数テーブルが名前を持つ場合、その名前がネストした関数内のアップバリューではなく、構文構造t[exp]またはt.idのベーステーブルとしてだけ使用される。無名の可変長引数テーブルは常にこれらの条件を満たすことに注意すること。

3.4.12 – 式のリスト、複数の結果、調整

関数呼び出しと可変長引数式はいずれも、複数の値を結果とすることができる。これらの式を複数結果式と呼ぶ。

複数結果式が式リストの最後の要素として使用されると、その式のすべての結果が、式リストによって生成される値リストへ追加される。式リストを期待する場所にある単一の式は、その(要素が1つの)リストの最後の式であることに注意すること。

Luaが式リストを期待する場所は次のとおりである。

  • return文。例: return e1,e2,e3§3.3.4を参照)。

  • テーブルコンストラクター。例:

    {e1,e2,e3}

    §3.4.9を参照)。

  • 関数呼び出しの引数。例:

    foo(e1,e2,e3)

    §3.4.10を参照)。

  • 多重代入。例:

    a,b,c = e1,e2,e3

    §3.3.3を参照)。

  • 多重代入と同様のローカル宣言またはグローバル宣言。

  • 汎用forループの初期値。例:

    for k in e1,e2,e3 do... end

    §3.3.5を参照)。

最後の4つの場合、式リストから得られる値リストは、特定の長さへ調整されなければならない。その長さは、非可変長引数関数の呼び出しにおける仮引数の数(§3.4.11を参照)、多重代入または宣言における変数の数、汎用forループでは正確に4つである。調整は次の規則に従う。必要な数より値が多い場合、余分な値は破棄される。必要な数より値が少ない場合、リストはnilで拡張される。式リストが複数結果式で終わる場合、調整前にその式のすべての結果が値リストへ入る。

複数結果式が式リストの最後でない要素として使われるか、構文が単一の式を期待する場所で使われる場合、Luaはその式の結果リストを1要素へ調整する。特別な場合として、括弧付き式の内部では構文が単一の式を期待するため、複数結果式を括弧で囲むと、正確に1つの結果を生成するよう強制される。

構文が単一の式を期待する場所で可変長引数式を使用する必要が生じることはまれである。(通常は、可変長部分の前に通常の仮引数を追加し、その引数を使用する方が単純である。)その必要がある場合、可変長引数式を単一の変数へ代入し、その変数を代わりに使用することを推奨する。

複数結果式の使用例を次に示す。いずれの場合も、構造が「n番目の結果」を必要とするときにその結果が存在しなければ、nilを使用する。

     print(x, f())      -- prints x and all results from f().
     print(x, (f()))    -- prints x and the first result from f().
     print(f(), x)      -- prints the first result from f() and x.
     print(1 + f())     -- prints 1 added to the first result from f().
     local x = ...      -- x gets the first vararg argument.
     x,y = ...          -- x gets the first vararg argument,
                        -- y gets the second vararg argument.
     x,y,z = w, f()     -- x gets w, y gets the first result from f(),
                        -- z gets the second result from f().
     x,y,z = f()        -- x gets the first result from f(),
                        -- y gets the second result from f(),
                        -- z gets the third result from f().
     x,y,z = f(), g()   -- x gets the first result from f(),
                        -- y gets the first result from g(),
                        -- z gets the second result from g().
     x,y,z = (f())      -- x gets the first result from f(), y and z get nil.
     return f()         -- returns all results from f().
     return x, ...      -- returns x and all received vararg arguments.
     return x,y,f()     -- returns x, y, and all results from f().
     {f()}              -- creates a list with all results from f().
     {...}              -- creates a list with all vararg arguments.
     {f(), 5}           -- creates a list with the first result from f() and 5.