TangentFox icon

Terminal WIP (for minetest luacontrollers)

TangentFox | PRO | 01/30/21 09:47:24 PM UTC (Edited) | 0 ⭐ | 522 👁️ | Never ⏰ | []
Lua |

4.07 KB

|

None

|

0 👍

/

0 👎

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