ryna/
execution.rs

1use std::sync::Arc;
2use std::time::Instant;
3
4use colored::Colorize;
5use rustc_hash::FxHashMap;
6use serde::Serialize;
7use malachite::Integer;
8use malachite::num::conversion::traits::{RoundingFrom, SaturatingInto};
9use malachite::rounding_modes::RoundingMode;
10
11use crate::config::{precompile_ryna_module_with_config, read_compiled_cache, save_compiled_cache, compute_project_hash};
12use crate::debug::DebugInfo;
13use crate::functions::FunctionOverload;
14use crate::integer_ext::{is_valid_index, to_usize, ONE};
15use crate::ryna_warning;
16use crate::types::Type;
17use crate::object::{RynaArray, RynaLambda, RynaTuple, Object, TypeInstance};
18use crate::context::RynaContext;
19use crate::operations::Operator;
20use crate::compilation::{message_and_exit, CompiledRynaExpr, RynaError};
21
22/*
23                                                  ╒══════════════════╕
24    ============================================= │  IMPLEMENTATION  │ =============================================
25                                                  ╘══════════════════╛
26*/
27
28impl RynaContext {
29    pub fn parse_and_execute_ryna_module(&mut self, code: &String) -> Result<ExecutionInfo, RynaError> {
30        let mut compiled_code = self.parse_and_compile(code)?;
31
32        if self.optimize {
33            self.optimize_instructions(&mut compiled_code);
34        }
35
36        for (idx, i) in compiled_code.iter().enumerate() {
37            println!("{:<3} {}", idx, i.to_string(self));
38        }
39        
40        self.execute_compiled_code::<false>(&compiled_code.into_iter().map(|i| i.instruction).collect::<Vec<_>>(), &[])
41    }
42
43    pub fn parse_and_execute_ryna_project_inner<const DEBUG: bool>(path: String, macro_code: Option<String>, force_recompile: bool, optimize: bool, test: bool, program_input: &[String]) -> Result<ExecutionInfo, RynaError> {
44        let combined_hash;
45        let all_modules;
46        let file_cache;
47
48        let no_macro = macro_code.is_none();
49
50        match compute_project_hash(&path, macro_code, optimize, test) {
51            Ok((hash, all_mods, files)) => {
52                combined_hash = hash.clone();
53                all_modules = all_mods;
54                file_cache = files;
55
56                if !force_recompile {
57                    if let Some(mut code) = read_compiled_cache(&path) {
58                        if hash == code.hash {
59                            if DEBUG {
60                                ryna_warning!(
61                                    "Function timings will not be dumped when executing cached code (use {} to force recompilation)",
62                                    "--recompile".green()
63                                );
64                            }
65
66                            return code.execute::<DEBUG>(program_input); 
67                        }    
68                    }
69                }
70            }
71
72            Err(err) => err.emit()
73        }
74
75        match precompile_ryna_module_with_config(&path, all_modules, file_cache, optimize, test, force_recompile) {
76            Ok((mut ctx, code)) => match ctx.compiled_form(&code) {
77                Ok(mut instr) => {
78                    if optimize {
79                        ctx.optimize_instructions(&mut instr);
80                    }
81                    
82                    if no_macro {
83                        let ser_module = ctx.get_serializable_module(combined_hash, &instr);
84
85                        if let Err(err) = save_compiled_cache(&path, &ser_module) {
86                            err.emit();
87                        }
88                    }
89
90                    ctx.program_input = program_input.to_vec();
91
92                    let mut instructions = Vec::with_capacity(instr.len());
93                    let mut debug_info = Vec::with_capacity(instr.len());
94
95                    for i in instr {
96                        instructions.push(i.instruction);
97                        debug_info.push(i.debug_info);
98                    }
99
100                    ctx.execute_compiled_code::<DEBUG>(&instructions, &debug_info)
101                },
102
103                Err(err) => err.emit(),
104            },
105
106            Err(err) => err.emit(),
107        }
108    }
109
110    pub fn parse_and_execute_ryna_project<const DEBUG: bool>(path: String, force_recompile: bool, optimize: bool, test: bool, program_input: &[String]) -> Result<ExecutionInfo, RynaError> {        
111        Self::parse_and_execute_ryna_project_inner::<DEBUG>(path, None, force_recompile, optimize, test, program_input)
112    }
113}
114
115#[derive(Serialize)]
116pub struct ProfilingInfo {
117    pub instr_count: FxHashMap<&'static str, usize>,
118    pub instr_time: FxHashMap<&'static str, u128>,
119    pub loc_time: FxHashMap<Arc<String>, FxHashMap<usize, u128>>,
120    pub total_time: u128
121}
122
123pub struct ExecutionInfo {
124    pub profiling_info: Option<ProfilingInfo>,
125    pub captured_output: String
126}
127
128impl RynaContext {
129    pub fn execute_compiled_code<const DEBUG: bool>(&mut self, program: &[CompiledRynaExpr], debug_info: &[DebugInfo]) -> Result<ExecutionInfo, RynaError> {
130        use CompiledRynaExpr::*;
131
132        const MAX_STACK_FRAMES: usize = 100000;
133
134        let mut ip: i32 = 0;
135        let mut offset: usize = 0;
136        
137        let mut call_stack: Vec<(i32, usize, i32)> = Vec::with_capacity(1000);
138        let mut stack: Vec<Object> = Vec::with_capacity(1000);
139
140        let mut instr_count = FxHashMap::<&str, usize>::default();
141        let mut instr_time = FxHashMap::<&str, u128>::default();
142        let mut loc_time = FxHashMap::<Arc<String>, FxHashMap<usize, u128>>::default();
143        let mut total_time = 0;
144
145        macro_rules! tos {
146            () => {
147                stack.pop().unwrap()
148            }
149        }
150
151        macro_rules! fetch_opcode {
152            () => {
153                unsafe { program.get_unchecked(ip as usize) }
154            }
155        }
156
157        macro_rules! curr_offset {
158            ($cond: expr) => {
159                offset * (!$cond as usize) 
160            };
161        }
162
163        macro_rules! unary_op {
164            ($name: expr, $a: ident, $get_a: ident, $t: ty, $op: expr) => {
165                ryna_instruction!($name, {
166                    let _a = tos!();
167                    let $a = &*_a.$get_a::<$t>();
168    
169                    stack.push(Object::new($op));
170                    ip += 1;
171                })
172            };
173        }
174
175        macro_rules! bin_op {
176            ($name: expr, $a: ident, $b: ident, $get_a: ident, $get_b: ident, $t: ty, $op: expr) => {
177                ryna_instruction!($name, {
178                    let _a = tos!();
179                    let _b = tos!();
180                    let $a = &*_a.$get_a::<$t>();
181                    let $b = &*_b.$get_b::<$t>();
182                        
183                    stack.push(Object::new($op));
184                    ip += 1;
185                })
186            };
187        }
188
189        macro_rules! ryna_instruction {
190            ($name: expr, $expr: expr) => {
191                if DEBUG {                    
192                    let now = Instant::now();
193
194                    $expr
195
196                    let elapsed = now.elapsed().as_nanos();
197
198                    *instr_time.entry($name).or_default() += elapsed;
199                    *instr_count.entry($name).or_default() += 1;
200
201                    let lines_to_check = call_stack[1..].iter()
202                                                        .flat_map(|i| &debug_info[i.0 as usize].lines)
203                                                        .chain(&debug_info[ip as usize].lines)
204                                                        .collect::<rustc_hash::FxHashSet<_>>();
205                    
206                    // For each frame in the stack (excluding the first)
207                    for j in lines_to_check {
208                        *loc_time.entry(j.0.clone()).or_default().entry(j.1).or_default() += elapsed;    
209                    }
210
211                    total_time += elapsed;
212
213                } else {
214                    $expr
215                }
216            };
217        }
218
219        macro_rules! idx_op {
220            ($deref_arr: ident, $ref_method: ident) => {
221                let arr = tos!();
222                let first = tos!();
223
224                let arr = &*arr.$deref_arr::<RynaArray>();
225                let idx = &*first.get::<Integer>();
226
227                if !is_valid_index(idx) {
228                    return Err(RynaError::execution_error(format!("{} is not a valid index", idx)));
229                
230                } else {
231                    let native_idx = to_usize(idx);
232                    
233                    if arr.elements.len() <= native_idx {
234                        return Err(RynaError::execution_error(format!("{} is higher than the length of the array ({})", idx, arr.elements.len())));
235    
236                    } else {
237                        stack.push(arr.elements[native_idx].$ref_method());
238                    }
239                } 
240
241                ip += 1;
242            };
243        }
244
245        macro_rules! check_call_stack_limit {
246            () => {
247                if call_stack.len() > MAX_STACK_FRAMES {
248                    return Err(RynaError::execution_error(format!("Too many stack frames (max. of {})", MAX_STACK_FRAMES)));
249                }
250            }
251        }
252
253        macro_rules! store_variable {
254            ($id: expr, $value: expr) => {
255                if $id >= self.variables.len() {
256                    self.variables.resize($id + 1, Object::no_value());
257                }
258
259                // SAFETY: this is safe because the previous check makes sure that the index
260                // exists inside self.variables, making this unsafe access an optimization
261                unsafe { *self.variables.get_unchecked_mut($id) = $value; }
262            }
263        }
264
265        macro_rules! get_variable {
266            ($id: expr) => {
267                // SAFETY: this is safe as long as an storage is made before the access, which
268                // is guaranteed by the Ryna compiler
269                unsafe { self.variables.get_unchecked($id) }
270            }
271        }
272
273        macro_rules! get_global_variable {
274            ($id: expr) => {
275                {
276                    let v = get_variable!($id);
277
278                    if v.is_moved() {
279                        message_and_exit("Accessing absent global variable".into());
280                    }
281
282                    v
283                }
284            }
285        }
286
287        macro_rules! update_max_var {
288            ($id: expr) => {
289                // SAFETY: this is safe because call_stack will never be empty
290                let idx = call_stack.len() - 1;
291                let l = unsafe { &mut call_stack.get_unchecked_mut(idx).2 };
292                *l = (*l).max($id as i32);
293            }
294        }
295
296        macro_rules! add_stack_frame {
297            ($new_ip: expr) => {
298                // SAFETY: this is safe because call_stack will never be empty
299                call_stack.push((ip + 1, offset, -1));
300                ip = $new_ip;
301                unsafe { offset += (call_stack.get_unchecked(call_stack.len() - 2).2 + 1) as usize };
302
303                check_call_stack_limit!();
304            }
305        }
306
307        macro_rules! lambda_call {
308            ($lambda_ref: ident) => {
309                let arg = tos!();
310                let f = &arg.$lambda_ref::<RynaLambda>();
311
312                stack.extend(f.captures.iter().rev().cloned());
313                
314                add_stack_frame!(f.loc as i32);
315            };
316        }
317
318        call_stack.push((0, 0, -1));
319        update_max_var!(self.num_globals); // Ensure that the first registers are only for globals
320
321        loop {
322            match fetch_opcode!() {
323                Empty => ryna_instruction!("Empty", {
324                    stack.push(Object::empty());
325                    ip += 1;
326                }),
327
328                Bool(obj) => ryna_instruction!("Bool", {
329                    stack.push(Object::new(*obj));
330                    ip += 1;
331                }),
332
333                Float(obj) => ryna_instruction!("Float", {
334                    stack.push(Object::new(*obj));
335                    ip += 1;
336                }),
337
338                Int(obj) => ryna_instruction!("Int", {
339                    stack.push(Object::new(obj.clone()));
340                    ip += 1;
341                }),
342
343                Str(obj) => ryna_instruction!("Str", {
344                    stack.push(Object::new(obj.clone()));
345                    ip += 1;
346                }),
347
348                Array(length, t) => ryna_instruction!("Array", {
349                    let start_idx = stack.len() - length;
350                    let args = stack.drain(start_idx..).rev().collect();
351
352                    stack.push(Object::arr(args, t.clone()));
353
354                    ip += 1;
355                }),
356
357                Lambda(pos, cap, args, ret) => ryna_instruction!("Lambda", {
358                    let start_idx = stack.len() - cap;
359                    let captures = stack.drain(start_idx..).rev().collect();
360
361                    stack.push(Object::lambda(*pos, captures, args.clone(), ret.clone()));
362                    ip += 1;
363                }),
364
365                Construct(id, length, ts) => ryna_instruction!("Construct", {
366                    let start_idx = stack.len() - length;
367                    let args = stack.drain(start_idx..).rev().collect();
368
369                    stack.push(Object::new(TypeInstance {
370                        id: *id,
371                        params: ts.clone(),
372                        attributes: args,
373                    }));
374
375                    ip += 1;
376                }),
377
378                AttributeAssign(attr_idx) => ryna_instruction!("AttributeAssign", {
379                    let a = tos!();
380                    let b = tos!();
381
382                    b.deref::<TypeInstance>().attributes[*attr_idx] = a;
383
384                    ip += 1;
385                }),
386
387                AttributeMove(idx) => ryna_instruction!("AttributeMove", {
388                    let elem = tos!();
389                    stack.push(elem.get::<TypeInstance>().attributes[*idx].move_contents_if_ref());
390                    ip += 1;
391                }),
392
393                AttributeRef(idx) => ryna_instruction!("AttributeRef", {
394                    let elem = tos!();
395                    stack.push(elem.deref::<TypeInstance>().attributes[*idx].get_ref());
396                    ip += 1;
397                }),
398
399                AttributeMut(idx) => ryna_instruction!("AttributeMut", {
400                    let elem = tos!();
401                    stack.push(elem.deref::<TypeInstance>().attributes[*idx].get_mut());
402                    ip += 1;
403                }),
404
405                AttributeCopy(idx) => ryna_instruction!("AttributeCopy", {
406                    let elem = tos!();
407                    stack.push(elem.deref::<TypeInstance>().attributes[*idx].deref_deep_clone());
408                    ip += 1;
409                }),
410
411                AttributeDeref(idx) => ryna_instruction!("AttributeDeref", {
412                    let elem = tos!();
413                    stack.push(elem.deref::<TypeInstance>().attributes[*idx].deref_if_ref());
414                    ip += 1;
415                }),
416
417                Tuple(length) => ryna_instruction!("Tuple", {     
418                    let start_idx = stack.len() - length;
419                    let args = stack.drain(start_idx..).rev().collect::<Vec<_>>();
420                    let types = args.iter().map(|i| i.get_type()).collect::<Vec<_>>();
421
422                    stack.push(Object::tuple(args, types));
423
424                    ip += 1;
425                }),
426
427                TupleElemMove(idx) => ryna_instruction!("TupleElemMove", {
428                    let elem = tos!();
429                    stack.push(elem.get::<RynaTuple>().elements[*idx].move_contents_if_ref());
430                    ip += 1;
431                }),
432
433                TupleElemRef(idx) => ryna_instruction!("TupleElemRef", {
434                    let elem = tos!();
435                    stack.push(elem.deref::<RynaTuple>().elements[*idx].get_ref());
436                    ip += 1;
437                }),
438
439                TupleElemMut(idx) => ryna_instruction!("TupleElemMut", {
440                    let elem = tos!();
441                    stack.push(elem.deref::<RynaTuple>().elements[*idx].get_mut());
442                    ip += 1;
443                }),
444
445                TupleElemCopy(idx) => ryna_instruction!("TupleElemCopy", {
446                    let elem = tos!();
447                    stack.push(elem.deref::<RynaTuple>().elements[*idx].deref_deep_clone());
448                    ip += 1;
449                }),
450
451                TupleElemDeref(idx) => ryna_instruction!("TupleElemDeref", {
452                    let elem = tos!();
453                    stack.push(elem.deref::<RynaTuple>().elements[*idx].deref_if_ref());
454                    ip += 1;
455                }),
456
457                IdxMove => ryna_instruction!("IdxMove", { idx_op!(get, move_contents_if_ref); }),
458                IdxRef => ryna_instruction!("IdxRef", { idx_op!(deref, get_ref_nostack); }),
459                IdxMut => ryna_instruction!("IdxMut", { idx_op!(deref, get_mut_nostack); }),
460                IdxMoveRef => ryna_instruction!("IdxMoveRef", { idx_op!(deref, move_contents_if_ref); }),
461
462                StoreIntVariable(id, g, obj) => ryna_instruction!("StoreIntVariable", {
463                    update_max_var!(*id);
464                    store_variable!(*id + curr_offset!(g), Object::new(obj.clone()));
465                    ip += 1;
466                }),
467
468                StoreStringVariable(id, g, obj) => ryna_instruction!("StoreStringVariable", {
469                    update_max_var!(*id);
470                    store_variable!(*id + curr_offset!(g), Object::new(obj.clone()));
471                    ip += 1;
472                }),
473
474                StoreBoolVariable(id, g, obj) => ryna_instruction!("StoreBoolVariable", {
475                    update_max_var!(*id);
476                    store_variable!(*id + curr_offset!(g), Object::new(*obj));
477                    ip += 1;
478                }),
479
480                StoreFloatVariable(id, g, obj) => ryna_instruction!("StoreFloatVariable", {
481                    update_max_var!(*id);
482                    store_variable!(*id + curr_offset!(g), Object::new(*obj));
483                    ip += 1;
484                }),
485                
486                StoreVariable(id, g) => ryna_instruction!("StoreVariable", {
487                    update_max_var!(*id);
488                    store_variable!(*id + curr_offset!(g), tos!());
489                    ip += 1;
490                }),
491
492                GetVariable(id, false) => ryna_instruction!("GetVariable", {
493                    stack.push(get_variable!(*id + offset).get_var());
494                    ip += 1;
495                }),
496
497                CloneVariable(id, false) => ryna_instruction!("CloneVariable", {
498                    stack.push(get_variable!(*id + offset).clone());
499                    ip += 1;
500                }),
501
502                RefVariable(id, false) => ryna_instruction!("RefVariable", {
503                    stack.push(get_variable!(*id + offset).get_ref());
504                    ip += 1;
505                }),
506
507                DerefVariable(id, false) => ryna_instruction!("DerefVariable", {
508                    stack.push(get_variable!(*id + offset).deref_if_ref());
509                    ip += 1;
510                }),
511
512                CopyVariable(id, false) => ryna_instruction!("CopyVariable", {
513                    stack.push(get_variable!(*id + offset).deref_deep_clone());
514                    ip += 1;
515                }),
516
517                MoveVariable(id, false) => ryna_instruction!("MoveVariable", {
518                    stack.push(get_variable!(*id + offset).move_contents_if_ref());
519                    ip += 1;
520                }),
521
522                GetVariable(id, true) => ryna_instruction!("GetVariable", {
523                    stack.push(get_global_variable!(*id).get_var());
524                    ip += 1;
525                }),
526
527                CloneVariable(id, true) => ryna_instruction!("CloneVariable", {
528                    stack.push(get_global_variable!(*id).clone());
529                    ip += 1;
530                }),
531
532                RefVariable(id, true) => ryna_instruction!("RefVariable", {
533                    stack.push(get_global_variable!(*id).get_ref());
534                    ip += 1;
535                }),
536
537                DerefVariable(id, true) => ryna_instruction!("DerefVariable", {
538                    stack.push(get_global_variable!(*id).deref_if_ref());
539                    ip += 1;
540                }),
541
542                CopyVariable(id, true) => ryna_instruction!("CopyVariable", {
543                    stack.push(get_global_variable!(*id).deref_deep_clone());
544                    ip += 1;
545                }),
546
547                MoveVariable(id, true) => ryna_instruction!("MoveVariable", {
548                    stack.push(get_global_variable!(*id).move_contents_if_ref());
549                    ip += 1;
550                }),
551
552                Assign => ryna_instruction!("Assign", {
553                    let a = tos!();
554                    let b = tos!();
555
556                    if let Err(msg) = a.assign(b, self) {
557                        return Err(RynaError::execution_error(msg));
558                    }
559
560                    ip += 1;
561                }),
562
563                AssignToVar(id, g) => ryna_instruction!("AssignToVar", {
564                    let var = &get_variable!(*id + curr_offset!(g));
565                    let value = tos!();
566
567                    if let Err(msg) = var.assign_direct(value, self) {
568                        return Err(RynaError::execution_error(msg));
569                    }
570
571                    ip += 1;
572                }),
573
574                AssignToVarDirect(id, g) => ryna_instruction!("AssignToVarDirect", {
575                    let var = &get_variable!(*id + curr_offset!(g));
576                    let value = tos!();
577
578                    if let Err(msg) = var.assign(value, self) {
579                        return Err(RynaError::execution_error(msg));
580                    }
581
582                    ip += 1;
583                }),
584
585                Drop => ryna_instruction!("Drop", {
586                    tos!();
587                    ip += 1;
588                }),
589
590                Jump(to) => ip = *to as i32,
591                RelativeJump(to) => ip += *to,
592                RelativeJumpIfFalse(to, false) => ryna_instruction!("RelativeJumpIfFalse", {
593                    if !*tos!().get::<bool>() {
594                        ip += *to as i32;
595
596                    } else {
597                        ip += 1;
598                    }
599                }),
600
601                RelativeJumpIfTrue(to, false) => ryna_instruction!("RelativeJumpIfTrue", {
602                    if *tos!().get::<bool>() {
603                        ip += *to as i32;
604
605                    } else {
606                        ip += 1;
607                    }
608                }),
609
610                RelativeJumpIfFalse(to, true) => ryna_instruction!("RelativeJumpIfFalse", {
611                    if !*stack.last().unwrap().get::<bool>() {
612                        ip += *to as i32;
613
614                    } else {
615                        ip += 1;
616                    }
617                }),
618
619                RelativeJumpIfTrue(to, true) => ryna_instruction!("RelativeJumpIfTrue", {
620                    if *stack.last().unwrap().get::<bool>() {
621                        ip += *to as i32;
622
623                    } else {
624                        ip += 1;
625                    }
626                }),
627
628                Call(to) => ryna_instruction!("Call", { add_stack_frame!(*to as i32); }),
629                CallDestructor(to) => ryna_instruction!("CallDestructor", { 
630                    let elem = stack.last().unwrap();
631
632                    if !elem.is_moved() && elem.ref_count() == 1 && !elem.is_moved_deref() && elem.deref_ref_count() <= 2 {
633                        add_stack_frame!(*to as i32); 
634                    
635                    } else {
636                        ip += 1;
637                    }
638                }),
639                LambdaCall => ryna_instruction!("LambdaCall", { lambda_call!(get); }),
640                LambdaCallRef => ryna_instruction!("LambdaCallRef", { lambda_call!(deref); }),
641
642                DeleteVar(var_idx, g) => ryna_instruction!("DeleteVar", { 
643                    self.variables[*var_idx + curr_offset!(g)] = Object::no_value();
644                    ip += 1;                    
645                }),
646
647                Return => ryna_instruction!("Return", {
648                    let (prev_ip, prev_offset, _) = call_stack.pop().unwrap();
649                    let idx = call_stack.len() - 1;
650                    let l = call_stack[idx].2.max(0) as usize;
651
652                    // Clear context variables
653                    let num_vars = self.variables.len();
654                    self.variables[offset..(offset + l).min(num_vars)].fill(Object::no_value());
655
656                    ip = prev_ip;
657                    offset = prev_offset;
658                }), 
659
660                NativeFunctionCall(func_id, ov_id, type_args) => ryna_instruction!("NativeFunctionCall", {
661                    if let FunctionOverload { args: Type::And(v), ret: r, function: Some(f), .. } = &self.functions[*func_id].overloads[*ov_id] {
662                        let mut args = Vec::with_capacity(v.len());
663
664                        for _ in v {
665                            args.push(tos!());
666                        }
667
668                        match f(type_args, r, args, self) {
669                            Ok(obj) => stack.push(obj),
670                            Err(msg) => return Err(RynaError::execution_error(msg))
671                        };
672
673                        ip += 1;
674                    
675                    } else {
676                        unreachable!();
677                    }
678                }),
679
680                NativeFunctionCallNoRet(func_id, ov_id, type_args) => ryna_instruction!("NativeFunctionCallNoRet", {
681                    if let FunctionOverload { args: Type::And(v), ret: r, function: Some(f), .. } = &self.functions[*func_id].overloads[*ov_id] {
682                        let mut args = Vec::with_capacity(v.len());
683
684                        for _ in v {
685                            args.push(tos!());
686                        }
687
688                        if let Err(msg) = f(type_args, r, args, self) {
689                            return Err(RynaError::execution_error(msg));
690                        };
691
692                        ip += 1;
693                    
694                    } else {
695                        unreachable!();
696                    }
697                }),
698
699                UnaryOperatorCall(op_id, ov_id, type_args) => ryna_instruction!("UnaryOperatorCall", {
700                    if let Operator::Unary{operations, ..} = &self.unary_ops[*op_id] {
701                        let obj = tos!();
702
703                        let ov = &operations[*ov_id];
704
705                        match ov.operation.unwrap()(type_args, &ov.ret, obj) {
706                            Ok(obj) => stack.push(obj),
707                            Err(msg) => return Err(RynaError::execution_error(msg))
708                        };
709
710                        ip += 1;
711                    
712                    } else {
713                        unreachable!();
714                    }
715                }),
716
717                UnaryOperatorCallNoRet(op_id, ov_id, type_args) => ryna_instruction!("UnaryOperatorCallNoRet", {
718                    if let Operator::Unary{operations, ..} = &self.unary_ops[*op_id] {
719                        let obj = tos!();
720
721                        let ov = &operations[*ov_id];
722
723                        if let Err(msg) = ov.operation.unwrap()(type_args, &ov.ret, obj) {
724                            return Err(RynaError::execution_error(msg));
725                        };
726
727                        ip += 1;
728                    
729                    } else {
730                        unreachable!();
731                    }
732                }),
733
734                BinaryOperatorCall(op_id, ov_id, type_args) => ryna_instruction!("BinaryOperatorCall", {
735                    if let Operator::Binary{operations, ..} = &self.binary_ops[*op_id] {
736                        let a = tos!();
737                        let b = tos!();
738
739                        let ov = &operations[*ov_id];
740
741                        match ov.operation.unwrap()(type_args, &ov.ret, a, b, self) {
742                            Ok(obj) => stack.push(obj),
743                            Err(msg) => return Err(RynaError::execution_error(msg))
744                        };
745                        
746                        ip += 1;
747                    
748                    } else {
749                        unreachable!();
750                    }
751                }),
752
753                BinaryOperatorCallNoRet(op_id, ov_id, type_args) => ryna_instruction!("BinaryOperatorCallNoRet", {
754                    if let Operator::Binary{operations, ..} = &self.binary_ops[*op_id] {
755                        let a = tos!();
756                        let b = tos!();
757
758                        let ov = &operations[*ov_id];
759
760                        if let Err(msg) = ov.operation.unwrap()(type_args, &ov.ret, a, b, self) {
761                            return Err(RynaError::execution_error(msg));
762                        };
763                        
764                        ip += 1;
765                    
766                    } else {
767                        unreachable!();
768                    }
769                }),
770
771                NaryOperatorCall(op_id, ov_id, type_args) => ryna_instruction!("NaryOperatorCall", {
772                    if let Operator::Nary{operations, ..} = &self.nary_ops[*op_id] {
773                        let op_ov = &operations[*ov_id];
774                        let res = op_ov.operation.unwrap()((&mut stack, &mut offset, &mut call_stack, &mut ip), type_args, &op_ov.ret);
775
776                        if let Err(msg) = res {
777                            return Err(RynaError::execution_error(msg));
778                        }
779
780                    } else {
781                        unreachable!();
782                    }
783                }),
784
785                ToFloat => unary_op!("ToFloat", a, get, Integer, f64::rounding_from(a, RoundingMode::Exact).0),
786
787                Ref => ryna_instruction!("Ref", {
788                    let a = tos!();
789                    stack.push(a.get_ref_nostack());
790                    ip += 1;
791                }),
792
793                Mut => ryna_instruction!("Mut", {
794                    let a = tos!();
795                    stack.push(a.get_mut_nostack());
796                    ip += 1;
797                }),
798
799                Copy => ryna_instruction!("Copy", {
800                    let a = tos!();
801                    stack.push(a.deref_obj().deep_clone());
802                    ip += 1;
803                }),
804
805                Deref => ryna_instruction!("Deref", {
806                    let a = tos!();
807                    stack.push(a.deref_obj());
808                    ip += 1;
809                }),
810
811                Demut => ryna_instruction!("Demut", {
812                    let a = tos!();
813                    stack.push(a.get_ref());
814                    ip += 1;
815                }),
816
817                Move => ryna_instruction!("Move", {
818                    let a = tos!();
819                    stack.push(a.move_contents());
820                    ip += 1;
821                }),
822
823                Inc => ryna_instruction!("Inc", {
824                    let a = tos!();
825                    *a.deref::<Integer>() += &*ONE;
826                    ip += 1;
827                }),
828
829                Dec => ryna_instruction!("Dec", {
830                    let a = tos!();
831                    *a.deref::<Integer>() -= &*ONE;
832                    ip += 1;
833                }),
834
835                Addi => bin_op!("Addi", a, b, get, get, Integer, a + b),
836                Subi => bin_op!("Subi", a, b, get, get, Integer, a - b),
837                Muli => bin_op!("Muli", a, b, get, get, Integer, a * b),
838                Divi => bin_op!("Divi", a, b, get, get, Integer, a / b),
839                Modi => bin_op!("Modi", a, b, get, get, Integer, a % b),
840                Negi => unary_op!("Negi", a, get, Integer, -a),
841                Addf => bin_op!("Addf", a, b, get, get, f64, a + b),
842                Subf => bin_op!("Subf", a, b, get, get, f64, a - b),
843                Mulf => bin_op!("Mulf", a, b, get, get, f64, a * b),
844                Divf => bin_op!("Divf", a, b, get, get, f64, a / b),
845                Modf => bin_op!("Modf", a, b, get, get, f64, a % b),
846                Negf => unary_op!("Negf", a, get, f64, -a),
847
848                AddStr => bin_op!("AddStr", a, b, get, get, String, format!("{}{}", a, b)),
849
850                NotB => unary_op!("NotB", a, get, Integer, !a),
851                AndB => bin_op!("AndB", a, b, get, get, Integer, a & b),
852                OrB => bin_op!("OrB", a, b, get, get, Integer, a | b),
853                XorB => bin_op!("XorB", a, b, get, get, Integer, a ^ b),
854                Shl => bin_op!("Shl", a, b, get, get, Integer, a << SaturatingInto::<i64>::saturating_into(b)),
855                Shr => bin_op!("Shr", a, b, get, get, Integer, a >> SaturatingInto::<i64>::saturating_into(b)),
856
857                Lti => bin_op!("Lti", a, b, get, get, Integer, a < b),
858                Gti => bin_op!("Gti", a, b, get, get, Integer, a > b),
859                Lteqi => bin_op!("Lteqi", a, b, get, get, Integer, a <= b),
860                Gteqi => bin_op!("Gteqi", a, b, get, get, Integer, a >= b),
861                Eqi => bin_op!("Eqi", a, b, get, get, Integer, a == b),
862                Neqi => bin_op!("Neqi", a, b, get, get, Integer, a != b),
863                Ltf => bin_op!("Ltf", a, b, get, get, f64, a < b),
864                Gtf => bin_op!("Gtf", a, b, get, get, f64, a > b),
865                Lteqf => bin_op!("Lteqf", a, b, get, get, f64, a <= b),
866                Gteqf => bin_op!("Gteqf", a, b, get, get, f64, a >= b),
867                Eqf => bin_op!("Eqf", a, b, get, get, f64, a == b),
868                Neqf => bin_op!("Neqf", a, b, get, get, f64, a != b),
869
870                EqBool => bin_op!("EqBool", a, b, get, get, bool, a == b),
871                NeqBool => bin_op!("NeqBool", a, b, get, get, bool, a != b),
872
873                EqStr => bin_op!("EqStr", a, b, get, get, String, a == b),
874                NeqStr => bin_op!("NeqStr", a, b, get, get, String, a != b),
875
876                Not => unary_op!("Not", a, get, bool, !a),
877                Or => bin_op!("Or", a, b, get, get, bool, *a || *b),
878                And => bin_op!("And", a, b, get, get, bool, *a && *b),
879                Xor => bin_op!("Xor", a, b, get, get, bool, *a ^ *b),
880                Nor => bin_op!("Nor", a, b, get, get, bool, !(*a || *b)),
881                Nand => bin_op!("Nand", a, b, get, get, bool, !(*a && *b)),
882
883                Placeholder(_) => unreachable!(),
884
885                Halt => break,
886            }
887        }
888
889        Ok(ExecutionInfo {
890            profiling_info: if DEBUG {
891                Some(ProfilingInfo { 
892                    instr_count, instr_time, loc_time, total_time
893                })
894
895            } else {
896                None
897            },
898
899            captured_output: self.captured_output.borrow().clone()
900        })
901    }
902}
903
904/*
905                                                  ╒═════════╕
906    ============================================= │  TESTS  │ =============================================
907                                                  ╘═════════╛
908*/
909
910#[cfg(test)]
911mod tests {
912    use malachite::Integer;
913
914    use crate::object::*;
915    use crate::context::*;
916    use crate::types::*;
917
918    #[test]
919    fn compilation_and_execution() {
920        let mut ctx = standard_ctx();
921
922        let code_str = "
923            fn test(a: Int) -> Int {
924                if 0 < a {
925                    return test(a - 1) + a;
926                }
927
928                print(*a);
929                print(0 < a);
930
931                return 0;
932            }
933
934            let a = test(100);
935        ";
936
937        ctx.parse_and_execute_ryna_module(&code_str.into()).unwrap();
938
939        assert_eq!(ctx.variables[0], Object::new(Integer::from(5050)));
940    }
941
942    #[test]
943    fn variable_definition() {
944        let mut ctx = standard_ctx();
945        
946        let code_str = "
947            let v_0 = 0;
948            let v_1: Bool = true;
949            let v_2: String = \"test\";
950        ".to_string();
951
952        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
953
954        assert_eq!(ctx.variables[0], Object::new(Integer::from(0)));
955        assert_eq!(ctx.variables[1], Object::new(true));
956        assert_eq!(ctx.variables[2], Object::new("test".to_string()));
957    }
958
959    #[test]
960    fn operations_and_functions() {
961        let mut ctx = standard_ctx();
962        
963        let code_str = "
964            let v_0 = !true;
965            let v_1 = 3 + 4;
966            let v_2: Int = 2;
967
968            inc(v_2);
969            inc(v_2);
970        ".to_string();
971
972        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
973
974        assert_eq!(ctx.variables[0], Object::new(false));
975        assert_eq!(ctx.variables[1], Object::new(Integer::from(7)));
976        assert_eq!(ctx.variables[2], Object::new(Integer::from(4)));
977    }
978
979    #[test]
980    fn flow_control() {
981        let mut ctx = standard_ctx();
982        
983        let code_str = "
984            let array: Array<Int> = arr<Int>();
985            array.push<Int>(5);
986
987            let iter: ArrayIterator<Int, @Int> = array.iterator<Int>();
988            let ended_1: Bool = iter.is_consumed();
989            
990            let elem: @Int = iter.next<Int>();
991            let ended_2: Bool = iter.is_consumed();
992
993            let array_2: Array<Int> = arr<Int>();
994            array_2.push<Int>(0);
995            array_2.push<Int>(2);
996            array_2.push<Int>(4);
997            array_2.push<Int>(6);
998            array_2.push<Int>(8);
999
1000            let sum: Int = 0;
1001
1002            for i in array_2 {
1003                sum = sum + i;
1004            }
1005
1006            let array_3: Array<Int> = arr<Int>();
1007            array_3.push<Int>(0);
1008            array_3.push<Int>(1);
1009            array_3.push<Int>(2);
1010            array_3.push<Int>(3);
1011            array_3.push<Int>(4);
1012            array_3.push<Int>(5);
1013            array_3.push<Int>(6);
1014            array_3.push<Int>(7);
1015            array_3.push<Int>(8);
1016
1017            let sum_2: Int = 0;
1018
1019            for i in array_3 {
1020                if i % 2 != 0 {
1021                    sum_2 = sum_2 + i;
1022                }
1023            }
1024        ".to_string();
1025
1026        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1027
1028        assert_eq!(ctx.variables[0], Object::arr(vec!(Object::new(Integer::from(5))), INT));
1029        assert_eq!(ctx.variables[1], Object::arr_it(INT, Type::MutRef(Box::new(INT)), ctx.variables[0].inner.clone(), 1));
1030        assert_eq!(ctx.variables[2], Object::new(false));
1031        assert_eq!(ctx.variables[3], Object::new(Integer::from(5)).get_mut());
1032        assert_eq!(ctx.variables[4], Object::new(true));
1033        assert_eq!(ctx.variables[5], Object::arr(vec!(
1034            Object::new(Integer::from(0)),
1035            Object::new(Integer::from(2)),
1036            Object::new(Integer::from(4)),
1037            Object::new(Integer::from(6)),
1038            Object::new(Integer::from(8)),
1039        ), INT));
1040        assert_eq!(ctx.variables[6], Object::new(Integer::from(20)));
1041
1042        if let Type::Template(..) = ctx.variables[8].get_type() {
1043            assert_eq!(ctx.variables[8], Object::arr(vec!(
1044                Object::new(Integer::from(0)),
1045                Object::new(Integer::from(1)),
1046                Object::new(Integer::from(2)),
1047                Object::new(Integer::from(3)),
1048                Object::new(Integer::from(4)),
1049                Object::new(Integer::from(5)),
1050                Object::new(Integer::from(6)),
1051                Object::new(Integer::from(7)),
1052                Object::new(Integer::from(8)),
1053            ), INT));
1054            assert_eq!(ctx.variables[9], Object::new(Integer::from(16)));
1055
1056        } else {
1057            assert_eq!(ctx.variables[9], Object::arr(vec!(
1058                Object::new(Integer::from(0)),
1059                Object::new(Integer::from(1)),
1060                Object::new(Integer::from(2)),
1061                Object::new(Integer::from(3)),
1062                Object::new(Integer::from(4)),
1063                Object::new(Integer::from(5)),
1064                Object::new(Integer::from(6)),
1065                Object::new(Integer::from(7)),
1066                Object::new(Integer::from(8)),
1067            ), INT));
1068            assert_eq!(ctx.variables[8], Object::new(Integer::from(16)));
1069        }
1070
1071        let mut ctx = standard_ctx();
1072        
1073        let code_str = "
1074            fn is_prime(n: @Int) -> Bool {
1075                if n <= 1 {
1076                    return false;
1077                }
1078                
1079                let i: Int = 1;
1080
1081                while i < n - 1 {
1082                    i = i + 1;
1083
1084                    if n % i == 0 {
1085                        return false;
1086                    }
1087                }
1088
1089                return true;
1090            }
1091
1092            let array: Array<Int> = arr<Int>();
1093            let it: Int = 0;
1094
1095            while it < 50 {
1096                if is_prime(it) {
1097                    array.push<Int>(it.deref<Int>());
1098                }
1099
1100                it = it + 1;
1101            }
1102        ".to_string();
1103        
1104        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1105
1106        assert_eq!(ctx.variables[0], Object::arr(vec!(
1107            Object::new(Integer::from(2)),
1108            Object::new(Integer::from(3)),
1109            Object::new(Integer::from(5)),
1110            Object::new(Integer::from(7)),
1111            Object::new(Integer::from(11)),
1112            Object::new(Integer::from(13)),
1113            Object::new(Integer::from(17)),
1114            Object::new(Integer::from(19)),
1115            Object::new(Integer::from(23)),
1116            Object::new(Integer::from(29)),
1117            Object::new(Integer::from(31)),
1118            Object::new(Integer::from(37)),
1119            Object::new(Integer::from(41)),
1120            Object::new(Integer::from(43)),
1121            Object::new(Integer::from(47)),
1122        ), INT));
1123    }
1124
1125    #[test]
1126    fn operator_definitions() {
1127        let mut ctx = standard_ctx();
1128        
1129        let code_str = "
1130            unary prefix op \"~\" (201);
1131
1132            op ~(arg: @Int) -> @Int {
1133                return arg;
1134            }
1135
1136            unary postfix op \"¡\" (301);
1137
1138            op (arg: @Int)¡ -> @Int {
1139                return arg;
1140            }
1141
1142            let a: Int = 3;
1143            let b: @Int = ~a¡;
1144
1145            binary op \"·\" (401);
1146            binary op \"$\" (501);
1147            binary op \"@\" (601);
1148
1149            op (a: @Int) · (b: @Int) -> Int {
1150                return a + b;
1151            }
1152
1153            let c: Int = a · b;
1154
1155            nary op from \"`\" to \"´\" (701);
1156
1157            op (a: @Int)`b: @Int, c: @Int´ -> Int {
1158                return a + b + ~c;
1159            }
1160
1161            let d = a`b, c´;
1162        ".to_string();
1163
1164        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1165    }
1166
1167    #[test]
1168    fn function_definitions() {
1169        let mut ctx = standard_ctx();
1170        
1171        let code_str = "
1172            fn test_1() -> Int {
1173                return 5;
1174            }
1175        
1176            fn test_2() -> @Int {
1177                let res: Int = 0;
1178
1179                return res;
1180            }
1181        
1182            fn test_3() -> @String {
1183                let res: String = \"\";
1184
1185                res = \"Hello\";
1186
1187                return res;
1188            }
1189        
1190            fn test_4() -> @Int {
1191                let res: Int = test_1() + test_1();
1192
1193                return res;
1194            }
1195        
1196            fn test_5(a: Int, b: Int) -> @Int {
1197                let res: Int = a + b;
1198
1199                return res;
1200            }
1201        
1202            fn test_6(a: Int) -> Int | @Int {
1203                if true {
1204                    return a;
1205
1206                } else {
1207                    return 0;
1208                }
1209            }
1210        
1211            fn test_7(a: Int) -> Int {
1212                if 0 < a {
1213                    return test_7(a - 1) + a;
1214                }
1215
1216                return 0;
1217            }
1218        
1219            fn test_8(a: Int) -> Int {
1220                if a == 1 {
1221                    return 1;
1222
1223                } else if a % 2 == 0 {
1224                    return test_8(a / 2) + 1;
1225
1226                } else {
1227                    return test_8(a * 3 + 1) + 1;
1228                }
1229            }
1230
1231            let v_1 = test_1();
1232            let v_2 = test_2();
1233            let v_3 = test_3();
1234            let v_4 = test_4();
1235            let v_5 = test_5(2, 4);
1236            let v_6 = test_6(9);
1237            let v_7 = test_7(10);
1238            let v_8 = test_8(100);
1239        ".to_string();
1240
1241        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1242
1243        assert_eq!(ctx.variables[0], Object::new(Integer::from(5)));
1244        assert_eq!(ctx.variables[1], Object::new(Integer::from(0)).get_mut());
1245        assert_eq!(ctx.variables[2], Object::new("Hello".to_string()).get_mut());
1246        assert_eq!(ctx.variables[3], Object::new(Integer::from(10)).get_mut());
1247        assert_eq!(ctx.variables[4], Object::new(Integer::from(6)).get_mut());
1248        assert_eq!(ctx.variables[5], Object::new(Integer::from(9)).get_mut());
1249        assert_eq!(ctx.variables[6], Object::new(Integer::from(55)));
1250        assert_eq!(ctx.variables[7], Object::new(Integer::from(26)));
1251    }
1252
1253    #[test]
1254    fn templated_functions() {
1255        let mut ctx = standard_ctx();
1256        
1257        let code_str = "
1258            fn<T> test() -> Array<'T> {
1259                return arr<'T>();
1260            }
1261
1262            let a = test<Int>();
1263            let b = test<String>();
1264        ".to_string();
1265
1266        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1267
1268        assert_eq!(ctx.variables[0], Object::arr(vec!(), INT));
1269        assert_eq!(ctx.variables[1], Object::arr(vec!(), STR));
1270
1271        let mut ctx = standard_ctx();
1272        
1273        let code_str = "
1274            fn<T> sum(a: 'T, b: 'T) -> 'T {
1275                return a + b;
1276            }
1277
1278            let a = sum<Int>(5, 6);
1279            let b = sum<String>(\"test\", \"tset\");
1280        ".to_string();
1281
1282        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1283
1284        assert_eq!(ctx.variables[0], Object::new(Integer::from(11)));
1285        assert_eq!(ctx.variables[1], Object::new("testtset".to_string()));
1286    }
1287
1288    #[test]
1289    fn templated_operations() {
1290        let mut ctx = standard_ctx();
1291        
1292        let code_str = "
1293            unary prefix op \"~\" (151);
1294
1295            op<T> ~(a: 'T) -> 'T {
1296                return a + a;
1297            }
1298            
1299            let a = ~<Int>7;
1300            let b = ~<String>\"test\";
1301        ".to_string();
1302
1303        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1304
1305        assert_eq!(ctx.variables[0], Object::new(Integer::from(14)));
1306        assert_eq!(ctx.variables[1], Object::new("testtest".to_string()));
1307        
1308        let mut ctx = standard_ctx();
1309        
1310        let code_str = "
1311            unary postfix op \"~\" (151);
1312
1313            op<T> (a: 'T)~ -> 'T {
1314                return a + a;
1315            }
1316            
1317            let a = 7<Int>~;
1318            let b = \"test\"<String>~;
1319        ".to_string();
1320
1321        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1322
1323        assert_eq!(ctx.variables[0], Object::new(Integer::from(14)));
1324        assert_eq!(ctx.variables[1], Object::new("testtest".to_string()));
1325        
1326        let mut ctx = standard_ctx();
1327        
1328        let code_str = "
1329            binary op \"@\" (151);
1330
1331            op<T> (a: 'T) @ (b: 'T) -> 'T {
1332                return a + b;
1333            }
1334
1335            let a = 5 <Int>@ 8;
1336            let b = \"test\" <String>@ \"tset\";
1337        ".to_string();
1338
1339        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1340
1341        assert_eq!(ctx.variables[0], Object::new(Integer::from(13)));
1342        assert_eq!(ctx.variables[1], Object::new("testtset".to_string()));
1343        
1344        let mut ctx = standard_ctx();
1345        
1346        let code_str = "
1347            nary op from \"`\" to \"´\" (151);
1348
1349            op<T, G> (a: 'T)`b: 'G´ -> 'T {
1350                return a + b;
1351            }
1352
1353            let a = 2<Int, Int>`9´;
1354            let b = \"test\"<String, String>`\"tttt\"´;
1355        ".to_string();
1356
1357        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1358
1359        assert_eq!(ctx.variables[0], Object::new(Integer::from(11)));
1360        assert_eq!(ctx.variables[1], Object::new("testtttt".to_string()));
1361    }
1362
1363    #[test]
1364    fn custom_iterators() {
1365        let mut ctx = standard_ctx();
1366        
1367        let code_str = "
1368        fn iterator(it: Int) -> Int {
1369            return it.deref<Int>();
1370        }
1371
1372        fn next(it: @Int) -> Int {
1373            it.inc();
1374            return it.deref<Int>();
1375        }
1376
1377        fn is_consumed(it: @Int) -> Bool {
1378            return it >= 10;
1379        }
1380
1381        implement Iterable<Int, Int> for Int;
1382
1383        let sum: Int = 0;
1384
1385        for i in 0 {
1386            sum = sum + i;
1387        }
1388        ".to_string();
1389
1390        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1391
1392        assert_eq!(ctx.variables[0], Object::new(Integer::from(55)));
1393
1394        let mut ctx = standard_ctx();
1395        
1396        let code_str = "
1397        class Range {
1398            start: Int;
1399            current: Int;
1400            end: Int;
1401        }
1402
1403        fn iterator(it: Range) -> Range {
1404            return it.deref<Range>();
1405        }
1406
1407        fn next(it: @Range) -> Int {
1408            let curr: @Int = it.current;
1409            curr.inc();
1410
1411            return curr.deref<Int>();
1412        }
1413
1414        fn is_consumed(it: @Range) -> Bool {
1415            return it.current >= it.end;
1416        }
1417
1418        implement Iterable<Range, Int> for Range;
1419
1420        let sum: Int = 0;
1421
1422        for i in Range(0, 0, 10) {
1423            sum = sum + i;
1424        }
1425        ".to_string();
1426
1427        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1428
1429        assert_eq!(ctx.variables[0], Object::new(Integer::from(55)));
1430    }
1431
1432    #[test]
1433    fn class_definitions() {
1434        let mut ctx = standard_ctx();
1435        
1436        let code_str = "
1437        class Range {
1438            start: Int;
1439            current: Int;
1440            end: Int;
1441        }
1442
1443        let r: Range = Range(0, 2, 10);
1444
1445        let a = r.start;
1446        let b = r.current;
1447        let c = r.end;
1448        ".to_string();
1449
1450        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1451
1452        let id = ctx.get_type_id("Range".into()).unwrap();
1453
1454        assert_eq!(ctx.variables[0], Object::new(TypeInstance {
1455            id,
1456            params: vec!(),
1457            attributes: vec!(
1458                Object::new(Integer::from(0)),
1459                Object::new(Integer::from(2)),
1460                Object::new(Integer::from(10))
1461            )
1462        }));
1463
1464        assert_eq!(ctx.variables[1], Object::new(Integer::from(0)).get_mut());
1465        assert_eq!(ctx.variables[2], Object::new(Integer::from(2)).get_mut());
1466        assert_eq!(ctx.variables[3], Object::new(Integer::from(10)).get_mut());
1467
1468        let mut ctx = standard_ctx();
1469        
1470        let code_str = "
1471        class Option<T> {
1472            present: Bool;
1473            obj: 'T;
1474        }
1475
1476        let a: Option<Int> = Option<Int>(true, 5);
1477
1478        let b = a.present;
1479        let c = a.obj;
1480        ".to_string();
1481
1482        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1483
1484        let id = ctx.get_type_id("Option".into()).unwrap();
1485
1486        assert_eq!(ctx.variables[0], Object::new(TypeInstance {
1487            id,
1488            params: vec!(INT),
1489            attributes: vec!(
1490                Object::new(true),
1491                Object::new(Integer::from(5))
1492            )
1493        }));
1494
1495        assert_eq!(ctx.variables[1], Object::new(true).get_mut());
1496        assert_eq!(ctx.variables[2], Object::new(Integer::from(5)).get_mut());
1497    }
1498
1499    #[test]
1500    fn lambda_definition() {
1501        let mut ctx = standard_ctx();
1502        
1503        let code_str = "
1504        let a: (Int) => Int = (n: Int) -> Int n * 2;
1505
1506        let b = a<Int, Int>(4);
1507
1508        let c: (Int, Bool) => Int = (n: Int, b: Bool) -> Int {
1509            if *<Bool>b {
1510                return n + 2;
1511            }
1512
1513            return n + 1;
1514        };
1515
1516        let d = c<Int, Bool, Int>(5, true);
1517        let e = c<Int, Bool, Int>(5, false);
1518        ".to_string();
1519
1520        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1521
1522        assert_eq!(ctx.variables[1], Object::new(Integer::from(8)));
1523        assert_eq!(ctx.variables[3], Object::new(Integer::from(7)));
1524        assert_eq!(ctx.variables[4], Object::new(Integer::from(6)));
1525
1526        let mut ctx = standard_ctx();
1527        
1528        let code_str = "
1529        let apply: (Int, @(Int => Int)) => Int = (n: Int, f: @(Int => Int)) -> Int f<Int, Int>(*<Int>n);
1530        let f: (Int) => Int = (n: Int) -> Int n * n;
1531
1532        let a = apply<Int, @(Int => Int), Int>(5, f);
1533        ".to_string();
1534
1535        ctx.parse_and_execute_ryna_module(&code_str).unwrap();
1536
1537        assert_eq!(ctx.variables[2], Object::new(Integer::from(25)));
1538    }
1539}