(ルーア)はスクリプト言語およびその処理系の実装で、主にのコンピュータ科学科 () および/または同大学附属研究所のTecgraf/PUC-Rioに所属するロベルト・イエルサリムスキー 学位論文、学術論文 ()。学位論文、学術論文 、、らによって設計開発された。
手続き型言語として、またプロトタイプベースのオブジェクト指向言語としても利用することができ、関数型言語としての要素も併せ持っている。
名称の由来 Luaという名前は、ポルトガル語の「月」に由来する。もともとLuaはブラジルの石油会社であるペトロブラス内部でデータ入力用に開発された言語DEL (data entry language) と、レポート生成用に開発されたSOL (simple object language) の2つの簡易言語に由来する。SOLがポルトガル語で太陽を意味することから、新しい言語の名称はLua(月)になった。
概要 Luaは、C言語のホストプログラムに組み込まれることを目的に設計されており、高速な動作と、高い移植性、組み込みの容易さが特徴である。いったんバイトコードにコンパイルされ、Lua VMで実行される。LuaJITは The Computer Language Benchmarks Game によると、動的型付けのスクリプト言語では最速の言語・処理系である。
では2007年に人気が急上昇し、2011年6月には10番目に人気なプログラミング言語になったが、その後は人気が下がっている。2009年2月の調査で、ゲーム開発者がイベントスクリプト等の内部処理に利用する言語として、最も利用例が多いと報告されるなど、はゲーム産業での利用が広がっているSatori » The Engine Survey:General results。2013年3月以来、ウィキメディア財団のサイトではLuaをサポートしている。
MITライセンスのもと配布されている。
特徴 Luaの特徴としては、汎用性が高いが比較的容易に実装が可能である、というものである。実際のところLuaは、オブジェクト指向などといった他の要素としての働きを明白にはサポートしていないが、サポートしていない範囲においても容易に拡張が可能である。また前述のような、動作の高速性や優れた移植性なども大きな特徴である。
文法的な特徴としては、Pascalによく似た構文を採用していること、コルーチン(協調的マルチタスク)のサポート、数値型は整数と浮動小数点数の区別がないこと(ただしLua 5.3では整数型が導入された)、関数を変数として扱えることなどが挙げられる。
Luaはいわゆる汎用スクリプト言語であり、特定の用途に限定されない性質を持つが、同じく汎用スクリプト言語であるPerl、Python、Rubyと比較して高速に動作する。これはLuaの理念である、簡素、高効率、高移植性を目指した実装の産物である。また、Luaにおけるテーブル(連想配列)の実装はかなり最適化されており、特にキーに数値のみを使用した場合は、単純な配列としてさらに高速に動作するようになる。
Lua 5.0以前はメモリ管理にマーク & スイープ方式のガベージコレクションが使用されていたが、Lua 5.1ではメモリ管理にインクリメンタル・ガベージコレクションが採用され、リアルタイム用途における性能の改善が図られている。ガベージコレクションの実装形態も Lua の高速動作および高リアルタイム性能に一役買っている。
LuaJIT LuaのJITコンパイラである LuaJITがMike Pallにより開発されている。動的型付けであるにもかかわらず、Javaよりも少し遅くなる程度の速度で動いている。静的単一代入などをつかった高度な最適化が行われており、バイトコードを実行する場合と比べて、数倍から数100倍の高速化が期待できるhttps://luajit.org/performance.html。
Luaの歴史 Lua 1993年7月28日 - Lua 1.0 リリース。 1995年2月7日 - Lua 2.1 リリース。 1997年7月1日 - Lua 3.0 リリース。 2000年11月6日 - Lua 4.0 リリース。 2003年4月11日 - Lua 5.0 リリース。MITライセンスの採用。 2006年2月21日 - Lua 5.1 リリース。インクリメンタルGCの採用。 2008年8月22日 - Lua 5.1.4 リリース。 2010年5月14日 - Lua 5.1.4-2 リリース。 2011年12月16日 - Lua 5.2.0 リリース。ビット演算ライブラリをサポート。 2012年6月14日 - Lua 5.2.1 リリース。 2013年3月27日 - Lua 5.2.2 リリース。 2013年12月7日 - Lua 5.2.3 リリース。 2015年1月6日 - Lua 5.3.0 リリース。整数型およびビット演算子のサポートなど。 2020年6月29日 - Lua 5.4.0 リリース。
LuaJIT 2005年9月8日 - LuaJIT 1.0.3 リリース。最初の公開版。 2006年3月13日 - LuaJIT 1.1.0 リリース。Lua 5.1対応。 2006年6月24日 - LuaJIT 1.1.2 リリース。 2007年5月24日 - LuaJIT 1.1.3 リリース。 2008年2月5日 - LuaJIT 1.1.4 リリース。 2008年10月25日 - LuaJIT 1.1.5 リリース。 2010年3月28日 - LuaJIT 1.1.6 リリース。 2011年5月5日 - LuaJIT 1.1.7 リリース。 2012年4月16日 - LuaJIT 1.1.8 リリース。 2012年11月8日 - LuaJIT 2.0.0 リリース。 2013年2月19日 - LuaJIT 2.0.1 リリース。 2013年6月3日 - LuaJIT 2.0.2 リリース。 2014年3月12日 - LuaJIT 2.0.3 リリース。 2015年5月14日 - LuaJIT 2.0.4 リリース。 2017年5月1日 - LuaJIT 2.0.5 リリース。
コード例 Hello World print("Hello World")
Hello World
挿入ソート -- `--´から行末までコメント local tabSort = {5, 3, 1, 4, 2} -- `{´と`}´はテーブルコンストラクタ for ind = 2, #tabSort do -- `#´は長さ演算子であり、`#tabSort´はテーブルtabSortのサイズ(ここでは5)を返す for innerIdx = ind, 2, -1 do -- ステップ -1 で ind から 2 まで逆向きに繰り返す(負のステップは減算を意味する) if tabSort[innerIdx - 1] <= tabSort[innerIdx] then break end -- innerIdx と innerIdx - 1 の位置にある値を入れ替える tabSort[innerIdx], tabSort[innerIdx - 1] = tabSort[innerIdx - 1], tabSort[innerIdx] end end -- ソート済みの結果を空白区切りの文字列として作成して出力 local res = ''; for ind = 1, #tabSort do res = res .. tabSort[ind] .. ' ' end; print(res)
1 2 3 4 5
コルーチン コルーチンは状態遷移を記述するのに便利である。
-- Lua コルーチンの例:非同期の状態遷移を同期的に記述する。
-- 1 を返すと「動作継続」を示す。0 を返すと「完了」を示す。 local function doAction() -- 4 フレーム分左へ移動する。 for idx = 1, 4 do print("Move Left " .. idx) coroutine.yield(1) -- yield 1:次のフレームで続行する(1フレーム分のステップを示す) end -- 1 フレーム分一時停止する。 print("Pause") coroutine.yield(1) -- 1フレーム分のポーズを示す -- 3 フレーム分右へ移動する。 for idx = 1, 3 do print("Move Right " .. idx) coroutine.yield(1) -- 1フレーム分のステップ end print("End") return 0 end
local doActionAsync = coroutine.wrap(doAction)
-- コルーチンの動作テスト。 -- 実際の使用ではメイン/ゲームループからフレームごとに1回呼び出す。 -- ループはコルーチンを1回ずつ進め、0 を返したら停止する。 while doActionAsync() ~= 0 do -- コルーチンが 0 を返すまで繰り返し呼び出す -- ここは空。実際のフレームループではエンジンに戻り、次のフレームで再度呼び出す。 end
Move Left 1 Move Left 2 Move Left 3 Move Left 4 Pause Move Right 1 Move Right 2 Move Right 3 End
正規表現 LuaはPOSIXやECMAScript標準の正規表現とは異なる独自のカスタムパターンマッチングをサポートするスクリプト化可能なアプリケーションに Lua を組み込む。 local myTable = { -- 解析する入力行 "Gnome,160,30", "Sylph,100,70", "Salamander,200,20", "Ondine,140,60", } for idx = 1, #myTable do -- 各行ごとに -- "([^,]+)" はカンマ以外の文字が1回以上続く部分をキャプチャ(名前) -- "," はカンマに一致する。カンマを "%" でエスケープする必要はない -- "([^,]+)" はカンマ以外の文字が1回以上続く部分をキャプチャ(HP) -- "," はもう一つのリテラルなカンマに一致 -- "(.+)" は行の残り全体をキャプチャ(MP) local name, hp, mp = string.match(myTable[idx], "([^,]+),([^,]+),(.+)") print(string.format("Name = %q, HP = %d, MP = %d", name, tonumber(hp), tonumber(mp))) end
Name = "Gnome", HP = 160, MP = 30 Name = "Sylph", HP = 100, MP = 70 Name = "Salamander", HP = 200, MP = 20 Name = "Ondine", HP = 140, MP = 60
LuaとC/C++の相互運用
LuaにはC言語向けの相互運用APIが用意されている。LuaからC/C++の関数を呼び出すためには以下の方法を用いる。下記のコードはC/C++の関数をLua VMに登録し、Luaスクリプト側から呼び出している。 #include <cstdio> #include <cstdlib> #include <lua.h> #include <lauxlib.h>
int my_add(lua_State* L) { const int x = (int)lua_tonumber(L, 1); // 第1引数の取得。 const int y = (int)lua_tonumber(L, 2); // 第2引数の取得。 lua_settop(L, 0); // スタックのクリア。 const int ret = x + y; // C/C++ 側での演算。 lua_pushnumber(L, ret); // 返却値をプッシュ。 return 1; }
int main(int argc, char* argv[]) { lua_State* L = luaL_newstate(); // Lua VM の初期化。 luaL_openlibs(L); // Lua の標準ライブラリを使えるようにする。 lua_register(L, "my_add", my_add); // Lua VM に C/C++ 関数を登録。 // my_add 関数を呼び出す Lua スクリプトを実行。 if (luaL_dostring(L, "print(my_add(5, 3))")) { lua_close(L); // Lua VM を閉じる。 return EXIT_FAILURE; // エラー終了。
lua_close(L); return EXIT_SUCCESS; } 逆に、C/C++からLuaの関数を呼び出す際にもスタック操作が必要となる。 #include <cstdio> #include <cstdlib> #include <lua.h> #include <lauxlib.h>
int main(int argc, char* argv[]) { lua_State* L = luaL_newstate(); // Lua VM の初期化。 // add_func 関数を定義する Lua スクリプトを実行。 if (luaL_dostring(L, "function add_func(x, y) return x + y end")) { lua_close(L); // Lua VM を閉じる。 return EXIT_FAILURE; // エラー終了。
lua_getglobal(L, "add_func"); // Lua のグローバルオブジェクトである「add_func」を取得し、スタックに積む。 lua_pushinteger(L, 5); // 整数値の「5」を Lua スタックにプッシュ。 lua_pushinteger(L, 3); // 整数値の「3」を Lua スタックにプッシュ。 lua_call(L, 2, 1); // Lua 側で実装した add_func 関数を呼び出す。引数の数は2、結果の数は1。 printf("Result: %d\n", lua_tointeger(L, -1)); // 結果を表示。 lua_close(L); return EXIT_SUCCESS; }
言語バインディングの例 Luaの他言語用バインディングは公式には提供されていないが、有志によるサードパーティ製ライブラリやツールがいくつか存在する。バインディングを使うと、前述のような煩雑なスタック操作を明示的に記述することなく、簡潔に相互運用できるようになる。
C++ LuaをC++言語で記述されたホストプログラムへ組み込むための省力化ツール(コードジェネレーター)および言語バインディングとして、toLuatoLua home page、 tolua++(Lua 5.2非対応)LuaDist/toluapp: tolua++ is an extension of toLua, a tool to integrate C/Cpp code with Lua、Luabind(Lua 5.2非対応)、Selene、Sol、Sol2などが開発されている。
以下にSol2を使った例を示す(C++11およびC++14の機能を利用するため、対応コンパイラが必要)。
LuaからC/C++の関数を呼び出す例: #include <iostream> #include <sol.hpp>
int add(int x, int y) { return x + y; }
int main() { // Luaの初期化 sol::state lua;
// Luaの標準ライブラリをすべて開く lua.open_libraries(sol::lib::base, sol::lib::coroutine, sol::lib::debug, sol::lib::debug, sol::lib::io, sol::lib::math, sol::lib::os, sol::lib::package, sol::lib::string, sol::lib::table, sol::lib::utf8);
// LuaにC/C++の関数を登録 lua["add"] = add;
// Luaスクリプトの読み込み try { lua.safe_script_file("test.lua"); } catch (const sol::error& e) { std::cout << e.what() << std::endl;
C/C++の関数を呼び出すLuaスクリプト (test.lua): print(add(100, 200)) -- 「300」と表示される
C++からLuaの関数を呼び出す例: #include <iostream> #include <sol.hpp>
int main() { // Luaの初期化 sol::state lua;
// Luaの標準ライブラリをすべて開く lua.open_libraries(sol::lib::base, sol::lib::coroutine, sol::lib::debug, sol::lib::debug, sol::lib::io, sol::lib::math, sol::lib::os, sol::lib::package, sol::lib::string, sol::lib::table, sol::lib::utf8);
// Luaスクリプトの読み込み try { lua.safe_script_file("test.lua"); } catch (const sol::error& e) { std::cout << e.what() << std::endl;
// Luaの関数を呼び出す sol::function_result ret = lua["add"](100, 200);
// 結果を表示する std::cout << ret.get<int>() << std::endl; } C++から呼び出される関数を定義するLuaスクリプト (test.lua): function add(a, b) return a + b end
Java LuajというJava仮想マシン向けの実装がある。Luaj 3.0は、Lua 5.2相当の仕様をJavaで実装しなおしたものであり、Javaのクラスからバインダ無しでインスタンスを生成したりメソッドを呼び出したりすることが可能である。そのほか、LuaのC APIをJNI経由でJavaから利用可能にするJNLuaJNLua (Java Native Lua) | Google Code Archive - Long-term storage for Google Code Project Hosting.が存在する。
.NET C#やVB.NETといった.NET Framework言語向けのバインディングとして、LunaRoad3F/LunaRoad: Lua C API for .NET :: LunaRoad represents flexible platform for work with Lua 5.1, 5.2, 5.3 ....が存在する。C#で書かれたLuaインタプリタとしてMoonSharpMoonSharpが存在する。また、DLR上に実装されたNeoLuaneolithos/neolua: A Lua implementation for the Dynamic Language Runtime (DLR).が存在する。
Luaを採用している製品
ゲーム
Blue Mars CRYSIS Far Cry Factorio From the depths Garry's MOD Lost Wind RagnarokOnline Roblox Stormworks Xenepic Online Revo ソニック・ザ・ヘッジホッグ (2006年のゲーム) ソニック ワールドアドベンチャー(北米版のタイトルはSonic Unleashed) ティアーズ・トゥ・ティアラ 花冠の大地 THE IDOLM@STER 2 Warhammer Online:Age of Reckoning World of Warcraft カンパニー・オブ・ヒーローズ GRAVITY DAZE ニンテンドークラシックミニ ファミリーコンピュータ (エミュレータシステム kachikachi のゲーム選択画面で使用) PHANTASY STAR ONLINE 2 ファイナルファンタジーXIV「FFXIV:新生エオルゼア」プロデューサー吉田直樹氏インタビュー ドラゴンクエストXWEB+DB PRESS Vol.90 特集2 ドラゴンクエストX開発ノウハウ大公開 国民的RPGオンライン化へのチャレンジ
ゲーム以外
3DMLWプラグイン Adobe Photoshop Lightroom Aegisub Anime Studio Apache mod_lua Asterisk extensions.lua AutoTouchAutoTouch 公式ホームページ AviUtl Computercraft - MinecraftのMOD FlashAir - 無線LAN機能を搭載した東芝製SDHCメモリーカードFlashAir Developers - ドキュメント - APIガイド - Lua機能 FLOW - 設定に使われている FreeBSD - ブートローダのUI等を実装 LuaTeX MediaWiki(Scribunto拡張により) MySQL Proxy Nginx nmap OpenResty OpenWrt osm2pgsql - OpenStreetMapのデータをPostGISに読み込むユーティリティ Premake Redis RigidChips Renoise Strata 3D Tachyon TileMan ヤマハのルータ製品 - RTXシリーズ(5000/3500/1300/1220/1210/1200/830/810) NVRシリーズ、FWX120、SRT100 Vim - ビルド時に有効化することで拡張スクリプト内でLuaを使用できる、派生のNeovimではLuaJITが内部的に利用されており組み込まれている VLC Media Player VOCALOID - ユーザー側で編集用スクリプトを自作できる(VOCALOID3〜4のみ) Synthesizer V - 同上。JavaScriptにも対応 Wireshark
脚注
注釈
出典
関連書籍
関連項目 Squirrel グルー言語 SciTE
外部リンク
Lua 5.4 Reference Manual - 公式の言語リファレンスマニュアル Lua 5.4 リファレンスマニュアル - 日本語マニュアル - 産業技術総合研究所 Luaj - SourceForge.net Lua入門講座 広井誠:「お気楽 Lua プログラミング超入門」 C/C++ 言語プログラマのための Lua 入門リファレンス