print.lua
Branches > main > a62588b > files / org / faddle / lang / print.lua
local list = require("org.faddle.lang.list")
local is_list = list.is_list
local first = list.first
local rest = list.rest
local count = list.count
local symbol = require("org.faddle.lang.symbol")
local is_symbol = symbol.is_symbol
local name = symbol.name
local module = symbol.module
local function quote(s)
return '"' .. s:gsub('\\','\\\\')
:gsub('"','\\"')
:gsub('\n','\\n')
:gsub('\r','\\r')
:gsub('\t','\\t')
:gsub('%z','\\0')
.. '"'
end
local function print_symbol(sym)
-- Symbols are unqualified as of now
if module(sym) then
return module(sym) .. ":" .. name(sym)
else
return name(sym)
end
end
local print_value
local function print_list(x, seen)
local l = x
local xs = {}
while count(l) > 0 do
xs[#xs+1] = print_value(first(l), seen)
l = rest(l)
end
return "(" .. table.concat(xs, " ") .. ")"
end
-- Could be a good idea if multiple tables with the same "value" are keys, like {[{}] = 1, [{}] = 2}, to print them differently using an id?
-- Otherwise that prints as {{} 1, {} 2} which is quite weird
-- Like [#0x4089324 {} #0x302498 {}] idk.
-- You could also print them with an id so they read back even if they're recursive :D
local function print_associative_table(x, seen)
if seen[x] then return "..." end
seen[x] = true
local xs = {}
for k, v in pairs(x) do
xs[#xs+1] = print_value(k, seen) .. " " .. print_value(v, seen)
end
return "{" .. table.concat(xs, ", ") .. "}"
end
local function print_sequential_table(x, seen)
if seen[x] then return "..." end
seen[x] = true
local xs = {}
for i = 1, #x do
xs[#xs+1] = print_value(x[i], seen)
end
return "[" .. table.concat(xs, " ") .. "]"
end
local function is_sequential(t)
local i = 1
if #t == 0 then return false end
for k in pairs(t) do
if k == i then
i = i + 1
else
return false
end
end
return true
end
local function print_table(x, seen)
return is_sequential(x) and print_sequential_table(x, seen) or print_associative_table(x, seen)
end
local has_debug = type(debug) == "table" and type(debug.getinfo) == "function"
local debug = debug
local function print_function(f)
if has_debug then
local info = debug.getinfo(f)
local defined = info.short_src and info.linedefined and (info.name and " " or "") .. info.short_src .. ":" .. info.linedefined or "..."
return "#fn [" .. (info.name or "") .. defined .. "]"
else
return "#fn [...]"
end
end
print_value = function(x, seen)
local t = type(x)
if t == "nil" then return "." end
if t == "boolean" or t == "number" then return tostring(x) end
if t == "string" then return quote(x) end
if is_list(x) then return print_list(x, seen) end
if is_symbol(x) then return print_symbol(x) end
if t == "table" then return print_table(x, seen) end
if t == "function" then return print_function(x) end
error("idk how to print that man: " .. t)
end
local function lisp_print(...)
local cnt = select("#", ...)
local xs = {"."}
for i = 1, cnt do
xs[i] = print_value(select(i, ...), {})
end
return table.concat(xs, ", ")
end
return {print = lisp_print}