Petr Mrázek 2012-03-11 23:01:14 +01:00
commit 68fbb535c9
11 changed files with 283 additions and 107 deletions

@ -13,3 +13,4 @@ DFHACK_PLUGIN(dfusion ${DFUSION_CPPS_ALL} ${DFUSION_HS} LINK_LIBRARIES lua)
# installs into DF root
install(DIRECTORY luafiles/ DESTINATION dfusion)
install(FILES ../../library/include/df/codegen.out.xml DESTINATION dfusion/patterns/)

@ -31,8 +31,10 @@ uint64_t timeLast=0;
DFHACK_PLUGIN("dfusion")
command_result dfusion (Core * c, vector <string> & parameters);
command_result lua_run (Core * c, vector <string> & parameters);
command_result dfusion (color_ostream &out, std::vector <std::string> &parameters);
command_result dfuse (color_ostream &out, std::vector <std::string> &parameters);
command_result lua_run (color_ostream &out, std::vector <std::string> &parameters);
command_result lua_run_file (color_ostream &out, std::vector <std::string> &parameters);
DFhackCExport const char * plugin_name ( void )
{
@ -43,8 +45,8 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand>
{
lua::state st=lua::glua::Get();
//maybe remake it to run automaticaly
lua::RegisterConsole(st,&c->con);
lua::RegisterProcess(st,c->p);
lua::RegisterConsole(st);
lua::RegisterProcess(st);
lua::RegisterHexsearch(st);
lua::RegisterMisc(st);
lua::RegisterVersionInfo(st);
@ -59,9 +61,10 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand>
st.setglobal("WINDOWS");
#endif
commands.push_back(PluginCommand("dfusion","Init dfusion system. Use 'dfusion init' to run dfusion in init mode (not interactive).",dfusion));
commands.push_back(PluginCommand("lua", "Run interactive interpreter. Use 'lua <filename>' to run <filename> instead.",lua_run));
commands.push_back(PluginCommand("dfusion","Run dfusion system (interactive i.e. can input further commands).",dfusion,true));
commands.push_back(PluginCommand("dfuse","Init dfusion system (not interactive).",dfuse,false));
commands.push_back(PluginCommand("lua", "Run interactive interpreter. Use 'lua <filename>' to run <filename> instead.",lua_run,true));
commands.push_back(PluginCommand("runlua", "Run non-interactive interpreter. Use 'runlua <filename>' to run <filename>.",lua_run_file,false));
mymutex=new tthread::mutex;
return CR_OK;
}
@ -93,9 +96,9 @@ DFhackCExport command_result plugin_onupdate_DISABLED ( Core * c )
}
catch(lua::exception &e)
{
c->con.printerr("Error OnTick:%s\n",e.what());
c->con.printerr("%s\n",lua::DebugDump(lua::glua::Get()).c_str());
c->con.msleep(1000);
c->getConsole().printerr("Error OnTick:%s\n",e.what());
c->getConsole().printerr("%s\n",lua::DebugDump(lua::glua::Get()).c_str());
c->getConsole().msleep(1000);
}
}
s.settop(0);
@ -103,13 +106,15 @@ DFhackCExport command_result plugin_onupdate_DISABLED ( Core * c )
return CR_OK;
}
void InterpreterLoop(Core* c)
void InterpreterLoop(color_ostream &out)
{
Console &con=c->con;
DFHack::CommandHistory hist;
lua::state s=lua::glua::Get();
string curline;
con.print("Type quit to exit interactive mode\n");
out.print("Type quit to exit interactive mode\n");
assert(out.is_console());
Console &con = static_cast<Console&>(out);
con.lineedit(">>",curline,hist);
while (curline!="quit") {
@ -122,18 +127,27 @@ void InterpreterLoop(Core* c)
catch(lua::exception &e)
{
con.printerr("Error:%s\n",e.what());
c->con.printerr("%s\n",lua::DebugDump(lua::glua::Get()).c_str());
con.printerr("%s\n",lua::DebugDump(lua::glua::Get()).c_str());
s.settop(0);
}
con.lineedit(">>",curline,hist);
}
s.settop(0);
}
command_result lua_run (Core * c, vector <string> & parameters)
command_result lua_run_file (color_ostream &out, std::vector <std::string> &parameters)
{
if(parameters.size()==0)
{
out.printerr("runlua without file to run!");
return CR_FAILURE;
}
return lua_run(out,parameters);
}
command_result lua_run (color_ostream &out, std::vector <std::string> &parameters)
{
Console &con=c->con;
mymutex->lock();
lua::state s=lua::glua::Get();
lua::SetConsole(s,out);
if(parameters.size()>0)
{
try{
@ -142,23 +156,21 @@ command_result lua_run (Core * c, vector <string> & parameters)
}
catch(lua::exception &e)
{
con.printerr("Error:%s\n",e.what());
c->con.printerr("%s\n",lua::DebugDump(lua::glua::Get()).c_str());
out.printerr("Error:%s\n",e.what());
out.printerr("%s\n",lua::DebugDump(lua::glua::Get()).c_str());
}
}
else
{
InterpreterLoop(c);
InterpreterLoop(out);
}
s.settop(0);// clean up
mymutex->unlock();
return CR_OK;
}
void RunDfusion(void *p)
void RunDfusion(color_ostream &out)
{
Console &con=static_cast<Core*>(p)->con;
mymutex->lock();
lua::state s=lua::glua::Get();
try{
s.getglobal("err");
@ -169,26 +181,27 @@ void RunDfusion(void *p)
}
catch(lua::exception &e)
{
con.printerr("Error:%s\n",e.what());
con.printerr("%s\n",lua::DebugDump(lua::glua::Get()).c_str());
out.printerr("Error:%s\n",e.what());
out.printerr("%s\n",lua::DebugDump(lua::glua::Get()).c_str());
}
s.settop(0);// clean up
mymutex->unlock();
}
command_result dfusion (Core * c, vector <string> & parameters)
command_result dfuse(color_ostream &out, std::vector <std::string> &parameters)
{
if(parameters[0]=="init")
{
lua::state s=lua::glua::Get();
lua::SetConsole(s,out);
s.push(1);
s.setglobal("INIT");
}
else
{
RunDfusion(out);
return CR_OK;
}
command_result dfusion (color_ostream &out, std::vector <std::string> &parameters)
{
lua::state s=lua::glua::Get();
lua::SetConsole(s,out);
s.push();
s.setglobal("INIT");
}
RunDfusion(c);
RunDfusion(out);
return CR_OK;
}

@ -6,8 +6,8 @@
namespace lua
{
void RegisterConsole(lua::state &st, DFHack::Console *c);
void RegisterConsole(lua::state &st);
void SetConsole(lua::state &st,DFHack::color_ostream& stream);
}
#endif

@ -8,6 +8,6 @@
namespace lua
{
void RegisterProcess(lua::state &st,DFHack::Process *p);
void RegisterProcess(lua::state &st);
}
#endif

@ -19,9 +19,9 @@ function GetTextRegion()
ranges__=Process.getMemRanges()
--print("Ranges:"..#ranges__)
for k,v in pairs(ranges__) do
--for k2,v2 in pairs(v) do
-- print(string.format("%d %s->%s",k,tostring(k2),tostring(v2)))
--end
for k2,v2 in pairs(v) do
--print(string.format("%d %s->%s",k,tostring(k2),tostring(v2)))
end
--local num
--flgs=""
--if(v["read"])then flgs=flgs..'r' end

@ -44,6 +44,8 @@ function mainmenu(t1)
end
dofile("dfusion/common.lua")
dofile("dfusion/utils.lua")
types=nil
dofile("dfusion/xml_struct.lua")
unlockDF()
plugins={}
table.insert(plugins,{"simple_embark","A simple embark dwarf count editor"})

@ -0,0 +1,7 @@
<ld:data-definition xmlns:ld="http://github.com/peterix/dfhack/lowered-data-definition">
<ld:global-type ld:meta="struct-type" type-name="coord">
<ld:field name="x" ld:meta="number" ld:subtype="int16_t" ld:bits="16"/>
<ld:field name="y" ld:meta="number" ld:subtype="int16_t" ld:bits="16"/>
<ld:field name="z" ld:meta="number" ld:subtype="int16_t" ld:bits="16"/>
</ld:global-type>
</ld:data-definition>

@ -40,7 +40,7 @@ function parseTree(t)
end
function parseTreeGlobals(t)
local glob={}
print("Parsing global-objects")
--print("Parsing global-objects")
for k,v in ipairs(t) do
if v.xarg~=nil and v.label=="ld:global-object" then
local name=v.xarg["name"];
@ -84,7 +84,7 @@ local df_meta={}
function df_meta:__index(key)
local addr=VersionInfo.getAddress(key)
local vartype=rawget(df,"types")[key];
if addr==nil then
if addr==0 then
error("No such global address exist")
elseif vartype==nil then
error("No such global type exist")
@ -95,7 +95,7 @@ end
function df_meta:__newindex(key,val)
local addr=VersionInfo.getAddress(key)
local vartype=rawget(df,"types")[key];
if addr==nil then
if addr==0 then
error("No such global address exist")
elseif vartype==nil then
error("No such global type exist")
@ -129,3 +129,26 @@ for k,v in pairs(labels) do
end
end
end--]=]
function addressOf(var)
local addr=rawget(var,"ptr")
return addr
end
function printGlobals()
print("Globals:")
for k,v in pairs(rawget(df,"types")) do
print(k)
end
end
function printFields(object)
local tbl
if getmetatable(object)==xtypes["struct-type"].wrap then
tbl=rawget(object,"mtype")
elseif getmetatable(object)==xtypes["struct-type"] then
tbl=object
else
error("Not an class_type or a class_object")
end
for k,v in pairs(tbl.types) do
print(k)
end
end

@ -1,13 +1,13 @@
function type_read(valtype,address)
if valtype.issimple then
print("Simple read:"..tostring(valtype.ctype))
--print("Simple read:"..tostring(valtype.ctype))
return engine.peek(address,valtype.ctype)
else
return valtype:makewrap(address)
end
end
function type_write(valtype,address,val)
if altype.issimple then
if valtype.issimple then
engine.poke(address,valtype.ctype,val)
else
engine.poke(address,DWORD,rawget(val,"ptr"))
@ -20,6 +20,15 @@ function first_of_type(node,labelname)
end
end
end
function padAddress(curoff,sizetoadd) --return new offset to place things
--windows -> sizeof(x)==alignof(x)
if sizetoadd>8 then sizetoadd=8 end
if(math.mod(curoff,sizetoadd)==0) then
return curoff
else
return curoff+(sizetoadd-math.mod(curoff,sizetoadd))
end
end
xtypes={} -- list of all types prototypes (e.g. enum-type -> announcement_type)
-- type must have new and makewrap (that makes a wrapper around ptr)
local sarr={}
@ -27,13 +36,13 @@ sarr.__index=sarr
function sarr.new(node)
local o={}
setmetatable(o,sarr)
print("Making array.")
--print("Making array.")
o.count=tonumber(node.xarg.count)
print("got cound:"..o.count)
--print("got count:"..o.count)
o.ctype=makeType(first_of_type(node,"ld:item"))
o.size=o.count*o.ctype.size
print("got subtypesize:"..o.ctype.size)
--print("got subtypesize:"..o.ctype.size)
return o
end
function sarr:makewrap(address)
@ -45,6 +54,9 @@ function sarr:makewrap(address)
end
sarr.wrap={}
function sarr.wrap:__index(key)
if key=="size" then
return rawget(self,"mtype").count
end
local num=tonumber(key)
local mtype=rawget(self,"mtype")
if num~=nil and num<mtype.count then
@ -104,22 +116,85 @@ function type_enum.new(node)
end
xtypes["enum-type"]=type_enum
local type_bitfield={}
local type_bitfield={} --bitfield can be accessed by number (bf[1]=true) or by name bf.DO_MEGA=true
type_bitfield.__index=type_bitfield
function type_bitfield.new(node)
local o={}
setmetatable(o,type_bitfield)
o.size=0
o.fields={}
for k,v in pairs(node) do
if type(v)=="table" and v.xarg~=nil then
--print("\t"..k.." "..v.xarg.name)
o[k-1]=v.xarg.name
local name=v.xarg.name
if name==nil then
name="anon_"..tostring(k)
end
--print("\t"..k.." "..name)
o.fields[k]=name
o.fields[name]=k
o.size=o.size+1
end
end
o.size=o.size/8 -- size in bytes, not bits.
return o
end
function type_bitfield:bitread(addr,nbit)
local byte=engine.peekb(addr+nbit/8)
if bit.band(byte,bit.lshift(1,nbit%8))~=0 then
return true
else
return false
end
end
function type_bitfield:bitwrite(addr,nbit,value)
local byte=engine.peekb(addr+nbit/8)
if self:bitread(addr,nbit)~= value then
local byte=bit.bxor(byte,bit.lshift(1,nbit%8))
engine.pokeb(addr+nbit/8,byte)
end
end
type_bitfield.wrap={}
function type_bitfield:makewrap(address)
local o={}
o.mtype=self
o.ptr=address
setmetatable(o,self.wrap)
return o
end
function type_bitfield.wrap:__index(key)
local myptr=rawget(self,"ptr")
local mytype=rawget(self,"mtype")
local num=tonumber(key)
if num~=nil then
if mytype.fields[num]~=nil then
return mytype:bitread(myptr,num-1)
else
error("No bit with index:"..tostring(num))
end
elseif mytype.fields[key]~= nil then
return mytype:bitread(myptr,mytype.fields[key]-1)
else
error("No such field exists")
end
end
function type_bitfield.wrap:__newindex(key,value)
local myptr=rawget(self,"ptr")
local mytype=rawget(self,"mtype")
local num=tonumber(key)
if num~=nil then
if mytype.fields[num]~=nil then
return mytype:bitwrite(myptr,num-1,value)
else
error("No bit with index:"..tostring(num))
end
elseif mytype.fields[key]~= nil then
return mytype:bitwrite(myptr,mytype.fields[key]-1,value)
else
error("No such field exists")
end
end
xtypes["bitfield-type"]=type_bitfield
@ -129,7 +204,19 @@ function type_class.new(node)
local o={}
setmetatable(o,type_class)
o.types={}
o.base={}
o.size=0
if node.xarg["inherits-from"]~=nil then
table.insert(o.base,getGlobal(node.xarg["inherits-from"]))
--error("Base class:"..node.xarg["inherits-from"])
end
for k,v in ipairs(o.base) do
for kk,vv in pairs(v.types) do
o.types[kk]={vv[1],vv[2]+o.size}
end
o.size=o.size+v.size
end
for k,v in pairs(node) do
if type(v)=="table" and v.label=="ld:field" and v.xarg~=nil then
local t_name=""
@ -141,6 +228,8 @@ function type_class.new(node)
--for k,v in pairs(ttype) do
-- print(k..tostring(v))
--end
local off=padAddress(o.size,ttype.size)
o.size=off
o.types[name]={ttype,o.size}
o.size=o.size+ttype.size
end
@ -151,7 +240,7 @@ end
type_class.wrap={}
function type_class.wrap:__index(key)
local myptr=rawget(self,"ptr")
local mytype=rawget(self,"ptype")
local mytype=rawget(self,"mtype")
if mytype.types[key] ~= nil then
return type_read(mytype.types[key][1],myptr+mytype.types[key][2])
else
@ -266,9 +355,13 @@ function farr:makewrap(address)
end
farr.wrap={}
function farr.wrap:__index(key)
local num=tonumber(key)
local mtype=rawget(self,"mtype")
local size=type_read(rawget(self,"ptr")+4,DWORD)
if key=="size" then
return size/mtype.ctype.size;
end
error("TODO make __index for df-flagarray")
if num~=nil and num<sizethen then
return type_read(mtype.ctype,num*mtype.ctype.size+rawget(self,"ptr"))
@ -292,14 +385,15 @@ local stl_vec={}
stl_vec.__index=stl_vec
function stl_vec.new(node)
local o={}
setmetatable(o,stl_vec)
o.size=12
o.size=16
local titem=first_of_type(node,"ld:item")
if titem~=nil then
o.item_type=makeType(titem)
else
o.item_type=getSimpleType("uint32_t")
end
setmetatable(o,stl_vec)
return o
end
function stl_vec:makewrap(address)
@ -312,10 +406,13 @@ end
stl_vec.wrap={}
function stl_vec.wrap:__index(key)
local num=tonumber(key)
local mtype=rawget(self,"item_type")
local mtype=rawget(self,"mtype")
local ptr=rawget(self,"ptr")
local p_begin=type_read(ptr,DWORD)
local p_end=type_read(ptr+4,DWORD)
local p_begin=engine.peek(ptr,DWORD)
local p_end=engine.peek(ptr+4,DWORD)
if key=="size" then
return (p_end-p_begin)/mtype.item_type.size;
end
--allocend=type_read(ptr+8,DWORD)
error("TODO make __index for stl_vec")
if num~=nil and num<sizethen then
@ -386,6 +483,16 @@ function bytes_pad.new(node)
end
xtypes["bytes"]=bytes_pad
--------------------------------------------
function getGlobal(name)
if types[name]== nil then
findAndParse(name)
if types[name]== nil then
error("type:"..name.." failed find-and-parse")
end
--error("type:"..node.xarg["type-name"].." should already be ready")
end
return types[name]
end
parser={}
parser["ld:global-type"]=function (node)
return xtypes[node.xarg.meta].new(node)
@ -393,6 +500,7 @@ end
parser["ld:global-object"]=function (node)
end
parser["ld:field"]=function (node)
local meta=node.xarg.meta
if meta=="number" or (meta=="primitive" and node.xarg.subtype=="stl-string") then
@ -400,14 +508,7 @@ parser["ld:field"]=function (node)
elseif meta=="static-array" then
return xtypes["static-array"].new(node)
elseif meta=="global" then
if types[node.xarg["type-name"]]== nil then
findAndParse(node.xarg["type-name"])
if types[node.xarg["type-name"]]== nil then
error("type:"..node.xarg["type-name"].." failed find-and-parse")
end
--error("type:"..node.xarg["type-name"].." should already be ready")
end
return types[node.xarg["type-name"]]
return getGlobal(node.xarg["type-name"])
elseif meta=="compound" then
if node.xarg.subtype==nil then
return xtypes["struct-type"].new(node)

@ -1,11 +1,11 @@
#include "lua_Console.h"
//TODO error management. Using lua error? or something other?
static DFHack::Console* GetConsolePtr(lua::state &st)
static DFHack::color_ostream* GetConsolePtr(lua::state &st)
{
int t=st.gettop();
st.getglobal("Console");
st.getfield("__pointer");
DFHack::Console* c=static_cast<DFHack::Console*>(lua_touserdata(st,-1));
DFHack::color_ostream* c=static_cast<DFHack::color_ostream*>(lua_touserdata(st,-1));
st.settop(t);
return c;
}
@ -13,7 +13,7 @@ static int lua_Console_print(lua_State *S)
{
lua::state st(S);
int t=st.gettop();
DFHack::Console* c=GetConsolePtr(st);
DFHack::color_ostream* c=GetConsolePtr(st);
c->print("%s",st.as<string>(t).c_str());
return 0;
}
@ -22,7 +22,7 @@ static int lua_Console_printerr(lua_State *S)
{
lua::state st(S);
int t=st.gettop();
DFHack::Console* c=GetConsolePtr(st);
DFHack::color_ostream* c=GetConsolePtr(st);
c->printerr("%s",st.as<string>(t).c_str());
return 0;
}
@ -30,69 +30,95 @@ static int lua_Console_printerr(lua_State *S)
static int lua_Console_clear(lua_State *S)
{
lua::state st(S);
DFHack::Console* c=GetConsolePtr(st);
DFHack::color_ostream* c=GetConsolePtr(st);
c->clear();
return 0;
}
static int lua_Console_gotoxy(lua_State *S)
{
lua::state st(S);
DFHack::Console* c=GetConsolePtr(st);
c->gotoxy(st.as<int>(1,1),st.as<int>(1,2));
DFHack::color_ostream* c=GetConsolePtr(st);
if(c->is_console())
{
DFHack::Console* con=static_cast<DFHack::Console*>(c);
con->gotoxy(st.as<int>(1,1),st.as<int>(1,2));
}
return 0;
}
static int lua_Console_color(lua_State *S)
{
lua::state st(S);
DFHack::Console* c=GetConsolePtr(st);
DFHack::color_ostream* c=GetConsolePtr(st);
c->color( static_cast<DFHack::Console::color_value>(st.as<int>(-1,1)) );
return 0;
}
static int lua_Console_reset_color(lua_State *S)
{
lua::state st(S);
DFHack::Console* c=GetConsolePtr(st);
DFHack::color_ostream* c=GetConsolePtr(st);
c->reset_color();
return 0;
}
static int lua_Console_cursor(lua_State *S)
{
lua::state st(S);
DFHack::Console* c=GetConsolePtr(st);
c->cursor(st.as<bool>(1));
DFHack::color_ostream* c=GetConsolePtr(st);
if(c->is_console())
{
DFHack::Console* con=static_cast<DFHack::Console*>(c);
con->cursor(st.as<bool>(1));
}
return 0;
}
static int lua_Console_msleep(lua_State *S)
{
lua::state st(S);
DFHack::Console* c=GetConsolePtr(st);
c->msleep(st.as<unsigned>(1));
DFHack::color_ostream* c=GetConsolePtr(st);
if(c->is_console())
{
DFHack::Console* con=static_cast<DFHack::Console*>(c);
con->msleep(st.as<unsigned>(1));
}
return 0;
}
static int lua_Console_get_columns(lua_State *S)
{
lua::state st(S);
DFHack::Console* c=GetConsolePtr(st);
st.push(c->get_columns());
DFHack::color_ostream* c=GetConsolePtr(st);
if(c->is_console())
{
DFHack::Console* con=static_cast<DFHack::Console*>(c);
st.push(con->get_columns());
}
return 1;
}
static int lua_Console_get_rows(lua_State *S)
{
lua::state st(S);
DFHack::Console* c=GetConsolePtr(st);
st.push(c->get_rows());
DFHack::color_ostream* c=GetConsolePtr(st);
if(c->is_console())
{
DFHack::Console* con=static_cast<DFHack::Console*>(c);
st.push(con->get_rows());
}
return 1;
}
static int lua_Console_lineedit(lua_State *S)
{
lua::state st(S);
DFHack::Console* c=GetConsolePtr(st);
DFHack::color_ostream* c=GetConsolePtr(st);
if(c->is_console())
{
DFHack::Console* con=static_cast<DFHack::Console*>(c);
string ret;
DFHack::CommandHistory hist;
int i=c->lineedit(st.as<string>(1),ret,hist);
int i=con->lineedit(st.as<string>(1),ret,hist);
st.push(ret);
st.push(i);
return 2;// dunno if len is needed...
}
else
return 0;
}
const luaL_Reg lua_console_func[]=
{
@ -109,7 +135,7 @@ const luaL_Reg lua_console_func[]=
{"lineedit",lua_Console_lineedit},
{NULL,NULL}
};
void lua::RegisterConsole(lua::state &st, DFHack::Console *c)
void lua::RegisterConsole(lua::state &st)
{
st.getglobal("Console");
if(st.is<lua::nil>())
@ -118,10 +144,21 @@ void lua::RegisterConsole(lua::state &st, DFHack::Console *c)
st.newtable();
}
st.pushlightuserdata(c);
st.setfield("__pointer");
lua::RegFunctionsLocal(st, lua_console_func);
//TODO add color consts
st.setglobal("Console");
}
void lua::SetConsole(lua::state &st,DFHack::color_ostream& stream)
{
int top=st.gettop();
st.getglobal("Console");
if(st.is<lua::nil>())
{
st.pop();
st.newtable();
}
st.pushlightuserdata(&stream);
st.setfield("__pointer");
st.settop(top);
}

@ -2,12 +2,7 @@
static DFHack::Process* GetProcessPtr(lua::state &st)
{
int t=st.gettop();
st.getglobal("Process");
st.getfield("__pointer");
DFHack::Process* c=static_cast<DFHack::Process*>(lua_touserdata(st,-1));
st.settop(t);
return c;
return DFHack::Core::getInstance().p;
}
static int lua_Process_readDWord(lua_State *S)
@ -275,7 +270,7 @@ const luaL_Reg lua_process_func[]=
{NULL,NULL}
};
#undef PROC_FUNC
void lua::RegisterProcess(lua::state &st,DFHack::Process *p)
void lua::RegisterProcess(lua::state &st)
{
st.getglobal("Process");
if(st.is<lua::nil>())
@ -284,9 +279,6 @@ void lua::RegisterProcess(lua::state &st,DFHack::Process *p)
st.newtable();
}
st.pushlightuserdata(p);
st.setfield("__pointer");
lua::RegFunctionsLocal(st, lua_process_func);
st.setglobal("Process");