local stage = {} local function get_index_name(base_name, key_node) if key_node.tag == "String" then return base_name .. "." .. key_node[1] end end local function get_full_field_name(node) if node.tag == "Id" then return node[1] elseif node.tag == "Index" then local base_name = get_full_field_name(node[1]) return base_name and get_index_name(base_name, node[2]) end end local handle_node local function handle_nodes(nodes) for _, node in ipairs(nodes) do if type(node) == "table" then handle_node(node) end end end function handle_node(node, name) if node.tag == "Function" then node.name = name handle_nodes(node[2]) elseif node.tag == "Set" or node.tag == "Local" or node.tag == "Localrec" then local lhs = node[1] local rhs = node[2] -- No need to handle LHS if there is no RHS, it's always just a list of locals in that case. if rhs then handle_nodes(lhs) for index, rhs_node in ipairs(rhs) do local lhs_node = lhs[index] local field_name = lhs_node and get_full_field_name(lhs_node) handle_node(rhs_node, field_name) end end elseif node.tag == "Table" and name then for _, pair_node in ipairs(node) do if pair_node.tag == "Pair" then local key_node = pair_node[1] local value_node = pair_node[2] handle_node(key_node) handle_node(value_node, get_index_name(name, key_node)) else handle_node(pair_node) end end else handle_nodes(node) end end -- Adds `name` field to `Function` ast nodes when possible: -- * Function assigned to a variable (doesn't matter if local or global): "foo". -- * Function assigned to a field: "foo.bar.baz". -- Function can be in a table assigned to a variable or a field, e.g. `foo.bar = {baz = function() ... end}`. -- * Otherwise: `nil`. function stage.run(chstate) handle_nodes(chstate.ast) end return stage