harn_parser/builtin_signatures/
lookup.rs1use crate::ast::TypeExpr;
10use harn_builtin_meta::{BuiltinExposure, CapabilityId};
11
12use super::signatures;
13use super::{BuiltinMetadata, BuiltinSignature, Ty, TyExt};
14
15pub fn lookup(name: &str) -> Option<&'static BuiltinSignature> {
21 if let Some(entry) = harn_builtin_registry::builtin_entry(name) {
22 return matches!(
23 entry.contract.exposure,
24 BuiltinExposure::PureGlobal | BuiltinExposure::CapabilityFunction { .. }
25 )
26 .then_some(entry.signature)
27 .or_else(|| {
28 (crate::legacy_ambient_capabilities_enabled()
29 && matches!(
30 entry.contract.exposure,
31 BuiltinExposure::HarnessMethod { .. }
32 | BuiltinExposure::PrivilegedWire
33 | BuiltinExposure::RuntimeInternal
34 ))
35 .then_some(entry.signature)
36 });
37 }
38 if crate::legacy_ambient_capabilities_enabled() {
39 if let Some(entry) = legacy_capability_method_entry(name) {
40 return Some(entry.signature);
41 }
42 if let Some(canonical) = crate::legacy_builtin_alias_target(name) {
43 return lookup(canonical);
44 }
45 }
46 for group in signatures::groups() {
47 for sig in group {
48 if sig.name == name {
49 return Some(sig);
50 }
51 }
52 }
53 None
54}
55
56pub fn legacy_capability_method_entry(
60 name: &str,
61) -> Option<&'static harn_builtin_registry::BuiltinManifestEntry> {
62 let mut matches = harn_builtin_registry::installed_manifest()
63 .into_iter()
64 .filter(|entry| {
65 matches!(
66 entry.contract.exposure,
67 BuiltinExposure::HarnessMethod { method, .. } if method == name
68 )
69 });
70 let entry = matches.next()?;
71 matches.next().is_none().then_some(entry)
72}
73
74pub fn lookup_capability_method(
76 capability: CapabilityId,
77 method: &str,
78) -> Option<&'static BuiltinSignature> {
79 capability_method_entry(capability.field_name(), method).map(|entry| entry.signature)
80}
81
82pub fn capability_method_entry(
86 field: &str,
87 method: &str,
88) -> Option<&'static harn_builtin_registry::BuiltinManifestEntry> {
89 let capability = CapabilityId::from_field_name(field)?;
90 harn_builtin_registry::installed_manifest()
91 .iter()
92 .copied()
93 .find(|entry| {
94 matches!(
95 entry.contract.exposure,
96 BuiltinExposure::HarnessMethod {
97 capability: candidate,
98 method: candidate_method,
99 } if candidate == capability && candidate_method == method
100 )
101 })
102 .or_else(|| harn_capability_contracts::capability_method_entry(field, method))
103}
104
105pub fn is_builtin(name: &str) -> bool {
107 lookup(name).is_some()
108 || (crate::legacy_ambient_capabilities_enabled()
109 && crate::is_registered_legacy_hostlib_name(name))
110}
111
112pub fn iter_builtin_names() -> impl Iterator<Item = &'static str> {
116 let installed: Vec<_> = harn_builtin_registry::installed_manifest()
117 .into_iter()
118 .filter(|entry| {
119 matches!(
120 entry.contract.exposure,
121 BuiltinExposure::PureGlobal | BuiltinExposure::CapabilityFunction { .. }
122 )
123 })
124 .collect();
125 let installed_names: std::collections::HashSet<&'static str> =
126 harn_builtin_registry::installed_manifest()
127 .into_iter()
128 .map(|entry| entry.name)
129 .collect();
130 installed.into_iter().map(|entry| entry.name).chain(
131 signatures::groups()
132 .into_iter()
133 .flat_map(|g| g.iter())
134 .filter(move |s| !installed_names.contains(s.name))
135 .map(|s| s.name),
136 )
137}
138
139pub fn static_signature_names() -> impl Iterator<Item = &'static str> {
148 signatures::groups()
149 .into_iter()
150 .flat_map(|g| g.iter())
151 .map(|s| s.name)
152}
153
154pub fn iter_builtin_metadata() -> impl Iterator<Item = BuiltinMetadata> {
159 let installed: Vec<_> = harn_builtin_registry::installed_manifest()
160 .into_iter()
161 .filter(|entry| {
162 matches!(
163 entry.contract.exposure,
164 BuiltinExposure::PureGlobal | BuiltinExposure::CapabilityFunction { .. }
165 )
166 })
167 .collect();
168 let installed_names: std::collections::HashSet<&'static str> =
169 harn_builtin_registry::installed_manifest()
170 .into_iter()
171 .map(|entry| entry.name)
172 .collect();
173 installed
174 .into_iter()
175 .map(|entry| BuiltinMetadata {
176 name: entry.name,
177 return_types: builtin_return_type_names(entry.signature),
178 })
179 .chain(
180 signatures::groups()
181 .into_iter()
182 .flat_map(|g| g.iter())
183 .filter(move |s| !installed_names.contains(s.name))
184 .map(|sig| BuiltinMetadata {
185 name: sig.name,
186 return_types: builtin_return_type_names(sig),
187 }),
188 )
189}
190
191pub fn builtin_return_type(name: &str) -> Option<TypeExpr> {
195 let sig = lookup(name)?;
196 if sig.returns.is_any() {
197 return None;
198 }
199 Some(sig.returns.to_type_expr())
200}
201
202pub fn is_untyped_boundary_source(name: &str) -> bool {
209 matches!(
210 name,
211 "json_parse"
212 | "json_extract"
213 | "yaml_parse"
214 | "toml_parse"
215 | "llm_call"
216 | "llm_call_safe"
217 | "llm_completion"
218 | "http_get"
219 | "http_post"
220 | "http_put"
221 | "http_patch"
222 | "http_delete"
223 | "http_download"
224 | "http_request"
225 | "http_session_request"
226 | "http_stream_info"
227 | "sse_receive"
228 | "sse_server_mock_receive"
229 | "sse_server_response"
230 | "sse_server_status"
231 | "websocket_accept"
232 | "websocket_receive"
233 | "host_call"
234 | "connector_call"
235 | "host_tool_call"
236 )
237}
238
239fn builtin_return_type_names(sig: &BuiltinSignature) -> &'static [&'static str] {
245 match &sig.returns {
246 Ty::Named(name) => match *name {
247 "bool" => &["bool"],
248 "bytes" => &["bytes"],
249 "dict" => &["dict"],
250 "float" => &["float"],
251 "int" => &["int"],
252 "list" => &["list"],
253 "nil" => &["nil"],
254 "string" => &["string"],
255 _ => &[],
256 },
257 Ty::Union(members) => match *members {
258 [Ty::Named("string"), Ty::Named("nil")] => &["string", "nil"],
259 [Ty::Named("nil"), Ty::Named("string")] => &["string", "nil"],
260 [Ty::Named("int"), Ty::Named("nil")] => &["int", "nil"],
261 [Ty::Named("nil"), Ty::Named("int")] => &["int", "nil"],
262 [Ty::Named("dict"), Ty::Named("nil")] => &["dict", "nil"],
263 [Ty::Named("nil"), Ty::Named("dict")] => &["dict", "nil"],
264 [Ty::Named("bytes"), Ty::Named("nil")] => &["bytes", "nil"],
265 [Ty::Named("nil"), Ty::Named("bytes")] => &["bytes", "nil"],
266 _ => &[],
267 },
268 Ty::Never => &["never"],
269 _ => &[],
270 }
271}