cortex_lang/preprocessing/
preprocessor.rs

1use std::{collections::{HashMap, HashSet, VecDeque}, error::Error, rc::Rc};
2
3use crate::parsing::{ast::{expression::{BinaryOperator, ConditionBody, Expression, OptionalIdentifier, Parameter, PathIdent, UnaryOperator}, statement::Statement, top_level::{BasicBody, Body, Bundle, Function, FunctionSignature, Struct, ThisArg, TopLevel}, r#type::{forwarded_type_args, CortexType}}, codegen::r#trait::SimpleCodeGen};
4
5use super::{ast::{expression::RExpression, function::{FunctionDict, RBody, RFunction, RInterpretedBody}, statement::{RConditionBody, RStatement}}, error::PreprocessingError, module::{CompositeType, Module, ModuleError}, 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<PathIdent, FunctionSignature>,
16    composite_map: HashMap<PathIdent, CompositeType>,
17}
18
19impl CortexPreprocessor {
20    pub fn new() -> Result<Self, CortexError> {
21        let mut this = CortexPreprocessor {
22            current_env: Some(Box::new(TypeCheckingEnvironment::base())),
23            current_context: PathIdent::empty(),
24            current_type_env: Some(Box::new(TypeEnvironment::base())),
25            function_dict: FunctionDict::new(),
26            function_signature_map: HashMap::new(),
27            composite_map: HashMap::new(),
28        };
29
30        let mut global_module = Module::new();
31        Self::add_list_funcs(&mut global_module)?;
32        Self::add_string_funcs(&mut global_module)?;
33
34        this.register_module(&PathIdent::empty(), global_module)?;
35
36        Ok(this)
37    }
38
39    pub(crate) fn get_function(&self, id: usize) -> Option<&Rc<RFunction>> {
40        self.function_dict.get(id)
41    }
42
43    pub(crate) fn determine_type(&mut self, expr: Expression) -> Result<CortexType, CortexError> {
44        let (_, typ) = self.check_exp(expr)?;
45        Ok(typ)
46    }
47
48    pub fn run_top_level(&mut self, top_level: TopLevel) -> Result<(), CortexError> {
49        match top_level {
50            TopLevel::Import { name: _, is_string_import: _ } => {
51                todo!("Imports are currently not supported!")
52            },
53            TopLevel::Module { name, contents } => {
54                let module = Self::construct_module(contents)?;
55                self.register_module(&PathIdent::simple(name), module)?;
56                Ok(())
57            },
58            TopLevel::Function(function) => {
59                self.add_signature(PathIdent::empty(), &function)?;
60                self.add_function(PathIdent::empty(), function)?;
61                Ok(())
62            },
63            TopLevel::Struct(struc) => {
64                self.add_struct(PathIdent::empty(), struc)?;
65                Ok(())
66            },
67            TopLevel::Bundle(bundle) => {
68                let mut funcs = Vec::new();
69                self.add_bundle(PathIdent::empty(), bundle, &mut funcs)?;
70                for f in &funcs {
71                    self.add_signature(PathIdent::empty(), &f)?;
72                }
73                for f in funcs {
74                    self.add_function(PathIdent::empty(), f)?;
75                }
76                Ok(())
77            },
78        }
79    }
80
81    pub fn register_module(&mut self, path: &PathIdent, mut module: Module) -> Result<(), CortexError> {
82        for (path_end, m) in module.children_iter() {
83            let this_path = PathIdent::continued(path.clone(), path_end);
84            self.register_module(&this_path, m)?;
85        }
86
87        let mut functions = module.take_functions()?;
88        let structs = module.take_structs()?;
89        let bundles = module.take_bundles()?;
90
91        let context_to_return_to = std::mem::replace(&mut self.current_context, path.clone());
92
93        for item in structs {
94            self.add_struct(path.clone(), item)?;
95        }
96
97        for item in bundles {
98            self.add_bundle(path.clone(), item, &mut functions)?;
99        }
100
101        for f in &functions {
102            self.add_signature(path.clone(), f)?;
103        }
104
105        for f in functions {
106            self.add_function(path.clone(), f)?;
107        }
108        self.current_context = context_to_return_to;
109
110        Ok(())
111    }
112
113    fn add_signature(&mut self, n: PathIdent, f: &Function) -> Result<(), CortexError> {
114        let sig = f.signature();
115        match f.name() {
116            OptionalIdentifier::Ident(func_name) => {
117                let full_path = PathIdent::continued(n, func_name.clone());
118                if self.function_signature_map.contains_key(&full_path) {
119                    return Err(Box::new(ModuleError::FunctionAlreadyExists(func_name.clone())));
120                }
121                let mut seen_type_param_names = HashSet::new();
122                for t in &sig.type_param_names {
123                    if seen_type_param_names.contains(t) {
124                        return Err(Box::new(ModuleError::DuplicateTypeArgumentName(t.clone())));
125                    }
126                    seen_type_param_names.insert(t);
127                }
128                self.function_signature_map.insert(full_path.clone(), sig);
129            },
130            OptionalIdentifier::Ignore => {},
131        }
132        Ok(())
133    }
134    fn add_function(&mut self, n: PathIdent, f: Function) -> Result<(), CortexError> {
135        let name = f.name().clone();
136        let processed = self.preprocess_function(f)?;
137        match name {
138            OptionalIdentifier::Ident(func_name) => {
139                let full_path = PathIdent::continued(n, func_name.clone());
140                self.function_dict.add_function(full_path, processed);
141            },
142            OptionalIdentifier::Ignore => {},
143        }
144        Ok(())
145    }
146    fn add_struct(&mut self, n: PathIdent, item: Struct) -> Result<(), CortexError> {
147        match &item.name {
148            OptionalIdentifier::Ident(item_name) => {
149                let full_path = PathIdent::continued(n, item_name.clone());
150                if self.has_composite(&full_path) {
151                    Err(Box::new(ModuleError::TypeAlreadyExists(full_path.codegen(0))))
152                } else {
153                    let has_loop = self.search_struct_for_loops(&item)?;
154                    if has_loop {
155                        Err(Box::new(ModuleError::StructContainsCircularFields(full_path.codegen(0))))
156                    } else {
157                        let mut seen_type_param_names = HashSet::new();
158                        for t in &item.type_param_names {
159                            if seen_type_param_names.contains(t) {
160                                return Err(Box::new(ModuleError::DuplicateTypeArgumentName(t.clone())));
161                            }
162                            seen_type_param_names.insert(t);
163                        }
164
165                        self.composite_map.insert(full_path, CompositeType {
166                            fields: item.fields,
167                            is_heap_allocated: false,
168                            type_param_names: item.type_param_names,
169                        });
170                        Ok(())
171                    }
172                }
173            },
174            OptionalIdentifier::Ignore => Ok(()),
175        }
176    }
177    pub fn add_bundle(&mut self, n: PathIdent, item: Bundle, funcs_to_add: &mut Vec<Function>) -> Result<(), CortexError> {
178        match &item.name {
179            OptionalIdentifier::Ident(item_name) => {
180                let full_path = PathIdent::continued(n, item_name.clone());
181                if let Ok(_) = self.lookup_composite(&full_path) {
182                    Err(Box::new(ModuleError::TypeAlreadyExists(full_path.codegen(0))))
183                } else {
184                    for func in item.functions {
185                        match func.name {
186                            OptionalIdentifier::Ident(func_name) => {
187                                let new_param = Parameter::named(
188                                    "this", 
189                                    CortexType::reference(
190                                        CortexType::basic(PathIdent::simple(item_name.clone()), false, forwarded_type_args(&item.type_param_names)),
191                                        func.this_arg == ThisArg::MutThis
192                                    ));
193                                let mut param_list = vec![new_param];
194                                param_list.extend(func.params);
195                                let mut type_param_names = func.type_param_names;
196                                let intersecting_type_param = item.type_param_names.iter().find(|t| type_param_names.contains(t));
197                                if let Some(name) = intersecting_type_param {
198                                    return Err(Box::new(ModuleError::DuplicateTypeArgumentName(name.clone())));
199                                }
200                                type_param_names.extend(item.type_param_names.clone());
201                                let new_func = Function::new(
202                                    OptionalIdentifier::Ident(Bundle::get_bundle_func_name(item_name, &func_name)),
203                                    param_list,
204                                    func.return_type,
205                                    func.body,
206                                    type_param_names,
207                                );
208                                funcs_to_add.push(new_func);
209                            },
210                            OptionalIdentifier::Ignore => (),
211                        }
212                    }
213
214                    let mut seen_type_param_names = HashSet::new();
215                    for t in &item.type_param_names {
216                        if seen_type_param_names.contains(t) {
217                            return Err(Box::new(ModuleError::DuplicateTypeArgumentName(t.clone())));
218                        }
219                        seen_type_param_names.insert(t);
220                    }
221
222                    self.composite_map.insert(full_path, CompositeType {
223                        fields: item.fields,
224                        is_heap_allocated: true,
225                        type_param_names: item.type_param_names,
226                    });
227                    Ok(())
228                }
229            },
230            OptionalIdentifier::Ignore => Ok(()),
231        }
232    }
233
234    pub fn preprocess(&mut self, body: BasicBody) -> Result<Program, CortexError> {
235        let (body, _) = self.check_body(body)?;
236        Ok(Program { code: body })
237    }
238
239    fn construct_module(contents: Vec<TopLevel>) -> Result<Module, CortexError> {
240        let mut module = Module::new();
241        for item in contents.into_iter() {
242            match item {
243                TopLevel::Import { name: _, is_string_import: _ } => todo!("Imports are currently not supported!"),
244                TopLevel::Module { name: submod_name, contents } => {
245                    let new_module = Self::construct_module(contents)?;
246                    module.add_child(submod_name, new_module)?;
247                },
248                TopLevel::Function(function) => {
249                    module.add_function(function)?;
250                },
251                TopLevel::Struct(item) => {
252                    module.add_struct(item)?;
253                },
254                TopLevel::Bundle(item) => {
255                    module.add_bundle(item)?;
256                },
257            }
258        }
259        Ok(module)
260    }
261
262    pub fn preprocess_function(&mut self, function: Function) -> Result<RFunction, CortexError> {
263        let parent_env = self.current_env.take().ok_or(PreprocessingError::NoParentEnv)?;
264        let mut new_env = TypeCheckingEnvironment::new(*parent_env);
265        let mut params = Vec::new();
266        for p in function.params {
267            let param_type = self.clean_type(p.typ.clone().with_prefix_if_not_core(&self.current_context));
268            new_env.add(p.name.clone(), param_type, false)?;
269            params.push(p.name);
270        }
271        self.current_env = Some(Box::new(new_env));
272
273        // Do check body
274        let final_fn_body;
275        match function.body {
276            Body::Basic(body) => {
277                let (new_body, body_type) = self.check_body(body)?;
278                let return_type = self.clean_type(function.return_type.clone().with_prefix_if_not_core(&self.current_context));
279                if !body_type.is_subtype_of(&return_type) {
280                    return Err(Box::new(PreprocessingError::ReturnTypeMismatch(return_type.codegen(0), body_type.codegen(0))));
281                }
282                final_fn_body = RBody::Interpreted(new_body);
283            },
284            Body::Native(native_body) => {
285                final_fn_body = RBody::Native(native_body);
286            },
287        }
288
289        self.current_env = Some(Box::new(self.current_env.take().unwrap().exit()?));
290
291        Ok(RFunction::new(params, final_fn_body))
292    }
293
294    fn check_statement(&mut self, statement: Statement) -> Result<RStatement, CortexError> {
295        match statement {
296            Statement::Expression(expression) => {
297                let (exp, _) = self.check_exp(expression)?;
298                Ok(RStatement::Expression(exp))
299            },
300            Statement::Throw(expression) => {
301                let (exp, _) = self.check_exp(expression)?;
302                Ok(RStatement::Throw(exp))
303            },
304            Statement::VariableDeclaration { name, is_const, typ, initial_value } => {
305                match name {
306                    OptionalIdentifier::Ident(ident) => {
307                        let (assigned_exp, assigned_type) = self.check_exp(initial_value)?;
308                        let type_of_var = if let Some(mut declared_type) = typ {
309                            declared_type = self.clean_type(declared_type.with_prefix_if_not_core(&self.current_context));
310                            if !assigned_type.is_subtype_of(&declared_type) {
311                                return Err(
312                                    Box::new(
313                                        PreprocessingError::MismatchedType(
314                                            declared_type.codegen(0),
315                                            assigned_type.codegen(0),
316                                            ident.clone(),
317                                        )
318                                    )
319                                );
320                            }
321                            declared_type.clone()
322                        } else {
323                            assigned_type
324                        };
325
326                        self.current_env.as_mut().unwrap().add(ident.clone(), type_of_var, is_const)?;
327
328                        Ok(RStatement::VariableDeclaration { name: ident, is_const: is_const, initial_value: assigned_exp })
329                    },
330                    OptionalIdentifier::Ignore => {
331                        let (exp, _) = self.check_exp(initial_value)?;
332                        Ok(RStatement::Expression(exp))
333                    },
334                }
335            },
336            Statement::Assignment { name, value } => {
337                let (assigned_exp, assigned_type) = self.check_exp(value)?;
338                if name.is_simple() {
339                    let var_name = &name.base;
340                    let var_type = &self.current_env.as_ref().unwrap().get(var_name)?.clone();
341                    if !assigned_type.is_subtype_of(var_type) {
342                        return Err(
343                            Box::new(
344                                PreprocessingError::MismatchedType(
345                                    var_type.codegen(0),
346                                    assigned_type.codegen(0),
347                                    var_name.clone(),
348                                )
349                            )
350                        );
351                    }
352                    
353                    if self.current_env.as_ref().unwrap().is_const(var_name)? {
354                        return Err(
355                            Box::new(
356                                PreprocessingError::CannotModifyConst(var_name.clone())
357                            )
358                        )
359                    }
360                } else {
361                    let source_expr = name.clone().without_last()?.to_member_access_expr();
362                    let (_, source_type) = self.check_exp(source_expr)?;
363                    if let CortexType::RefType { contained, mutable } = source_type {
364                        if !mutable {
365                            return Err(
366                                Box::new(
367                                    PreprocessingError::CannotModifyFieldOnImmutableReference(contained.codegen(0))
368                                )
369                            );
370                        }
371                    }
372
373                    let name_expr = name.clone().to_member_access_expr();
374                    let (_, var_type) = self.check_exp(name_expr)?;
375                    let chain = name.chain.clone();
376                    if !assigned_type.is_subtype_of(&var_type) {
377                        return Err(
378                            Box::new(
379                                PreprocessingError::MismatchedType(
380                                    var_type.codegen(0),
381                                    assigned_type.codegen(0),
382                                    chain.last().unwrap().clone(),
383                                )
384                            )
385                        );
386                    }
387                }
388
389                Ok(RStatement::Assignment { name: name.into(), value: assigned_exp })
390            },
391            Statement::WhileLoop(condition_body) => {
392                let (cond, cond_type) = self.check_exp(condition_body.condition)?;
393                if !cond_type.is_subtype_of(&CortexType::boolean(false)) {
394                    return Err(
395                        Box::new(
396                            PreprocessingError::MismatchedType(
397                                String::from("bool"),
398                                cond_type.codegen(0),
399                                String::from("while condition"),
400                            )
401                        )
402                    );
403                }
404
405                let (body, body_type) = self.check_body(condition_body.body)?;
406                if !body_type.is_subtype_of(&CortexType::void(false)) {
407                    return Err(
408                        Box::new(
409                            PreprocessingError::LoopCannotHaveReturnValue
410                        )
411                    );
412                }
413
414                Ok(RStatement::WhileLoop(RConditionBody::new(cond, body)))
415            },
416        }
417    }
418
419    fn check_exp(&mut self, exp: Expression) -> CheckResult<RExpression> {
420        match exp {
421            Expression::Number(v) => Ok((RExpression::Number(v), CortexType::number(false))),
422            Expression::Boolean(v) => Ok((RExpression::Boolean(v), CortexType::boolean(false))),
423            Expression::Void => Ok((RExpression::Void, CortexType::void(false))),
424            Expression::None => Ok((RExpression::None, CortexType::none())),
425            Expression::String(v) => Ok((RExpression::String(v), CortexType::string(false))),
426            Expression::PathIdent(path_ident) => Ok((RExpression::Identifier(path_ident.get_back()?.clone()), self.lookup_type(&path_ident)?)),
427            Expression::Call(path, arg_exps) => {
428                let extended = PathIdent::concat(&self.current_context, &path.without_last());
429                let context_to_return_to = std::mem::replace(&mut self.current_context, extended);
430                let function_name = path.get_back()?;
431                let result = self.check_call(PathIdent::simple(function_name.clone()), arg_exps);
432                self.current_context = context_to_return_to;
433                result
434            },
435            Expression::Construction { name, type_args, assignments } => {
436                self.check_construction(name, type_args, assignments)
437            },
438            Expression::IfStatement { first, conds, last } => {
439                self.check_if_statement(*first, conds, last.map(|b| *b))
440            },
441            Expression::UnaryOperation { op, exp } => {
442                let (exp, typ) = self.check_exp(*exp)?;
443                match op {
444                    UnaryOperator::Negate => {
445                        if typ == CortexType::number(false) {
446                            Ok((RExpression::UnaryOperation { op: UnaryOperator::Negate, exp: Box::new(exp) }, CortexType::number(false)))
447                        } else {
448                            Err(Box::new(PreprocessingError::InvalidOperatorUnary("number")))
449                        }
450                    },
451                    UnaryOperator::Invert => {
452                        if typ == CortexType::boolean(false) {
453                            Ok((RExpression::UnaryOperation { op: UnaryOperator::Invert, exp: Box::new(exp) }, CortexType::boolean(false)))
454                        } else {
455                            Err(Box::new(PreprocessingError::InvalidOperatorUnary("bool")))
456                        }
457                    },
458                }
459            },
460            Expression::ListLiteral(items) => {
461                let mut contained_type = CortexType::Unknown(false);
462                let mut new_items = Vec::new();
463                for item in items {
464                    let (item_exp, item_type) = self.check_exp(item)?;
465                    let item_type_str = item_type.codegen(0);
466                    let typ_str = contained_type.codegen(0);
467                    contained_type = contained_type
468                        .combine_with(item_type)
469                        .ok_or(PreprocessingError::CannotDetermineListLiteralType(typ_str, item_type_str))?;
470                    new_items.push(item_exp);
471                }
472                let true_type = CortexType::reference(CortexType::list(contained_type, false), true);
473                Ok((RExpression::ListLiteral(new_items), true_type))
474            },
475            Expression::Bang(inner) => {
476                let (exp, typ) = self.check_exp(*inner)?;
477                Ok((RExpression::Bang(Box::new(exp)), typ.to_non_optional()))
478            },
479            Expression::MemberAccess(inner, member) => {
480                let (atom_exp, atom_type) = self.check_exp(*inner)?;
481                if atom_type.is_non_composite() {
482                    return Err(Box::new(PreprocessingError::CannotAccessMemberOfNonComposite));
483                }
484                let is_mutable;
485                match &atom_type {
486                    CortexType::BasicType { optional: _, name: _, type_args: _ } => {
487                        is_mutable = true;
488                    },
489                    CortexType::RefType { contained: _, mutable } => {
490                        is_mutable = *mutable;
491                    },
492                    CortexType::Unknown(_) => {
493                        return Err(Box::new(PreprocessingError::UnknownTypeFound));
494                    },
495                }
496                let composite = self.lookup_composite(&atom_type.name()?.clone().subtract(&self.current_context)?)?;
497                if !composite.fields.contains_key(&member) {
498                    Err(Box::new(PreprocessingError::FieldDoesNotExist(member.clone(), atom_type.codegen(0))))
499                } else {
500                    let mut member_type = composite.fields.get(&member).unwrap().clone();
501                    let bindings = Self::get_bindings(&composite.type_param_names, &atom_type)?;
502                    member_type = TypeEnvironment::fill(member_type, 
503                        &bindings
504                            .into_iter()
505                            .map(|(k, v)| (k, v.subtract_if_possible(&atom_type.prefix())))
506                            .collect::<HashMap<_, _>>()
507                        );
508                    member_type = member_type.with_prefix_if_not_core(&atom_type.prefix());
509                    member_type = member_type.forward_immutability(is_mutable);
510                    Ok((RExpression::MemberAccess(Box::new(atom_exp), member), member_type))
511                }
512            },
513            Expression::MemberCall { callee, member, mut args } => {
514                let (_, atom_type) = self.check_exp(*callee.clone())?;
515                let caller_type = atom_type.name()?;
516                let caller_func_prefix = caller_type.without_last();
517                let caller_func_base = caller_type.get_back()?;
518                let member_func_name = Bundle::get_bundle_func_name(caller_func_base, &member);
519                let member_func_path = PathIdent::continued(caller_func_prefix.clone(), member_func_name)
520                    .subtract(&self.current_context)?;
521                args.insert(0, *callee);
522                let call_exp = Expression::Call(member_func_path, args);
523                let result = self.check_exp(call_exp)?;
524                Ok(result)
525            },
526            Expression::BinaryOperation { left, op, right } => {
527                let (left_exp, left_type) = self.check_exp(*left)?;
528                let (right_exp, right_type) = self.check_exp(*right)?;
529                let op_type = self.check_operator(left_type, &op, right_type)?;
530                Ok((RExpression::BinaryOperation { left: Box::new(left_exp), op: op, right: Box::new(right_exp) }, op_type))
531            },
532        }
533    }
534    fn check_call(&mut self, path_ident: PathIdent, arg_exps: Vec<Expression>) -> CheckResult<RExpression> {
535        let provided_arg_count = arg_exps.len();
536        let mut processed_args = Vec::new();
537        let mut arg_types = Vec::new();
538        for a in arg_exps.into_iter() {
539            let (arg, typ) = self.check_exp(a)?;
540            arg_types.push(typ);
541            processed_args.push(arg);
542        }
543        
544        let sig = self.lookup_signature(&path_ident)?.clone();
545
546        let full_path = PathIdent::concat(&self.current_context, &path_ident);
547        if provided_arg_count != sig.params.len() {
548            return Err(Box::new(
549                PreprocessingError::MismatchedArgumentCount(full_path.codegen(0), sig.params.len(), provided_arg_count)
550            ));
551        }
552
553        let mut return_type = sig
554            .return_type
555            .clone();
556
557        let mut param_names = Vec::<String>::with_capacity(sig.params.len());
558        let mut param_types = Vec::<CortexType>::with_capacity(sig.params.len());
559        for param in &sig.params {
560            param_names.push(param.name.clone());
561            param_types.push(param.typ.clone());
562        }
563
564        let bindings = self.infer_type_args(&sig, &arg_types, &full_path)?;
565        let parent_type_env = self.current_type_env.take().ok_or(PreprocessingError::NoParentEnv)?;
566        let mut new_type_env = TypeEnvironment::new(*parent_type_env);
567        for (name, typ) in &bindings {
568            new_type_env.add(name.clone(), typ.clone());
569        }
570        self.current_type_env = Some(Box::new(new_type_env));
571
572        for (i, arg_type) in arg_types.into_iter().enumerate() {
573            let arg_type = self.clean_type(arg_type);
574            let param_type = self.clean_type(param_types.get(i).unwrap().clone().with_prefix_if_not_core(&self.current_context));
575            if !arg_type.is_subtype_of(&param_type) {
576                return Err(
577                    Box::new(
578                        PreprocessingError::MismatchedType(
579                            param_type.codegen(0),
580                            arg_type.codegen(0),
581                            param_names.get(i).unwrap().clone(),
582                        )
583                    )
584                );
585            }
586        }
587
588        return_type = self.clean_type(return_type)
589            .with_prefix_if_not_core(&self.current_context);
590
591        self.current_type_env = Some(Box::new(self.current_type_env.take().unwrap().exit()?));
592
593        let func_id = self.function_dict.add_call(full_path)?;
594
595        Ok((RExpression::Call(func_id, processed_args), return_type))
596    }
597    fn check_construction(&mut self, name: PathIdent, type_args: Vec<CortexType>, assignments: Vec<(String, Expression)>) -> CheckResult<RExpression> {
598        let composite = self.lookup_composite(&name)?;
599        let base_type = CortexType::basic(name.clone(), false, type_args.clone()).with_prefix_if_not_core(&self.current_context);
600
601        if type_args.len() != composite.type_param_names.len() {
602            return Err(Box::new(PreprocessingError::MismatchedTypeArgCount(name.codegen(0), composite.type_param_names.len(), type_args.len())));
603        }
604        let mut fields_to_assign = Vec::new();
605        for k in composite.fields.keys() {
606            fields_to_assign.push(k.clone());
607        }
608
609        let is_heap_allocated = composite.is_heap_allocated;
610        let fields = composite.fields.clone();
611
612        let bindings = TypeEnvironment::create_bindings(&composite.type_param_names, &type_args);
613        let bindings = bindings
614            .iter()
615            .map(|(k, v)| (k.clone(), v.clone().subtract_if_possible(&name.without_last())))
616            .collect::<HashMap<_, _>>();
617        let mut new_assignments = Vec::new();
618        for (fname, fvalue) in assignments {
619            let opt_typ = fields
620                .get(&fname)
621                .map(|t| t.clone());
622            if let Some(typ) = opt_typ {
623                let field_type = TypeEnvironment::fill(typ, &bindings)
624                    .with_prefix_if_not_core(&self.current_context)
625                    .with_prefix_if_not_core(&name.without_last());
626                let (exp, assigned_type) = self.check_exp(fvalue)?;
627                if !assigned_type.is_subtype_of(&field_type) {
628                    return Err(
629                        Box::new(
630                            PreprocessingError::MismatchedType(
631                                field_type.codegen(0),
632                                assigned_type.codegen(0),
633                                fname.clone(),
634                            )
635                        )
636                    );
637                }
638
639                new_assignments.push((fname.clone(), exp));
640
641                let index_opt = fields_to_assign.iter().position(|x| *x == *fname);
642                if let Some(index) = index_opt {
643                    fields_to_assign.remove(index);
644                } else {
645                    return Err(Box::new(PreprocessingError::MultipleFieldAssignment(fname.clone())));
646                }
647            } else {
648                return Err(Box::new(PreprocessingError::FieldDoesNotExist(fname.clone(), name.codegen(0))));
649            }
650        }
651
652        if fields_to_assign.is_empty() {
653            if is_heap_allocated {
654                Ok((RExpression::Construction { assignments: new_assignments, is_heap_allocated: true }, CortexType::reference(base_type, true)))
655            } else {
656                Ok((RExpression::Construction { assignments: new_assignments, is_heap_allocated: false }, base_type))
657            }
658        } else {
659            Err(Box::new(PreprocessingError::NotAllFieldsAssigned(name.codegen(0), fields_to_assign.join(","))))
660        }
661    }
662    fn check_if_statement(&mut self, first: ConditionBody, conds: Vec<ConditionBody>, last: Option<BasicBody>) -> CheckResult<RExpression> {
663        let (cond_exp, cond_typ) = self.check_exp(first.condition)?;
664        if cond_typ != CortexType::boolean(false) {
665            return Err(
666                Box::new(
667                    PreprocessingError::MismatchedType(
668                        String::from("bool"),
669                        cond_typ.codegen(0),
670                        String::from("if condition"),
671                    )
672                )
673            );
674        }
675        let (first_body, mut the_type) = self.check_body(first.body)?;
676        
677        let mut condition_bodies = Vec::<RConditionBody>::new();
678        for c in conds {
679            let (cond, cond_typ) = self.check_exp(c.condition)?;
680            if !cond_typ.is_subtype_of(&CortexType::boolean(false)) {
681                return Err(
682                    Box::new(
683                        PreprocessingError::MismatchedType(
684                            String::from("bool"),
685                            cond_typ.codegen(0),
686                            String::from("else-if condition"),
687                        )
688                    )
689                );
690            }
691            let (body, typ) = self.check_body(c.body)?;
692            let the_type_str = the_type.codegen(0);
693            let typ_str = typ.codegen(0);
694            let next = the_type.combine_with(typ);
695            if let Some(t) = next {
696                the_type = t;
697                condition_bodies.push(RConditionBody::new(cond, body));
698            } else {
699                return Err(Box::new(PreprocessingError::IfArmsDoNotMatch(the_type_str, typ_str)));
700            }
701        }
702        let mut final_body = None;
703        if let Some(fin) = last {
704            let (body, typ) = self.check_body(fin)?;
705            final_body = Some(Box::new(body));
706            let the_type_str = the_type.codegen(0);
707            let typ_str = typ.codegen(0);
708            let next = the_type.combine_with(typ);
709            if let Some(t) = next {
710                the_type = t;
711            } else {
712                return Err(Box::new(PreprocessingError::IfArmsDoNotMatch(the_type_str, typ_str)));
713            }
714        } else if the_type != CortexType::void(false) {
715            return Err(Box::new(PreprocessingError::IfRequiresElseBlock));
716        }
717
718        Ok((RExpression::IfStatement { 
719            first: Box::new(RConditionBody::new(cond_exp, first_body)),
720            conds: condition_bodies,
721            last: final_body,
722        }, the_type))
723    }
724
725    fn check_body(&mut self, body: BasicBody) -> CheckResult<RInterpretedBody> {
726        let mut statements = Vec::new();
727        for st in body.statements {
728            let s = self.check_statement(st)?;
729            statements.push(s);
730        }
731        if let Some(exp) = body.result {
732            let (exp, typ) = self.check_exp(exp)?;
733            Ok((RInterpretedBody::new(statements, Some(exp)), typ))
734        } else {
735            Ok((RInterpretedBody::new(statements, None), CortexType::void(false)))
736        }
737    }
738
739    fn check_operator(&self, first: CortexType, op: &BinaryOperator, second: CortexType) -> Result<CortexType, CortexError> {
740        let number = CortexType::number(false);
741        let string = CortexType::string(false);
742        let boolean = CortexType::boolean(false);
743        match op {
744            BinaryOperator::Add => {
745                if first == number && second == number {
746                    Ok(number)
747                } else if first == string && second == string {
748                    Ok(string)
749                } else {
750                    Err(Box::new(PreprocessingError::InvalidOperator("number, string", "number, string")))
751                }
752            },
753            BinaryOperator::Subtract => {
754                if first == number && second == number {
755                    Ok(number)
756                } else {
757                    Err(Box::new(PreprocessingError::InvalidOperator("number", "number")))
758                }
759            },
760            BinaryOperator::Multiply => {
761                if first == number && second == number {
762                    Ok(number)
763                } else if first == number && second == string {
764                    Ok(string)
765                } else if first == string && second == number {
766                    Ok(string)
767                } else {
768                    Err(Box::new(PreprocessingError::InvalidOperator("number", "string")))
769                }
770            },
771            BinaryOperator::Divide => {
772                if first == number && second == number {
773                    Ok(number)
774                } else {
775                    Err(Box::new(PreprocessingError::InvalidOperator("number", "number")))
776                }
777            },
778            BinaryOperator::Remainder => {
779                if first == number && second == number {
780                    Ok(number)
781                } else {
782                    Err(Box::new(PreprocessingError::InvalidOperator("number", "number")))
783                }
784            },
785            BinaryOperator::LogicAnd => {
786                if first == boolean && second == boolean {
787                    Ok(boolean)
788                } else {
789                    Err(Box::new(PreprocessingError::InvalidOperator("boolean", "boolean")))
790                }
791            },
792            BinaryOperator::LogicOr => {
793                if first == boolean && second == boolean {
794                    Ok(boolean)
795                } else {
796                    Err(Box::new(PreprocessingError::InvalidOperator("boolean", "boolean")))
797                }
798            },
799            BinaryOperator::IsEqual => {
800                Ok(boolean)
801            },
802            BinaryOperator::IsNotEqual => {
803                Ok(boolean)
804            },
805            BinaryOperator::IsLessThan => {
806                if first == number && second == number {
807                    Ok(boolean)
808                } else {
809                    Err(Box::new(PreprocessingError::InvalidOperator("number", "number")))
810                }
811            },
812            BinaryOperator::IsGreaterThan => {
813                if first == number && second == number {
814                    Ok(boolean)
815                } else {
816                    Err(Box::new(PreprocessingError::InvalidOperator("number", "number")))
817                }
818            },
819            BinaryOperator::IsLessThanOrEqualTo => {
820                if first == number && second == number {
821                    Ok(boolean)
822                } else {
823                    Err(Box::new(PreprocessingError::InvalidOperator("number", "number")))
824                }
825            },
826            BinaryOperator::IsGreaterThanOrEqualTo => {
827                if first == number && second == number {
828                    Ok(boolean)
829                } else {
830                    Err(Box::new(PreprocessingError::InvalidOperator("number", "number")))
831                }
832            },
833        }
834    }
835
836    // "Cleans" type, for example replacing type arguments
837    fn clean_type(&self, typ: CortexType) -> CortexType {
838        self.current_type_env.as_ref().unwrap().fill_in(typ)
839    }
840
841    // Used to get bindings for a type (give param names and the concrete type)
842    fn get_bindings(type_param_names: &Vec<String>, typ: &CortexType) -> Result<HashMap<String, CortexType>, CortexError> {
843        let mut type_args_handled = false;
844        let mut typ = typ.clone();
845        let mut bindings = HashMap::new();
846        while !type_args_handled {
847            if let CortexType::BasicType { optional: _, name: _, type_args } = &typ {
848                bindings = TypeEnvironment::create_bindings(type_param_names, type_args);
849                typ = TypeEnvironment::fill(typ, &bindings);
850                type_args_handled = true;
851            } else if let CortexType::RefType { contained, mutable: _} = typ {
852                typ = *contained;
853            }
854        }
855        Ok(bindings)
856    }
857    fn infer_type_args(&self, sig: &FunctionSignature, args: &Vec<CortexType>, name: &PathIdent) -> Result<HashMap<String, CortexType>, CortexError> {
858        let mut bindings = HashMap::<String, CortexType>::new();
859        for (arg, param) in args.iter().zip(&sig.params) {
860            self.infer_arg(&param.typ, &arg, &sig.type_param_names, &mut bindings, param.name())?;
861        }
862
863        if bindings.len() != sig.type_param_names.len() {
864            Err(Box::new(PreprocessingError::CouldNotInferTypeBinding(name.codegen(0))))
865        } else {
866            Ok(bindings)
867        }
868    }
869    fn infer_arg(&self, param_type: &CortexType, arg_type: &CortexType, type_param_names: &Vec<String>, bindings: &mut HashMap<String, CortexType>, param_name: &String) -> Result<(), CortexError> {
870        let correct;
871        match (&param_type, arg_type) {
872            (CortexType::BasicType { optional, name: _, type_args }, arg_type) => {
873                if let Some(name) = TypeEnvironment::does_arg_list_contain(type_param_names, &param_type) {
874                    // If we take in a T? and passing a number?, then we want T = number, not T = number?
875                    let mut bound_type = arg_type.clone();
876                    if *optional {
877                        bound_type = bound_type.to_non_optional();
878                    }
879                    if type_args.len() > 0 {
880                        return Err(Box::new(PreprocessingError::CannotHaveTypeArgsOnGeneric(param_type.codegen(0))));
881                    }
882                    if let Some(existing_binding) = bindings.get(name) {
883                        let combined = bound_type.combine_with(existing_binding.clone());
884                        if let Some(result) = combined {
885                            bindings.insert(name.clone(), result);
886                            correct = true;
887                        } else {
888                            correct = false;
889                        }
890                    } else {
891                        bindings.insert(name.clone(), bound_type);
892                        correct = true;
893                    }
894                } else {
895                    // Try to match up type args (ex. list<T> to list<number>)
896                    // If both are not BasicType, then we just ignore this
897                    if let CortexType::BasicType { optional: _, name: _, type_args: type_args2 } = arg_type {
898                        if type_args.len() == type_args2.len() {
899                            for (type_param, type_arg) in type_args.iter().zip(type_args2) {
900                                self.infer_arg(type_param, type_arg, type_param_names, bindings, param_name)?;
901                            }
902                            correct = true;
903                        } else {
904                            correct = false;
905                        }
906                    } else {
907                        correct = true;
908                    }
909                }
910            },
911            (CortexType::RefType { contained, mutable: _ }, CortexType::RefType { contained: contained2, mutable: _ }) => {
912                self.infer_arg(contained, contained2, type_param_names, bindings, param_name)?;
913                correct = true;
914            },
915            (CortexType::RefType { contained: _, mutable: _ }, _) => {
916                // parameter is reference but arg is not a reference
917                correct = false;
918            },
919            (_, _) => {
920                correct = false;
921            },
922        }
923        if correct {
924            Ok(())
925        } else {
926            Err(Box::new(PreprocessingError::MismatchedType(param_type.codegen(0), arg_type.codegen(0), param_name.clone())))
927        }
928    }
929
930    fn search_struct_for_loops(&self, s: &Struct) -> Result<bool, CortexError> {
931        match &s.name {
932            OptionalIdentifier::Ident(name) => {
933                let stype = CortexType::basic(PathIdent::simple(name.clone()), false, forwarded_type_args(&s.type_param_names));
934                let mut q = VecDeque::new();
935                for field in &s.fields {
936                    q.push_back(field.1.clone());
937                }
938                // Only need to search for references to this struct, everything else should be fine
939                while !q.is_empty() {
940                    let typ = q.pop_front().unwrap();
941                    if typ == stype {
942                        return Ok(true);
943                    }
944                    if !typ.is_core() {
945                        // Enqueue all fields of this type
946                        let typ_name = typ.name().map_err(|e| ModuleError::TypeError(e))?;
947
948                        // It's ok if the struct doesn't exist yet
949                        // If it has loops, then they will be caught when we visit this function upon registering it
950                        // Unfortunately, the order in which structs are added is not deterministic
951                        if self.has_composite(typ_name) {
952                            let struc = self.lookup_composite(typ_name)?;
953                            for field in &struc.fields {
954                                q.push_back(field.1.clone());
955                            }
956                        }
957                    }
958                }
959                Ok(false)
960            },
961            OptionalIdentifier::Ignore => Ok(false),
962        }
963    }
964
965    fn lookup_type(&self, path: &PathIdent) -> Result<CortexType, CortexError> {
966        if path.is_final() {
967            // Search in our environment for it
968            let front = path.get_front()?;
969            Ok(self.current_env.as_ref().unwrap().get(front)?.clone())
970        } else {
971            Err(Box::new(PreprocessingError::ValueNotFound(path.codegen(0))))
972        }
973    }
974    
975    fn lookup_signature(&self, path: &PathIdent) -> Result<&FunctionSignature, CortexError> {
976        let full_path = PathIdent::concat(&self.current_context, &path);
977        if let Some(sig) = self.function_signature_map.get(&full_path) {
978            Ok(sig)
979        } else {
980            Err(Box::new(ModuleError::FunctionDoesNotExist(full_path.codegen(0))))
981        }
982    }
983
984    fn lookup_composite(&self, path: &PathIdent) -> Result<&CompositeType, CortexError> {
985        let full_path = PathIdent::concat(&self.current_context, &path);
986        if let Some(c) = self.composite_map.get(&full_path) {
987            Ok(c)
988        } else {
989            Err(Box::new(ModuleError::TypeDoesNotExist(full_path.codegen(0))))
990        }
991    }
992    fn has_composite(&self, path: &PathIdent) -> bool {
993        let full_path = PathIdent::concat(&self.current_context, &path);
994        self.composite_map.contains_key(&full_path)
995    }
996}