use crate::ast::TypeExpr;
use harn_builtin_meta::{BuiltinExposure, CapabilityId};
use super::signatures;
use super::{BuiltinMetadata, BuiltinSignature, Ty, TyExt};
pub fn lookup(name: &str) -> Option<&'static BuiltinSignature> {
for entry in harn_builtin_registry::installed_manifest() {
if entry.name == name {
return matches!(
entry.contract.exposure,
BuiltinExposure::PureGlobal | BuiltinExposure::CapabilityFunction { .. }
)
.then_some(entry.signature);
}
}
for group in signatures::groups() {
for sig in group {
if sig.name == name {
return Some(sig);
}
}
}
None
}
pub fn lookup_capability_method(
capability: CapabilityId,
method: &str,
) -> Option<&'static BuiltinSignature> {
capability_method_entry(capability.field_name(), method).map(|entry| entry.signature)
}
pub fn capability_method_entry(
field: &str,
method: &str,
) -> Option<&'static harn_builtin_registry::BuiltinManifestEntry> {
let capability = CapabilityId::from_field_name(field)?;
harn_builtin_registry::installed_manifest()
.iter()
.copied()
.find(|entry| {
matches!(
entry.contract.exposure,
BuiltinExposure::HarnessMethod {
capability: candidate,
method: candidate_method,
} if candidate == capability && candidate_method == method
)
})
.or_else(|| harn_capability_contracts::capability_method_entry(field, method))
}
pub fn is_builtin(name: &str) -> bool {
lookup(name).is_some()
}
pub fn iter_builtin_names() -> impl Iterator<Item = &'static str> {
let installed: Vec<_> = harn_builtin_registry::installed_manifest()
.into_iter()
.filter(|entry| {
matches!(
entry.contract.exposure,
BuiltinExposure::PureGlobal | BuiltinExposure::CapabilityFunction { .. }
)
})
.collect();
let installed_names: std::collections::HashSet<&'static str> =
harn_builtin_registry::installed_manifest()
.into_iter()
.map(|entry| entry.name)
.collect();
installed.into_iter().map(|entry| entry.name).chain(
signatures::groups()
.into_iter()
.flat_map(|g| g.iter())
.filter(move |s| !installed_names.contains(s.name))
.map(|s| s.name),
)
}
pub fn static_signature_names() -> impl Iterator<Item = &'static str> {
signatures::groups()
.into_iter()
.flat_map(|g| g.iter())
.map(|s| s.name)
}
pub fn iter_builtin_metadata() -> impl Iterator<Item = BuiltinMetadata> {
let installed: Vec<_> = harn_builtin_registry::installed_manifest()
.into_iter()
.filter(|entry| {
matches!(
entry.contract.exposure,
BuiltinExposure::PureGlobal | BuiltinExposure::CapabilityFunction { .. }
)
})
.collect();
let installed_names: std::collections::HashSet<&'static str> =
harn_builtin_registry::installed_manifest()
.into_iter()
.map(|entry| entry.name)
.collect();
installed
.into_iter()
.map(|entry| BuiltinMetadata {
name: entry.name,
return_types: builtin_return_type_names(entry.signature),
})
.chain(
signatures::groups()
.into_iter()
.flat_map(|g| g.iter())
.filter(move |s| !installed_names.contains(s.name))
.map(|sig| BuiltinMetadata {
name: sig.name,
return_types: builtin_return_type_names(sig),
}),
)
}
pub fn builtin_return_type(name: &str) -> Option<TypeExpr> {
let sig = lookup(name)?;
if sig.returns.is_any() {
return None;
}
Some(sig.returns.to_type_expr())
}
pub fn is_untyped_boundary_source(name: &str) -> bool {
matches!(
name,
"json_parse"
| "json_extract"
| "yaml_parse"
| "toml_parse"
| "llm_call"
| "llm_call_safe"
| "llm_completion"
| "http_get"
| "http_post"
| "http_put"
| "http_patch"
| "http_delete"
| "http_download"
| "http_request"
| "http_session_request"
| "http_stream_info"
| "sse_receive"
| "sse_server_mock_receive"
| "sse_server_response"
| "sse_server_status"
| "websocket_accept"
| "websocket_receive"
| "host_call"
| "connector_call"
| "host_tool_call"
)
}
fn builtin_return_type_names(sig: &BuiltinSignature) -> &'static [&'static str] {
match &sig.returns {
Ty::Named(name) => match *name {
"bool" => &["bool"],
"bytes" => &["bytes"],
"dict" => &["dict"],
"float" => &["float"],
"int" => &["int"],
"list" => &["list"],
"nil" => &["nil"],
"string" => &["string"],
_ => &[],
},
Ty::Union(members) => match *members {
[Ty::Named("string"), Ty::Named("nil")] => &["string", "nil"],
[Ty::Named("nil"), Ty::Named("string")] => &["string", "nil"],
[Ty::Named("int"), Ty::Named("nil")] => &["int", "nil"],
[Ty::Named("nil"), Ty::Named("int")] => &["int", "nil"],
[Ty::Named("dict"), Ty::Named("nil")] => &["dict", "nil"],
[Ty::Named("nil"), Ty::Named("dict")] => &["dict", "nil"],
[Ty::Named("bytes"), Ty::Named("nil")] => &["bytes", "nil"],
[Ty::Named("nil"), Ty::Named("bytes")] => &["bytes", "nil"],
_ => &[],
},
Ty::Never => &["never"],
_ => &[],
}
}