1use std::collections::HashMap;
7
8use indexmap::IndexMap;
9
10use crate::ast::{BinaryOp, Block, ElseClause, Expression, Program, Statement, UnaryOp};
11use crate::builtins::get_default_builtins;
12use crate::error::RuntimeError;
13use crate::Value;
14
15const MAX_CALL_DEPTH: usize = 64;
19
20const MAX_OUTPUT_LINES: usize = 1000;
22
23const MAX_OUTPUT_BYTES: usize = 64 * 1024; #[derive(Debug, Clone)]
28struct UserFunction {
29 params: Vec<String>,
31 body: Block,
33}
34
35enum ControlFlow {
37 Continue(Value),
39 Return(Value),
41}
42
43impl ControlFlow {
44 fn into_value(self) -> Value {
45 match self {
46 ControlFlow::Continue(v) | ControlFlow::Return(v) => v,
47 }
48 }
49}
50
51pub struct Interpreter {
53 scopes: Vec<HashMap<String, Value>>,
55 functions: HashMap<String, UserFunction>,
57 builtins: HashMap<String, fn(Vec<Value>) -> Result<Value, RuntimeError>>,
59 output: Vec<String>,
61 output_bytes: usize,
63 output_truncated: bool,
65 call_depth: usize,
67}
68
69impl Default for Interpreter {
70 fn default() -> Self {
71 Self::new()
72 }
73}
74
75impl Interpreter {
76 pub fn new() -> Self {
81 Self::with_builtins(get_default_builtins())
82 }
83
84 pub fn with_builtins(
89 builtins: HashMap<String, fn(Vec<Value>) -> Result<Value, RuntimeError>>,
90 ) -> Self {
91 let mut global_scope = HashMap::new();
92
93 for (key, value) in std::env::vars() {
95 global_scope.insert(key, Value::String(value));
96 }
97
98 Self {
99 scopes: vec![global_scope],
100 functions: HashMap::new(),
101 builtins,
102 output: Vec::new(),
103 output_bytes: 0,
104 output_truncated: false,
105 call_depth: 0,
106 }
107 }
108
109 pub fn new_without_env() -> Self {
111 Self {
112 scopes: vec![HashMap::new()],
113 functions: HashMap::new(),
114 builtins: get_default_builtins(),
115 output: Vec::new(),
116 output_bytes: 0,
117 output_truncated: false,
118 call_depth: 0,
119 }
120 }
121
122 pub fn parse_only(&self, source: &str) -> Result<crate::ast::Program, crate::FiddlerError> {
127 crate::parse(source)
128 }
129
130 pub fn run(&mut self, source: &str) -> Result<Value, crate::FiddlerError> {
132 let program = crate::parse(source)?;
133 Ok(self.execute(&program)?)
134 }
135
136 pub fn execute(&mut self, program: &Program) -> Result<Value, RuntimeError> {
138 let mut result = Value::Null;
139 for statement in &program.statements {
140 match self.execute_statement(statement)? {
141 ControlFlow::Continue(v) => result = v,
142 ControlFlow::Return(_) => {
143 return Err(RuntimeError::ReturnOutsideFunction);
144 }
145 }
146 }
147 Ok(result)
148 }
149
150 pub fn output(&self) -> &[String] {
152 &self.output
153 }
154
155 pub fn clear_output(&mut self) {
157 self.output.clear();
158 self.output_bytes = 0;
159 self.output_truncated = false;
160 }
161
162 pub fn is_output_truncated(&self) -> bool {
164 self.output_truncated
165 }
166
167 pub fn set_variable_value(&mut self, name: impl Into<String>, value: Value) {
178 if let Some(scope) = self.scopes.first_mut() {
179 scope.insert(name.into(), value);
180 }
181 }
182
183 pub fn set_variable_bytes(&mut self, name: impl Into<String>, bytes: Vec<u8>) {
191 self.set_variable_value(name, Value::Bytes(bytes));
192 }
193
194 pub fn set_variable_string(&mut self, name: impl Into<String>, value: impl Into<String>) {
202 self.set_variable_value(name, Value::String(value.into()));
203 }
204
205 pub fn set_variable_int(&mut self, name: impl Into<String>, value: i64) {
213 self.set_variable_value(name, Value::Integer(value));
214 }
215
216 pub fn set_variable_array(&mut self, name: impl Into<String>, values: Vec<Value>) {
224 self.set_variable_value(name, Value::Array(values));
225 }
226
227 pub fn set_variable_dict(&mut self, name: impl Into<String>, values: IndexMap<String, Value>) {
235 self.set_variable_value(name, Value::Dictionary(values));
236 }
237
238 pub fn get_value(&self, name: &str) -> Option<Value> {
249 for scope in self.scopes.iter().rev() {
250 if let Some(value) = scope.get(name) {
251 return Some(value.clone());
252 }
253 }
254 None
255 }
256
257 pub fn get_bytes(&self, name: &str) -> Option<Vec<u8>> {
268 self.get_value(name).map(|v| v.to_bytes())
269 }
270
271 pub fn has_variable(&self, name: &str) -> bool {
280 self.get_value(name).is_some()
281 }
282
283 fn push_scope(&mut self) {
286 self.scopes.push(HashMap::new());
287 }
288
289 fn pop_scope(&mut self) {
290 self.scopes.pop();
291 }
292
293 fn define_variable(&mut self, name: String, value: Value) {
294 if let Some(scope) = self.scopes.last_mut() {
295 scope.insert(name, value);
296 }
297 }
298
299 fn get_variable(&self, name: &str) -> Result<Value, RuntimeError> {
300 for scope in self.scopes.iter().rev() {
301 if let Some(value) = scope.get(name) {
302 return Ok(value.clone());
303 }
304 }
305 Err(RuntimeError::undefined_variable(name))
306 }
307
308 fn set_variable(&mut self, name: &str, value: Value) -> Result<(), RuntimeError> {
309 for scope in self.scopes.iter_mut().rev() {
310 if scope.contains_key(name) {
311 scope.insert(name.to_string(), value);
312 return Ok(());
313 }
314 }
315 Err(RuntimeError::undefined_variable(name))
316 }
317
318 fn execute_statement(&mut self, stmt: &Statement) -> Result<ControlFlow, RuntimeError> {
321 match stmt {
322 Statement::Let { name, value, .. } => {
323 let val = self.evaluate_expression(value)?;
324 self.define_variable(name.clone(), val);
325 Ok(ControlFlow::Continue(Value::Null))
326 }
327
328 Statement::If {
329 condition,
330 then_block,
331 else_block,
332 ..
333 } => {
334 let cond = self.evaluate_expression(condition)?;
335 if self.is_truthy(&cond) {
336 self.execute_block(then_block)
337 } else if let Some(else_clause) = else_block {
338 match else_clause {
339 ElseClause::Block(block) => self.execute_block(block),
340 ElseClause::ElseIf(if_stmt) => self.execute_statement(if_stmt),
341 }
342 } else {
343 Ok(ControlFlow::Continue(Value::Null))
344 }
345 }
346
347 Statement::For {
348 init,
349 condition,
350 update,
351 body,
352 ..
353 } => {
354 self.push_scope();
355
356 if let Some(init_stmt) = init {
358 self.execute_statement(init_stmt)?;
359 }
360
361 loop {
363 if let Some(cond) = condition {
365 let cond_val = self.evaluate_expression(cond)?;
366 if !self.is_truthy(&cond_val) {
367 break;
368 }
369 }
370
371 match self.execute_block(body)? {
373 ControlFlow::Return(v) => {
374 self.pop_scope();
375 return Ok(ControlFlow::Return(v));
376 }
377 ControlFlow::Continue(_) => {}
378 }
379
380 if let Some(upd) = update {
382 self.evaluate_expression(upd)?;
383 }
384 }
385
386 self.pop_scope();
387 Ok(ControlFlow::Continue(Value::Null))
388 }
389
390 Statement::Return { value, .. } => {
391 let val = if let Some(expr) = value {
392 self.evaluate_expression(expr)?
393 } else {
394 Value::Null
395 };
396 Ok(ControlFlow::Return(val))
397 }
398
399 Statement::Function {
400 name, params, body, ..
401 } => {
402 self.functions.insert(
403 name.clone(),
404 UserFunction {
405 params: params.clone(),
406 body: body.clone(),
407 },
408 );
409 Ok(ControlFlow::Continue(Value::Null))
410 }
411
412 Statement::Expression { expression, .. } => {
413 let val = self.evaluate_expression(expression)?;
414 Ok(ControlFlow::Continue(val))
415 }
416
417 Statement::Block(block) => self.execute_block(block),
418 }
419 }
420
421 fn execute_block(&mut self, block: &Block) -> Result<ControlFlow, RuntimeError> {
422 self.push_scope();
423 let mut result = ControlFlow::Continue(Value::Null);
424
425 for stmt in &block.statements {
426 result = self.execute_statement(stmt)?;
427 if matches!(result, ControlFlow::Return(_)) {
428 break;
429 }
430 }
431
432 self.pop_scope();
433 Ok(result)
434 }
435
436 fn evaluate_expression(&mut self, expr: &Expression) -> Result<Value, RuntimeError> {
439 match expr {
440 Expression::Integer { value, .. } => Ok(Value::Integer(*value)),
441 Expression::Float { value, .. } => Ok(Value::Float(*value)),
442 Expression::String { value, .. } => Ok(Value::String(value.clone())),
443 Expression::Boolean { value, .. } => Ok(Value::Boolean(*value)),
444 Expression::Null { .. } => Ok(Value::Null),
445
446 Expression::Identifier { name, .. } => self.get_variable(name),
447
448 Expression::Binary {
449 left,
450 operator,
451 right,
452 ..
453 } => {
454 let left_val = self.evaluate_expression(left)?;
455 let right_val = self.evaluate_expression(right)?;
456 self.evaluate_binary_op(*operator, left_val, right_val)
457 }
458
459 Expression::Unary {
460 operator, operand, ..
461 } => {
462 let val = self.evaluate_expression(operand)?;
463 self.evaluate_unary_op(*operator, val)
464 }
465
466 Expression::Assignment { name, value, .. } => {
467 let val = self.evaluate_expression(value)?;
468 self.set_variable(name, val.clone())?;
469 Ok(val)
470 }
471
472 Expression::Call {
473 function,
474 arguments,
475 ..
476 } => self.call_function(function, arguments),
477
478 Expression::MethodCall {
479 receiver,
480 method,
481 arguments,
482 ..
483 } => self.call_method(receiver, method, arguments),
484
485 Expression::Grouped { expression, .. } => self.evaluate_expression(expression),
486
487 Expression::ArrayLiteral { elements, .. } => {
488 let values: Vec<Value> = elements
489 .iter()
490 .map(|e| self.evaluate_expression(e))
491 .collect::<Result<_, _>>()?;
492 Ok(Value::Array(values))
493 }
494
495 Expression::DictionaryLiteral { pairs, .. } => {
496 let mut dict = IndexMap::new();
497 for (key_expr, value_expr) in pairs {
498 let key = match self.evaluate_expression(key_expr)? {
499 Value::String(s) => s,
500 _ => {
501 return Err(RuntimeError::type_mismatch(
502 "Dictionary key must be a string",
503 ))
504 }
505 };
506 let value = self.evaluate_expression(value_expr)?;
507 dict.insert(key, value);
508 }
509 Ok(Value::Dictionary(dict))
510 }
511 }
512 }
513
514 fn evaluate_binary_op(
515 &mut self,
516 op: BinaryOp,
517 left: Value,
518 right: Value,
519 ) -> Result<Value, RuntimeError> {
520 match op {
521 BinaryOp::Add => match (&left, &right) {
523 (Value::Integer(a), Value::Integer(b)) => Ok(Value::Integer(a + b)),
524 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a + b)),
525 (Value::Integer(a), Value::Float(b)) => Ok(Value::Float(*a as f64 + b)),
526 (Value::Float(a), Value::Integer(b)) => Ok(Value::Float(a + *b as f64)),
527 (Value::String(a), Value::String(b)) => Ok(Value::String(format!("{}{}", a, b))),
528 _ => Err(RuntimeError::type_mismatch(format!(
529 "Cannot add {:?} and {:?}",
530 left, right
531 ))),
532 },
533 BinaryOp::Subtract => match (&left, &right) {
534 (Value::Integer(a), Value::Integer(b)) => Ok(Value::Integer(a - b)),
535 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a - b)),
536 (Value::Integer(a), Value::Float(b)) => Ok(Value::Float(*a as f64 - b)),
537 (Value::Float(a), Value::Integer(b)) => Ok(Value::Float(a - *b as f64)),
538 _ => Err(RuntimeError::type_mismatch(
539 "Subtraction requires numeric types".to_string(),
540 )),
541 },
542 BinaryOp::Multiply => match (&left, &right) {
543 (Value::Integer(a), Value::Integer(b)) => Ok(Value::Integer(a * b)),
544 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a * b)),
545 (Value::Integer(a), Value::Float(b)) => Ok(Value::Float(*a as f64 * b)),
546 (Value::Float(a), Value::Integer(b)) => Ok(Value::Float(a * *b as f64)),
547 _ => Err(RuntimeError::type_mismatch(
548 "Multiplication requires numeric types".to_string(),
549 )),
550 },
551 BinaryOp::Divide => match (&left, &right) {
552 (Value::Integer(_), Value::Integer(0)) => {
553 Err(RuntimeError::DivisionByZero { position: None })
554 }
555 (Value::Integer(a), Value::Integer(b)) => Ok(Value::Integer(a / b)),
556 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a / b)), (Value::Integer(a), Value::Float(b)) => Ok(Value::Float(*a as f64 / b)),
558 (Value::Float(a), Value::Integer(b)) => Ok(Value::Float(a / *b as f64)),
559 _ => Err(RuntimeError::type_mismatch(
560 "Division requires numeric types".to_string(),
561 )),
562 },
563 BinaryOp::Modulo => match (&left, &right) {
564 (Value::Integer(_), Value::Integer(0)) => {
565 Err(RuntimeError::DivisionByZero { position: None })
566 }
567 (Value::Integer(a), Value::Integer(b)) => Ok(Value::Integer(a % b)),
568 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a % b)),
569 (Value::Integer(a), Value::Float(b)) => Ok(Value::Float(*a as f64 % b)),
570 (Value::Float(a), Value::Integer(b)) => Ok(Value::Float(a % *b as f64)),
571 _ => Err(RuntimeError::type_mismatch(
572 "Modulo requires numeric types".to_string(),
573 )),
574 },
575
576 BinaryOp::Equal => Ok(Value::Boolean(left == right)),
578 BinaryOp::NotEqual => Ok(Value::Boolean(left != right)),
579 BinaryOp::LessThan
580 | BinaryOp::LessEqual
581 | BinaryOp::GreaterThan
582 | BinaryOp::GreaterEqual => self.evaluate_comparison(op, &left, &right),
583
584 BinaryOp::And => Ok(Value::Boolean(
586 self.is_truthy(&left) && self.is_truthy(&right),
587 )),
588 BinaryOp::Or => Ok(Value::Boolean(
589 self.is_truthy(&left) || self.is_truthy(&right),
590 )),
591 }
592 }
593
594 fn evaluate_comparison(
596 &self,
597 op: BinaryOp,
598 left: &Value,
599 right: &Value,
600 ) -> Result<Value, RuntimeError> {
601 let result = match (left, right) {
602 (Value::Integer(a), Value::Integer(b)) => match op {
603 BinaryOp::LessThan => a < b,
604 BinaryOp::LessEqual => a <= b,
605 BinaryOp::GreaterThan => a > b,
606 BinaryOp::GreaterEqual => a >= b,
607 _ => unreachable!(),
608 },
609 (Value::Float(a), Value::Float(b)) => match op {
610 BinaryOp::LessThan => a < b,
611 BinaryOp::LessEqual => a <= b,
612 BinaryOp::GreaterThan => a > b,
613 BinaryOp::GreaterEqual => a >= b,
614 _ => unreachable!(),
615 },
616 (Value::Integer(a), Value::Float(b)) => {
618 let a_float = *a as f64;
619 match op {
620 BinaryOp::LessThan => a_float < *b,
621 BinaryOp::LessEqual => a_float <= *b,
622 BinaryOp::GreaterThan => a_float > *b,
623 BinaryOp::GreaterEqual => a_float >= *b,
624 _ => unreachable!(),
625 }
626 }
627 (Value::Float(a), Value::Integer(b)) => {
628 let b_float = *b as f64;
629 match op {
630 BinaryOp::LessThan => *a < b_float,
631 BinaryOp::LessEqual => *a <= b_float,
632 BinaryOp::GreaterThan => *a > b_float,
633 BinaryOp::GreaterEqual => *a >= b_float,
634 _ => unreachable!(),
635 }
636 }
637 (Value::String(a), Value::String(b)) => match op {
638 BinaryOp::LessThan => a < b,
639 BinaryOp::LessEqual => a <= b,
640 BinaryOp::GreaterThan => a > b,
641 BinaryOp::GreaterEqual => a >= b,
642 _ => unreachable!(),
643 },
644 _ => {
645 return Err(RuntimeError::type_mismatch(
646 "Comparison requires matching or numeric types".to_string(),
647 ))
648 }
649 };
650 Ok(Value::Boolean(result))
651 }
652
653 fn evaluate_unary_op(&self, op: UnaryOp, operand: Value) -> Result<Value, RuntimeError> {
654 match op {
655 UnaryOp::Not => Ok(Value::Boolean(!self.is_truthy(&operand))),
656 UnaryOp::Negate => match operand {
657 Value::Integer(n) => Ok(Value::Integer(-n)),
658 Value::Float(f) => Ok(Value::Float(-f)),
659 _ => Err(RuntimeError::type_mismatch(
660 "Negation requires numeric type".to_string(),
661 )),
662 },
663 }
664 }
665
666 fn is_truthy(&self, value: &Value) -> bool {
667 match value {
668 Value::Boolean(b) => *b,
669 Value::Integer(n) => *n != 0,
670 Value::Float(f) => *f != 0.0 && !f.is_nan(),
671 Value::String(s) => !s.is_empty(),
672 Value::Bytes(b) => !b.is_empty(),
673 Value::Array(a) => !a.is_empty(),
674 Value::Dictionary(d) => !d.is_empty(),
675 Value::Null => false,
676 }
677 }
678
679 fn capture_print_output(&mut self, args: &[Value]) {
684 if self.output_truncated {
685 return;
686 }
687
688 let output_str = args
689 .iter()
690 .map(|v| format!("{}", v))
691 .collect::<Vec<_>>()
692 .join(" ");
693
694 let new_bytes = self.output_bytes + output_str.len();
695 let new_lines = self.output.len() + 1;
696
697 if new_lines > MAX_OUTPUT_LINES || new_bytes > MAX_OUTPUT_BYTES {
698 self.output.push("[truncated]".to_string());
699 self.output_truncated = true;
700 } else {
701 self.output_bytes = new_bytes;
702 self.output.push(output_str);
703 }
704 }
705
706 fn call_function(
708 &mut self,
709 name: &str,
710 arguments: &[Expression],
711 ) -> Result<Value, RuntimeError> {
712 let args: Vec<Value> = arguments
714 .iter()
715 .map(|arg| self.evaluate_expression(arg))
716 .collect::<Result<_, _>>()?;
717
718 if let Some(&builtin) = self.builtins.get(name) {
720 if name == "print" {
721 self.capture_print_output(&args);
722 }
723 return builtin(args);
724 }
725
726 if let Some(func) = self.functions.get(name).cloned() {
728 return self.call_user_function(&func, args);
729 }
730
731 Err(RuntimeError::undefined_function(name))
732 }
733
734 fn call_method(
764 &mut self,
765 receiver: &Expression,
766 method: &str,
767 arguments: &[Expression],
768 ) -> Result<Value, RuntimeError> {
769 let receiver_value = self.evaluate_expression(receiver)?;
771
772 let mut args = Vec::with_capacity(arguments.len() + 1);
775 args.push(receiver_value);
776
777 for arg in arguments {
778 args.push(self.evaluate_expression(arg)?);
779 }
780
781 if let Some(&builtin) = self.builtins.get(method) {
783 if method == "print" {
784 self.capture_print_output(&args);
785 }
786 return builtin(args);
787 }
788
789 if let Some(func) = self.functions.get(method).cloned() {
791 return self.call_user_function(&func, args);
792 }
793
794 Err(RuntimeError::undefined_function(method))
795 }
796
797 fn call_user_function(
799 &mut self,
800 func: &UserFunction,
801 args: Vec<Value>,
802 ) -> Result<Value, RuntimeError> {
803 if self.call_depth >= MAX_CALL_DEPTH {
805 return Err(RuntimeError::StackOverflow {
806 max_depth: MAX_CALL_DEPTH,
807 });
808 }
809
810 if args.len() != func.params.len() {
811 return Err(RuntimeError::WrongArgumentCount {
812 expected: func.params.len(),
813 actual: args.len(),
814 position: None,
815 });
816 }
817
818 self.call_depth += 1;
820
821 self.push_scope();
823
824 for (param, arg) in func.params.iter().zip(args) {
826 self.define_variable(param.clone(), arg);
827 }
828
829 let result = self.execute_block(&func.body);
831
832 self.pop_scope();
833
834 self.call_depth -= 1;
836
837 result.map(|cf| cf.into_value())
838 }
839}
840
841#[cfg(test)]
842mod tests {
843 use super::*;
844
845 fn run(source: &str) -> Result<Value, crate::FiddlerError> {
846 let mut interpreter = Interpreter::new();
847 interpreter.run(source)
848 }
849
850 #[test]
851 fn test_integer_literal() {
852 assert_eq!(run("42;").unwrap(), Value::Integer(42));
853 }
854
855 #[test]
856 fn test_string_literal() {
857 assert_eq!(
858 run(r#""hello";"#).unwrap(),
859 Value::String("hello".to_string())
860 );
861 }
862
863 #[test]
864 fn test_boolean_literal() {
865 assert_eq!(run("true;").unwrap(), Value::Boolean(true));
866 assert_eq!(run("false;").unwrap(), Value::Boolean(false));
867 }
868
869 #[test]
870 fn test_arithmetic() {
871 assert_eq!(run("5 + 3;").unwrap(), Value::Integer(8));
872 assert_eq!(run("5 - 3;").unwrap(), Value::Integer(2));
873 assert_eq!(run("5 * 3;").unwrap(), Value::Integer(15));
874 assert_eq!(run("6 / 2;").unwrap(), Value::Integer(3));
875 assert_eq!(run("7 % 3;").unwrap(), Value::Integer(1));
876 }
877
878 #[test]
879 fn test_string_concatenation() {
880 assert_eq!(
881 run(r#""hello" + " " + "world";"#).unwrap(),
882 Value::String("hello world".to_string())
883 );
884 }
885
886 #[test]
887 fn test_comparison() {
888 assert_eq!(run("5 > 3;").unwrap(), Value::Boolean(true));
889 assert_eq!(run("5 < 3;").unwrap(), Value::Boolean(false));
890 assert_eq!(run("5 == 5;").unwrap(), Value::Boolean(true));
891 assert_eq!(run("5 != 3;").unwrap(), Value::Boolean(true));
892 }
893
894 #[test]
895 fn test_logical() {
896 assert_eq!(run("true && true;").unwrap(), Value::Boolean(true));
897 assert_eq!(run("true && false;").unwrap(), Value::Boolean(false));
898 assert_eq!(run("true || false;").unwrap(), Value::Boolean(true));
899 assert_eq!(run("!true;").unwrap(), Value::Boolean(false));
900 }
901
902 #[test]
903 fn test_variable() {
904 assert_eq!(run("let x = 10; x;").unwrap(), Value::Integer(10));
905 }
906
907 #[test]
908 fn test_variable_assignment() {
909 assert_eq!(run("let x = 10; x = 20; x;").unwrap(), Value::Integer(20));
910 }
911
912 #[test]
913 fn test_if_true() {
914 assert_eq!(
915 run("let x = 0; if (true) { x = 1; } x;").unwrap(),
916 Value::Integer(1)
917 );
918 }
919
920 #[test]
921 fn test_if_false() {
922 assert_eq!(
923 run("let x = 0; if (false) { x = 1; } x;").unwrap(),
924 Value::Integer(0)
925 );
926 }
927
928 #[test]
929 fn test_if_else() {
930 assert_eq!(
931 run("let x = 0; if (false) { x = 1; } else { x = 2; } x;").unwrap(),
932 Value::Integer(2)
933 );
934 }
935
936 #[test]
937 fn test_for_loop() {
938 assert_eq!(
939 run("let sum = 0; for (let i = 0; i < 5; i = i + 1) { sum = sum + i; } sum;").unwrap(),
940 Value::Integer(10) );
942 }
943
944 #[test]
945 fn test_function() {
946 assert_eq!(
947 run("fn add(a, b) { return a + b; } add(2, 3);").unwrap(),
948 Value::Integer(5)
949 );
950 }
951
952 #[test]
953 fn test_recursion() {
954 let source = r#"
955 fn factorial(n) {
956 if (n <= 1) {
957 return 1;
958 }
959 return n * factorial(n - 1);
960 }
961 factorial(5);
962 "#;
963 assert_eq!(run(source).unwrap(), Value::Integer(120));
964 }
965
966 #[test]
967 fn test_division_by_zero() {
968 let result = run("5 / 0;");
969 assert!(matches!(
970 result,
971 Err(crate::FiddlerError::Runtime(RuntimeError::DivisionByZero {
972 position: None
973 }))
974 ));
975 }
976
977 #[test]
978 fn test_undefined_variable() {
979 let result = run("x;");
980 assert!(matches!(
981 result,
982 Err(crate::FiddlerError::Runtime(
983 RuntimeError::UndefinedVariable { .. }
984 ))
985 ));
986 }
987
988 #[test]
989 fn test_undefined_function() {
990 let result = run("foo();");
991 assert!(matches!(
992 result,
993 Err(crate::FiddlerError::Runtime(
994 RuntimeError::UndefinedFunction { .. }
995 ))
996 ));
997 }
998
999 #[test]
1000 fn test_wrong_argument_count() {
1001 let result = run("fn add(a, b) { return a + b; } add(1);");
1002 assert!(matches!(
1003 result,
1004 Err(crate::FiddlerError::Runtime(
1005 RuntimeError::WrongArgumentCount {
1006 expected: 2,
1007 actual: 1,
1008 ..
1009 }
1010 ))
1011 ));
1012 }
1013
1014 #[test]
1015 fn test_set_and_get_variable() {
1016 let mut interpreter = Interpreter::new_without_env();
1017 interpreter.set_variable_value("x", Value::Integer(42));
1018 assert_eq!(interpreter.get_value("x"), Some(Value::Integer(42)));
1019 }
1020
1021 #[test]
1022 fn test_set_variable_string() {
1023 let mut interpreter = Interpreter::new_without_env();
1024 interpreter.set_variable_string("name", "Alice");
1025 assert_eq!(
1026 interpreter.get_value("name"),
1027 Some(Value::String("Alice".to_string()))
1028 );
1029 }
1030
1031 #[test]
1032 fn test_set_variable_bytes() {
1033 let mut interpreter = Interpreter::new_without_env();
1034 interpreter.set_variable_bytes("data", vec![1, 2, 3]);
1035 assert_eq!(
1036 interpreter.get_value("data"),
1037 Some(Value::Bytes(vec![1, 2, 3]))
1038 );
1039 }
1040
1041 #[test]
1042 fn test_get_bytes() {
1043 let mut interpreter = Interpreter::new_without_env();
1044 interpreter.set_variable_string("msg", "hello");
1045 assert_eq!(
1046 interpreter.get_bytes("msg"),
1047 Some("hello".as_bytes().to_vec())
1048 );
1049 }
1050
1051 #[test]
1052 fn test_has_variable() {
1053 let mut interpreter = Interpreter::new_without_env();
1054 interpreter.set_variable_int("count", 10);
1055 assert!(interpreter.has_variable("count"));
1056 assert!(!interpreter.has_variable("nonexistent"));
1057 }
1058
1059 #[test]
1060 fn test_env_vars_loaded() {
1061 std::env::set_var("FIDDLER_TEST_VAR", "test123");
1062 let interpreter = Interpreter::new();
1063 assert_eq!(
1064 interpreter.get_value("FIDDLER_TEST_VAR"),
1065 Some(Value::String("test123".to_string()))
1066 );
1067 std::env::remove_var("FIDDLER_TEST_VAR");
1068 }
1069
1070 #[test]
1071 fn test_use_injected_variable_in_script() {
1072 let mut interpreter = Interpreter::new_without_env();
1073 interpreter.set_variable_int("input", 5);
1074 let result = interpreter.run("input * 2;").unwrap();
1075 assert_eq!(result, Value::Integer(10));
1076 }
1077
1078 #[test]
1079 fn test_bytes_in_script() {
1080 let mut interpreter = Interpreter::new_without_env();
1081 interpreter.set_variable_bytes("data", b"hello".to_vec());
1082 let result = interpreter.run("bytes_to_string(data);").unwrap();
1083 assert_eq!(result, Value::String("hello".to_string()));
1084 }
1085
1086 #[test]
1087 fn test_parse_json_in_script() {
1088 let mut interpreter = Interpreter::new_without_env();
1089 interpreter.set_variable_bytes("json_data", br#"{"name": "test"}"#.to_vec());
1090 let result = interpreter.run("parse_json(json_data);").unwrap();
1091 assert!(matches!(result, Value::Dictionary(_)));
1092 }
1093
1094 #[test]
1095 fn test_bytes_truthy() {
1096 let mut interpreter = Interpreter::new_without_env();
1097 interpreter.set_variable_bytes("data", b"hello".to_vec());
1098 let result = interpreter.run("if (data) { 1; } else { 0; }").unwrap();
1099 assert_eq!(result, Value::Integer(1));
1100 }
1101
1102 #[test]
1103 fn test_empty_bytes_falsy() {
1104 let mut interpreter = Interpreter::new_without_env();
1105 interpreter.set_variable_bytes("empty", vec![]);
1106 let result = interpreter.run("if (empty) { 1; } else { 0; }").unwrap();
1107 assert_eq!(result, Value::Integer(0));
1108 }
1109
1110 #[test]
1111 fn test_print_output_capture() {
1112 let mut interpreter = Interpreter::new_without_env();
1113 interpreter
1114 .run(r#"print("hello"); print("world");"#)
1115 .unwrap();
1116 assert_eq!(interpreter.output(), &["hello", "world"]);
1117 }
1118
1119 #[test]
1120 fn test_print_output_multiple_args() {
1121 let mut interpreter = Interpreter::new_without_env();
1122 interpreter.run(r#"print("a", 42, true);"#).unwrap();
1123 assert_eq!(interpreter.output(), &["a 42 true"]);
1124 }
1125
1126 #[test]
1127 fn test_clear_output() {
1128 let mut interpreter = Interpreter::new_without_env();
1129 interpreter.run(r#"print("test");"#).unwrap();
1130 assert_eq!(interpreter.output().len(), 1);
1131 assert!(!interpreter.is_output_truncated());
1132 interpreter.clear_output();
1133 assert!(interpreter.output().is_empty());
1134 assert!(!interpreter.is_output_truncated());
1135 }
1136
1137 #[test]
1138 fn test_output_truncation_by_lines() {
1139 let mut interpreter = Interpreter::new_without_env();
1140 let mut source = String::new();
1142 for i in 0..1005 {
1143 source.push_str(&format!("print({});\n", i));
1144 }
1145 interpreter.run(&source).unwrap();
1146
1147 assert!(interpreter.output().len() <= MAX_OUTPUT_LINES + 1);
1149 assert!(interpreter.is_output_truncated());
1150 assert_eq!(
1151 interpreter.output().last(),
1152 Some(&"[truncated]".to_string())
1153 );
1154 }
1155
1156 #[test]
1157 fn test_output_truncation_by_bytes() {
1158 let mut interpreter = Interpreter::new_without_env();
1159 let long_string = "x".repeat(70_000);
1161 let source = format!(r#"print("{}");"#, long_string);
1162 interpreter.run(&source).unwrap();
1163
1164 assert!(interpreter.is_output_truncated());
1166 assert_eq!(
1167 interpreter.output().last(),
1168 Some(&"[truncated]".to_string())
1169 );
1170 }
1171
1172 #[test]
1173 fn test_output_not_truncated_within_limits() {
1174 let mut interpreter = Interpreter::new_without_env();
1175 interpreter
1177 .run(r#"print("a"); print("b"); print("c");"#)
1178 .unwrap();
1179 assert!(!interpreter.is_output_truncated());
1180 assert_eq!(interpreter.output(), &["a", "b", "c"]);
1181 }
1182
1183 #[test]
1184 fn test_stack_overflow() {
1185 let mut interpreter = Interpreter::new_without_env();
1186 let source = r#"
1187 fn recurse() {
1188 recurse();
1189 }
1190 recurse();
1191 "#;
1192 let result = interpreter.run(source);
1193 assert!(matches!(
1194 result,
1195 Err(crate::FiddlerError::Runtime(
1196 RuntimeError::StackOverflow { .. }
1197 ))
1198 ));
1199 }
1200
1201 #[test]
1202 fn test_deep_recursion_within_limit() {
1203 let mut interpreter = Interpreter::new_without_env();
1204 let source = r#"
1206 fn count_down(n) {
1207 if (n <= 0) {
1208 return 0;
1209 }
1210 return 1 + count_down(n - 1);
1211 }
1212 count_down(50);
1213 "#;
1214 let result = interpreter.run(source).unwrap();
1215 assert_eq!(result, Value::Integer(50));
1216 }
1217
1218 #[test]
1219 fn test_array_literal() {
1220 let result = run("[1, 2, 3];").unwrap();
1221 assert_eq!(
1222 result,
1223 Value::Array(vec![
1224 Value::Integer(1),
1225 Value::Integer(2),
1226 Value::Integer(3),
1227 ])
1228 );
1229 }
1230
1231 #[test]
1232 fn test_empty_array_literal() {
1233 let result = run("[];").unwrap();
1234 assert_eq!(result, Value::Array(vec![]));
1235 }
1236
1237 #[test]
1238 fn test_dictionary_literal() {
1239 let result = run(r#"{"key": 42};"#).unwrap();
1240 if let Value::Dictionary(dict) = result {
1241 assert_eq!(dict.get("key"), Some(&Value::Integer(42)));
1242 } else {
1243 panic!("Expected dictionary");
1244 }
1245 }
1246
1247 #[test]
1248 fn test_empty_dictionary_literal() {
1249 let result = run("{};").unwrap();
1250 assert_eq!(result, Value::Dictionary(IndexMap::new()));
1251 }
1252
1253 #[test]
1254 fn test_nested_literals() {
1255 let result = run(r#"{"arr": [1, 2], "nested": {"a": 1}};"#).unwrap();
1256 assert!(matches!(result, Value::Dictionary(_)));
1257 }
1258
1259 #[test]
1260 fn test_dictionary_preserves_insertion_order() {
1261 let result = run(r#"{"z": 1, "a": 2, "m": 3};"#).unwrap();
1263 if let Value::Dictionary(dict) = result {
1264 let keys: Vec<&String> = dict.keys().collect();
1265 assert_eq!(keys, vec!["z", "a", "m"]);
1266 } else {
1267 panic!("Expected dictionary");
1268 }
1269 }
1270
1271 #[test]
1272 fn test_keys_preserves_insertion_order() {
1273 let mut interpreter = Interpreter::new_without_env();
1274 let result = interpreter
1275 .run(r#"let d = {"third": 3, "first": 1, "second": 2}; keys(d);"#)
1276 .unwrap();
1277 assert_eq!(
1279 result,
1280 Value::Array(vec![
1281 Value::String("third".to_string()),
1282 Value::String("first".to_string()),
1283 Value::String("second".to_string()),
1284 ])
1285 );
1286 }
1287
1288 #[test]
1291 fn test_max_integer() {
1292 let max = i64::MAX;
1293 let source = format!("{};", max);
1294 let result = run(&source).unwrap();
1295 assert_eq!(result, Value::Integer(max));
1296 }
1297
1298 #[test]
1299 fn test_min_integer() {
1300 let min_plus_one = i64::MIN + 1;
1303 let source = format!("{};", min_plus_one);
1304 let result = run(&source).unwrap();
1305 assert_eq!(result, Value::Integer(min_plus_one));
1306 }
1307
1308 #[test]
1309 fn test_unicode_strings() {
1310 let result = run(r#""Hello, 世界! 🎉 émojis";"#).unwrap();
1312 assert_eq!(result, Value::String("Hello, 世界! 🎉 émojis".to_string()));
1313 }
1314
1315 #[test]
1316 fn test_unicode_string_concatenation() {
1317 let result = run(r#""こんにちは" + " " + "世界";"#).unwrap();
1318 assert_eq!(result, Value::String("こんにちは 世界".to_string()));
1319 }
1320
1321 #[test]
1322 fn test_deeply_nested_expressions() {
1323 let result = run("((((((1 + 2) * 3) - 4) / 2) + 1) * 2);").unwrap();
1326 assert_eq!(result, Value::Integer(6));
1327 }
1328
1329 #[test]
1330 fn test_modulo_with_negative_dividend() {
1331 let result = run("-7 % 3;").unwrap();
1332 assert_eq!(result, Value::Integer(-1)); }
1334
1335 #[test]
1336 fn test_modulo_with_negative_divisor() {
1337 let result = run("7 % -3;").unwrap();
1338 assert_eq!(result, Value::Integer(1)); }
1340
1341 #[test]
1342 fn test_empty_string_falsy() {
1343 let result = run(r#"if ("") { 1; } else { 0; }"#).unwrap();
1344 assert_eq!(result, Value::Integer(0));
1345 }
1346
1347 #[test]
1348 fn test_nonempty_string_truthy() {
1349 let result = run(r#"if ("x") { 1; } else { 0; }"#).unwrap();
1350 assert_eq!(result, Value::Integer(1));
1351 }
1352
1353 #[test]
1354 fn test_zero_integer_falsy() {
1355 let result = run("if (0) { 1; } else { 0; }").unwrap();
1356 assert_eq!(result, Value::Integer(0));
1357 }
1358
1359 #[test]
1360 fn test_nonzero_integer_truthy() {
1361 let result = run("if (-1) { 1; } else { 0; }").unwrap();
1362 assert_eq!(result, Value::Integer(1));
1363 }
1364
1365 #[test]
1366 fn test_empty_array_falsy() {
1367 let mut interpreter = Interpreter::new_without_env();
1368 interpreter.set_variable_array("arr", vec![]);
1369 let result = interpreter.run("if (arr) { 1; } else { 0; }").unwrap();
1370 assert_eq!(result, Value::Integer(0));
1371 }
1372
1373 #[test]
1374 fn test_nonempty_array_truthy() {
1375 let mut interpreter = Interpreter::new_without_env();
1376 interpreter.set_variable_array("arr", vec![Value::Integer(1)]);
1377 let result = interpreter.run("if (arr) { 1; } else { 0; }").unwrap();
1378 assert_eq!(result, Value::Integer(1));
1379 }
1380
1381 #[test]
1384 fn test_method_call_string_len() {
1385 let result = run(r#""hello".len();"#).unwrap();
1386 assert_eq!(result, Value::Integer(5));
1387 }
1388
1389 #[test]
1390 fn test_method_call_string_lowercase() {
1391 let result = run(r#""HELLO".lowercase();"#).unwrap();
1392 assert_eq!(result, Value::String("hello".to_string()));
1393 }
1394
1395 #[test]
1396 fn test_method_call_string_uppercase() {
1397 let result = run(r#""hello".uppercase();"#).unwrap();
1398 assert_eq!(result, Value::String("HELLO".to_string()));
1399 }
1400
1401 #[test]
1402 fn test_method_call_array_len() {
1403 let result = run("[1, 2, 3].len();").unwrap();
1404 assert_eq!(result, Value::Integer(3));
1405 }
1406
1407 #[test]
1408 fn test_method_call_array_push() {
1409 let result = run("[1, 2].push(3);").unwrap();
1410 assert_eq!(
1411 result,
1412 Value::Array(vec![
1413 Value::Integer(1),
1414 Value::Integer(2),
1415 Value::Integer(3)
1416 ])
1417 );
1418 }
1419
1420 #[test]
1421 fn test_method_call_array_get() {
1422 let result = run(r#"["a", "b", "c"].get(1);"#).unwrap();
1423 assert_eq!(result, Value::String("b".to_string()));
1424 }
1425
1426 #[test]
1427 fn test_method_call_dict_get() {
1428 let result = run(r#"{"name": "Alice"}.get("name");"#).unwrap();
1429 assert_eq!(result, Value::String("Alice".to_string()));
1430 }
1431
1432 #[test]
1433 fn test_method_call_dict_keys() {
1434 let result = run(r#"{"a": 1, "b": 2}.keys();"#).unwrap();
1435 assert_eq!(
1436 result,
1437 Value::Array(vec![
1438 Value::String("a".to_string()),
1439 Value::String("b".to_string())
1440 ])
1441 );
1442 }
1443
1444 #[test]
1445 fn test_method_call_chaining() {
1446 let result = run(r#"" HELLO ".trim().lowercase();"#).unwrap();
1448 assert_eq!(result, Value::String("hello".to_string()));
1449 }
1450
1451 #[test]
1452 fn test_method_call_chain_array() {
1453 let result = run("[1].push(2).push(3).len();").unwrap();
1455 assert_eq!(result, Value::Integer(3));
1456 }
1457
1458 #[test]
1459 fn test_method_call_on_variable() {
1460 let result = run(r#"let s = "HELLO"; s.lowercase();"#).unwrap();
1461 assert_eq!(result, Value::String("hello".to_string()));
1462 }
1463
1464 #[test]
1465 fn test_method_call_backwards_compatibility() {
1466 let func_result = run(r#"len("hello");"#).unwrap();
1468 let method_result = run(r#""hello".len();"#).unwrap();
1469 assert_eq!(func_result, method_result);
1470 }
1471
1472 #[test]
1473 fn test_method_call_split() {
1474 let result = run(r#""a,b,c".split(",");"#).unwrap();
1475 assert_eq!(
1476 result,
1477 Value::Array(vec![
1478 Value::String("a".to_string()),
1479 Value::String("b".to_string()),
1480 Value::String("c".to_string())
1481 ])
1482 );
1483 }
1484
1485 #[test]
1486 fn test_method_call_trim_prefix() {
1487 let result = run(r#""/path/file".trim_prefix("/path");"#).unwrap();
1488 assert_eq!(result, Value::String("/file".to_string()));
1489 }
1490
1491 #[test]
1492 fn test_method_call_has_prefix() {
1493 let result = run(r#""hello world".has_prefix("hello");"#).unwrap();
1494 assert_eq!(result, Value::Boolean(true));
1495 }
1496
1497 #[test]
1498 fn test_method_call_on_grouped_expression() {
1499 let result = run(r#"("hello" + " world").len();"#).unwrap();
1500 assert_eq!(result, Value::Integer(11));
1501 }
1502
1503 #[test]
1504 fn test_method_call_undefined_method() {
1505 let result = run(r#""hello".nonexistent();"#);
1506 assert!(matches!(
1507 result,
1508 Err(crate::FiddlerError::Runtime(
1509 RuntimeError::UndefinedFunction { .. }
1510 ))
1511 ));
1512 }
1513
1514 #[test]
1515 fn test_method_call_with_function_call_args() {
1516 let result = run(r#""hello".get(len("ab"));"#).unwrap();
1518 assert_eq!(result, Value::String("l".to_string()));
1519 }
1520
1521 #[test]
1522 fn test_method_call_complex_chain() {
1523 let result = run(r#"" HELLO WORLD ".trim().lowercase().split(" ").len();"#).unwrap();
1525 assert_eq!(result, Value::Integer(2));
1526 }
1527
1528 #[test]
1529 fn test_method_call_on_function_result() {
1530 let result = run(r#"str(42).len();"#).unwrap();
1532 assert_eq!(result, Value::Integer(2));
1533 }
1534
1535 #[test]
1536 fn test_method_and_function_mixed() {
1537 let result = run(r#"len("hello".uppercase());"#).unwrap();
1539 assert_eq!(result, Value::Integer(5));
1540 }
1541
1542 #[test]
1545 fn test_array_contains_found() {
1546 let result = run(r#"[1, 2, 3].contains(2);"#).unwrap();
1547 assert_eq!(result, Value::Boolean(true));
1548 }
1549
1550 #[test]
1551 fn test_array_contains_not_found() {
1552 let result = run(r#"[1, 2, 3].contains(5);"#).unwrap();
1553 assert_eq!(result, Value::Boolean(false));
1554 }
1555
1556 #[test]
1557 fn test_array_contains_string() {
1558 let result = run(r#"["apple", "banana"].contains("banana");"#).unwrap();
1559 assert_eq!(result, Value::Boolean(true));
1560 }
1561
1562 #[test]
1563 fn test_dict_contains_key() {
1564 let result = run(r#"{"name": "Alice", "age": 30}.contains("name");"#).unwrap();
1565 assert_eq!(result, Value::Boolean(true));
1566 }
1567
1568 #[test]
1569 fn test_dict_contains_key_not_found() {
1570 let result = run(r#"{"name": "Alice"}.contains("email");"#).unwrap();
1571 assert_eq!(result, Value::Boolean(false));
1572 }
1573
1574 #[test]
1575 fn test_contains_function_syntax() {
1576 let result = run(r#"contains([1, 2, 3], 2);"#).unwrap();
1577 assert_eq!(result, Value::Boolean(true));
1578 }
1579
1580 #[test]
1583 fn test_abs_positive() {
1584 let result = run("abs(42);").unwrap();
1585 assert_eq!(result, Value::Integer(42));
1586 }
1587
1588 #[test]
1589 fn test_abs_negative() {
1590 let result = run("abs(-42);").unwrap();
1591 assert_eq!(result, Value::Integer(42));
1592 }
1593
1594 #[test]
1595 fn test_abs_method_syntax() {
1596 let result = run("let x = -10; x.abs();").unwrap();
1597 assert_eq!(result, Value::Integer(10));
1598 }
1599
1600 #[test]
1601 fn test_ceil_identity() {
1602 let result = run("ceil(42);").unwrap();
1603 assert_eq!(result, Value::Integer(42));
1604 }
1605
1606 #[test]
1607 fn test_floor_identity() {
1608 let result = run("floor(42);").unwrap();
1609 assert_eq!(result, Value::Integer(42));
1610 }
1611
1612 #[test]
1613 fn test_round_identity() {
1614 let result = run("round(42);").unwrap();
1615 assert_eq!(result, Value::Integer(42));
1616 }
1617
1618 #[test]
1619 fn test_math_method_syntax() {
1620 let result = run("42.ceil();").unwrap();
1621 assert_eq!(result, Value::Integer(42));
1622 }
1623
1624 #[test]
1627 fn test_timestamp() {
1628 let result = run("timestamp();").unwrap();
1629 if let Value::Integer(ts) = result {
1630 assert!(ts > 1577836800);
1632 } else {
1633 panic!("Expected integer");
1634 }
1635 }
1636
1637 #[test]
1638 fn test_epoch_alias() {
1639 let result = run("epoch();").unwrap();
1640 if let Value::Integer(ts) = result {
1641 assert!(ts > 1577836800);
1642 } else {
1643 panic!("Expected integer");
1644 }
1645 }
1646
1647 #[test]
1648 fn test_timestamp_millis() {
1649 let result = run("timestamp_millis();").unwrap();
1650 if let Value::Integer(ts) = result {
1651 assert!(ts > 1577836800000);
1653 } else {
1654 panic!("Expected integer");
1655 }
1656 }
1657
1658 #[test]
1659 fn test_timestamp_micros() {
1660 let result = run("timestamp_micros();").unwrap();
1661 if let Value::Integer(ts) = result {
1662 assert!(ts > 1577836800000000);
1664 } else {
1665 panic!("Expected integer");
1666 }
1667 }
1668
1669 #[test]
1670 fn test_timestamp_iso8601() {
1671 let result = run("timestamp_iso8601();").unwrap();
1672 if let Value::String(s) = result {
1673 assert!(s.contains('T'));
1675 assert!(s.contains('-'));
1676 assert!(s.contains(':'));
1677 } else {
1678 panic!("Expected string");
1679 }
1680 }
1681
1682 #[test]
1683 fn test_timestamp_in_calculation() {
1684 let result =
1686 run("let start = timestamp_millis(); let end = timestamp_millis(); end - start >= 0;")
1687 .unwrap();
1688 assert_eq!(result, Value::Boolean(true));
1689 }
1690
1691 #[test]
1694 fn test_float_literal() {
1695 let result = run("3.14;").unwrap();
1696 assert_eq!(result, Value::Float(3.14));
1697 }
1698
1699 #[test]
1700 fn test_float_arithmetic() {
1701 let result = run("3.5 + 2.0;").unwrap();
1702 assert_eq!(result, Value::Float(5.5));
1703 }
1704
1705 #[test]
1706 fn test_float_subtraction() {
1707 let result = run("10.5 - 3.2;").unwrap();
1708 if let Value::Float(f) = result {
1709 assert!((f - 7.3).abs() < 1e-10);
1710 } else {
1711 panic!("Expected float");
1712 }
1713 }
1714
1715 #[test]
1716 fn test_float_multiplication() {
1717 let result = run("2.5 * 4.0;").unwrap();
1718 assert_eq!(result, Value::Float(10.0));
1719 }
1720
1721 #[test]
1722 fn test_float_division() {
1723 let result = run("7.5 / 2.5;").unwrap();
1724 assert_eq!(result, Value::Float(3.0));
1725 }
1726
1727 #[test]
1728 fn test_mixed_arithmetic_int_float() {
1729 let result = run("10 + 3.5;").unwrap();
1730 assert_eq!(result, Value::Float(13.5));
1731 }
1732
1733 #[test]
1734 fn test_mixed_arithmetic_float_int() {
1735 let result = run("2.5 * 4;").unwrap();
1736 assert_eq!(result, Value::Float(10.0));
1737 }
1738
1739 #[test]
1740 fn test_float_comparison() {
1741 let result = run("3.14 > 3.0;").unwrap();
1742 assert_eq!(result, Value::Boolean(true));
1743 }
1744
1745 #[test]
1746 fn test_float_equality() {
1747 let result = run("2.5 == 2.5;").unwrap();
1748 assert_eq!(result, Value::Boolean(true));
1749 }
1750
1751 #[test]
1752 fn test_cross_type_equality() {
1753 let result = run("1.0 == 1;").unwrap();
1754 assert_eq!(result, Value::Boolean(true));
1755 }
1756
1757 #[test]
1758 fn test_float_negation() {
1759 let result = run("-3.14;").unwrap();
1760 assert_eq!(result, Value::Float(-3.14));
1761 }
1762
1763 #[test]
1764 fn test_float_truthy() {
1765 let result = run("if (1.5) { 1; } else { 0; }").unwrap();
1766 assert_eq!(result, Value::Integer(1));
1767 }
1768
1769 #[test]
1770 fn test_float_zero_falsy() {
1771 let result = run("if (0.0) { 1; } else { 0; }").unwrap();
1772 assert_eq!(result, Value::Integer(0));
1773 }
1774
1775 #[test]
1776 fn test_float_conversion() {
1777 let result = run("float(42);").unwrap();
1778 assert_eq!(result, Value::Float(42.0));
1779 }
1780
1781 #[test]
1782 fn test_float_conversion_from_string() {
1783 let result = run(r#"float("3.14");"#).unwrap();
1784 assert_eq!(result, Value::Float(3.14));
1785 }
1786
1787 #[test]
1788 fn test_int_from_float() {
1789 let result = run("int(3.99);").unwrap();
1790 assert_eq!(result, Value::Integer(3));
1791 }
1792
1793 #[test]
1794 fn test_ceil_float() {
1795 let result = run("ceil(3.14);").unwrap();
1796 assert_eq!(result, Value::Integer(4));
1797 }
1798
1799 #[test]
1800 fn test_floor_float() {
1801 let result = run("floor(3.99);").unwrap();
1802 assert_eq!(result, Value::Integer(3));
1803 }
1804
1805 #[test]
1806 fn test_round_float() {
1807 let result = run("round(3.5);").unwrap();
1808 assert_eq!(result, Value::Integer(4));
1809 }
1810
1811 #[test]
1812 fn test_abs_float() {
1813 let result = run("abs(-3.14);").unwrap();
1814 assert_eq!(result, Value::Float(3.14));
1815 }
1816
1817 #[test]
1818 fn test_float_method_syntax() {
1819 let result = run("let x = -2.5; x.abs();").unwrap();
1820 assert_eq!(result, Value::Float(2.5));
1821 }
1822
1823 #[test]
1824 fn test_float_in_variable() {
1825 let result = run("let pi = 3.14159; pi * 2.0;").unwrap();
1826 if let Value::Float(f) = result {
1827 assert!((f - 6.28318).abs() < 1e-5);
1828 } else {
1829 panic!("Expected float");
1830 }
1831 }
1832
1833 #[test]
1834 fn test_float_division_by_zero() {
1835 let result = run("1.0 / 0.0;").unwrap();
1836 if let Value::Float(f) = result {
1837 assert!(f.is_infinite() && f.is_sign_positive());
1838 } else {
1839 panic!("Expected float infinity");
1840 }
1841 }
1842
1843 #[test]
1844 fn test_nan_creation() {
1845 let result = run("0.0 / 0.0;").unwrap();
1846 if let Value::Float(f) = result {
1847 assert!(f.is_nan());
1848 } else {
1849 panic!("Expected NaN");
1850 }
1851 }
1852
1853 #[test]
1854 fn test_mixed_comparison() {
1855 let result = run("1 < 1.5;").unwrap();
1856 assert_eq!(result, Value::Boolean(true));
1857 }
1858}