symbol.lua

Faddle · faddle.git · Tickets

Branches > main > 5b1f6f9 > 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}