cxc/unit/
functions.rs

1use crate::{
2    errors::{CResult, FErr, TErr, TResult},
3    FuncType, Type, TypeRelation, typ::{can_transform::{transformation_steps_dist, Transformation}, ABI},
4};
5
6pub type DeriverFunc = fn(&CompData, Type) -> Option<FuncCode>;
7pub type TypeLevelFunc = fn(Vec<Type>, &CompData) -> Type;
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
10pub struct DeriverInfo {
11    pub func_name: VarName,
12    pub is_static: bool,
13}
14
15impl<'a> TryFrom<FuncCodeQuery<'a>> for DeriverInfo {
16    type Error = ();
17
18    fn try_from(info: FuncCodeQuery) -> Result<Self, ()> {
19        let is_static = match info.relation {
20            TypeRelation::MethodOf(_) => false,
21            TypeRelation::Static(_) => true,
22            TypeRelation::Unrelated => return Err(()),
23        };
24
25        Ok(DeriverInfo {
26            func_name: info.name.clone(),
27            is_static,
28        })
29    }
30}
31
32impl CompData {
33    pub fn new() -> Self {
34        let mut out = Self::default();
35
36        out.insert_intrinsic(FuncCode {
37            name: VarName::from("intrinsic_alloc"),
38            args: vec![VarDecl {
39                name: VarName::None,
40                type_spec: TypeSpec::Int(64),
41            }],
42            ret_type: TypeSpec::UInt(8).get_ref(),
43            generic_count: 0,
44            is_external: true,
45            ..FuncCode::empty()
46        });
47
48        out.insert_intrinsic(FuncCode {
49            name: VarName::from("free"),
50            ret_type: TypeSpec::Void,
51            args: vec![VarDecl {
52                name: VarName::None,
53                type_spec: TypeSpec::GenParam(0).get_ref(),
54            }],
55            generic_count: 1,
56            is_external: true,
57            ..FuncCode::empty()
58        });
59
60        out.insert_intrinsic(FuncCode {
61            name: VarName::from("memmove"),
62            ret_type: TypeSpec::Void,
63            args: vec![
64                VarDecl {
65                    name: VarName::None,
66                    type_spec: TypeSpec::GenParam(0).get_ref(),
67                },
68                VarDecl {
69                    name: VarName::None,
70                    type_spec: TypeSpec::GenParam(0).get_ref(),
71                },
72                VarDecl {
73                    name: VarName::None,
74                    type_spec: TypeSpec::UInt(64),
75                },
76            ],
77            generic_count: 1,
78            is_external: true,
79            ..FuncCode::empty()
80        });
81
82        out.insert_intrinsic(FuncCode {
83            name: VarName::from("memcpy"),
84            ret_type: TypeSpec::Void,
85            args: vec![
86                VarDecl {
87                    name: VarName::None,
88                    type_spec: TypeSpec::GenParam(0).get_ref(),
89                },
90                VarDecl {
91                    name: VarName::None,
92                    type_spec: TypeSpec::GenParam(0).get_ref(),
93                },
94                VarDecl {
95                    name: VarName::None,
96                    type_spec: TypeSpec::UInt(64),
97                },
98            ],
99            generic_count: 1,
100            is_external: true,
101            ..FuncCode::empty()
102        });
103
104        out.insert_intrinsic(FuncCode {
105            name: VarName::from("size_of"),
106            ret_type: TypeSpec::UInt(64),
107            args: Vec::new(),
108            generic_count: 1,
109            is_external: true,
110            ..FuncCode::empty()
111        });
112
113        out.insert_intrinsic(FuncCode {
114            name: VarName::from("alignment_of"),
115            ret_type: TypeSpec::UInt(64),
116            args: Vec::new(),
117            generic_count: 1,
118            is_external: true,
119            ..FuncCode::empty()
120        });
121
122        out.insert_intrinsic(FuncCode {
123            name: VarName::from("cast"),
124            args: vec![VarDecl {
125                name: VarName::None,
126                type_spec: "T".into(),
127            }],
128            ret_type: "U".into(),
129            generic_count: 2,
130            is_external: true,
131            ..FuncCode::empty()
132        });
133
134        out.insert_intrinsic(FuncCode {
135            name: VarName::from("typeobj"),
136            args: vec![],
137            ret_type: "Type".into(),
138            generic_count: 1,
139            is_external: true,
140            ..FuncCode::empty()
141        });
142
143        out.typedefs.insert("Type".into(), TypeSpec::Int(64));
144
145        out
146    }
147
148    pub fn insert_code(&mut self, code: FuncCode, backend: Option<&mut Backend>) -> FuncCodeId {
149        for (code_id, old_code) in &self.func_code {
150            if old_code.name == code.name && old_code.relation == code.relation {
151                self.func_code.remove(code_id);
152
153                if let Some(backend) = backend &&
154                    let Some(realizations) = self.realizations.remove(code_id) {
155                    for realization in realizations {
156                        backend.mark_to_recompile(realization);
157                    }
158                }
159
160                break;
161            }
162        }
163
164        self.func_code.insert(code)
165    }
166
167    fn insert_intrinsic(&mut self, code: FuncCode) {
168        let decl_info = self.insert_code(code, None);
169        self.intrinsics.insert(decl_info);
170    }
171
172    pub fn name_is_intrinsic(&self, name: &VarName) -> bool {
173        self.intrinsics.iter().any(|id| {
174            &self.func_code[*id].name == name
175        })
176    }
177
178    pub fn query_for_code_with_transformation(
179        &self, 
180        query: FuncCodeQuery
181    ) -> Option<(FuncCodeId, Option<Transformation>)> {
182        if let Some(looking_for_relation) = query.relation.inner_type() {
183            let mut closest_function: Option<(FuncCodeId, Option<Transformation>)> = None;
184            let mut closest_function_dist = u32::MAX;
185
186            for (id, code) in &self.func_code {
187                if &code.name != query.name {
188                    continue;
189                }
190
191                let Some(looking_at_relation) = code.relation.inner_type() else { continue };
192
193                if let Some(result) = 
194                    looking_for_relation.can_transform_to(looking_at_relation.clone()) {
195                    let result_dist = transformation_steps_dist(&result.steps);
196                    
197                    if closest_function_dist > result_dist {
198                        closest_function_dist = result_dist;
199                        closest_function = Some((id, Some(result)));
200                    }
201                }
202            }
203
204            return closest_function;
205        } else {
206            for (id, code) in &self.func_code {
207                if &code.name != query.name {
208                    continue;
209                }
210
211                return Some((id, None));
212            }
213
214            None
215        }
216    }
217
218    pub fn query_for_code(
219        &self, 
220        info: FuncCodeQuery,
221    ) -> Option<FuncCodeId> {
222        self.query_for_code_with_transformation(info).map(|f| f.0)        
223    }
224
225    pub fn query_for_id(&self, query: &FuncQuery) -> Option<FuncId> {
226        if let Some((code_id, transformation)) = 
227            self.query_for_code_with_transformation(query.code_query()) &&
228            let Some(realizations) = self.realizations.get(code_id) {
229
230            let generics = transformation.map(|t| t.generics).unwrap_or_default();
231
232            for realization in realizations {
233                let realization_info = &self.processed[*realization];
234                if realization_info.generics == generics {
235                    return Some(*realization);
236                }
237            }
238        }
239
240        for (func_id, info) in &self.processed {
241            if info.name == query.name && 
242                info.relation == query.relation && 
243                info.generics == query.generics {
244                return Some(func_id);
245            }
246        }
247
248        return None;
249    }
250
251
252    pub fn get_func_type(&self, query: &FuncQuery) -> CResult<FuncType> {
253        if let Some(func_id) = self.query_for_id(query) {
254            return Ok(self.processed[func_id].typ.clone());
255        }
256
257        let (code, _) = self.get_code(query.code_query())?;
258
259        let ret_type = self.get_spec(&code.ret_type, &query.generics)?;
260
261        let arg_types = code
262            .args
263            .iter()
264            .map(|arg| self.get_spec(&arg.type_spec, &query.generics))
265            .collect::<TResult<Vec<_>>>()?;
266
267        Ok(FuncType {
268            ret: ret_type,
269            args: arg_types,
270            abi: ABI::C,
271        })
272    }
273
274    pub fn get_derived_code(&self, info: FuncCodeQuery) -> Option<FuncCode> {
275        if let Ok(deriver_info) = DeriverInfo::try_from(info.clone()) && 
276            info.relation.inner_type()?.is_known() {
277            let deriver = self.derivers.get(&deriver_info)?;
278            deriver(self, info.relation.inner_type().cloned()?)
279        } else {
280            None
281        }
282    }
283
284    // TODO: completely redo the way that derivations are handled, because re-running
285    // the deriver every time seems like a bad way to do things. In rust, they know what
286    // the type signature is going to be because everything is done through traits.
287    // Maybe alongside each deriver function there should be a shorter function that
288    // just produces the type.
289    //
290    // also, just based on some debug statistics, this function is called way too much.
291    pub fn get_code(&self, query: FuncCodeQuery) -> CResult<(Cow<FuncCode>, FuncQuery)> {
292        if let Some((decl_info, trans)) = self.query_for_code_with_transformation(query) {
293            return Ok((
294                Cow::Borrowed(&self.func_code[decl_info]), 
295                FuncQuery {
296                    name: query.name.clone(),
297                    relation: query.relation.clone(),
298                    generics: trans.map(|t| t.generics).unwrap_or_default(),
299                },
300            ));
301        };
302
303        self.get_derived_code(query)
304            .map(|code| (
305                    Cow::Owned(code), 
306                    FuncQuery {
307                        name: query.name.clone(),
308                        relation: query.relation.clone(),
309                        generics: Vec::new(),
310                    },
311            ))
312            .ok_or(FErr::NotFound(query.name.clone(), query.relation.clone()).into())
313    }
314
315    pub fn add_method_deriver(&mut self, func_name: VarName, func: DeriverFunc) {
316        self.derivers.insert(
317            DeriverInfo {
318                func_name,
319                is_static: false,
320            },
321            func,
322        );
323    }
324
325    pub fn add_static_deriver(&mut self, func_name: VarName, func: DeriverFunc) {
326        self.derivers.insert(
327            DeriverInfo {
328                func_name,
329                is_static: true,
330            },
331            func,
332        );
333    }
334
335    pub fn add_type_spec(&mut self, name: TypeName, a: TypeSpec) {
336        self.typedefs.insert(name, a);
337    }
338
339    pub fn contains(&self, key: &TypeName) -> bool { self.typedefs.contains_key(key) }
340
341    pub fn get_by_name(&self, name: &TypeName) -> TResult<Type> {
342        let alias = self.get_typedef_of(name)?;
343        let realized_type = self.get_spec(alias, &())?;
344        Ok(realized_type.with_name(name.clone()).with_generics(&Vec::new()))
345    }
346
347    pub fn get_typedef_of(&self, name: &TypeName) -> TResult<&TypeSpec> {
348        self.typedefs.get(name).ok_or(TErr::Unknown(name.clone()))
349    }
350}
351
352use std::{hash::Hash, borrow::Cow};
353
354use super::*;
355
356#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, XcReflectMac)]
357#[repr(C)]
358pub struct FuncQuery {
359    pub name: VarName,
360    pub relation: TypeRelation,
361    pub generics: Vec<Type>,
362}
363
364impl From<&str> for FuncQuery {
365    fn from(name: &str) -> FuncQuery {
366        FuncQuery {
367            name: name.into(),
368            ..Default::default()
369        }
370    }
371}
372
373impl From<VarName> for FuncQuery {
374    fn from(name: VarName) -> FuncQuery {
375        FuncQuery {
376            name,
377            ..Default::default()
378        }
379    }
380}
381
382impl FuncQuery {
383    pub fn code_query<'a>(&'a self) -> FuncCodeQuery<'a> {
384        FuncCodeQuery {
385            name: &self.name,
386            relation: &self.relation,
387        }
388    }
389}
390
391#[derive(Copy, Debug, Clone, PartialEq, Eq, Hash)]
392#[repr(C)]
393pub struct FuncCodeQuery<'a> {
394    pub name: &'a VarName,
395    pub relation: &'a TypeRelation,
396}
397
398impl<'a> FuncCodeQuery<'a> {
399    pub fn to_owned_fcq(&self) -> OwnedFuncCodeQuery {
400        OwnedFuncCodeQuery {
401            name: self.name.clone(),
402            relation: self.relation.clone(),
403        }
404    }
405}
406
407#[derive(Debug, Clone, PartialEq, Eq, Hash)]
408#[repr(C)]
409// TODO: rename this to code query?? idk why it's called function code query. 
410// where else would code be. where else did i think code was.
411pub struct OwnedFuncCodeQuery {
412    pub name: VarName,
413    pub relation: TypeRelation,
414}
415
416impl OwnedFuncCodeQuery {
417    pub fn to_borrowed_fcq<'a>(&'a self) -> FuncCodeQuery<'a> {
418        FuncCodeQuery {
419            name: &self.name,
420            relation: &self.relation,
421        }
422    }
423}