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
22impl 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 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 unsafe { *self.variables.get_unchecked_mut($id) = $value; }
256 }
257 }
258
259 macro_rules! get_variable {
260 ($id: expr) => {
261 unsafe { self.variables.get_unchecked($id) }
264 }
265 }
266
267 macro_rules! update_max_var {
268 ($id: expr) => {
269 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 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 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#[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}