ここでは、ScenarioMod/TSModに搭載されているLuaインタプリタの特殊な機能について解説しています。
ScenarioMod/TSMod用のLuaインタプリタは、Lua version 5.1.5 をコアとしています。
Lua 5.1.5 の標準文法については、原則利用可能です。
レガシーゲームである天翔記のMod用途に作られましたので、
cp932(sjis)の文字コードで記述されたLuaファイルが取り扱えるようになっています。
cp932の文字の勘定等をするための専用の関数なども取りそろっています。
独自拡張を施しており、その中には、Lua 5.2向きに書かれたスクリプトを互換動作させるような修正も含まれます。
Lua5.2の深層機能を利用していない限り、Lua5.2のスクリプトも極めて高い確率で動作します。
但し、独自の機能としてcontinue文を追加した代わりに、Lua5.2には存在するgoto文がありませんので注意して下さい。
Lua5.3にて導入されたビット演算等や、追加のLua関数も、そのほとんどが追加されています。
よって、Lua5.3向けに記述されたスクリプトすらも、それなりに高い確率で動作します。
luaの5.1は本来UTF8のBOM付ファイルは読み込みができずエラーとなりますが、
jLuaでは、Lua5.2以降同様実行が可能となっています。
luaのprint関数と同じですが、出力先が「ModDebugger」となります。
こちらも出力先が「ModDebugger」となります。
(jLua.exeに関しては、こちらは、標準出力となります)
準標準ライブラリともいえるlfsライブラリを追加しています。
Lua5.2の資産でも流用しやすいように、5.2と同一動作のbit32ライブラリを追加しています。
stringライブラリやutf8ライブラリのcp932版として、
(cp932.len、cp932.upper、cp932.lower、cp932.reverse、cp932.sub、cp932.char、cp932.codepoint、cp932.codes、cp932.encode(文字列, "utf8"))
が追加されています。
luaの5.3にて新たに加えられたmath関数を持っています。
(math.type、 math.ult、math.mininteger、math.maxinteger、math.tointeger、math.round(x [, precision ])))
正規表現系のエンジン(string.match等)に関して、cp932(sjis)に適した対応がなされています。
luaの5.3にて新たに加えられたstring関数を持っています。
(string.pack、string.unpack)
string.getencoding(文字列)
が追加されています。
日本語系で、利用する可能性が高い「メジャーどころ」に絞った高速な判定です。
nilもしくは空のテーブルであることを判定するtable.emptyが追加されています。
luaの5.2の機能に準ずる 2つの関数を搭載しています。
(table.unpack / table.pack)
luaの5.3にて新たに加えられたtable関数を持っています。
(table.move)
luaの5.3にて加えられたutf8系ライブラリを全て持っています。
(utf8.encode(文字列, "cp932") )が特別に追加されています。
luaの5.2に準ずるload関数を搭載しています。
これにより、5.2準拠で記述されたload文を処理することができます。
luaの5.2の機能に準ずる rawlen関数を搭載しています。
__lenの振る舞いも、限りなく5.2へと準拠しています。
Lua5.3 で実装された、ビット演算子(&,|,<<,>>,~)が実装されています。
また、対応するメタメソッド(__band, __bor, __bxor, __bnot, __shl, __shr)も実装されています。
Lua5.3 で実装された、整数とみなしての除算 (例: 10 // 3 ) が実装されています。
また、対応するメタメソッド(__idiv)も実装されています。
標準のluaには存在しない、continue文を持っています。
luaでは「~=」と記述しますが、独特ですので、多くの言語で採用されている「!=」も利用可能としています。
C風の「+=」「-=」「*=」「/=」「%=」「^=」の6つの代入演算子が使えます。
これは簡単な演算の際、ソースコードを結構短くできるはずです。
16進数の「0xF0」 などと同様に、「0b10101」の2進数表記を受け付けます。
この場合、最初のパラメータは、暗黙で「self」となります。
通常、luaのメソッド定義スタイルは
tbl = {} function tbl:my_method(x, y) endもしくは
tbl = { my_method = function(self, x, y) end }
ですが、通常の関数と同じスタイルで、
tbl = { function my_method(x, y) end }
と、記述することが出来ます。
この場合、function内には、暗黙の第1引数として「self」が存在します。
__newindexの逆の意味合いとなる__usedindexを持ちます。
これは、値を代入しようとする度に実行されますので、読み取り専用テーブルを作成するのに役立ちます。
function table.const(tbl) -- テーブルの要素を for k, v in pairs(tbl) do -- 要素がテーブルなら再帰 if type(v) == "table" then table.const(v) end end return setmetatable(tbl, { __usedindex = function(table, key, value) dprint("警告!! このテーブルは読み取り専用です。\n") dprint( string.format("\tキー:%s, 代入しようとした値:%s\n", tostring(key), tostring(value) ) ) end, __newindex = function(table, key, value) dprint("警告!! このテーブルは読み取り専用です。\n") dprint( string.format("\tキー:%s, 代入しようとした値:%s\n", tostring(key), tostring(value) ) ) end, }); end local mytable = table.const{ 1,2, a=3, b={1,2} } mytable[2] = 10 -- 直接の子要素も読み取り専用 mytable.b[1] = 30 -- ネストのテーブル要素も読み取り専用となる。
テーブルにおいて、イテレータ関数を指定できます。
local mytbl = {1,2,3} setmetatable(mytbl,{__iter=ipair}) -- すでにイテレータが指定されているので、ipair関数を使う必要がない。もちろんipairがpairを使っても良い。 for k, v in mytbl do dprint(k, v) end
class 'Person' { __init__ = function(self, name) self.name = name end; say = function(self) print('Hello, my name is ' .. self.name .. '.') self:saySthElse() end; saySthElse = function(self) end } class 'Worker' { function __init__(id) self.id = id end; function showId() print('My worker id is ' .. self.id .. '.') end } class 'Employee: Person, Worker' { function __init__(name, salary, id) Person.__init__(self, name) Worker.__init__(self, id) self.salary = salary end; function saySthElse() print('My salary is ' .. self.salary .. '.') end } p = cls.Person('Bob') p:say() p2 = cls.Person('David') p2:say() print '--------------------------------------------' e = cls.Employee('Bob', 1000, 1) e:say() e:showId() e2 = cls.Employee('Alice', 10000, 2) e2:say() e2:showId() print '--------------------------------------------' if is_instance_of(e, cls.Person) then print 'e is an instance of Person' else print 'e is not an instance of Person' end if is_instance_of(e, cls.Worker) then print 'e is an instance of Worker' else print 'e is not an instance of Worker' end w = cls.Worker(100) if is_instance_of(w, cls.Person) then print 'w is an instance of Person' else print 'w is not an instance of Person' end if is_instance_of(w, cls.Worker) then print 'w is an instance of Worker' else print 'w is not an instance of Worker' end