diff --git a/CMakeLists.txt b/CMakeLists.txt index ff75973..42f2ebb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,17 +1,19 @@ +set(LUA_VERSION "lua" CACHE STRING "lua version") if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/lua5.4/lua.h") find_package(PkgConfig) if(PkgConfig_FOUND) - foreach(pkg lua lua54 lua53 lua52 luajit lua51) - pkg_check_modules(LUA ${pkg}) + foreach(pkg ${LUA_VERSION} lua54 lua53 lua52 luajit lua51) + pkg_check_modules(LUA IMPORTED_TARGET GLOBAL ${pkg}) if(LUA_FOUND) break() endif() endforeach() endif() if(LUA_FOUND) + set(LUA_TARGET PkgConfig::LUA) include_directories(${LUA_INCLUDE_DIRS}) else() - message(FATAL_ERROR "Lua not found, consider using `bash travis-install.sh` to download.") + message(FATAL_ERROR "Lua not found, consider using `bash action-install.sh` to download.") endif() else() message(STATUS "Using in-tree lua source") @@ -44,5 +46,5 @@ endif() set(plugin_name "rime-lua" PARENT_SCOPE) set(plugin_objs $ PARENT_SCOPE) -set(plugin_deps ${LUA_LIBRARIES} ${rime_library} ${rime_gears_library} PARENT_SCOPE) +set(plugin_deps ${LUA_TARGET} ${rime_library} ${rime_gears_library} PARENT_SCOPE) set(plugin_modules "lua" PARENT_SCOPE) diff --git a/sample/lua/charset.lua b/sample/lua/charset.lua index 081ddcc..77998b9 100644 --- a/sample/lua/charset.lua +++ b/sample/lua/charset.lua @@ -17,15 +17,16 @@ -- 帮助函数(可跳过) local charset = { - ["CJK"] = { first = 0x4E00, last = 0x9FFF }, -- CJK Unified Ideographs - https://unicode.org/charts/PDF/U4E00.pdf - ["ExtA"] = { first = 0x3400, last = 0x4DBF }, -- CJK Unified Ideographs Extension A - https://unicode.org/charts/PDF/U3400.pdf - ["ExtB"] = { first = 0x20000, last = 0x2A6DF }, -- CJK Unified Ideographs Extension B - https://unicode.org/charts/PDF/U20000.pdf - ["ExtC"] = { first = 0x2A700, last = 0x2B73F }, -- CJK Unified Ideographs Extension C - https://unicode.org/charts/PDF/U2A700.pdf - ["ExtD"] = { first = 0x2B740, last = 0x2B81F }, -- CJK Unified Ideographs Extension D - https://unicode.org/charts/PDF/U2B740.pdf - ["ExtE"] = { first = 0x2B820, last = 0x2CEAF }, -- CJK Unified Ideographs Extension E - https://unicode.org/charts/PDF/U2B820.pdf - ["ExtF"] = { first = 0x2CEB0, last = 0x2EBEF }, -- CJK Unified Ideographs Extension F - https://unicode.org/charts/PDF/U2CEB0.pdf - ["ExtG"] = { first = 0x30000, last = 0x3134A }, -- CJK Unified Ideographs Extension G - https://unicode.org/charts/PDF/U30000.pdf - ["Compat"] = { first = 0x2F800, last = 0x2FA1F } -- CJK Compatibility Ideographs Supplement - https://unicode.org/charts/PDF/U2F800.pdf + ["CJK"] = { first = 0x4E00, last = 0x9FFF }, -- CJK Unified Ideographs - https://unicode.org/charts/PDF/U4E00.pdf + ["ExtA"] = { first = 0x3400, last = 0x4DBF }, -- CJK Unified Ideographs Extension A - https://unicode.org/charts/PDF/U3400.pdf + ["ExtB"] = { first = 0x20000, last = 0x2A6DF }, -- CJK Unified Ideographs Extension B - https://unicode.org/charts/PDF/U20000.pdf + ["ExtC"] = { first = 0x2A700, last = 0x2B73F }, -- CJK Unified Ideographs Extension C - https://unicode.org/charts/PDF/U2A700.pdf + ["ExtD"] = { first = 0x2B740, last = 0x2B81F }, -- CJK Unified Ideographs Extension D - https://unicode.org/charts/PDF/U2B740.pdf + ["ExtE"] = { first = 0x2B820, last = 0x2CEAF }, -- CJK Unified Ideographs Extension E - https://unicode.org/charts/PDF/U2B820.pdf + ["ExtF"] = { first = 0x2CEB0, last = 0x2EBEF }, -- CJK Unified Ideographs Extension F - https://unicode.org/charts/PDF/U2CEB0.pdf + ["ExtG"] = { first = 0x30000, last = 0x3134A }, -- CJK Unified Ideographs Extension G - https://unicode.org/charts/PDF/U30000.pdf + ["Compat"] = { first = 0xF900, last = 0xFAFF }, -- CJK Compatibility Ideographs - https://unicode.org/charts/PDF/UF900.pdf + ["CompatSupp"] = { first = 0x2F800, last = 0x2FA1F } -- CJK Compatibility Ideographs Supplement - https://unicode.org/charts/PDF/U2F800.pdf } local function exists(single_filter, text) @@ -48,7 +49,8 @@ local function is_cjk_ext(c) return is_charset("ExtA")(c) or is_charset("ExtB")(c) or is_charset("ExtC")(c) or is_charset("ExtD")(c) or is_charset("ExtE")(c) or is_charset("ExtF")(c) or - is_charset("ExtG")(c) or is_charset("Compat")(c) + is_charset("ExtG")(c) or is_charset("Compat")(c) or + is_charset("CompatSupp")(c) end --[[ diff --git a/sample/lua/expand_translator.lua b/sample/lua/expand_translator.lua index b343952..1aee36b 100644 --- a/sample/lua/expand_translator.lua +++ b/sample/lua/expand_translator.lua @@ -28,11 +28,20 @@ local function memoryCallback(memory, commit) return true end +local function memoryCallback1(commit) + for i, dictentry in ipairs(commit:get()) do + commits:update_entry(dictentry, 1, "") + end + --commits:update(1) -- +end + + local function init(env) env.mem = Memory(env.engine,env.engine.schema) -- ns= "translator" -- env.mem = Memory(env.engine,env.engine.schema, env.name_space ) -- env.mem = Memory(env.engine,Schema("cangjie5") ) -- ns= "translator- - env.mem:memorize(function(commit) memoryCallback(env.mem, commit) end) + --env.mem:memorize(function(commit) memoryCallback(env.mem, commit) end) + env.mem:memorize(memoryCallback1) -- or use -- schema = Schema("cangjie5") -- schema_id -- env.mem = Memory(env.engine, schema, "translator") diff --git a/sample/lua/number.lua b/sample/lua/number.lua index 126bae4..768626a 100644 --- a/sample/lua/number.lua +++ b/sample/lua/number.lua @@ -3,92 +3,106 @@ number_translator: 将 `/` + 阿拉伯数字 翻译为大小写汉字 --]] local confs = { - { - comment = " 大写", - number = { [0] = "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }, - suffix = { [0] = "", "拾", "佰", "仟" }, - suffix2 = { [0] = "", "万", "亿", "万亿", "亿亿" } - }, - { - comment = " 小写", - number = { [0] = "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" }, - suffix = { [0] = "", "十", "百", "千" }, - suffix2 = { [0] = "", "万", "亿", "万亿", "亿亿" } - }, - { - comment = " 大寫", - number = { [0] = "零", "壹", "貳", "參", "肆", "伍", "陸", "柒", "捌", "玖" }, - suffix = { [0] = "", "拾", "佰", "仟" }, - suffix2 = { [0] = "", "萬", "億", "萬億", "億億" } - }, - { - comment = " 小寫", - number = { [0] = "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" }, - suffix = { [0] = "", "十", "百", "千" }, - suffix2 = { [0] = "", "萬", "億", "萬億", "億億" } - }, + { + comment = " 大写", + numeral = { [0] = "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }, + place = { [0] = "", "拾", "佰", "仟" }, + group = { [0] = "", "万", "亿", "万亿", "亿亿" } + }, + { + comment = " 小写", + numeral = { [0] = "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" }, + place = { [0] = "", "十", "百", "千" }, + group = { [0] = "", "万", "亿", "万亿", "亿亿" } + }, + { + comment = " 序数", + numeral = { [0] = "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九" } + }, + { + comment = " 大寫", + numeral = { [0] = "零", "壹", "貳", "參", "肆", "伍", "陸", "柒", "捌", "玖" }, + place = { [0] = "", "拾", "佰", "仟" }, + group = { [0] = "", "萬", "億", "兆", "京" } + }, + { + comment = " 小寫", + numeral = { [0] = "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" }, + place = { [0] = "", "十", "百", "千" }, + group = { [0] = "", "萬", "億", "兆", "京" } + }, + { + comment = " 序數", + numeral = { [0] = "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九" } + } } local function read_seg(conf, n) - local s = "" - local i = 0 - local zf = true + local s = "" + local i = 0 + local zf = true - while string.len(n) > 0 do - local d = tonumber(string.sub(n, -1, -1)) - if d ~= 0 then - s = conf.number[d] .. conf.suffix[i] .. s - zf = false - else - if not zf then - s = conf.number[0] .. s - end - zf = true + while string.len(n) > 0 do + local d = tonumber(string.sub(n, -1, -1)) + if conf.place == nil then + s = conf.numeral[d] .. s + elseif d == 1 and i == 1 and string.len(n) == 1 then + s = conf.place[i] .. s + elseif d ~= 0 then + s = conf.numeral[d] .. conf.place[i] .. s + zf = false + else + if not zf then + s = conf.numeral[0] .. s end - i = i + 1 - n = string.sub(n, 1, -2) - end + zf = true + end + i = i + 1 + n = string.sub(n, 1, -2) + end - return i < 4, s + return i < 4, s end local function read_number(conf, n) - local s = "" - local i = 0 - local zf = false + local s = "" + local i = 0 + local zf = false - n = string.gsub(n, "^0+", "") + n = string.gsub(n, "^0+", "") - if n == "" then - return conf.number[0] - end + if n == "" then + return conf.numeral[0] + end - while string.len(n) > 0 do - local zf2, r = read_seg(conf, string.sub(n, -4, -1)) - if r ~= "" then - if zf and s ~= "" then - s = r .. conf.suffix2[i] .. conf.number[0] .. s - else - s = r .. conf.suffix2[i] .. s - end + while string.len(n) > 0 do + local zf2, r = read_seg(conf, string.sub(n, -4, -1)) + if r ~= "" then + if conf.group == nil then + s = r .. s + elseif zf and s ~= "" then + s = r .. conf.group[i] .. conf.numeral[0] .. s + else + s = r .. conf.group[i] .. s end - zf = zf2 - i = i + 1 - n = string.sub(n, 1, -5) - end - return s + end + zf = zf2 + i = i + 1 + n = string.sub(n, 1, -5) + end + return s end local function translator(input, seg) - if string.sub(input, 1, 1) == "/" then - local n = string.sub(input, 2) - if tonumber(n) ~= nil then - for _, conf in ipairs(confs) do - local r = read_number(conf, n) - yield(Candidate("number", seg.start, seg._end, r, conf.comment)) - end + if string.sub(input, 1, 1) == "/" then + local n = string.sub(input, 2) + if tonumber(n) ~= nil then + for _, conf in ipairs(confs) do + local r = read_number(conf, n) + yield(Candidate("number", seg.start, seg._end, r, conf.comment)) end - end + end + end end return translator diff --git a/sample/lua/script_translator.lua b/sample/lua/script_translator.lua new file mode 100644 index 0000000..5dedaa5 --- /dev/null +++ b/sample/lua/script_translator.lua @@ -0,0 +1,86 @@ +#! /usr/bin/env lua +-- +-- script_translator.lua +-- Copyright (C) 2023 Shewer Lu +-- +-- Distributed under terms of the MIT license. +-- + +--[[ + +''' custom.yaml' +patch: + engine/translators/+: + - lua_translator@*table_translator@translator + - lua_translator@*script_translator@cangjie +```` +------- methods return +env.tran:start_session false function() +env.tran:finish_session false function() +env.tran:discard_session false function() +env.tran:query false function(inp, seg) +env.tran:memorize false function(commit_entrys) +env.tran:update_entry false function(entry, state, prefix_str) +env.tran:set_memorize_callback bool function(commit_entry) +------- vars_set +env.tran.spelling_hints = int >0 +env.tran.initial_quality = double +env.tran.contextual_suggestions = boolean +env.tran.memorize_callback = [function | nil] +env.tran.enable_completion = boolean +env.tran.always_show_comments = boolean +env.tran.strict_spelling = boolean +env.tran.max_homophones = int +env.tran.enable_correction = boolean +env.tran.tag = string +env.tran.delimiters = string + +------- vars_get +res = env.tran.spelling_hints 0 number +res = env.tran.initial_quality 0.0 number +res = env.tran.contextual_suggestions false boolean +env.tran.memorize_callback function|nil +res = env.tran.enable_completion true boolean +res = env.tran.always_show_comments false boolean +res = env.tran.strict_spelling false boolean +res = env.tran.max_homophones 1 number +res = env.tran.enable_correction false boolean +res = env.tran.tag abc string +res = env.tran.delimiters ' string + +--]] +local M={} +local function simple_callback(self, commits) + local context = self.engine.context + if true then + return self:memorize(commits) + end +end +local function callback(self, commits) -- self : env.tran commits : list + local context = self.engine.context + for i, entry in ipairs(commits:get()) do + self:update_entry(entry,0,"") -- do nothing to userdict + -- self:update_entry(entry,1,"") -- update entry to userdict + -- self:update_entry(entry,-1,"") -- delete entry to userdict + end +end +function M.init(env) + env.tran = Component.ScriptTranslator(env.engine, env.name_space, "script_translator") + env.tran:set_memorize_callback(simple_callback) + --env.tran:set_memorize_callback() -- reset callback + --env.tran.memorize_callback= function(simple_callback) + --env.tran.memorize_callback= nil -- reset callback +end + +function M.fini(env) +end + +function M.func(inp, seg, env) + local t = env.tran:query(inp,seg) + if not t then return end + for cand in t:iter() do + yield(cand) + end +end + +return M diff --git a/sample/lua/table_translator.lua b/sample/lua/table_translator.lua new file mode 100644 index 0000000..fcefa0c --- /dev/null +++ b/sample/lua/table_translator.lua @@ -0,0 +1,89 @@ +#! /usr/bin/env lua +-- +-- table_translator.lua +-- Copyright (C) 2023 Shewer Lu +-- +-- Distributed under terms of the MIT license. +-- +--[[ +-- +''' custom.yaml' +patch: + engine/translators/+: + - lua_translator@*table_translator@translator + - lua_translator@*script_translator@cangjie +```` + +------- methods +env.tran:finish_session bool function() +env.tran:start_session bool function() +env.tran:discard_session bool function() +env.tran:query translation function(inp, seg) +env.tran:memorize bool function(commit_entrys) +env.tran:update_entry bool function(entry) +env.tran:set_memorize_callback bool function(commit_entry) + +------- vars_set 設定值 +env.tran.max_homophones = number +env.tran.spelling_hints = number +env.tran.enable_correction = boolean +env.tran.memorize_callback = function(commits)|nil +env.tran.enable_completion = false boolean +env.tran.delimiters = false string +env.tran.strict_spelling = boolean +env.tran.contextual_suggestions = boolean +env.tran.initial_quality = double +env.tran.always_show_comments = boolean +env.tran.tag = string + +------- vars_get 取值 +res = env.tran.max_homophones 1 number +res = env.tran.spelling_hints 0 number +res = env.tran.enable_correction false boolean +env.tran.memorize_callback function|nil +res = env.tran.enable_completion true boolean +res = env.tran.delimiters ' string +res = env.tran.strict_spelling false boolean +res = env.tran.contextual_suggestions false boolean +res = env.tran.initial_quality 0.0 number +res = env.tran.always_show_comments false boolean +res = env.tran.tag cangjie string + + +--]] + +local M={} +local function simple_callback(self, commits) + local context = self.engine.context + if true then + return self:memorize(commits) + end +end +local function callback(self, commits) -- self : env.tran commits : list + local context = self.engine.context + for i, entry in ipairs(commits:get()) do + self:update_entry(entry, 0,"") -- do nothing to userdict + -- self:update_entry(entry,1,"") -- update entry to userdict + -- self:update_entry(entry,-1,"") -- delete entry to userdict + end +end +function M.init(env) + env.tran = Component.TableTranslator(env.engine, env.name_space, "table_translator") + env.tran:set_memorize_callback(simple_callback) + --env.tran:set_memorize_callback() -- reset callback + --env.tran.memorize_callback= function(simple_callback) + --env.tran.memorize_callback= nil -- reset callback +end + +function M.fini(env) +end + +function M.func(inp, seg, env) + local t = env.tran:query(inp,seg) + if not t then return end + for cand in t:iter() do + yield(cand) + end +end + +return M diff --git a/sample/lua/userdb.lua b/sample/lua/userdb.lua new file mode 100644 index 0000000..fed86f6 --- /dev/null +++ b/sample/lua/userdb.lua @@ -0,0 +1,73 @@ +#! /usr/bin/env lua +-- +-- userdb.lua +-- Copyright (C) 2024 Shewer Lu +-- +-- Distributed under terms of the MIT license. +-- +--[[ +example: +local userdb = require 'userdb' +local ldb=userdb.LevelDb('ecdict') +ldb:open() +for k,v in ldb:query('a'):iter() do print(k,v) end + +--]] +local db_pool_ = {} +local vars_get= { + _loaded=true, + read_only=true, + disabled=true, + name=true, + file_name=true, + } +local vars_set= {} +local userdb_mt = {} +function userdb_mt.__newindex(tab,key,value) + local db = db_pool_[tab._db_key] + if not db then + db = UserDb(tab._db_name, tab._db_class) + db_pool_[tab._db_key] = db + end + if db and vars_set[key] then + db[key]= value + end +end + +function userdb_mt.__index(tab,key) + local db = db_pool_[tab._db_key] + if not db then + db = UserDb(tab._db_name, tab._db_class) + db_pool_[tab._db_key] = db + end + + if db and vars_get[key] then + return db[key] + else + return function (tab, ...) + return db[key](db,...) + end + end +end + +local userdb= {} + +function userdb.UserDb(db_name, db_class) + local db_key = db_name .. "." .. db_class + local db = { + _db_key = db_key, + _db_name= db_name, + _db_class = db_class, + } + db_pool_[db_key] = UserDb(db_name, db_class) + return setmetatable(db , userdb_mt) +end + +function userdb.LevelDb(db_name) + return userdb.UserDb(db_name, "userdb") +end +function userdb.TableDb(db_name) + return userdb.UserDb(db_name, "plain_userdb") +end + +return userdb diff --git a/sample/luna_pinyin.custom.yaml b/sample/luna_pinyin.custom.yaml new file mode 100644 index 0000000..dc85bd3 --- /dev/null +++ b/sample/luna_pinyin.custom.yaml @@ -0,0 +1,6 @@ +patch: + engine/translators/+: + - lua_translator@*table_translator@translator + - lua_translator@*script_translator@cangjie + + diff --git a/src/lib/lua.cc b/src/lib/lua.cc index fab99bf..ced2a24 100644 --- a/src/lib/lua.cc +++ b/src/lib/lua.cc @@ -2,6 +2,23 @@ #include "lua_templates.h" namespace LuaImpl { + int wrap_common(lua_State *L, int (*cfunc)(lua_State *)) { + char room[sizeof(C_State)]; + C_State *C = new (&room) C_State(); + lua_pushcfunction(L, cfunc); + lua_insert(L, 1); + lua_pushlightuserdata(L, (void *) C); + lua_insert(L, 2); + int status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); + if (status != LUA_OK) { + C->~C_State(); + lua_error(L); + abort(); // unreachable + } + C->~C_State(); + return lua_gettop(L); + } + static int index(lua_State *L) { if (luaL_getmetafield(L, 1, "methods") != LUA_TNIL) { lua_pushvalue(L, 2); @@ -247,6 +264,10 @@ std::shared_ptr Lua::getglobal(const std::string &v) { return o; } +void Lua::gc() { + lua_gc(L_, LUA_GCCOLLECT, 0); +} + LuaObj::LuaObj(lua_State *L, int i) : L_(L) { lua_pushvalue(L, i); id_ = luaL_ref(L, LUA_REGISTRYINDEX); diff --git a/src/lib/lua.h b/src/lib/lua.h index 29e0633..c2d00c4 100644 --- a/src/lib/lua.h +++ b/src/lib/lua.h @@ -34,6 +34,8 @@ class Lua { std::shared_ptr newthreadx(lua_State *L, int nargs); + void gc(); + template std::shared_ptr newthread(I ... input); @@ -53,4 +55,8 @@ class Lua { lua_State *L_; }; +namespace LuaImpl { + int wrap_common(lua_State *L, int (*cfunc)(lua_State *)); +} + #endif // LIB_LUA_H_ diff --git a/src/lib/lua_templates.h b/src/lib/lua_templates.h index a98a577..13076db 100644 --- a/src/lib/lua_templates.h +++ b/src/lib/lua_templates.h @@ -595,20 +595,7 @@ struct LuaWrapper { } static int wrap(lua_State *L) { - char room[sizeof(C_State)]; - C_State *C = new (&room) C_State(); - lua_pushcfunction(L, wrap_helper); - lua_insert(L, 1); - lua_pushlightuserdata(L, (void *) C); - lua_insert(L, 2); - int status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); - if (status != LUA_OK) { - C->~C_State(); - lua_error(L); - abort(); // unreachable - } - C->~C_State(); - return lua_gettop(L); + return LuaImpl::wrap_common(L, wrap_helper); } }; @@ -642,6 +629,32 @@ struct MemberWrapper { } }; +#if __cplusplus >= 201703L || _MSVC_LANG >= 201703L +template +struct MemberWrapper { + template + static R wrapT(D &c, T... t) { + return (c.*f)(t...); + } + + static R wrap(C &c, T... t) { + return wrapT(c, t...); + } +}; + +template +struct MemberWrapper { + template + static R wrapT(const D &c, T... t) { + return (c.*f)(t...); + } + + static R wrap(const C &c, T... t) { + return wrapT(c, t...); + } +}; +#endif + template struct LUAWRAPPER_LOCAL MemberWrapperV; diff --git a/src/lib/luatype_std_optional.h b/src/lib/luatype_std_optional.h new file mode 100644 index 0000000..f65e532 --- /dev/null +++ b/src/lib/luatype_std_optional.h @@ -0,0 +1,24 @@ +#ifndef LUATYPE_STD_OPTIONAL_H +#define LUATYPE_STD_OPTIONAL_H + +#include "lua_templates.h" +#include + +template +struct LuaType> { + static void pushdata(lua_State *L, std::optional o) { + if (o) + LuaType::pushdata(L, *o); + else + lua_pushnil(L); + } + + static std::optional &todata(lua_State *L, int i, C_State *C) { + if (lua_type(L, i) == LUA_TNIL) + return C->alloc>(); + else + return C->alloc>(LuaType::todata(L, i, C)); + } +}; + +#endif /* LUATYPE_STD_OPTIONAL_H */ diff --git a/src/lua_gears.cc b/src/lua_gears.cc index beb0fdc..9e1f704 100644 --- a/src/lua_gears.cc +++ b/src/lua_gears.cc @@ -1,5 +1,7 @@ #include "lib/lua_templates.h" #include "lua_gears.h" +#include +#include namespace rime { @@ -21,6 +23,43 @@ bool LuaTranslation::Next() { } } +LuaTranslation::~LuaTranslation() { + lua_->gc(); +} + +static std::vector split_string(const std::string& str, const std::string& delimiter) { + std::vector result; + size_t pos = 0; + size_t found; + while ((found = str.find(delimiter, pos)) != std::string::npos) { + result.push_back(str.substr(pos, found - pos)); + pos = found + delimiter.length(); + } + result.push_back(str.substr(pos)); + return result; +} +static bool sub_module_init(lua_State *L, const Ticket &t, + const std::vector& vec_klass) { + size_t vec_klass_sz= vec_klass.size(); + for (size_t index=1 ;index < vec_klass_sz; index++) { + lua_getfield(L, -1, vec_klass.at(index).c_str() ); + if ( index < vec_klass_sz-1 && lua_type(L, -1) != LUA_TTABLE ) { + std::ostringstream ostr; + ostr << "Lua Compoment of initialize error:(" + << " klass: " << t.klass + << " module: "<< vec_klass.at(0) + << ", name_space: " << t.name_space + << ", sub-table(" <::pushdata(L, ostr.str()); + return false; + } + } + return true; +} //--- static void raw_init(lua_State *L, const Ticket &t, an *env, an *func, an *fini, an *tags_match= NULL) { @@ -33,9 +72,11 @@ static void raw_init(lua_State *L, const Ticket &t, *env = LuaObj::todata(L, -1); lua_pop(L, 1); + std::vector _vec_klass = (t.klass[0] == '*') ? + split_string(t.klass.substr(1), "*") : split_string(t.klass, "*"); if (t.klass.size() > 0 && t.klass[0] == '*') { lua_getglobal(L, "require"); - lua_pushstring(L, t.klass.c_str() + 1); + lua_pushstring(L, _vec_klass.at(0).c_str()); int status = lua_pcall(L, 1, 1, 0); if (status != LUA_OK) { const char *e = lua_tostring(L, -1); @@ -46,7 +87,11 @@ static void raw_init(lua_State *L, const Ticket &t, << " ): " << e; } } else { - lua_getglobal(L, t.klass.c_str()); + lua_getglobal(L, _vec_klass.at(0).c_str()); + } + + if (_vec_klass.size() > 1) { + sub_module_init(L, t, _vec_klass); } if (lua_type(L, -1) == LUA_TTABLE) { @@ -70,7 +115,7 @@ static void raw_init(lua_State *L, const Ticket &t, *fini = LuaObj::todata(L, -1); } lua_pop(L, 1); - + if (tags_match) { lua_getfield(L, -1, "tags_match"); if (lua_type(L, -1) == LUA_TFUNCTION) { diff --git a/src/lua_gears.h b/src/lua_gears.h index d763970..8c44c6f 100644 --- a/src/lua_gears.h +++ b/src/lua_gears.h @@ -24,6 +24,8 @@ class LuaTranslation : public Translation { return c_; } + virtual ~LuaTranslation(); + private: Lua *lua_; an c_; diff --git a/src/modules.cc b/src/modules.cc index 2e84459..6ca704e 100644 --- a/src/modules.cc +++ b/src/modules.cc @@ -2,6 +2,7 @@ #include #include #include +#include #include "lib/lua_templates.h" #include "lua_gears.h" @@ -16,9 +17,39 @@ static bool file_exists(const char *fname) noexcept { return false; } +namespace { +template using void_t = void; + +template +struct COMPAT { + static std::string get_shared_data_dir() { + return std::string(rime_get_api()->get_shared_data_dir()); + } + + static std::string get_user_data_dir() { + return std::string(rime_get_api()->get_user_data_dir()); + } +}; + +template +struct COMPAT().user_data_dir.string())>> { + static std::string get_shared_data_dir() { + // path::string() returns native encoding on Windows + T &deployer = rime::Service::instance().deployer(); + return deployer.shared_data_dir.string(); + } + + static std::string get_user_data_dir() { + T &deployer = rime::Service::instance().deployer(); + return deployer.user_data_dir.string(); + } +}; +} + static void lua_init(lua_State *L) { - const auto user_dir = std::string(RimeGetUserDataDir()); - const auto shared_dir = std::string(RimeGetSharedDataDir()); + + const auto user_dir = COMPAT::get_user_data_dir(); + const auto shared_dir = COMPAT::get_shared_data_dir(); types_init(L); lua_getglobal(L, "package"); diff --git a/src/opencc.cc b/src/opencc.cc index 77f7495..4413397 100644 --- a/src/opencc.cc +++ b/src/opencc.cc @@ -13,22 +13,23 @@ #include #include #include -#include #include -#include +#include #include "lib/lua_export_type.h" -#include "lib/luatype_boost_optional.h" +#include "optional.h" -using namespace std; -using boost::optional; +using std::string; +using std::vector; +using std::list; +using namespace rime; namespace { class Opencc { public: - //static shared_ptr create(const string &config_path); - Opencc(const string& config_path); + //static shared_ptr create(const path &config_path); + Opencc(const string& utf8_config_path); bool ConvertWord(const string& text, vector* forms); bool RandomConvertText(const string& text, string* simplified); bool ConvertText(const string& text, string* simplified); @@ -42,32 +43,15 @@ class Opencc { opencc::DictPtr dict_; }; -/* -shared_ptr Opencc::create(const string &config_path) { - try { - return make_shared(config_path); - } - catch (opencc::FileNotFound &ex) { - LOG(ERROR) << config_path << " : onpecc file not found";// << ex.what(); - } - catch (opencc::InvalidFormat &ex) { - LOG(ERROR) << config_path << " : opencc file InvalidFormat";// << ex.what(); - } - catch (...){ - LOG(ERROR) << config_path << "Opencc ininialize faild" ; - } - return {}; -} -*/ -Opencc::Opencc(const string& config_path) { +Opencc::Opencc(const string& utf8_config_path) { opencc::Config config; - converter_ = config.NewFromFile(config_path); + // OpenCC accepts UTF-8 encoded path. + converter_ = config.NewFromFile(utf8_config_path); const list conversions = converter_->GetConversionChain()->GetConversions(); dict_ = conversions.front()->GetDict(); } - bool Opencc::ConvertText(const string& text, string* simplified) { if (converter_ == nullptr) return false; *simplified = converter_->Convert(text); @@ -75,40 +59,90 @@ bool Opencc::ConvertText(const string& text, string* simplified) { } bool Opencc::ConvertWord(const string& text, vector* forms) { - if (dict_ == nullptr) return false; - opencc::Optional item = dict_->Match(text); - if (item.IsNull()) { - // Match not found - return false; - } else { - const opencc::DictEntry* entry = item.Get(); - for (auto&& value : entry->Values()) { - forms->push_back(std::move(value)); + if (converter_ == nullptr) return false; + const list conversions = + converter_->GetConversionChain()->GetConversions(); + vector original_words{text}; + bool matched = false; + for (auto conversion : conversions) { + opencc::DictPtr dict = conversion->GetDict(); + if (dict == nullptr) return false; + set word_set; + vector converted_words; + for (const auto& original_word : original_words) { + opencc::Optional item = + dict->Match(original_word); + if (item.IsNull()) { + // No exact match, but still need to convert partially matched + std::ostringstream buffer; + for (const char* wstr = original_word.c_str(); *wstr != '\0';) { + opencc::Optional matched = + dict->MatchPrefix(wstr); + size_t matched_length; + if (matched.IsNull()) { + matched_length = opencc::UTF8Util::NextCharLength(wstr); + buffer << opencc::UTF8Util::FromSubstr(wstr, matched_length); + } else { + matched_length = matched.Get()->KeyLength(); + buffer << matched.Get()->GetDefault(); + } + wstr += matched_length; + } + const string& converted_word = buffer.str(); + // Even if current dictionary doesn't convert the word + // (converted_word == original_word), we still need to keep it for + // subsequent dicts in the chain. e.g. s2t.json expands 里 to 里 and + // 裏, then t2tw.json passes 里 as-is and converts 裏 to 裡. + if (word_set.insert(converted_word).second) { + converted_words.push_back(converted_word); + } + continue; + } + matched = true; + const opencc::DictEntry* entry = item.Get(); + for (const auto& converted_word : entry->Values()) { + if (word_set.insert(converted_word).second) { + converted_words.push_back(converted_word); + } + } } - return forms->size() > 0; + original_words.swap(converted_words); } + // No dictionary contains the word + if (!matched) return false; + *forms = std::move(original_words); + return forms->size() > 0; } bool Opencc::RandomConvertText(const string& text, string* simplified) { if (dict_ == nullptr) return false; - const char *phrase = text.c_str(); - std::ostringstream buffer; - for (const char* pstr = phrase; *pstr != '\0';) { - opencc::Optional matched = dict_->MatchPrefix(pstr); - size_t matchedLength; - if (matched.IsNull()) { - matchedLength = opencc::UTF8Util::NextCharLength(pstr); - buffer << opencc::UTF8Util::FromSubstr(pstr, matchedLength); - } else { - matchedLength = matched.Get()->KeyLength(); - size_t i = rand() % (matched.Get()->NumValues()); - buffer << matched.Get()->Values().at(i); + const list conversions = + converter_->GetConversionChain()->GetConversions(); + const char* phrase = text.c_str(); + for (auto conversion : conversions) { + opencc::DictPtr dict = conversion->GetDict(); + if (dict == nullptr) return false; + std::ostringstream buffer; + for (const char* pstr = phrase; *pstr != '\0';) { + opencc::Optional matched = + dict->MatchPrefix(pstr); + size_t matched_length; + if (matched.IsNull()) { + matched_length = opencc::UTF8Util::NextCharLength(pstr); + buffer << opencc::UTF8Util::FromSubstr(pstr, matched_length); + } else { + matched_length = matched.Get()->KeyLength(); + size_t i = rand() % (matched.Get()->NumValues()); + buffer << matched.Get()->Values().at(i); + } + pstr += matched_length; } - pstr += matchedLength; + *simplified = buffer.str(); + phrase = simplified->c_str(); } - *simplified = buffer.str(); return *simplified != text; } + // for lua string Opencc::convert_text(const string& text) { string res; @@ -129,30 +163,53 @@ vector Opencc::convert_word(const string& text){ }; namespace OpenccReg { - typedef Opencc T; - namespace ns = boost::filesystem; - - optional make(const string &filename) { - string user_path( RimeGetUserDataDir()); - string shared_path(RimeGetSharedDataDir()); - user_path += "/opencc/" + filename; - shared_path += "/opencc/" + filename; - const string *path; - if (ns::exists(user_path)) - path = &user_path; - else if (ns::exists(shared_path)) - path = &shared_path; - else - path = &filename; - - try{ - return T(*path); + using T = Opencc; + + template using void_t = void; + + template + struct COMPAT { + static optional make(const string &filename) { + auto user_path = string(rime_get_api()->get_user_data_dir()); + auto shared_path = string(rime_get_api()->get_shared_data_dir()); + try{ + return T(user_path + "/opencc/" + filename); + } + catch(...) { + try{ + return T(shared_path + "/opencc/" + filename); + } + catch(...) { + LOG(ERROR) << " [" << user_path << "|" << shared_path << "]/opencc/" + << filename << ": File not found or InvalidFormat"; + return {}; + } + } } - catch(...) { - LOG(ERROR) << *path << " File not found or InvalidFormat"; - return {}; + }; + + template + struct COMPAT().user_data_dir.string())>> { + static optional make(const string &filename) { + U &deployer = Service::instance().deployer(); + auto user_path = deployer.user_data_dir; + auto shared_path = deployer.shared_data_dir; + try{ + return T((user_path / "opencc" / filename).u8string()); + } + catch(...) { + try{ + return T((shared_path / "opencc" / filename).u8string()); + } + catch(...) { + LOG(ERROR) << " [" << user_path << "|" << shared_path << "]/opencc/" + << filename << ": File not found or InvalidFormat"; + return {}; + } + } } - } + }; + optional> convert_word(T &t,const string &s) { vector res; if (t.ConvertWord(s,&res)) @@ -161,7 +218,7 @@ namespace OpenccReg { } static const luaL_Reg funcs[] = { - {"Opencc",WRAP(make)}, + {"Opencc",WRAP(COMPAT::make)}, { NULL, NULL }, }; diff --git a/src/optional.h b/src/optional.h new file mode 100644 index 0000000..e0f6a45 --- /dev/null +++ b/src/optional.h @@ -0,0 +1,7 @@ +#if __cplusplus >= 201703L || _MSVC_LANG >= 201703L +#include "lib/luatype_std_optional.h" +using std::optional; +#else +#include "lib/luatype_boost_optional.h" +using boost::optional; +#endif diff --git a/src/script_translator.cc b/src/script_translator.cc new file mode 100644 index 0000000..6d9e2d4 --- /dev/null +++ b/src/script_translator.cc @@ -0,0 +1,198 @@ +/* + * table_translator.cc + * Copyright (C) 2023 Shewer Lu + * + * Distributed under terms of the MIT license. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "translator.h" + +using namespace rime; + +namespace { +namespace ScriptTranslatorReg { + + class LScriptTranslator : public ScriptTranslator { + public: + LScriptTranslator(const Ticket& ticket, Lua* lua) + : ScriptTranslator(ticket), lua_(lua) {}; + + virtual bool Memorize(const CommitEntry& commit_entry); + bool memorize(const CommitEntry& commit_entry); + bool update_entry(const DictEntry& index, + int commits, const string& new_entory_prefix); + + SET_(memorize_callback, an); + optional> memorize_callback(); + string lang_name() const { return (language_) ? language_->name() : "";}; + + // TranslatorOptions + SET_(contextual_suggestions, bool); + SET_(delimiters, string&); + SET_(preedit_formatter, Projection&); + SET_(comment_formatter, Projection&); + bool reload_user_dict_disabling_patterns(an); + + // ScriptTranslator member + ACCESS_(spelling_hints, int); + ACCESS_(always_show_comments, bool); + ACCESS_(max_homophones, int); + GET_(enable_correction, bool); + void set_enable_correction(bool); + + void disconnect() { + dict_.reset(); + user_dict_.reset(); + language_.reset(); + } + + protected: + Lua* lua_; + an memorize_callback_; + void init_correction(); + }; + + using T = LScriptTranslator; + + optional> T::memorize_callback() { + if (memorize_callback_) + return memorize_callback_; + return {}; + } + + bool T::memorize(const CommitEntry& commit_entry) { + return ScriptTranslator::Memorize(commit_entry); + } + + bool T::Memorize(const CommitEntry& commit_entry) { + if (!memorize_callback_) { + return memorize(commit_entry); + } + + auto r = lua_->call, LScriptTranslator*, const CommitEntry&>( + memorize_callback_, this, commit_entry); + if (!r.ok()) { + auto e = r.get_err(); + LOG(ERROR) << "LScriptTranslator of " << name_space_ + << ": memorize_callback error(" << e.status << "): " << e.e; + return false; + } + return r.get(); + } + + void T::init_correction() { + if (auto* corrector = Corrector::Require("corrector")) { + Ticket ticket(engine_, name_space_); + corrector_.reset(corrector->Create(ticket)); + } + } + + void T::set_enable_correction(bool enable) { + if ((enable_correction_ = enable && !corrector_)) + init_correction(); + } + + bool T::update_entry(const DictEntry& entry, + int commits, const string& new_entory_prefix) { + if (user_dict_ && user_dict_->loaded()) + return user_dict_->UpdateEntry(entry, commits, new_entory_prefix); + + return false; + } + + bool T::reload_user_dict_disabling_patterns(an cl) { + return cl ? user_dict_disabling_patterns_.Load(cl) : false; + } + + an as_translator(an &t) { + return As(t); + } + + static const luaL_Reg funcs[] = { + {NULL, NULL}, + }; + + static const luaL_Reg methods[] = { + {"query", WRAPMEM(T, Query)}, // string, segment + {"start_session", WRAPMEM(T, StartSession)}, + {"finish_session", WRAPMEM(T, FinishSession)}, + {"discard_session", WRAPMEM(T, DiscardSession)}, + WMEM(memorize), // delegate TableTransaltor::Momorize + WMEM(update_entry), // delegate UserDictionary::UpdateEntry + WMEM(reload_user_dict_disabling_patterns), + {"set_memorize_callback", raw_set_memorize_callback}, // an callback function + {"disconnect", WRAPMEM(T::disconnect)}, + {NULL, NULL}, + }; + + static const luaL_Reg vars_get[] = { + Get_WMEM(name_space), // string + Get_WMEM(lang_name), // string + Get_WMEM(memorize_callback), // an callback function + // ScriptTranslator member + Get_WMEM(max_homophones), // int + Get_WMEM(spelling_hints), // int + Get_WMEM(always_show_comments), // bool + Get_WMEM(enable_correction), // bool + //TranslatorOptions + Get_WMEM(delimiters), // string& + Get_WMEM(tag), // string + Get_WMEM(enable_completion), // bool + Get_WMEM(contextual_suggestions), // bool + Get_WMEM(strict_spelling), // bool + Get_WMEM(initial_quality), // double + Get_WMEM(preedit_formatter), // Projection& + Get_WMEM(comment_formatter), // Projection& + // Memory + Get_WMEM(dict), + Get_WMEM(user_dict), + {"translator", WRAP(as_translator)}, + {NULL, NULL}, + }; + + static const luaL_Reg vars_set[] = { + {"memorize_callback", raw_set_memorize_callback}, // an callback function + // ScriptTranslator member + Set_WMEM(max_homophones), // int + Set_WMEM(spelling_hints), // int + Set_WMEM(always_show_comments), // bool + Set_WMEM(enable_correction), // bool + // TranslatorOptions + Set_WMEM(delimiters), // string& + Set_WMEM(tag), // string + Set_WMEM(enable_completion), // bool + Set_WMEM(contextual_suggestions), // bool + Set_WMEM(strict_spelling), // bool + Set_WMEM(initial_quality), // double + Set_WMEM(preedit_formatter), // Projection& + Set_WMEM(comment_formatter), // Projection& + {NULL, NULL}, + }; + + void reg_Component(lua_State* L) { + lua_getglobal(L, "Component"); + if (lua_type(L, -1) != LUA_TTABLE) { + LOG(ERROR) << "table of _G[\"Component\"] not found."; + } else { + lua_pushcfunction(L, raw_make_translator); + lua_setfield(L, -2, "ScriptTranslator"); + } + lua_pop(L, 1); + } + +} // namespace ScriptTranslatorReg +} // namespace + +void LUAWRAPPER_LOCAL script_translator_init(lua_State* L) { + EXPORT(ScriptTranslatorReg, L); + ScriptTranslatorReg::reg_Component(L); +} diff --git a/src/table_translator.cc b/src/table_translator.cc new file mode 100644 index 0000000..155d15c --- /dev/null +++ b/src/table_translator.cc @@ -0,0 +1,245 @@ +/* + * table_translator.cc + * Copyright (C) 2023 Shewer Lu + * + * Distributed under terms of the MIT license. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "translator.h" + +using namespace rime; + +namespace { +namespace TableTranslatorReg { + + class LTableTranslator : public TableTranslator { + public: + LTableTranslator(const Ticket& ticket, Lua* lua) + : TableTranslator(ticket), lua_(lua) {}; + + virtual bool Memorize(const CommitEntry& commit_entry); + bool memorize(const CommitEntry& commit_entry); + bool update_entry(const DictEntry& index, + int commits, const string& new_entory_prefix); + + SET_(memorize_callback, an); + optional> memorize_callback(); + string lang_name() const { return (language_) ? language_->name() : "";}; + + // TranslatorOptions + void set_contextual_suggestions(bool); + SET_(delimiters, string&); + SET_(preedit_formatter, Projection&); + SET_(comment_formatter, Projection&); + bool reload_user_dict_disabling_patterns(an); + + // TableTranslator member + ACCESS_(encode_commit_history, bool); + ACCESS_(max_phrase_length, int); + ACCESS_(max_homographs, int); + ACCESS_(enable_charset_filter, bool); + GET_(sentence_over_completion, bool); + void set_sentence_over_completion(bool); + GET_(enable_encoder, bool); + void set_enable_encoder(bool); + GET_(enable_sentence, bool); + void set_enable_sentence(bool); + + void disconnect() { + dict_.reset(); + user_dict_.reset(); + language_.reset(); + } + + protected: + Lua* lua_; + an memorize_callback_; + bool init_poet(); + bool init_encoder(); + }; + + + using T = LTableTranslator; + + optional> T::memorize_callback() { + if (memorize_callback_) + return memorize_callback_; + return {}; + } + + bool T::memorize(const CommitEntry& commit_entry) { + return TableTranslator::Memorize(commit_entry); + } + + bool T::Memorize(const CommitEntry& commit_entry) { + if (!memorize_callback_) { + return memorize(commit_entry); + } + + auto r = lua_->call, LTableTranslator*, const CommitEntry&>( + memorize_callback_, this, commit_entry); + if (!r.ok()) { + auto e = r.get_err(); + LOG(ERROR) << "LTableTranslator of " << name_space_ + << ": memorize_callback error(" << e.status << "): " << e.e; + return false; + } + return r.get(); + } + + bool T::update_entry(const DictEntry& entry, + int commits, const string& new_entory_prefix) { + if (user_dict_ && user_dict_->loaded()) + return user_dict_->UpdateEntry(entry, commits, new_entory_prefix); + + return false; + } + + // enable_encoder + bool T::init_encoder() { + if (!user_dict_) + return false; + encoder_.reset(new UnityTableEncoder(user_dict_.get())); + Ticket ticket(engine_, name_space_); + encoder_->Load(ticket); + if (!encoder_) { + LOG(WARNING) << "init encoder failed"; + return false; + } + return true; + } + + void T::set_enable_encoder(bool enable) { + if ((enable_encoder_ = enable && user_dict_ && !encoder_)) { + init_encoder(); + } + } + // enable sentence contextual + bool T::init_poet() { + Config* config = engine_->schema()->config(); + poet_.reset(new Poet(language(), config, Poet::LeftAssociateCompare)); + if (!poet_) { + LOG(WARNING) << "init poet failed"; + return false; + } + return true; + } + + void T::set_enable_sentence(bool enable) { + if ((enable_sentence_ = enable && !poet_)) + init_poet(); + } + + void T::set_sentence_over_completion(bool enable) { + if ((sentence_over_completion_ = enable && !poet_ )) + init_poet(); + } + + void T::set_contextual_suggestions(bool enable) { + if ((contextual_suggestions_ = enable && !poet_)) + init_poet(); + } + bool T::reload_user_dict_disabling_patterns(an cl) { + return cl ? user_dict_disabling_patterns_.Load(cl) : false; + } + + an as_translator(an &t) { + return As(t); + } + + static const luaL_Reg funcs[] = { + {NULL, NULL}, + }; + + static const luaL_Reg methods[] = { + {"query", WRAPMEM(T, Query)}, // string, segment + {"start_session", WRAPMEM(T, StartSession)}, + {"finish_session", WRAPMEM(T, FinishSession)}, + {"discard_session", WRAPMEM(T, DiscardSession)}, + WMEM(memorize), // delegate TableTransaltor::Momorize + WMEM(update_entry), // delegate UserDictionary::UpdateEntry + WMEM(reload_user_dict_disabling_patterns), + {"set_memorize_callback", raw_set_memorize_callback}, // an callback function + {"disconnect", WRAPMEM(T::disconnect)}, + {NULL, NULL}, + }; + + static const luaL_Reg vars_get[] = { + // class translator member + Get_WMEM(name_space), // string + Get_WMEM(lang_name), // string + Get_WMEM(memorize_callback), // an callback function + // TabletTranslator member + Get_WMEM(enable_charset_filter), // bool + Get_WMEM(enable_encoder), // bool + Get_WMEM(enable_sentence), // bool + Get_WMEM(sentence_over_completion), // bool + Get_WMEM(encode_commit_history), // int + Get_WMEM(max_phrase_length), // int + Get_WMEM(max_homographs), // bool + // TranslatorOptions + Get_WMEM(delimiters), // string& + Get_WMEM(tag), // string + Get_WMEM(enable_completion), // bool + Get_WMEM(contextual_suggestions), // bool + Get_WMEM(strict_spelling), // bool + Get_WMEM(initial_quality), // double + Get_WMEM(preedit_formatter), // Projection& + Get_WMEM(comment_formatter), // Projection& + // Memory + Get_WMEM(dict), + Get_WMEM(user_dict), + {"translator", WRAP(as_translator)}, + {NULL, NULL}, + }; + + static const luaL_Reg vars_set[] = { + {"memorize_callback", raw_set_memorize_callback}, // an callback function + // TableTranslator member + Set_WMEM(enable_charset_filter), // bool + Set_WMEM(enable_encoder), // bool + Set_WMEM(enable_sentence), // bool + Set_WMEM(sentence_over_completion), // bool + Set_WMEM(encode_commit_history), // bool + Set_WMEM(max_phrase_length), // int + Set_WMEM(max_homographs), // int + // TranslatorOptions + Set_WMEM(delimiters), // string& + Set_WMEM(tag), // string + Set_WMEM(enable_completion), // bool + Set_WMEM(contextual_suggestions), // bool + Set_WMEM(strict_spelling), // bool + Set_WMEM(initial_quality), // double + Set_WMEM(preedit_formatter), // Projection& + Set_WMEM(comment_formatter), // Projection& + {NULL, NULL}, + }; + + void reg_Component(lua_State* L) { + lua_getglobal(L, "Component"); + if (lua_type(L, -1) != LUA_TTABLE) { + LOG(ERROR) << "table of _G[\"Component\"] not found."; + } else { + lua_pushcfunction(L, raw_make_translator); + lua_setfield(L, -2, "TableTranslator"); + } + lua_pop(L, 1); + } + +} // namespace TableTranslatorReg +} // namespace + +void LUAWRAPPER_LOCAL table_translator_init(lua_State* L) { + EXPORT(TableTranslatorReg, L); + TableTranslatorReg::reg_Component(L); +} diff --git a/src/translator.h b/src/translator.h new file mode 100644 index 0000000..afcdc4e --- /dev/null +++ b/src/translator.h @@ -0,0 +1,88 @@ +/* + * script_translator.h + * Copyright (C) 2023 Shewer Lu + * + * Distributed under terms of the MIT license. + */ + +#ifndef _LUA_TRANSLATOR_H +#define _LUA_TRANSLATOR_H + +#include +#include "lib/lua_export_type.h" +#include "optional.h" + +#define SET_(name, type) \ + void set_##name(const type data) { \ + name##_ = data; \ + } +#define GET_(name, type) \ + type name() { \ + return name##_; \ + } +#define ACCESS_(name, type) \ + SET_(name, type); \ + GET_(name, type) + +#define Set_WMEM(name) \ + { #name, WRAPMEM(T, set_##name) } +#define WMEM(name) \ + { #name, WRAPMEM(T, name) } +#define Get_WMEM(name) \ + { #name, WRAPMEM(T, name) } + +#if LUA_VERSION_NUM < 502 +#define lua_absindex(L, i) abs_index((L), (i)) +#endif + + +template +int raw_make_translator(lua_State* L){ + int n = lua_gettop(L); + if (3 > n || 4 < n) + return 0; + + C_State C; + rime::Ticket ticket( + LuaType::todata(L, 1), + LuaType::todata(L, -2, &C), + LuaType::todata(L, -1, &C) + ); + DLOG(INFO) << "check Ticket:" << ticket.klass << "@" <::todata(L, 2) ); //overwrite schema + Lua* lua= Lua::from_state(L); + std::shared_ptr obj = rime::New(ticket, lua); + if (obj) { + LuaType>::pushdata(L, obj); + return 1; + } + else { + //LOG(ERROR) << "error creating " << typeid(O).name() << ": '" << ticket.klass << "'"; + return 0; + } +}; + +template +int raw_set_memorize_callback(lua_State *L) { + bool res = false; + auto t = LuaType>::todata(L, 1); + const int type = (1 < lua_gettop(L)) ? lua_type(L, 2) : LUA_TNIL; + if (type == LUA_TNIL) { + // reset memorize_callback + LOG(INFO) << typeid(*t).name() <<" of " << t->name_space() << ": reset memorize_callback"; + t->set_memorize_callback({}); + res = true; + } + else if (type == LUA_TFUNCTION) { + t->set_memorize_callback( LuaObj::todata(L, 2)); + res = true; + } + else { + LOG(WARNING) << typeid(*t).name() <<" of " << t->name_space() + << ": set memorize_callback '?' (function expected, got " << lua_typename(L, type) <<")"; + } + lua_pushboolean(L, res); + return 1; +} +#endif /* !_LUA_TRANSLATOR_H */ diff --git a/src/types.cc b/src/types.cc index af7553f..0d2073f 100644 --- a/src/types.cc +++ b/src/types.cc @@ -1,3 +1,4 @@ +#include #include #include #include @@ -11,27 +12,72 @@ #include #include #include +#include #include #include #include +#include #include #include "lua_gears.h" -#include #include #include "lib/lua_export_type.h" -#include "lib/luatype_boost_optional.h" +#include "optional.h" #define ENABLE_TYPES_EXT using namespace rime; -using boost::optional; namespace { +template using void_t = void; + +template +struct COMPAT { + // fallback version if librime is old + static an new_ReverseDb(const std::string &file) { + return New(string(rime_get_api()->get_user_data_dir()) + "/" + file); + } + + static string get_shared_data_dir() { + return string(rime_get_api()->get_shared_data_dir()); + } + + static string get_user_data_dir() { + return string(rime_get_api()->get_user_data_dir()); + } + + static string get_sync_dir() { + return string(rime_get_api()->get_sync_dir()); + } +}; + +template +struct COMPAT().user_data_dir.string())>> { + static an new_ReverseDb(const std::string &file) { + T &deployer = Service::instance().deployer(); + return New(deployer.user_data_dir / file); + } + + static string get_shared_data_dir() { + T &deployer = Service::instance().deployer(); + return deployer.shared_data_dir.string(); + } + + static string get_user_data_dir() { + T &deployer = Service::instance().deployer(); + return deployer.user_data_dir.string(); + } + + static string get_sync_dir() { + T &deployer = Service::instance().deployer(); + return deployer.sync_dir.string(); + } +}; + //--- wrappers for Segment namespace SegmentReg { - typedef Segment T; + using T = Segment; T make(int start_pos, int end_pos) { return Segment(start_pos, end_pos); @@ -58,6 +104,10 @@ namespace SegmentReg { t.status = T::kConfirmed; } + string active_text(T &t, const string &r) { + return r.substr(t.start, t.end - t.start); + } + static const luaL_Reg funcs[] = { { "Segment", WRAP(make) }, { NULL, NULL }, @@ -70,6 +120,7 @@ namespace SegmentReg { { "has_tag", WRAPMEM(T::HasTag) }, { "get_candidate_at", WRAPMEM(T::GetCandidateAt) }, { "get_selected_candidate", WRAPMEM(T::GetSelectedCandidate) }, + { "active_text", WRAP(active_text) }, { NULL, NULL }, }; @@ -102,9 +153,11 @@ namespace SegmentReg { //--- wrappers for an namespace CandidateReg { - typedef Candidate T; + using T = Candidate; string dynamic_type(T &c) { + if (dynamic_cast(&c)) + return "Sentence"; if (dynamic_cast(&c)) return "Phrase"; if (dynamic_cast(&c)) @@ -143,16 +196,58 @@ namespace CandidateReg { } an shadow_candidate(const an item, - const string& type, const string& text, const string& comment) + const string& type, const string& text, const string& comment, + const bool inherit_comment) { return New(item, type, text, comment); } + int raw_shadow_candidate(lua_State* L) { + size_t n = lua_gettop(L); + if (2 > n) { + return (1 == n) ? + luaL_error(L, "bad argument #2 to func (string expected, got no value)") : + luaL_error(L, "bad argument #1 to func (an expected, got no value)"); + } + // init args(2-5) ( an, type [,text, comment, inherit_comment]) + if (5 < n) + lua_pop(L, n-5); + else if (4 == n) + lua_pushboolean(L, true); + else if (4 > n) { + for (int i=n; 4 > i ; i++) + lua_pushstring(L, ""); + lua_pushboolean(L, true); + } + lua_pushcfunction(L, WRAP(shadow_candidate)); + lua_insert(L, 1); + return (LUA_OK==lua_pcall(L, lua_gettop(L)-1, 1, 0)) ? 1 : 0; + } + an uniquified_candidate(const an item, const string& type, const string& text, const string& comment) { return New(item, type, text, comment); } + int raw_uniquified_candidate(lua_State* L) { + size_t n = lua_gettop(L); + if (2 > n) { + return (1 == n) ? + luaL_error(L, "bad argument #2 to func (string expected, got no value)") : + luaL_error(L, "bad argument #1 to func (an expected, got no value)"); + } + // init args(2-4) ( an, type [,text, comment]) + if (4 < n) + lua_pop(L, n-4); + else if (4 > n) { + for (int i=n; 4 > i ; i++) + lua_pushstring(L, ""); + } + lua_pushcfunction(L, WRAP(uniquified_candidate)); + lua_insert(L, 1); + return (LUA_OK==lua_pcall(L, lua_gettop(L)-1, 1, 0)) ? 1 : 0; + } + bool append(an self, an item) { if (auto cand= As(self) ) { cand->Append(item); @@ -162,11 +257,15 @@ namespace CandidateReg { return false; }; + template + an candidate_to_(an t) { + return std::dynamic_pointer_cast(t); + }; static const luaL_Reg funcs[] = { { "Candidate", WRAP(make) }, - { "ShadowCandidate", WRAP(shadow_candidate) }, - { "UniquifiedCandidate", WRAP(uniquified_candidate) }, + { "ShadowCandidate", (raw_shadow_candidate) }, + { "UniquifiedCandidate", (raw_uniquified_candidate) }, { NULL, NULL }, }; @@ -174,8 +273,10 @@ namespace CandidateReg { { "get_dynamic_type", WRAP(dynamic_type) }, { "get_genuine", WRAP(T::GetGenuineCandidate) }, { "get_genuines", WRAP(T::GetGenuineCandidates) }, - { "to_shadow_candidate", WRAP(shadow_candidate) }, - { "to_uniquified_candidate", WRAP(uniquified_candidate) }, + { "to_shadow_candidate", (raw_shadow_candidate) }, + { "to_uniquified_candidate", (raw_uniquified_candidate) }, + { "to_phrase", WRAP(candidate_to_)}, + { "to_sentence", WRAP(candidate_to_)}, { "append", WRAP(append)}, { NULL, NULL }, }; @@ -207,7 +308,7 @@ namespace CandidateReg { //--- wrappers for an namespace TranslationReg { - typedef Translation T; + using T = Translation; int raw_make(lua_State *L) { Lua *lua = Lua::from_state(L); @@ -248,6 +349,7 @@ namespace TranslationReg { }; static const luaL_Reg vars_get[] = { + {"exhausted", WRAPMEM(T, exhausted)}, { NULL, NULL }, }; @@ -257,10 +359,10 @@ namespace TranslationReg { } namespace ReverseDbReg { - typedef ReverseDb T; + using T = ReverseDb; an make(const string &file) { - an db = New(string(RimeGetUserDataDir()) + "/" + file); + an db = COMPAT::new_ReverseDb(file); db->Load(); return db; } @@ -293,12 +395,12 @@ namespace ReverseDbReg { } namespace SegmentationReg { - typedef Segmentation T; + using T = Segmentation; - optional back(T &t) { + Segment *back(T &t) { if (t.empty()) - return {}; - return t.back(); + return nullptr; + return &t.back(); } void pop_back(T &t) { @@ -323,15 +425,15 @@ namespace SegmentationReg { return ret; } - optional get_at(T &t, const int idx) { + Segment *get_at(T &t, const int idx) { size_t size = t.size(); int index = (idx < 0) ? size + idx : idx; if (index >=0 && index < size) - return t.at(index); + return &t.at(index); LOG(WARNING) << "the index(" << idx <<")" << " is out of range(-size .. size-1); size: "<< size ; - return {}; + return nullptr; } static const luaL_Reg funcs[] = { @@ -369,7 +471,7 @@ namespace SegmentationReg { } namespace MenuReg { - typedef Menu T; + using T = Menu; an make() { return New(); @@ -401,7 +503,7 @@ namespace MenuReg { } namespace KeyEventReg { - typedef KeyEvent T; + using T = KeyEvent; int keycode(const T &t) { return t.keycode(); @@ -411,12 +513,20 @@ namespace KeyEventReg { return t.modifier(); } - an make(const string &key) { - return New(key) ; + int raw_make(lua_State *L) { + an res; + int n = lua_gettop(L); + if (n == 1) + res = New( string(lua_tostring(L, 1)) ); + else if (n > 1) + res = New( lua_tointeger(L, 1), lua_tointeger(L, 2) ); + + LuaType>::pushdata(L, res); + return 1; } static const luaL_Reg funcs[] = { - { "KeyEvent", WRAP(make) }, + { "KeyEvent", raw_make }, { NULL, NULL }, }; @@ -445,7 +555,7 @@ namespace KeyEventReg { } namespace EngineReg { - typedef Engine T; + using T = Engine; static void apply_schema(T *engine, the &schema) { engine->ApplySchema(schema.release()); @@ -477,7 +587,7 @@ namespace EngineReg { } namespace CommitRecordReg { - typedef CommitRecord T; + using T = CommitRecord; static const luaL_Reg funcs[] = { { NULL, NULL }, @@ -502,9 +612,9 @@ namespace CommitRecordReg { } namespace CommitHistoryReg { - typedef CommitHistory T; - typedef CommitRecord CR; - typedef T::reverse_iterator R_ITER; + using T = CommitHistory; + using CR = CommitRecord; + using R_ITER = T::reverse_iterator; int raw_push(lua_State *L){ C_State C; @@ -536,10 +646,10 @@ namespace CommitHistoryReg { return 0; } - optional back(T &t) { + CR *back(T &t) { if (t.empty()) - return {}; - return t.back(); + return nullptr; + return &t.back(); } vector to_table(T &t) { @@ -606,7 +716,7 @@ namespace CommitHistoryReg { } namespace ContextReg { - typedef Context T; + using T = Context; Composition &get_composition(T &t) { return t.composition(); @@ -683,7 +793,7 @@ namespace ContextReg { } namespace PreeditReg { - typedef Preedit T; + using T = Preedit; static const luaL_Reg funcs[] = { { NULL, NULL }, @@ -711,16 +821,16 @@ namespace PreeditReg { } namespace CompositionReg { - typedef Composition T; + using T = Composition; Segmentation *toSegmentation(T &t) { return dynamic_cast(&t); } - optional back(T &t) { + Segment *back(T &t) { if (t.empty()) - return {}; - return t.back(); + return nullptr; + return &t.back(); } void push_back(T &t, Segment &seg) { @@ -761,7 +871,7 @@ namespace CompositionReg { } namespace SchemaReg { - typedef Schema T; + using T = Schema; the make(const string &schema_id) { return std::unique_ptr(new T(schema_id)); @@ -793,8 +903,8 @@ namespace SchemaReg { } namespace ConfigValueReg { - typedef ConfigValue T; - typedef ConfigItem E; + using T = ConfigValue; + using E = ConfigItem; // an make(){ // return New(); @@ -883,8 +993,8 @@ namespace ConfigValueReg { }; } namespace ConfigListReg { - typedef ConfigList T; - typedef ConfigItem E; + using T = ConfigList; + using E = ConfigItem; an make(){ return New(); @@ -935,8 +1045,8 @@ namespace ConfigListReg { namespace ConfigMapReg { - typedef ConfigMap T; - typedef ConfigItem E; + using T = ConfigMap; + using E = ConfigItem; an make(){ return New(); @@ -999,10 +1109,15 @@ namespace ConfigMapReg { } namespace ConfigItemReg { - typedef ConfigItem T; - typedef ConfigMap M; - typedef ConfigList L; - typedef ConfigValue V; + using T = ConfigItem; + using M = ConfigMap; + using L = ConfigList; + using V = ConfigValue; + +template +an Get(an t) { + return std::dynamic_pointer_cast(t); +}; string type(T &t){ switch (t.type()) { @@ -1014,30 +1129,37 @@ namespace ConfigItemReg { return ""; } -//START_GET_ -//sed sed -n -e'/\/\/START_GET_/,/\/\/END_GET_/p' src/types.cc | gcc -E - -#define GET_(f_name,from ,rt, k_type) \ - an f_name( an t) { \ - if (t->type() == from::k_type) \ - return std::dynamic_pointer_cast (t);\ - return nullptr;\ + int get_obj(lua_State *L_) { + if (an t = LuaType>::todata(L_, 1)) { + auto t_type = t->type(); + if (T::kScalar == t_type) { + lua_pushcfunction(L_, WRAP(Get)); + } + else if (T::kList == t_type) { + lua_pushcfunction(L_, WRAP(Get)); + } + else if (T::kMap == t_type) { + lua_pushcfunction(L_, WRAP(Get)); + } + else { + return 0; + } + lua_pushvalue(L_, 1); + lua_call(L_, 1, 1); + return 1; + } + return 0; } - GET_( get_value,T, V, kScalar ); - GET_( get_list, T, L, kList ); - GET_( get_map, T, M, kMap ); - -#undef GET_ -//END_GET_ - static const luaL_Reg funcs[] = { { NULL, NULL }, }; static const luaL_Reg methods[] = { - {"get_value",WRAP(get_value)}, - {"get_list",WRAP(get_list)}, - {"get_map",WRAP(get_map)}, + {"get_value",WRAP(Get)}, + {"get_list",WRAP(Get)}, + {"get_map",WRAP(Get)}, + {"get_obj", get_obj}, { NULL, NULL }, }; @@ -1055,61 +1177,53 @@ namespace ConfigItemReg { namespace ProjectionReg{ typedef Projection T; - // an, ... return bool int raw_load(lua_State *L) { int n = lua_gettop(L); - bool res = false; - if (1 < n) { - an t = LuaType>::todata(L,1); - an cl; - if ( lua_isstring(L, 2) ){ - //load from strings - cl = New(); - for (int i = 2; i<=n ; i++){ - if (!lua_isstring(L,i)){ - // fixed NULL will (core dumped) error. - LOG(ERROR) << "bad argument #" << i << " to'?' string expected"; - lua_pop(L, n); - lua_pushboolean(L, false); - return 1; - } - cl->Append( - New( lua_tostring(L,i) ) ); + bool res =false; + an t = LuaType>::todata(L,1); + an cl ={}; + if (lua_isuserdata(L,2)) { + cl = LuaType>::todata(L, 2); + } + else if (lua_istable(L, 2)) { + cl = New(); + for (size_t i=1;;i++) { + lua_rawgeti(L, 2, i); + if (lua_isnil(L, -1)) { + break; + } + if (lua_isstring(L, -1)) { + auto item = New(lua_tostring(L, -1)); + cl->Append(item); } } - else { - cl = LuaType>::todata(L,2); - } - res= t->Load(cl); } - lua_pop(L, n); + res = t->Load(cl); lua_pushboolean(L, res); return 1; } - // return an, bool(loaded success) int raw_make(lua_State *L) { int n = lua_gettop(L); - an t = New(); - if ( 1 > n ) { - LuaType>::pushdata(L, t); - lua_pushboolean(L, false); - return 2; - } - else { - // raw_load(t,...) + auto t = New(); + if ( 1 <= lua_gettop(L)) { LuaType>::pushdata(L, t); - lua_rotate(L, 1, 1); + lua_insert(L, 1); raw_load(L); - LuaType>::pushdata(L, t); - lua_rotate(L, 1, 1); - return 2; } + LuaType>::pushdata(L, t); + return 1; } - string apply(T &t, const string &s) { - string res(s); - return (t.Apply(&res)) ? res : ""; + int raw_apply(lua_State* L) { + an t = LuaType>::todata(L, 1); + string res(lua_tostring(L, 2)); + bool ret_org_str = lua_gettop(L)>2 && lua_toboolean(L, 3); + if (!t->Apply(&res) && !ret_org_str) + res.clear(); + + LuaType::pushdata(L, res); + return 1; } static const luaL_Reg funcs[] = { @@ -1119,7 +1233,7 @@ namespace ProjectionReg{ static const luaL_Reg methods[] = { {"load", raw_load}, - {"apply",WRAP(apply)}, + {"apply", raw_apply}, { NULL, NULL }, }; @@ -1133,7 +1247,7 @@ namespace ProjectionReg{ } namespace ConfigReg { - typedef Config T; + using T = Config; optional get_bool(T &t, const string &path) { bool v; @@ -1254,22 +1368,21 @@ static int raw_connect(lua_State *L) { Lua *lua = Lua::from_state(L); T & t = LuaType::todata(L, 1); an o = LuaObj::todata(L, 2); + auto f = [lua, o](I... i) { + auto r = lua->void_call, Context *>(o, i...); + if (!r.ok()) { + auto e = r.get_err(); + LOG(ERROR) << "Context::Notifier error(" << e.status << "): " << e.e; + } + }; - auto c = t.connect - ([lua, o](I... i) { - auto r = lua->void_call, Context *>(o, i...); - if (!r.ok()) { - auto e = r.get_err(); - LOG(ERROR) << "Context::Notifier error(" << e.status << "): " << e.e; - } - }); - + auto c = (lua_gettop(L) > 2) ? t.connect(lua_tointeger(L, 3), f) : t.connect(f); LuaType::pushdata(L, c); return 1; } namespace ConnectionReg { - typedef boost::signals2::connection T; + using T = boost::signals2::connection; static const luaL_Reg funcs[] = { { NULL, NULL }, @@ -1311,7 +1424,7 @@ namespace NotifierReg { } namespace OptionUpdateNotifierReg { - typedef Context::OptionUpdateNotifier T; + using T = Context::OptionUpdateNotifier; static const luaL_Reg funcs[] = { { NULL, NULL }, @@ -1332,7 +1445,7 @@ namespace OptionUpdateNotifierReg { } namespace PropertyUpdateNotifierReg { - typedef Context::PropertyUpdateNotifier T; + using T = Context::PropertyUpdateNotifier; static const luaL_Reg funcs[] = { { NULL, NULL }, @@ -1353,7 +1466,7 @@ namespace PropertyUpdateNotifierReg { } namespace KeyEventNotifierReg { - typedef Context::KeyEventNotifier T; + using T = Context::KeyEventNotifier; static const luaL_Reg funcs[] = { { NULL, NULL }, @@ -1400,11 +1513,34 @@ namespace LogReg { } } namespace CommitEntryReg { - typedef CommitEntry T; + using T = CommitEntry; + using D = DictEntry; vector get(const T& ce) { return ce.elements; } + bool update_entry(const T &t, const D& entry, int commit, const string& prefix_str) { + if (!t.memory) + return false; + auto user_dict = t.memory->user_dict(); + if (!user_dict || !user_dict->loaded()) + return false; + + return user_dict->UpdateEntry(entry, commit, prefix_str); + } + + bool update(const T& t, int commit) { + if (!t.memory) + return false; + auto user_dict = t.memory->user_dict(); + if (!user_dict || !user_dict->loaded()) + return false; + + for (const DictEntry* e : t.elements) { + user_dict->UpdateEntry(*e, commit); + } + return true; + } static const luaL_Reg funcs[] = { { NULL, NULL }, @@ -1412,6 +1548,8 @@ namespace CommitEntryReg { static const luaL_Reg methods[] = { {"get",WRAP(get)}, + {"update_entry",WRAP(update_entry)}, + {"update",WRAP(update)}, { NULL, NULL }, }; @@ -1424,13 +1562,18 @@ namespace CommitEntryReg { }; } namespace DictEntryReg { - typedef DictEntry T; - an make() { - return an(new T()); + using T = DictEntry; + + int raw_make(lua_State* L) { + an t = (lua_gettop(L)>0) + ? New(LuaType::todata(L,1)) : New(); + + LuaType>::pushdata(L, t); + return 1; } static const luaL_Reg funcs[] = { - {"DictEntry",WRAP(make)}, + {"DictEntry",raw_make}, { NULL, NULL }, }; @@ -1463,8 +1606,7 @@ namespace DictEntryReg { }; } namespace CodeReg { - - typedef Code T; + using T = Code; an make() { return an(new Code()); @@ -1497,34 +1639,226 @@ namespace CodeReg { { NULL, NULL }, }; } + +namespace DictionaryReg { + using T = Dictionary; + using I = DictEntryIterator; + using D = DictEntry; + + an lookup_words(T& t, const string& code, bool predictive , size_t limit) { + an ret=New(); + t.LookupWords(ret.get(),code, predictive, limit); + return ret; + } + + vector decode(T& t, const Code& code) { + vector ret; + t.Decode(code, &ret); + return ret; + } + + static const luaL_Reg funcs[] = { + { NULL, NULL }, + }; + + static const luaL_Reg methods[] = { + { "lookup_words", WRAP(lookup_words)}, + //{ "lookup", WRAPMEM(T, Lookup)}, + { "decode", WRAP(decode)}, + { NULL, NULL }, + }; + + static const luaL_Reg vars_get[] = { + { "name", WRAPMEM(T, name)}, + { "loaded", WRAPMEM(T, loaded)}, + { NULL, NULL }, + }; + + static const luaL_Reg vars_set[] = { + { NULL, NULL }, + }; +} + +namespace UserDictionaryReg { + using T = UserDictionary; + using I = UserDictEntryIterator; + using D = DictEntry; + + an lookup_words(T& t, const string& code, bool predictive , size_t limit) { + an ret=New(); + t.LookupWords(ret.get(),code, predictive, limit); + return ret; + } + bool update_entry(T& t, const D& entry, int commits, const string& prefix, + const string lang_name) { + return (lang_name == t.name()) ? t.UpdateEntry(entry, commits, prefix) : false; + } + + static const luaL_Reg funcs[] = { + { NULL, NULL }, + }; + + static const luaL_Reg methods[] = { + { "lookup_words", WRAP(lookup_words)}, + //{ "lookup", WRAPMEM(T, Lookup)}, + { "update_entry", WRAP(update_entry)}, + { NULL, NULL }, + }; + + static const luaL_Reg vars_get[] = { + { "name", WRAPMEM(T, name)}, + { "loaded", WRAPMEM(T, loaded)}, + { "tick", WRAPMEM(T, tick)}, + { NULL, NULL }, + }; + + static const luaL_Reg vars_set[] = { + { NULL, NULL }, + }; +} + +namespace DictEntryIteratorReg { + using T = DictEntryIterator; + using D = DictEntry; + + optional> Next(T& t) { + if ( t.exhausted()) { + return {}; + } + an ret = t.Peek(); + t.Next(); + return ret; + } + + int raw_iter(lua_State* L) { + int n = lua_gettop(L); + if (n>=1) { // :iter() + lua_pushcfunction(L, WRAP(Next)); + lua_insert(L, 1); + return 2; + } + return 0; + } + + static const luaL_Reg funcs[] = { + { NULL, NULL }, + }; + + static const luaL_Reg methods[] = { + {"iter", raw_iter}, + { NULL, NULL }, + }; + + static const luaL_Reg vars_get[] = { + {"exhausted", WRAPMEM(T, exhausted)}, + {"size", WRAPMEM(T, entry_count)}, + { NULL, NULL }, + }; + + static const luaL_Reg vars_set[] = { + { NULL, NULL }, + }; + +} + +namespace UserDictEntryIteratorReg { + using T = UserDictEntryIterator; + using D = DictEntry; + + optional> Next(T& t) { + if ( t.exhausted()) { + return {}; + } + an ret = t.Peek(); + t.Next(); + return ret; + } + + int raw_iter(lua_State* L) { + int n = lua_gettop(L); + if (n>=1) { // :iter() + lua_pushcfunction(L, WRAP(Next)); + lua_insert(L, 1); + return 2; + } + return 0; + } + + static const luaL_Reg funcs[] = { + { NULL, NULL }, + }; + + static const luaL_Reg methods[] = { + {"iter", raw_iter}, + { NULL, NULL }, + }; + + static const luaL_Reg vars_get[] = { + {"exhausted", WRAPMEM(T, exhausted)}, + {"size", WRAPMEM(T, cache_size)}, + { NULL, NULL }, + }; + + static const luaL_Reg vars_set[] = { + { NULL, NULL }, + }; +} namespace MemoryReg { class LuaMemory : public Memory { an memorize_callback; Lua *lua_; public: - using Memory::Memory; - DictEntryIterator iter; - UserDictEntryIterator uter; + an iter; + an uter; - LuaMemory(Lua *lua, const Ticket& ticket) - : lua_(lua), Memory(ticket) {} + bool dictLookup(const string& str_code, + bool predictive, size_t expand_search_limit); + + bool userLookup(const string& input, const bool isExpand); + + an dictiterLookup(const string& str_code, + bool predictive, size_t expand_search_limit); - virtual bool Memorize(const CommitEntry&); + an useriterLookup(const string& input, const bool isExpand); + + vector decode(const Code& code); + bool update_userdict(const DictEntry& entry, const int commits, + const string& new_entry_prefix); + + bool update_entry(const DictEntry& entry, const int commits, + const string& new_entry_prefix, const string& lang_string); + + bool update_candidate(const an cand, const int commits); + const string lang_name() { return (language_) ? language_->name() : ""; }; + virtual bool Memorize(const CommitEntry& entry); + + LuaMemory(const Ticket& ticket, Lua* lua) + : lua_(lua), Memory(ticket) {} void memorize(an func) { memorize_callback = func; } - void clearDict() { - iter = DictEntryIterator(); + iter.reset(); } void clearUser() { - uter = UserDictEntryIterator(); + uter.reset(); + } + void disconnect() { + dict_.reset(); + user_dict_.reset(); + language_.reset(); } }; - typedef LuaMemory T; - bool MemoryReg::LuaMemory::Memorize(const CommitEntry& commit_entry) { + vector LuaMemory::decode(const Code& code) { + vector res; + if (dict_ && dict_->loaded()) + dict_->Decode(code,&res); + return res; + } + + bool LuaMemory::Memorize(const CommitEntry& commit_entry) { if (!memorize_callback) return false; @@ -1537,8 +1871,78 @@ namespace MemoryReg { return r.get(); } + bool LuaMemory::dictLookup(const string& input, const bool isExpand, size_t limit) { + iter = New();// t= New(); + limit = limit == 0 ? 0xffffffffffffffff : limit; + if (dict_ && dict_->loaded()) { + return dict_->LookupWords(iter.get(), input, isExpand, limit) > 0; + } + return false; + } + + bool LuaMemory::userLookup(const string& input, const bool isExpand) { + uter = New(); + if (user_dict_ && user_dict_->loaded()) { + return user_dict_->LookupWords(uter.get(), input, isExpand) > 0; + } + return false; + } + + an LuaMemory::dictiterLookup(const string& input, const bool isExpand, size_t limit) { + dictLookup(input, isExpand, limit); + return iter; + } + + an LuaMemory::useriterLookup(const string& input, const bool isExpand) { + userLookup(input, isExpand); + return uter; + } + + + bool LuaMemory::update_userdict(const DictEntry& entry, const int commits, + const string& new_entry_prefix) { + if (user_dict_ && user_dict_->loaded()) + return user_dict_->UpdateEntry(entry, commits, new_entry_prefix); + + return false; + } + + bool LuaMemory::update_entry(const DictEntry& entry, const int commits, + const string& new_entry_prefix, const string& lang_name) + { + if (user_dict_ && user_dict_->loaded() && lang_name == language_->name()) + return user_dict_->UpdateEntry(entry, commits, new_entry_prefix); + + return false; + } + + bool LuaMemory::update_candidate(const an cand, const int commits) { + if (!user_dict_ || !user_dict_->loaded()) + return false; + + bool res = false; + vector> cands = Candidate::GetGenuineCandidates(cand); + for (auto cand : cands) { + if (auto c = std::dynamic_pointer_cast(cand)) { + if (*language_ == *c->language()) { + for (auto entry : c->components()) { + res |= user_dict()->UpdateEntry(c->entry(), commits); + }//components + } + } + else if (auto c = std::dynamic_pointer_cast(cand)) { + res |= (*language_ == *c->language()) && + user_dict()->UpdateEntry(c->entry(), commits); + } + }// cands + return res; + } + // XXX: Currently the WRAP macro is not generic enough, // so that we need a raw function to get the lua state / parse variable args. + + using T = LuaMemory; + int raw_make(lua_State *L) { // TODO: fix the memory leak C_State C; @@ -1554,63 +1958,36 @@ namespace MemoryReg { if (3 <= n) translatorTicket.name_space = LuaType::todata(L, 3, &C); - an memoli = New(lua, translatorTicket); + an memoli = New(translatorTicket, lua); LuaType>::pushdata(L, memoli); return 1; } - bool dictLookup(T& memory, const string& input, const bool isExpand,size_t limit) { - memory.clearDict(); - limit = limit == 0 ? 0xffffffffffffffff : limit; - if (auto dict = memory.dict()) - return dict->LookupWords(&memory.iter, input, isExpand, limit) > 0; - else - return false; - } - - optional> dictNext(T& memory) { - if (memory.iter.exhausted()) { - return {}; - } - an ret = memory.iter.Peek(); - memory.iter.Next(); - return ret; - } - - bool userLookup(T& memory, const string& input, const bool isExpand) { - memory.clearUser(); - if (auto dict = memory.user_dict()) - return dict->LookupWords(&memory.uter, input, isExpand) > 0; - else - return false; - } - - optional> userNext(T& memory) { - if (memory.uter.exhausted()) { - return {}; - } - an ret = memory.uter.Peek(); - memory.uter.Next(); - return ret; - } - - bool updateToUserdict(T& memory, const DictEntry& entry, const int commits, const string& new_entry_prefix) { - if (auto dict = memory.user_dict()) - return dict->UpdateEntry(entry, commits, new_entry_prefix); - else - return false; - } + // :iter_user([func[,...]]) return next_func, entryiterator + // return next_entry, enter_iter[,func[, ...]] int raw_iter_user(lua_State* L) { - lua_pushcfunction(L, WRAP(userNext)); - lua_pushvalue(L, 1); - return 2; + an t = LuaType>::todata(L, 1); + LuaType>::pushdata(L, t->uter); + lua_replace(L, 1); + lua_getfield(L, 1, "iter"); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L) -1 , 2,0) != LUA_OK) + return 0; + return lua_gettop(L); } + // :iter_user([func[,...]]) return next_func, entryiterator + // return next_entry, enter_iter[,func[, ...]] int raw_iter_dict(lua_State* L) { - lua_pushcfunction(L, WRAP(dictNext)); - lua_pushvalue(L, 1); - return 2; + an t = LuaType>::todata(L, 1); + LuaType>::pushdata(L, t->iter); + lua_replace(L, 1); + lua_getfield(L, 1, "iter"); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L) -1 , 2,0) != LUA_OK) + return 0; + return lua_gettop(L); } static const luaL_Reg funcs[] = { @@ -1618,24 +1995,29 @@ namespace MemoryReg { {NULL, NULL}, }; - std::vector decode(T& memory, Code& code) { - std::vector res; - if (auto dict = memory.dict()) - dict->Decode(code,&res); - return res; - } static const luaL_Reg methods[] = { - { "dict_lookup", WRAP(dictLookup)}, - { "user_lookup", WRAP(userLookup)}, + {"start_session", WRAPMEM(T, StartSession)}, + {"finish_session", WRAPMEM(T, FinishSession)}, + {"discard_session", WRAPMEM(T, DiscardSession)}, + { "dict_lookup", WRAPMEM(T::dictLookup)}, // bool + { "user_lookup", WRAPMEM(T::userLookup)}, // bool + { "dictiter_lookup", WRAPMEM(T::dictiterLookup)}, // iter + { "useriter_lookup", WRAPMEM(T::useriterLookup)}, // iter { "memorize", WRAPMEM(T::memorize)}, - { "decode", WRAP(decode)}, + { "decode", WRAPMEM(T::decode)}, { "iter_dict", raw_iter_dict}, { "iter_user", raw_iter_user}, - { "update_userdict", WRAP(updateToUserdict)}, + { "update_userdict", WRAPMEM(T::update_userdict)}, + { "update_entry", WRAPMEM(T::update_entry)}, + { "update_candidate", WRAPMEM(T::update_candidate)}, + { "disconnect", WRAPMEM(T::disconnect)}, {NULL, NULL}, }; static const luaL_Reg vars_get[] = { + { "lang_name", WRAPMEM(T, lang_name)}, + { "dict", WRAPMEM(T, dict)}, + { "user_dict", WRAPMEM(T, user_dict)}, {NULL, NULL}, }; @@ -1644,9 +2026,52 @@ namespace MemoryReg { }; } // namespace MemoryReg +//--- wrappers for Spans +namespace SpansReg { + using T = Spans; + + T make() { + return Spans(); + } + + size_t count(T& spans) { + return spans.Count(); + } + + size_t count_between(T& spans, size_t start, size_t end) { + return spans.Count(start, end); + } + + static const luaL_Reg funcs[] = { + { "Spans", WRAP(make) }, + { NULL, NULL }, + }; + + static const luaL_Reg methods[] = { + { "add_span", WRAPMEM(T, AddSpan) }, + { "add_spans", WRAPMEM(T, AddSpans) }, + { "previous_stop", WRAPMEM(T, PreviousStop) }, + { "next_stop", WRAPMEM(T, NextStop) }, + { "has_vertex", WRAPMEM(T, HasVertex) }, + { "count_between", WRAP(count_between) }, + { NULL, NULL }, + }; + + static const luaL_Reg vars_get[] = { + { "start", WRAPMEM(T, start) }, + { "end", WRAPMEM(T, end) }, + { "count", WRAP(count) }, + { NULL, NULL }, + }; + + static const luaL_Reg vars_set[] = { + { NULL, NULL }, + }; +} // namespace SpansReg + //--- wrappers for Phrase namespace PhraseReg { - typedef Phrase T; + using T = Phrase; an make(MemoryReg::LuaMemory& memory, const string& type, @@ -1661,6 +2086,10 @@ namespace PhraseReg { return phrase; } + string lang_name(T &t){ + return t.language()->name(); + } + static const luaL_Reg funcs[] = { { "Phrase", WRAP(make) }, { NULL, NULL }, @@ -1668,11 +2097,13 @@ namespace PhraseReg { static const luaL_Reg methods[] = { { "toCandidate", WRAP(toCandidate)}, + { "spans", WRAPMEM(T, spans) }, { NULL, NULL }, }; static const luaL_Reg vars_get[] = { { "language", WRAPMEM(T, language)}, + { "lang_name", WRAP(lang_name)}, { "type", WRAPMEM(T, type) }, { "start", WRAPMEM(T, start) }, { "_start", WRAPMEM(T, start) }, @@ -1684,7 +2115,6 @@ namespace PhraseReg { { "weight", WRAPMEM(T, weight)}, { "code", WRAPMEM(T, code)}, { "entry", WRAPMEM(T, entry)}, - //span //language doesn't wrap yet, so Wrap it later { NULL, NULL }, }; @@ -1702,9 +2132,75 @@ namespace PhraseReg { { NULL, NULL }, }; }// Phrase work with Translator +//--- wrappers for Phrase +namespace SentenceReg { + using T = Sentence; + + an toCandidate(an t) { + return t; + } + + string lang_name(T& t){ + return t.language()->name(); + } + + vector components(T& t) { + return t.components(); + } + + vector word_lengths(T& t) { + return t.word_lengths(); + } + + static const luaL_Reg funcs[] = { + { NULL, NULL }, + }; + + static const luaL_Reg methods[] = { + { "toCandidate", WRAP(toCandidate)}, + { NULL, NULL }, + }; + + static const luaL_Reg vars_get[] = { + { "language", WRAPMEM(T, language)}, + { "lang_name", WRAP(lang_name)}, + { "type", WRAPMEM(T, type) }, + { "start", WRAPMEM(T, start) }, + { "_start", WRAPMEM(T, start) }, + { "_end", WRAPMEM(T, end) }, // end is keyword in Lua... + { "quality", WRAPMEM(T, quality) }, + { "text", WRAPMEM(T, text) }, + { "comment", WRAPMEM(T, comment) }, + { "preedit", WRAPMEM(T, preedit) }, + { "weight", WRAPMEM(T, weight)}, + { "code", WRAPMEM(T, code)}, + { "entry", WRAPMEM(T, entry)}, + //span + //language doesn't wrap yet, so Wrap it later + // Sentence membors + { "word_lengths", WRAP(word_lengths)}, + { "entrys", WRAP(components)}, + { "entrys_size", WRAPMEM(T, size)}, + { "entrys_empty", WRAPMEM(T, empty)}, + { NULL, NULL }, + }; + + static const luaL_Reg vars_set[] = { + { "type", WRAPMEM(T, set_type) }, + { "start", WRAPMEM(T, set_start) }, + { "_start", WRAPMEM(T, set_start) }, + { "_end", WRAPMEM(T, set_end) }, + { "quality", WRAPMEM(T, set_quality) }, + { "comment", WRAPMEM(T, set_comment) }, + { "preedit", WRAPMEM(T, set_preedit) }, + { "weight", WRAPMEM(T, set_weight)}, + // set_syllabifier + { NULL, NULL }, + }; +}// Sentence work with Translator namespace KeySequenceReg { - typedef KeySequence T; + using T = KeySequence; int raw_make(lua_State *L){ an t = (0(( lua_tostring(L,1) )) : New(); @@ -1740,43 +2236,23 @@ namespace KeySequenceReg { namespace RimeApiReg { string get_rime_version() { - RimeApi* rime = rime_get_api(); - return string(rime->get_version()); - } - - string get_shared_data_dir() { - RimeApi* rime = rime_get_api(); - return string(rime->get_shared_data_dir()); - } - - string get_user_data_dir() { - RimeApi* rime = rime_get_api(); - return string(rime->get_user_data_dir()); - } - - string get_sync_dir() { - RimeApi* rime = rime_get_api(); - return string(rime->get_sync_dir()); + return string(rime_get_api()->get_version()); } string get_distribution_name(){ - Deployer &deployer(Service::instance().deployer()); - return deployer.distribution_name; + return Service::instance().deployer().distribution_name; } string get_distribution_code_name(){ - Deployer &deployer(Service::instance().deployer()); - return deployer.distribution_code_name; + return Service::instance().deployer().distribution_code_name; } string get_distribution_version(){ - Deployer &deployer(Service::instance().deployer()); - return deployer.distribution_version; + return Service::instance().deployer().distribution_version; } string get_user_id(){ - Deployer &deployer(Service::instance().deployer()); - return deployer.user_id; + return Service::instance().deployer().user_id; } // boost::regex api @@ -1808,9 +2284,9 @@ namespace RimeApiReg { static const luaL_Reg funcs[]= { { "get_rime_version", WRAP(get_rime_version) }, - { "get_shared_data_dir", WRAP(get_shared_data_dir) }, - { "get_user_data_dir", WRAP(get_user_data_dir) }, - { "get_sync_dir", WRAP(get_sync_dir) }, + { "get_shared_data_dir", WRAP(COMPAT::get_shared_data_dir) }, + { "get_user_data_dir", WRAP(COMPAT::get_user_data_dir) }, + { "get_sync_dir", WRAP(COMPAT::get_sync_dir) }, { "get_distribution_name", WRAP(get_distribution_name) }, { "get_distribution_code_name", WRAP(get_distribution_code_name) }, { "get_distribution_version", WRAP(get_distribution_version) }, @@ -1829,7 +2305,7 @@ namespace RimeApiReg { } namespace SwitcherReg { - typedef Switcher T; + using T = Switcher; an make(Engine *engine) { return New(engine); @@ -1894,10 +2370,16 @@ void types_init(lua_State *L) { EXPORT(KeyEventNotifierReg, L); EXPORT(ConnectionReg, L); EXPORT(MemoryReg, L); + EXPORT(DictionaryReg, L); + EXPORT(UserDictionaryReg, L); + EXPORT(DictEntryIteratorReg, L); + EXPORT(UserDictEntryIteratorReg, L); EXPORT(DictEntryReg, L); EXPORT(CodeReg, L); EXPORT(CommitEntryReg, L); + EXPORT(SpansReg, L); EXPORT(PhraseReg, L); + EXPORT(SentenceReg, L); EXPORT(KeySequenceReg, L); EXPORT(SwitcherReg, L); LogReg::init(L); diff --git a/src/types_ext.cc b/src/types_ext.cc index 330fa7e..673fdfa 100644 --- a/src/types_ext.cc +++ b/src/types_ext.cc @@ -5,21 +5,20 @@ * Distributed under terms of the MIT license. */ +#include #include #include #include #include #include #include -#include +#include #include "lib/lua_export_type.h" -#include "lib/luatype_boost_optional.h" - +#include "optional.h" #include using namespace rime; - namespace { template using void_t = void; @@ -27,7 +26,7 @@ template using void_t = void; template struct COMPAT { // fallback version of name_space() if librime is old - static nullptr_t name_space(T &t) { + static std::nullptr_t name_space(T &t) { return nullptr; } }; @@ -39,8 +38,20 @@ struct COMPAT().name_space())>> { } }; +// fallback version of file_path() if librime is old +template struct void_t1 { using t = int; }; +template().file_name())>::t = 0> +std::string get_UserDb_file_path_string(const T &t) { + return t.file_name(); +} + +template().file_path())>::t = 0> +std::string get_UserDb_file_path_string(const T &t) { + return t.file_path().string(); +} + namespace ProcessorReg{ - typedef Processor T; + using T = Processor; int process_key_event(T &t, const KeyEvent &key){ switch (t.ProcessKeyEvent(key) ){ @@ -71,7 +82,7 @@ namespace ProcessorReg{ } namespace SegmentorReg{ - typedef Segmentor T; + using T = Segmentor; bool proceed(T &t, Segmentation & s) { return t.Proceed(&s); @@ -97,7 +108,7 @@ namespace SegmentorReg{ } namespace TranslatorReg{ - typedef Translator T; + using T = Translator; static const luaL_Reg funcs[] = { { NULL, NULL }, @@ -119,7 +130,7 @@ namespace TranslatorReg{ } namespace FilterReg{ - typedef Filter T; + using T = Filter; static const luaL_Reg funcs[] = { { NULL, NULL }, @@ -142,8 +153,8 @@ namespace FilterReg{ } // ReverseDictionary namespace ReverseLookupDictionaryReg { - typedef ReverseLookupDictionary T; - typedef ReverseLookupDictionaryComponent C; + using T = ReverseLookupDictionary; + using C = ReverseLookupDictionaryComponent; an make(const string& dict_name) { if ( auto c = (C *) T::Require("reverse_lookup_dictionary")){ @@ -186,7 +197,7 @@ namespace ReverseLookupDictionaryReg { // leveldb namespace DbAccessorReg{ - typedef DbAccessor T; + using T = DbAccessor; // return key , value or nil int raw_next(lua_State* L){ @@ -236,44 +247,60 @@ namespace DbAccessorReg{ { NULL, NULL }, }; } -namespace LevelDbReg{ - typedef LevelDb T; - typedef DbAccessor A; +namespace UserDbReg{ + using T = Db; + using A = DbAccessor; - // - an make(const string& file_name, const string& db_name){ - return New(file_name,db_name,"userdb"); + an make(const string& db_name, const string& db_class) { + if (auto comp= Db::Require(db_class)) { + return an(comp->Create(db_name)); + } + return {}; } - optional fetch(an t, const string& key){ + + an make_leveldb(const string& db_name) { + return make(db_name, "userdb"); + } + + an make_tabledb(const string& db_name) { + return make(db_name, "plain_userdb"); + } + + optional fetch(an t, const string& key) { string res; if ( t->Fetch(key,&res) ) return res; return {}; } - bool loaded(an t){ - return t->loaded(); - } - static const luaL_Reg funcs[] = { - {"LevelDb", WRAP(make)}, + {"UserDb", WRAP(make)},// an LevelDb( db_file, db_name) + {"LevelDb", WRAP(make_leveldb)},// an LevelDb( db_file, db_name) + {"TableDb", WRAP(make_tabledb)},// Db UserDb( db_name, db_type:userdb|plain_userdb) { NULL, NULL }, }; static const luaL_Reg methods[] = { - {"open", WRAPMEM(T::Open)}, - {"open_read_only", WRAPMEM(T::OpenReadOnly)}, - {"close", WRAPMEM(T::Close)}, - {"query", WRAPMEM(T::Query)}, // query(prefix_key) return DbAccessor + {"open", WRAPMEM(T, Open)}, + {"open_read_only", WRAPMEM(T, OpenReadOnly)}, + {"close", WRAPMEM(T, Close)}, + {"query", WRAPMEM(T, Query)}, // query(prefix_key) return DbAccessor {"fetch", WRAP(fetch)}, // fetch(key) return value - {"update", WRAPMEM(T::Update)}, // update(key,value) return bool - {"erase", WRAPMEM(T::Erase)}, // erase(key) return bool - {"loaded",WRAPMEM(T,loaded)}, + {"update", WRAPMEM(T, Update)}, // update(key,value) return bool + {"erase", WRAPMEM(T, Erase)}, // erase(key) return bool + {"loaded",WRAPMEM(T, loaded)}, + {"disable", WRAPMEM(T, disable)}, + {"enable", WRAPMEM(T, enable)}, { NULL, NULL }, }; static const luaL_Reg vars_get[] = { + {"_loaded",WRAPMEM(T, loaded)}, + {"read_only",WRAPMEM(T, readonly)}, + {"disabled",WRAPMEM(T, disabled)}, + {"name", WRAPMEM(T, name)}, + {"file_name", WRAP(get_UserDb_file_path_string)}, { NULL, NULL }, }; @@ -283,10 +310,10 @@ namespace LevelDbReg{ } namespace ComponentReg{ - typedef Processor P; - typedef Segmentor S; - typedef Translator T; - typedef Filter F; + using P = Processor; + using S = Segmentor; + using T = Translator; + using F = Filter; template int raw_create(lua_State *L){ @@ -314,6 +341,7 @@ namespace ComponentReg{ } }; + static const luaL_Reg funcs[] = { {"Processor", raw_create

}, {"Segmentor" , raw_create}, @@ -331,6 +359,9 @@ namespace ComponentReg{ } +void table_translator_init(lua_State *L); +void script_translator_init(lua_State *L); + void LUAWRAPPER_LOCAL types_ext_init(lua_State *L) { EXPORT(ProcessorReg, L); EXPORT(SegmentorReg, L); @@ -338,6 +369,9 @@ void LUAWRAPPER_LOCAL types_ext_init(lua_State *L) { EXPORT(FilterReg, L); EXPORT(ReverseLookupDictionaryReg, L); EXPORT(DbAccessorReg, L); - EXPORT(LevelDbReg, L); + EXPORT(UserDbReg, L); ComponentReg::init(L); + // add LtableTranslator ScriptTranslator in Component + table_translator_init(L); + script_translator_init(L); }