cortex_lang/preprocessing/
preprocessor.rs

1use std::{collections::{HashMap, HashSet, VecDeque}, error::Error, rc::Rc};
2
3use crate::parsing::{ast::{expression::{BinaryOperator, IdentExpression, OptionalIdentifier, PConditionBody, PExpression, Parameter, PathIdent, UnaryOperator}, statement::{AssignmentName, DeclarationName, PStatement}, top_level::{BasicBody, Body, Bundle, Extension, FunctionSignature, MemberFunction, PFunction, Struct, ThisArg, TopLevel}, r#type::{forwarded_type_args, CortexType, TupleType, TypeError}}, codegen::r#trait::SimpleCodeGen};
4
5use super::{ast::{expression::RExpression, function::{FunctionDict, RBody, RFunction, RInterpretedBody}, function_address::FunctionAddress, statement::{RConditionBody, RStatement}}, error::PreprocessingError, module::{Module, ModuleError, TypeDefinition}, program::Program, type_checking_env::TypeCheckingEnvironment, type_env::TypeEnvironment};
6
7type CortexError = Box<dyn Error>;
8pub type CheckResult<T> = Result<(T, CortexType), CortexError>;
9
10pub struct CortexPreprocessor {
11    current_env: Option<Box<TypeCheckingEnvironment>>,
12    current_context: PathIdent,
13    current_type_env: Option<Box<TypeEnvironment>>,
14    function_dict: FunctionDict,
15    function_signature_map: HashMap<FunctionAddress, FunctionSignature>,
16    type_map: HashMap<PathIdent, TypeDefinition>,
17    loop_depth: u32,
18    temp_num: usize,
19}
20
21impl CortexPreprocessor {
22    pub fn new() -> Result<Self, CortexError> {
23        let mut this = CortexPreprocessor {
24            current_env: Some(Box::new(TypeCheckingEnvironment::base())),
25            current_context: PathIdent::empty(),
26            current_type_env: Some(Box::new(TypeEnvironment::base())),
27            function_dict: FunctionDict::new(),
28            function_signature_map: HashMap::new(),
29            type_map: HashMap::new(),
30            loop_depth: 0,
31            temp_num: 0,
32        };
33
34        macro_rules! add_core_type {
35            ($name:literal) => {
36                this.type_map.insert(PathIdent::simple(String::from($name)), TypeDefinition { fields: HashMap::new(), type_param_names: Vec::new(), is_heap_allocated: false });
37            }
38        }
39
40        add_core_type!("number");
41        add_core_type!("bool");
42        add_core_type!("string");
43        add_core_type!("void");
44        add_core_type!("none");
45
46        let mut global_module = Module::new();
47        Self::add_list_funcs(&mut global_module)?;
48        Self::add_string_funcs(&mut global_module)?;
49        Self::add_range_funcs(&mut global_module)?;
50
51        this.register_module(&PathIdent::empty(), global_module)?;
52
53        Ok(this)
54    }
55
56    pub(crate) fn get_function(&self, id: usize) -> Option<&Rc<RFunction>> {
57        self.function_dict.get(id)
58    }
59
60    pub(crate) fn determine_type(&mut self, expr: PExpression) -> Result<CortexType, CortexError> {
61        let (_, typ) = self.check_exp(expr)?;
62        Ok(typ)
63    }
64
65    pub fn run_top_level(&mut self, top_level: TopLevel) -> Result<(), CortexError> {
66        match top_level {
67            TopLevel::Import { name: _, is_string_import: _ } => {
68                todo!("Imports are currently not supported!")
69            },
70            TopLevel::Module { name, contents } => {
71                let module = Self::construct_module(contents)?;
72                self.register_module(&PathIdent::simple(name), module)?;
73                Ok(())
74            },
75            TopLevel::Function(function) => {
76                match &function.name {
77                    OptionalIdentifier::Ident(func_name) => {
78                        let addr = FunctionAddress {
79                            own_module_path: PathIdent::simple(func_name.clone()),
80                            target: None,
81                        };
82                        self.add_signature(&addr, &function)?;
83                        self.add_function(addr, function)?;
84                        Ok(())
85                    },
86                    OptionalIdentifier::Ignore => Ok(()),
87                }
88            },
89            TopLevel::Struct(struc) => {
90                let mut funcs = Vec::new();
91                self.add_struct(PathIdent::empty(), struc, &mut funcs)?;
92                for (addr, f) in &funcs {
93                    self.add_signature(addr, &f)?;
94                }
95                for (addr, f) in funcs {
96                    self.add_function(addr, f)?;
97                }
98                Ok(())
99            },
100            TopLevel::Bundle(bundle) => {
101                let mut funcs = Vec::new();
102                self.add_bundle(PathIdent::empty(), bundle, &mut funcs)?;
103                for (addr, f) in &funcs {
104                    self.add_signature(addr, &f)?;
105                }
106                for (addr, f) in funcs {
107                    self.add_function(addr, f)?;
108                }
109                Ok(())
110            },
111            TopLevel::Extension(extension) => {
112                let mut funcs = Vec::new();
113                self.add_extension(PathIdent::empty(), extension, &mut funcs)?;
114                for (addr, f) in &funcs {
115                    self.add_signature(addr, &f)?;
116                }
117                for (addr, f) in funcs {
118                    self.add_function(addr, f)?;
119                }
120                Ok(())
121            }
122        }
123    }
124
125    pub fn register_module(&mut self, path: &PathIdent, mut module: Module) -> Result<(), CortexError> {
126        for (path_end, m) in module.children_iter() {
127            let this_path = PathIdent::continued(path.clone(), path_end);
128            self.register_module(&this_path, m)?;
129        }
130
131        let mut functions = module
132            .take_functions()?
133            .into_iter()
134            .map(|f| {
135                match &f.name {
136                    OptionalIdentifier::Ident(func_name) => {
137                        let addr = FunctionAddress {
138                            own_module_path: PathIdent::continued(path.clone(), func_name.clone()),
139                            target: None,
140                        };
141                        Some((addr, f))
142                    },
143                    OptionalIdentifier::Ignore => None,
144                }
145            })
146            .filter_map(|x| x)
147            .collect::<Vec<(FunctionAddress, PFunction)>>();
148        let structs = module.take_structs()?;
149        let bundles = module.take_bundles()?;
150        let extensions = module.take_extensions()?;
151
152        let context_to_return_to = std::mem::replace(&mut self.current_context, path.clone());
153
154        for item in structs {
155            self.add_struct(path.clone(), item, &mut functions)?;
156        }
157
158        for item in bundles {
159            self.add_bundle(path.clone(), item, &mut functions)?;
160        }
161
162        for item in extensions {
163            self.add_extension(path.clone(), item, &mut functions)?;
164        }
165
166        for (addr, f) in &functions {
167            self.add_signature(addr, &f)?;
168        }
169
170        for (addr, f) in functions {
171            self.add_function(addr, f)?;
172        }
173
174        self.current_context = context_to_return_to;
175
176        Ok(())
177    }
178
179    fn add_signature(&mut self, addr: &FunctionAddress, f: &PFunction) -> Result<(), CortexError> {
180        let sig = f.signature();
181        if self.function_signature_map.contains_key(&addr) {
182            return Err(Box::new(ModuleError::FunctionAlreadyExists(addr.own_module_path.codegen(0))));
183        }
184        let mut seen_type_param_names = HashSet::new();
185        for t in &sig.type_param_names {
186            if seen_type_param_names.contains(t) {
187                return Err(Box::new(ModuleError::DuplicateTypeArgumentName(t.clone())));
188            }
189            seen_type_param_names.insert(t);
190        }
191        self.function_signature_map.insert(addr.clone(), sig);
192        Ok(())
193    }
194    fn add_function(&mut self, addr: FunctionAddress, f: PFunction) -> Result<(), CortexError> {
195        let name = f.name().clone();
196        let processed = self.preprocess_function(f)?;
197        match name {
198            OptionalIdentifier::Ident(_) => {
199                self.function_dict.add_function(addr, processed);
200            },
201            OptionalIdentifier::Ignore => {},
202        }
203        Ok(())
204    }
205    
206    fn add_struct(&mut self, n: PathIdent, item: Struct, funcs_to_add: &mut Vec<(FunctionAddress, PFunction)>) -> Result<(), CortexError> {
207        match &item.name {
208            OptionalIdentifier::Ident(item_name) => {
209                let full_path = PathIdent::continued(n.clone(), item_name.clone());
210                if self.has_type(&full_path) {
211                    Err(Box::new(ModuleError::TypeAlreadyExists(full_path.codegen(0))))
212                } else {
213                    let has_loop = self.search_struct_for_loops(&item)?;
214                    if has_loop {
215                        return Err(Box::new(PreprocessingError::StructContainsCircularFields(full_path.codegen(0))));
216                    }
217                    
218                    Self::handle_member_functions(item.functions, n, &item.type_param_names, item_name, funcs_to_add)?;
219
220                    let mut seen_type_param_names = HashSet::new();
221                    for t in &item.type_param_names {
222                        if seen_type_param_names.contains(t) {
223                            return Err(Box::new(ModuleError::DuplicateTypeArgumentName(t.clone())));
224                        }
225                        seen_type_param_names.insert(t);
226                    }
227
228                    self.type_map.insert(full_path, TypeDefinition {
229                        fields: item.fields,
230                        is_heap_allocated: false,
231                        type_param_names: item.type_param_names,
232                    });
233                    Ok(())
234                }
235            },
236            OptionalIdentifier::Ignore => Ok(()),
237        }
238    }
239    fn add_bundle(&mut self, n: PathIdent, item: Bundle, funcs_to_add: &mut Vec<(FunctionAddress, PFunction)>) -> Result<(), CortexError> {
240        match &item.name {
241            OptionalIdentifier::Ident(item_name) => {
242                let full_path = PathIdent::continued(n.clone(), item_name.clone());
243                if self.has_type(&full_path) {
244                    Err(Box::new(ModuleError::TypeAlreadyExists(full_path.codegen(0))))
245                } else {
246                    Self::handle_member_functions(item.functions, n, &item.type_param_names, item_name, funcs_to_add)?;
247
248                    let mut seen_type_param_names = HashSet::new();
249                    for t in &item.type_param_names {
250                        if seen_type_param_names.contains(t) {
251                            return Err(Box::new(ModuleError::DuplicateTypeArgumentName(t.clone())));
252                        }
253                        seen_type_param_names.insert(t);
254                    }
255
256                    self.type_map.insert(full_path, TypeDefinition {
257                        fields: item.fields,
258                        is_heap_allocated: true,
259                        type_param_names: item.type_param_names,
260                    });
261                    Ok(())
262                }
263            },
264            OptionalIdentifier::Ignore => Ok(()),
265        }
266    }
267    fn handle_member_functions(functions: Vec<MemberFunction>, n: PathIdent, item_type_param_names: &Vec<String>, item_name: &String, funcs_to_add: &mut Vec<(FunctionAddress, PFunction)>) -> Result<(), CortexError> {
268        for func in functions {
269            match func.name {
270                OptionalIdentifier::Ident(func_name) => {
271                    let new_param = Parameter::named("this", Self::this_arg_to_type(func.this_arg, item_name, item_type_param_names));
272                    let mut param_list = vec![new_param];
273                    param_list.extend(func.params);
274                    let mut type_param_names = func.type_param_names;
275                    let intersecting_type_param = item_type_param_names.iter().find(|t| type_param_names.contains(t));
276                    if let Some(name) = intersecting_type_param {
277                        return Err(Box::new(ModuleError::DuplicateTypeArgumentName(name.clone())));
278                    }
279                    type_param_names.extend(item_type_param_names.clone());
280                    let new_func = PFunction::new(
281                        OptionalIdentifier::Ident(func_name.clone()),
282                        param_list,
283                        func.return_type,
284                        func.body,
285                        type_param_names,
286                    );
287                    let addr = FunctionAddress {
288                        own_module_path: PathIdent::continued(n.clone(), func_name),
289                        target: Some(PathIdent::continued(n.clone(), item_name.clone())),
290                    };
291                    funcs_to_add.push((addr, new_func));
292                },
293                OptionalIdentifier::Ignore => (),
294            }
295        }
296        Ok(())
297    }
298    
299    fn add_extension(&mut self, n: PathIdent, item: Extension, funcs_to_add: &mut Vec<(FunctionAddress, PFunction)>) -> Result<(), CortexError> {
300        let item_name = item.name.get_back()?;
301        let item_prefix = item.name.without_last();
302        for func in item.functions {
303            match func.name {
304                OptionalIdentifier::Ident(func_name) => {
305                    let new_param = Parameter::named("this", Self::this_arg_to_type(func.this_arg, item_name, &item.type_param_names).with_prefix(&item_prefix));
306                    let mut param_list = vec![new_param];
307                    param_list.extend(func.params);
308                    let mut type_param_names = func.type_param_names;
309                    let intersecting_type_param = item.type_param_names.iter().find(|t| type_param_names.contains(t));
310                    if let Some(name) = intersecting_type_param {
311                        return Err(Box::new(ModuleError::DuplicateTypeArgumentName(name.clone())));
312                    }
313                    type_param_names.extend(item.type_param_names.clone());
314                    let new_func = PFunction::new(
315                        OptionalIdentifier::Ident(func_name.clone()),
316                        param_list,
317                        func.return_type,
318                        func.body,
319                        type_param_names,
320                    );
321                    let addr = FunctionAddress {
322                        own_module_path: PathIdent::continued(n.clone(), func_name),
323                        target: Some(PathIdent::concat(&n, &item.name)),
324                    };
325                    funcs_to_add.push((addr, new_func));
326                },
327                OptionalIdentifier::Ignore => (),
328            }
329        }
330        Ok(())
331    }
332
333    fn this_arg_to_type(this_arg: ThisArg, item_name: &String, type_param_names: &Vec<String>) -> CortexType {
334        match this_arg {
335            ThisArg::RefThis => 
336                CortexType::reference(
337                    CortexType::basic(PathIdent::simple(item_name.clone()), false, forwarded_type_args(type_param_names)),
338                    false,
339                ),
340            ThisArg::RefMutThis => 
341                CortexType::reference(
342                    CortexType::basic(PathIdent::simple(item_name.clone()), false, forwarded_type_args(type_param_names)),
343                    true,
344                ),
345            ThisArg::DirectThis => CortexType::basic(PathIdent::simple(item_name.clone()), false, forwarded_type_args(type_param_names)),
346        }
347    }
348
349    pub fn preprocess(&mut self, body: BasicBody) -> Result<Program, CortexError> {
350        let (body, _) = self.check_body(body)?;
351        Ok(Program { code: body })
352    }
353
354    fn construct_module(contents: Vec<TopLevel>) -> Result<Module, CortexError> {
355        let mut module = Module::new();
356        for item in contents.into_iter() {
357            match item {
358                TopLevel::Import { name: _, is_string_import: _ } => todo!("Imports are currently not supported!"),
359                TopLevel::Module { name: submod_name, contents } => {
360                    let new_module = Self::construct_module(contents)?;
361                    module.add_child(submod_name, new_module)?;
362                },
363                TopLevel::Function(function) => {
364                    module.add_function(function)?;
365                },
366                TopLevel::Struct(item) => {
367                    module.add_struct(item)?;
368                },
369                TopLevel::Bundle(item) => {
370                    module.add_bundle(item)?;
371                },
372                TopLevel::Extension(item) => {
373                    module.add_extension(item)?;
374                },
375            }
376        }
377        Ok(module)
378    }
379
380    pub fn preprocess_function(&mut self, function: PFunction) -> Result<RFunction, CortexError> {
381        let parent_env = self.current_env.take().ok_or(PreprocessingError::NoParentEnv)?;
382        let mut new_env = TypeCheckingEnvironment::new(*parent_env);
383        let mut params = Vec::new();
384        for p in function.params {
385            let param_type = self.clean_type(p.typ.clone().with_prefix_if_not_core(&self.current_context));
386            new_env.add(p.name.clone(), param_type, false)?;
387            params.push(p.name);
388        }
389        self.current_env = Some(Box::new(new_env));
390
391        // Do check body
392        let final_fn_body;
393        match function.body {
394            Body::Basic(body) => {
395                let (new_body, body_type) = self.check_body(body)?;
396                let return_type = self.clean_type(function.return_type.clone().with_prefix_if_not_core(&self.current_context));
397                if !body_type.is_subtype_of(&return_type) {
398                    return Err(Box::new(PreprocessingError::ReturnTypeMismatch(return_type.codegen(0), body_type.codegen(0))));
399                }
400                final_fn_body = RBody::Interpreted(new_body);
401            },
402            Body::Native(native_body) => {
403                final_fn_body = RBody::Native(native_body);
404            },
405        }
406
407        self.current_env = Some(Box::new(self.current_env.take().unwrap().exit()?));
408
409        Ok(RFunction::new(params, final_fn_body))
410    }
411
412    fn check_statement(&mut self, statement: PStatement) -> Result<Vec<RStatement>, CortexError> {
413        let st_str = statement.codegen(0);
414        match statement {
415            PStatement::Expression(expression) => {
416                let (exp, _) = self.check_exp(expression)?;
417                Ok(vec![RStatement::Expression(exp)])
418            },
419            PStatement::Throw(expression) => {
420                let (exp, _) = self.check_exp(expression)?;
421                Ok(vec![RStatement::Throw(exp)])
422            },
423            PStatement::VariableDeclaration { name, is_const, typ, initial_value } => {
424                Ok(self.check_declaration_recursive(name, typ, is_const, initial_value, &st_str)?)
425            },
426            PStatement::Assignment { name, value } => {
427                Ok(self.check_assignment_recursive(name, value, &st_str)?)
428            },
429            PStatement::WhileLoop(condition_body) => {
430                let (cond, cond_type) = self.check_exp(condition_body.condition)?;
431                if !cond_type.is_subtype_of(&CortexType::boolean(false)) {
432                    return Err(
433                        Box::new(
434                            PreprocessingError::MismatchedType(
435                                String::from("bool"),
436                                cond_type.codegen(0),
437                                String::from("while condition"),
438                                st_str,
439                            )
440                        )
441                    );
442                }
443
444                self.loop_depth += 1;
445                let (body, body_type) = self.check_body_and_handle_env(condition_body.body)?;
446                if !body_type.is_subtype_of(&CortexType::void(false)) {
447                    return Err(
448                        Box::new(
449                            PreprocessingError::LoopCannotHaveReturnValue
450                        )
451                    );
452                }
453                self.loop_depth -= 1;
454
455                Ok(vec![RStatement::WhileLoop(RConditionBody::new(cond, body))])
456            },
457            PStatement::Break => {
458                if self.loop_depth <= 0 {
459                    Err(Box::new(PreprocessingError::BreakUsedInNonLoopContext))
460                } else {
461                    Ok(vec![RStatement::Break])
462                }
463            },
464            PStatement::Continue => {
465                if self.loop_depth <= 0 {
466                    Err(Box::new(PreprocessingError::ContinueUsedInNonLoopContext))
467                } else {
468                    Ok(vec![RStatement::Continue])
469                }
470            },
471        }
472    }
473
474    fn check_declaration(&mut self, name: OptionalIdentifier, typ: Option<CortexType>, is_const: bool, initial_value: PExpression, st_str: &String) -> Result<Vec<RStatement>, CortexError> {
475        match name {
476            OptionalIdentifier::Ident(ident) => {
477                let (assigned_exp, assigned_type) = self.check_exp(initial_value)?;
478                let type_of_var = if let Some(mut declared_type) = typ {
479                    declared_type = self.clean_type(declared_type.with_prefix_if_not_core(&self.current_context));
480                    if !assigned_type.is_subtype_of(&declared_type) {
481                        return Err(
482                            Box::new(
483                                PreprocessingError::MismatchedType(
484                                    declared_type.codegen(0),
485                                    assigned_type.codegen(0),
486                                    ident.clone(),
487                                    st_str.clone(),
488                                )
489                            )
490                        );
491                    }
492                    declared_type.clone()
493                } else {
494                    assigned_type
495                };
496
497                self.current_env.as_mut().unwrap().add(ident.clone(), type_of_var, is_const)?;
498
499                Ok(vec![RStatement::VariableDeclaration { name: ident, is_const: is_const, initial_value: assigned_exp }])
500            },
501            OptionalIdentifier::Ignore => {
502                let (exp, _) = self.check_exp(initial_value)?;
503                Ok(vec![RStatement::Expression(exp)])
504            },
505        }
506    }
507    fn check_declaration_recursive(&mut self, name: DeclarationName, typ: Option<CortexType>, is_const: bool, initial_value: PExpression, st_str: &String) -> Result<Vec<RStatement>, CortexError> {
508        match name {
509            DeclarationName::Single(name) => {
510                Ok(self.check_declaration(name, typ, is_const, initial_value, &st_str)?)
511            },
512            DeclarationName::Tuple(names) => {
513                let mut result = Vec::new();
514                // We want to save off the initial expression in case it is an expensive calculation
515                let temp_name = self.next_temp();
516                // We need to run through this so that the preprocessor registers that the temp var was created
517                let var_dec = self.check_statement(PStatement::VariableDeclaration {
518                    name: DeclarationName::Single(OptionalIdentifier::Ident(temp_name.clone())),
519                    is_const: true,
520                    typ,
521                    initial_value,
522                })?;
523                result.extend(var_dec);
524                let temp_expr = PExpression::PathIdent(PathIdent::simple(temp_name));
525                for (i, name) in names.into_iter().enumerate() {
526                    let new_value = PExpression::MemberAccess(Box::new(temp_expr.clone()), format!("t{}", i));
527                    result.extend(self.check_declaration_recursive(name, None, is_const, new_value, &st_str)?);
528                }
529                Ok(result)
530            },
531        }
532    }
533
534    fn check_assignment(&mut self, name: IdentExpression, value: PExpression, st_str: &String) -> Result<Vec<RStatement>, CortexError> {
535        let (assigned_exp, assigned_type) = self.check_exp(value)?;
536        if name.is_simple() {
537            let var_name = &name.base;
538            let var_type = &self.current_env.as_ref().unwrap().get(var_name)?.clone();
539            if !assigned_type.is_subtype_of(var_type) {
540                return Err(
541                    Box::new(
542                        PreprocessingError::MismatchedType(
543                            var_type.codegen(0),
544                            assigned_type.codegen(0),
545                            var_name.clone(),
546                            st_str.clone(),
547                        )
548                    )
549                );
550            }
551            
552            if self.current_env.as_ref().unwrap().is_const(var_name)? {
553                return Err(
554                    Box::new(
555                        PreprocessingError::CannotModifyConst(var_name.clone())
556                    )
557                )
558            }
559        } else {
560            let source_expr = name.clone().without_last()?.to_member_access_expr();
561            let (_, source_type) = self.check_exp(source_expr)?;
562            if let CortexType::RefType(r) = source_type {
563                if !r.mutable {
564                    return Err(
565                        Box::new(
566                            PreprocessingError::CannotModifyFieldOnImmutableReference(r.contained.codegen(0))
567                        )
568                    );
569                }
570            }
571
572            let name_expr = name.clone().to_member_access_expr();
573            let (_, var_type) = self.check_exp(name_expr)?;
574            if !assigned_type.is_subtype_of(&var_type) {
575                return Err(
576                    Box::new(
577                        PreprocessingError::MismatchedType(
578                            var_type.codegen(0),
579                            assigned_type.codegen(0),
580                            name.codegen(0),
581                            st_str.clone(),
582                        )
583                    )
584                );
585            }
586        }
587
588        Ok(vec![RStatement::Assignment { name: name.into(), value: assigned_exp }])
589    }
590    fn check_assignment_recursive(&mut self, name: AssignmentName, value: PExpression, st_str: &String) -> Result<Vec<RStatement>, CortexError> {
591        match name {
592            AssignmentName::Single(name) => {
593                Ok(self.check_assignment(name, value, &st_str)?)
594            },
595            AssignmentName::Ignore => {
596                Ok(self.check_statement(PStatement::Expression(value))?)
597            },
598            AssignmentName::Tuple(names) => {
599                let mut result = Vec::new();
600                // We want to save off the initial expression in case it is an expensive calculation
601                let temp_name = self.next_temp();
602                // We need to run through this so that the preprocessor registers that the temp var was created
603                let var_dec = self.check_statement(PStatement::VariableDeclaration {
604                    name: DeclarationName::Single(OptionalIdentifier::Ident(temp_name.clone())),
605                    is_const: true,
606                    typ: None,
607                    initial_value: value,
608                })?;
609                result.extend(var_dec);
610                let temp_expr = PExpression::PathIdent(PathIdent::simple(temp_name));
611                for (i, name) in names.into_iter().enumerate() {
612                    let new_value = PExpression::MemberAccess(Box::new(temp_expr.clone()), format!("t{}", i));
613                    result.extend(self.check_assignment_recursive(name, new_value, &st_str)?);
614                }
615                Ok(result)
616            },
617        }
618    }
619
620    fn check_exp(&mut self, exp: PExpression) -> CheckResult<RExpression> {
621        let st_str = exp.codegen(0);
622        match exp {
623            PExpression::Number(v) => Ok((RExpression::Number(v), CortexType::number(false))),
624            PExpression::Boolean(v) => Ok((RExpression::Boolean(v), CortexType::boolean(false))),
625            PExpression::Void => Ok((RExpression::Void, CortexType::void(false))),
626            PExpression::None => Ok((RExpression::None, CortexType::none())),
627            PExpression::String(v) => Ok((RExpression::String(v), CortexType::string(false))),
628            PExpression::Char(v) => Ok((RExpression::Char(v), CortexType::char(false))),
629            PExpression::PathIdent(path_ident) => Ok((RExpression::Identifier(path_ident.get_back()?.clone()), self.get_variable_type(&path_ident)?)),
630            PExpression::Call { name: addr, args: arg_exps, type_args } => {
631                let prefix = addr.without_last();
632                let result = self.check_call(
633                    addr.get_back()?,
634                    arg_exps, 
635                    type_args,
636                    prefix,
637                    &st_str
638                );
639                result
640            },
641            PExpression::Construction { name, type_args, assignments } => {
642                self.check_construction(name, type_args, assignments, &st_str)
643            },
644            PExpression::IfStatement { first, conds, last } => {
645                self.check_if_statement(*first, conds, last.map(|b| *b), &st_str)
646            },
647            PExpression::UnaryOperation { op, exp } => {
648                let (exp, typ) = self.check_exp(*exp)?;
649                match op {
650                    UnaryOperator::Negate => {
651                        if typ == CortexType::number(false) {
652                            Ok((RExpression::UnaryOperation { op: UnaryOperator::Negate, exp: Box::new(exp) }, CortexType::number(false)))
653                        } else {
654                            Err(Box::new(PreprocessingError::InvalidOperatorUnary("number")))
655                        }
656                    },
657                    UnaryOperator::Invert => {
658                        if typ == CortexType::boolean(false) {
659                            Ok((RExpression::UnaryOperation { op: UnaryOperator::Invert, exp: Box::new(exp) }, CortexType::boolean(false)))
660                        } else {
661                            Err(Box::new(PreprocessingError::InvalidOperatorUnary("bool")))
662                        }
663                    },
664                }
665            },
666            PExpression::ListLiteral(items) => {
667                let mut contained_type = CortexType::Unknown(false);
668                let mut new_items = Vec::new();
669                for item in items {
670                    let (item_exp, item_type) = self.check_exp(item)?;
671                    let item_type_str = item_type.codegen(0);
672                    let typ_str = contained_type.codegen(0);
673                    contained_type = contained_type
674                        .combine_with(item_type)
675                        .ok_or(PreprocessingError::CannotDetermineListLiteralType(typ_str, item_type_str))?;
676                    new_items.push(item_exp);
677                }
678                let true_type = CortexType::reference(CortexType::list(contained_type, false), true);
679                Ok((RExpression::ListLiteral(new_items), true_type))
680            },
681            PExpression::Bang(inner) => {
682                let (exp, typ) = self.check_exp(*inner)?;
683                Ok((RExpression::Bang(Box::new(exp)), typ.to_non_optional()))
684            },
685            PExpression::MemberAccess(inner, member) => {
686                let inner_as_string = inner.codegen(0);
687                let (atom_exp, atom_type) = self.check_exp(*inner)?;
688                match &atom_type {
689                    CortexType::BasicType(_) |
690                    CortexType::RefType(_) => {
691                        if atom_type.is_non_composite() {
692                            return Err(Box::new(PreprocessingError::CannotAccessMemberOfNonComposite));
693                        }
694                        if atom_type.optional() {
695                            return Err(Box::new(PreprocessingError::CannotAccessMemberOfOptional(inner_as_string)));
696                        }
697                        Ok(self.check_composite_member_access(atom_exp, atom_type, member)?)
698                    },
699                    CortexType::Unknown(_) => Err(Box::new(TypeError::UnknownTypeNotValid)),
700                    CortexType::TupleType(t) => {
701                        if t.optional {
702                            return Err(Box::new(PreprocessingError::CannotAccessMemberOfOptional(inner_as_string)));
703                        }
704                        Ok(self.check_tuple_member_access(atom_exp, t, member)?)
705                    },
706                }
707            },
708            PExpression::MemberCall { callee, member, mut args, type_args } => {
709                let (_, atom_type) = self.check_exp(*callee.clone())?;
710                
711                let caller_type = atom_type.name()?;
712                let caller_type_prefix = caller_type.without_last();
713                let non_extension_func_addr = FunctionAddress::member_func(
714                    PathIdent::continued(caller_type_prefix.clone().subtract(&self.current_context)?, member.clone()), 
715                    caller_type.clone().subtract(&self.current_context)?);
716                
717                args.insert(0, *callee);
718                let true_type_args;
719                if let Some(mut type_args) = type_args {
720                    let typedef = self.lookup_type(caller_type)?;
721                    let mut bindings = HashMap::new();
722                    self.infer_arg(&CortexType::reference(
723                        CortexType::basic(caller_type.clone(), false, forwarded_type_args(&typedef.type_param_names)),
724                        true,
725                    ), &atom_type, &typedef.type_param_names, &mut bindings, &String::from("this"), &st_str)?;
726                    let mut beginning_type_args = Vec::new();
727                    for a in &typedef.type_param_names {
728                        beginning_type_args.push(bindings.remove(a).unwrap());
729                    }
730                    type_args.extend(beginning_type_args);
731                    true_type_args = Some(type_args);
732                } else {
733                    true_type_args = None;
734                }
735
736                let actual_func_addr;
737                if self.has_function(&non_extension_func_addr) {
738                    actual_func_addr = non_extension_func_addr;
739                } else {
740                    let attempted_extension_path = self.search_for_extension(&caller_type, &member)?;
741                    if let Some(extension_func_path) = attempted_extension_path {
742                        actual_func_addr = extension_func_path.clone();
743                    } else {
744                        return Err(Box::new(PreprocessingError::FunctionDoesNotExist(non_extension_func_addr.codegen(0))));
745                    }
746                }
747
748                let call_exp = PExpression::Call {
749                    name: actual_func_addr, 
750                    args,
751                    type_args: true_type_args,
752                };
753                let result = self.check_exp(call_exp)?;
754                Ok(result)
755            },
756            PExpression::BinaryOperation { left, op, right } => {
757                let (left_exp, left_type) = self.check_exp(*left)?;
758                let (right_exp, right_type) = self.check_exp(*right)?;
759                let op_type = self.check_operator(left_type, &op, right_type)?;
760                Ok((RExpression::BinaryOperation { left: Box::new(left_exp), op: op, right: Box::new(right_exp) }, op_type))
761            },
762            PExpression::Tuple(items) => {
763                let results = items
764                    .into_iter()
765                    .map(|e| self.check_exp(e))
766                    .collect::<Result<Vec<_>, _>>()?;
767                let (exps, types): (Vec<RExpression>, Vec<CortexType>) = results.into_iter().unzip();
768                Ok((RExpression::Tuple(exps), CortexType::tuple(types, false)))
769            },
770            PExpression::Range { start, end, step } => {
771                fn otov(o: Option<f64>) -> RExpression {
772                    match o {
773                        Some(v) => RExpression::Number(v),
774                        None => RExpression::None,
775                    }
776                }
777                let construction = RExpression::Construction {
778                    assignments: vec![
779                        (String::from("start"), otov(start)),
780                        (String::from("end"), otov(end)),
781                        (String::from("step"), otov(step)),
782                    ],
783                    is_heap_allocated: false,
784                };
785                Ok((construction, CortexType::range(false)))
786            },
787        }
788    }
789    fn check_composite_member_access(&mut self, atom_exp: RExpression, atom_type: CortexType, member: String) -> CheckResult<RExpression> {
790        let is_mutable;
791        match &atom_type {
792            CortexType::BasicType(_) | 
793            CortexType::TupleType(_) => {
794                is_mutable = true;
795            },
796            CortexType::RefType(r) => {
797                is_mutable = r.mutable;
798            },
799            CortexType::Unknown(_) => {
800                return Err(Box::new(PreprocessingError::UnknownTypeFound));
801            },
802        }
803        let typedef = self.lookup_type(&atom_type.name()?.clone().subtract(&self.current_context)?)?;
804        if !typedef.fields.contains_key(&member) {
805            Err(Box::new(PreprocessingError::FieldDoesNotExist(member.clone(), atom_type.codegen(0))))
806        } else {
807            let mut member_type = typedef.fields.get(&member).unwrap().clone();
808            let bindings = Self::get_bindings(&typedef.type_param_names, &atom_type)?;
809            let prefix = atom_type.prefix();
810            member_type = TypeEnvironment::fill(member_type, 
811                &bindings
812                    .into_iter()
813                    .map(|(k, v)| (k, v.subtract_if_possible(&prefix)))
814                    .collect::<HashMap<_, _>>()
815                );
816            member_type = member_type.with_prefix_if_not_core(&prefix);
817            member_type = member_type.forward_immutability(is_mutable);
818            Ok((RExpression::MemberAccess(Box::new(atom_exp), member), member_type))
819        }
820    }
821    fn check_tuple_member_access(&mut self, atom_exp: RExpression, atom_type: &TupleType, member: String) -> CheckResult<RExpression> {
822        fn strip_t(s: &str) -> Option<usize> {
823            s.strip_prefix('t')?.parse().ok()
824        }
825
826        let index = strip_t(&member).ok_or(PreprocessingError::TupleMemberSyntaxInvalid(member))?;
827        if index > atom_type.types.len() {
828            return Err(Box::new(PreprocessingError::TupleIndexValueInvalid(atom_type.types.len(), index)));
829        }
830
831        let member_type = atom_type.types.get(index).unwrap().clone();
832        
833        Ok((RExpression::MemberAccess(Box::new(atom_exp), format!("t{}", index)), member_type))
834    }
835
836    fn search_for_extension(&self, typ: &PathIdent, member: &String) -> Result<Option<&FunctionAddress>, CortexError> {
837        // Search through *ALL* functions
838        // If they are prefixed by the current_context, and have a target type = to `typ`,
839        // and a function name .getBack() == member, then return that address
840        let candidates = self.function_signature_map.keys().filter_map(|p| {
841            // Must be prefixed by current_context to be in scope at this point
842            if p.own_module_path.is_prefixed_by(&self.current_context) {
843                // Must have the same target type to be able to be called
844                if let Some(target) = &p.target {
845                    if target == typ {
846                        // Finally, must have same method name (getBack() == member)
847                        let back = p.own_module_path.get_back();
848                        match back {
849                            Ok(back_name) => {
850                                if back_name == member {
851                                    return Some(Ok::<_, CortexError>(p));
852                                }
853                            },
854                            Err(err) => {
855                                return Some(Err(Box::new(err)));
856                            },
857                        }
858                    }
859                }
860            }
861            None
862        }).collect::<Result<Vec<_>, _>>()?;
863
864        if candidates.len() > 1 {
865            Err(Box::new(PreprocessingError::AmbiguousExtensionCall(member.clone(), typ.codegen(0))))
866        } else {
867            Ok(candidates.get(0).cloned())
868        }
869    }
870
871    fn check_call(&mut self, addr: FunctionAddress, arg_exps: Vec<PExpression>, type_args: Option<Vec<CortexType>>, prefix: PathIdent, st_str: &String) -> CheckResult<RExpression> {
872        let provided_arg_count = arg_exps.len();
873        let mut processed_args = Vec::new();
874        let mut arg_types = Vec::new();
875        for a in arg_exps.into_iter() {
876            let (arg, typ) = self.check_exp(a)?;
877            arg_types.push(typ);
878            processed_args.push(arg);
879        }
880        
881        let extended_prefix = PathIdent::concat(&self.current_context, &prefix);
882        let sig = self.lookup_signature(&FunctionAddress::concat(&prefix, &addr))?.clone();
883
884        let full_path = FunctionAddress::concat(&extended_prefix, &addr);
885        if provided_arg_count != sig.params.len() {
886            return Err(Box::new(
887                PreprocessingError::MismatchedArgumentCount(full_path.codegen(0), sig.params.len(), provided_arg_count)
888            ));
889        }
890
891        let mut return_type = sig
892            .return_type
893            .clone();
894
895        let mut param_names = Vec::<String>::with_capacity(sig.params.len());
896        let mut param_types = Vec::<CortexType>::with_capacity(sig.params.len());
897        for param in &sig.params {
898            param_names.push(param.name.clone());
899            param_types.push(param.typ.clone().with_prefix_if_not_core(&extended_prefix));
900        }
901
902        let bindings;
903        if let Some(type_args) = type_args {
904            bindings = sig.type_param_names.iter().cloned().zip(type_args).collect();
905        } else {
906            bindings = self.infer_type_args(&sig, &arg_types, &full_path, st_str)?;
907        }
908        let parent_type_env = self.current_type_env.take().ok_or(PreprocessingError::NoParentEnv)?;
909        let mut new_type_env = TypeEnvironment::new(*parent_type_env);
910        for (name, typ) in &bindings {
911            new_type_env.add(name.clone(), typ.clone());
912        }
913        self.current_type_env = Some(Box::new(new_type_env));
914
915        for (i, arg_type) in arg_types.into_iter().enumerate() {
916            let arg_type = self.clean_type(arg_type);
917            let param_type = self.clean_type(param_types.get(i).unwrap().clone());
918            if !arg_type.is_subtype_of(&param_type) {
919                return Err(
920                    Box::new(
921                        PreprocessingError::MismatchedType(
922                            param_type.codegen(0),
923                            arg_type.codegen(0),
924                            param_names.get(i).unwrap().clone(),
925                            st_str.clone(),
926                        )
927                    )
928                );
929            }
930        }
931
932        return_type = self.clean_type(return_type)
933            .with_prefix_if_not_core(&extended_prefix);
934
935        self.current_type_env = Some(Box::new(self.current_type_env.take().unwrap().exit()?));
936
937        let func_id = self.function_dict.add_call(full_path)?;
938
939        Ok((RExpression::Call(func_id, processed_args), return_type))
940    }
941    fn check_construction(&mut self, name: PathIdent, type_args: Vec<CortexType>, assignments: Vec<(String, PExpression)>, st_str: &String) -> CheckResult<RExpression> {
942        let typedef = self.lookup_type(&name)?;
943        let base_type = CortexType::basic(name.clone(), false, type_args.clone()).with_prefix_if_not_core(&self.current_context);
944
945        if type_args.len() != typedef.type_param_names.len() {
946            return Err(Box::new(PreprocessingError::MismatchedTypeArgCount(name.codegen(0), typedef.type_param_names.len(), type_args.len())));
947        }
948        let mut fields_to_assign = Vec::new();
949        for k in typedef.fields.keys() {
950            fields_to_assign.push(k.clone());
951        }
952
953        let is_heap_allocated = typedef.is_heap_allocated;
954        let fields = typedef.fields.clone();
955
956        let bindings = TypeEnvironment::create_bindings(&typedef.type_param_names, &type_args);
957        let bindings = bindings
958            .iter()
959            .map(|(k, v)| (k.clone(), v.clone().subtract_if_possible(&name.without_last())))
960            .collect::<HashMap<_, _>>();
961        let mut new_assignments = Vec::new();
962        for (fname, fvalue) in assignments {
963            let opt_typ = fields
964                .get(&fname)
965                .map(|t| t.clone());
966            if let Some(typ) = opt_typ {
967                let field_type = TypeEnvironment::fill(typ, &bindings)
968                    .with_prefix_if_not_core(&self.current_context)
969                    .with_prefix_if_not_core(&name.without_last());
970                let (exp, assigned_type) = self.check_exp(fvalue)?;
971                if !assigned_type.is_subtype_of(&field_type) {
972                    return Err(
973                        Box::new(
974                            PreprocessingError::MismatchedType(
975                                field_type.codegen(0),
976                                assigned_type.codegen(0),
977                                fname.clone(),
978                                st_str.clone(),
979                            )
980                        )
981                    );
982                }
983
984                new_assignments.push((fname.clone(), exp));
985
986                let index_opt = fields_to_assign.iter().position(|x| *x == *fname);
987                if let Some(index) = index_opt {
988                    fields_to_assign.remove(index);
989                } else {
990                    return Err(Box::new(PreprocessingError::MultipleFieldAssignment(fname.clone())));
991                }
992            } else {
993                return Err(Box::new(PreprocessingError::FieldDoesNotExist(fname.clone(), name.codegen(0))));
994            }
995        }
996
997        if fields_to_assign.is_empty() {
998            if is_heap_allocated {
999                Ok((RExpression::Construction { assignments: new_assignments, is_heap_allocated: true }, CortexType::reference(base_type, true)))
1000            } else {
1001                Ok((RExpression::Construction { assignments: new_assignments, is_heap_allocated: false }, base_type))
1002            }
1003        } else {
1004            Err(Box::new(PreprocessingError::NotAllFieldsAssigned(name.codegen(0), fields_to_assign.join(","))))
1005        }
1006    }
1007    fn check_if_statement(&mut self, first: PConditionBody, conds: Vec<PConditionBody>, last: Option<BasicBody>, st_str: &String) -> CheckResult<RExpression> {
1008        let (cond_exp, cond_typ) = self.check_exp(first.condition)?;
1009        if cond_typ != CortexType::boolean(false) {
1010            return Err(
1011                Box::new(
1012                    PreprocessingError::MismatchedType(
1013                        String::from("bool"),
1014                        cond_typ.codegen(0),
1015                        String::from("if condition"),
1016                        st_str.clone(),
1017                    )
1018                )
1019            );
1020        }
1021        let (first_body, mut the_type) = self.check_body_and_handle_env(first.body)?;
1022        
1023        let mut condition_bodies = Vec::<RConditionBody>::new();
1024        for c in conds {
1025            let (cond, cond_typ) = self.check_exp(c.condition)?;
1026            if !cond_typ.is_subtype_of(&CortexType::boolean(false)) {
1027                return Err(
1028                    Box::new(
1029                        PreprocessingError::MismatchedType(
1030                            String::from("bool"),
1031                            cond_typ.codegen(0),
1032                            String::from("else-if condition"),
1033                            st_str.clone(),
1034                        )
1035                    )
1036                );
1037            }
1038            let (body, typ) = self.check_body_and_handle_env(c.body)?;
1039            let the_type_str = the_type.codegen(0);
1040            let typ_str = typ.codegen(0);
1041            let next = the_type.combine_with(typ);
1042            if let Some(t) = next {
1043                the_type = t;
1044                condition_bodies.push(RConditionBody::new(cond, body));
1045            } else {
1046                return Err(Box::new(PreprocessingError::IfArmsDoNotMatch(the_type_str, typ_str)));
1047            }
1048        }
1049        let mut final_body = None;
1050        if let Some(fin) = last {
1051            let (body, typ) = self.check_body_and_handle_env(fin)?;
1052            final_body = Some(Box::new(body));
1053            let the_type_str = the_type.codegen(0);
1054            let typ_str = typ.codegen(0);
1055            let next = the_type.combine_with(typ);
1056            if let Some(t) = next {
1057                the_type = t;
1058            } else {
1059                return Err(Box::new(PreprocessingError::IfArmsDoNotMatch(the_type_str, typ_str)));
1060            }
1061        } else if the_type != CortexType::void(false) {
1062            return Err(Box::new(PreprocessingError::IfRequiresElseBlock));
1063        }
1064
1065        Ok((RExpression::IfStatement { 
1066            first: Box::new(RConditionBody::new(cond_exp, first_body)),
1067            conds: condition_bodies,
1068            last: final_body,
1069        }, the_type))
1070    }
1071
1072    fn check_body_and_handle_env(&mut self, body: BasicBody) -> CheckResult<RInterpretedBody> {
1073        let parent_env = self.current_env.take().ok_or(PreprocessingError::NoParentEnv)?;
1074        self.current_env = Some(Box::new(TypeCheckingEnvironment::new(*parent_env)));
1075
1076        let result = self.check_body(body);
1077
1078        self.current_env = Some(Box::new(self.current_env.take().unwrap().exit()?));
1079        result
1080    }
1081
1082    fn check_body(&mut self, body: BasicBody) -> CheckResult<RInterpretedBody> {
1083        let mut statements = Vec::new();
1084        for st in body.statements {
1085            let s = self.check_statement(st)?;
1086            statements.extend(s);
1087        }
1088        if let Some(exp) = body.result {
1089            let (exp, typ) = self.check_exp(exp)?;
1090            Ok((RInterpretedBody::new(statements, Some(exp)), typ))
1091        } else {
1092            Ok((RInterpretedBody::new(statements, None), CortexType::void(false)))
1093        }
1094    }
1095
1096    fn check_operator(&self, first: CortexType, op: &BinaryOperator, second: CortexType) -> Result<CortexType, CortexError> {
1097        let number = CortexType::number(false);
1098        let string = CortexType::string(false);
1099        let boolean = CortexType::boolean(false);
1100        match op {
1101            BinaryOperator::Add => {
1102                if first == number && second == number {
1103                    Ok(number)
1104                } else if first == string && second == string {
1105                    Ok(string)
1106                } else {
1107                    Err(Box::new(PreprocessingError::InvalidOperator("number, string", "number, string")))
1108                }
1109            },
1110            BinaryOperator::Subtract => {
1111                if first == number && second == number {
1112                    Ok(number)
1113                } else {
1114                    Err(Box::new(PreprocessingError::InvalidOperator("number", "number")))
1115                }
1116            },
1117            BinaryOperator::Multiply => {
1118                if first == number && second == number {
1119                    Ok(number)
1120                } else if first == number && second == string {
1121                    Ok(string)
1122                } else if first == string && second == number {
1123                    Ok(string)
1124                } else {
1125                    Err(Box::new(PreprocessingError::InvalidOperator("number", "string")))
1126                }
1127            },
1128            BinaryOperator::Divide => {
1129                if first == number && second == number {
1130                    Ok(number)
1131                } else {
1132                    Err(Box::new(PreprocessingError::InvalidOperator("number", "number")))
1133                }
1134            },
1135            BinaryOperator::Remainder => {
1136                if first == number && second == number {
1137                    Ok(number)
1138                } else {
1139                    Err(Box::new(PreprocessingError::InvalidOperator("number", "number")))
1140                }
1141            },
1142            BinaryOperator::LogicAnd => {
1143                if first == boolean && second == boolean {
1144                    Ok(boolean)
1145                } else {
1146                    Err(Box::new(PreprocessingError::InvalidOperator("boolean", "boolean")))
1147                }
1148            },
1149            BinaryOperator::LogicOr => {
1150                if first == boolean && second == boolean {
1151                    Ok(boolean)
1152                } else {
1153                    Err(Box::new(PreprocessingError::InvalidOperator("boolean", "boolean")))
1154                }
1155            },
1156            BinaryOperator::IsEqual => {
1157                Ok(boolean)
1158            },
1159            BinaryOperator::IsNotEqual => {
1160                Ok(boolean)
1161            },
1162            BinaryOperator::IsLessThan => {
1163                if first == number && second == number {
1164                    Ok(boolean)
1165                } else {
1166                    Err(Box::new(PreprocessingError::InvalidOperator("number", "number")))
1167                }
1168            },
1169            BinaryOperator::IsGreaterThan => {
1170                if first == number && second == number {
1171                    Ok(boolean)
1172                } else {
1173                    Err(Box::new(PreprocessingError::InvalidOperator("number", "number")))
1174                }
1175            },
1176            BinaryOperator::IsLessThanOrEqualTo => {
1177                if first == number && second == number {
1178                    Ok(boolean)
1179                } else {
1180                    Err(Box::new(PreprocessingError::InvalidOperator("number", "number")))
1181                }
1182            },
1183            BinaryOperator::IsGreaterThanOrEqualTo => {
1184                if first == number && second == number {
1185                    Ok(boolean)
1186                } else {
1187                    Err(Box::new(PreprocessingError::InvalidOperator("number", "number")))
1188                }
1189            },
1190        }
1191    }
1192
1193    // "Cleans" type, for example replacing type arguments
1194    fn clean_type(&self, typ: CortexType) -> CortexType {
1195        self.current_type_env.as_ref().unwrap().fill_in(typ)
1196    }
1197
1198    // Used to get bindings for a type (give param names and the concrete type)
1199    fn get_bindings(type_param_names: &Vec<String>, typ: &CortexType) -> Result<HashMap<String, CortexType>, CortexError> {
1200        let mut type_args_handled = false;
1201        let mut typ = typ.clone();
1202        let mut bindings = HashMap::new();
1203        while !type_args_handled {
1204            if let CortexType::BasicType(b) = &typ {
1205                bindings = TypeEnvironment::create_bindings(type_param_names, &b.type_args);
1206                typ = TypeEnvironment::fill(typ, &bindings);
1207                type_args_handled = true;
1208            } else if let CortexType::RefType(r) = typ {
1209                typ = *r.contained;
1210            }
1211        }
1212        Ok(bindings)
1213    }
1214    fn infer_type_args(&self, sig: &FunctionSignature, args: &Vec<CortexType>, name: &FunctionAddress, st_str: &String) -> Result<HashMap<String, CortexType>, CortexError> {
1215        let mut bindings = HashMap::<String, CortexType>::new();
1216        for (arg, param) in args.iter().zip(&sig.params) {
1217            self.infer_arg(&param.typ, &arg, &sig.type_param_names, &mut bindings, param.name(), st_str)?;
1218        }
1219
1220        if bindings.len() != sig.type_param_names.len() {
1221            Err(Box::new(PreprocessingError::CouldNotInferTypeBinding(name.codegen(0))))
1222        } else {
1223            Ok(bindings)
1224        }
1225    }
1226    fn infer_arg(&self, param_type: &CortexType, arg_type: &CortexType, type_param_names: &Vec<String>, bindings: &mut HashMap<String, CortexType>, param_name: &String, st_str: &String) -> Result<(), CortexError> {
1227        let correct;
1228        match (&param_type, arg_type) {
1229            (CortexType::BasicType(b), arg_type) => {
1230                if let Some(name) = TypeEnvironment::does_arg_list_contain(type_param_names, &param_type) {
1231                    // If we take in a T? and passing a number?, then we want T = number, not T = number?
1232                    let mut bound_type = arg_type.clone();
1233                    if b.optional {
1234                        bound_type = bound_type.to_non_optional();
1235                    }
1236                    if b.type_args.len() > 0 {
1237                        return Err(Box::new(PreprocessingError::CannotHaveTypeArgsOnGeneric(param_type.codegen(0))));
1238                    }
1239                    if let Some(existing_binding) = bindings.get(name) {
1240                        let combined = bound_type.combine_with(existing_binding.clone());
1241                        if let Some(result) = combined {
1242                            bindings.insert(name.clone(), result);
1243                            correct = true;
1244                        } else {
1245                            correct = false;
1246                        }
1247                    } else {
1248                        bindings.insert(name.clone(), bound_type);
1249                        correct = true;
1250                    }
1251                } else {
1252                    // Try to match up type args (ex. list<T> to list<number>)
1253                    // If both are not BasicType, then we just ignore this
1254                    if let CortexType::BasicType(b2) = arg_type {
1255                        if b.type_args.len() == b2.type_args.len() {
1256                            for (type_param, type_arg) in b.type_args.iter().zip(&b2.type_args) {
1257                                self.infer_arg(type_param, type_arg, type_param_names, bindings, param_name, st_str)?;
1258                            }
1259                            correct = true;
1260                        } else {
1261                            correct = false;
1262                        }
1263                    } else {
1264                        correct = true;
1265                    }
1266                }
1267            },
1268            (CortexType::RefType(r), CortexType::RefType(r2)) => {
1269                self.infer_arg(&*r.contained, &*r2.contained, type_param_names, bindings, param_name, st_str)?;
1270                correct = true;
1271            },
1272            (CortexType::TupleType(t1), CortexType::TupleType(t2)) => {
1273                if t1.types.len() == t2.types.len() {
1274                    for (type1, type2) in t1.types.iter().zip(&t2.types) {
1275                        self.infer_arg(type1, type2, type_param_names, bindings, param_name, st_str)?;
1276                    }
1277                    correct = true;
1278                } else {
1279                    correct = false;
1280                }
1281            },
1282            (_, _) => {
1283                correct = false;
1284            },
1285        }
1286        if correct {
1287            Ok(())
1288        } else {
1289            Err(Box::new(PreprocessingError::MismatchedType(param_type.codegen(0), arg_type.codegen(0), param_name.clone(), st_str.clone())))
1290        }
1291    }
1292
1293    fn search_struct_for_loops(&self, s: &Struct) -> Result<bool, CortexError> {
1294        match &s.name {
1295            OptionalIdentifier::Ident(name) => {
1296                let stype = CortexType::basic(PathIdent::simple(name.clone()), false, forwarded_type_args(&s.type_param_names));
1297                let mut q = VecDeque::new();
1298                for field in &s.fields {
1299                    q.push_back(field.1.clone());
1300                }
1301                // Only need to search for references to this struct, everything else should be fine
1302                while !q.is_empty() {
1303                    let typ = q.pop_front().unwrap();
1304                    if typ == stype {
1305                        return Ok(true);
1306                    }
1307                    if !typ.is_core() {
1308                        // Enqueue all fields of this type
1309                        let typ_name = typ.name()?;
1310
1311                        // It's ok if the struct doesn't exist yet
1312                        // If it has loops, then they will be caught when we visit this function upon registering it
1313                        // Unfortunately, the order in which structs are added is not deterministic
1314                        if self.has_type(typ_name) {
1315                            let struc = self.lookup_type(typ_name)?;
1316                            for field in &struc.fields {
1317                                q.push_back(field.1.clone());
1318                            }
1319                        }
1320                    }
1321                }
1322                Ok(false)
1323            },
1324            OptionalIdentifier::Ignore => Ok(false),
1325        }
1326    }
1327
1328    fn get_variable_type(&self, path: &PathIdent) -> Result<CortexType, CortexError> {
1329        if path.is_final() {
1330            // Search in our environment for it
1331            let front = path.get_front()?;
1332            Ok(self.current_env.as_ref().unwrap().get(front)?.clone())
1333        } else {
1334            Err(Box::new(PreprocessingError::ValueNotFound(path.codegen(0))))
1335        }
1336    }
1337
1338    fn has_function(&self, path: &FunctionAddress) -> bool {
1339        let full_path: FunctionAddress = FunctionAddress::concat(&self.current_context, &path);
1340        self.function_signature_map.contains_key(&full_path)
1341    }
1342    fn lookup_signature(&self, path: &FunctionAddress) -> Result<&FunctionSignature, CortexError> {
1343        let full_path: FunctionAddress = FunctionAddress::concat(&self.current_context, &path);
1344        if let Some(sig) = self.function_signature_map.get(&full_path) {
1345            Ok(sig)
1346        } else {
1347            Err(Box::new(PreprocessingError::FunctionDoesNotExist(full_path.codegen(0))))
1348        }
1349    }
1350
1351    fn lookup_type(&self, path: &PathIdent) -> Result<&TypeDefinition, CortexError> {
1352        let full_path = PathIdent::concat(&self.current_context, &path);
1353        if let Some(c) = self.type_map.get(&full_path) {
1354            Ok(c)
1355        } else {
1356            Err(Box::new(PreprocessingError::TypeDoesNotExist(full_path.codegen(0))))
1357        }
1358    }
1359    fn has_type(&self, path: &PathIdent) -> bool {
1360        let full_path = PathIdent::concat(&self.current_context, &path);
1361        self.type_map.contains_key(&full_path)
1362    }
1363
1364    fn next_temp(&mut self) -> String {
1365        let res = format!("$temp{}", self.temp_num);
1366        self.temp_num += 1;
1367        res
1368    }
1369}