lua metaprogram: atom bundle support.

This commit is contained in:
ed
2026-08-21 10:13:32 -04:00
parent b2858b3c73
commit 1b950ab5b5
4 changed files with 144 additions and 4 deletions
+10
View File
@@ -1041,6 +1041,16 @@ function M.find_atom_proc_decl_for(source, before_pos, mips_atom_ptr_len)
if source:sub(next_pos, next_pos) == "(" then if source:sub(next_pos, next_pos) == "(" then
local inner, after_paren = M.read_parens(source, next_pos) ---@type string|nil, integer local inner, after_paren = M.read_parens(source, next_pos) ---@type string|nil, integer
if inner then if inner then
if ident == "AtomBundleEntry_" then
local tmpl = M.split_top_level_commas(inner) ---@type string[]
if #tmpl ~= 2 then return nil end
local name = M.trim(tmpl[1]) .. "_" .. M.trim(tmpl[2]) ---@type string
local formals_pos = M.skip_ws_and_cmt(source, after_paren) ---@type integer
if source:sub(formals_pos, formals_pos) ~= "(" then return nil end
local real_inner, after_real = M.read_parens(source, formals_pos) ---@type string|nil, integer
if not real_inner then return nil end
return name, real_inner, name, after_real
end
return ident, inner, ident, after_paren return ident, inner, ident, after_paren
end end
end end
+30
View File
@@ -544,6 +544,35 @@ local function render_section_binds(add, view)
if not wrote then add("_(none)_"); add("") end if not wrote then add("_(none)_"); add("") end
end end
--- @param add fun(s: string): nil
--- @param view ModuleView
--- @return nil
local function render_section_atom_bundles(add, view)
local bundles = (view.corpus and view.corpus.atom_bundles) or {} ---@type table<string, AtomBundle>
local names = {} ---@type string[]
for name, bundle in pairs(bundles) do ---@type string, AtomBundle
if path_in_module(bundle.path, view) then
names[#names + 1] = name
end
end
if #names == 0 then add("_(none)_"); add(""); return end
table.sort(names)
for _, name in ipairs(names) do ---@type integer, string
local bundle = bundles[name] ---@type AtomBundle
local entries = bundle.entries or {} ---@type table<string, string>
add(string.format("### %s", name))
for _, slot in ipairs(bundle.slots or {}) do ---@type integer, string
local ident = entries[slot] ---@type string|nil
if ident then
add(string.format("- `%s` `%s`", slot, ident))
else
add(string.format("- `%s`", slot))
end
end
add("")
end
end
--- @param add fun(s: string): nil --- @param add fun(s: string): nil
--- @param view ModuleView --- @param view ModuleView
--- @return nil --- @return nil
@@ -895,6 +924,7 @@ local SECTION_RENDERERS = { ---@type SectionRenderer[]
{ header = "## Annotations", render = render_section_annotations }, { header = "## Annotations", render = render_section_annotations },
{ header = "## Component annotations", render = render_section_component_annotations }, { header = "## Component annotations", render = render_section_component_annotations },
{ header = "## Binds_* structs", render = render_section_binds }, { header = "## Binds_* structs", render = render_section_binds },
{ header = "## Atom bundles", render = render_section_atom_bundles },
{ header = "## Phases / views / ctx", render = render_section_phases }, { header = "## Phases / views / ctx", render = render_section_phases },
{ header = "## Register aliases", render = render_section_aliases }, { header = "## Register aliases", render = render_section_aliases },
{ header = "## Auto-reg", render = render_section_autoreg }, { header = "## Auto-reg", render = render_section_autoreg },
+102 -4
View File
@@ -127,6 +127,13 @@ local parse_enum_int_literal ---@type fun(text: string, start: integer): (intege
--- @field body string --- @field body string
--- @field bytes integer|nil --- @field bytes integer|nil
--- @class AtomBundle
--- @field name string
--- @field slots string[] -- typedef order
--- @field line integer
--- @field path string
--- @field entries table<string, string>|nil -- slot → B_E when an AtomBundleEntry_ proc exists
--- @class AliasEntry --- @class AliasEntry
--- @field name string --- @field name string
--- @field code integer --- @field code integer
@@ -208,6 +215,7 @@ local parse_enum_int_literal ---@type fun(text: string, start: integer): (intege
--- @field reg_use_schemas table<string, RegUseSchema> --- @field reg_use_schemas table<string, RegUseSchema>
--- @field reg_use_errors RegUseError[] --- @field reg_use_errors RegUseError[]
--- @field tape_chains TapeChain[] --- @field tape_chains TapeChain[]
--- @field atom_bundles table<string, AtomBundle>
--- @field _source_file string|nil --- @field _source_file string|nil
--- @field _code_macros table<string, integer>|nil -- bag --- @field _code_macros table<string, integer>|nil -- bag
--- @field _code_macro_bodies table<string, string>|nil -- bag --- @field _code_macro_bodies table<string, string>|nil -- bag
@@ -2439,11 +2447,76 @@ local function parse_typedef_array(source, pos, id2_end, line_of, out, after_typ
return semi and (semi + 1) or after_paren return semi and (semi + 1) or after_paren
end end
--- Parse `MipsAtom *slot, …;` from an AtomBundle_ typedef body.
--- Ignores the MipsAtom type token. Slot name is the ident after `*`.
--- @param body string
--- @return string[]
local function parse_atom_bundle_slots(body)
local slots = {} ---@type string[]
local pos = 1 ---@type integer
while pos <= #body do
pos = duffle.skip_ws_and_cmt(body, pos)
if pos > #body then break end
local b = body:byte(pos) ---@type integer
if b == BYTE_SEMI then
break
elseif b == BYTE_COMMA then
pos = pos + 1
elseif b == BYTE_STAR then
local after_star = duffle.skip_ws_and_cmt(body, pos + 1) ---@type integer
local ident, ident_end = duffle.read_ident(body, after_star) ---@type string|nil, integer
if ident then
slots[#slots + 1] = ident
pos = ident_end
else
pos = pos + 1
end
else
local ident, ident_end = duffle.read_ident(body, pos) ---@type string|nil, integer
if ident then
pos = ident_end
else
pos = pos + 1
end
end
end
return slots
end
-- Shape 5: `typedef AtomBundle_(<name>) { MipsAtom *slot, … };`
--- @param source string
--- @param pos integer
--- @param id2_end integer
--- @param line_of fun(pos: integer): integer
--- @param out SourceScan
--- @param after_typedef integer
--- @return integer
local function parse_typedef_atom_bundle(source, pos, id2_end, line_of, out, after_typedef)
local inner, after_paren, open_paren = read_parens_after(source, id2_end, id2_end) ---@type string|nil, integer, integer
if not inner then return id2_end end
local name = duffle.trim(inner) ---@type string
local body, after_brace = find_body_braces(source, after_paren, open_paren + 1) ---@type string|nil, integer
if not body then return after_brace end
if name ~= "" and out.atom_bundles[name] == nil then
local bundle = { ---@type AtomBundle
name = name,
slots = parse_atom_bundle_slots(body),
line = line_of(pos),
path = out._source_file or "",
}
out.atom_bundles[name] = bundle
end
attach_debug_skip_marker(out, "unrelated")
return after_brace
end
local TYPE_FORMS = { ---@type table<string, fun(source: string, pos: integer, id2_end: integer, line_of: fun(pos: integer): integer, out: SourceScan, after_typedef: integer): integer> local TYPE_FORMS = { ---@type table<string, fun(source: string, pos: integer, id2_end: integer, line_of: fun(pos: integer): integer, out: SourceScan, after_typedef: integer): integer>
Struct_ = parse_typedef_struct, Struct_ = parse_typedef_struct,
Enum_ = parse_typedef_enum, Enum_ = parse_typedef_enum,
TSet_ = parse_typedef_tset, TSet_ = parse_typedef_tset,
Array_ = parse_typedef_array, Array_ = parse_typedef_array,
AtomBundle_ = parse_typedef_atom_bundle,
} }
--- Parse: `typedef` declarations. --- Parse: `typedef` declarations.
@@ -2924,6 +2997,7 @@ local function scan_source(source, source_file, code_macros, code_macro_bodies)
atoms = {}, atoms = {},
raw_atoms = {}, raw_atoms = {},
binds = {}, binds = {},
atom_bundles = {},
atom_infos = {}, atom_infos = {},
component_atom_infos = {}, component_atom_infos = {},
macros = {}, macros = {},
@@ -3238,6 +3312,7 @@ local function merge_corpus_registries(corpus)
corpus.reg_use_schemas = corpus.reg_use_schemas or {} corpus.reg_use_schemas = corpus.reg_use_schemas or {}
corpus.reg_use_errors = corpus.reg_use_errors or {} corpus.reg_use_errors = corpus.reg_use_errors or {}
corpus.tape_chains = corpus.tape_chains or {} corpus.tape_chains = corpus.tape_chains or {}
corpus.atom_bundles = corpus.atom_bundles or {}
-- Replace the existing corpus collections with empty tables so a re-run on the same corpus produces identical state (deterministic merge). -- Replace the existing corpus collections with empty tables so a re-run on the same corpus produces identical state (deterministic merge).
-- This is safe because M.run is the only writer to these tables within a single orchestrator invocation. -- This is safe because M.run is the only writer to these tables within a single orchestrator invocation.
@@ -3255,6 +3330,7 @@ local function merge_corpus_registries(corpus)
"reg_use_schemas", "reg_use_schemas",
"reg_use_errors", "reg_use_errors",
"tape_chains", "tape_chains",
"atom_bundles",
}) do }) do
corpus[key] = {} corpus[key] = {}
end end
@@ -3362,6 +3438,28 @@ local function merge_corpus_registries(corpus)
for _, chain in ipairs(scan.tape_chains or {}) do ---@type integer, TapeChain for _, chain in ipairs(scan.tape_chains or {}) do ---@type integer, TapeChain
corpus.tape_chains[#corpus.tape_chains + 1] = chain corpus.tape_chains[#corpus.tape_chains + 1] = chain
end end
-- atom_bundles: keyed by typedef name. First-wins per name (like components).
for name, bundle in pairs(scan.atom_bundles or {}) do ---@type string, AtomBundle
if corpus.atom_bundles[name] == nil then
corpus.atom_bundles[name] = bundle
end
end
end
end
-- Join slot roles to AtomBundleEntry_ identities after catalogs and atoms exist.
-- Do not invent a catalog from an entry that has no typedef.
for _, bundle in pairs(corpus.atom_bundles) do ---@type string, AtomBundle
local entries = {} ---@type table<string, string>
for _, slot in ipairs(bundle.slots or {}) do ---@type integer, string
local atom_name = bundle.name .. "_" .. slot ---@type string
if corpus.atoms_by_name[atom_name] then
entries[slot] = atom_name
end
end
if next(entries) then
bundle.entries = entries
end end
end end
end end
+2
View File
@@ -77,6 +77,7 @@ local PASS_FLAG_DISPATCH_KEY = "__pass__" ---@type string
--- @field atom_phases table<string, AtomPhaseGroup> --- @field atom_phases table<string, AtomPhaseGroup>
--- @field word_counts WordCounts --- @field word_counts WordCounts
--- @field components table<string, Component> --- @field components table<string, Component>
--- @field atom_bundles table<string, AtomBundle>|nil
--- @field collisions CorpusCollision[] --- @field collisions CorpusCollision[]
--- @field resolver SourceResolver --- @field resolver SourceResolver
--- @field component_atom_infos AtomInfoEntry[]|nil --- @field component_atom_infos AtomInfoEntry[]|nil
@@ -665,6 +666,7 @@ local function build_ctx(args)
atom_phases = {}, atom_phases = {},
word_counts = {}, word_counts = {},
components = {}, components = {},
atom_bundles = {},
collisions = {}, collisions = {},
resolver = resolution.resolver, resolver = resolution.resolver,
} }