local DISPLAY = "lcd" local INPUT = "kbd" local run, fns if not event then -- running outside of minetest local _print = print print = function(...) local args = {...} if #args == 1 and type(args[1]) == "table" then _print(run(args[1])) else _print(...) end end digiline_send = function(c, ...) print("digiline_send -> " .. c, ...) end event = { type = "program" } else -- running inside minetest print = function(...) 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, run(args[1])) else digiline_send(DISPLAY, tostring(args[1])) end end end string.rep = function(str, c) local out = "" while c > 0 do out = out .. str c = c - 1 end return out end 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 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 local show_table -- basic debug output / pretty print for objects show_table = function(t,d) if type(t) ~= "table" then return tostring(t) end 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 .. show_table(v,d+1) end end return str 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 set_env(name, ...) if type(name) == "table" then name = run(name) end local args = {...} local value if #args > 1 then value = table.concat(args, " ") elseif #args == 1 then if "table" == type(args[1]) then value = run(args[1]) else value = args[1] end end value = tonumber(value) or value mem.env[name] = value end local function get_env(name) if type(name) == "table" then name = run(name) end return mem.env[name] end local function send(channel, ...) if type(channel) == "table" then channel = run(channel) end local args = {...} if #args > 1 then digiline_send(channel, table.concat(args, " ")) elseif #args == 1 then if "table" == type(args[1]) then digiline_send(channel, run(args[1])) else digiline_send(channel, args[1]) end end end fns = { -- available to custom code echo = print, show_table = show_table, ["if"] = _if, ["while"] = _while, ["="] = set_env, ["$"] = get_env, ["true"] = function() return true end, ["false"] = function() return false end, -- ["`"] = function(...) return table.concat({...}, " ") end, digiline_send = send, } -- local example_code = "digiline_send lcd Hello!" -- local example_code = "print Hello world!" -- local example_code = "if false (print This is true.) (print This is false.)" if event.type == "digiline" then if event.channel == INPUT then run(event.msg) end elseif event.type == "program" then mem.env = {} print("Ready.") end