ryna/
context.rs

1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::collections::HashSet;
4use std::sync::Arc;
5use std::sync::Mutex;
6
7use colored::Colorize;
8use rustc_hash::FxHashMap;
9
10use crate::annotations::Annotation;
11use crate::cache::RynaCache;
12use crate::compilation::RynaInstruction;
13use crate::interfaces::Interface;
14use crate::interfaces::InterfaceBinaryOpHeader;
15use crate::interfaces::InterfaceConstraint;
16use crate::interfaces::InterfaceFunctionHeader;
17use crate::interfaces::InterfaceImpl;
18use crate::interfaces::InterfaceNaryOpHeader;
19use crate::interfaces::InterfaceUnaryOpHeader;
20use crate::interfaces::standard_interfaces;
21use crate::macros::RynaMacro;
22use crate::parser::Location;
23use crate::translation::load_optimized_opcodes;
24use crate::types::*;
25use crate::operations::*;
26use crate::object::*;
27use crate::functions::*;
28use crate::patterns::*;
29use crate::variable_map::VariableMap;
30
31/*
32                                                  ╒══════════════════╕
33    ============================================= │  IMPLEMENTATION  │ =============================================
34                                                  ╘══════════════════╛
35*/
36
37#[derive(Default, Clone)]
38pub struct RynaContext {
39    pub type_templates: Vec<TypeTemplate>, 
40    pub interfaces: Vec<Interface>,
41    pub interface_impls: Vec<InterfaceImpl>,
42
43    pub unary_ops: Vec<Operator>,
44    pub binary_ops: Vec<Operator>,
45    pub nary_ops: Vec<Operator>,
46    pub sorted_ops: Vec<Operator>,
47
48    pub functions: Vec<Function>,
49
50    pub macros: Vec<RynaMacro>,
51
52    pub variables: Vec<Object>,
53
54    pub var_map: VariableMap,
55    pub registers: Vec<usize>,
56    pub num_globals: usize,
57
58    pub lambdas: usize,
59    pub lambda_code_length: usize,
60    pub lambda_code: Vec<RynaInstruction>,
61    pub lambda_positions: HashMap<usize, usize>,
62
63    pub cache: RynaCache,
64
65    pub optimize: bool,
66    
67    pub module_name: Arc<String>,
68    pub module_path: String,
69    pub captured_output: RefCell<String>,
70    pub program_input: Vec<String>
71}
72
73impl RynaContext {
74
75    /*
76        ╒════════════════════════════╕
77        │ Type template manipulation │
78        ╘════════════════════════════╛
79    */
80
81    pub fn redefine_type(&mut self, l: Location, annotations: Vec<Annotation>, representation: String, params: Vec<String>, attributes: Vec<(String, Type)>, alias: Option<Type>, patterns: Vec<Pattern>, parser: Option<ParsingFunction>) -> Result<(), String> {
82        for t in self.type_templates.iter_mut() {
83            if t.name == representation {
84                *t = TypeTemplate {
85                    id: t.id,
86                    name: representation,
87                    params,
88                    location: l,
89                    annotations,
90                    attributes,
91                    alias,
92                    patterns,
93                    parser
94                };
95
96                return Ok(());
97            }
98        }
99
100        Err(format!("Class {} was not defined", representation))
101    }
102
103    pub fn define_type(&mut self, l: Location, annotations: Vec<Annotation>, representation: String, params: Vec<String>, attributes: Vec<(String, Type)>, alias: Option<Type>, patterns: Vec<Pattern>, parser: Option<ParsingFunction>) -> Result<(), String> {
104        for t in &self.type_templates {
105            if t.name == representation {
106                return Err(format!("Type \"{}\" is already defined", representation))
107            }
108        }
109
110        self.cache.class_id.insert(representation.clone(), Ok(self.type_templates.len()));
111
112        self.type_templates.push(TypeTemplate {
113            id: self.type_templates.len(),
114            name: representation,
115            params,
116            location: l,
117            annotations,
118            attributes,
119            alias,
120            patterns,
121            parser
122        });
123
124        Ok(())
125    }
126
127    pub fn redefine_interface(&mut self, l: Location, annotations: Vec<Annotation>, representation: String, params: Vec<String>, fns: Vec<InterfaceFunctionHeader>, uns: Vec<InterfaceUnaryOpHeader>, bin: Vec<InterfaceBinaryOpHeader>, nary: Vec<InterfaceNaryOpHeader>) -> Result<(), String> {
128        for i in self.interfaces.iter_mut() {
129            if i.name == representation {
130                *i = Interface {
131                    id: i.id,
132                    name: representation,
133                    params,
134                    location: l,
135                    annotations,
136                    fns,
137                    uns,
138                    bin,
139                    nary
140                };
141
142                return Ok(());
143            }
144        }
145
146        Err(format!("Interface {} was not defined", representation))
147    }
148
149    pub fn define_interface(&mut self, l: Location, annotations: Vec<Annotation>, representation: String, params: Vec<String>, fns: Vec<InterfaceFunctionHeader>, uns: Vec<InterfaceUnaryOpHeader>, bin: Vec<InterfaceBinaryOpHeader>, nary: Vec<InterfaceNaryOpHeader>) -> Result<(), String> {
150        for i in &self.interfaces {
151            if i.name == representation {
152                return Err(format!("Interface \"{}\" is already defined", representation))
153            }
154        }
155
156        self.cache.interface_id.insert(representation.clone(), Ok(self.interfaces.len()));
157
158        self.interfaces.push(Interface {
159            id: self.interfaces.len(),
160            name: representation,
161            params,
162            location: l,
163            annotations,
164            fns,
165            uns,
166            bin,
167            nary
168        });
169
170        Ok(())
171    }
172
173    pub fn define_interface_impl(&mut self, representation: String, templates: Vec<String>, mut tp: Type, mut t_args: Vec<Type>) -> Result<(), String> {
174        tp.compile_templates(&templates);
175        t_args.iter_mut().for_each(|t| {
176            t.compile_templates(&templates);
177        });
178
179        self.interface_impls.push(InterfaceImpl {
180            interface_id: self.get_interface_id(representation)?,
181            args: t_args,
182            interface_type: tp
183        });
184
185        Ok(())
186    }
187
188    /*
189        ╒══════════════════╕
190        │ Interface checks │
191        ╘══════════════════╛
192    */
193
194    /*
195        Theoretically this is not correct, but no "sane" program would countain more than this many templates and the compiler would probably crash anyway.
196        It is assumed that if you offset templates by this constant then the template indexes are free.
197    */
198    const FREE_TEMPLATE_OFFSET: usize = 10_000_000;
199
200    pub fn implements_interface(&self, t: &Type, constraint: &InterfaceConstraint, t_assignments: &mut HashMap<usize, Type>, t_deps: &mut HashMap<usize, HashSet<usize>>) -> bool {
201        let cons_and = Type::And(constraint.args.clone());
202
203        for i in &self.interface_impls {
204            if i.interface_id == constraint.id {
205                let mut int_type = i.interface_type.clone();
206                let mut int_args = Type::And(i.args.clone());
207
208                let max_key = t_assignments.keys().copied().map(|i| i as i32).max().unwrap_or(-1);
209                let max_tms = int_type.max_template().max(int_args.max_template()).max(max_key);
210
211                if max_tms >= 0 {
212                    int_type.offset_templates(max_tms as usize + Self::FREE_TEMPLATE_OFFSET);
213                    int_args.offset_templates(max_tms as usize + Self::FREE_TEMPLATE_OFFSET);    
214                }
215
216                let mut t_assignments_cpy = t_assignments.clone();
217                let mut t_deps_cpy = t_deps.clone();
218
219                let args_match = int_args.template_bindable_to(&cons_and, &mut t_assignments_cpy, &mut t_deps_cpy, self);
220                let type_matches = int_type.template_bindable_to(t, &mut t_assignments_cpy, &mut t_deps_cpy, self);
221    
222                if args_match && type_matches {
223                    *t_assignments = t_assignments_cpy;
224                    *t_deps = t_deps_cpy;
225                
226                    return true;
227                }
228            }
229        }
230
231        false
232    }
233
234    /*
235        ╒═════════════════════════════╕
236        │ Unary operator manipulation │
237        ╘═════════════════════════════╛
238    */
239
240    pub fn define_unary_operator(&mut self, representation: String, prefix: bool, precedence: usize) -> Result<(), String> {
241        for o in &self.unary_ops {
242            if let Operator::Unary{representation: r, ..} = o {
243                if *r == representation {
244                    return Err(format!("Unary operator \"{}\" is already defined", representation))
245                }
246            }
247        }
248
249        let op = Operator::Unary {
250            id: self.unary_ops.len(),
251            representation,
252            prefix,
253            precedence,
254            operations: vec!()
255        };
256
257        self.unary_ops.push(op.clone());
258
259        match self.sorted_ops.binary_search_by(|i| i.get_precedence().cmp(&precedence)) {
260            Ok(_) => return Err(format!("Precedence {} is already taken", precedence)),
261            Err(pos) => self.sorted_ops.insert(pos, op)
262        }
263
264        Ok(())
265    }
266
267    pub fn get_unary_operations(&self, id: usize, a: Type) -> Vec<&Operation<UnaryFunctionFn>> {
268        if let Operator::Unary{operations: o, ..} = &self.unary_ops[id] {
269            return o.iter().filter(|op_ov| a.bindable_to(&op_ov.args, self)).collect::<Vec<_>>();
270        }
271
272        vec!()
273    }
274
275    pub fn define_native_unary_operation(&mut self, id: usize, templates: usize, a: Type, ret: Type, f: fn(&Vec<Type>, &Type, Object) -> Result<Object, String>) -> Result<usize, String> {
276        self.define_unary_operation(Location::none(), vec!(), id, templates, a, ret, Some(f))
277    }
278
279    pub fn define_unary_operation(&mut self, l: Location, annot: Vec<Annotation>, id: usize, templates: usize, a: Type, ret: Type, f: OptUnaryFunctionFn) -> Result<usize, String> {
280        let op = &self.unary_ops[id];
281
282        if let Operator::Unary{operations: o, representation: r, ..} = op {
283            for op_ov in o { // Check subsumption
284                if a.bindable_to(&op_ov.args, self) {
285                    return Err(format!("Unary operation {}{} is subsumed by {}{}, so it cannot be defined", 
286                                        r.green(), a.get_name(self), r.green(), op_ov.args.get_name(self)));
287                }
288    
289                if op_ov.args.bindable_to(&a, self) {
290                    return Err(format!("Unary operation {}{} subsumes {}{}, so it cannot be defined", 
291                                        r.green(), a.get_name(self), r.green(), op_ov.args.get_name(self)));
292                }
293            }
294        }
295
296        if let Operator::Unary{operations: o, ..} = &mut self.unary_ops[id] {
297            o.push(Operation { 
298                location: l,
299                annotations: annot, 
300                templates: templates, 
301                args: a, 
302                ret: ret, 
303                operation: f 
304            });
305
306            Ok(o.len() - 1)
307        
308        } else {
309            unreachable!()
310        }
311
312    }
313
314    /*
315        ╒══════════════════════════════╕
316        │ Binary operator manipulation │
317        ╘══════════════════════════════╛
318    */
319
320    pub fn define_binary_operator(&mut self, representation: String, right_associative: bool, precedence: usize) -> Result<(), String> {
321        for o in &self.binary_ops {
322            if let Operator::Binary{representation: r, ..} = o {
323                if *r == representation {
324                    return Err(format!("Binary operator \"{}\" is already defined", representation))
325                }
326            }
327        }
328
329        let op = Operator::Binary {
330            id: self.binary_ops.len(),
331            right_associative,
332            representation,
333            precedence,
334            operations: vec!()
335        };
336
337        self.binary_ops.push(op.clone());
338
339        match self.sorted_ops.binary_search_by(|i| i.get_precedence().cmp(&precedence)) {
340            Ok(_) => return Err(format!("Precedence {} is already taken", precedence)),
341            Err(pos) => self.sorted_ops.insert(pos, op)
342        }
343
344        Ok(())
345    }
346
347    pub fn get_binary_operations(&self, id: usize, a: Type, b: Type) -> Vec<&Operation<BinaryFunctionFn>> {
348        let and = Type::And(vec!(a, b));
349
350        if let Operator::Binary{operations: o, ..} = &self.binary_ops[id] {
351            return o.iter().filter(|op_ov| and.bindable_to(&op_ov.args, self)).collect::<Vec<_>>();
352        }
353
354        vec!()
355    }
356
357    pub fn define_native_binary_operation(&mut self, id: usize, templates: usize, a: Type, b: Type, ret: Type, f: BinaryFunctionFn) -> Result<usize, String> {
358        self.define_binary_operation(Location::none(), vec!(), id, templates, a, b, ret, Some(f))
359    }
360
361    pub fn define_binary_operation(&mut self, l: Location, annot: Vec<Annotation>, id: usize, templates: usize, a: Type, b: Type, ret: Type, f: OptBinaryFunctionFn) -> Result<usize, String> {
362        let and = Type::And(vec!(a.clone(), b.clone()));
363        let op = &self.binary_ops[id];
364
365        if let Operator::Binary{operations: o, representation: r, ..} = op {
366            for op_ov in o { // Check subsumption
367                if let Type::And(v) = &op_ov.args {
368                    if and.bindable_to(&op_ov.args, self) {
369                        return Err(format!("Binary operation {} {} {} is subsumed by {} {} {}, so it cannot be defined", 
370                                            a.get_name(self), r.green(), b.get_name(self), 
371                                            v[0].get_name(self), r.green(), v[1].get_name(self)));
372                    }
373
374                    if op_ov.args.bindable_to(&and, self) {
375                        return Err(format!("Binary operation {} {} {} subsumes {} {} {}, so it cannot be defined", 
376                                            a.get_name(self), r.green(), b.get_name(self), 
377                                            v[0].get_name(self), r.green(), v[1].get_name(self)));
378                    }
379                }
380            }
381        }
382
383        if let Operator::Binary{operations: o, ..} = &mut self.binary_ops[id] {
384            o.push(Operation { 
385                location: l,
386                annotations: annot, 
387                templates: templates, 
388                args: and, 
389                ret: ret, 
390                operation: f 
391            });
392
393            Ok(o.len() - 1)
394
395        } else {
396            unreachable!();
397        }
398    }
399
400    /*
401        ╒═════════════════════════════╕
402        │ N-ary operator manipulation │
403        ╘═════════════════════════════╛
404    */
405
406    pub fn define_nary_operator(&mut self, open_rep: String, close_rep: String, precedence: usize) -> Result<(), String> {
407        for o in &self.nary_ops {
408            if let Operator::Nary{open_rep: or, close_rep: cr, ..} = o {
409                if *or == open_rep || *cr == close_rep {
410                    return Err(format!("N-ary operator \"{}{}\" has a syntax overlap with \"{}{}\", so it cannot be defined", 
411                                        open_rep, close_rep, or, cr))
412                }
413            }
414        }
415
416        let op = Operator::Nary {
417            id: self.nary_ops.len(),
418            open_rep,
419            close_rep,
420            precedence,
421            operations: vec!()
422        };
423
424        self.nary_ops.push(op.clone());
425
426        match self.sorted_ops.binary_search_by(|i| i.get_precedence().cmp(&precedence)) {
427            Ok(_) => return Err(format!("Precedence {} is already taken", precedence)),
428            Err(pos) => self.sorted_ops.insert(pos, op)
429        }
430
431        Ok(())
432    }
433
434    pub fn get_nary_operations(&self, id: usize, from: Type, args: &[Type]) -> Vec<&Operation<NaryFunctionFn>> {
435        let mut subtypes = vec!(from);
436        subtypes.extend(args.iter().cloned());
437
438        let and = Type::And(subtypes);
439
440        if let Operator::Nary{operations: o, ..} = &self.nary_ops[id] {
441            return o.iter().filter(|op_ov| and.bindable_to(&op_ov.args, self)).collect::<Vec<_>>();
442        }
443
444        vec!()
445    }
446
447    pub fn define_native_nary_operation(&mut self, id: usize, templates: usize, from: Type, args: &[Type], ret: Type, f: NaryFunctionFn) -> Result<usize, String> {
448        self.define_nary_operation(Location::none(), vec!(), id, templates, from, args, ret, Some(f))
449    }
450
451    pub fn define_nary_operation(&mut self, l: Location, annot: Vec<Annotation>, id: usize, templates: usize, from: Type, args: &[Type], ret: Type, f: OptNaryFunctionFn) -> Result<usize, String> {
452        let mut subtypes = vec!(from.clone());
453        subtypes.extend(args.iter().cloned());
454
455        let and = Type::And(subtypes);
456        let op = &self.nary_ops[id];
457
458        if let Operator::Nary{operations: o, open_rep: or, close_rep: cr, ..} = op {
459            for op_ov in o { // Check subsumption
460                if let Type::And(v) = &op_ov.args {
461                    if and.bindable_to(&op_ov.args, self) {
462                        return Err(format!("N-ary operation {}{}{}{} is subsumed by {}{}{}{}, so it cannot be defined", 
463                                            from.get_name(self), or.green(), args.iter().map(|i| i.get_name(self)).collect::<Vec<_>>().join(", "), cr.green(), 
464                                            v[0].get_name(self), or.green(), v[1..].iter().map(|i| i.get_name(self)).collect::<Vec<_>>().join(", "), cr.green()));
465                    }
466
467                    if op_ov.args.bindable_to(&and, self) {
468                        return Err(format!("N-ary operation {}{}{}{} subsumes {}{}{}{}, so it cannot be defined", 
469                                            from.get_name(self), or.green(), args.iter().map(|i| i.get_name(self)).collect::<Vec<_>>().join(", "), cr.green(), 
470                                            v[0].get_name(self), or.green(), v[1..].iter().map(|i| i.get_name(self)).collect::<Vec<_>>().join(", "), cr.green()));
471                    }
472                }
473            }
474        }
475
476        if let Operator::Nary{operations: o, ..} = &mut self.nary_ops[id] {
477            o.push(Operation { 
478                location: l,
479                annotations: annot, 
480                templates: templates, 
481                args: and, 
482                ret: ret, 
483                operation: f 
484            });
485
486            Ok(o.len() - 1)
487
488        } else {
489            unreachable!()
490        }
491    }
492
493    /*
494        ╒═══════════════════════╕
495        │ Function manipulation │
496        ╘═══════════════════════╛
497    */
498
499    pub fn define_function(&mut self, name: String) -> Result<usize, String> {        
500        for f in &self.functions {
501            if f.name == name {
502                return Err(format!("Function \"{}\" is already defined", name))
503            }
504        }
505
506        self.cache.function_id.insert(name.clone(), Ok(self.functions.len()));
507        
508        self.functions.push(Function {
509            id: self.functions.len(),
510            name,
511            overloads: vec!()
512        });
513
514        Ok(self.functions.len() - 1)
515    }
516
517    pub fn get_function_overloads(&self, id: usize, templates: &[Type], args: &[Type]) -> Vec<&FunctionOverload> {
518        let and = Type::And(args.to_vec());
519
520        return self.functions[id].overloads.iter().filter(|f_ov| and.bindable_to_template(&f_ov.args, templates, self)).collect::<Vec<_>>();
521    }
522
523    pub fn define_native_function_overload(&mut self, id: usize, templates: usize, args: &[Type], ret: Type, f: FunctionOverloadFn) -> Result<usize, String> {
524        self.define_function_overload(Location::none(), vec!(), id, templates, args, ret, Some(f))
525    }
526
527    pub fn define_function_overload(&mut self, l: Location, annot: Vec<Annotation>, id: usize, templates: usize, args: &[Type], ret: Type, f: OptFunctionOverloadFn) -> Result<usize, String> {
528        let and = Type::And(args.to_vec());
529        let func = &self.functions[id];
530
531        for f_ov in &func.overloads{ // Check subsumption
532            if let Type::And(v) = &f_ov.args {
533                if and.bindable_to(&f_ov.args, self) {
534                    return Err(format!("Function overload {}({}) is subsumed by {}({}), so it cannot be defined", 
535                                        func.name.green(), args.iter().map(|i| i.get_name(self)).collect::<Vec<_>>().join(", "), 
536                                        func.name.green(), v.iter().map(|i| i.get_name(self)).collect::<Vec<_>>().join(", ")));
537                }
538
539                if f_ov.args.bindable_to(&and, self) {
540                    return Err(format!("Function overload {}({}) subsumes {}({}), so it cannot be defined", 
541                                        func.name.green(), args.iter().map(|i| i.get_name(self)).collect::<Vec<_>>().join(", "), 
542                                        func.name.green(), v.iter().map(|i| i.get_name(self)).collect::<Vec<_>>().join(", ")));
543                }
544            }
545        }
546
547        self.functions[id].overloads.push(FunctionOverload { 
548            location: l,
549            annotations: annot, 
550            templates: templates, 
551            args: Type::And(args.to_vec()), 
552            ret: ret, 
553            function: f 
554        });
555
556        Ok(self.functions[id].overloads.len() - 1)
557    }
558
559    pub fn reset_registers(&mut self) {
560        self.registers = (0..self.variables.len()).rev().collect();
561    }
562
563    pub fn compute_num_globals(&mut self) {
564        self.num_globals = self.var_map.num_vars();
565    }
566}
567
568/*
569                                                  ╒════════════════╕
570    ============================================= │  STANDARD CTX  │ =============================================
571                                                  ╘════════════════╛
572*/
573
574lazy_static! {
575    pub static ref NUM_STD_TYPES: Mutex<RefCell<usize>> = Mutex::default();
576    
577    pub static ref NUM_STD_INTS: Mutex<RefCell<usize>> = Mutex::default();    
578    pub static ref NUM_STD_INT_IMPL: Mutex<RefCell<usize>> = Mutex::default();    
579    
580    pub static ref NUM_STD_FNS: Mutex<RefCell<FxHashMap<usize, usize>>> = Mutex::default(); 
581    pub static ref NUM_STD_UNOPS: Mutex<RefCell<FxHashMap<usize, usize>>> = Mutex::default(); 
582    pub static ref NUM_STD_BINOPS: Mutex<RefCell<FxHashMap<usize, usize>>> = Mutex::default(); 
583    pub static ref NUM_STD_NARYOPS: Mutex<RefCell<FxHashMap<usize, usize>>> = Mutex::default(); 
584
585    pub static ref NUM_STD_MACROS: Mutex<RefCell<usize>> = Mutex::default();    
586}
587
588pub fn standard_ctx() -> RynaContext {
589    let mut ctx = RynaContext::default();
590
591    // Define std context contents
592    standard_types(&mut ctx);
593    standard_interfaces(&mut ctx);
594
595    standard_unary_operations(&mut ctx);
596    standard_binary_operations(&mut ctx);
597    standard_nary_operations(&mut ctx);
598
599    standard_functions(&mut ctx);
600
601    load_optimized_opcodes(&mut ctx);
602
603    // Update std sizes
604    *NUM_STD_TYPES.lock().unwrap().borrow_mut() = ctx.type_templates.len();
605    *NUM_STD_INTS.lock().unwrap().borrow_mut() = ctx.interfaces.len();
606    *NUM_STD_INT_IMPL.lock().unwrap().borrow_mut() = ctx.interface_impls.len();
607    *NUM_STD_MACROS.lock().unwrap().borrow_mut() = ctx.macros.len();
608    *NUM_STD_FNS.lock().unwrap().borrow_mut() = ctx.functions.iter().map(|f| (f.id, f.overloads.len())).collect();
609
610    *NUM_STD_UNOPS.lock().unwrap().borrow_mut() = ctx.unary_ops.iter().map(|o| {
611        if let Operator::Unary { id, operations, .. } = o {
612            return (*id, operations.len());
613        }
614
615        unreachable!()
616    }).collect();
617
618    *NUM_STD_BINOPS.lock().unwrap().borrow_mut() = ctx.binary_ops.iter().map(|o| {
619        if let Operator::Binary { id, operations, .. } = o {
620            return (*id, operations.len());
621        }
622
623        unreachable!()
624    }).collect();
625
626    *NUM_STD_NARYOPS.lock().unwrap().borrow_mut() = ctx.nary_ops.iter().map(|o| {
627        if let Operator::Nary { id, operations, .. } = o {
628            return (*id, operations.len());
629        }
630
631        unreachable!()
632    }).collect();
633
634    ctx.variables = vec!(Object::no_value(); 10000); // 10000 variables by default
635    ctx.var_map = VariableMap::new();
636    ctx.reset_registers();
637
638    ctx
639}
640
641/*
642                                                  ╒═════════╕
643    ============================================= │  TESTS  │ =============================================
644                                                  ╘═════════╛
645*/
646
647#[cfg(test)]
648mod tests {
649    use crate::types::Type;
650    use crate::context::*;
651
652    #[test]
653    fn operation_subsumption() {
654        let mut ctx = standard_ctx();
655
656        let def_1 = ctx.define_native_unary_operation(0, 0, STR, STR, |_, _, a| { Ok(a.clone()) });
657        let def_2 = ctx.define_native_unary_operation(0, 0, INT, STR, |_, _, a| { Ok(a.clone()) });
658        let def_3 = ctx.define_native_unary_operation(0, 0, Type::Wildcard, Type::Wildcard, |_, _, a| { Ok(a.clone()) });
659
660        assert!(def_1.is_ok());
661        assert!(def_2.is_err());
662        assert!(def_3.is_err());
663
664        let def_1 = ctx.define_native_binary_operation(0, 0, INT, STR, STR, |_, _, a, _, _| { Ok(a.clone()) });
665        let def_2 = ctx.define_native_binary_operation(0, 0, STR, STR, STR, |_, _, a, _, _| { Ok(a.clone()) });
666        let def_3 = ctx.define_native_binary_operation(0, 0, Type::Wildcard, Type::Wildcard, Type::Wildcard, |_, _, a, _, _| { Ok(a.clone()) });
667
668        assert!(def_1.is_ok());
669        assert!(def_2.is_err());
670        assert!(def_3.is_err());
671
672        let def_1 = ctx.define_native_nary_operation(0, 0, INT, &[INT], INT, |_, _, _| { Ok(()) });
673        let def_2 = ctx.define_native_nary_operation(0, 0, STR, &[Type::Ref(Box::new(STR))], STR, |_, _, _| { Ok(()) });
674        let def_3 = ctx.define_native_nary_operation(0, 0, STR, &[STR], STR, |_, _, _| { Ok(()) });
675        let def_4 = ctx.define_native_nary_operation(0, 0, Type::Wildcard, &[Type::Wildcard], Type::Wildcard, |_, _, _| { Ok(()) });
676
677        assert!(def_1.is_ok());
678        assert!(def_2.is_ok());
679        assert!(def_3.is_ok());
680        assert!(def_4.is_err());
681    }
682
683    #[test]
684    fn function_subsumption() {
685        let mut ctx = standard_ctx();
686
687        let def_1 = ctx.define_native_function_overload(0, 0, &[STR], INT, |_, _, a, _| { Ok(a[0].clone()) });
688        let def_2 = ctx.define_native_function_overload(0, 0, &[Type::MutRef(Box::new(INT))], INT, |_, _, a, _| { Ok(a[0].clone()) });
689        let def_3 = ctx.define_native_function_overload(0, 0, &[Type::Wildcard], INT, |_, _, a, _| { Ok(a[0].clone()) });
690
691        assert!(def_1.is_ok());
692        assert!(def_2.is_err());
693        assert!(def_3.is_err());
694    }
695
696    #[test]
697    fn operator_redefinition() {
698        let mut ctx = standard_ctx();
699
700        let def_1 = ctx.define_unary_operator("~".into(), true, 0);
701        let def_2 = ctx.define_unary_operator("-".into(), true, 1);
702
703        assert!(def_1.is_ok());
704        assert!(def_2.is_err());
705
706        let def_1 = ctx.define_binary_operator("$".into(), false, 2);
707        let def_2 = ctx.define_binary_operator("+".into(), false, 3);
708
709        assert!(def_1.is_ok());
710        assert!(def_2.is_err());
711
712        let def_1 = ctx.define_nary_operator("`".into(), "´".into(), 4);
713        let def_2 = ctx.define_nary_operator("(".into(), ")".into(), 5);
714        let def_3 = ctx.define_nary_operator("{".into(), ")".into(), 6);
715        let def_4 = ctx.define_nary_operator("(".into(), "}".into(), 7);
716
717        assert!(def_1.is_ok());
718        assert!(def_2.is_err());
719        assert!(def_3.is_err());
720        assert!(def_4.is_err());
721    }
722
723    #[test]
724    fn type_redefinition() {
725        let mut ctx = standard_ctx();
726
727        let def_1 = ctx.define_type(Location::none(), vec!(), "Matrix".into(), vec!(), vec!(), None, vec!(), None);
728        let def_2 = ctx.define_type(Location::none(), vec!(), "Int".into(), vec!(), vec!(), None, vec!(), None);
729
730        assert!(def_1.is_ok());
731        assert!(def_2.is_err());
732    }
733
734    #[test]
735    fn function_redefinition() {
736        let mut ctx = standard_ctx();
737
738        let def_1 = ctx.define_function("example".into());
739        let def_2 = ctx.define_function("inc".into());
740
741        assert!(def_1.is_ok());
742        assert!(def_2.is_err());
743    }
744}