if not event then
-- compat running outside of minetest
digiline_send = function(c, ...) print(...) end
event = { type = "program" }
else
-- compat running inside minetest
string.rep = function(str, c)
local out = ""
while c > 0 do
out = out .. str
c = c - 1
end
return out
end
end
local print_table -- basic debug output / pretty print for objects
print_table = function(t,d)
local str = ""
d = d or 0
for k,v in pairs(t) do
str = str .. string.rep(" ", d) .. tostring(k) .. " = " .. tostring(v) .. "\n"
if type(v) == "table" then str = str .. print_table(v,d+1) end
end
return str
end
local tokenize -- translate string into tokens of parenthesis & sequences of non-space characters
tokenize = function(str)
local tokens = {}
local currentToken = ""
while #str > 0 do
local t = str:sub(1, 1)
if t == " " then
if #currentToken > 0 then
table.insert(tokens, currentToken)
currentToken = ""
end
elseif t == "(" then
if #currentToken > 0 then
table.insert(tokens, currentToken)
currentToken = ""
end
table.insert(tokens, "(")
elseif t == ")" then
if #currentToken > 0 then
table.insert(tokens, currentToken)
currentToken = ""
end
table.insert(tokens, ")")
else
currentToken = currentToken .. t
end
str = str:sub(2)
end
if #currentToken > 0 then
table.insert(tokens, currentToken)
end
return tokens
end
local store -- store tokens into an abstract syntax tree
store = function(tokens)
local ast = {}
local ret
while #tokens > 0 do
if tokens[1] == "(" then
table.remove(tokens, 1)
ret, tokens = store(tokens)
table.insert(ast, ret)
elseif tokens[1] == ")" then
table.remove(tokens, 1)
return ast, tokens
else
table.insert(ast, table.remove(tokens, 1))
end
end
if #ast == 1 then
return ast[1]
else
return ast
end
end
local run, fns, print
run = function(str_or_ast, args)
local program, fn
if "string" == type(str_or_ast) then
program = store(tokenize(str_or_ast))
else
program = str_or_ast
end
if "string" == type(program) then
fn = program
program = {}
else
fn = table.remove(program, 1)
end
if "string" == type(fn) then
if fns[fn] then
if args then
return fns[fn](args, unpack(program))
else
return fns[fn](unpack(program))
end
elseif _G[fn] then
if args then
return _G[fn](args, unpack(program))
else
return _G[fn](unpack(program))
end
else
print("error! function '"..tostring(fn).."' doesn't exist")
end
else
return run(fn, args)
end
end
print = function(...) -- slightly modified version of print, and also goes to our display instead of the server console
local args = {...}
if #args > 1 then
digiline_send("display", table.concat(args, "\t"))
elseif #args == 1 then
if "table" == type(args[1]) then
digiline_send("display", print_table(args[1]))
else
digiline_send("display", tostring(args[1]))
end
end
end
local function _if(condition, codeT, codeF)
if run(condition) then
return run(codeT)
elseif codeF then
return run(codeF)
end
end
local function _while(condition, loop)
while run(condition) do
run(loop)
end
end
local function _for(iterate, code)
local res = run(iterate)
while res do
run(code, res)
end
end
fns = { -- available to custom code
print = print,
["$"] = run,
["if"] = _if,
["while"] = _while,
["for"] = _for,
["true"] = function() return true end,
["false"] = function() return false end,
}
-- local example_code = "digiline_send display Hello!"
-- local example_code = "print Hello world!"
-- local example_code = "$(print hi there)"
local example_code = "if false (print This is true.) (print This is false.)"
if event.type == "program" then
run(example_code)
end
Comments