forked from Hyperion/HyperionOS
did some reorganizing
This commit is contained in:
323
Src/lua/bin/lua
Normal file
323
Src/lua/bin/lua
Normal file
@@ -0,0 +1,323 @@
|
||||
--:Minify:--
|
||||
local C_PROMPT = 7
|
||||
local C_CONT = 13
|
||||
local C_OUT = 5
|
||||
local C_ERR = 2
|
||||
local C_KEY = 3
|
||||
local C_STR = 9
|
||||
local C_NUM = 10
|
||||
local C_BOOL = 8
|
||||
local C_NIL = 12
|
||||
local C_TABLE = 13
|
||||
|
||||
local function c(col) syscall.devctl(1, "sfgc", col) end
|
||||
local function w(s) syscall.write(1, tostring(s)) end
|
||||
|
||||
local MAX_DEPTH = 6
|
||||
local MAX_ENTRIES = 64
|
||||
|
||||
local function prettyVal(val, indent, seen)
|
||||
indent = indent or 0
|
||||
seen = seen or {}
|
||||
local t = type(val)
|
||||
|
||||
if t == "nil" then
|
||||
c(C_NIL); w("nil")
|
||||
elseif t == "boolean" then
|
||||
c(C_BOOL); w(tostring(val))
|
||||
elseif t == "number" then
|
||||
c(C_NUM)
|
||||
if val ~= val then
|
||||
w("nan")
|
||||
elseif val == math.huge then
|
||||
w("inf")
|
||||
elseif val == -math.huge then
|
||||
w("-inf")
|
||||
elseif val == math.floor(val) and math.abs(val) < 1e15 then
|
||||
w(tostring(math.floor(val)))
|
||||
else
|
||||
w(tostring(val))
|
||||
end
|
||||
elseif t == "string" then
|
||||
c(C_STR)
|
||||
local s = string.format("%q", val)
|
||||
w(s)
|
||||
elseif t == "function" then
|
||||
c(C_TABLE); w(tostring(val))
|
||||
elseif t == "table" then
|
||||
if seen[val] then
|
||||
c(C_TABLE); w("<circular " .. tostring(val) .. ">")
|
||||
return
|
||||
end
|
||||
if indent >= MAX_DEPTH then
|
||||
c(C_TABLE); w("<table " .. tostring(val) .. ">")
|
||||
return
|
||||
end
|
||||
seen[val] = true
|
||||
|
||||
local pad = string.rep(" ", indent)
|
||||
local padIn = string.rep(" ", indent + 1)
|
||||
|
||||
local arrKeys = {}
|
||||
local hashKeys = {}
|
||||
local arrMax = #val
|
||||
|
||||
for k in pairs(val) do
|
||||
if type(k) == "number" and k >= 1 and k <= arrMax and k == math.floor(k) then
|
||||
arrKeys[#arrKeys+1] = k
|
||||
else
|
||||
hashKeys[#hashKeys+1] = k
|
||||
end
|
||||
end
|
||||
table.sort(arrKeys)
|
||||
|
||||
table.sort(hashKeys, function(a, b)
|
||||
local ta, tb = type(a), type(b)
|
||||
if ta == tb then
|
||||
if ta == "string" then return a < b end
|
||||
if ta == "number" then return a < b end
|
||||
return tostring(a) < tostring(b)
|
||||
end
|
||||
return ta < tb
|
||||
end)
|
||||
|
||||
local total = #arrKeys + #hashKeys
|
||||
if total == 0 then
|
||||
c(C_TABLE); w("{}")
|
||||
seen[val] = nil
|
||||
return
|
||||
end
|
||||
|
||||
c(C_TABLE); w("{\n")
|
||||
|
||||
local shown = 0
|
||||
local function printEntry(k, v, isLast)
|
||||
shown = shown + 1
|
||||
if shown > MAX_ENTRIES then return true end
|
||||
w(padIn)
|
||||
if type(k) == "number" and arrKeys[k] then
|
||||
else
|
||||
if type(k) == "string" and k:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then
|
||||
c(C_KEY); w(k)
|
||||
else
|
||||
c(C_TABLE); w("[")
|
||||
prettyVal(k, indent+1, seen)
|
||||
c(C_TABLE); w("]")
|
||||
end
|
||||
c(C_TABLE); w(" = ")
|
||||
end
|
||||
prettyVal(v, indent+1, seen)
|
||||
c(C_TABLE)
|
||||
if not isLast then w(",") end
|
||||
w("\n")
|
||||
end
|
||||
|
||||
for i, k in ipairs(arrKeys) do
|
||||
w(padIn)
|
||||
prettyVal(val[k], indent+1, seen)
|
||||
c(C_TABLE)
|
||||
if i < total then w(",") end
|
||||
w("\n")
|
||||
shown = shown + 1
|
||||
if shown >= MAX_ENTRIES then
|
||||
c(C_NIL); w(padIn .. "-- ..." .. (total - shown) .. " more entries\n")
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if shown < MAX_ENTRIES then
|
||||
for i, k in ipairs(hashKeys) do
|
||||
local isLast = (shown + 1 >= total)
|
||||
w(padIn)
|
||||
if type(k) == "string" and k:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then
|
||||
c(C_KEY); w(k)
|
||||
else
|
||||
c(C_TABLE); w("[")
|
||||
prettyVal(k, indent+1, seen)
|
||||
c(C_TABLE); w("]")
|
||||
end
|
||||
c(C_TABLE); w(" = ")
|
||||
prettyVal(val[k], indent+1, seen)
|
||||
c(C_TABLE)
|
||||
shown = shown + 1
|
||||
if shown < total then w(",") end
|
||||
w("\n")
|
||||
if shown >= MAX_ENTRIES then
|
||||
local rem = total - shown
|
||||
if rem > 0 then
|
||||
c(C_NIL); w(padIn .. "-- ..." .. rem .. " more entries\n")
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
c(C_TABLE); w(pad .. "}")
|
||||
seen[val] = nil
|
||||
else
|
||||
c(C_TABLE); w(tostring(val))
|
||||
end
|
||||
c(1)
|
||||
end
|
||||
|
||||
local function printResults(...)
|
||||
local n = select("#", ...)
|
||||
if n == 0 then return end
|
||||
for i = 1, n do
|
||||
if i > 1 then c(C_TABLE); w("\t") end
|
||||
prettyVal(select(i, ...), 0, {})
|
||||
end
|
||||
w("\n")
|
||||
c(1)
|
||||
end
|
||||
|
||||
local luaEnv = setmetatable({}, {__index = _ENV})
|
||||
luaEnv._G = luaEnv
|
||||
|
||||
luaEnv.print = function(...)
|
||||
local n = select("#", ...)
|
||||
for i = 1, n do
|
||||
if i > 1 then w("\t") end
|
||||
prettyVal(select(i, ...), 0, {})
|
||||
end
|
||||
w("\n")
|
||||
c(1)
|
||||
end
|
||||
|
||||
luaEnv.pp = function(val)
|
||||
prettyVal(val, 0, {})
|
||||
w("\n")
|
||||
c(1)
|
||||
end
|
||||
|
||||
luaEnv.exit = setmetatable({}, {
|
||||
__tostring = function() return "function: exit()" end,
|
||||
__call = function() syscall.exit() end,
|
||||
})
|
||||
|
||||
local function compile(code)
|
||||
local exprFn = load("return " .. code, "@lua", "t", luaEnv)
|
||||
if exprFn then return exprFn, true end
|
||||
local stmtFn, err = load(code, "@lua", "t", luaEnv)
|
||||
return stmtFn, false, err
|
||||
end
|
||||
|
||||
local function isIncomplete(code)
|
||||
local _, err = load(code, "@lua", "t", luaEnv)
|
||||
return err and (err:find("<eof>") ~= nil or err:find("'end'") ~= nil
|
||||
or err:find("'then'") ~= nil or err:find("'until'") ~= nil)
|
||||
end
|
||||
|
||||
local function cleanErr(msg)
|
||||
return tostring(msg)
|
||||
:gsub("^%[string .-%]:", "")
|
||||
:gsub("^@lua:", "")
|
||||
:gsub("stack traceback:.*", "")
|
||||
:match("^%s*(.-)%s*$")
|
||||
end
|
||||
|
||||
local function runCode(code)
|
||||
local fn, isExpr, err = compile(code)
|
||||
if not fn then
|
||||
c(C_ERR); w("[error] "); c(1); w(cleanErr(err) .. "\n")
|
||||
return
|
||||
end
|
||||
|
||||
local results = table.pack(xpcall(fn, debug.traceback))
|
||||
local ok = table.remove(results, 1)
|
||||
results.n = results.n - 1
|
||||
|
||||
if not ok then
|
||||
c(C_ERR); w("[error] "); c(1); w(cleanErr(results[1]) .. "\n")
|
||||
elseif isExpr and results.n > 0 then
|
||||
c(C_OUT); w("= ")
|
||||
printResults(table.unpack(results, 1, results.n))
|
||||
end
|
||||
end
|
||||
|
||||
local function getUserInput(prompt, history)
|
||||
c(C_PROMPT); w(prompt); c(1)
|
||||
local pos = syscall.devctl(1, "gpos")
|
||||
local ox = tonumber(pos:sub(1, pos:find(";")-1))
|
||||
local oy = tonumber(pos:sub(pos:find(";")+1))
|
||||
|
||||
local input = ""
|
||||
local cursor = 1
|
||||
local histIdx = 0
|
||||
local blink = false
|
||||
local dirty = true
|
||||
|
||||
local function redraw()
|
||||
syscall.devctl(1, "spos", ox, oy)
|
||||
w(input:sub(1, cursor-1))
|
||||
if blink then syscall.devctl(1,"sfgc",16); syscall.devctl(1,"sbgc",1) end
|
||||
w(cursor > #input and " " or input:sub(cursor, cursor))
|
||||
syscall.devctl(1,"sfgc",1); syscall.devctl(1,"sbgc",16)
|
||||
w(input:sub(cursor+1) .. " ")
|
||||
dirty = false
|
||||
end
|
||||
|
||||
while true do
|
||||
local key = syscall.read(0)
|
||||
if key and key ~= "" then
|
||||
if key == "[C" then
|
||||
if cursor > 1 then cursor = cursor - 1; dirty = true end
|
||||
elseif key == "[D" then
|
||||
if cursor <= #input then cursor = cursor + 1; dirty = true end
|
||||
elseif key == "[A" then
|
||||
if history and histIdx < #history then
|
||||
histIdx = histIdx + 1
|
||||
input = history[#history - histIdx + 1]
|
||||
cursor = #input + 1; dirty = true
|
||||
end
|
||||
elseif key == "[B" then
|
||||
if histIdx > 1 then
|
||||
histIdx = histIdx - 1
|
||||
input = history[#history - histIdx + 1]
|
||||
cursor = #input + 1; dirty = true
|
||||
elseif histIdx == 1 then
|
||||
histIdx = 0; input = ""; cursor = 1; dirty = true
|
||||
end
|
||||
elseif key == "\b" then
|
||||
if cursor > 1 then
|
||||
input = input:sub(1, cursor-2) .. input:sub(cursor)
|
||||
cursor = cursor - 1; dirty = true
|
||||
end
|
||||
elseif key == "\n" then
|
||||
syscall.devctl(1,"sfgc",1); syscall.devctl(1,"sbgc",16)
|
||||
syscall.devctl(1,"spos",ox,oy)
|
||||
w(input .. " \n")
|
||||
return input
|
||||
elseif #key == 1 and key:byte(1) >= 32 and key:byte(1) < 127 then
|
||||
input=string.sub(input,1,cursor-1)..key..string.sub(input,cursor)
|
||||
cursor=cursor+1;dirty=true
|
||||
end
|
||||
end
|
||||
local nb = (math.floor(syscall.getUptime() / 500) % 2) == 0
|
||||
if nb ~= blink then blink = nb; dirty = true end
|
||||
if dirty then redraw() end
|
||||
end
|
||||
end
|
||||
|
||||
c(C_PROMPT); w("HyperionOS " .. _VERSION .. "\n")
|
||||
c(C_NIL)
|
||||
w("Interactive Lua REPL. exit() to quit.\n\n")
|
||||
c(1)
|
||||
|
||||
local history = {}
|
||||
|
||||
while true do
|
||||
local code = getUserInput("lua> ", history)
|
||||
if code == "" then goto continue end
|
||||
|
||||
while isIncomplete(code) do
|
||||
code = code .. "\n" .. getUserInput("... ", nil)
|
||||
end
|
||||
|
||||
if code ~= history[#history] then
|
||||
history[#history+1] = code
|
||||
end
|
||||
|
||||
runCode(code)
|
||||
::continue::
|
||||
end
|
||||
Reference in New Issue
Block a user