Lua 5.1 言語仕様メモ


[Lua 5.1 リファレンスマニュアル](http://milkpot.sakura.ne.jp/lua/lua51_manual_ja.html "Lua 5.1 リファレンスマニュアル") の第2章と [Programming in Lua プログラミング言語Lua公式解説書](http://www.amazon.co.jp/dp/4048677977) の気になった部分のメモです。
間違いや誤解があるかもしれないので、正確な情報はリンク先か原文を参照することをお勧めいたします。

書籍の方は通販で手に入れるのが難しいようなので、リアル書店で見つけた場合は入手しておくとよいかもしません。

# -- メモ

## 値と型
- Lua は動的型付け
  - 変数は型を持たない
  - 値が型を持つ
  - 型定義の構文はない

- 全ての値がファーストクラス
  - いかなる値も変数に格納できる
  - 他の関数に引数として与えられる
  - 全ての値は関数の戻り値にできる

### 基本型8種
1. nil
  - **nil**値の型
     - というか、この型の値は **nil** しかない
  - 役に立つ値がない、ということを表す
  - テーブル要素の削除や、グローバル変数の削除にも使われる
     - ただの Null値 という感じではない
1. ブーリアン
  - true / false
1. 数値
  - 実数 (double)
     - 整数表現は 10^14 までは誤差は発生しない
  - 内部表現を float, long などに変えたい場合は Luaインタプリタをリビルドする
1. 文字列
  - 文字の配列
  - 8bitクリーン
1. 関数
  - 関数
1. ユーザーデータ
  - 任意のC言語のデータをLuaの変数に格納する
  - CとのAPIを通してのみ作成と変更が可能
  - 代入と等価比較演算以外、Lua側で演算が定義されていない
  - _メタテーブル_ という機能を用いると、演算を定義できる
1. スレッド
  - 実行されているスレッドを表す
  - コルーチン実装のために使われる
  - LuaのスレッドとOSのスレッドは別物
1. テーブル
  - 連想配列
    - nil 以外の任意の値をキーにできる
    - nil 以外のあらゆる型を値に持てる
    - Lua唯一のデータ構造
      - 通常の配列のほか以下を表現するためにも使われる
         1. 記号表
         1. 集合
         1. レコード
         1. グラフ
         1. ツリー
    - `a["name"]` でフィールドにアクセス
      - `a.name` でもアクセス可能
    - テーブルには関数を格納できる
      - 関数がファーストクラスなので
      - つまり、テーブルにメソッドを持たせることができる
      - JSっぽい

#### 偽の値
- 条件判断で 偽 となるのは
  1. **nil**
  1. **false**

つまり、空文字列や空のテーブル、 0 などは **真** になるので注意

#### オブジェクト
以下の型は _オブジェクト_ である

1. テーブル
  - Luaのテーブルは動的に確保された _オブジェクト_
1. 関数
1. スレッド
1. ユーザーデータ

- オブジェクトは変数の格納されず、参照されるのみである
  - 代入、引数渡し、関数の返り値は、コピーではなく参照が渡される

##### テーブルついて

```lua
a = {}       -- テーブルを作成し、参照を取得
a[1] = 'hoge'
print(a[1])  -- 'hoge'
b = a        -- 同じ参照先を取得
a = nil      -- 参照を削除
print(b[1])  -- 'hoge'

c = {[1] = 1, [2] = 2; ['a'] = 'a'}  -- 区切り文字には , ; の二種が使える
```

`type` 関数で型名の文字列が取得できる

#### 変換
Lua は文字列と数値を実行時に自動的に変換

- 演算の状況に応じて文字列⇔数値の変換をLua側がよしなに行ってくれる
- ちゃんと制御したいときは `string.format` のドキュメントを読むこと


## 変数
Luaの変数は三種類

1. グローバル変数
  - **環境テーブル** または **環境** と呼ばれる Lua テーブル内のフィールドとして存在する
     - グローバルな領域からアクセスできるテーブルのフィールドが、グローバル変数
     - **nil** を代入するとグローバル変数を削除できる
1. ローカル変数
  - グローバル変数より高速にアクセスできる
  - スコープを抜けるとガベージコレクタによって解放される
     - メモリ節約
  - レキシカルスコープ
     - 定義されたスコープ内から自由にアクセス可能
        - つまり、中の関数は外側の関数のローカル変数にアクセスできる
1. テーブルフィールド

変数のルール

- 明示的にローカル宣言されない変数は全てグローバル変数
- 関数の仮引数はローカル変数
- 代入が行われる前の変数の値は、自動的に **nil**

_メタテーブル_ によってグローバル変数とテーブルフィールドへアクセスする効果を変更できる

- `gettable_event` という関数の呼び出しと等価
  - この関数は Lua から定義したり呼び出すことはできない
  - 説明のために用いているだけ

インデックス付き変数へのアクセス

```lua
hoge = t[i]
-- これは以下と等価 (実際には呼び出せない)
hoge = gettable_event(t, i)
```

グローバル変数へのアクセス

- 各関数は独自に **環境** への参照を持つ
  - その関数内のグローバル変数は、 **環境テーブル** を参照する
    - 関数が作られるとき、作られた関数から見える **環境** を受け継ぐ
  - Lua関数の **環境テーブル** を
    - 取得するには `getfenv` を呼ぶ
    - 変更するには `setfenv` を呼ぶ

```lua
-- グローバル変数 x へのアクセスは以下と等価
-- _env は、その関数が実行されている 環境 を表す
gettable_event(_env, "x")
```


## 文
CやPascalのように文のセットをサポートしている。以下は文の一種。

- 変数宣言
- 代入
- テーブルコンストラクタ
- 関数呼び出し
- 制御構造


### チャンク
Lua の実行の単位を _チャンク_ と呼ぶ

- 順番に実行される連続した文
- 文末のセミコロンは省略可
  - 空文は許可されない
     - `;;` はエラー

```lua
-- チャンク
a = 'hoge'; b = 'fuga'; function f(x, y) return x..y end; print(f(a, b))
-- 以下のチャンクはエラー
d = 1; e = 1; print(d+e);;print('hoge')
-- これはOK
a = 1 b = 2
```

チャンクの実体

- 可変引数を持つ無名関数
  - 関数なのでローカル変数を宣言できる
  - 引数を受け取れる
  - 戻り値を返せる


### ブロック
構文的にはチャンクと同じ

- `block ::= chunk` である

ブロックは以下のいずれか

1. 制御構造のボディ
1. 関数のボディ
1. チャンク
   - 変数が宣言されているファイル or 文字列

`do end` で囲む

- `do` を入力すると、`end` が来るまでコマンドがしない

- 明示的なブロック宣言
- 変数のスコープをコントロールするのに便利
   - ローカル変数のスコープは、宣言されたブロックとなる
- `return` や `break` をブロックの途中に仕込むのにも使える
   - 構文上、 `break` と `return` はブロックの最後にしか置けないから
   - 言い換えると、 `end` `else` `until` などの直前にしか書けない

```lua
function f()
    return  -- エラー
    print('hoge')
end

function f2()
    do return end  -- OK
    print('hoge')
end
```

### 代入
多重代入ができる

```lua
-- python ライクに以下のコードで値のスワップができる
x, y = y, x
```

### 制御構文

### for
`for i in array` のような for文を **ジェネリックfor** と呼ぶ

- `for i in` の _i_ の部分を **制御変数**
   - 変数が複数ある場合、先頭の変数が制御変数
   - 制御変数が **nil** になるとループ終了

- 内部で _イテレータ_ を使う
   - イテレータは、実質的ただのクロージャ

```lua
-- for i in {} と同じ動作
function make_iter(t)
    local i = 0
    return function()
            i = i + 1
            return t[i]
        end

iter = make_iter{1, 2, 3}
while true do
    local val = iter()  -- イテレータが尽きるまで while が回る
    if val == nil then
        break
    end
    print(val)
end
```

### ローカル宣言
ローカル変数は、ブロック内のどこでも宣言できる

#### イディオム
グローバル変数の値を保護しながらローカル変数化する

```lua
do
local hoge = hoge
end
```


## 式
関数呼び出しを `()` で包むと、戻り値が1つになる。
`{}` で包むとテーブルにして返す。

```lua
function f(x, y, z)
    return x, y, z
end

print( f(1, 2, 3)   )  -- 1, 2, 3 が出力
print( (f(1, 2, 3)) )  -- 1 のみ出力
print( {f(1, 2, 3)} )  -- {[1] = 1; [2] = 2; [3] = 3} が返る

print( f(1, 2, 3), 4 )  -- 1, 4
print( 4, f(1, 2, 3) )  -- 4, 1, 2, 3

-- 式の途中で呼ばれたときは、最初の引数のみ得られる
print( f(1, 2, 3) .. 4 )  -- '14'
print( 4 .. f(1, 2, 3) )  -- '41'
```

### 関係演算子
常に true / false のどちらかを返す

```lua
t = {1, 2, 3}
print("0" == 0)  -- false
print(t[1] == t["1"])  -- false
```

### 論理演算子
以下の3種

1. and
  - 最初の引数が
     - 偽ならその値を返す
     - 真なら二番目の引数を返す
1. or
  - 最初の引数が
     - 真ならその値を返す
     - 偽なら二番目の引数を返す
1. not
  - true / false のいずれかを返す

なお論理演算子は、必要になるまで2つ目の引数を評価しない。

```lua
-- and
print(0 and 1)     --  1
print(true and 2)  --  2
print(3 and true)  --  true
print(nil and 1)   --  nil
print(false and 1) -- false

-- or
print(0 or  1)   --  0
print(nil or 1)  --  1
print(nil or false)  --  false
print(false or nil)  --  nil

-- not
print(not 1)  -- false
print(not {}) -- false
print(not nil)    -- true
print(not false)  -- true
print(not not true)  -- true

-- 引数の評価
function f(x)
    return x+1
end

print(0 and f(1))  -- 2
print(nil and f(2))  -- nil
```

#### 論理演算子のイディオム
1. 変数のみ定義時のデフォルト値を設定する

```lua
-- 未定義変数だった場合, x = 'hoge' を実行
if not x then x = 'hoge' end
-- これは以下と等価
x = x or 'hoge'
```

2. 関数のデフォルト引数とする

```lua
function increment(n)
    n = n or 1  -- n が未定義時は 1
    return n+1
end
```

2. 三項演算子の再現

```lua
-- Python の hoge = a if cond else b は以下と等価
hoge = (cond and b) or c

-- 値の大きいを方を取得する例
hoge = ((a > b) and a) or b
```

### 長さ演算子
`#` を使う

  - 文字列はバイト数を返す
  - テーブルは、テーブルの長さ

```lua
t = {[1] = 1; [2] = 2}
print(#'a')  -- 1 (byte)
print(#'あ')  -- 3 (byte)

print(#{}) -- 0
print(#t)  -- 2 (テーブルの長さ)

t['a'] = 'b'
print(#t)  -- 2 


function f(x)
    return x
end

t2 = {[f(1)] = 11;'x'; y = 'y'; [2] = 2}
print(#t2)  -- 2
```

#### 長さ演算を使うイディオム

```lua
a = {[1] = 1, [2] = 2, [3] = 3}
print(a[#a])    -- 末尾要素の出力
a[#a] = nil     -- 末尾要素の削除
a[#a+1] = hoge  -- 末尾に値を追加
```

### テーブルコンストラクタ
テーブルを作る式

- 評価されるたび、新しいテーブルが作られる
   - 最も単純なコンストラクタ式は `{}`
   - コンストラクタはテーブルの初期化時のみ影響を与える
      - 作成されるテーブルの性質は同じ


## 関数

### 関数呼び出し
メソッド呼び出し

- `v:name(...)` は `v.name(v, ...)` と等価


### 関数定義
Lua の関数は全て無名関数。

- python でいう lambda
   - よくある `filter`, `map` 関数に引数として渡す関数ように扱うこともできる

```lua
-- 無名関数を print
print( function (x) return x end )

-- 無名関数を return
function gen_func(x)
    return function (a)
            return a + x
        end
end
```

関数名とは、関数を保持する変数のこと。

```lua
-- 以下の2つは等価
function f(x) return x end
f = function (x) return x end
```

### 名前付き引数
テーブルを引数に与えると、名前付き引数と同等の機能を得られる

```lua
function _f(a, b)
    print(a + b)
end

function f(args)
    -- 必須引数のチェック
    if type(args.a) ~= "number" then
        error("a は数値")
    end

    _f(args.a,
       args.b or 0  -- b はデフォルト値を与えておく
    )

-- 呼び出し
print( f{a=1, b=1} )  -- 2
print( f{a=1} )       -- 1
print( f{b=1} )       -- error
```

### 末尾呼び出し
例

```lua
function g()
    return 1
end

function f()
    return g()  -- ここが末尾呼び出し
end
```

関数f() は g() を呼び出した時点でやることがないので、スタックから排除される。
これは、 g() の実行が終了するとき、 f() のスタックを経由せずに f() を呼び出した場所までコントロールが戻る。
いわゆる _末尾再帰最適化_ に通じるもの。

よって、以下は末尾呼び出しではない。

```lua
function f(x)
    g(x)  -- 返り値を return していない => 戻り値を廃棄する処理が残っている
end

function f2(x)
    return g2(x) + 1  -- 加算演算が残っているので f2 のスタックを捨てれない
end
```

末尾再帰の例

```lua
-- 階乗
function fact(n, acc)
    local acc = acc or 1
    if (n < 1) then return acc end
    return fact(n - 1, n * acc)
end
```


## エラー処理
`error` 関数を呼ぶと、明示的なエラーを発生させることができる
Lua内でエラーをキャッチしたいなら `pcall` 関数を使う

## メタテーブル
Luaの値は **メタテーブル** を持てる

- 通常のLuaテーブル
  - 値に対して、特殊な演算をしたときの挙動を定義する
  - メタテーブルのフィールドを設定すると、オブジェクトの動作を変えることができる
    - 数値以外で加算を行おうとしたとき、メタテーブルの `__add` が定義されていれば、加算のためその関数を呼び出す

いわゆる演算子のオーバーロード
自分で独自のデータ型の挙動を定義できる

キーを _イベント_ と呼ぶ

  - `add` など

値を _メタメソッド_ と呼ぶ

  - 加算を行う関数など

#### テーブルのメタテーブル
- `setmetatable` 関数で変更できる

略


## 環境
以下のオブジェクトは、 _メタテーブル_ の他に、 **環境** という関連付けられたテーブルを持つ

1. スレッド
  - グローバル環境と呼ばれる
  - スレッドと、スレッドが作成した(ネストされていない)関数のデフォルトの _環境_ として使われる
     - Cのコードに直接アクセスできる
1. 関数
  - その関数がアクセスするグローバル変数の解決に使われる
  - 関数が内部で生成する関数のデフォルト環境としても使われる
     - 生成元の環境を引き継ぐ
1. ユーザーデータ



## ガベージコレクション

略

## コルーチン
協調スレッド

コルーチンは4つの状態の持つ
状態は `coroutine.status` 関数で確認できる

1. suspended
    - 中断
    - コルーチン生成時のデフォルトの状態はこれ
1. running
    - 実行中
1. dead
    - 終了
    - いちど dead になると他に状態には移行できない
1. normal
    - 通常
    - suspended ではないが、別のコルーチンが実行中である

- `yield` 関数を呼んで、明示的に実行を中断しなければならない

**コルーチンのフロー**
#### 作成
`coroutine.create` を呼ぶ

- 引数に関数を与える
- 新しいコルーチンを作成し、 `スレッドオブジェクト` を返す

#### 実行
- コルーチンはすぐには実行されない
  - `coroutine.resume` 関数を呼び出すと実行される
    - 関数の終わりか、 `yield` を呼ぶまで実行される

#### 中断
- `yield` を呼ぶと中断
  - 対応する `coroutine.resume` から戻る
  - `resume` は true を返す
    - `yield` に引数がある場合は、それも返す
  - 同じコルーチンを `resume` すると、中断し箇所から再開
    - 再開時に引数を渡すと、 復帰先の `yield` からそれらが返される

#### 終了
2つの場合がある

1. メイン関数から return して正常終了したとき
  - true とメイン関数の戻り値を返す
1. エラーで異常終了した時
  - false とエラーメッセージを返す

#### coroutine.wrap
コルーチンを作成するもう一つの関数

- コルーチンではなく、 `resume` する関数を返す
  - その関数に渡される引数は、 `coroutine.resume` の追加の引数として渡される
  - 戻り値は 最初のブーリアン(成功、失敗) を除いた関数の戻り値
    - この関数で発生したエラーは捕らえられず、内部エラーは呼び出し側に伝搬する

### コルーチン使用の実例
#### プロデューサ/コンシューマ

- プロデューサー
   - 値を生成し続ける関数や機能
- コンシューマ
   - 生成した値を使用して処理する関数や機能

この2つをコルーチンで実装する。マスタースレーブの関係を作る

```lua
-- receive(コンシューマ) がコルーチン再開の起点なので
-- コンシューマ駆動と呼ばれる設計

function receive()
    local status, value = coroutine.resume(producer)
    -- resume して受け取った値を何らかの関数に返す
    -- producer(coroutine) は再び実行を開始し yeild(x) してxを渡すのを待っている
    return value
end

function send(x)
    coroutine.yeild(x)
end

producer = coroutine.create(
    function()
        while true do
        local x = io.read()
            send(x)  -- yeild で動作を中断し x を resume 先に渡す
        end
    end
end)
```


## コンパイル、実行
ソースは実行される前に中間言語へプリコンパイルする。

### load関数
`loadfile` や `loadstring` はファイルや文字列をチャンクとして読み込み、コンパイルする。
このとき、コンパイルはグローバル環境で行われる
コンパイルされたチャンクは関数として返される

```lua
f = loadstring("i = i + 1")
print(f)  -- function: 0xhogehoge
f()  -- グローバル変数 i が無いためエラー
i = 0
f()  -- OK
print(i)  -- 1
```

## エラー処理
エラーを通知する方法は大きく2つ

1. エラーコードを返す
    - 大体は **nil** を返す
    - 容易に回避できないエラーはこっちを使うことが多い
1. `error`関数を呼ぶ
    - 容易に回避できそうなエラーはこっち(が多い)

### assert関数
Lua では `assert` は通常のコードのなかでもエラー処理のためによく使うらしい

```lua
-- イディオム
file = assert(io.open("does-not-exist.txt", "r"))
-- stdin:1: does-not-exist.txt: No such file or directory が出力される
```

### エラー処理
Luaは、アプリケーション側がLuaに「チャンクを実行しろ」って呼び出すことで動作を開始する。
普通は、LuaではなくLuaを呼び出した側がエラー処理を行う。

Lua側でのエラー処理が必要なときは **pcall**(protected call)関数 を使う。
これはコードをカプセル化する。
pcall は処理結果(true/false) と、カプセル化した関数の戻り値の2つを返す。

```lua
function f()
    -- なにか処理
    if not cond then error() end
    -- なにか処理
    print(a.x)  -- aがテーブルじゃなかったらエラー
    -- なにか処理
end

if pcall(f) then
    -- f() 実行中にエラーが発生しない
    print('success!')  -- なにか処理
else
    -- f() 実行中にエラー発生
    print('error!')  -- エラー処理
end
```

## Luaインタプリタ
Luaインタプリタは、入力された **行** を **完結したチャンク** として評価する

### 起動オプション

```bash
$ lua -i hoge.lua  # hoge.lua を実行したあとに起動
$ lua -e "print(1 + 1)"  # 直接チャンクを実行する
$ lua -i -e "require 'hoge.lua'"  # -e のチャンクを実行したあと起動
$ lua -l hoge  # hoge というライブラリをロードする
```