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
Comments