symbol.lua
Branches > main > f18d690 > files / org / faddle / lang / symbol.lua
-- Symbol type
-- Interned and immutable outside of rawset
local symbol_registry = setmetatable({}, {__mode = "v"})
-- TODO is this lua's whole identifier namespace?
-- Also needs to support `.f`, +, -, ?, ->, etc, probably, if that's how I want to do this (bi-directional munging to lua names)
local symbol_regex = "^[%a_][%w_]*$"
local SYMBOL_METATABLE = {}
local NAME = {}
local MODULE = {}
local NEWINDEX = function() error("Cannot mutate list!") end
local function is_valid_part(s)
return s:match(symbol_regex) ~= nil
end
local function is_valid_symbol(module, name)
if name == nil then
if module == "." then return true end
return is_valid_part(module)
else
return is_valid_part(module) and is_valid_part(name)
end
end
local function is_symbol(x)
return getmetatable(x) == SYMBOL_METATABLE
end
local function name(sym)
if is_symbol(sym) then
return assert(sym[NAME])
else
error("Cannot get the symbol name of type " .. type(sym), 2)
end
end
local function module(sym)
if is_symbol(sym) then
return sym[MODULE]
else
error("Cannot get the symbol module of type " .. type(sym), 2)
end
end
local function str(sym)
if is_symbol(sym) then
if module(sym) then
return module(sym) .. ":" .. name(sym)
else
return name(sym)
end
else
error("Not a symbol")
end
end
-- Eventually munge these names.
-- I guess table is referring to any table but perhaps it should refer strictly to an aliased module...
-- Maybe should be 'module'
local function intern(m, n)
if not is_valid_symbol(m, n) then
error("Cannot intern invalid symbol!", 2)
end
if n == nil then
n = m
m = nil
end
local id = (m or "") .. ":" .. n
if not symbol_registry[id] then
symbol_registry[id] = setmetatable({}, {__newindex = NEWINDEX, __index = {[NAME] = n, [MODULE] = m}, __metatable = SYMBOL_METATABLE})
end
return symbol_registry[id]
end
--- Munges a simple symbol to produce a valid Lua identifier
local function munge(simple_sym)
assert(not module(simple_sym), "Cannot munge a symbol with a module.", 2)
-- Right now the identifier spaces are identical
-- If they're ever made to not be, then this would have to change of course
return name(simple_sym)
end
return {is_symbol = is_symbol,
intern = intern,
is_valid_symbol = is_valid_symbol,
name = name,
module = module,
str = str,
munge = munge}