symbol.lua

Faddle · faddle.git · Tickets

Branches > main > d2ef4c4 > 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 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 table of type " .. type(sym), 2)
  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

-- local function munge(sym) end
-- local function demunge(sym) end ?

return {is_symbol = is_symbol, intern = intern, is_valid_symbol = is_valid_symbol, name = name, module = module}