1pub use crate::catalog::functions::BUILTIN_NAMES;
3use crate::{Type, Value};
4use std::collections::BTreeMap;
5
6#[derive(Clone)]
9pub struct NativeFunction {
10 pub name: String,
12 pub parameters: Vec<Type>,
14 pub returns: Type,
16 pub call: fn(&[Value]) -> Result<Value, String>,
18}
19#[derive(Clone, Default)]
22pub struct NativeRegistry {
23 pub(crate) functions: BTreeMap<String, NativeFunction>,
24}
25impl NativeRegistry {
26 pub fn register(&mut self, function: NativeFunction) -> Result<(), String> {
28 fn concrete(ty: &Type) -> bool {
29 match ty {
30 Type::Applied { arguments, .. } => arguments.iter().all(concrete),
31 Type::List(inner) | Type::Tensor(inner) | Type::ComponentReference(inner) => {
32 concrete(inner)
33 }
34 Type::Function {
35 parameters,
36 returns,
37 } => parameters.iter().all(concrete) && concrete(returns),
38 Type::Named(name) => name != "Any" && name != "List",
39 }
40 }
41 if !function.parameters.iter().all(concrete) || !concrete(&function.returns) {
42 return Err(
43 "native signatures require concrete types; use List[T] instead of List or Any"
44 .into(),
45 );
46 }
47 if self.functions.contains_key(&function.name) || is_builtin(&function.name) {
48 return Err(format!(
49 "native function `{}` is already defined or reserved",
50 function.name
51 ));
52 }
53 self.functions.insert(function.name.clone(), function);
54 Ok(())
55 }
56 pub fn functions(&self) -> impl Iterator<Item = &NativeFunction> {
58 self.functions.values()
59 }
60 pub(crate) fn signatures(&self) -> BTreeMap<String, (Vec<Type>, Type)> {
61 self.functions
62 .values()
63 .map(|function| {
64 (
65 function.name.clone(),
66 (function.parameters.clone(), function.returns.clone()),
67 )
68 })
69 .collect()
70 }
71}
72pub(crate) fn is_builtin(name: &str) -> bool {
73 BUILTIN_NAMES.contains(&name) && !crate::methods::is_owned_global(name)
74}
75
76pub(crate) fn monomorphic_signature(name: &str) -> Option<Type> {
79 if crate::methods::is_owned_global(name) {
80 return None;
81 }
82 crate::catalog::functions::monomorphic_signature(name)
83}
84
85pub(crate) fn valid_builtin_specialization(
86 name: &str,
87 signature: &Type,
88 is_class: impl Fn(&str) -> bool,
89) -> bool {
90 if crate::methods::is_owned_global(name) {
91 return false;
92 }
93 if crate::data::valid_data_signature(name, signature) {
94 return true;
95 }
96 if let Some(known) = monomorphic_signature(name) {
97 return known == *signature;
98 }
99 let Type::Function {
100 parameters,
101 returns,
102 } = signature
103 else {
104 return false;
105 };
106 let unit = Type::named("Unit");
107 let number = Type::named("f64");
108 let entity = Type::named("Entity");
109 match (name, parameters.as_slice()) {
110 ("print", [_]) => **returns == unit,
111 ("len", [Type::List(_)]) => **returns == number,
112 ("len", [Type::Named(name)]) => name == "Str" && **returns == number,
113 ("append", [list @ Type::List(inner), element]) => {
114 inner.as_ref() == element && returns.as_ref() == list
115 }
116 ("range", [one]) => {
117 *one == number && **returns == crate::data::result_type(Type::List(Box::new(number)))
118 }
119 ("range", [one, two]) => {
120 *one == number
121 && *two == number
122 && **returns == crate::data::result_type(Type::List(Box::new(number)))
123 }
124 ("spawn", [Type::Named(class)]) => is_class(class) && **returns == entity,
125 ("add" | "set", [first, Type::Named(class)]) => {
126 *first == entity && is_class(class) && **returns == unit
127 }
128 _ => false,
129 }
130}