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