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