mirror of
https://github.com/Ed94/pikuma_ps1.git
synced 2026-08-25 02:20:33 +00:00
utilizing trailing type annotations more
This commit is contained in:
+186
-372
@@ -18,16 +18,13 @@
|
||||
-- Uses `debug.getinfo` to find this file's own directory, so it works both standalone and when require'd from the orchestrator.
|
||||
-- Bootstrap: Load `duffle_paths.lua` via `debug.getinfo(1, "S").source` (works both standalone + when require'd).
|
||||
-- duffle_paths.lua sets package.path then returns `require("duffle")` at the bottom, so the dofile value IS the duffle module.
|
||||
--- @type string
|
||||
local _bootstrap_dir = debug.getinfo(1, "S").source:match("^@?(.*[/\\])") or "./"
|
||||
--- @type DuffleExport
|
||||
local duffle = dofile(_bootstrap_dir .. "../duffle_paths.lua")
|
||||
local _bootstrap_dir = debug.getinfo(1, "S").source:match("^@?(.*[/\\])") or "./" ---@type string
|
||||
local duffle = dofile(_bootstrap_dir .. "../duffle_paths.lua") ---@type DuffleExport
|
||||
|
||||
-- Load atoms_source_map for the `render_source_map` / `render_provenance` module functions (used by `render_module_atoms_md` to produce `<module>.atoms.md` without re-walking source tokens).
|
||||
-- The pass itself emits no per-source files anymore; we only consume the two pure renderers here.
|
||||
-- Defined BEFORE the renderer functions below so their upvalues resolve to this local (not the global `atoms_source_map`, which is nil).
|
||||
--- @type AtomSourceMapPass
|
||||
local atoms_source_map = dofile(_bootstrap_dir .. "atoms_source_map.lua")
|
||||
local atoms_source_map = dofile(_bootstrap_dir .. "atoms_source_map.lua") ---@type AtomSourceMapPass
|
||||
|
||||
-- ════════════════════════════════════════════════════════════════════════════
|
||||
-- Constants
|
||||
@@ -35,32 +32,22 @@ local atoms_source_map = dofile(_bootstrap_dir .. "atoms_source_map.lua")
|
||||
|
||||
-- Section separators used in the rendered text reports.
|
||||
-- The thin rules are hand-tuned to align with the per-section content width; do not change without also checking the section renderers below.
|
||||
--- @type string
|
||||
local RULE_THICK = "========================================================"
|
||||
--- @type string
|
||||
local SECTION_HEADER_ATOMS = "── Atoms ────────────────────────────────────────────────"
|
||||
--- @type string
|
||||
local SECTION_HEADER_ANNOTS = "── Annotations ──────────────────────────────────────────"
|
||||
--- @type string
|
||||
local SECTION_HEADER_BINDS = "── Binds_* structs ──────────────────────────────────────"
|
||||
--- @type string
|
||||
local SECTION_HEADER_MACROS = "── Macro word-count declarations ─────────────────────────"
|
||||
--- @type string
|
||||
local SECTION_HEADER_ERRORS = "── Errors ──────────────────────────────────────────────"
|
||||
--- @type string
|
||||
local SECTION_HEADER_WARNINGS = "── Warnings ────────────────────────────────────────────"
|
||||
local RULE_THICK = "========================================================" ---@type string
|
||||
local SECTION_HEADER_ATOMS = "── Atoms ────────────────────────────────────────────────" ---@type string
|
||||
local SECTION_HEADER_ANNOTS = "── Annotations ──────────────────────────────────────────" ---@type string
|
||||
local SECTION_HEADER_BINDS = "── Binds_* structs ──────────────────────────────────────" ---@type string
|
||||
local SECTION_HEADER_MACROS = "── Macro word-count declarations ─────────────────────────" ---@type string
|
||||
local SECTION_HEADER_ERRORS = "── Errors ──────────────────────────────────────────────" ---@type string
|
||||
local SECTION_HEADER_WARNINGS = "── Warnings ────────────────────────────────────────────" ---@type string
|
||||
|
||||
-- Lua pattern that captures the basename (last path segment) of a forward- or back-slash separated path.
|
||||
--- @type string
|
||||
local BASENAME_PATTERN = "([^/\\]+)$"
|
||||
local BASENAME_PATTERN = "([^/\\]+)$" ---@type string
|
||||
|
||||
-- Debug flag name — set to truthy in `_G` to enable verbose logging.
|
||||
--- @type string
|
||||
local DEBUG_FLAG = "_DEBUG_REPORT"
|
||||
local DEBUG_FLAG = "_DEBUG_REPORT" ---@type string
|
||||
|
||||
-- Pass identifier for log messages.
|
||||
--- @type string
|
||||
local PASS_NAME = "report"
|
||||
local PASS_NAME = "report" ---@type string
|
||||
|
||||
-- ════════════════════════════════════════════════════════════════════════════
|
||||
-- Type declarations
|
||||
@@ -245,18 +232,15 @@ end
|
||||
--- @param all_results ProjectSummaryRow[]
|
||||
--- @return string
|
||||
local function render_project_summary(all_results)
|
||||
--- @type string[]
|
||||
local lines = {
|
||||
local lines = { ---@type string[]
|
||||
"# Project summary",
|
||||
"> Auto-generated by ps1_meta.lua (passes/report.lua).",
|
||||
"",
|
||||
"| module | atoms | annots | binds | macros | findings | errors | warnings | info |",
|
||||
"|--------|-------|--------|-------|--------|----------|--------|----------|------|",
|
||||
}
|
||||
--- @type ProjectSummaryTotals
|
||||
local totals = { atoms = 0, annots = 0, binds = 0, macros = 0, findings = 0, errors = 0, warnings = 0, info = 0 }
|
||||
--- @type integer, ProjectSummaryRow
|
||||
for _, e in ipairs(all_results) do
|
||||
local totals = { atoms = 0, annots = 0, binds = 0, macros = 0, findings = 0, errors = 0, warnings = 0, info = 0 } ---@type ProjectSummaryTotals
|
||||
for _, e in ipairs(all_results) do ---@type integer, ProjectSummaryRow
|
||||
lines[#lines + 1] = string.format("| %s | %d | %d | %d | %d | %d | %d | %d | %d |"
|
||||
, e.module, e.atoms, e.annots, e.binds, e.macros, e.findings, e.errors, e.warnings, e.info)
|
||||
totals.atoms = totals.atoms + e.atoms
|
||||
@@ -281,29 +265,22 @@ end
|
||||
--- @param wc WordCounts
|
||||
--- @return string
|
||||
local function render_module_atoms_md(dir, dir_sources, wc)
|
||||
--- @type string
|
||||
local dir_basename = source_basename(dir)
|
||||
--- @type string[]
|
||||
local lines = {
|
||||
local dir_basename = source_basename(dir) ---@type string
|
||||
local lines = { ---@type string[]
|
||||
"# " .. dir_basename .. " — atoms (verbose source map)",
|
||||
"> Per-word call-site + provenance. Auto-generated.",
|
||||
"",
|
||||
}
|
||||
--- @type integer, SourceFile
|
||||
for _, src in ipairs(dir_sources) do
|
||||
--- @type string
|
||||
local src_name = source_basename(src.path)
|
||||
for _, src in ipairs(dir_sources) do ---@type integer, SourceFile
|
||||
local src_name = source_basename(src.path) ---@type string
|
||||
lines[#lines + 1] = "## " .. src_name
|
||||
lines[#lines + 1] = ""
|
||||
-- For each atom with a projection, render its sourcemap + provenance.
|
||||
--- @type AtomEntry[]
|
||||
local atoms_list = {}
|
||||
--- @type integer, AtomEntry
|
||||
for _, atom in ipairs((src.scan or {}).atoms or {}) do
|
||||
local atoms_list = {} ---@type AtomEntry[]
|
||||
for _, atom in ipairs((src.scan or {}).atoms or {}) do ---@type integer, AtomEntry
|
||||
if atom.paths then atoms_list[#atoms_list + 1] = atom end
|
||||
end
|
||||
--- @type integer, AtomEntry
|
||||
for _, atom in ipairs((src.scan or {}).raw_atoms or {}) do
|
||||
for _, atom in ipairs((src.scan or {}).raw_atoms or {}) do ---@type integer, AtomEntry
|
||||
if atom.paths then atoms_list[#atoms_list + 1] = atom end
|
||||
end
|
||||
if #atoms_list == 0 then
|
||||
@@ -312,10 +289,8 @@ local function render_module_atoms_md(dir, dir_sources, wc)
|
||||
else
|
||||
-- Per-source forward-slash path (same one `emit_atom_stanza` / `emit_provenance_stanza` would derive;
|
||||
-- computed once per `## <source>` heading and reused by each atom's `WORD N CALL ...` field).
|
||||
--- @type string
|
||||
local rel_path = src.path:gsub("\\\\", "/")
|
||||
--- @type integer, AtomEntry
|
||||
for _, atom in ipairs(atoms_list) do
|
||||
local rel_path = src.path:gsub("\\\\", "/") ---@type string
|
||||
for _, atom in ipairs(atoms_list) do ---@type integer, AtomEntry
|
||||
lines[#lines + 1] = string.format(
|
||||
"### atom: %s (line %d, %d words)",
|
||||
atom.name, atom.line or 0, #((atom.paths or {}).word_events or {}))
|
||||
@@ -342,18 +317,15 @@ end
|
||||
--- @param atom AtomEntry
|
||||
--- @return integer
|
||||
local function decl_words(atom)
|
||||
--- @type AtomPaths
|
||||
local p = atom.paths or {}
|
||||
local p = atom.paths or {} ---@type AtomPaths
|
||||
return #(p.word_events or {})
|
||||
end
|
||||
|
||||
--- @param decls AtomEntry[]|nil
|
||||
--- @return KindCounts
|
||||
local function count_kinds(decls)
|
||||
--- @type KindCounts
|
||||
local n = { atom = 0, atom_proc = 0, comp_bare = 0, comp_proc = 0 }
|
||||
--- @type integer, AtomEntry
|
||||
for _, a in ipairs(decls or {}) do
|
||||
local n = { atom = 0, atom_proc = 0, comp_bare = 0, comp_proc = 0 } ---@type KindCounts
|
||||
for _, a in ipairs(decls or {}) do ---@type integer, AtomEntry
|
||||
if n[a.kind] ~= nil then n[a.kind] = n[a.kind] + 1 end
|
||||
end
|
||||
return n
|
||||
@@ -369,10 +341,8 @@ end
|
||||
--- @param view ModuleView
|
||||
--- @return table<string, boolean>
|
||||
local function decl_names(view)
|
||||
--- @type table<string, boolean> -- bag: atom name -> true
|
||||
local names = {}
|
||||
--- @type integer, AtomEntry
|
||||
for _, a in ipairs(view.decls or {}) do
|
||||
local names = {} ---@type table<string, boolean> -- bag: atom name -> true
|
||||
for _, a in ipairs(view.decls or {}) do ---@type integer, AtomEntry
|
||||
if a.name then names[a.name] = true end
|
||||
end
|
||||
return names
|
||||
@@ -383,15 +353,12 @@ end
|
||||
--- @return boolean
|
||||
local function path_in_module(path, view)
|
||||
if type(path) ~= "string" or path == "" then return false end
|
||||
--- @type string
|
||||
local norm = path:gsub("\\", "/")
|
||||
--- @type string
|
||||
local dir = (view.dir or ""):gsub("\\", "/")
|
||||
local norm = path:gsub("\\", "/") ---@type string
|
||||
local dir = (view.dir or ""):gsub("\\", "/") ---@type string
|
||||
if dir ~= "" and (norm == dir or norm:sub(1, #dir + 1) == dir .. "/") then
|
||||
return true
|
||||
end
|
||||
--- @type integer, SourceFile
|
||||
for _, src in ipairs(view.sources or {}) do
|
||||
for _, src in ipairs(view.sources or {}) do ---@type integer, SourceFile
|
||||
if (src.path or ""):gsub("\\", "/") == norm then return true end
|
||||
end
|
||||
return false
|
||||
@@ -402,26 +369,18 @@ end
|
||||
--- @param corpus Corpus
|
||||
--- @return ModuleView
|
||||
local function build_module_view(dir, dir_sources, corpus)
|
||||
--- @type AtomEntry[]
|
||||
local decls = {}
|
||||
--- @type integer, SourceFile
|
||||
for _, src in ipairs(dir_sources or {}) do
|
||||
--- @type integer, AtomEntry
|
||||
for _, a in ipairs((src.scan and src.scan.atoms) or {}) do
|
||||
local decls = {} ---@type AtomEntry[]
|
||||
for _, src in ipairs(dir_sources or {}) do ---@type integer, SourceFile
|
||||
for _, a in ipairs((src.scan and src.scan.atoms) or {}) do ---@type integer, AtomEntry
|
||||
if not a.source_path then a.source_path = src.path end
|
||||
decls[#decls + 1] = a
|
||||
end
|
||||
end
|
||||
--- @type string
|
||||
local dir_basename = source_basename(dir)
|
||||
--- @type AtomAnalysis
|
||||
local sa = (corpus.static_analysis_results or {})[dir_basename] or {}
|
||||
--- @type RegUseSchema[]
|
||||
local schemas = {}
|
||||
--- @type string, RegUseSchema
|
||||
for name, schema in pairs(corpus.reg_use_schemas or {}) do
|
||||
--- @type integer, AtomEntry
|
||||
for _, a in ipairs(decls) do
|
||||
local dir_basename = source_basename(dir) ---@type string
|
||||
local sa = (corpus.static_analysis_results or {})[dir_basename] or {} ---@type AtomAnalysis
|
||||
local schemas = {} ---@type RegUseSchema[]
|
||||
for name, schema in pairs(corpus.reg_use_schemas or {}) do ---@type string, RegUseSchema
|
||||
for _, a in ipairs(decls) do ---@type integer, AtomEntry
|
||||
if a.reg_use_schema_name == name then
|
||||
schemas[#schemas + 1] = schema
|
||||
break
|
||||
@@ -445,10 +404,8 @@ local function render_section_declarations(add, view)
|
||||
if #view.decls == 0 then add("_(none)_"); add(""); return end
|
||||
add("| kind | name | source | line | words | min | max | branches | paths |")
|
||||
add("|------|------|--------|------|-------|-----|-----|----------|-------|")
|
||||
--- @type integer, AtomEntry
|
||||
for _, a in ipairs(view.decls) do
|
||||
--- @type AtomPaths
|
||||
local p = a.paths or {}
|
||||
for _, a in ipairs(view.decls) do ---@type integer, AtomEntry
|
||||
local p = a.paths or {} ---@type AtomPaths
|
||||
add(string.format("| %s | %s | %s | %d | %d | %s | %s | %s | %s |",
|
||||
a.kind or "?",
|
||||
a.name or "?",
|
||||
@@ -467,17 +424,12 @@ end
|
||||
--- @param view ModuleView
|
||||
--- @return nil
|
||||
local function render_section_components(add, view)
|
||||
--- @type ComponentReportRow[]
|
||||
local rows = {}
|
||||
--- @type table<string, ComponentBodyEntry>
|
||||
local index = (view.corpus and view.corpus.component_body_index) or {}
|
||||
--- @type integer, AtomEntry
|
||||
for _, a in ipairs(view.decls) do
|
||||
local rows = {} ---@type ComponentReportRow[]
|
||||
local index = (view.corpus and view.corpus.component_body_index) or {} ---@type table<string, ComponentBodyEntry>
|
||||
for _, a in ipairs(view.decls) do ---@type integer, AtomEntry
|
||||
if a.kind == "comp_bare" or a.kind == "comp_proc" then
|
||||
--- @type ComponentBodyEntry
|
||||
local idx = index[a.name] or {}
|
||||
--- @type string[]
|
||||
local args = idx.arg_names or {}
|
||||
local idx = index[a.name] or {} ---@type ComponentBodyEntry
|
||||
local args = idx.arg_names or {} ---@type string[]
|
||||
rows[#rows + 1] = {
|
||||
name = a.name,
|
||||
kind = a.kind,
|
||||
@@ -490,8 +442,7 @@ local function render_section_components(add, view)
|
||||
if #rows == 0 then add("_(none)_"); add(""); return end
|
||||
add("| name | kind | arg_names | words | map |")
|
||||
add("|------|------|-----------|-------|-----|")
|
||||
--- @type integer, ComponentReportRow
|
||||
for _, r in ipairs(rows) do
|
||||
for _, r in ipairs(rows) do ---@type integer, ComponentReportRow
|
||||
add(string.format("| %s | %s | %s | %d | %s |",
|
||||
r.name, r.kind, r.args ~= "" and r.args or "—", r.words, r.map))
|
||||
end
|
||||
@@ -502,38 +453,28 @@ end
|
||||
--- @param view ModuleView
|
||||
--- @return nil
|
||||
local function render_section_reguse(add, view)
|
||||
--- @type boolean
|
||||
local wrote = false
|
||||
--- @type integer, RegUseSchema
|
||||
for _, schema in ipairs(view.schemas or {}) do
|
||||
local wrote = false ---@type boolean
|
||||
for _, schema in ipairs(view.schemas or {}) do ---@type integer, RegUseSchema
|
||||
wrote = true
|
||||
add(string.format("### %s", schema.name or "?"))
|
||||
--- @type integer, RegUseSlot
|
||||
for _, slot in ipairs(schema.slots or {}) do
|
||||
--- @type string
|
||||
local aliases = table.concat(slot.aliases or { slot.name }, ", ")
|
||||
--- @type string
|
||||
local ro = slot.readonly and " readonly" or ""
|
||||
for _, slot in ipairs(schema.slots or {}) do ---@type integer, RegUseSlot
|
||||
local aliases = table.concat(slot.aliases or { slot.name }, ", ") ---@type string
|
||||
local ro = slot.readonly and " readonly" or "" ---@type string
|
||||
add(string.format("- slot `%s` aliases %s%s", slot.name, aliases, ro))
|
||||
end
|
||||
--- @type integer, AtomEntry
|
||||
for _, a in ipairs(view.decls) do
|
||||
for _, a in ipairs(view.decls) do ---@type integer, AtomEntry
|
||||
if a.reg_use_schema_name == schema.name then
|
||||
add(string.format("- bound `%s` param `%s`", a.name, a.reg_use_param_name or "?"))
|
||||
end
|
||||
end
|
||||
add("")
|
||||
end
|
||||
--- @type table<string, boolean> -- bag: schema name -> true
|
||||
local bound = {}
|
||||
--- @type integer, RegUseSchema
|
||||
for _, schema in ipairs(view.schemas or {}) do
|
||||
local bound = {} ---@type table<string, boolean> -- bag: schema name -> true
|
||||
for _, schema in ipairs(view.schemas or {}) do ---@type integer, RegUseSchema
|
||||
if schema.name then bound[schema.name] = true end
|
||||
end
|
||||
--- @type RegUseError[]
|
||||
local errors = {}
|
||||
--- @type integer, RegUseError
|
||||
for _, err in ipairs((view.corpus and view.corpus.reg_use_errors) or {}) do
|
||||
local errors = {} ---@type RegUseError[]
|
||||
for _, err in ipairs((view.corpus and view.corpus.reg_use_errors) or {}) do ---@type integer, RegUseError
|
||||
if bound[err.schema_name] or path_in_module(err.source_file, view) then
|
||||
errors[#errors + 1] = err
|
||||
end
|
||||
@@ -541,8 +482,7 @@ local function render_section_reguse(add, view)
|
||||
if #errors > 0 then
|
||||
wrote = true
|
||||
add("### parse errors")
|
||||
--- @type integer, RegUseError
|
||||
for _, err in ipairs(errors) do
|
||||
for _, err in ipairs(errors) do ---@type integer, RegUseError
|
||||
add(string.format("- `%s` %s", err.kind or "?", err.schema_name or ""))
|
||||
end
|
||||
add("")
|
||||
@@ -554,12 +494,9 @@ end
|
||||
--- @param view ModuleView
|
||||
--- @return nil
|
||||
local function render_section_annotations(add, view)
|
||||
--- @type AnnotReportRow[]
|
||||
local rows = {}
|
||||
--- @type integer, SourceFile
|
||||
for _, src in ipairs(view.sources) do
|
||||
--- @type integer, AtomInfoEntry
|
||||
for _, info in ipairs((src.scan and src.scan.atom_infos) or {}) do
|
||||
local rows = {} ---@type AnnotReportRow[]
|
||||
for _, src in ipairs(view.sources) do ---@type integer, SourceFile
|
||||
for _, info in ipairs((src.scan and src.scan.atom_infos) or {}) do ---@type integer, AtomInfoEntry
|
||||
rows[#rows + 1] = {
|
||||
source = source_basename(src.path),
|
||||
line = info.info_line or 0,
|
||||
@@ -574,8 +511,7 @@ local function render_section_annotations(add, view)
|
||||
if #rows == 0 then add("_(none)_"); add(""); return end
|
||||
add("| source | line | name | binds | reads | writes | phase |")
|
||||
add("|--------|------|------|-------|-------|--------|-------|")
|
||||
--- @type integer, AnnotReportRow
|
||||
for _, r in ipairs(rows) do
|
||||
for _, r in ipairs(rows) do ---@type integer, AnnotReportRow
|
||||
add(string.format("| %s | %d | %s | %s | %s | %s | %s |",
|
||||
r.source, r.line, r.name, r.binds, r.reads, r.writes, r.phase))
|
||||
end
|
||||
@@ -586,12 +522,9 @@ end
|
||||
--- @param view ModuleView
|
||||
--- @return nil
|
||||
local function render_section_component_annotations(add, view)
|
||||
--- @type CompAnnotReportRow[]
|
||||
local rows = {}
|
||||
--- @type integer, SourceFile
|
||||
for _, src in ipairs(view.sources) do
|
||||
--- @type integer, AtomInfoEntry
|
||||
for _, info in ipairs((src.scan and src.scan.component_atom_infos) or {}) do
|
||||
local rows = {} ---@type CompAnnotReportRow[]
|
||||
for _, src in ipairs(view.sources) do ---@type integer, SourceFile
|
||||
for _, info in ipairs((src.scan and src.scan.component_atom_infos) or {}) do ---@type integer, AtomInfoEntry
|
||||
rows[#rows + 1] = {
|
||||
source = source_basename(src.path),
|
||||
line = info.info_line or 0,
|
||||
@@ -604,8 +537,7 @@ local function render_section_component_annotations(add, view)
|
||||
if #rows == 0 then add("_(none)_"); add(""); return end
|
||||
add("| source | line | name | reads | writes |")
|
||||
add("|--------|------|------|-------|--------|")
|
||||
--- @type integer, CompAnnotReportRow
|
||||
for _, r in ipairs(rows) do
|
||||
for _, r in ipairs(rows) do ---@type integer, CompAnnotReportRow
|
||||
add(string.format("| %s | %d | %s | %s | %s |",
|
||||
r.source, r.line, r.name, r.reads, r.writes))
|
||||
end
|
||||
@@ -616,17 +548,13 @@ end
|
||||
--- @param view ModuleView
|
||||
--- @return nil
|
||||
local function render_section_binds(add, view)
|
||||
--- @type boolean
|
||||
local wrote = false
|
||||
--- @type integer, SourceFile
|
||||
for _, src in ipairs(view.sources) do
|
||||
--- @type integer, BindsEntry
|
||||
for _, b in ipairs((src.scan and src.scan.binds) or {}) do
|
||||
local wrote = false ---@type boolean
|
||||
for _, src in ipairs(view.sources) do ---@type integer, SourceFile
|
||||
for _, b in ipairs((src.scan and src.scan.binds) or {}) do ---@type integer, BindsEntry
|
||||
wrote = true
|
||||
add(string.format("### %s (%s:%s, %s bytes)",
|
||||
b.name, source_basename(src.path), tostring(b.line or 0), tostring(b.bytes or "—")))
|
||||
--- @type integer, TypeField
|
||||
for _, f in ipairs(b.fields or {}) do
|
||||
for _, f in ipairs(b.fields or {}) do ---@type integer, TypeField
|
||||
add(string.format("- `+%s %s`", tostring(f.offset or "?"), f.name or "?"))
|
||||
end
|
||||
add("")
|
||||
@@ -639,18 +567,12 @@ end
|
||||
--- @param view ModuleView
|
||||
--- @return nil
|
||||
local function render_section_phases(add, view)
|
||||
--- @type Corpus
|
||||
local corpus = view.corpus or {}
|
||||
--- @type table<string, boolean>
|
||||
local names = decl_names(view)
|
||||
--- @type boolean
|
||||
local wrote = false
|
||||
--- @type string, AtomPhaseGroup
|
||||
for phase, entry in pairs(corpus.atom_phases or {}) do
|
||||
--- @type string[]
|
||||
local here = {}
|
||||
--- @type integer, string
|
||||
for _, atom_name in ipairs(entry.atoms or {}) do
|
||||
local corpus = view.corpus or {} ---@type Corpus
|
||||
local names = decl_names(view) ---@type table<string, boolean>
|
||||
local wrote = false ---@type boolean
|
||||
for phase, entry in pairs(corpus.atom_phases or {}) do ---@type string, AtomPhaseGroup
|
||||
local here = {} ---@type string[]
|
||||
for _, atom_name in ipairs(entry.atoms or {}) do ---@type integer, string
|
||||
if names[atom_name] then here[#here + 1] = atom_name end
|
||||
end
|
||||
if #here > 0 then
|
||||
@@ -658,15 +580,13 @@ local function render_section_phases(add, view)
|
||||
add(string.format("- phase `%s`: %s", phase, table.concat(here, ", ")))
|
||||
end
|
||||
end
|
||||
--- @type string, AtomViewEntry
|
||||
for name, entry in pairs(corpus.atom_views or {}) do
|
||||
for name, entry in pairs(corpus.atom_views or {}) do ---@type string, AtomViewEntry
|
||||
if names[name] then
|
||||
wrote = true
|
||||
add(string.format("- view `%s` binds `%s`", name, entry.binds_name or "—"))
|
||||
end
|
||||
end
|
||||
--- @type string, AtomCtxEntry
|
||||
for name, entry in pairs(corpus.atom_ctxs or {}) do
|
||||
for name, entry in pairs(corpus.atom_ctxs or {}) do ---@type string, AtomCtxEntry
|
||||
if names[name] then
|
||||
wrote = true
|
||||
add(string.format("- ctx `%s` rbind `%s`", name, entry.rbind_atom or "—"))
|
||||
@@ -680,14 +600,10 @@ end
|
||||
--- @param view ModuleView
|
||||
--- @return nil
|
||||
local function render_section_aliases(add, view)
|
||||
--- @type string[]
|
||||
local names = {}
|
||||
--- @type table<string, AliasEntry>
|
||||
local seen = {}
|
||||
--- @type integer, SourceFile
|
||||
for _, src in ipairs(view.sources or {}) do
|
||||
--- @type string, AliasEntry
|
||||
for name, entry in pairs((src.scan and src.scan.register_alias_registry) or {}) do
|
||||
local names = {} ---@type string[]
|
||||
local seen = {} ---@type table<string, AliasEntry>
|
||||
for _, src in ipairs(view.sources or {}) do ---@type integer, SourceFile
|
||||
for name, entry in pairs((src.scan and src.scan.register_alias_registry) or {}) do ---@type string, AliasEntry
|
||||
if not seen[name] then
|
||||
seen[name] = entry
|
||||
names[#names + 1] = name
|
||||
@@ -698,10 +614,8 @@ local function render_section_aliases(add, view)
|
||||
if #names == 0 then add("_(none)_"); add(""); return end
|
||||
add("| alias | type |")
|
||||
add("|-------|------|")
|
||||
--- @type integer, string
|
||||
for _, name in ipairs(names) do
|
||||
--- @type AliasEntry|nil
|
||||
local e = seen[name]
|
||||
for _, name in ipairs(names) do ---@type integer, string
|
||||
local e = seen[name] ---@type AliasEntry|nil
|
||||
add(string.format("| %s | %s |", name, (e and e.default_type) or "—"))
|
||||
end
|
||||
add("")
|
||||
@@ -711,40 +625,30 @@ end
|
||||
--- @param view ModuleView
|
||||
--- @return nil
|
||||
local function render_section_autoreg(add, view)
|
||||
--- @type table<string, boolean>
|
||||
local allowed = decl_names(view)
|
||||
--- @type string, AtomPhaseGroup
|
||||
for phase, entry in pairs((view.corpus and view.corpus.atom_phases) or {}) do
|
||||
--- @type integer, string
|
||||
for _, atom_name in ipairs(entry.atoms or {}) do
|
||||
local allowed = decl_names(view) ---@type table<string, boolean>
|
||||
for phase, entry in pairs((view.corpus and view.corpus.atom_phases) or {}) do ---@type string, AtomPhaseGroup
|
||||
for _, atom_name in ipairs(entry.atoms or {}) do ---@type integer, string
|
||||
if allowed[atom_name] then allowed[phase] = true end
|
||||
end
|
||||
end
|
||||
--- @type boolean
|
||||
local wrote = false
|
||||
--- @type table<string, boolean> -- bag: label\\0scope -> already dumped
|
||||
local seen = {}
|
||||
local wrote = false ---@type boolean
|
||||
local seen = {} ---@type table<string, boolean> -- bag: label\\0scope -> already dumped
|
||||
--- @param label string
|
||||
--- @param table_map table<string, GprAllocMap>|nil
|
||||
--- @return nil
|
||||
local function dump(label, table_map)
|
||||
--- @type string[]
|
||||
local scopes = {}
|
||||
--- @type string
|
||||
for scope in pairs(table_map or {}) do
|
||||
local scopes = {} ---@type string[]
|
||||
for scope in pairs(table_map or {}) do ---@type string
|
||||
if allowed[scope] and not seen[label .. "\0" .. scope] then
|
||||
scopes[#scopes + 1] = scope
|
||||
end
|
||||
end
|
||||
table.sort(scopes)
|
||||
--- @type integer, string
|
||||
for _, scope in ipairs(scopes) do
|
||||
for _, scope in ipairs(scopes) do ---@type integer, string
|
||||
seen[label .. "\0" .. scope] = true
|
||||
wrote = true
|
||||
--- @type string[]
|
||||
local syms = {}
|
||||
--- @type string, string
|
||||
for sym, gpr in pairs(table_map[scope] or {}) do
|
||||
local syms = {} ---@type string[]
|
||||
for sym, gpr in pairs(table_map[scope] or {}) do ---@type string, string
|
||||
if type(gpr) == "string" and gpr ~= sym then
|
||||
syms[#syms + 1] = string.format("%s → %s", sym, gpr)
|
||||
else
|
||||
@@ -755,12 +659,10 @@ local function render_section_autoreg(add, view)
|
||||
add(string.format("- %s `%s`: %s", label, scope, table.concat(syms, ", ")))
|
||||
end
|
||||
end
|
||||
--- @type Corpus
|
||||
local corpus = view.corpus or {}
|
||||
local corpus = view.corpus or {} ---@type Corpus
|
||||
dump("atom", corpus.atom_auto_regs)
|
||||
dump("phase", corpus.phase_auto_regs)
|
||||
--- @type integer, SourceFile
|
||||
for _, src in ipairs(view.sources or {}) do
|
||||
for _, src in ipairs(view.sources or {}) do ---@type integer, SourceFile
|
||||
dump("atom", src.scan and src.scan.atom_auto_regs)
|
||||
dump("phase", src.scan and src.scan.phase_auto_regs)
|
||||
end
|
||||
@@ -772,25 +674,18 @@ end
|
||||
--- @param view ModuleView
|
||||
--- @return nil
|
||||
local function render_section_collisions(add, view)
|
||||
--- @type CorpusCollision[]
|
||||
local rows = {}
|
||||
--- @type integer, CorpusCollision
|
||||
for _, c in ipairs((view.corpus and view.corpus.collisions) or {}) do
|
||||
--- @type CollisionSite
|
||||
local first = c.first_site or {}
|
||||
--- @type CollisionSite
|
||||
local other = c.conflicting_site or {}
|
||||
local rows = {} ---@type CorpusCollision[]
|
||||
for _, c in ipairs((view.corpus and view.corpus.collisions) or {}) do ---@type integer, CorpusCollision
|
||||
local first = c.first_site or {} ---@type CollisionSite
|
||||
local other = c.conflicting_site or {} ---@type CollisionSite
|
||||
if path_in_module(first.path, view) or path_in_module(other.path, view) then
|
||||
rows[#rows + 1] = c
|
||||
end
|
||||
end
|
||||
if #rows == 0 then add("_(none)_"); add(""); return end
|
||||
--- @type integer, CorpusCollision
|
||||
for _, c in ipairs(rows) do
|
||||
--- @type CollisionSite
|
||||
local first = c.first_site or {}
|
||||
--- @type CollisionSite
|
||||
local other = c.conflicting_site or {}
|
||||
for _, c in ipairs(rows) do ---@type integer, CorpusCollision
|
||||
local first = c.first_site or {} ---@type CollisionSite
|
||||
local other = c.conflicting_site or {} ---@type CollisionSite
|
||||
add(string.format("- `%s` `%s` first %s:%s conflict %s:%s",
|
||||
c.kind or "?", c.name or "?",
|
||||
tostring(first.path or "?"), tostring(first.line or "?"),
|
||||
@@ -803,29 +698,22 @@ end
|
||||
--- @param view ModuleView
|
||||
--- @return nil
|
||||
local function render_section_findings(add, view)
|
||||
--- @type table<string, CheckFinding[]>
|
||||
local by_atom = {}
|
||||
--- @type integer, CheckFinding
|
||||
for _, f in ipairs(view.findings or {}) do
|
||||
--- @type string
|
||||
local key = f.atom or "?"
|
||||
local by_atom = {} ---@type table<string, CheckFinding[]>
|
||||
for _, f in ipairs(view.findings or {}) do ---@type integer, CheckFinding
|
||||
local key = f.atom or "?" ---@type string
|
||||
by_atom[key] = by_atom[key] or {}
|
||||
by_atom[key][#by_atom[key] + 1] = f
|
||||
end
|
||||
if next(by_atom) == nil then add("_(none)_"); add(""); return end
|
||||
--- @type table<string, boolean> -- bag: atom name already emitted
|
||||
local seen = {}
|
||||
local seen = {} ---@type table<string, boolean> -- bag: atom name already emitted
|
||||
--- @param name string
|
||||
--- @param fs CheckFinding[]
|
||||
--- @return nil
|
||||
local function emit(name, fs)
|
||||
add("### " .. name)
|
||||
--- @type integer, CheckFinding
|
||||
for _, f in ipairs(fs) do
|
||||
--- @type string
|
||||
local msg = f.msg or ""
|
||||
--- @type string|nil
|
||||
local slot = slot_suffix(f.gpr_key or f.producer_destination)
|
||||
for _, f in ipairs(fs) do ---@type integer, CheckFinding
|
||||
local msg = f.msg or "" ---@type string
|
||||
local slot = slot_suffix(f.gpr_key or f.producer_destination) ---@type string|nil
|
||||
if slot and not msg:find("(slot ", 1, true) then
|
||||
msg = msg .. " (slot " .. slot .. ")"
|
||||
end
|
||||
@@ -833,45 +721,34 @@ local function render_section_findings(add, view)
|
||||
end
|
||||
add("")
|
||||
end
|
||||
--- @type integer, AtomEntry
|
||||
for _, a in ipairs(view.decls) do
|
||||
for _, a in ipairs(view.decls) do ---@type integer, AtomEntry
|
||||
if by_atom[a.name] then
|
||||
seen[a.name] = true
|
||||
emit(a.name, by_atom[a.name])
|
||||
end
|
||||
end
|
||||
--- @type string[]
|
||||
local leftovers = {}
|
||||
--- @type string
|
||||
for name in pairs(by_atom) do
|
||||
local leftovers = {} ---@type string[]
|
||||
for name in pairs(by_atom) do ---@type string
|
||||
if not seen[name] then leftovers[#leftovers + 1] = name end
|
||||
end
|
||||
table.sort(leftovers)
|
||||
--- @type integer, string
|
||||
for _, name in ipairs(leftovers) do emit(name, by_atom[name]) end
|
||||
for _, name in ipairs(leftovers) do emit(name, by_atom[name]) end ---@type integer, string
|
||||
end
|
||||
|
||||
--- @param add fun(s: string): nil
|
||||
--- @param view ModuleView
|
||||
--- @return nil
|
||||
local function render_section_relations(add, view)
|
||||
--- @type boolean
|
||||
local wrote = false
|
||||
--- @type integer, AtomEntry
|
||||
for _, a in ipairs(view.decls) do
|
||||
--- @type AtomRelation[]
|
||||
local rels = (a.paths and a.paths.relations) or {}
|
||||
local wrote = false ---@type boolean
|
||||
for _, a in ipairs(view.decls) do ---@type integer, AtomEntry
|
||||
local rels = (a.paths and a.paths.relations) or {} ---@type AtomRelation[]
|
||||
if #rels > 0 then
|
||||
wrote = true
|
||||
add("### " .. a.name)
|
||||
--- @type integer, AtomRelation
|
||||
for _, rel in ipairs(rels) do
|
||||
--- @type string
|
||||
local dest = rel.destination or rel.producer_destination or "—"
|
||||
--- @type string|nil
|
||||
local slot = slot_suffix(dest)
|
||||
--- @type string
|
||||
local dest_s = tostring(dest)
|
||||
for _, rel in ipairs(rels) do ---@type integer, AtomRelation
|
||||
local dest = rel.destination or rel.producer_destination or "—" ---@type string
|
||||
local slot = slot_suffix(dest) ---@type string|nil
|
||||
local dest_s = tostring(dest) ---@type string
|
||||
if slot then dest_s = dest_s .. " (slot " .. slot .. ")" end
|
||||
add(string.format("- `%s` words %s → %s dest %s",
|
||||
rel.semantic or "?",
|
||||
@@ -885,13 +762,11 @@ local function render_section_relations(add, view)
|
||||
if not wrote then add("_(none)_"); add("") end
|
||||
end
|
||||
|
||||
--- @type table<string, boolean> -- bag: GPR key hidden unless an encoder wrote it
|
||||
local HIDDEN_UNLESS_WRITTEN = {
|
||||
local HIDDEN_UNLESS_WRITTEN = { ---@type table<string, boolean> -- bag: GPR key hidden unless an encoder wrote it
|
||||
R_AT = true, R_TapePtr = true, R_AtomJmp = true,
|
||||
}
|
||||
|
||||
--- @type table<string, boolean> -- bag: physical GPR alias -> true
|
||||
local PHYSICAL_GPR = {
|
||||
local PHYSICAL_GPR = { ---@type table<string, boolean> -- bag: physical GPR alias -> true
|
||||
R_T0 = true, R_T1 = true, R_T2 = true, R_T3 = true,
|
||||
R_T4 = true, R_T5 = true, R_T6 = true, R_T7 = true,
|
||||
R_V0 = true, R_V1 = true,
|
||||
@@ -901,10 +776,8 @@ local PHYSICAL_GPR = {
|
||||
--- @param key string
|
||||
--- @return boolean
|
||||
local function encoder_wrote_key(atom, key)
|
||||
--- @type integer, WordEvent
|
||||
for _, ev in ipairs((atom.paths and atom.paths.word_events) or {}) do
|
||||
--- @type integer|string, string
|
||||
for _, dest in pairs(ev.gpr_keys or {}) do
|
||||
for _, ev in ipairs((atom.paths and atom.paths.word_events) or {}) do ---@type integer, WordEvent
|
||||
for _, dest in pairs(ev.gpr_keys or {}) do ---@type integer|string, string
|
||||
if dest == key then return true end
|
||||
end
|
||||
end
|
||||
@@ -915,11 +788,9 @@ end
|
||||
--- @param atom AtomEntry
|
||||
--- @return string
|
||||
local function written_name_for(key, atom)
|
||||
--- @type string|nil
|
||||
local slot = key:match("^reguse:.+:(.+)$")
|
||||
local slot = key:match("^reguse:.+:(.+)$") ---@type string|nil
|
||||
if slot then
|
||||
--- @type string|nil
|
||||
local param = atom.reg_use_param_name
|
||||
local param = atom.reg_use_param_name ---@type string|nil
|
||||
if param and param ~= "" then return param .. "." .. slot end
|
||||
return slot
|
||||
end
|
||||
@@ -931,21 +802,15 @@ end
|
||||
--- @param view ModuleView
|
||||
--- @return string
|
||||
local function aliases_for_key(key, atom, view)
|
||||
--- @type string|nil
|
||||
local slot = key:match("^reguse:.+:(.+)$")
|
||||
local slot = key:match("^reguse:.+:(.+)$") ---@type string|nil
|
||||
if not slot then return "—" end
|
||||
--- @type string|nil
|
||||
local schema_name = atom.reg_use_schema_name
|
||||
--- @type RegUseSchema|nil
|
||||
local schema = view.corpus and view.corpus.reg_use_schemas and view.corpus.reg_use_schemas[schema_name]
|
||||
local schema_name = atom.reg_use_schema_name ---@type string|nil
|
||||
local schema = view.corpus and view.corpus.reg_use_schemas and view.corpus.reg_use_schemas[schema_name] ---@type RegUseSchema|nil
|
||||
if not schema then return "—" end
|
||||
--- @type integer, RegUseSlot
|
||||
for _, s in ipairs(schema.slots or {}) do
|
||||
for _, s in ipairs(schema.slots or {}) do ---@type integer, RegUseSlot
|
||||
if s.name == slot then
|
||||
--- @type string[]
|
||||
local names = {}
|
||||
--- @type integer, string
|
||||
for _, alias in ipairs(s.aliases or {}) do
|
||||
local names = {} ---@type string[]
|
||||
for _, alias in ipairs(s.aliases or {}) do ---@type integer, string
|
||||
if alias ~= slot then names[#names + 1] = alias end
|
||||
end
|
||||
if #names == 0 then
|
||||
@@ -964,25 +829,19 @@ end
|
||||
--- @return string
|
||||
local function physical_for_key(key, atom, view)
|
||||
if PHYSICAL_GPR[key] then return key end
|
||||
--- @type Corpus
|
||||
local corpus = view.corpus or {}
|
||||
--- @type AliasEntry|string|nil
|
||||
local alias = (corpus.register_alias_registry or {})[key]
|
||||
local corpus = view.corpus or {} ---@type Corpus
|
||||
local alias = (corpus.register_alias_registry or {})[key] ---@type AliasEntry|string|nil
|
||||
if type(alias) == "table" then
|
||||
--- @type string|nil
|
||||
local phys = alias.physical or alias.gpr or alias.code_name
|
||||
local phys = alias.physical or alias.gpr or alias.code_name ---@type string|nil
|
||||
if type(phys) == "string" and PHYSICAL_GPR[phys] then return phys end
|
||||
if type(alias.name) == "string" and PHYSICAL_GPR[alias.name] then return alias.name end
|
||||
elseif type(alias) == "string" and PHYSICAL_GPR[alias] then
|
||||
return alias
|
||||
end
|
||||
--- @type GprAllocMap|nil
|
||||
local atom_map = (corpus.atom_auto_regs or {})[atom.name]
|
||||
local atom_map = (corpus.atom_auto_regs or {})[atom.name] ---@type GprAllocMap|nil
|
||||
if type(atom_map) == "table" then
|
||||
--- @type string
|
||||
local slot = key:match("^reguse:.+:(.+)$") or key
|
||||
--- @type string|nil
|
||||
local bound = atom_map[slot] or atom_map["R_" .. slot]
|
||||
local slot = key:match("^reguse:.+:(.+)$") or key ---@type string
|
||||
local bound = atom_map[slot] or atom_map["R_" .. slot] ---@type string|nil
|
||||
if type(bound) == "string" and PHYSICAL_GPR[bound] then return bound end
|
||||
end
|
||||
return "—"
|
||||
@@ -992,21 +851,15 @@ end
|
||||
--- @param atom AtomEntry
|
||||
--- @return string
|
||||
local function last_relation_for(key, atom)
|
||||
--- @type AtomRelation|nil
|
||||
local last = nil
|
||||
--- @type integer, AtomRelation
|
||||
for _, rel in ipairs((atom.paths and atom.paths.relations) or {}) do
|
||||
--- @type string|nil
|
||||
local dest = rel.destination or rel.producer_destination
|
||||
local last = nil ---@type AtomRelation|nil
|
||||
for _, rel in ipairs((atom.paths and atom.paths.relations) or {}) do ---@type integer, AtomRelation
|
||||
local dest = rel.destination or rel.producer_destination ---@type string|nil
|
||||
if dest == key then last = rel end
|
||||
end
|
||||
if not last then return "—" end
|
||||
--- @type string
|
||||
local sem = last.semantic or "?"
|
||||
--- @type integer|nil
|
||||
local a = last.producer_word
|
||||
--- @type integer|nil
|
||||
local b = last.consumer_word
|
||||
local sem = last.semantic or "?" ---@type string
|
||||
local a = last.producer_word ---@type integer|nil
|
||||
local b = last.consumer_word ---@type integer|nil
|
||||
if a and b then return string.format("%s w%s→%s", sem, tostring(a), tostring(b)) end
|
||||
return sem
|
||||
end
|
||||
@@ -1015,16 +868,11 @@ end
|
||||
--- @param view ModuleView
|
||||
--- @return nil
|
||||
local function render_section_forward(add, view)
|
||||
--- @type boolean
|
||||
local wrote = false
|
||||
--- @type integer, AtomEntry
|
||||
for _, a in ipairs(view.decls) do
|
||||
--- @type table<string, GprLatticeSlot>|nil
|
||||
local gpr = a.paths and a.paths.forward_state and a.paths.forward_state.gpr_values
|
||||
--- @type string[]
|
||||
local keys = {}
|
||||
--- @type string
|
||||
for k in pairs(gpr or {}) do
|
||||
local wrote = false ---@type boolean
|
||||
for _, a in ipairs(view.decls) do ---@type integer, AtomEntry
|
||||
local gpr = a.paths and a.paths.forward_state and a.paths.forward_state.gpr_values ---@type table<string, GprLatticeSlot>|nil
|
||||
local keys = {} ---@type string[]
|
||||
for k in pairs(gpr or {}) do ---@type string
|
||||
if k == "R_0" then
|
||||
-- hidden
|
||||
elseif HIDDEN_UNLESS_WRITTEN[k] and not encoder_wrote_key(a, k) then
|
||||
@@ -1039,12 +887,9 @@ local function render_section_forward(add, view)
|
||||
add("| written | aliases | physical | lattice | last relation |")
|
||||
add("|---|---|---|---|---|")
|
||||
table.sort(keys)
|
||||
--- @type integer, string
|
||||
for _, k in ipairs(keys) do
|
||||
--- @type GprLatticeSlot|nil
|
||||
local slot = gpr[k]
|
||||
--- @type string
|
||||
local lattice = "—"
|
||||
for _, k in ipairs(keys) do ---@type integer, string
|
||||
local slot = gpr[k] ---@type GprLatticeSlot|nil
|
||||
local lattice = "—" ---@type string
|
||||
if slot and slot.kind == "constant" then
|
||||
lattice = tostring(slot.value)
|
||||
end
|
||||
@@ -1061,8 +906,7 @@ local function render_section_forward(add, view)
|
||||
if not wrote then add("_(none)_"); add("") end
|
||||
end
|
||||
|
||||
--- @type SectionRenderer[]
|
||||
local SECTION_RENDERERS = {
|
||||
local SECTION_RENDERERS = { ---@type SectionRenderer[]
|
||||
{ header = "## Declarations", render = render_section_declarations },
|
||||
{ header = "## Components", render = render_section_components },
|
||||
{ header = "## RegUse schemas", render = render_section_reguse },
|
||||
@@ -1083,10 +927,8 @@ local SECTION_RENDERERS = {
|
||||
--- @param view ModuleView
|
||||
--- @return string
|
||||
local function render_module_meta_report(view)
|
||||
--- @type string
|
||||
local dir_basename = source_basename(view.dir)
|
||||
--- @type string[]
|
||||
local lines = {
|
||||
local dir_basename = source_basename(view.dir) ---@type string
|
||||
local lines = { ---@type string[]
|
||||
"# " .. dir_basename .. " — atom meta report",
|
||||
"> Auto-generated by ps1_meta.lua (passes/report.lua). Do not edit.",
|
||||
"",
|
||||
@@ -1095,20 +937,15 @@ local function render_module_meta_report(view)
|
||||
--- @return nil
|
||||
local function add(s) lines[#lines + 1] = s end
|
||||
|
||||
--- @type KindCounts
|
||||
local kinds = count_kinds(view.decls)
|
||||
--- @type integer, integer, integer
|
||||
local n_annot, n_binds, n_macros = 0, 0, 0
|
||||
--- @type integer, SourceFile
|
||||
for _, src in ipairs(view.sources) do
|
||||
local kinds = count_kinds(view.decls) ---@type KindCounts
|
||||
local n_annot, n_binds, n_macros = 0, 0, 0 ---@type integer, integer, integer
|
||||
for _, src in ipairs(view.sources) do ---@type integer, SourceFile
|
||||
n_annot = n_annot + #((src.scan and src.scan.atom_infos) or {})
|
||||
n_binds = n_binds + #((src.scan and src.scan.binds) or {})
|
||||
n_macros = n_macros + #((src.scan and src.scan.macros) or {})
|
||||
end
|
||||
--- @type integer, integer, integer
|
||||
local n_err, n_warn, n_info = 0, 0, 0
|
||||
--- @type integer, CheckFinding
|
||||
for _, f in ipairs(view.findings or {}) do
|
||||
local n_err, n_warn, n_info = 0, 0, 0 ---@type integer, integer, integer
|
||||
for _, f in ipairs(view.findings or {}) do ---@type integer, CheckFinding
|
||||
if f.kind == "error" then n_err = n_err + 1
|
||||
elseif f.kind == "warning" then n_warn = n_warn + 1
|
||||
else n_info = n_info + 1
|
||||
@@ -1128,12 +965,10 @@ local function render_module_meta_report(view)
|
||||
add("")
|
||||
|
||||
add("## Sources"); add("")
|
||||
--- @type integer, SourceFile
|
||||
for _, s in ipairs(view.sources) do add("- `" .. s.path .. "`") end
|
||||
for _, s in ipairs(view.sources) do add("- `" .. s.path .. "`") end ---@type integer, SourceFile
|
||||
add("")
|
||||
|
||||
--- @type integer, SectionRenderer
|
||||
for _, row in ipairs(SECTION_RENDERERS) do
|
||||
for _, row in ipairs(SECTION_RENDERERS) do ---@type integer, SectionRenderer
|
||||
add(row.header); add("")
|
||||
row.render(add, view)
|
||||
end
|
||||
@@ -1147,8 +982,7 @@ end
|
||||
-- `once = true` means render once at the project level (not per-module).
|
||||
-- `basename(dir_basename)` yields the file's basename for that kind.
|
||||
-- `gather(ctx, dir, dir_sources [, all_modules])` returns the rendered string.
|
||||
--- @type ReportRenderer[]
|
||||
local REPORT_RENDERERS = {
|
||||
local REPORT_RENDERERS = { ---@type ReportRenderer[]
|
||||
{
|
||||
name = "atom_meta_report",
|
||||
ext = "md",
|
||||
@@ -1161,8 +995,7 @@ local REPORT_RENDERERS = {
|
||||
--- @param dir_sources SourceFile[]
|
||||
--- @return string
|
||||
gather = function(ctx, dir, dir_sources)
|
||||
--- @type Corpus
|
||||
local corpus = ctx.shared.corpus
|
||||
local corpus = ctx.shared.corpus ---@type Corpus
|
||||
return render_module_meta_report(build_module_view(dir, dir_sources, corpus))
|
||||
end,
|
||||
},
|
||||
@@ -1204,20 +1037,16 @@ local REPORT_RENDERERS = {
|
||||
-- M — public pass surface
|
||||
-- ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
--- @type ReportPass
|
||||
local M = {}
|
||||
local M = {} ---@type ReportPass
|
||||
|
||||
--- Run the report pass. Emits 1 `atom_meta_report.summary.md` per build + 2 `atom_meta_report.md` + 2 `atoms.md` files per module (duffle + gte_hello).
|
||||
--- Reads `corpus.static_analysis_results` (added in Phase 1) to populate per-module findings without re-running validate().
|
||||
--- @param ctx PassCtx
|
||||
--- @return PassResult
|
||||
function M.run(ctx)
|
||||
--- @type PassOutputEntry[]
|
||||
local outputs = {}
|
||||
--- @type Corpus|nil
|
||||
local corpus = ctx.shared and ctx.shared.corpus
|
||||
--- @type table<string, SourceFile[]>
|
||||
local by_dir = (corpus and corpus.sources_by_dir) or {}
|
||||
local outputs = {} ---@type PassOutputEntry[]
|
||||
local corpus = ctx.shared and ctx.shared.corpus ---@type Corpus|nil
|
||||
local by_dir = (corpus and corpus.sources_by_dir) or {} ---@type table<string, SourceFile[]>
|
||||
|
||||
-- `out_path_root`: when the conventional `out_root` is `build/gen` (any spelling — relative, absolute, separator variants).
|
||||
-- Write the md files to `build/` (parent of `gen/`) instead of nested under `gen/`.
|
||||
@@ -1228,49 +1057,37 @@ function M.run(ctx)
|
||||
return type(p) == "string" and (p:match("[/\\]gen[/\\]?$") ~= nil
|
||||
or p == "build/gen" or p == "build\\gen")
|
||||
end
|
||||
--- @type string
|
||||
local out_root_effective = ends_with_gen(ctx.out_root)
|
||||
local out_root_effective = ends_with_gen(ctx.out_root) ---@type string
|
||||
and ctx.out_root:gsub("[/\\]gen[/\\]?$", "")
|
||||
or ctx.out_root
|
||||
|
||||
duffle.ensure_dir(out_root_effective)
|
||||
|
||||
-- Aggregator for the project-wide `once = true` summary renderer.
|
||||
--- @type ProjectSummaryRow[]
|
||||
local all_modules = {}
|
||||
local all_modules = {} ---@type ProjectSummaryRow[]
|
||||
|
||||
--- @type string, SourceFile[]
|
||||
for dir, dir_sources in pairs(by_dir) do
|
||||
--- @type string
|
||||
local dir_basename = dir:match("([^/\\]+)$") or dir
|
||||
for dir, dir_sources in pairs(by_dir) do ---@type string, SourceFile[]
|
||||
local dir_basename = dir:match("([^/\\]+)$") or dir ---@type string
|
||||
|
||||
-- Per-renderer dispatch for the per-module renderers (once = false).
|
||||
--- @type integer, ReportRenderer
|
||||
for _, renderer in ipairs(REPORT_RENDERERS) do
|
||||
for _, renderer in ipairs(REPORT_RENDERERS) do ---@type integer, ReportRenderer
|
||||
if not renderer.once then
|
||||
--- @type string
|
||||
local body = renderer.gather(ctx, dir, dir_sources)
|
||||
--- @type string
|
||||
local out_path = out_root_effective .. "/" .. renderer.basename(dir_basename) .. "." .. renderer.ext
|
||||
local body = renderer.gather(ctx, dir, dir_sources) ---@type string
|
||||
local out_path = out_root_effective .. "/" .. renderer.basename(dir_basename) .. "." .. renderer.ext ---@type string
|
||||
duffle.write_file(out_path, body)
|
||||
outputs[#outputs + 1] = { kind = renderer.name, path = out_path }
|
||||
end
|
||||
end
|
||||
|
||||
--- @type ModuleView
|
||||
local view = build_module_view(dir, dir_sources, corpus)
|
||||
--- @type integer, integer, integer
|
||||
local n_annot, n_binds, n_macros = 0, 0, 0
|
||||
--- @type integer, SourceFile
|
||||
for _, src in ipairs(dir_sources) do
|
||||
local view = build_module_view(dir, dir_sources, corpus) ---@type ModuleView
|
||||
local n_annot, n_binds, n_macros = 0, 0, 0 ---@type integer, integer, integer
|
||||
for _, src in ipairs(dir_sources) do ---@type integer, SourceFile
|
||||
n_annot = n_annot + #((src.scan and src.scan.atom_infos) or {})
|
||||
n_binds = n_binds + #((src.scan and src.scan.binds) or {})
|
||||
n_macros = n_macros + #((src.scan and src.scan.macros) or {})
|
||||
end
|
||||
--- @type integer, integer, integer
|
||||
local n_err, n_warn, n_info = 0, 0, 0
|
||||
--- @type integer, CheckFinding
|
||||
for _, f in ipairs(view.findings or {}) do
|
||||
local n_err, n_warn, n_info = 0, 0, 0 ---@type integer, integer, integer
|
||||
for _, f in ipairs(view.findings or {}) do ---@type integer, CheckFinding
|
||||
if f.kind == "error" then n_err = n_err + 1
|
||||
elseif f.kind == "warning" then n_warn = n_warn + 1
|
||||
else n_info = n_info + 1
|
||||
@@ -1290,13 +1107,10 @@ function M.run(ctx)
|
||||
end
|
||||
|
||||
-- Project-wide renderer (once = true): write the summary file.
|
||||
--- @type integer, ReportRenderer
|
||||
for _, renderer in ipairs(REPORT_RENDERERS) do
|
||||
for _, renderer in ipairs(REPORT_RENDERERS) do ---@type integer, ReportRenderer
|
||||
if renderer.once then
|
||||
--- @type string
|
||||
local body = renderer.gather(ctx, nil, nil, all_modules)
|
||||
--- @type string
|
||||
local out_path = out_root_effective .. "/" .. renderer.basename("") .. "." .. renderer.ext
|
||||
local body = renderer.gather(ctx, nil, nil, all_modules) ---@type string
|
||||
local out_path = out_root_effective .. "/" .. renderer.basename("") .. "." .. renderer.ext ---@type string
|
||||
duffle.write_file(out_path, body)
|
||||
outputs[#outputs + 1] = { kind = renderer.name, path = out_path }
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user