TangentFox icon

Terminal WIP v2 (for minetest luacontrollers)

TangentFox | PRO | 01/30/21 09:48:35 PM UTC (Edited) | 0 ⭐ | 545 👁️ | Never ⏰ | []
Lua |

5.21 KB

|

None

|

0 👍

/

0 👎

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