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