--
-- decoy.model
--
-- SPDX-FileCopyrightText: Copyright (c) 2023-2024 Chris Pressey, Cat's Eye Technologies.
-- This work is distributed under a 2-clause BSD license. For more information, see:
-- SPDX-License-Identifier: LicenseRef-BSD-2-Clause-X-Decoy
table = require "table"
--[[ ========== DEBUG ========= ]]--
debug_what = ""
do_debug = function(what, fn)
if debug_what:find(what) then
fn()
end
end
debug = function(what, s)
do_debug(what, function() print("--> (" .. s .. ")") end)
end
render = function(v, count)
if not count then count = 0 end
if count > 100 then return "!!OVERFLOW!!" end
if type(v) == "table" then
local s = "{"
local key, value
for key, value in pairs(v) do
s = s .. render(key, count + 1) .. ": " .. render(value, count + 1) .. ","
end
return s .. "}"
else
return tostring(v)
end
end
--[[ ========== Data Model ========= ]]--
--
-- The following mapping is used for types:
--
-- lambda function function
-- empty list Nil (singleton table)
-- cons cell Cons (table)
-- string String (table) -- note, this means they're not interned
-- symbol Symbol (table) -- note, this means they're not interned
-- boolean True (singleton table), False (singleton table)
-- number Number (table)
--
local list = require "decoy.model.list"
Cons = list.Cons
Nil = list.Nil
assert(Nil ~= nil)
local bool = require "decoy.model.boolean"
Boolean = bool.Boolean
True = bool.True
False = bool.False
Symbol = require "decoy.model.symbol"
String = require "decoy.model.string"
Number = require "decoy.model.number"
--[[ ========== Utils ========= ]]--
depict = function(sexp)
local s = ""
if type(sexp) == "function" then
return "<<" .. tostring(sexp) .. ">>"
elseif sexp == Nil then
return "()"
elseif Cons.is_class_of(sexp) then
s = s .. "("
s = s .. depict(sexp:head())
sexp = sexp:tail()
local done = false
while not done do
if Cons.is_class_of(sexp) then
s = s .. " "
s = s .. depict(sexp:head())
sexp = sexp:tail()
elseif sexp == Nil then
done = true
else
s = s .. " . " .. depict(sexp)
done = true
end
end
s = s .. ")"
return s
elseif Symbol.is_class_of(sexp) then
return sexp:text()
elseif String.is_class_of(sexp) then
return "\"" .. sexp:text() .. "\""
elseif Number.is_class_of(sexp) then
return tostring(sexp:value())
elseif Boolean.is_class_of(sexp) then
if sexp:value() then return "#t" else return "#f" end
elseif sexp == nil then
return "<<<LUA NIL>>>"
elseif sexp.depict then
return sexp:depict()
else
error("Invalid lua representation of s-expression: " .. render(sexp) .. ": " .. type(sexp))
end
end