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 lookup_with_privileged_wire(name, false)
22}
23
24pub fn lookup_with_privileged_wire(
28 name: &str,
29 allow_privileged_wire: bool,
30) -> Option<&'static BuiltinSignature> {
31 if let Some(entry) = harn_builtin_registry::builtin_entry(name) {
32 return matches!(
33 entry.contract.exposure,
34 BuiltinExposure::PureGlobal | BuiltinExposure::CapabilityFunction { .. }
35 )
36 .then_some(entry.signature)
37 .or_else(|| {
38 (allow_privileged_wire && entry.contract.exposure == BuiltinExposure::PrivilegedWire)
39 .then_some(entry.signature)
40 })
41 .or_else(|| {
42 (crate::legacy_ambient_capabilities_enabled()
43 && matches!(
44 entry.contract.exposure,
45 BuiltinExposure::HarnessMethod { .. }
46 | BuiltinExposure::PrivilegedWire
47 | BuiltinExposure::RuntimeInternal
48 ))
49 .then_some(entry.signature)
50 });
51 }
52 if crate::legacy_ambient_capabilities_enabled() {
53 if let Some(entry) = legacy_capability_method_entry(name) {
54 return Some(entry.signature);
55 }
56 if let Some(entry) = legacy_ambient_cap_global_entry(name) {
57 return Some(entry.signature);
58 }
59 if let Some(canonical) = crate::legacy_builtin_alias_target(name) {
60 return lookup(canonical);
61 }
62 }
63 for group in signatures::groups() {
64 for sig in group {
65 if sig.name == name {
66 return Some(sig);
67 }
68 }
69 }
70 None
71}
72
73pub fn legacy_capability_method_entry(
77 name: &str,
78) -> Option<&'static harn_builtin_registry::BuiltinManifestEntry> {
79 let mut matches = ambient_harness_method_entries().filter(|entry| {
80 matches!(
81 entry.contract.exposure,
82 BuiltinExposure::HarnessMethod { method, .. } if method == name
83 )
84 });
85 let entry = matches.next()?;
86 matches.next().is_none().then_some(entry)
87}
88
89pub fn legacy_ambient_cap_global_entry(
93 name: &str,
94) -> Option<&'static harn_builtin_registry::BuiltinManifestEntry> {
95 ambient_harness_method_entries().find(|entry| entry.name.strip_prefix("__cap_") == Some(name))
96}
97
98pub fn legacy_privileged_wire_entry(
101 name: &str,
102) -> Option<&'static harn_builtin_registry::BuiltinManifestEntry> {
103 harn_builtin_registry::installed_manifest()
104 .into_iter()
105 .find(|entry| {
106 matches!(entry.contract.exposure, BuiltinExposure::PrivilegedWire)
107 && entry.name.strip_prefix("__") == Some(name)
108 })
109}
110
111pub fn legacy_ambient_runtime_name(name: &str) -> Option<&'static str> {
119 if let Some(target) = crate::legacy_builtin_alias_target(name) {
120 return Some(target);
121 }
122 legacy_privileged_wire_entry(name).map(|entry| entry.name)
123}
124
125fn ambient_harness_method_entries(
126) -> impl Iterator<Item = &'static harn_builtin_registry::BuiltinManifestEntry> {
127 harn_builtin_registry::installed_manifest()
128 .into_iter()
129 .chain(harn_capability_contracts::manifest().iter().copied())
130}
131
132pub fn lookup_capability_method(
134 capability: CapabilityId,
135 method: &str,
136) -> Option<&'static BuiltinSignature> {
137 capability_method_entry(capability.field_name(), method).map(|entry| entry.signature)
138}
139
140pub fn capability_method_entry(
144 field: &str,
145 method: &str,
146) -> Option<&'static harn_builtin_registry::BuiltinManifestEntry> {
147 let capability = CapabilityId::from_field_name(field)?;
148 harn_builtin_registry::installed_manifest()
149 .iter()
150 .copied()
151 .find(|entry| {
152 matches!(
153 entry.contract.exposure,
154 BuiltinExposure::HarnessMethod {
155 capability: candidate,
156 method: candidate_method,
157 } if candidate == capability && candidate_method == method
158 )
159 })
160 .or_else(|| harn_capability_contracts::capability_method_entry(field, method))
161}
162
163pub fn is_builtin(name: &str) -> bool {
165 lookup(name).is_some()
166 || (crate::legacy_ambient_capabilities_enabled()
167 && crate::is_registered_legacy_hostlib_name(name))
168}
169
170pub fn is_builtin_with_privileged_wire(name: &str, allow_privileged_wire: bool) -> bool {
171 lookup_with_privileged_wire(name, allow_privileged_wire).is_some()
172 || (crate::legacy_ambient_capabilities_enabled()
173 && crate::is_registered_legacy_hostlib_name(name))
174}
175
176pub fn iter_builtin_names() -> impl Iterator<Item = &'static str> {
180 let installed: Vec<_> = harn_builtin_registry::installed_manifest()
181 .into_iter()
182 .filter(|entry| {
183 matches!(
184 entry.contract.exposure,
185 BuiltinExposure::PureGlobal | BuiltinExposure::CapabilityFunction { .. }
186 )
187 })
188 .collect();
189 let installed_names: std::collections::HashSet<&'static str> =
190 harn_builtin_registry::installed_manifest()
191 .into_iter()
192 .map(|entry| entry.name)
193 .collect();
194 installed.into_iter().map(|entry| entry.name).chain(
195 signatures::groups()
196 .into_iter()
197 .flat_map(|g| g.iter())
198 .filter(move |s| !installed_names.contains(s.name))
199 .map(|s| s.name),
200 )
201}
202
203pub fn static_signature_names() -> impl Iterator<Item = &'static str> {
212 signatures::groups()
213 .into_iter()
214 .flat_map(|g| g.iter())
215 .map(|s| s.name)
216}
217
218pub fn iter_builtin_metadata() -> impl Iterator<Item = BuiltinMetadata> {
223 let installed: Vec<_> = harn_builtin_registry::installed_manifest()
224 .into_iter()
225 .filter(|entry| {
226 matches!(
227 entry.contract.exposure,
228 BuiltinExposure::PureGlobal | BuiltinExposure::CapabilityFunction { .. }
229 )
230 })
231 .collect();
232 let installed_names: std::collections::HashSet<&'static str> =
233 harn_builtin_registry::installed_manifest()
234 .into_iter()
235 .map(|entry| entry.name)
236 .collect();
237 installed
238 .into_iter()
239 .map(|entry| BuiltinMetadata {
240 name: entry.name,
241 return_types: builtin_return_type_names(entry.signature),
242 })
243 .chain(
244 signatures::groups()
245 .into_iter()
246 .flat_map(|g| g.iter())
247 .filter(move |s| !installed_names.contains(s.name))
248 .map(|sig| BuiltinMetadata {
249 name: sig.name,
250 return_types: builtin_return_type_names(sig),
251 }),
252 )
253}
254
255pub fn builtin_return_type(name: &str) -> Option<TypeExpr> {
259 let sig = lookup(name)?;
260 if sig.returns.is_any() {
261 return None;
262 }
263 Some(sig.returns.to_type_expr())
264}
265
266pub fn is_untyped_boundary_source(name: &str) -> bool {
273 matches!(
274 name,
275 "json_parse"
276 | "json_extract"
277 | "yaml_parse"
278 | "toml_parse"
279 | "llm_call"
280 | "llm_call_safe"
281 | "llm_completion"
282 | "http_get"
283 | "http_post"
284 | "http_put"
285 | "http_patch"
286 | "http_delete"
287 | "http_download"
288 | "http_request"
289 | "http_session_request"
290 | "http_stream_info"
291 | "sse_receive"
292 | "sse_server_mock_receive"
293 | "sse_server_response"
294 | "sse_server_status"
295 | "websocket_accept"
296 | "websocket_receive"
297 | "host_call"
298 | "connector_call"
299 | "host_tool_call"
300 )
301}
302
303fn builtin_return_type_names(sig: &BuiltinSignature) -> &'static [&'static str] {
309 match &sig.returns {
310 Ty::Named(name) => match *name {
311 "bool" => &["bool"],
312 "bytes" => &["bytes"],
313 "dict" => &["dict"],
314 "float" => &["float"],
315 "int" => &["int"],
316 "list" => &["list"],
317 "nil" => &["nil"],
318 "string" => &["string"],
319 _ => &[],
320 },
321 Ty::Union(members) => match *members {
322 [Ty::Named("string"), Ty::Named("nil")] => &["string", "nil"],
323 [Ty::Named("nil"), Ty::Named("string")] => &["string", "nil"],
324 [Ty::Named("int"), Ty::Named("nil")] => &["int", "nil"],
325 [Ty::Named("nil"), Ty::Named("int")] => &["int", "nil"],
326 [Ty::Named("dict"), Ty::Named("nil")] => &["dict", "nil"],
327 [Ty::Named("nil"), Ty::Named("dict")] => &["dict", "nil"],
328 [Ty::Named("bytes"), Ty::Named("nil")] => &["bytes", "nil"],
329 [Ty::Named("nil"), Ty::Named("bytes")] => &["bytes", "nil"],
330 _ => &[],
331 },
332 Ty::Never => &["never"],
333 _ => &[],
334 }
335}