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