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