adding comments for scan progress

This commit is contained in:
ed
2026-07-11 02:00:05 -04:00
parent 91a91b3495
commit 318516a354
4 changed files with 164 additions and 105 deletions
+22
View File
@@ -316,6 +316,7 @@ local function parse_pragma_operator(source, ident_pos, after_ident)
return nil, open_paren + 1 return nil, open_paren + 1
end end
local str, str_end = read_parens(source, open_paren) local str, str_end = read_parens(source, open_paren)
-- scan: _Pragma(<string>)
str = trim(str) str = trim(str)
if str:sub(1, 1) ~= '"' or str:sub(-1) ~= '"' then if str:sub(1, 1) ~= '"' or str:sub(-1) ~= '"' then
return nil, str_end return nil, str_end
@@ -350,6 +351,7 @@ local function parse_pragma_directive(source, ident_pos, after_ident)
eol = eol + 1 eol = eol + 1
end end
local line_text = trim(source:sub(rest_start, eol - 1)) local line_text = trim(source:sub(rest_start, eol - 1))
-- scan: #pragma <mac_name> tape_atom words=<N>
local tokens = split_ws(line_text) local tokens = split_ws(line_text)
local entry local entry
if #tokens >= 3 and tokens[2] == "tape_atom" and tokens[3]:sub(1, WORDS_KEY_PREFIX_LEN) == WORDS_KEY_PREFIX then if #tokens >= 3 and tokens[2] == "tape_atom" and tokens[3]:sub(1, WORDS_KEY_PREFIX_LEN) == WORDS_KEY_PREFIX then
@@ -389,9 +391,11 @@ local function find_macro_word_annotations(source)
pos = skip_preprocessor_line(source, pos) pos = skip_preprocessor_line(source, pos)
else else
local ident, after_ident = read_ident(source, pos) local ident, after_ident = read_ident(source, pos)
-- scan: <ident>
if not ident then if not ident then
pos = pos + 1 pos = pos + 1
elseif ident == PRAGMA_OPERATOR then elseif ident == PRAGMA_OPERATOR then
-- scan: _Pragma(...)
local entry, new_pos = parse_pragma_operator(source, pos, after_ident) local entry, new_pos = parse_pragma_operator(source, pos, after_ident)
if entry then if entry then
local line_of = duffle.LineIndex(source) local line_of = duffle.LineIndex(source)
@@ -400,6 +404,7 @@ local function find_macro_word_annotations(source)
end end
pos = new_pos pos = new_pos
elseif ident == PRAGMA_IDENT then elseif ident == PRAGMA_IDENT then
-- scan: #pragma <mac_name> tape_atom words=<N>
local entry, new_pos = parse_pragma_directive(source, pos, after_ident) local entry, new_pos = parse_pragma_directive(source, pos, after_ident)
if entry then out[#out + 1] = entry end if entry then out[#out + 1] = entry end
pos = new_pos pos = new_pos
@@ -458,6 +463,7 @@ end
local function parse_typedef_binds(source, ident_pos, after_typedef, line_of) local function parse_typedef_binds(source, ident_pos, after_typedef, line_of)
local after_type = skip_ws_and_cmt(source, after_typedef) local after_type = skip_ws_and_cmt(source, after_typedef)
local type_ident, after_type_ident = read_ident(source, after_type) local type_ident, after_type_ident = read_ident(source, after_type)
-- scan: typedef <type_ident>
if type_ident ~= STRUCT_TYPE then if type_ident ~= STRUCT_TYPE then
return nil, after_type_ident or (after_type + 1) return nil, after_type_ident or (after_type + 1)
end end
@@ -468,12 +474,15 @@ local function parse_typedef_binds(source, ident_pos, after_typedef, line_of)
end end
local inner, after_paren = read_parens(source, open_paren) local inner, after_paren = read_parens(source, open_paren)
-- scan: typedef Struct_(<name>)
local name = trim(inner) local name = trim(inner)
local brace = scan_to_char(source, "{", after_paren) local brace = scan_to_char(source, "{", after_paren)
-- scan: typedef Struct_(<name>) {
if not brace then return nil, open_paren + 1 end if not brace then return nil, open_paren + 1 end
local body, after_brace = read_braces(source, brace) local body, after_brace = read_braces(source, brace)
-- scan: typedef Struct_(<name>) { <fields> }
local fields, bytes = parse_binds_body(body) local fields, bytes = parse_binds_body(body)
-- Only emit Binds_* structs (other Struct_ typedefs are ignored). -- Only emit Binds_* structs (other Struct_ typedefs are ignored).
@@ -505,9 +514,11 @@ local function find_binds_structs(source)
pos = skip_preprocessor_line(source, pos) pos = skip_preprocessor_line(source, pos)
else else
local ident, after_ident = read_ident(source, pos) local ident, after_ident = read_ident(source, pos)
-- scan: <ident>
if not ident then if not ident then
pos = pos + 1 pos = pos + 1
elseif ident == "typedef" then elseif ident == "typedef" then
-- scan: typedef Struct_(<name>) { <fields> }
local binds_struct, new_pos = parse_typedef_binds(source, pos, after_ident, line_of) local binds_struct, new_pos = parse_typedef_binds(source, pos, after_ident, line_of)
if binds_struct then out[#out + 1] = binds_struct end if binds_struct then out[#out + 1] = binds_struct end
pos = new_pos pos = new_pos
@@ -550,6 +561,7 @@ local function find_atom_names(source)
if pos > str_len then break end if pos > str_len then break end
local ident, after_ident = read_ident(source, pos) local ident, after_ident = read_ident(source, pos)
-- scan: <ident>
if not ident then if not ident then
pos = pos + 1 pos = pos + 1
elseif ident ~= ATOM_DECL then elseif ident ~= ATOM_DECL then
@@ -560,13 +572,16 @@ local function find_atom_names(source)
pos = open_paren + 1 pos = open_paren + 1
else else
local inner, after_paren = read_parens(source, open_paren) local inner, after_paren = read_parens(source, open_paren)
-- scan: MipsAtom_(<name>)
local name, _ = read_alnum_ident(inner, 1) local name, _ = read_alnum_ident(inner, 1)
if name and name ~= "" then if name and name ~= "" then
out[#out + 1] = { line = line_of(pos), name = name } out[#out + 1] = { line = line_of(pos), name = name }
end end
local brace = scan_to_char(source, "{", after_paren) local brace = scan_to_char(source, "{", after_paren)
-- scan: MipsAtom_(<name>) {
if brace then if brace then
local _, after_brace = read_braces(source, brace) local _, after_brace = read_braces(source, brace)
-- scan: MipsAtom_(<name>) { <body> }
pos = after_brace pos = after_brace
else else
pos = open_paren + 1 pos = open_paren + 1
@@ -630,12 +645,14 @@ end
local function parse_atom_info_call(source, atom_name, after_mipsatom_paren, line_of) local function parse_atom_info_call(source, atom_name, after_mipsatom_paren, line_of)
local lookahead = skip_ws_and_cmt(source, after_mipsatom_paren) local lookahead = skip_ws_and_cmt(source, after_mipsatom_paren)
local look_ident, look_after = read_ident(source, lookahead) local look_ident, look_after = read_ident(source, lookahead)
-- scan: MipsAtom_(<name>) <look_ident>
if look_ident ~= ATOM_INFO then return nil, after_mipsatom_paren end if look_ident ~= ATOM_INFO then return nil, after_mipsatom_paren end
local info_open = skip_ws_and_cmt(source, look_after) local info_open = skip_ws_and_cmt(source, look_after)
if source:byte(info_open) ~= BYTE_OPEN_PAREN then return nil, info_open + 1 end if source:byte(info_open) ~= BYTE_OPEN_PAREN then return nil, info_open + 1 end
local info_inner, info_after = read_parens(source, info_open) local info_inner, info_after = read_parens(source, info_open)
-- scan: MipsAtom_(<name>) atom_info(<binds>, <reads>, <writes>)
local args = parse_atom_annot_args(info_inner) local args = parse_atom_annot_args(info_inner)
local entry = new_annot_entry(line_of(lookahead), ATOM_INFO, atom_name, "info") local entry = new_annot_entry(line_of(lookahead), ATOM_INFO, atom_name, "info")
ANNOT_ARG_HANDLERS.info(entry, args) ANNOT_ARG_HANDLERS.info(entry, args)
@@ -661,6 +678,7 @@ local function find_atom_annotations(source)
pos = skip_preprocessor_line(source, pos) pos = skip_preprocessor_line(source, pos)
else else
local ident, after_ident = read_ident(source, pos) local ident, after_ident = read_ident(source, pos)
-- scan: <ident>
if not ident then if not ident then
pos = pos + 1 pos = pos + 1
elseif ident == ATOM_DECL then elseif ident == ATOM_DECL then
@@ -669,16 +687,20 @@ local function find_atom_annotations(source)
pos = open_paren + 1 pos = open_paren + 1
else else
local inner, after_paren = read_parens(source, open_paren) local inner, after_paren = read_parens(source, open_paren)
-- scan: MipsAtom_(<name>)
local name, _ = read_alnum_ident(inner, 1) local name, _ = read_alnum_ident(inner, 1)
local entry, new_pos = parse_atom_info_call(source, name, after_paren, line_of) local entry, new_pos = parse_atom_info_call(source, name, after_paren, line_of)
-- scan: MipsAtom_(<name>) atom_info(<binds>, <reads>, <writes>)
if entry then annots[#annots + 1] = entry end if entry then annots[#annots + 1] = entry end
pos = new_pos pos = new_pos
-- Skip past the body { ... } if present. -- Skip past the body { ... } if present.
local brace = scan_to_char(source, "{", pos) local brace = scan_to_char(source, "{", pos)
-- scan: MipsAtom_(<name>) atom_info(...) {
if brace then if brace then
local _, after_brace = read_braces(source, brace) local _, after_brace = read_braces(source, brace)
-- scan: MipsAtom_(<name>) atom_info(...) { <body> }
pos = after_brace pos = after_brace
end end
end end
+10
View File
@@ -173,7 +173,9 @@ local function find_function_args_for(source, name, before_pos)
end end
local open_paren = last_idx + #name -- position of "(" local open_paren = last_idx + #name -- position of "("
-- scan: MipsAtom ac_X(
local inner = duffle.read_parens(source, open_paren) local inner = duffle.read_parens(source, open_paren)
-- scan: MipsAtom ac_X(<args>)
if not inner then return nil end if not inner then return nil end
return inner return inner
end end
@@ -408,8 +410,10 @@ end
--- @return Component|nil, integer -- the component + new source position --- @return Component|nil, integer -- the component + new source position
local function make_bare_component(source, name, ident_pos, after_paren, line_of, args, comment) local function make_bare_component(source, name, ident_pos, after_paren, line_of, args, comment)
local brace = duffle.scan_to_char(source, "{", after_paren) local brace = duffle.scan_to_char(source, "{", after_paren)
-- scan: <ident>(<name>) {
if not brace then return nil, after_paren + 1 end if not brace then return nil, after_paren + 1 end
local body, after_brace = duffle.read_braces(source, brace) local body, after_brace = duffle.read_braces(source, brace)
-- scan: <ident>(<name>) { <body> }
return { return {
line = line_of(ident_pos), line = line_of(ident_pos),
name = name:sub(AC_PREFIX_LEN + 1), -- strip "ac_" prefix name = name:sub(AC_PREFIX_LEN + 1), -- strip "ac_" prefix
@@ -449,6 +453,7 @@ local function find_component_atoms(source)
if pos > src_len then break end if pos > src_len then break end
local ident, after_ident = duffle.read_ident(source, pos) local ident, after_ident = duffle.read_ident(source, pos)
-- scan: <ident>
local is_comp = ident == ATOM_COMP or ident == ATOM_COMP_PROC local is_comp = ident == ATOM_COMP or ident == ATOM_COMP_PROC
if not ident then if not ident then
pos = pos + 1 pos = pos + 1
@@ -460,7 +465,9 @@ local function find_component_atoms(source)
pos = open_paren + 1 pos = open_paren + 1
else else
local inner, after_paren = duffle.read_parens(source, open_paren) local inner, after_paren = duffle.read_parens(source, open_paren)
-- scan: <ident>(<args>)
local name, body = parse_atomcomp_inner(inner) local name, body = parse_atomcomp_inner(inner)
-- scan: <ident>(<name>) OR <ident>(<name>, { <body> })
if not name or name:sub(1, AC_PREFIX_LEN) ~= AC_PREFIX then if not name or name:sub(1, AC_PREFIX_LEN) ~= AC_PREFIX then
pos = open_paren + 1 pos = open_paren + 1
else else
@@ -468,11 +475,14 @@ local function find_component_atoms(source)
local comment = preceding_comment_block(source, pos) local comment = preceding_comment_block(source, pos)
if body == nil then if body == nil then
-- Bare form: body comes from the brace block after the parens. -- Bare form: body comes from the brace block after the parens.
-- scan: <ident>(<name>) {
local comp, new_pos = make_bare_component(source, name, pos, after_paren, line_of, args, comment) local comp, new_pos = make_bare_component(source, name, pos, after_paren, line_of, args, comment)
-- scan: <ident>(<name>) { <body> }
if comp then out[#out + 1] = comp end if comp then out[#out + 1] = comp end
pos = new_pos pos = new_pos
else else
-- Function form: body was inside the parens. -- Function form: body was inside the parens.
-- scan: <ident>(<name>, { <body> })
out[#out + 1] = make_proc_component(name, body, pos, line_of, args, comment) out[#out + 1] = make_proc_component(name, body, pos, line_of, args, comment)
pos = after_paren pos = after_paren
end end
+13
View File
@@ -147,6 +147,7 @@ local function extract_ident_args(token, after_ident)
local arg_start = duffle.skip_ws_and_cmt(token, after_ident) local arg_start = duffle.skip_ws_and_cmt(token, after_ident)
if token:sub(arg_start, arg_start) ~= "(" then return {}, nil end if token:sub(arg_start, arg_start) ~= "(" then return {}, nil end
local inner, after_paren = duffle.read_parens(token, arg_start) local inner, after_paren = duffle.read_parens(token, arg_start)
-- scan: <marker>(<args>)
local args = {} local args = {}
local pos = 1 local pos = 1
@@ -236,7 +237,9 @@ local function find_marker_call_end(tok)
pos = (nx > pos) and nx or (pos + 1) pos = (nx > pos) and nx or (pos + 1)
else else
local ident, after_ident = duffle.read_ident(tok, pos) local ident, after_ident = duffle.read_ident(tok, pos)
-- scan: <ident>
if ident == LABEL_MARKER or ident == OFFSET_MARKER then if ident == LABEL_MARKER or ident == OFFSET_MARKER then
-- scan: atom_label(<name>) OR atom_offset(<tag>, <target>)
local open_paren = duffle.skip_ws_and_cmt(tok, after_ident) local open_paren = duffle.skip_ws_and_cmt(tok, after_ident)
if tok:sub(open_paren, open_paren) == "(" then if tok:sub(open_paren, open_paren) == "(" then
local _, end_paren = duffle.read_parens(tok, open_paren) local _, end_paren = duffle.read_parens(tok, open_paren)
@@ -276,6 +279,7 @@ local function try_wrapped_atom(source_text, after_pos)
local paren_pos = duffle.skip_ws_and_cmt(source_text, after_pos) local paren_pos = duffle.skip_ws_and_cmt(source_text, after_pos)
if source_text:sub(paren_pos, paren_pos) ~= "(" then return nil end if source_text:sub(paren_pos, paren_pos) ~= "(" then return nil end
local inner, after_paren = duffle.read_parens(source_text, paren_pos) local inner, after_paren = duffle.read_parens(source_text, paren_pos)
-- scan: MipsAtom_(<name>)
local name_start = 1 local name_start = 1
while name_start <= #inner and duffle.is_space(inner:sub(name_start, name_start)) do while name_start <= #inner and duffle.is_space(inner:sub(name_start, name_start)) do
@@ -289,8 +293,10 @@ local function try_wrapped_atom(source_text, after_pos)
if name == "" then return nil end if name == "" then return nil end
local brace_pos = duffle.scan_to_char(source_text, "{", after_paren) local brace_pos = duffle.scan_to_char(source_text, "{", after_paren)
-- scan: MipsAtom_(<name>) {
if not brace_pos then return nil end if not brace_pos then return nil end
local body, after_brace = duffle.read_braces(source_text, brace_pos) local body, after_brace = duffle.read_braces(source_text, brace_pos)
-- scan: MipsAtom_(<name>) { <body> }
return { name = name, body = body, after_brace = after_brace } return { name = name, body = body, after_brace = after_brace }
end end
@@ -301,13 +307,17 @@ end
local function try_raw_atom(source_text, after_pos) local function try_raw_atom(source_text, after_pos)
local next_pos = duffle.skip_ws_and_cmt(source_text, after_pos) local next_pos = duffle.skip_ws_and_cmt(source_text, after_pos)
local next_ident, next_after = duffle.read_ident(source_text, next_pos) local next_ident, next_after = duffle.read_ident(source_text, next_pos)
-- scan: MipsCode <next_ident>
if not next_ident then return nil end if not next_ident then return nil end
if not starts_with(next_ident, CODE_RAW_PREFIX) then return nil end if not starts_with(next_ident, CODE_RAW_PREFIX) then return nil end
if #next_ident <= CODE_RAW_PREFIX_LEN then return nil end if #next_ident <= CODE_RAW_PREFIX_LEN then return nil end
local atom_name = next_ident:sub(CODE_RAW_PREFIX_LEN + 1) local atom_name = next_ident:sub(CODE_RAW_PREFIX_LEN + 1)
-- scan: MipsCode code_<name>
local brace_pos = duffle.scan_to_char(source_text, "{", next_after) local brace_pos = duffle.scan_to_char(source_text, "{", next_after)
-- scan: MipsCode code_<name> {
if not brace_pos then return nil end if not brace_pos then return nil end
local body, after_brace = duffle.read_braces(source_text, brace_pos) local body, after_brace = duffle.read_braces(source_text, brace_pos)
-- scan: MipsCode code_<name> { <body> }
return { name = atom_name, body = body, after_brace = after_brace } return { name = atom_name, body = body, after_brace = after_brace }
end end
@@ -324,9 +334,11 @@ local function find_atoms(source_text)
pos = skip_qualifiers(source_text, pos); if pos > src_len then break end pos = skip_qualifiers(source_text, pos); if pos > src_len then break end
local ident, after = duffle.read_ident(source_text, pos) local ident, after = duffle.read_ident(source_text, pos)
-- scan: <ident>
if not ident then if not ident then
pos = pos + 1 pos = pos + 1
elseif ident == ATOM_PREFIX then elseif ident == ATOM_PREFIX then
-- scan: MipsAtom_(<name>) { <body> }
local atom = try_wrapped_atom(source_text, after) local atom = try_wrapped_atom(source_text, after)
if atom then if atom then
atoms[#atoms + 1] = { name = atom.name, body = atom.body } atoms[#atoms + 1] = { name = atom.name, body = atom.body }
@@ -335,6 +347,7 @@ local function find_atoms(source_text)
pos = pos + 1 pos = pos + 1
end end
elseif ident == CODE_DECL then elseif ident == CODE_DECL then
-- scan: MipsCode code_<name> { <body> }
local atom = try_raw_atom(source_text, after) local atom = try_raw_atom(source_text, after)
if atom then if atom then
atoms[#atoms + 1] = { name = atom.name, body = atom.body } atoms[#atoms + 1] = { name = atom.name, body = atom.body }
+25 -11
View File
@@ -157,6 +157,7 @@ local function find_atom_bodies(source_text)
pos = eol_pos + 1 pos = eol_pos + 1
else else
local ident, ident_end = duffle.read_ident(source_text, pos) local ident, ident_end = duffle.read_ident(source_text, pos)
-- scan: <ident>
if not ident then if not ident then
pos = pos + 1 pos = pos + 1
elseif ident == "MipsAtom_" elseif ident == "MipsAtom_"
@@ -175,6 +176,7 @@ local function find_atom_bodies(source_text)
pos = open_paren + 1 pos = open_paren + 1
else else
local inner, after_paren = duffle.read_parens(source_text, open_paren) local inner, after_paren = duffle.read_parens(source_text, open_paren)
-- scan: <ident>(<args>)
if kind == "comp_proc" then if kind == "comp_proc" then
-- MipsAtomComp_Proc_(sym, { body }) -- MipsAtomComp_Proc_(sym, { body })
@@ -216,6 +218,7 @@ local function find_atom_bodies(source_text)
-- unmatched; bail -- unmatched; bail
pos = open_paren + 1 pos = open_paren + 1
else else
-- scan: <ident>(<name>, { <body> })
-- First ident in `inner` is the comp name. -- First ident in `inner` is the comp name.
local name_match = inner:match("^%s*([%w_]+)") local name_match = inner:match("^%s*([%w_]+)")
local name = name_match or "?" local name = name_match or "?"
@@ -245,12 +248,15 @@ local function find_atom_bodies(source_text)
local name_end = name_start local name_end = name_start
while name_end <= #inner and inner:sub(name_end, name_end):match("[%w_]") do name_end = name_end + 1 end while name_end <= #inner and inner:sub(name_end, name_end):match("[%w_]") do name_end = name_end + 1 end
local name = inner:sub(name_start, name_end - 1) local name = inner:sub(name_start, name_end - 1)
-- scan: <ident>(<name>)
if name == "" then if name == "" then
pos = open_paren + 1 pos = open_paren + 1
else else
local brace = duffle.scan_to_char(source_text, "{", after_paren) local brace = duffle.scan_to_char(source_text, "{", after_paren)
-- scan: <ident>(<name>) {
if brace then if brace then
local body, after_brace = duffle.read_braces(source_text, brace) local body, after_brace = duffle.read_braces(source_text, brace)
-- scan: <ident>(<name>) { <body> }
local body_off = brace + 1 local body_off = brace + 1
out[#out + 1] = { out[#out + 1] = {
line = line_of(pos), line = line_of(pos),
@@ -410,8 +416,7 @@ local function check_gte_pipeline_fill(atoms, findings, line_of)
local ti = 1 local ti = 1
while ti <= tn do while ti <= tn do
local tok = tokens[ti].tok local tok = tokens[ti].tok
local cmdw_full = tok:match("^(gte_cmdw_[%w_]+)%s*[,%)]") local cmdw_full = tok:match("^(gte_cmdw_[%w_]+)%s*[,%)]") or tok:match("^(gte_cmdw_[%w_]+)%s*$")
or tok:match("^(gte_cmdw_[%w_]+)%s*$")
if cmdw_full then if cmdw_full then
local variant = cmdw_full:match("^gte_cmdw_(.+)$") local variant = cmdw_full:match("^gte_cmdw_(.+)$")
local need = duffle.GTE_PIPELINE_LATENCY[cmdw_full] local need = duffle.GTE_PIPELINE_LATENCY[cmdw_full]
@@ -597,11 +602,13 @@ local function find_binds_structs(source_text)
pos = eol_pos + 1 pos = eol_pos + 1
else else
local ident, ident_end = duffle.read_ident(source_text, pos) local ident, ident_end = duffle.read_ident(source_text, pos)
-- scan: <ident>
if not ident then if not ident then
pos = pos + 1 pos = pos + 1
elseif ident == "typedef" then elseif ident == "typedef" then
local after_typedef = duffle.skip_ws_and_cmt(source_text, ident_end) local after_typedef = duffle.skip_ws_and_cmt(source_text, ident_end)
local id2, id2_end = duffle.read_ident(source_text, after_typedef) local id2, id2_end = duffle.read_ident(source_text, after_typedef)
-- scan: typedef <id2>
if id2 ~= "Struct_" then if id2 ~= "Struct_" then
pos = id2_end or (after_typedef + 1) pos = id2_end or (after_typedef + 1)
else else
@@ -610,12 +617,15 @@ local function find_binds_structs(source_text)
pos = open_paren + 1 pos = open_paren + 1
else else
local inner, after_paren = duffle.read_parens(source_text, open_paren) local inner, after_paren = duffle.read_parens(source_text, open_paren)
-- scan: typedef Struct_(<name>)
local name = duffle.trim(inner) local name = duffle.trim(inner)
local brace = duffle.scan_to_char(source_text, "{", after_paren) local brace = duffle.scan_to_char(source_text, "{", after_paren)
-- scan: typedef Struct_(<name>) {
if not brace then if not brace then
pos = open_paren + 1 pos = open_paren + 1
else else
local body, after_brace = duffle.read_braces(source_text, brace) local body, after_brace = duffle.read_braces(source_text, brace)
-- scan: typedef Struct_(<name>) { <fields> }
local fields = {} local fields = {}
local byte_off = 0 local byte_off = 0
local body_pos = 1 local body_pos = 1
@@ -668,6 +678,7 @@ local function find_atom_info(source_text)
pos = eol_pos + 1 pos = eol_pos + 1
else else
local ident, ident_end = duffle.read_ident(source_text, pos) local ident, ident_end = duffle.read_ident(source_text, pos)
-- scan: <ident>
if not ident then if not ident then
pos = pos + 1 pos = pos + 1
elseif ident == "MipsAtom_" then elseif ident == "MipsAtom_" then
@@ -676,6 +687,7 @@ local function find_atom_info(source_text)
pos = open_paren + 1 pos = open_paren + 1
else else
local inner, after_paren = duffle.read_parens(source_text, open_paren) local inner, after_paren = duffle.read_parens(source_text, open_paren)
-- scan: MipsAtom_(<name>)
local name_start = 1 local name_start = 1
while name_start <= #inner and inner:sub(name_start, name_start):match("[%s]") do name_start = name_start + 1 end while name_start <= #inner and inner:sub(name_start, name_start):match("[%s]") do name_start = name_start + 1 end
local name_end = name_start local name_end = name_start
@@ -683,10 +695,12 @@ local function find_atom_info(source_text)
local atom_name = inner:sub(name_start, name_end - 1) local atom_name = inner:sub(name_start, name_end - 1)
local lookahead = duffle.skip_ws_and_cmt(source_text, after_paren) local lookahead = duffle.skip_ws_and_cmt(source_text, after_paren)
local look_ident, look_end = duffle.read_ident(source_text, lookahead) local look_ident, look_end = duffle.read_ident(source_text, lookahead)
-- scan: MipsAtom_(<name>) <look_ident>
if look_ident == "atom_info" then if look_ident == "atom_info" then
local info_open = duffle.skip_ws_and_cmt(source_text, look_end) local info_open = duffle.skip_ws_and_cmt(source_text, look_end)
if source_text:sub(info_open, info_open) == "(" then if source_text:sub(info_open, info_open) == "(" then
local info_inner, info_after = duffle.read_parens(source_text, info_open) local info_inner, info_after = duffle.read_parens(source_text, info_open)
-- scan: MipsAtom_(<name>) atom_info(<binds>, <reads>, <writes>)
local binds, reads, writes = nil, nil, nil local binds, reads, writes = nil, nil, nil
local sub_pos = 1 local sub_pos = 1
while sub_pos <= #info_inner do while sub_pos <= #info_inner do
@@ -698,6 +712,7 @@ local function find_atom_info(source_text)
local sub_open = duffle.skip_ws_and_cmt(info_inner, sub_end) local sub_open = duffle.skip_ws_and_cmt(info_inner, sub_end)
if info_inner:sub(sub_open, sub_open) == "(" then if info_inner:sub(sub_open, sub_open) == "(" then
local sub_inner, sub_after2 = duffle.read_parens(info_inner, sub_open) local sub_inner, sub_after2 = duffle.read_parens(info_inner, sub_open)
-- scan: atom_bind(<Binds_X>)
binds = duffle.trim(sub_inner) binds = duffle.trim(sub_inner)
sub_pos = sub_after2 sub_pos = sub_after2
else else
@@ -708,6 +723,7 @@ local function find_atom_info(source_text)
local sub_open = duffle.skip_ws_and_cmt(info_inner, sub_end) local sub_open = duffle.skip_ws_and_cmt(info_inner, sub_end)
if info_inner:sub(sub_open, sub_open) == "(" then if info_inner:sub(sub_open, sub_open) == "(" then
local sub_inner, sub_after2 = duffle.read_parens(info_inner, sub_open) local sub_inner, sub_after2 = duffle.read_parens(info_inner, sub_open)
-- scan: atom_reads(<regs>) OR atom_writes(<regs>)
local regs = {} local regs = {}
local sub_inner_pos = 1 local sub_inner_pos = 1
while sub_inner_pos <= #sub_inner do while sub_inner_pos <= #sub_inner do
@@ -800,6 +816,7 @@ local function check_abi_handoff(atoms, atom_infos, binds_index, findings)
if tok:match("^load_word%s*%(") then if tok:match("^load_word%s*%(") then
if tok:find("R_TapePtr", 1, true) and tok:find("O_(" .. binds_name .. ",", 1, true) then if tok:find("R_TapePtr", 1, true) and tok:find("O_(" .. binds_name .. ",", 1, true) then
local field = tok:match(bind_re) local field = tok:match(bind_re)
-- scan: load_word(R_*, R_TapePtr, O_(<Binds_X>, <field>))
if field then if field then
found_field_seq[#found_field_seq + 1] = field found_field_seq[#found_field_seq + 1] = field
found_field_set[field] = true found_field_set[field] = true
@@ -816,6 +833,7 @@ local function check_abi_handoff(atoms, atom_infos, binds_index, findings)
end end
if tok:find("R_TapePtr", 1, true) if tok:find("R_TapePtr", 1, true)
and tok:find("S_(" .. binds_name .. ")", 1, true) then and tok:find("S_(" .. binds_name .. ")", 1, true) then
-- scan: add_ui_self(R_TapePtr, S_(<Binds_X>))
found_advance = true found_advance = true
end end
end end
@@ -893,8 +911,7 @@ local function check_gpu_portstore_shape(atoms, findings)
local tok = t.tok local tok = t.tok
-- Match `mac_format_<shape>_color(...)` and strip `_color` -- Match `mac_format_<shape>_color(...)` and strip `_color`
-- to get the bare shape suffix (f3 / g4 / etc). -- to get the bare shape suffix (f3 / g4 / etc).
local shape = tok:match("^mac_format_([%w_]+)_color%s*%(") local shape = tok:match("^mac_format_([%w_]+)_color%s*%(") or tok:match("^mac_format_([%w_]+)_color%s*$")
or tok:match("^mac_format_([%w_]+)_color%s*$")
if shape and duffle.GP0_CMD_BY_SHAPE[shape] then if shape and duffle.GP0_CMD_BY_SHAPE[shape] then
if not cmd_byte then if not cmd_byte then
cmd_byte = duffle.GP0_CMD_BY_SHAPE[shape] cmd_byte = duffle.GP0_CMD_BY_SHAPE[shape]
@@ -1279,10 +1296,8 @@ local function validate(ctx, src)
-- either severity (errors for missing nops; warnings for unknown -- either severity (errors for missing nops; warnings for unknown
-- cmdw macros not in the latency table). Bin by `kind`, not by -- cmdw macros not in the latency table). Bin by `kind`, not by
-- check name. -- check name.
if f.kind == "error" then if f.kind == "error" then errors [#errors + 1] = { line = f.line, msg = f.msg }
errors[#errors + 1] = { line = f.line, msg = f.msg } else warnings[#warnings + 1] = { line = f.line, msg = f.msg }
else
warnings[#warnings + 1] = { line = f.line, msg = f.msg }
end end
end end
-- Per-source "scanned:" summary line. Includes the source basename -- Per-source "scanned:" summary line. Includes the source basename
@@ -1410,9 +1425,8 @@ local function emit_static_analysis_txt(ctx, src, result)
return out_path return out_path
end end
-- (Old per-source emit function above; kept for backward compat but no -- (Old per-source emit function above; kept for backward compat but no longer called from M.run.
-- longer called from M.run. Replaced by `emit_module_static_analysis_txt` -- Replaced by `emit_module_static_analysis_txt` which aggregates by directory.)
-- which aggregates by directory.)
--- Per-directory emit. Aggregates atoms + findings across every source --- Per-directory emit. Aggregates atoms + findings across every source
--- in `dir_sources` and writes a single report to --- in `dir_sources` and writes a single report to