improved code preprocessor
parent
c3599643a9
commit
1169f5877f
150
init.lua
150
init.lua
|
@ -11,7 +11,7 @@ basic_robot.password = "raN___dOM_ p4S"; -- IMPORTANT: change it before running
|
||||||
|
|
||||||
local admin_bot_pos = {x=0,y=0,z=0} -- position of admin robot spawner that will be run automatically on server start
|
local admin_bot_pos = {x=0,y=0,z=0} -- position of admin robot spawner that will be run automatically on server start
|
||||||
|
|
||||||
basic_robot.maxoperations = 10; -- how many operations (dig, generate energy,..) available per run, 0 = unlimited
|
basic_robot.maxoperations = 10; -- how many operations (dig, place,move,...,generate energy,..) available per run, 0 = unlimited
|
||||||
basic_robot.dig_require_energy = true; -- does robot require energy to dig?
|
basic_robot.dig_require_energy = true; -- does robot require energy to dig?
|
||||||
|
|
||||||
basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes inventories to prevent player abuses
|
basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes inventories to prevent player abuses
|
||||||
|
@ -21,7 +21,7 @@ basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes invento
|
||||||
|
|
||||||
basic_robot.http_api = minetest.request_http_api();
|
basic_robot.http_api = minetest.request_http_api();
|
||||||
|
|
||||||
basic_robot.version = "2018/06/30a";
|
basic_robot.version = "2018/07/22a";
|
||||||
|
|
||||||
basic_robot.data = {}; -- stores all robot related data
|
basic_robot.data = {}; -- stores all robot related data
|
||||||
--[[
|
--[[
|
||||||
|
@ -348,34 +348,8 @@ function getSandboxEnv (name)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
run = function(script)
|
|
||||||
if basic_robot.data[name].authlevel < 3 then
|
|
||||||
local err = check_code(script);
|
|
||||||
script = preprocess_code(script);
|
|
||||||
if err then
|
|
||||||
minetest.chat_send_player(name,"#ROBOT CODE CHECK ERROR : " .. err)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local ScriptFunc, CompileError = loadstring( script )
|
|
||||||
if CompileError then
|
|
||||||
minetest.chat_send_player(name, "#code.run: compile error " .. CompileError )
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
setfenv( ScriptFunc, basic_robot.data[name].sandbox )
|
|
||||||
|
|
||||||
local Result, RuntimeError = pcall( ScriptFunc );
|
|
||||||
if RuntimeError then
|
|
||||||
minetest.chat_send_player(name, "#code.run: run error " .. RuntimeError )
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
},
|
},
|
||||||
|
|
||||||
rom = basic_robot.data[name].rom,
|
rom = basic_robot.data[name].rom,
|
||||||
|
|
||||||
string = {
|
string = {
|
||||||
|
@ -490,6 +464,34 @@ function getSandboxEnv (name)
|
||||||
end
|
end
|
||||||
|
|
||||||
if authlevel>=1 then -- robot privs
|
if authlevel>=1 then -- robot privs
|
||||||
|
|
||||||
|
env.code.run = function(script)
|
||||||
|
if basic_robot.data[name].authlevel < 3 then
|
||||||
|
local err = check_code(script);
|
||||||
|
script = preprocess_code(script);
|
||||||
|
if err then
|
||||||
|
minetest.chat_send_player(name,"#ROBOT CODE CHECK ERROR : " .. err)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local ScriptFunc, CompileError = loadstring( script )
|
||||||
|
if CompileError then
|
||||||
|
minetest.chat_send_player(name, "#code.run: compile error " .. CompileError )
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
setfenv( ScriptFunc, basic_robot.data[name].sandbox )
|
||||||
|
|
||||||
|
local Result, RuntimeError = pcall( ScriptFunc );
|
||||||
|
if RuntimeError then
|
||||||
|
minetest.chat_send_player(name, "#code.run: run error " .. RuntimeError )
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
env.self.read_form = function()
|
env.self.read_form = function()
|
||||||
local fields = basic_robot.data[name].read_form;
|
local fields = basic_robot.data[name].read_form;
|
||||||
local sender = basic_robot.data[name].form_sender;
|
local sender = basic_robot.data[name].form_sender;
|
||||||
|
@ -551,8 +553,8 @@ end
|
||||||
-- code checker
|
-- code checker
|
||||||
|
|
||||||
check_code = function(code)
|
check_code = function(code)
|
||||||
--"while ", "for ", "do ","goto ",
|
--"while ", "for ", "do ","goto ",
|
||||||
local bad_code = {"repeat", "until", "_ccounter", "_G", "while%(", "while{", "pcall","\\\""}
|
local bad_code = {"repeat", "until", "_ccounter", "_G", "while%(", "while{", "pcall"} --,"\\\"", "%[=*%[","--[["}
|
||||||
for _, v in pairs(bad_code) do
|
for _, v in pairs(bad_code) do
|
||||||
if string.find(code, v) then
|
if string.find(code, v) then
|
||||||
return v .. " is not allowed!";
|
return v .. " is not allowed!";
|
||||||
|
@ -561,6 +563,59 @@ check_code = function(code)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local identify_strings = function(code) -- returns list of positions {start,end} of literal strings in lua code
|
||||||
|
|
||||||
|
local i = 0; local j; local length = string.len(code);
|
||||||
|
local mode = 0; -- 0: not in string, 1: in '...' string, 2: in "..." string, 3. in [==[ ... ]==] string
|
||||||
|
local modes = {
|
||||||
|
{"'","'"},
|
||||||
|
{"\"","\""},
|
||||||
|
{"%[=*%[","%]=*%]"}
|
||||||
|
}
|
||||||
|
local ret = {}
|
||||||
|
while i < length do
|
||||||
|
i=i+1
|
||||||
|
|
||||||
|
local jmin = length+1;
|
||||||
|
if mode == 0 then -- not yet inside string
|
||||||
|
for k=1,#modes do
|
||||||
|
j = string.find(code,modes[k][1],i);
|
||||||
|
if j and j<jmin then -- pick closest one
|
||||||
|
jmin = j
|
||||||
|
mode = k
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if mode ~= 0 then -- found something
|
||||||
|
j=jmin
|
||||||
|
ret[#ret+1] = {jmin}
|
||||||
|
end
|
||||||
|
if not j then break end -- found nothing
|
||||||
|
else
|
||||||
|
_,j = string.find(code,modes[mode][2],i); -- search for closing pair
|
||||||
|
if not j then break end
|
||||||
|
if (mode~=2 or string.sub(code,j-1,j-1) ~= "\\") then -- not (" and \")
|
||||||
|
ret[#ret][2] = j
|
||||||
|
mode = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i=j -- move to next position
|
||||||
|
end
|
||||||
|
if mode~= 0 then ret[#ret][2] = length end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
is_inside_string = function(strings,pos) -- is position inside one of the strings?
|
||||||
|
local low = 1; local high = #strings;
|
||||||
|
local mid = high;
|
||||||
|
while high>low+1 do
|
||||||
|
mid = math.floor((low+high)/2)
|
||||||
|
if pos<strings[mid][1] then high = mid else low = mid end
|
||||||
|
end
|
||||||
|
if pos>strings[low][2] then mid = high else mid = low end
|
||||||
|
return strings[mid][1]<=pos and pos<=strings[mid][2]
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
is_inside_string = function(pos,script)
|
is_inside_string = function(pos,script)
|
||||||
local i1=string.find (script, "\"", 1);
|
local i1=string.find (script, "\"", 1);
|
||||||
if not i1 then
|
if not i1 then
|
||||||
|
@ -588,15 +643,19 @@ is_inside_string = function(pos,script)
|
||||||
end
|
end
|
||||||
return false;
|
return false;
|
||||||
end
|
end
|
||||||
|
--]]
|
||||||
|
|
||||||
-- COMPILATION
|
-- COMPILATION
|
||||||
|
|
||||||
preprocess_code = function(script)
|
preprocess_code = function(script) -- version 07/22/2018
|
||||||
|
|
||||||
--[[ idea: in each local a = function (args) ... end insert counter like:
|
--[[ idea: in each local a = function (args) ... end insert counter like:
|
||||||
local a = function (args) counter() ... end
|
local a = function (args) counter() ... end
|
||||||
when counter exceeds limit exit with error
|
when counter exceeds limit exit with error
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
|
script = script:gsub("%-%-%[%[.*%-%-%]%]",""):gsub("%-%-.*\n","\n") -- strip comments in fancy way
|
||||||
|
|
||||||
script="_ccounter = 0; " .. script;
|
script="_ccounter = 0; " .. script;
|
||||||
|
|
||||||
local i1 -- process script to insert call counter in every function
|
local i1 -- process script to insert call counter in every function
|
||||||
|
@ -607,6 +666,9 @@ preprocess_code = function(script)
|
||||||
local i1=0; local i2 = 0;
|
local i1=0; local i2 = 0;
|
||||||
local found = true;
|
local found = true;
|
||||||
|
|
||||||
|
|
||||||
|
local strings = identify_strings(script);
|
||||||
|
|
||||||
while (found) do -- PROCESS SCRIPT AND INSERT COUNTER AT PROBLEMATIC SPOTS
|
while (found) do -- PROCESS SCRIPT AND INSERT COUNTER AT PROBLEMATIC SPOTS
|
||||||
|
|
||||||
found = false;
|
found = false;
|
||||||
|
@ -614,12 +676,13 @@ preprocess_code = function(script)
|
||||||
|
|
||||||
-- i1 = where its looking
|
-- i1 = where its looking
|
||||||
|
|
||||||
i2=string.find (script, "while ", i1) -- fix while OK
|
i2=string.find (script, "while%s", i1) -- fix while OK
|
||||||
if i2 then
|
if i2 then
|
||||||
if not is_inside_string(i2,script) then
|
if not is_inside_string(strings,i2) then
|
||||||
local i21 = i2;
|
local i21 = i2;
|
||||||
i2=string.find(script, "do", i2);
|
i2=string.find(script, "%sdo%s", i2);
|
||||||
if i2 then
|
if i2 then
|
||||||
|
i2 = i2 + 1
|
||||||
script = script.sub(script,1, i2+1) .. _increase_ccounter .. script.sub(script, i2+2);
|
script = script.sub(script,1, i2+1) .. _increase_ccounter .. script.sub(script, i2+2);
|
||||||
i1=i21+6; -- after while
|
i1=i21+6; -- after while
|
||||||
found = true;
|
found = true;
|
||||||
|
@ -630,7 +693,7 @@ preprocess_code = function(script)
|
||||||
i2=string.find (script, "function", i1) -- fix functions
|
i2=string.find (script, "function", i1) -- fix functions
|
||||||
if i2 then
|
if i2 then
|
||||||
--minetest.chat_send_all("func0")
|
--minetest.chat_send_all("func0")
|
||||||
if not is_inside_string(i2,script) then
|
if not is_inside_string(strings,i2) then
|
||||||
i2=string.find(script, ")", i2);
|
i2=string.find(script, ")", i2);
|
||||||
if i2 then
|
if i2 then
|
||||||
script = script.sub(script,1, i2) .. _increase_ccounter .. script.sub(script, i2+1);
|
script = script.sub(script,1, i2) .. _increase_ccounter .. script.sub(script, i2+1);
|
||||||
|
@ -641,11 +704,12 @@ preprocess_code = function(script)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
i2=string.find (script, "for ", i1) -- fix for OK
|
i2=string.find (script, "for%s", i1) -- fix for OK
|
||||||
if i2 then
|
if i2 then
|
||||||
if not is_inside_string(i2,script) then
|
if not is_inside_string(strings,i2) then
|
||||||
i2=string.find(script, "do", i2);
|
i2=string.find(script, "%sdo%s", i2);
|
||||||
if i2 then
|
if i2 then
|
||||||
|
i2 = i2 + 1
|
||||||
script = script.sub(script,1, i2+1) .. _increase_ccounter .. script.sub(script, i2+2);
|
script = script.sub(script,1, i2+1) .. _increase_ccounter .. script.sub(script, i2+2);
|
||||||
i1=i2+string.len(_increase_ccounter);
|
i1=i2+string.len(_increase_ccounter);
|
||||||
found = true;
|
found = true;
|
||||||
|
@ -653,9 +717,9 @@ preprocess_code = function(script)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
i2=string.find (script, "goto ", i1) -- fix goto OK
|
i2=string.find (script, "goto%s", i1) -- fix goto OK
|
||||||
if i2 then
|
if i2 then
|
||||||
if not is_inside_string(i2,script) then
|
if not is_inside_string(strings,i2) then
|
||||||
script = script.sub(script,1, i2-1) .. _increase_ccounter .. script.sub(script, i2);
|
script = script.sub(script,1, i2-1) .. _increase_ccounter .. script.sub(script, i2);
|
||||||
i1=i2+string.len(_increase_ccounter)+5; -- insert + skip goto
|
i1=i2+string.len(_increase_ccounter)+5; -- insert + skip goto
|
||||||
found = true;
|
found = true;
|
||||||
|
@ -664,7 +728,7 @@ preprocess_code = function(script)
|
||||||
|
|
||||||
i2=string.find (script, "pause()", i1) -- fix pause ?
|
i2=string.find (script, "pause()", i1) -- fix pause ?
|
||||||
if i2 then
|
if i2 then
|
||||||
if not is_inside_string(i2,script) then
|
if not is_inside_string(strings,i2) then
|
||||||
script = script.sub(script,1, i2-1) .. "_ccounter = 0;" .. script.sub(script,i2)
|
script = script.sub(script,1, i2-1) .. "_ccounter = 0;" .. script.sub(script,i2)
|
||||||
i1=i2+14+7; -- insert + skip _ccounter & pause
|
i1=i2+14+7; -- insert + skip _ccounter & pause
|
||||||
found = true;
|
found = true;
|
||||||
|
@ -1385,7 +1449,7 @@ local on_receive_robot_form = function(pos, formname, fields, sender)
|
||||||
" read_text.direction(stringname,mode) reads text of signs, chests and other blocks, optional stringname for other meta,\n mode 1 read number\n"..
|
" read_text.direction(stringname,mode) reads text of signs, chests and other blocks, optional stringname for other meta,\n mode 1 read number\n"..
|
||||||
" write_text.direction(text,mode) writes text to target block as infotext\n"..
|
" write_text.direction(text,mode) writes text to target block as infotext\n"..
|
||||||
"**BOOKS/CODE\n title,text=book.read(i) returns title,contents of book at i-th position in library \n book.write(i,title,text) writes book at i-th position at spawner library\n"..
|
"**BOOKS/CODE\n title,text=book.read(i) returns title,contents of book at i-th position in library \n book.write(i,title,text) writes book at i-th position at spawner library\n"..
|
||||||
" code.run(text) compiles and runs the code in sandbox\n"..
|
" code.run(text) compiles and runs the code in sandbox (privs only)\n"..
|
||||||
" code.set(text) replaces current bytecode of robot\n"..
|
" code.set(text) replaces current bytecode of robot\n"..
|
||||||
" find_nodes(\"default:dirt\",3) returns distance to node in radius 3 around robot, or false if none\n"..
|
" find_nodes(\"default:dirt\",3) returns distance to node in radius 3 around robot, or false if none\n"..
|
||||||
"**PLAYERS\n"..
|
"**PLAYERS\n"..
|
||||||
|
|
Loading…
Reference in New Issue