-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode_parse.lua
More file actions
143 lines (120 loc) · 4.03 KB
/
Copy pathcode_parse.lua
File metadata and controls
143 lines (120 loc) · 4.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
-- MCP Tool: code_parse
-- Parse source code and return the syntax tree structure
-- Useful for understanding code structure at any depth
-- Entry kind: function.lua
local json = require("json")
local treesitter = require("treesitter")
local parser = require("parser")
--- Walk tree to specified depth, collecting node info
local function walk_tree(node, code, max_depth, current_depth)
if not node then return nil end
current_depth = current_depth or 0
local pos = parser.node_pos(node)
local entry = {
kind = node:kind(),
named = node:is_named(),
line = pos.start_line,
end_line = pos.end_line,
}
-- Include text for leaf nodes or shallow trees
local child_count = node:named_child_count()
if child_count == 0 then
local text = node:text()
if #text <= 120 then
entry.text = text
else
entry.text = string.sub(text, 1, 117) .. "..."
end
end
-- Add field name if available
local field = node:field_name_for_child(0)
if field then
entry.field = field
end
-- Error markers
if node:is_error() then
entry.error = true
end
if node:is_missing() then
entry.missing = true
end
-- Recurse into children up to max depth
if child_count > 0 and current_depth < max_depth then
entry.children = {}
local count = node:child_count()
for i = 0, count - 1 do
local child = node:child(i)
if child and child:is_named() then
local child_entry = walk_tree(child, code, max_depth, current_depth + 1)
if child_entry then
table.insert(entry.children, child_entry)
end
end
end
if #entry.children == 0 then
entry.children = nil
end
elseif child_count > 0 then
entry.children_count = child_count
end
return entry
end
--- Format tree as indented text
local function format_tree(entry, indent)
indent = indent or 0
local lines = {}
local prefix = string.rep(" ", indent)
local line_info = string.format("L%d", entry.line)
if entry.end_line ~= entry.line then
line_info = string.format("L%d-%d", entry.line, entry.end_line)
end
local text_part = ""
if entry.text then
local clean = string.gsub(entry.text, "\n", "\\n")
if #clean > 60 then
clean = string.sub(clean, 1, 57) .. "..."
end
text_part = ' "' .. clean .. '"'
end
local marker = ""
if entry.error then marker = " ⚠ERROR" end
if entry.missing then marker = " ⚠MISSING" end
table.insert(lines, string.format(
"%s(%s) [%s]%s%s",
prefix, entry.kind, line_info, text_part, marker
))
if entry.children then
for _, child in ipairs(entry.children) do
local child_lines = format_tree(child, indent + 1)
for _, l in ipairs(child_lines) do
table.insert(lines, l)
end
end
elseif entry.children_count then
table.insert(lines, prefix .. " ... " .. entry.children_count .. " children")
end
return lines
end
local function call(arguments)
local code, lang, err = parser.resolve_source(arguments)
if err then return "Error: " .. err end
local max_depth = arguments.depth or 3
if max_depth < 0 then max_depth = 0 end
if max_depth > 20 then max_depth = 20 end
local tree, root, parse_err = parser.parse(lang, code)
if parse_err then return "Error: " .. parse_err end
local ast = walk_tree(root, code, max_depth, 0)
-- Format output
local lines = {}
table.insert(lines, "# Syntax Tree (" .. lang .. ")")
if parser.has_errors(root) then
table.insert(lines, "⚠ Source contains syntax errors (partial tree)")
end
table.insert(lines, "")
local tree_lines = format_tree(ast, 0)
for _, l in ipairs(tree_lines) do
table.insert(lines, l)
end
return table.concat(lines, "\n")
end
return { call = call }