1use std::sync::Arc;
31
32use harn_vm::VmValue;
33
34use crate::error::HostlibError;
35use crate::registry::{BuiltinRegistry, HostlibCapability, RegisteredBuiltin, SyncHandler};
36
37mod bracket_balance;
38mod function_body;
39mod fuzzy;
40mod imports;
41mod language;
42mod mutation;
43mod outline;
44mod parse;
45mod parse_errors;
46mod symbols;
47mod symbols_call;
48mod types;
49mod undefined_names;
50
51pub use language::Language;
52pub use types::{OutlineItem, ParseError, ParsedNode, Symbol, SymbolKind, UndefinedName};
53
54pub mod api {
58 use std::path::Path;
59
60 use crate::error::HostlibError;
61
62 use super::language::Language;
63 use super::outline::build_outline;
64 use super::parse::{parse_source, read_source};
65 use super::symbols::extract;
66 use super::types::{OutlineItem, Symbol};
67
68 pub fn symbols(
70 path: &Path,
71 language_hint: Option<&str>,
72 ) -> Result<(Language, Vec<Symbol>), HostlibError> {
73 let language = detect(path, language_hint)?;
74 let source = read_source(&path.to_string_lossy(), 0)?;
75 let tree = parse_source(&source, language)?;
76 Ok((language, extract(&tree, &source, language)))
77 }
78
79 pub fn outline(
81 path: &Path,
82 language_hint: Option<&str>,
83 ) -> Result<(Language, Vec<OutlineItem>), HostlibError> {
84 let (language, symbols) = symbols(path, language_hint)?;
85 Ok((language, build_outline(symbols)))
86 }
87
88 pub fn symbols_from_source(
91 source: &str,
92 language: Language,
93 ) -> Result<Vec<Symbol>, HostlibError> {
94 let tree = parse_source(source, language)?;
95 Ok(extract(&tree, source, language))
96 }
97
98 fn detect(path: &Path, language_hint: Option<&str>) -> Result<Language, HostlibError> {
99 Language::detect(path, language_hint).ok_or_else(|| HostlibError::InvalidParameter {
100 builtin: "ast::api",
101 param: "language",
102 message: format!(
103 "could not infer a tree-sitter grammar for `{}` \
104 (extension or `language` field unrecognized)",
105 path.display()
106 ),
107 })
108 }
109}
110
111#[derive(Default)]
115pub struct AstCapability;
116
117impl HostlibCapability for AstCapability {
118 fn module_name(&self) -> &'static str {
119 "ast"
120 }
121
122 fn register_builtins(&self, registry: &mut BuiltinRegistry) {
123 register(registry, "hostlib_ast_parse_file", "parse_file", parse::run);
124 register(
125 registry,
126 "hostlib_ast_symbols",
127 "symbols",
128 symbols_call::run,
129 );
130 register(registry, "hostlib_ast_outline", "outline", outline::run);
131 register(
132 registry,
133 "hostlib_ast_parse_errors",
134 "parse_errors",
135 parse_errors::run,
136 );
137 register(
138 registry,
139 "hostlib_ast_undefined_names",
140 "undefined_names",
141 undefined_names::run,
142 );
143 register(
144 registry,
145 "hostlib_ast_function_body",
146 "function_body",
147 function_body::run_single,
148 );
149 register(
150 registry,
151 "hostlib_ast_function_bodies",
152 "function_bodies",
153 function_body::run_bulk,
154 );
155 register(
156 registry,
157 "hostlib_ast_extract_imports",
158 "extract_imports",
159 imports::run,
160 );
161 register(
162 registry,
163 "hostlib_ast_symbol_extract",
164 "symbol_extract",
165 mutation::run_extract,
166 );
167 register(
168 registry,
169 "hostlib_ast_symbol_delete",
170 "symbol_delete",
171 mutation::run_delete,
172 );
173 register(
174 registry,
175 "hostlib_ast_symbol_replace",
176 "symbol_replace",
177 mutation::run_replace,
178 );
179 register(
180 registry,
181 "hostlib_ast_bracket_balance",
182 "bracket_balance",
183 bracket_balance::run,
184 );
185 }
186}
187
188fn register(
189 registry: &mut BuiltinRegistry,
190 name: &'static str,
191 method: &'static str,
192 runner: fn(&[VmValue]) -> Result<VmValue, HostlibError>,
193) {
194 let handler: SyncHandler = Arc::new(runner);
195 registry.register(RegisteredBuiltin {
196 name,
197 module: "ast",
198 method,
199 handler,
200 });
201}