トップページ
ひらく | たたむ | ページトップ
↓マウスで反転選択した文字を検索
Lua
   
ページ内検索 ページ外検索
検索したい文字を入力して
ENTERを押すと移動します。
\n
[ トップページ ]
[ ____CommandPrompt ] [ ____JScript ] [ ____MySQL ] [ ____Cygwin ] [ ____Java ] [ ____Emacs ] [ ____Make ] [ ____Perl ] [ ____Python ] [ ____OpenGL ] [ ____C# ] [ ____StyleSheet ] [ ____C++ ] [ ____Winsock ] [ ____Thread ] [ ____VisualStudio ] [ ____C ] [ ____Win32API ] [ ____Lua ] [ ____PhotoShop ]
ヘッダ検索
___

■ 制御構文



___

■ if

SYNTAX if 式 then 文 else 文 end if 式 then 文 elseif 式 then 文 else 文 end WARNING 型が異なるもの同士の比較はすべて false; [ "false" | "nil" ] 以外はすべて 真
  -- 以下すべて真
  if (  0 ) then ... end;
  if ( "" ) then ... end;
  if ( {} ) then ... end;
   0 = "0";   // RET: false
   a, b = 128, 18;

   if a == b then
    print("equal");
   else
    print("not equal");
   end
___

■ for

SYNTAX for Name `=´ exp `,´ exp [`,´ exp] do block end for 変数 = 初期値, 終了値[, 増加量] do 文 end for 変数 = 初期値, 終了値, 増加量 do 〜 end 0 から 10 まで
    for i=0,10 do
      print(i);
    end
2 個飛ばしで
    for i=0,10,2 do
      print(i);
    end
配列(テーブル)をイテレートする
    a = { 3, 4, 5 }

    for i=1,#a do
      print( a[i] );
    end

WARNING [ i ]は ローカル変数のため, for 文が終了した瞬間に終了。 break については block 末尾のみできる
    for i = 0, 10 do
          print("test")
          do
                  break;
          end
          print("test")
    end

___

■ repeat

SYNTAX repeat 文 until 条件式

    local cnt = 0;
    repeat
       print( cnt );
       cnt = cnt + 1;
    until cnt > 3

___

■ while

SYNTAX while 評価式 do 文 end WARNING break; は block 末尾にある必要がある.
___

■ foreach

SYNTAX for key,value in pairs(連想配列) do 文 end DESC 配列扱いのテーブルを巡回する場合は、ipairs() 関数を利用する。
    local a = { 1, 2, 5, 8 };

    for i, v in pairs( a ) do
      print(tostring(i) .. " = " .. tostring(v) )
    end
WARNING 巡回する index の最大値は最大のインデックスまで。 index は連続している必要はない。


___

■ 変数


  Lua には 3種類の変数がある。
     global
     local
     tablefield
データ( 情報 )はすべて, テーブルという構造に格納される。 グローバル変数はグローバル用のテーブルにセットされる。
  -- local と言わなければ, global
  v = 10;

  -- local 宣言で local変数扱い
  local t = "test";

  -- 値が代入されない変数は nil がセットされる。
  local v;

POINT 変数に型はなく、任意の型のオブジェクトの場所だけを知っている存在。 動的にわりあてることができるが、 変数の型チェックをしてくれないため自前でする必要がある。 ( Perl, Python 同様 ) 静的わりつけ Merit 実行前に チェック 可能 効率のよい cmp 作成可能 DeMerit 頻繁な型変換 param が異なる場合に複数の関数が必要. 動的わりつけ Merit Object の型をしらべて, 処理をするという動的な処理が可能 DeMerit 実効時にエラーが発生 param が異なる場合に複数の関数が必要. ひとつの 変数(Symbol) に 文字列, 数値 を代入できる。 Java, C では変数に型情報があるため, 実行前にチェックができる。 スペルミスが素通りされる危険がある
___

■ ローカル変数

ローカル変数を定義するには local 文を使用する。
    local  i = 10;
    local i, j = 10, 20;
SYNTAX local name [= expression] local namelist [= expressionlist] POINT ブロック内で local 文を使用する度に, 新たに変数が定義される。 ( C 同様 ) C と同じでブロック内のスコープになる。
    i = 20             -- グローバル変数 i
    do 
      local i = 10     -- 変数 i
      do
        local i = 7    -- これは別オブジェクトの 変数 i
        -- 7
        print (i)
      end              -- もっとも内側のブロックで変数は消滅する 
      -- 10
      print (i)
    end
    for i=1, 10 do
      local y;  -- ここで新規定義
      if y == nil then 
        y = 0 
      else 
        y = y + 1 
      end
    done
___

■ グローバル変数

すべてのグローバル変数は、Luaの環境テーブルというテーブル内のフィールドとして存在する。 global変数とテーブルフィールドへアクセスする効果はメタテーブルによって変えられる. 各関数はそれぞれ独自に環境への参照を持つ. 関数が作られたとき、関数は、それが作られた関数から見える環境を受け継ぐ( ENV 同様 x == _env.x == gettable_event(_env, "x") ( MetaMethod を利用する ) Lua で グローバル変数を宣言( 代入 )する際は, TblGbl( _G ) に格納される
  mt = {};
  mt.__newindex = function( t, n, v );
POINT block do ... end に属さない local v は file scope になる 保守性のために, local にすること.
    -- 未定義変数のチェック
    if ( v ~= nil ) 
        
    end

___

■ 演算子


     算術演算子
     関係演算子
     論理演算子( C などの 論理演算子と異なるので注意 )

___

■ or.and.not

    if a == 10 and s == "test" then
      print( "test" );
    end

    if a == 10 or s == "test" then
      print( "test" );
    end

    if ( not a ) then

    end
POINT
    -- or : 最初の引数が false か nil 以外ならその値を返す
    a = a or 10;
連結演算子 | 文字列連結
    print( "foo" .. "bar" );
___

■ 代入

多重代入OK (右辺の値, 左辺の添え字がすべて評価された後, 代入 ) POINT x, y = y, x; // 入れ替え可能. 関数も複数返すことが可能. function f() return 1, 2; end print( f );
___

■ 論理

   if ( "aaa" ~= "bbb" )
      print ( "diff" )
   end

   if ( "aaa" == "bbb" )
      print ( "same" )
   end
___

■ TableConstructor

SYNTAX TableConstructor ::= { [fieldlist] } Lua にも Constructor がある tbl{ f1=val, f2=val ... } < -> tbl( {...} ) // Tbl関数に Arg として渡した関数. -> DefalutArg の修理とか可能. a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 } [exp1] = exp2 形式のフィールド name = exp 形式のフィールドは ["name"] = exp と等価
  do
     local t = {}
     t[f(1)] = g
     t[1] = "x"         -- 最初のexp
     t[2] = "y"         -- 2番目のexp
     t.x = 1            -- temp["x"] = 1
     t[3] = f(x)        -- 3番目のexp
     t[30] = 23
     t[4] = 45          -- 4番目のexp
     a = t
  end
___

■ 関数呼び出し

( lisp と同様の設計. -> lua_type() -> functioncall ::= prefixexp args... POINT prefixexp と args が評価される ---> prefixexp が関数なら 与えられた引数で関数 call ret = func( arg1, arg2, ...) Function は [ 何かの入力をうけとり ] ---> [ 何かの( 処理 | 判断 | 保存 )をして ] --> [ 何かを出力する ] [ 何か ]を { int, float, vec3, string } と種類を限定することも可能. Ret がない場合は nil をかえす
___

■ method として扱う

( OO 的な呼び出しをする. ) POINT functioncall ::= prefixexp `:´ Name args v:name(...) == v.name( v, ... ); == [ method ] t:f(x) という表現は t.f(t,x); 終端呼び出し( 呼び出し側の stack entry を再利用する ) return functioncall のような呼び出し形式は
___

■ テーブル(Table)


  Lua にはデータを構造化するのはテーブルのみ。
  キーと値の組の集合からなる、連想配列のこと。

    -- table の生成
    tbl = { name="xxx", age=10, price=0 }

    -- テーブルへのメンバのアクセスには [] を使う。
    -- .key の表記は [ "key" ] と同じ。
    tbl[ "key" ]
    tbl.key

    -- 指定したフィールドがない場合は nil が返る
    tbl.foo;

    -- field の追加
    tbl.foo = "bar";

WARNING tbl.name 表記は tbl[ "name" ] と同じ。 次の処理は思ったとおりの動作をしない。
    function isKeyExist( tbl, key ) 
      if ( tbl.key !~ nil ) then
      
      end
    end
tbl.key は tbl[ "key" ] とみなされる。 そこで [ key ] とすれば正しく動作する。
      if ( tbl[key] !~ nil ) then
      end
___

■ 追加.削除

    tbl[ "age" ] = 10
    tbl[ "name" ] = "test"

    -- キーは数値でも指定できる
    tbl[ 1 ] = 10;


    -- 削除をするには nil をセットする
    tbl[ "name" ] = nil


    -- iterate すると削減されたことがわかる
    for key, val in pairs( tbl ) do
       print ( key )
       print ( val )
    end

___

■ ソート(sort)

SYNTAX table.sort( array [, function ] ) DESC 配列を昇順にソートする。
       local a = {7, 5, 3};
       table.sort(a);

       -- 結果を表示
       for i=1, #a do
          print(a[i]);
       end
比較用の関数を指定する。
    a = {}
    a[1] = { name="a", price=300 };
    a[2] = { name="b", price=100 };
    a[3] = { name="c", price=200 };

    function cmpfunc( a, b )
       return a.price <  b.price
    end

    table.sort( a, cmpfunc ); 

    for i=1, #a do
       print( a[i].price );
    end
___

■ foreach(イテレート)

   for t, val in pairs( members ) do
      for k, v in pairs(val) do
         print( k, v );
      end
   end

  while で利用する
   k, v = next( player1 );
   while (k) do
      print( v );
      k, v = next( player1, k );
   end
___

■ 配列(Array)



    


___

■ 配列

POINT 配列はテーブルのキーを数値にすることで利用する。 テーブルの特殊系にすぎない。 . Table{ Arr{} } -- Constructor 起動( この処理は必須 ) a = {};
  -- list 表記
  --    初期化リストつき
  local a = { "x", "y", "z" };
  print( a[1] );

数値 index として扱う
    a = {}

    -- 追加する
    a[ #a + 1 ] = "a"
    a[ #a + 1 ] = "b"

    -- イテレートする
    for i = 1, #a do
        local s = a[ i ]
        print( s )
    end    
配列の要素数をとるには 単項演算子( # ), table.getn(), table.maxn() をつかう
    -- 3
    a = { 2, 5, 6 }
    print( #a )

    -- 3
    a = { "a", "b", "c" }
    table.getn( a ); 

    -- 3
    a = { "a", "b", "c" }
    table.maxn( a ); 
WARNING テーブル内の最大の数値インデックス値を返す。 インデックスに数値が使われていない場合は 0 が返る
    -- 0
    local a = { a=1, b=2 }
    print( table.maxn( a ) )
    print( table.getn( a ) )
    print( #a ) )
maxn はテーブル内の最大の数値インデックス値を返す。 #, getn() は連続している最大の数値インデックス値を返す。
    local a = {}
    a[1] = 0;
    a[2] = 0;
    a[100] = 0;
    
    -- 2
    print( #a )
    print( table.getn( a ) )

    -- 100
    print( table.maxn( a ) )
  a[ "key" ] = 10;  // 文字 KEY による代入
  a[ 3 ] = 20;      // 数値を使用すれば, 配列としても可能
  b = a;            // 参照.
  print(b.x)        // == b["x"];  BAD b.0
b.y = "test"; print( b.y ); // index 1 の値を削除. b[3] = nil; POINT 開始 idx == 1 要素数は可変. 使う前の定義が必要 -> arr = {}; 空要素を取得しようとすると, nil が返る。 -- 疎行列 -- ( 配列index(索引)は連続している必要はない ) a[1] = 0; a[2] = 0; a[4] = 0; a[5] = 0; print( #a ) = 2; 変数と同じで、値のないインデックスを参照すると nil が返る。

    a = { "x", "y", "z" };
    -- nil
    print( a[4] );  
___

■ 追加

table.insert() でテーブルの末尾のインデックスに追加する。 テーブルの添え字は数値インデックスになる。
    tbl = {}

    -- index 1 に追加
    table.insert(tbl, "A")  

    -- index 2
    table.insert(tbl, "B")

    -- index3
    table.insert(tbl, "C")
index を指定した場合は、その位置に追加されて残りは後ろにシフトされる。
    -- D, A, B, C
    table.insert(tbl, 1, "D")
___

■ 削除

SYNTAX table.remove( table, number )
    local tbl = {}
    table.insert(tbl, "foo")  
    table.insert(tbl, "bar")    

    -- 要素ではなく index を指定する
    table.remove( tbl, "foo" );


    local tbl = { 2, 4, 6 }
    table.remove( tbl, 1 );
    print ( #tbl )

-- イテレートする。 for i=1, #a, 1 do print(a[i]) end table.foreach( t, func ); -- call func( idx, val );
WARNING 間違った field を指定した場合は, nil がかえるので, spellmiss が素通りする可能性あり.
___

■ 結合

SYNTAX table.concat (table [, sep [, i [, j ) 要素を指定した文字列で結合して返す
    a = {1,2,3}

    -- 1__2__3
    table.concat( a, "__" )

結合する要素の数を指定する
    -- 1__2
    table.concat( a, "__", 1, 2 )
___

■ 2次元配列

1次元配列を利用して, 2次元配列を作成する. 配列の要素を配列にする。
   m = {};
   m[1] = {};
   m[2] = {};

   m[1][1] = 10;

   print( m[1][1] );
___

■ Lua 言語の字句の構成

Lua が使用する, 内部 global変数. _VERSION
___

■ 値と型

[ 変数は型をもたず ], [ 値が型をもつ ] -> つまり 型自身はある. 変数には[ 宣言 ]は不要. -> 変数には型という概念がないから. 代入, 引数わたし, 関数の返値は すべて [ 参照 ]
___

■ 構文


___

■ comment

  -- comment

  WARNING 
  --- これはコメントではない
  --[[
    cmt ...
  ]]
___

■ 日本語対応

Manual では Unicode , UTF8 が対応とのこと. source code が S-JIS, Unicode で記述されていても, そのまま binary 列として渡される. SJIS を利用する場合は, [[日本語]] とすること. ( \ をEscape しない. ) WARNING さらにいうと, 環境に font がない場合もある.
___

■ 文字code

[ 文字という情報 ]を数値で表現する. それを 文字Code( 符号 ) という string.byte( s, i[, j] ); string.char( s, 1, 3 );
___

■ 文(Statement)

LuaProgram の実行単位のこと 文の区切りは ; または改行コード
    -- 代入文
    price = 40
    price = 40;
___

■ chunk

SYNTAX {stat [';']} 文の集合のこと。 Luaの実行の単位は chunk という Luaはチャンクを、可変個の引数を持つ無名関数の本体として扱う。 チャンクはバイナリ形式のコンパイル済みコードであっても良い 改行code == 空白 var = 40;
___

■ ブロック

SYNTAX do block end POINT 明示的なブロックは変数宣言スコープをコントロールするのに便利
    do
      chunk;
    end
C 同様, 外側の block での宣言した変数は有効になる。
    do
       local j = j or 10;
       print( j );
       do
    local k = 20;
    print( j, k );  -- 10 20
       end
       print( j, k );  -- 10 nil
    end
    print( j ); -- nil
___

■ 代入

POINT Luaは多重代入を許している { 左辺: 変数リスト }, { 右辺:式リスト} i, a[i] = i+1, 20 -- 多重代入. ( 先ずすべての式を評価する -> 最後に代入 )
___

■ String(文字列)


    文字列型は "", '' で囲む
    local s = "test"
    local s = 'test'

    -- 複数行にまたがるには [[ ]] でくくる
    local s = [[message
                test]]

    
___

■ 連結

    "aaa" .. "bbb"
___

■ 長さ

# でバイト数を返す
    -- 3
    print ( #"aaa" )

    -- 6( SJIS )
    print ( #"あいう" )

    -- 9( utf8 )
    print ( #"あいう" )

    -- 3
    string.len( "abc" )

    -- 9( utf8 )
    string.len( "あいう" )
___

■ 変換

"test" .. tostring( 1 ) -- 暗黙的に変換される "test" .. 1 -- Escape 文字使用可能 "foo\n" | 'bar\t' [[c:\foo\bar]] [[c:\foo \bar]]
___

■ 分割(split)

SYNTAX string.gmatch( string, pattern ) DESC split がないため gmatch で代用する。 gmatch はマッチしたすべての要素を順に返すイテレータ関数を返すため for - in と併用して文字列を分割する。

    local s = "d:/foo/bar/goo.txt";
    local a = {}
    for w in string.gmatch(s, "[^/]+") do
       table.insert(a, w);
    end

    for i=1, #a, 1 do
       print ( i .. " = " .. (a[i]) )
    end
___

■ 部分文字列

string.sub( string, s, e )
  local ret = string.sub( "aaa___bbb", 1, 3 );

  -- 7番目より後ろ
  local ret = string.sub( "aaa___bbb", 7 );
  print( ret );
___

■ match(検索)

SYNTAX string.match( string, pattern [, index ] ) DESC pattern にマッチする文字列を string から返す。 index が指定された場合は index の位置から検索をする。
    -- RET hello
    local ret = string.match("hello world", "%w+")

    -- RET f 
    string.match( "foobar", "[a-z]" );
___

■ find(インデックス検索)

SYNTAX string.find( string, regexp [, index ] ) RET start, end : マッチした文字列の開始, 終了位置インデックス nil : マッチしない場合 DESC regexp にマッチする文字列を string から検索して 開始、終了の index を返す。 index が指定された場合は index の位置から検索をする。
    -- 1, 4
    s, e = string.find( "test", "%a*");
    -- 4, 6
    local s, e = string.find ( "aaa___bbb", "___" )
-- 拡張子を返す
    path = "d:/foo/test.txt"
    local idx = string.find( path, '%.' )
    local ext = string.sub( path, 0, idx - 1 )    
    -- 1, 3
    local path = "c:/foo.txt"
    local s, e = string.find( path, "[Cc]:/" );
  string.upper();
  string.lower();
  string string.format("string %s", s)
    %-12s : 左寄せ.
    %+12d : [+-] 記号.
  string.gsub( s, ptn, d[, n] )

  s = string.gsub( "foo", "[a-z]", "c" );

  string.len( s );
  string.rep( s, n );  -- repeat
___

■ 反転

    -- "cba"
    string.reverse( "abc" )
___

■ include(require)


  -- 同一ディレクトリの lib.lua をロードする。
  require "lib"

  add(1, 2);
呼ばれる側
    function add( a, b )
      return a + b;
    end 
module (name [, ・・・]) モジュールをつくる。 作成されるのはテーブルであり、 package.loaded[ test ] というテーブルとして作成される。 または global テーブルに追加される。 またこのテーブルをカレントの関数の環境にする。 パッケージ名は _NAME 属性に設定される。
    test._NAME
名前は Python のモジュールと同じくネストすることもできる。
    module( a.b.c )
require (modname) 指定したモジュールをロードする。 package.loaded テーブルをまずはロードすみか検索する。 そうならば package.loaded[modname] を返す。 ローダが見つかれば、 C ローダのモジュールの検索先は package.loaders 配列を変更することで制御できる。 package.path を検索する。 C ローダが見つかると, modname を使ってコールをしてそれをpackage.loaded[modname] にセットする。 つまりロード先を C で実装できる。
___

■ Moduleの定義

SYNTAX module( "name", package.seeall ) require( "name", package.seeall ) DESC file を module として扱うように宣言.
    -- module 名がそのまま NameSpace || tbl ? になる.
    require( "test" );
    test.sum( 100, 16 );
モジュールの定義は 定義する側のファイルの頭でモジュール名を引数に module 関数を実行します。 以後、module 関数の引数で指定した名前の テーブルに環境が変更される   その副作用として グローバル環境で定義されている関数の呼び出し (組み込み関数の math.random() 等も含む) もできなくなってしまいます。 そのため、module 関数の引数の 2 番目に package.seeall を指定することで この対処が可能になっている -- ファイル mod_test.lua module("mod_test",package.seeall) value=2 function box_muller() local alpha=math.random() -- package.seeall のおかげで使える local beta =math.random() return math.sqrt(-2*math.log(alpha))*math .sin(2*math.pi*beta) end
___

■ 関数(Function)


  SYNTAX
    function ::= 
      function funcbody
    funcbody ::= 
      `(´ [parlist1] `)´ block end

  function 関数名( [引数list] ) 文 end


    function func(x)
       print(x)

       return 1;
    end
    local func = function(x)
       print(x)

       return 1;
    end

    local ret = func( 10 );
    print ( ret );
POINT Lua では全ての関数は値になる。 (関数もファーストクラスオブジェクト) 関数定義も命令のひとつ. Host から呼ぶことも, Lua 自身から呼ぶことも可能 関数定義は実行可能な式. 関数型の値を持つ 関数が呼ばれると、実引数リストは仮引数リストの長さに調節される ( 多ければ,きりすてられる, たりなければ, nil がセット ) POINT 関数定義も、[ 関数名の名前を持つ変数 ]に [ 関数の実体を代入 ]していることになる。 add = function(x, y) return x*y end add(x, y);
___

■ 関数呼び出し

POINT 複数の値をかえす f() -- 戻り値は0個に調節される g(f(), x) -- f()の戻り値は1個に調節される return f() -- f()の戻り値をすべて返す {f()} -- f()のすべての戻り値からなるリストを作る
___

■ 可変引数

SYNTAX [ function(...) ]
  function ( a, b, ... )
    a = select(5, ...);   -- 可変引数 5 番目取得.
  end
  string.format
function test(...)
   local arr = {...};
   for i=1, #arr do
      print( arr[i] );
   end
end
do test( "a", "b", "c", 10 ); end function fnMyUpper( s ) local l = string.len( s ); local str = string.upper( s ); return l, str; end do local len, s; len, s = fnMyUpper( "aiueo" ); print( len.."\t"..s); end
___

■ 複数の値を返す関数

( Stack を利用することで実現している Lua は複数の値を返すことができる。 関数は data を返す際に, push 代入する際に pop;
    x, y = foo();

  -- 実は pop している. 

POINT 次の実行文では, stack 内容は消去される. x, y = 1, 2; も同様 ( stack に 1, 2 を push してから x, y へ pop ) だから次のことができる。
     x, y = y, x;
___

■ return

SYNTAX return [ expression ] DESC 関数やチャンク (関数) から値を返すために使う POINT return, break は block の最後で利用できる。 function t.a.b.c:f (...) ... end t.a.b.c.f = function (self, ...) ... end POINT [ メソッド ]とは、暗黙の引数 self を余分に持つ[ 関数 ]
___

■ ラムダ関数(名前なし関数)

方針としては [ その場で 1 度しか利用しない関数 ]は, 名前なし関数にする. 登録済みの関数は 未使用になったら GC で回収される.
    a = {}
    a[1] = { name="a", price=300 };
    a[2] = { name="b", price=100 };
    a[3] = { name="c", price=200 };


    table.sort( a, function ( a, b ) return a.price > b.price end ); 

    for i=1, #a do
       print( a[i].price );
    end
___

■ 文としての関数呼び出し

( 副作用を許すため, 関数呼び出しは文として実行可能 ) stat ::= functioncall // 戻り値はすべて捨てられる. Lua は Luaで書かれた関数もCで書かれた関数も呼べる
___

■ Error 処理


  POINT
    error 関数は Lua interpreter を[ 終了 ]させる

  スクリプト内で error を利用することで
  明示的に Error を発生させる.
  Lua は組み込み拡張言語であるから, Lua の処理は Host 側からスタート。
  Error が発生すると, 制御が C に返る。


___

■ pcall

SYNTAX pcall( function, arg1, ... ) RET true : false : エラーが発生
-- エラー制御
   function test( s )
      print(s);
      error("Err");
   end

   if ( pcall( test, "foo" ) )then
      print("OK");
   else
      print("error");
   end

___

■ metatable


  metatable とは
  userdata, table への演算に対してどの関数を呼び出すのかを
  連想配列で表した表( テーブル )のこと。
  データ型はテーブルと同じで、userdata, table と関連づけるだけの違い。




  
___

■ MetaMethod とは演算子を独自処理におきかえる

POINT [ 演算子 ]を独自処理におきかえる.( operator のこと ) MetaMethod を利用することで実現している. tbl の値取得, 関数呼び出しの値を変更することも可能. OO では [ 演算子を独自に定義できる ]ことが特徴. {"pos" , getPos() } < -> tbl 経由で呼び出す. ? { data, Evt=Func } の組を MetaTbl として にセットすることで Lua に通知する。
___

■ event の種類

-- MetaMethod
   local data1 = { name="a", price=120}
   local data2 = { name="b", price=100}

   function add( op1, op2 )
      return op1.price + op2.price;
   end

   -- data1 の加算 + には myAdd を利用するように登録
   setmetatable( data1, { __add = add, ... } )
   print( data1 + data2 );
___

■ Overload

POINT metatable はある値( Object )に対して, 特別な演算を overload する際に便利。 スレッド、関数、ユーザーデータ型のオブジェクトはメタテーブルをもつ。 { KEY == Event , 値 = MetaMethod } 使いどころ その値に対して特殊な処理をした際の, 挙動を定義する 数値以外の値が加算のオペランドになった ---> Luaはメタテーブルの "__add" フィールドをチェック 加算を行うためにその関数をcall Object のふるまいを定義する metatable は、算術演算、関係比較、連結、長さ演算子、インデックス付けについて オブジェクトがどう振る舞うかを制御する メタテーブルがコントロールできる演算を以下のとおり 各演算のキーは、その名前の前に2つのアンダースコア `__´ が付く文字列
  __add,            a + b の時にコールされる
  __sub, 
  __mul, 
  __div, 
  __mod,
  __concat, 
  __len
  __tostring       print( a ); 

-- 配列に metatable を セットして, add を overload してみる
  setmetatable( metatableをセットする値, {metatable}), 
  metatable = {_add, 関数名 }
___

■ 環境table

環境は table のひとつ. thread に関連つけられた環境は, global環境と呼ぶ.
___

■ Class



___

■ クラスの定義

POINT Lua は Table を利用して Object をあらわす。 構造体としてとらえることも可能 Method の実体は Table の Field の値として関数があるだけ。 Lua Table を利用することで, Object を作成できる。 { data , method ... } キーをメンバ変数名とみなせば、構造体としても表現できる。 Method には InstanceData をわたしたい.
    file.open( file )  ---> file:open(); となる.
   -- MetaTable
   Colormeta = {
      --  + の演算はこの関数でオーバーライド
      __add = function(a, b) 
                local r, g, b = (a.r+b.r), (a.g+b.g), (a.b+b.b)
                return newrgb( r, g, b );
              end,

      -- 文字列表現
      __tostring = function(a) 
                      return string.format("rgb %3d %3d %3d", a.r, a.g, a.b ) 
                    end,
   }

   -- ctor
   function Color( r, g, b )
      local tbl = { r = r or 0, g = g or 0, b = b or 0 };

      -- 毎度設定しないとだめ
      setmetatable( tbl, Colormeta );
      return tbl;
   end

   -- テーブルを作成して返す
   g = Color(0, 255, 0);
   b = Color(0, 0, 255);

   -- MetaMethod を使う。
   cyn = g + b;
   print( cyn );
  function T.new(value)

    -- 
    local obj = {
      value = value,

      toString = function(self)
        return "T: value=" .. tostring(value)
      end
    }

    return obj
  end

  -- new clsFoo(); の模倣.
  obj = T.new(5)
  print( obj:toString() )

  obj2 = T.new(7)
  print( obj2:toString() )
___

■ メソッドの定義

POINT : を記述することで, メソッドのような記述ができる。 obj:function() とすると, 第一引数に暗黙のパラメータとして obj 自身がわたる。 実体は obj.function( obj ); と同じ。 ( 構造体もある意味で 連想 Table -> obj.key = val )
  String = {
      -- メンバ変数
      val = 3,

      -- { KEY , 関数body } でメソッドらしくする。
      -- . の代わりに : で代用する。
      toString = function(self)
                    return "value=" .. tostring( self.val )
                 end
      }
次のように使う
     String:toString();

     -- これと同じ
     String.toString( self );
[ : ] を利用した関数定義 function object:read( a, b, c ) -- self は local 変数 print( self ); end function object.read( self, a, b, c ) -- self は local 変数 print( self ); end 新規の型を定義できないため、クラスのインスタンスを作成するには コンストラクタに相当する関数内でテーブルを作成して返す。

    function Vector( x, y, z ) 
       -- インスタンスに相当するテーブルを作成
       local tbl = { x=x, y=y, z=z }

       -- メソッドを定義
       tbl.length = function( self )  
           return math.sqrt( self.x*self.x + self.y*self.y + self.z*self.z )
        end

       tbl.normalize = function( self )  
              local n = self:length()
              self.x = self.x / n
              self.y = self.y / n
              self.z = self.z / n
        end

       return tbl
    end


    -- インスタンスを作成
    local v = Vector( 1, 2, 3 )

    -- メソッドをよびだす
    v:normalize()
    local len = v:length()
    print ( len )


___

■ Closure

source code 上のまとまりのある単体. Cの関数を作成するとき、いくつかの値を関連付けて Cのクロージャ を作ることができる。 ( 関数に変数を付属させたもの関数のこと ) ( 関数内で使用するdataを関数内にとじこめる ) Table とは異なり, data を隠ぺいすることができる。 a = {} local x = 20 for i=1,10 do local y = 0 a[i] = function () y=y+1; return x+y end end クロージャはすべて同じ x を参照するが、それぞれ異なった y を参照する。 (y の解決を実行時の環境ではなく、 定義時の環境で行っているため. for i=1,10 do print(a[i]()) end -- 実行結果は 21 が 10 個表示される
___

■ Math(数値演算)


___

■ MathModule

    math.max(x, ...)
    math.min(x, ...)
    math.floor(x)
    math.ceil(x)
    math.abs(x)
    math.pi
    math.random
    math.sqrt
___

■ IO.FileSystem


  POINT
    CRT stdio を拡張したもの

  fp = io.input("text");

  io.input(); -- console に戻す.

  io.output("text");

  -- \n ふくまず
  io.write();  
  -- console に戻す
  io.output(); 

--  file handle 経由
do
   local file = io.open("d:/lua/test.txt", "r");

   if ( file ) then
      -- filehandle:read( format );
      -- [ *l | *a | *n ]
      local t = file:read("*a");
      print(t);
   else
      print("no file");
   end
end

    --  file handle 経由
   local fp = io.open("d:/lua/test.txt", "w");

   if ( fp ) then
      -- fp:read( format );
      -- [ *l | *a | *n ]
      local t = fp:read("*a");
      print(t);
   else
      print("no file");
   end

WARNING 当然ながら文字コードが SHIFT_JIS や UTF-8 は問題ないが UNICODE はうまく動かない POINT file 入出力 library も oo を利用する ( filehandle は userdata ) fp = io.open( file, "r" ); line = fp:read();

    f   = io.open( "test.txt", "r")
    out = io.open("out.txt","w")

    -- 各行を処理をする
    for line in f:lines() do
      out:write(line.."\n")
      print(line)
    end

    out:close()
    f:close()
___

■ OS

   


  OS が提供する機能を提供する.

  os.date()
  os.time()
  os.remove( filename );
  os.rename( filename );

___

■ Process

外部プロセスの実行は os.execute() を使う
  -- 処理はブロックされる
  os.execute( "ping localhost" );

  -- ブロックを回避するには start コマンドを使う。
  os.execute( "start notepad" );


  -- 終了コードをとる
  local ret = os.execute( "ping localhost" );
___

■ Type(Data型)



___

■ 型の種類

Data 型とは [dataをどう扱うか(どう見るか)] の形式 計算機内部では すべての情報は 数値として扱われる. 文字列型 . bit列 を 文字として解釈する. nil number string boolean table function thread userdata ( C のメモリブロック )
    -- 型をしらべる
    local n = "aaa";
    print ( type(n) );
number : double( luaconf.h で変更可能 ) usrdata: 任意の C の data を格納する. ( == 生の memblock ) -> ( 代入, 比較 )演算のみ定義 thread : 実行している thread を格納. ( coroutign の実装のために使用 ) Lua Thread と OS Thread は異なる. table : 連想配列. [ == KEY が数値以外に任意の値がOK ] table は異種混合可能. ( 関数をおくことも可能 ) この table が Lua での 唯一の data 構造. record を table を利用して, 表現してみる. field名 == index として利用する. a.test == a["test"]; table thread function usrdata の値は参照.
___

■ キャスト(cast)




  Luaは文字列と数値を実行時に自動的に変換してくれる。
     
    -- number -> string
    c = 10 + 20;
    String.print( c ); 

    Number -> 文字列演算 -> String
    string -> 数値演算   -> Number

  nr = nr + "1";
     nr += "35";   -- これはダメらしい.

文字列と数値の結合ができる
    -- "number = 10"
    "number = " .. 10
WARNING bool は .. で文字列に cast できない?
    str = str .. 10
POINT C では float -> int では自動的に少数部が切り捨てられる. Lua では数値という概念しかないので, 切り捨てられることはない. -- math.abs() の型 chk version を用意する.
    function myabs(n)
       if(type(n) ~= "number" ) then
          print(n);
          error("must be a number prm");
       end
       print(math.abs(n));
    end


    myabs( "10" );
WARNING だたし等号をとるときは, 同じ型である必要がある。
    if "107" == "107" then
      print ( "true" )
    end
___

■ 代入演算子 [ = ] の左側にかける[ 式 ]を [ 左辺値 ] という

loadstring("print(_VERSION)")() loadstring("print(_VERSION)") -- 戻り値は関数. POINT 戻り値として使用する関数を, 高階関数という. table を返して, すぐに利用する.
  function test()
     arr = { 1, 2, 3 };
     return arr;
  end
  do
     test()[2] = 10;
     print( test()[3] );
  end
___

■ GC

  Luaは自動的にメモリを管理する
  ガベージコレクタ を時々実行することで、自動的にメモリを管理する
  Luaはインクリメンタルマークアンドスイープコレクタを実装している
  ガベージコレクタ停止値 と ガベージコレクタステップ係数 を使うことができる
     -> usr が調整可能.

___

■ ガベージコレクションメタメソッド

ユーザーデータにガベージコレクタメタメソッドを設定する. ( hook みたいなもの ? ) 使う目的: [ Lua GC を 外部のリソースに利用ささせる. ] -> 独自に確保した work を解放する. -> finalizer と呼ばれる. メタテーブルに __gc フィールドをもつ, usrdata に以下の関数相当のことをする. function gc_event (udata) local h = metatable(udata).__gc if h then h(udata) end end
___

■ Cから実行する。


     C < --- lua_toXXX()              ---  Lua   ret = func( x, y );
     C  --- lua_pushXXX() return Nr; ---> Lua
pushXXX : 結果を stack に のせる. toXXX : スタック から値を取得 ( stack は取り除かれない ) Ret2 < --- ここから Lua は Nr 個を script の変数に順番に格納 ------- Ret1 ------- Arg2 ------- Arg1 -------

  WARNING 
    // C++ からリンクする時は "C" リンケージをすること。
    // Link エラーになる。
    
#include "lua.hpp"

#pragma comment(lib, "../../lib/lua51.lib")
#pragma comment(lib, "../../lib/lua5.1.lib")

int main()
{
  lua_State *s;

  s = lua_open();

  luaL_openlibs( s );
  luaL_dofile( s, "d:/test.lua" );

  lua_close( s );
  
  return 0;
}
ビルドする。
    shell> cl main.cpp 
Lua スクリプトを用意して実行してもらう。
    print "test lua"
___

■ Cの関数をバインドする


  POINT
   Lua < -> C で Data を交換するのは, すべてスタック経由
   Lua からの引数もスタック経由でうけとり、 C からの返値をスタックにのせる


int add( lua_State *s )
{
  printf( "call func\n" );

  // 第2引数をスタックから int として取得
  int n2 = luaL_checkint(s, -2);
  // 第一引数
  int n1 = luaL_checkint(s, -1);

  int ret = n1 + n2;
  
  //  戻値をスタックに積む
  lua_pushnumber( s, ret );
  
  // スタックに積んだ数を返す。
  return 1;
}


int main()
{
  printf( "test\n" );


  lua_State *s;

  s = lua_open();
  luaL_openlibs( s );

  // add
  lua_register(s, "add", add );

  //luaL_dofile( s, path.c_str() );
  luaL_dofile( s, "d:/work/pro/lua/script/test.lua" );

  lua_close( s );
  
  return 0;
}
___

■ C++のクラスをバインドする


    // テストクラス
    class Test 
    {
      int _x;
     public:
      Test(int x) : _x(x) {
        printf("ctor: %p, %d\n", this, _x);
      }
      ~Test() {
        printf("dtor: %p\n", this);
      }
      void talk() {
        printf("talk(), %p, %d\n", this, _x);
      }

      void *operator new ( size_t sz, void *mem ) {
        return mem;
      }
    };
メソッドをコールするために lua へバインドするための関数でラップする。

    static int l_talk(lua_State* L) 
    {
      // ユーザデータ(ポインタ)を Lua Script からもらう。
      Test* p = (Test*)lua_touserdata(L, -1);

      // メソッド本体をコール
      p->talk();

      // 戻り値の数
      return 0;    
    }
Lua から new をしたら, C++ 側では実際にオブジェクトを作成する。 さらにメソッドをフィールドアクセスの構文( p.method() )で呼べるように __index を指定したメタテーブルをオブジェクトに設定する。

    int l_new( lua_State *s )
    {
      // Lua 側から数値パラメータを一個もらう。
      int i = lua_tonumber( s, -1 );

      // オブジェクトを new して、そのポインタを Luaスタックに積む。
      void *p = lua_newuserdata ( s, sizeof( Test ) );
      void *q = new(p) Test( i );

      // クロージャで関連づけたテーブルを取り出し、
      lua_pushvalue( s, lua_upvalueindex(1));
      //  メタテーブルとして設定する
      lua_setmetatable( s, -2);


      // ポインタを Lua Script 側へ返す。
      // これで Lua 側からオブジェクトをハンドルできる。
      return 1;
    }
Lua からは次のように作成する。
      -- オブジェクトを生成して、ハンドルをもらう。
      -- Test テーブルの new メソッドをコールする。
      local p = Test.new( 5 );


      -- 操作したいハンドルを指定してメソッドをコールする。
      -- オブジェクト p に対して p.talk と書けるのはフィールドアクセス( __index )をオーバーライドしたから
      p.talk( p );


      -- : を利用することで、第一引数を省略できメソッド的な記述ができる。
      -- やっているのは上と同じ。
      p:talk();


      -- 別オブジェクトをつくる。
      local p2 = Test.new( 3 );
    void defclass( lua_State *s )
    {

      // クラスをテーブルとして生成
      lua_newtable( s );

            // ユーザデータで共有するメタテーブル用テーブル作成
            //  インスタンス毎に setmetatable される
            lua_newtable( s );

                // __index をオーバーライドすることで  obj.method() という記述した( フィールドアクセス )時に
                // メソッド用関数のテーブルを参照させる。
                // setfield によって値がポップするためコピーしておく。
                lua_pushvalue(s, -1);    // メタテーブル自身
                lua_setfield( s, -2, "__index");


                // クラスのメソッドをテーブルを登録しておく
                lua_pushcfunction( s, l_talk );
                lua_setfield( s, -2, "talk");


            // テーブルを上位値としてクロージャ生成
            // 後で new() をした時にテーブルを取り出し instance のメタテーブルとして設定する。
            lua_pushcclosure( s, l_new, 1);
            lua_setfield( s, -2, "new");


       // 生成したクラス(テーブル)を Test という名前でグローバル変数に公開
       lua_setglobal( s, "Test");
    } 
___

■ Reference




 



___

■ util

___

■ lua_type

SYNTAX int lua_type (lua_State *s, int index ); DESC index で指定した値の型を返す。
     LUA_TNIL
     LUA_TNUMBER
     LUA_TBOOLEAN
     LUA_TSTRING
     LUA_TTABLE
     LUA_TFUNCTION
     LUA_TUSERDATA
     LUA_TTHREAD
     LUA_TLIGHTUSERDATA
___

■ lua_typename

SYNTAX const char *lua_typename (lua_State *L, int tp); DESC lua_type で取得した型から型名を返す。
    int t = lua_type( s, idx );
    printf( "%d %s", idx, lua_type(s, t)  );
___

■ lua_gettop

SYNTAX int lua_gettop (lua_State *) DESC スタックトップのインデックスを返す。 インデックスは1から始まるのでスタックサイズを取得できる。
___

■ スタック操作

POINT 1つの関数内で使用できる, stack の大きさは 256 程度 limits.h MAXSTACK で変更できる。
___

■ lua_pop

SYNTAX void lua_pop (lua_State *L, int n); DESC stack 上位から [ N個 ]の要素を取り除く. POINT stack 数以上を削除すると, 空になる
___

■ lua_remove

SYNTAX void lua_remove (lua_State *s, int index); DESC 指定した有効なインデックスの要素を取り除き、 上の要素をずらして隙間を埋める 疑似インデックスは、実際のスタック位置でないため指定できない
___

■ lua_settop

SYNTAX lua_settop( lua_State *, int index ); DESC index 番目の要素を top にして それより上を削除 ( メタファは上を刈り取る ) 余計な値を除去する時に使う。 現在値より上段を指定すると nil で埋められる。
    // index 0 を指定するとスタックは空( というかインデックス位置が移動するため無効 )になる

      < - 現在地( 3 ) 
    -------    -------     
      A                
    -------     -------
      B                
    -------     ------- < - ( 0 番目 )
lua_settop( s, 2 );
         --------        --------
           key      -->
         --------        --------
          table
         --------        --------
           bbb             bbb   < -- 2 番目をトップに指定
         --------        --------
           ccc             ccc
         --------        --------
___

■ スタックからの取得

POINT Lua から C の関数を呼ぶときに Lua で引数を指定して C 側からスタックに積まれた引数を取得。 スタックの要素の位置は +- で指定できる。 -2 というのは stack 上位から2 番目の要素 + : 下から N 番目 - : 上から N 番目
    [      ]  < -  -1
    [      ]
    [      ]
    [      ]  < -   1
仮想スタックは Lua と Host が data を交換する Object Lua が C の関数をコールする際は, 以前のスタックを破壊しないように, 新規stackを作成する. スタックは関数ごとに用意される. ( というより, Arg 以下が隠される. ) lua_gettop() で確認できる。 stack は関数ごとに用意される. [ 関数の中では ] [ stack が 1 から利用 ]される. -> ( 厳密には 不要な部分が隠蔽される )
     3 param, 2 ret
     // prm
     ---
      3
     ---
      2
     ---
      1
     ---

     // ret ( 終わった時点で stack にのっている点に注意. )
     ---
      2
     ---
      1
     ---
___

■ lua_tonumber

SYNTAX lua_Number lua_tonumber (lua_State *L, int index); DESC index の位置にある値を lua_Number 型に変換して返す。 数値 または 数値に変換できる文字列である必要がある。 値を参照するだけで、スタックの数は変わらない。 RET 0 : 変換できなかった。 STACK [-0, +0, -]
    -- 1番目の引数から順番にスタックにつまれる。
    add( 100, 200 );

    ----------
       200
    ----------
       100
    ----------
    // C 側は引数をスタックから取得して何かの処理をして、必要なら結果をスタックにのせる。
    int l_add( lua_State *s ) {
      int arg0 = lua_tonumber( s, -2 );  // 上から 2 番目をとる
      int arg1 = lua_tonumber( s, -1 );  // 上から 1 番目をとる

      int ret = arg0 + arg1;

      lua_pushnumber( ret );             // スタックに結果をつむ
      return 1;                          // 結果の数を Lua に教える
    }
___

■ lua_touserdata

SYNTAX void *lua_touserdata (lua_State *L, int index); DESC 指定 index 値がフルユーザーデータ( または lightuserdata )であれば そのブロックのアドレスを返す lightuserdata であれば、そのポインタを返す どちらでもなければ null
    -- Window のポインタを受け取り、
    w = CreateWindow();

    -- ポインタ経由で操作してもらう。
    SetWindowText( w, "test" );
    SetWindowSize( w, 600, 400 );

    local w, h = GetWindowSize( w );
    l_createWindow( lua_State *) {
      lua_newuserdata( s );

      Window p = new Window();
      return 1;
    }

    l_setWindowText( lua_State *) {
      lua_touserdata( s, -2 );
      lua_tostring  ( s, -1 );

      p->setText( s )
    }
___

■ lua_tostring

SYNTAX const char *lua_tostring (lua_State *L, int index); DESC lua_tolstring を呼ぶのと同じ WARNING Lua -> C への 文字列の受け渡し( adress )は Lua の GC によって回収される可能性がある POINT 逆に C -> Lua ( lua_pushstring() ) は 文字列をコピーするので C 側での文字列のメモリは開放、変更をしてもよい。
___

■ lua_tolstring

SYNTAX const char *lua_tolstring (lua_State *L, int index, size_t *len); DESC 指定 index がさす値を 文字列に変換する.( stack 内が変化する ) index は [ 文字列 | 数値 ] を指す必要あり len != NULL: 文字数をセット. WARNING stack 内部の alignment された pointer をかえす ( GC される可能性あり )
___

■ lua_getglobal

SYNTAX void lua_getglobal( lua_State *s, const char *name ); DESC lua_getfield の限定版 グローバル変数 name の値をスタックに積む。 STACK [-0, +1, e] POINT マクロとして定義されている。 #define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, s) POINT ブロック外で定義した Var, Fn はすべて TblGlobal に存在する.
              -->
   --------        --------
                   fn | var
   --------        --------
    string          string
   --------        --------
     -- lua
      config = {
        width  = 600,
        height = 400,
      };
     // cpp
     {
       lua_getglobal( s, "config" );

       lua_getfield( s, -1, "width" );
       int v = luaL_checknumber( s, -1 );
     }
___

■ 生成

___

■ lua_createtable

SYNTAX void lua_createtable (lua_State *L, int narr, int nrec); STACK [-0, +1, m] DESC 空のテーブルを作成してスタックに追加。 The new table has space pre-allocated for narr array elements and nrec non-array elements. This pre-allocation is useful when you know exactly how many elements the table will have.
___

■ lua_newuserdata

SYNTAX void *lua_newuserdata (lua_State *, size_t size); STACK [-0, +1, m] DESC 指定 size の メモリをわりあて, そのアドレスをもつ fulluserdata をスタックにつむ。 fulluserdata は メモリブロックをあらわし, 独自の[ metatable ] を持つことができる。 table も metatable を持つことができる。 WARNING Lua が解放するので free() 禁止. GC 回収の際に memory address を変更する場合もあるかも POINT TblGbl , Tbl に値をセットしておくことで, [ 使用中 ]の扱いになるので, 解放はされない. local 変数だと問題がある。 data が必要なくなった場合は, [ __gc ] に指定する MetaMethod を利用する.
         --------        --------
                         userdata
         --------        --------
          number    -->   number
         --------        --------
  int create_rgb( lua_state *s )
  {
    char *data;
    // 4 Byte 確保. ( Lua 版 malloc と同じ )
    data = (char *)lua_newuserdata( s, 4 );

    memsset( data, 0, 4 );
    return 1;
  }
___

■ lua_newtable

SYNTAX void lua_newtable (lua_State *s); DESC 新しい空のテーブルを作ってスタックに積む lua_createtable(L, 0, 0) と同じ。
         --------        --------
                          table
         --------        --------
          number    -->   number
         --------        --------
___

■ lua_pushinteger

SYNTAX void lua_pushinteger (lua_State *s, lua_Integer n); DESC 値 n を持つ数値をスタックに積む
___

■ lua_pushnumber

SYNTAX void lua_pushnumber (lua_state *s, lua_Number n); desc n を stack top へ積む。 WARNING うけとる文字列は, Lua 側でGCされる可能性あり
                          
         --------        --------
                          number
         --------  -->   --------
          string          string
         --------        --------
___

■ lua_pushnil

SYNTAX void lua_pushnil (lua_State *s); desc nil 値を stack に積む.
___

■ lua_pushvalue

SYNTAX void lua_pushvalue (lua_State *L, int index); DESC 指定した有効なインデックスにある要素の[ コピー ]をスタックに積む 有効な index top でなくても OK STACK [-0, +1, -] lua_pushvalue( s, -1 );
                          
         --------        --------
                          table
         --------  -->   --------
          table           table
         --------        --------
___

■ lua_setfield

SYNTAX void lua_setfield (lua_State *L, int index, const char *key); STACK [-1, +0, e] DESC index で指定したテーブルに key の名前でスタック最上段の値を登録する。 値はポップされる。 table[ key ] = value という設定をする。 Lua の中では, newindex meta method が呼ばれる可能性がある. Tbl に G を指定すれば, VarGbl にも指定可能. As in Lua, this function may trigger a metamethod for the "newindex" event lua_pushnumber( s, 10 ); lua_setfield( s, -2, "test" );
         --------        --------
           10      -->    
         --------        --------
          table           table( test=10 )
         --------        --------
___

■ lua_settable

SYNTAX void lua_settable (lua_State *L, int index); DESC スタック最上位に値、キーをつみ、 index で指定したテーブルの位置にフィールドを追加する。 POINT lua_setfield() は特殊系
     --------        --------
       val      -->
     --------        --------
       key
      --------        --------
       table           table
     --------        --------
POINT newindex event の MetaMethod を呼ぶ.
___

■ lua_rawset

SYNTAX void lua_rawset (lua_State *L, int index); DESC lua_settable と同じだが 生の代入である点が異なる (メタメソッドを呼ばない)。 index は table を指す index stack から { KEY, VAL } == {下, 上}は pop される. --> field と同じと考えよう ^ ^/ VAL --- KEY これと同じ t = {a=10, b=20};
    lua_rawset( s, LUA_ENVIRONINDEX );
    lua_rawset( s, -3 );  // stack top から 3番目の table へアクセス
___

■ lua_rawget

SYNTAX void lua_rawget (lua_State *L, int index); DESC lua_gettable と同じ。 スタック最上段につんだキーの値で index が指すテーブルから値をとる。 metamethod は起動しない。 t = {a=10, b=20}; Lua でやっていることを, LuaAPI でしているだけ
    lua_rawset( s, LUA_ENVIRONINDEX );
    lua_rawset( s, -3 );  // stack top から 3番目の table へアクセス
POINT 指定した KEY がない場合は, nil をスタックトップへ返す。
___

■ lua_rawgeti

SYNTAX void lua_rawgeti (lua_State *s, int idxTbl, int n ); DESC lua_rawget のキーの値を整数の n に限定した関数。 table[ n ] の結果をスタックへ積む。 ( MetaMethod はよばれない ) STACK [-0, +1, -] POP tbl[n];
      lua_rawgeti( s, -2, 1 );
         --------        --------
                          value
         --------        --------
          string   -->    string
         --------        --------
          table           table
         --------        --------
___

■ lua_getfield

SYNTAX void lua_getfield (lua_State *L, int index, const char *k); desc index が指す table["k"] の値を stack top へ積む。 key は stack top の値 field 名を指定できるのが point lua_rawset( s, LUA_ENVIRONINDEX ); POP KEY の値に対応する VAL POINT 指定した KEY がない場合は nil を返す。
              -->
   --------        --------
                    number
   --------        --------
     tbl             tbl
   --------        --------
    // グローバルテーブルにアクセス
    lua_getfield( s, LUA_GLOBALSINDEX, nameKey );
___

■ lua_gettable

SYNTAX void lua_gettable (lua_State *L, int index); DESC キーとなる値をスタックトップへつむ index が指す テーブル["key"] の値をスタックが積まれ、 キーの値はスタックから捨てられる。 ( また MetaMethod の index イベントがトリガーされる ) STACK [-1, +1, e] Ex. lua_rawset( s, LUA_ENVIRONINDEX ); POINT lua_getfield() は lua_gettable() のキーの型を文字列に限定した関数 指定した KEY がない場合は nil を返す.
              -->
   --------        --------
     key             value 
   --------        --------
    table            table
   --------        --------
    void lua_arraygeti( lua_state *s, int tblindex, int i )
    {
      // stack 最上位に 配列の index をセット
      lua_pushnumber( s, i );
      lua_gettable( s, tblindex );
    }
___

■ lua_insert

SYNTAX void lua_insert (lua_State *L, int index); STACK [-1, +1, -] DESC スタック最上段の値を index の位置へ移動する。 index の位置より上の値は上へシフトする。
              -->
   --------        --------
    string           number
   --------        --------
    number           string 
   --------        --------
    table            table
   --------        --------
___

■ lua_setglobal

SYNTAX void lua_setglobal (lua_State *L, const char *name); DESC スタック最上段の値を指定した名前でグロバール変数として登録する。 登録する値はスタックからポップされる。 関数がpushされていれば関数に名前をつけて公開することになる。 STACK [-1, +0, e]
     #define lua_setglobal(L,s)   lua_setfield(L, LUA_GLOBALSINDEX, s)    
lua_setglobal( "testfunc" )
         --------        --------
         function   -->    
         --------        --------
          table           table
         --------        --------
___

■ lua_pushcfunction

SYNTAX void lua_pushcfunction (lua_State *L, lua_CFunction f); STACK [-0, +1, m] DESC 関数へのポインタを受け取り、関数型のLua値をスタックに積む 関数のシグネーチャは一致させること。 POINT lua_pushcclosure(L, f, 0) と同等 これによって、Lua Script 内の任意の場所から関数呼び出しができる。 POINT
    #define lua_pushcfunction(L,f)  lua_pushcclosure(L,f,0)
    #define lua_register(L,n,f)  (lua_pushcfunction(L, f), lua_setglobal(L, n))
___

■ lua_register

DESC C の関数を lua の関数として登録する
     lua_register( s, l_func, "func");
___

■ lua_pushcclosure

SYNTAX void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n ); STACK [-n, +1, m] DESC Cのクロージャをスタックへつむ。 このとき関連した値を設定できる。 関連づける値は先にスタックへ積んでおく。 クロージャが作成されるとこの値はスタックからポップされる。 lua_pushcclosure ( s, fn, 2 );
         --------        --------
          arg1    -->    
         --------        --------
          arg0     -->   function(arg0, arg1)
         --------        --------
          table           table
         --------        --------
           aaa             aaa
         --------        --------
___

■ lua_pushlightuserdata

SYNTAX void lua_pushlightuserdata (lua_state *s, void *p); DESC lightuserdata(ポインタ)をスタックに積む POINT lightuserdata とは host object のポインタのこと 作成はせず、メタテーブルも持たず、(作成しないので) 回収もされない
    // C 側で Window をつくり
    int CreateWindow( lua_State *s )
    {
        void *p = new Window( 1 );
        lua_pushlightuserdata( s, p );
        
        return 1;
    }

    // 操作させる
    int SetWindowSize( lua_State *s )
    {
      Window* p = (Window *)lua_touserdata(s, -1); 
      int i = lua_tonumber(s, -2); 
      p->setSize( i );
    }    
    -- lua
    local p = CreateWindow();
    SetWindowSize( p, 100  );
___

■ C Closures

C の関数を作るときに、特定の値を関連づけることができる。 これらは upvalue と呼ばれる。 upvalue は関数をコールされたときに参照できる。 参照へのインデックス( 最大 256 )は lua_upvalueindex を利用する。
___

■ メタテーブル

通常のテーブルと同じだが、 メタテーブルのキーに対して, 関数などを設定することで + などの演算を上書きして 独自の動作をさせることができる C++ での operator +() と同じ。 Lua の各値はメタテーブルをもつ。 クラスのインスタンスを作ったときに メタテーブルを設定しておくと + などで独自の設定ができる。 メタテーブルのキーは getmetatable() でリストできる。 Every value in Lua can have a metatable. This metatable is an ordinary Lua table that defines the behavior of the original value under certain special operations. You can change several aspects of the behavior of operations over a value by setting specific fields in its metatable. For instance, when a non-numeric value is the operand of an addition, Lua checks for a function in the field "__add" in its metatable. If it finds one, Lua calls this function to perform the addition. We call the keys in a metatable events and the values metamethods. In the previous example, the event is "add" and the metamethod is the function that performs the addition. You can query the metatable of any value through the getmetatable function. You can replace the metatable of tables through the setmetatable function. You cannot change the metatable of other types from Lua (except by using the debug library); you must use the C API for that. Tables and full userdata have individual metatables (although multiple tables and userdata can share their metatables). Values of all other types share one single metatable per type; that is, there is one single metatable for all numbers, one for all strings, etc. A metatable controls how an object behaves in arithmetic operations, order comparisons, concatenation, length operation, and indexing. A metatable also can define a function to be called when a userdata is garbage collected. For each of these operations Lua associates a specific key called an event. When Lua performs one of these operations over a value, it checks whether this value has a metatable with the corresponding event. If so, the value associated with that key (the metamethod) controls how Lua will perform the operation. Metatables control the operations listed next. Each operation is identified by its corresponding name. The code shown here in Lua is only illustrative; the real behavior is hard coded in the interpreter and it is much more efficient than this simulation. All functions used in these descriptions (rawget, tonumber, etc.) are described in §5.1. In particular, to retrieve the metamethod of a given object, we use the expression metatable(obj)[event]
___

■ lua_setmetatable

SYNTAX int lua_setmetatable (lua_State *L, int index); DESC index で指定したオブジェクトにスタック最上段のテーブルをメタテーブルとして設定する。 最上段のテーブルはPOPされる。 lua_setmetatable( s, -2 );
         --------        --------
          table     -->    
         --------        --------
         userdata        userdata(table)
         --------        --------
           aaa             aaa
         --------        --------
___

■ luaL_newmetatable

SYNTAX int luaL_newmetatable (lua_State *L, const char *tname); DESC registory( table ) に KEY [ tname ] があれば, 0 を返す. そうでなければ, userdata の metatable として使う 新しい table を作る. registory tname に関連づいた値( VAL )を stack に積む.
___

■ lua_getmetatable

SYNTAX int lua_getmetatable (lua_State *L, int index); DESC index がさすオブジェクトが持つ metatable を stacktop へつむ. RET 0 : 失敗。index が無効。または 指定したオブジェクトが metatable をもっていない。
___

■ 型チェック

WARNING [ 型を調べる ]ことで適切な処理をする スタックの操作を間違えると処理がとまる。
___

■ lua_isstring

___

■ lua_isfunction

___

■ lua_istable

SYNTAX int lua_istable (lua_State *L, int index); DESC 指定した index のさす値がテーブルであれば1、そうでなければ0を返す
___

■ lua_isnil

SYNTAX int lua_isnil (lua_State *L, int index); DESC 指定 index の値が nil ならば 1 else 0
___

■ luaL_checkstring

SYNTAX const char *luaL_checkstring (lua_State *L, int narg); DESC 関数の第 narg 引数が文字列であるかをチェックし その文字列を返す チェックに不合格ながらエラーをなげる。 POINT Lua -> C
___

■ luaL_checknumber

SYNTAX lua_Number luaL_checknumber (lua_State *L, int narg); DESC 関数の第 narg 引数が数値であるかをチェックし その数値を返す stack から値を取得するので, 関数呼び出しでなくても利用可能. この場合は stack 全体を index 指定することになる. 関数の引数は指定した順番に stack にのる。 POINT スクリプトの引数のチェックができる -> number expected, got string
___

■ luaL_typerror

SYNTAX int luaL_typerror (lua_State *L, int narg, const char *tname); DESC 次の message を出力する 型に対してアサートする。
     < location>: bad argument < narg> to < function> (< tname> expected, got < realt>)
___

■ luaL_checkudata

SYNTAX void *luaL_checkudata (lua_State *L, int narg, const char *tname); DESC 関数の第 narg 引数が [ 型 tname ] のユーザーデータであるかチェックする
___

■ その他

___

■ lua_error

SYNTAX int lua_error (lua_State *L); STACK [-1, +0, v] DESC Lua のエラーを発生させる スタックトップの値がエラーメッセージに使われる。 long jump を利用しないため、戻ることはない。
___

■ luaL_dofile

SYNTAX void luaL_dofile( s, const char *path ); DESC path から lua file を読み込む. function は [ load ] する && 実行文は そのまま[ 実行 ] -> LUA_GLOBALSINDEX がさす table に格納される = { "nameFunction", funcbody }; 関数 はたぶん reload される ? -> table の要素数を取得すれば OK #define luaL_dofile(L, fn) (luaL_loadfile(L, fn) || lua_pcall(L, 0, 0, 0))
___

■ luaL_dostring

SYNTAX luaL_dostring( s, "code..."); DESC C言語から Lua interpreter 呼んで, 処理をする。 RET 0 : 成功 !0 : 失敗 POINT Lua での制御タイミングを提供する。
___

■ luaL_loadfile

SYNTAX int luaL_loadfile(lua_State *L, const char *filename); DESC ファイルから LuaChunk をロードして compile した Chunk を Stack に積む
___

■ lua_call

SYNTAX void lua_call(lua_State *s, int nrArg, int nrRet ); DESC Lua 関数を C からコールする。 コールする関数と引数の順番にスタックへ積む。 関数の戻値は順番通りに (最初の戻値が最初に) スタックに積まれる PUSH 返値( nrArg で指定 , LUA_MULTRET の場合は, すべての返値がかえる )
    // 引数と関数がポップされて、結果がスタックにのる。
      lua_call( s, 2, 1 );
         --------        --------
           arg      -->
         --------        --------
           arg
         --------        --------
         function          ret
         --------        --------
POINT nrArg : Lua は nrArg + 1 に関数があることを知る. ( 間違えると落ちる. ) func( arg1, arg2 ) には順番に Stk からセットされる. nrRet : Lua に 何個の返値を Stk に積むか教える. ( -> 嘘つくと nil がつまれる ) // 以下の Lua Code と等価なことを C でやってみる.
    ret = f("test", t.x, 14)

    // Lua の関数は LUA_GLOBALSINDEX に登録されている
    lua_getfield(s, LUA_GLOBALSINDEX, "f");
    lua_getglobal( s, "f" );   // これは同じ
    

    // 第一引数をセット
    lua_pushstring(s, "test");                          

    // table も LUA_GLOBALSINDEX にある
    lua_getfield(s, LUA_GLOBALSINDEX, "t");
    lua_getfield(s, -1, "x");                 /* t.xの結果(2番目の引数)を積む */
    lua_remove(s, -2);                           /* スタックから `t' を取り除く */

    // 第3引数
    lua_pushinteger(s, 14);

    // 3個の引数と1個の戻値で関数をコール
    lua_call(s, 3, 1);

    // Lua は global 変数は table[ KEY = VAL ] という特性をうまく利用している.

    // グローバル変数 a に代入
    lua_setfield(s, LUA_GLOBALSINDEX, "ret");      

___

■ lua_pcall

SYNTAX int lua_pcall(lua_State *s, int nrArg, int nrRet, int errfunc); DESC Protected Mode で関数をコールする。 エラーがなければ, lua_call と同じ処理。 エラーが発生すると、エラーメッセージをスタックへ積みエラーコードを返す。 errfunc で指定したエラーハンドラー関数があればエラーメッセージを引数に呼ばれる。 スタックトレースなどの追加情報をいれるために使う。 RET 0 : 成功 N : 失敗( lua.h ) POINT 失敗した場合は, lua_pop() する
___

■ lua_replace

SYNTAX void lua_replace (lua_State *L, int index); DESC スタックトップの要素を指定した位置に移動する. ( 他の要素は変わらない点に注意. ) ------ ------ string ------ ------ 20 20 ------ ------ 30 string ------ ------ lua_repalce( s, 1 );
___

■ lua_getfenv

SYNTAX void lua_getfenv (lua_State *s, int index); desc 指定した index の値の環境テーブルをスタックに積む PUSH 指定 index がさす table
___

■ lua_setfenv

SYNTAX int lua_setfenv (lua_State *s, int index); DESC index が指す値が 関数, thread, userdata ならば, stacktop の 環境テーブルを新しい環境として set する. POP stacktop の EnvTable
___

■ luaL_openlibs

SYNTAX void luaL_openlibs (lua_state *s); DESC 指定したステートにすべての標準Luaライブラリを開く String.print() などに利用すること C SRT で実装されている.
___

■ luaL_getmetatable

SYNTAX void luaL_getmetatable (lua_State *L, const char *tname); DESC registory( == table )の名前 tname に関連付けられたメタテーブルをスタックに積む PUSH tname に関連つけられた metatable
___

■ luaL_register

SYNTAX void luaL_register( lua_State *L, const char *libname, const luaL_Reg *l); DESC stack top にその table をおく libname がNULLでなければ新しいテーブル t を作成し、 それをグローバル変数 libname の値として設定し POINT Lua関数名 が KEY, Host関数 が VAL の Table
___

■ lua_rawequal

SYNTAX int lua_rawequal (lua_State *L, int index1, int index2); DESC index1 と index2 がプリミティブに等しい (つまりメタメソッドを呼ばない) とき1を返す。 そうでなければ0を返す。 どちらかのインデックスが有効でないときも0を返す。
___

■ metatable(MetaMethod)


  POINT
    MetaMethod を利用して, Lua を拡張(カスタマイズ)できる。


___

■ 自分で作成した型を調べる

type( data ) == "table" if ( getmetatable( g ) == rgbmeta ) then print("custom data"); end
___

■ 配列の上限値を設定する

( MetaMethod を利用することで テーブル要素の参照をカスタマイズする __index, __newindex を上書きする. __index : val = tbl["name"]; // 参照. __newindex : tbl["name"] = "foo"; // 代入 MetaMethod の定義中に, MetaMethod を呼ぶのを防ぐのは, rawget, rawset() -- rawget( tbl, idx ); val = tbl[idx] -- rawset( tbl, idx, val ); tbl[idx] = val -- -- MetaTbl -- この tbl EventKey に対して OverWrite 関数をセットする. tblTest = { limit = 3 }; -- -- tbl を参照する [] 演算子を overwrite する -- tblTest.__index = function( t, idx ) if ( idx > tblTest.limit ) then error("invalid dana idx"); end return rawget( t, idx ); end -- メタテーブルをセットする。 tt = {} setmetatable( tt, tblTest ); -- テスト print( tt[10] );
___

■ luaRef


___

■ rawget

SYNTAX rawget(table, key) table … テーブル型 key … 任意の型 DESC メタメソッドを用いずに テーブルtableのkeyをキーとする要素の値(table[key])を返す。
___

■ dofile

SYNTAX dofile( string file ) DESC filenameで指定されたファイルを読み、Luaスクリプトとして実行する。 file の指定がない場合は stdin から読む。 RET スクリプト全体の返値
___

■ error

SYNTAX error (message [, level]) DESC 最後に保護された関数呼び出しを終了し、 message をエラーメッセージとして返す
___

■ setmetatable

SYNTAX setmetatable (table, metatable) DESC table の metatable を変更する. RET table POP Ex. setmetatable( t, nil ); table[ t ]から metatable を除去する. POINT WARNING
___

■ print

SYNTAX print( arg ... ) DESC tostring で[ 文字列に変換 ]してから標準出力 (stdout) に表示 BAD print 10;
___

■ GarbageCollection

文字列など,登録されないものを, 回収する. Lua が Table を扱う仕組みについて, かんがえる table data は 内容が同一でも, 異なるworkに確保される. [ 変数はdataの場所を参照しているだけ ]
___

■ collectgarbage

SYNTAX collectgarbage( string opt [, number arg ] ) DESC GC を実行する。
___

■ その他



___

■ DEBUG

local v = 0; function testHook() print("Debug v = "..v); end -- 実行文がよばれる直前に testHook を呼ぶ. debug.sethook( testHook, "l" ); v = v + 1; POINT 最終的にスタックは元の状態に戻っている これは良いプログラミング作法
___

■ Coroutine(Co-routine)

複数の coroutine を作成できるが, 平行して動作することはできない. 互いに譲りあい( yield ) ながら作業をする。 協調的 multithread OS が CPU の実行を切り替えながらする作業を, PreemptiveMultiTask という. 先制. ( 先買権 == はやいもの勝ち ) [ 実行処理自体 == worker ]が 切り替えの合図を送るのが, NonPreenptiveMultiTask だから協調 ( だから yield ) POINT Coroutine とは 実行を一時中断して, 後で再開する仕組みのこと。 自分で中断を宣言することが、 OS の管理する multithread とは異なる。 自分で yield() をコールして初めて中断される。
     Coroutign 作成. ( worker ) // thread object をかえす.
     thread = coroutine.create;

     2. main() 関数にわたす. ( Job )
     main( thread, prm ... );

     3. coroutine を稼働させる.
     coroutine.resume() で稼働させる.

     4. 終了をまつか, yield を実行する.
条件式は任意の値OK.( false と nil は共に偽 )
___

■ Luaのつかいみち

設定ファイルとして扱う Lua format を利用する
      Var=Val;( これを自分で解釈( Interprete )する )
      -- lua でグローバル変数を設定。
      var=10;
foo.cpp
      lua_getglobal( s, "var" );  // globalTbl から var key stack にのせる
      luaL_checknumber( s, -1 );  // stack から値を取得する.
C から lua のグローバル変数を設定する。
    lua_pushstring(s, "test");
    lua_setfield(s, LUA_GLOBALSINDEX, "name");
___

■ C 言語が主体

指定したところで, Lua にうつり, 処理がおわったら Lua から戻る。 ある処理における Callback の際に使う。 MVC でいうところの Control を Lua から制御する Controler の機能を Lua に公開する Controller, Data ともに C 側にある
___

■ Lua が主体

Lua 側に data, Controler を配置. ( Lua の data 構造を利用可能. ) 設定 file は Lua 変数を扱うだけになる. Gui は Lua でサポートされる必要がある. Controller, Data ともに Lua 側にある.
___

■ hash

Hash とは, 文字列を数値に変換したもの. ( 検索する際に数値に変換して高速に検索する ) 均等に分布するのが良い Hash 関数。 比較を用意にすることが目的. Lua は内部に Hash 関数をもつ Lua には Switch 文がない. ( if-elseif ... | table )で代用.
___

■ _G

DESC グローバル環境を保持するグローバル変数 [ Lua の環境 ]と呼ばれる, global 変数をもつテーブルのこと。 POINT __index : field に値を入れる時に使用される method. a = 1; < -> _G.a = 1;
___

■ registory

registory とは 定義済みの [ table ] 好きなLuaの値を格納するために [ Cのコードから ]使うことができる. 疑似 index [ LUA_REGISTRYINDEX ]に置かれている KEY が重複しないように注意すること. Cオブジェクトのアドレスを持つライトユーザーデータ を用いるとよい.
___

■ lua_checkstack

SYNTAX int lua_checkstack (lua_State *L, int n ); DESC スタックに n の空きがあるかチェックする。 チェックするだけでスタックのサイズは変更しない。 STACK [-0, +0, m] RET false : スタックに n 個の空きがない。
___

■ table に weakReference の設定をする

POINT ( table には 予約済みの field がある ) [ __mode ] field に "k" を含む -> KEY が weakReference [ __mode ] field に "v" を含む -> VAL が weakReference
___

■ 擬似インデックス

スタック内に無いいくつかのLuaの値に[ Cのコードから ]アクセスするためのもの stack 以外にある Lua が管理する値を 指すINDEX どの関数も 疑似インデックス と呼ばれる有効なインデックスを受け付ける LUA_GLOBALSINDEX : スレッドの環境 (グローバル変数がある場所) LUA_ENVIRONINDEX : 実行中の C の関数の環境がある 擬似インデックス
















NINJAIDX 18