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