Skip to main content

quickpython/
main.rs

1mod builtins;
2mod bytecode;
3mod compiler;
4mod context;
5mod serializer;
6mod value;
7mod vm;
8
9pub use bytecode::{ByteCode, Instruction};
10pub use compiler::Compiler;
11pub use context::Context;
12pub use serializer::{deserialize_bytecode, serialize_bytecode};
13pub use value::{DictKey, ExceptionType, Module, Value};
14
15use clap::{Parser, Subcommand};
16
17#[cfg(not(test))]
18use std::process;
19
20#[derive(Parser)]
21#[command(name = "quickpython")]
22#[command(about = "A simple Python interpreter", long_about = None)]
23struct Cli {
24    #[command(subcommand)]
25    command: Commands,
26}
27
28#[derive(Subcommand)]
29enum Commands {
30    /// Run a Python file
31    Run { file: String },
32    /// Compile a Python file to bytecode
33    Compile {
34        file: String,
35        #[arg(short, long)]
36        output: Option<String>,
37    },
38}
39
40#[cfg(not(test))]
41#[allow(dead_code)]
42fn main() {
43    let cli = Cli::parse();
44
45    match cli.command {
46        Commands::Run { file } => {
47            // 检测文件类型
48            if file.ends_with(".pyq") {
49                // 运行字节码文件
50                let data = match std::fs::read(&file) {
51                    Ok(d) => d,
52                    Err(e) => {
53                        eprintln!("Error reading file '{}': {}", file, e);
54                        process::exit(1);
55                    }
56                };
57
58                let bytecode = match deserialize_bytecode(&data) {
59                    Ok(bc) => bc,
60                    Err(e) => {
61                        eprintln!("Error deserializing bytecode: {}", e);
62                        process::exit(1);
63                    }
64                };
65
66                let mut vm = vm::VM::new();
67                let mut globals = std::collections::HashMap::new();
68                match vm.execute(&bytecode, &mut globals) {
69                    Ok(result) => {
70                        if let Some(i) = result.as_int() {
71                            println!("{}", i);
72                        }
73                    }
74                    Err(e) => {
75                        eprintln!("Runtime error: {:?}", e);
76                        process::exit(1);
77                    }
78                }
79            } else {
80                // 运行 Python 文件
81                let source = match std::fs::read_to_string(&file) {
82                    Ok(s) => s,
83                    Err(e) => {
84                        eprintln!("Error reading file '{}': {}", file, e);
85                        process::exit(1);
86                    }
87                };
88
89                let mut ctx = Context::new();
90                match ctx.eval(&source) {
91                    Ok(result) => {
92                        if let Some(i) = result.as_int() {
93                            println!("{}", i);
94                        }
95                    }
96                    Err(e) => {
97                        eprintln!("Error: {}", e);
98                        process::exit(1);
99                    }
100                }
101            }
102        }
103        Commands::Compile { file, output } => {
104            // 读取源文件
105            let source = match std::fs::read_to_string(&file) {
106                Ok(s) => s,
107                Err(e) => {
108                    eprintln!("Error reading file '{}': {}", file, e);
109                    process::exit(1);
110                }
111            };
112
113            // 编译
114            let bytecode = match Compiler::compile(&source) {
115                Ok(bc) => bc,
116                Err(e) => {
117                    eprintln!("Compile error: {}", e);
118                    process::exit(1);
119                }
120            };
121
122            // 序列化
123            let data = match serialize_bytecode(&bytecode) {
124                Ok(d) => d,
125                Err(e) => {
126                    eprintln!("Serialization error: {}", e);
127                    process::exit(1);
128                }
129            };
130
131            // 确定输出文件名
132            let output_file = output
133                .unwrap_or_else(|| file.strip_suffix(".py").unwrap_or(&file).to_string() + ".pyq");
134
135            // 写入文件
136            match std::fs::write(&output_file, data) {
137                Ok(_) => {
138                    println!("Compiled successfully: {}", output_file);
139                }
140                Err(e) => {
141                    eprintln!("Error writing file '{}': {}", output_file, e);
142                    process::exit(1);
143                }
144            }
145        }
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152
153    #[test]
154    fn test_simple_add() {
155        let mut ctx = Context::new();
156        let result = ctx.eval("1 + 2").unwrap();
157        assert_eq!(result.as_int(), Some(3));
158    }
159
160    #[test]
161    fn test_simple_mul() {
162        let mut ctx = Context::new();
163        let result = ctx.eval("10 * 5").unwrap();
164        assert_eq!(result.as_int(), Some(50));
165    }
166
167    #[test]
168    fn test_simple_div() {
169        let mut ctx = Context::new();
170        let result = ctx.eval("100 / 4").unwrap();
171        assert_eq!(result.as_int(), Some(25));
172    }
173
174    #[test]
175    fn test_simple_sub() {
176        let mut ctx = Context::new();
177        let result = ctx.eval("7 - 3").unwrap();
178        assert_eq!(result.as_int(), Some(4));
179    }
180
181    #[test]
182    fn test_complex_expr() {
183        let mut ctx = Context::new();
184        let result = ctx.eval("(10 + 5) * 2").unwrap();
185        assert_eq!(result.as_int(), Some(30));
186    }
187
188    #[test]
189    fn test_another_complex_expr() {
190        let mut ctx = Context::new();
191        let result = ctx.eval("(1 + 2) * 3").unwrap();
192        assert_eq!(result.as_int(), Some(9));
193    }
194
195    #[test]
196    fn test_division_by_zero() {
197        let mut ctx = Context::new();
198        let result = ctx.eval("10 / 0");
199        assert!(result.is_err());
200    }
201
202    #[test]
203    fn test_variable_assignment() {
204        let mut ctx = Context::new();
205        ctx.eval("x = 42").unwrap();
206        let x = ctx.eval("x").unwrap();
207        assert_eq!(x.as_int(), Some(42));
208    }
209
210    #[test]
211    fn test_variable_expr() {
212        let mut ctx = Context::new();
213        ctx.eval("x = 10").unwrap();
214        ctx.eval("y = x * 2").unwrap();
215        let y = ctx.eval("y").unwrap();
216        assert_eq!(y.as_int(), Some(20));
217    }
218
219    #[test]
220    fn test_get_set_api() {
221        let mut ctx = Context::new();
222        ctx.set("z", Value::Int(100));
223        let z = ctx.get("z").unwrap();
224        assert_eq!(z.as_int(), Some(100));
225    }
226
227    #[test]
228    fn test_undefined_variable() {
229        let mut ctx = Context::new();
230        let result = ctx.eval("undefined_var");
231        assert!(result.is_err());
232    }
233
234    #[test]
235    fn test_function_def_and_call() {
236        let mut ctx = Context::new();
237        ctx.eval("def add(a, b):\n    return a + b").unwrap();
238        let result = ctx.eval("add(1, 2)").unwrap();
239        assert_eq!(result.as_int(), Some(3));
240    }
241
242    #[test]
243    fn test_factorial() {
244        let mut ctx = Context::new();
245        ctx.eval(
246            r#"
247def factorial(n):
248    if n <= 1:
249        return 1
250    return n * factorial(n - 1)
251        "#,
252        )
253        .unwrap();
254
255        let result = ctx.eval("factorial(5)").unwrap();
256        assert_eq!(result.as_int(), Some(120));
257    }
258
259    #[test]
260    fn test_if_else() {
261        let mut ctx = Context::new();
262        ctx.eval(
263            r#"
264def max(a, b):
265    if a > b:
266        return a
267    else:
268        return b
269        "#,
270        )
271        .unwrap();
272
273        let result = ctx.eval("max(10, 5)").unwrap();
274        assert_eq!(result.as_int(), Some(10));
275
276        let result = ctx.eval("max(3, 8)").unwrap();
277        assert_eq!(result.as_int(), Some(8));
278    }
279
280    #[test]
281    fn test_comparison_operators() {
282        let mut ctx = Context::new();
283
284        let result = ctx.eval("5 > 3").unwrap();
285        assert_eq!(result.as_bool(), Some(true));
286
287        let result = ctx.eval("5 < 3").unwrap();
288        assert_eq!(result.as_bool(), Some(false));
289
290        let result = ctx.eval("5 == 5").unwrap();
291        assert_eq!(result.as_bool(), Some(true));
292    }
293
294    #[test]
295    fn test_while_loop() {
296        let mut ctx = Context::new();
297        ctx.eval(
298            r#"
299i = 0
300sum = 0
301while i < 10:
302    sum = sum + i
303    i = i + 1
304        "#,
305        )
306        .unwrap();
307
308        let sum = ctx.get("sum").unwrap();
309        assert_eq!(sum.as_int(), Some(45));
310    }
311
312    #[test]
313    fn test_fibonacci_iterative() {
314        let mut ctx = Context::new();
315        ctx.eval(
316            r#"
317def fib(n):
318    if n <= 1:
319        return n
320    a = 0
321    b = 1
322    i = 2
323    while i <= n:
324        temp = a + b
325        a = b
326        b = temp
327        i = i + 1
328    return b
329        "#,
330        )
331        .unwrap();
332
333        let result = ctx.eval("fib(10)").unwrap();
334        assert_eq!(result.as_int(), Some(55));
335    }
336
337    #[test]
338    fn test_string_literal() {
339        let mut ctx = Context::new();
340        let result = ctx.eval(r#""hello""#).unwrap();
341        assert_eq!(result.as_string(), Some("hello"));
342    }
343
344    #[test]
345    fn test_string_concatenation() {
346        let mut ctx = Context::new();
347        let result = ctx.eval(r#""hello" + " " + "world""#).unwrap();
348        assert_eq!(result.as_string(), Some("hello world"));
349    }
350
351    #[test]
352    fn test_string_variable() {
353        let mut ctx = Context::new();
354        ctx.eval(r#"s = "test""#).unwrap();
355        let result = ctx.eval("s").unwrap();
356        assert_eq!(result.as_string(), Some("test"));
357    }
358
359    #[test]
360    fn test_print_string() {
361        let mut ctx = Context::new();
362        let result = ctx.eval(r#"print("hello")"#).unwrap();
363        assert_eq!(result, Value::None);
364    }
365
366    #[test]
367    fn test_print_int() {
368        let mut ctx = Context::new();
369        let result = ctx.eval("print(42)").unwrap();
370        assert_eq!(result, Value::None);
371    }
372
373    #[test]
374    fn test_float_literal() {
375        let mut ctx = Context::new();
376        let result = ctx.eval("3.15").unwrap();
377        assert_eq!(result.as_float(), Some(3.15));
378    }
379
380    #[test]
381    fn test_float_arithmetic() {
382        let mut ctx = Context::new();
383        let result = ctx.eval("3.15 * 2.0").unwrap();
384        assert_eq!(result.as_float(), Some(6.3));
385    }
386
387    #[test]
388    fn test_mixed_int_float() {
389        let mut ctx = Context::new();
390        let result = ctx.eval("10 + 3.5").unwrap();
391        assert_eq!(result.as_float(), Some(13.5));
392
393        let result = ctx.eval("10 / 3.0").unwrap();
394        assert!((result.as_float().unwrap() - 3.333333333333333).abs() < 0.0001);
395    }
396
397    #[test]
398    fn test_int_conversion() {
399        let mut ctx = Context::new();
400        ctx.eval("x = 3.14").unwrap();
401        let result = ctx.eval("int(x)").unwrap();
402        assert_eq!(result.as_int(), Some(3));
403
404        let result = ctx.eval("int(3.9)").unwrap();
405        assert_eq!(result.as_int(), Some(3));
406    }
407
408    #[test]
409    fn test_float_conversion() {
410        let mut ctx = Context::new();
411        let result = ctx.eval("float(42)").unwrap();
412        assert_eq!(result.as_float(), Some(42.0));
413
414        ctx.eval("x = 10").unwrap();
415        let result = ctx.eval("float(x)").unwrap();
416        assert_eq!(result.as_float(), Some(10.0));
417    }
418
419    #[test]
420    fn test_list_literal() {
421        let mut ctx = Context::new();
422        ctx.eval("numbers = [1, 2, 3, 4, 5]").unwrap();
423        let numbers = ctx.get("numbers").unwrap();
424        let list = numbers.as_list().unwrap();
425        assert_eq!(list.borrow().items.len(), 5);
426    }
427
428    #[test]
429    fn test_list_index() {
430        let mut ctx = Context::new();
431        ctx.eval("numbers = [10, 20, 30]").unwrap();
432        let result = ctx.eval("numbers[0]").unwrap();
433        assert_eq!(result.as_int(), Some(10));
434
435        let result = ctx.eval("numbers[2]").unwrap();
436        assert_eq!(result.as_int(), Some(30));
437    }
438
439    #[test]
440    fn test_list_index_assignment() {
441        let mut ctx = Context::new();
442        ctx.eval("numbers = [1, 2, 3]").unwrap();
443        ctx.eval("numbers[1] = 99").unwrap();
444        let result = ctx.eval("numbers[1]").unwrap();
445        assert_eq!(result.as_int(), Some(99));
446    }
447
448    #[test]
449    fn test_list_append() {
450        let mut ctx = Context::new();
451        ctx.eval("numbers = [1, 2, 3]").unwrap();
452        ctx.eval("numbers.append(4)").unwrap();
453        let numbers = ctx.get("numbers").unwrap();
454        let list = numbers.as_list().unwrap();
455        assert_eq!(list.borrow().items.len(), 4);
456        assert_eq!(list.borrow().items[3].as_int(), Some(4));
457    }
458
459    #[test]
460    fn test_list_pop() {
461        let mut ctx = Context::new();
462        ctx.eval("numbers = [1, 2, 3]").unwrap();
463        let result = ctx.eval("numbers.pop()").unwrap();
464        assert_eq!(result.as_int(), Some(3));
465
466        let numbers = ctx.get("numbers").unwrap();
467        let list = numbers.as_list().unwrap();
468        assert_eq!(list.borrow().items.len(), 2);
469    }
470
471    #[test]
472    fn test_dict_literal_string_keys() {
473        let mut ctx = Context::new();
474        ctx.eval(r#"person = {"name": "Alice", "age": 30}"#)
475            .unwrap();
476        let result = ctx.eval(r#"person["name"]"#).unwrap();
477        assert_eq!(result.as_string(), Some("Alice"));
478    }
479
480    #[test]
481    fn test_dict_literal_int_keys() {
482        let mut ctx = Context::new();
483        ctx.eval("scores = {1: 100, 2: 95, 3: 88}").unwrap();
484        let result = ctx.eval("scores[1]").unwrap();
485        assert_eq!(result.as_int(), Some(100));
486    }
487
488    #[test]
489    fn test_dict_assignment() {
490        let mut ctx = Context::new();
491        ctx.eval(r#"person = {"name": "Bob"}"#).unwrap();
492        ctx.eval(r#"person["age"] = 25"#).unwrap();
493        let result = ctx.eval(r#"person["age"]"#).unwrap();
494        assert_eq!(result.as_int(), Some(25));
495    }
496
497    #[test]
498    fn test_dict_keys() {
499        let mut ctx = Context::new();
500        ctx.eval(r#"person = {"name": "Alice", "age": 30}"#)
501            .unwrap();
502        let result = ctx.eval("person.keys()").unwrap();
503        let keys = result.as_list().unwrap();
504        assert_eq!(keys.borrow().items.len(), 2);
505    }
506
507    #[test]
508    fn test_len_function() {
509        let mut ctx = Context::new();
510
511        ctx.eval("numbers = [1, 2, 3, 4, 5]").unwrap();
512        let result = ctx.eval("len(numbers)").unwrap();
513        assert_eq!(result.as_int(), Some(5));
514
515        ctx.eval(r#"person = {"name": "Alice", "age": 30}"#)
516            .unwrap();
517        let result = ctx.eval("len(person)").unwrap();
518        assert_eq!(result.as_int(), Some(2));
519
520        let result = ctx.eval(r#"len("hello")"#).unwrap();
521        assert_eq!(result.as_int(), Some(5));
522    }
523
524    #[test]
525    fn test_for_range_simple() {
526        let mut ctx = Context::new();
527        ctx.eval(
528            r#"
529sum = 0
530for i in range(10):
531    sum = sum + i
532        "#,
533        )
534        .unwrap();
535
536        let sum = ctx.get("sum").unwrap();
537        assert_eq!(sum.as_int(), Some(45));
538    }
539
540    #[test]
541    fn test_for_range_start_stop() {
542        let mut ctx = Context::new();
543        ctx.eval(
544            r#"
545sum = 0
546for i in range(5, 10):
547    sum = sum + i
548        "#,
549        )
550        .unwrap();
551
552        let sum = ctx.get("sum").unwrap();
553        assert_eq!(sum.as_int(), Some(35)); // 5+6+7+8+9 = 35
554    }
555
556    #[test]
557    fn test_for_range_with_step() {
558        let mut ctx = Context::new();
559        ctx.eval(
560            r#"
561sum = 0
562for i in range(0, 10, 2):
563    sum = sum + i
564        "#,
565        )
566        .unwrap();
567
568        let sum = ctx.get("sum").unwrap();
569        assert_eq!(sum.as_int(), Some(20)); // 0+2+4+6+8 = 20
570    }
571
572    #[test]
573    fn test_for_list_iteration() {
574        let mut ctx = Context::new();
575        ctx.eval(
576            r#"
577numbers = [10, 20, 30, 40]
578sum = 0
579for num in numbers:
580    sum = sum + num
581        "#,
582        )
583        .unwrap();
584
585        let sum = ctx.get("sum").unwrap();
586        assert_eq!(sum.as_int(), Some(100));
587    }
588
589    #[test]
590    fn test_for_dict_iteration() {
591        let mut ctx = Context::new();
592        ctx.eval(
593            r#"
594scores = {1: 100, 2: 95, 3: 88}
595sum = 0
596for key in scores:
597    sum = sum + key
598        "#,
599        )
600        .unwrap();
601
602        let sum = ctx.get("sum").unwrap();
603        assert_eq!(sum.as_int(), Some(6)); // 1+2+3 = 6
604    }
605
606    #[test]
607    fn test_nested_for_loops() {
608        let mut ctx = Context::new();
609        ctx.eval(
610            r#"
611sum = 0
612for i in range(3):
613    for j in range(3):
614        sum = sum + i * j
615        "#,
616        )
617        .unwrap();
618
619        let sum = ctx.get("sum").unwrap();
620        assert_eq!(sum.as_int(), Some(9)); // 0+0+0 + 0+1+2 + 0+2+4 = 9
621    }
622
623    #[test]
624    fn test_for_with_function() {
625        let mut ctx = Context::new();
626        ctx.eval(
627            r#"
628def sum_range(n):
629    total = 0
630    for i in range(n):
631        total = total + i
632    return total
633        "#,
634        )
635        .unwrap();
636
637        let result = ctx.eval("sum_range(10)").unwrap();
638        assert_eq!(result.as_int(), Some(45));
639    }
640
641    #[test]
642    fn test_exception_creation() {
643        use crate::value::ExceptionType;
644
645        let exc = Value::error(ExceptionType::ValueError, "test error");
646        assert!(exc.is_exception());
647
648        let exc_value = exc.as_exception().unwrap();
649        assert_eq!(exc_value.exception_type, ExceptionType::ValueError);
650        assert_eq!(exc_value.message, "test error");
651    }
652
653    #[test]
654    fn test_exception_equality() {
655        use crate::value::ExceptionType;
656
657        let exc1 = Value::error(ExceptionType::ValueError, "test");
658        let exc2 = Value::error(ExceptionType::ValueError, "test");
659        let exc3 = Value::error(ExceptionType::TypeError, "test");
660
661        assert_eq!(exc1, exc2);
662        assert_ne!(exc1, exc3);
663    }
664
665    #[test]
666    fn test_raise_value_error() {
667        let mut ctx = Context::new();
668        let result = ctx.eval(r#"raise ValueError("test error")"#);
669        assert!(result.is_err());
670
671        let err = result.unwrap_err();
672        assert!(err.contains("ValueError"));
673        assert!(err.contains("test error"));
674    }
675
676    #[test]
677    fn test_division_by_zero_exception() {
678        let mut ctx = Context::new();
679        let result = ctx.eval("x = 1 / 0");
680        assert!(result.is_err());
681
682        let err = result.unwrap_err();
683        assert!(err.contains("ZeroDivisionError"));
684    }
685
686    #[test]
687    fn test_index_error_exception() {
688        let mut ctx = Context::new();
689        let result = ctx.eval(
690            r#"
691my_list = [1, 2, 3]
692x = my_list[10]
693        "#,
694        );
695        assert!(result.is_err());
696
697        let err = result.unwrap_err();
698        assert!(err.contains("IndexError"));
699    }
700
701    #[test]
702    fn test_key_error_exception() {
703        let mut ctx = Context::new();
704        let result = ctx.eval(
705            r#"
706my_dict = {"a": 1}
707x = my_dict["b"]
708        "#,
709        );
710        assert!(result.is_err());
711
712        let err = result.unwrap_err();
713        assert!(err.contains("KeyError"));
714    }
715
716    #[test]
717    fn test_try_except_basic() {
718        let mut ctx = Context::new();
719        ctx.eval(
720            r#"
721result = "ok"
722try:
723    x = 1 / 0
724except ZeroDivisionError:
725    result = "caught"
726        "#,
727        )
728        .unwrap();
729
730        let result = ctx.get("result").unwrap();
731        assert_eq!(result.as_string(), Some("caught"));
732    }
733
734    #[test]
735    fn test_try_except_with_binding() {
736        let mut ctx = Context::new();
737        ctx.eval(
738            r#"
739msg = ""
740try:
741    raise ValueError("test error")
742except ValueError as e:
743    msg = "caught"
744        "#,
745        )
746        .unwrap();
747
748        let msg = ctx.get("msg").unwrap();
749        assert_eq!(msg.as_string(), Some("caught"));
750    }
751
752    #[test]
753    fn test_try_except_multiple() {
754        let mut ctx = Context::new();
755        ctx.eval(
756            r#"
757result = ""
758try:
759    x = 1 / 0
760except ValueError:
761    result = "value"
762except ZeroDivisionError:
763    result = "zero"
764        "#,
765        )
766        .unwrap();
767
768        let result = ctx.get("result").unwrap();
769        assert_eq!(result.as_string(), Some("zero"));
770    }
771
772    #[test]
773    fn test_try_except_no_match() {
774        let mut ctx = Context::new();
775        let result = ctx.eval(
776            r#"
777try:
778    x = 1 / 0
779except ValueError:
780    pass
781        "#,
782        );
783
784        assert!(result.is_err());
785        let err = result.unwrap_err();
786        assert!(err.contains("ZeroDivisionError"));
787    }
788
789    #[test]
790    fn test_break_in_while() {
791        let mut ctx = Context::new();
792        ctx.eval(
793            r#"
794i = 0
795sum = 0
796while i < 100:
797    if i == 5:
798        break
799    sum = sum + i
800    i = i + 1
801        "#,
802        )
803        .unwrap();
804
805        let sum = ctx.get("sum").unwrap();
806        assert_eq!(sum.as_int(), Some(10)); // 0+1+2+3+4 = 10
807
808        let i = ctx.get("i").unwrap();
809        assert_eq!(i.as_int(), Some(5));
810    }
811
812    #[test]
813    fn test_continue_in_while() {
814        let mut ctx = Context::new();
815        ctx.eval(
816            r#"
817i = 0
818sum = 0
819while i < 10:
820    i = i + 1
821    if i == 5:
822        continue
823    sum = sum + i
824        "#,
825        )
826        .unwrap();
827
828        let sum = ctx.get("sum").unwrap();
829        assert_eq!(sum.as_int(), Some(50)); // 1+2+3+4+6+7+8+9+10 = 50 (skips 5)
830    }
831
832    #[test]
833    fn test_break_in_for() {
834        let mut ctx = Context::new();
835        ctx.eval(
836            r#"
837sum = 0
838for i in range(100):
839    if i == 5:
840        break
841    sum = sum + i
842        "#,
843        )
844        .unwrap();
845
846        let sum = ctx.get("sum").unwrap();
847        assert_eq!(sum.as_int(), Some(10)); // 0+1+2+3+4 = 10
848    }
849
850    #[test]
851    fn test_continue_in_for() {
852        let mut ctx = Context::new();
853        ctx.eval(
854            r#"
855sum = 0
856for i in range(10):
857    if i == 5:
858        continue
859    sum = sum + i
860        "#,
861        )
862        .unwrap();
863
864        let sum = ctx.get("sum").unwrap();
865        assert_eq!(sum.as_int(), Some(40)); // 0+1+2+3+4+6+7+8+9 = 40 (skips 5)
866    }
867
868    #[test]
869    fn test_break_in_nested_loop() {
870        let mut ctx = Context::new();
871        ctx.eval(
872            r#"
873outer_count = 0
874inner_count = 0
875for i in range(3):
876    outer_count = outer_count + 1
877    for j in range(5):
878        if j == 2:
879            break
880        inner_count = inner_count + 1
881        "#,
882        )
883        .unwrap();
884
885        let outer_count = ctx.get("outer_count").unwrap();
886        assert_eq!(outer_count.as_int(), Some(3)); // outer loop runs 3 times
887
888        let inner_count = ctx.get("inner_count").unwrap();
889        assert_eq!(inner_count.as_int(), Some(6)); // inner loop runs 2 times per outer (0, 1) * 3 = 6
890    }
891
892    #[test]
893    fn test_continue_in_nested_loop() {
894        let mut ctx = Context::new();
895        ctx.eval(
896            r#"
897count = 0
898for i in range(3):
899    for j in range(5):
900        if j == 2:
901            continue
902        count = count + 1
903        "#,
904        )
905        .unwrap();
906
907        let count = ctx.get("count").unwrap();
908        assert_eq!(count.as_int(), Some(12)); // (5-1) * 3 = 12 (skips one per inner loop)
909    }
910
911    #[test]
912    fn test_break_outside_loop() {
913        let mut ctx = Context::new();
914        let result = ctx.eval("break");
915
916        assert!(result.is_err());
917        let err = result.unwrap_err();
918        assert!(err.contains("break") && err.contains("outside loop"));
919    }
920
921    #[test]
922    fn test_continue_outside_loop() {
923        let mut ctx = Context::new();
924        let result = ctx.eval("continue");
925
926        assert!(result.is_err());
927        let err = result.unwrap_err();
928        assert!(err.contains("continue") && err.contains("outside loop"));
929    }
930
931    #[test]
932    fn test_break_with_list_iteration() {
933        let mut ctx = Context::new();
934        ctx.eval(
935            r#"
936numbers = [10, 20, 30, 40, 50]
937sum = 0
938for num in numbers:
939    if num == 30:
940        break
941    sum = sum + num
942        "#,
943        )
944        .unwrap();
945
946        let sum = ctx.get("sum").unwrap();
947        assert_eq!(sum.as_int(), Some(30)); // 10+20 = 30
948    }
949
950    #[test]
951    fn test_continue_with_list_iteration() {
952        let mut ctx = Context::new();
953        ctx.eval(
954            r#"
955numbers = [10, 20, 30, 40, 50]
956sum = 0
957for num in numbers:
958    if num == 30:
959        continue
960    sum = sum + num
961        "#,
962        )
963        .unwrap();
964
965        let sum = ctx.get("sum").unwrap();
966        assert_eq!(sum.as_int(), Some(120)); // 10+20+40+50 = 120
967    }
968
969    #[test]
970    fn test_break_in_function() {
971        let mut ctx = Context::new();
972        ctx.eval(
973            r#"
974def find_first_even(numbers):
975    result = 0
976    for num in numbers:
977        if num == 0:
978            break
979        if num / 2 * 2 == num:
980            result = num
981            break
982    return result
983        "#,
984        )
985        .unwrap();
986
987        let result = ctx.eval("find_first_even([1, 3, 5, 8, 10])").unwrap();
988        assert_eq!(result.as_int(), Some(8));
989    }
990
991    #[test]
992    fn test_continue_skip_odds() {
993        let mut ctx = Context::new();
994        ctx.eval(
995            r#"
996sum = 0
997for i in range(10):
998    if i / 2 * 2 != i:
999        continue
1000    sum = sum + i
1001        "#,
1002        )
1003        .unwrap();
1004
1005        let sum = ctx.get("sum").unwrap();
1006        assert_eq!(sum.as_int(), Some(20)); // 0+2+4+6+8 = 20 (only evens)
1007    }
1008
1009    #[test]
1010    fn test_try_finally_basic() {
1011        let mut ctx = Context::new();
1012        ctx.eval(
1013            r#"
1014executed = []
1015try:
1016    executed.append(1)
1017finally:
1018    executed.append(2)
1019        "#,
1020        )
1021        .unwrap();
1022
1023        let executed = ctx.get("executed").unwrap().as_list().unwrap();
1024        assert_eq!(executed.borrow().items.len(), 2);
1025    }
1026
1027    #[test]
1028    fn test_try_except_finally() {
1029        let mut ctx = Context::new();
1030        ctx.eval(
1031            r#"
1032result = ""
1033try:
1034    x = 1 / 0
1035except ZeroDivisionError:
1036    result = "caught"
1037finally:
1038    result = result + " finally"
1039        "#,
1040        )
1041        .unwrap();
1042
1043        let result = ctx.get("result").unwrap();
1044        assert_eq!(result.as_string(), Some("caught finally"));
1045    }
1046
1047    #[test]
1048    fn test_iterator_modification_append() {
1049        let mut ctx = Context::new();
1050        let result = ctx.eval(
1051            r#"
1052numbers = [1, 2, 3]
1053for n in numbers:
1054    numbers.append(10)
1055        "#,
1056        );
1057
1058        assert!(result.is_err());
1059        let err = result.unwrap_err();
1060        assert!(err.contains("IteratorError"));
1061    }
1062
1063    #[test]
1064    fn test_iterator_modification_pop() {
1065        let mut ctx = Context::new();
1066        let result = ctx.eval(
1067            r#"
1068numbers = [1, 2, 3]
1069for n in numbers:
1070    numbers.pop()
1071        "#,
1072        );
1073
1074        assert!(result.is_err());
1075        let err = result.unwrap_err();
1076        assert!(err.contains("IteratorError"));
1077    }
1078
1079    #[test]
1080    fn test_iterator_modification_after_loop_ok() {
1081        let mut ctx = Context::new();
1082        ctx.eval(
1083            r#"
1084numbers = [1, 2, 3]
1085for n in numbers:
1086    pass
1087numbers.append(4)
1088        "#,
1089        )
1090        .unwrap();
1091
1092        let numbers = ctx.get("numbers").unwrap().as_list().unwrap();
1093        assert_eq!(numbers.borrow().items.len(), 4);
1094    }
1095
1096    // Task 016: 比较运算符类型支持测试
1097
1098    #[test]
1099    fn test_float_comparison() {
1100        let mut ctx = Context::new();
1101        ctx.eval("x = 3.14").unwrap();
1102        ctx.eval("y = 2.71").unwrap();
1103
1104        let result = ctx.eval("x > y").unwrap();
1105        assert_eq!(result.as_bool(), Some(true));
1106
1107        let result = ctx.eval("x == y").unwrap();
1108        assert_eq!(result.as_bool(), Some(false));
1109
1110        let result = ctx.eval("x != y").unwrap();
1111        assert_eq!(result.as_bool(), Some(true));
1112    }
1113
1114    #[test]
1115    fn test_mixed_int_float_comparison() {
1116        let mut ctx = Context::new();
1117        ctx.eval("score = 87.5").unwrap();
1118
1119        let result = ctx.eval("score >= 90").unwrap();
1120        assert_eq!(result.as_bool(), Some(false));
1121
1122        let result = ctx.eval("score >= 80").unwrap();
1123        assert_eq!(result.as_bool(), Some(true));
1124
1125        let result = ctx.eval("10 == 10.0").unwrap();
1126        assert_eq!(result.as_bool(), Some(true));
1127
1128        let result = ctx.eval("5 < 5.5").unwrap();
1129        assert_eq!(result.as_bool(), Some(true));
1130    }
1131
1132    #[test]
1133    fn test_string_comparison() {
1134        let mut ctx = Context::new();
1135
1136        // 相等性
1137        let result = ctx.eval(r#""hello" == "hello""#).unwrap();
1138        assert_eq!(result.as_bool(), Some(true));
1139
1140        let result = ctx.eval(r#""hello" == "world""#).unwrap();
1141        assert_eq!(result.as_bool(), Some(false));
1142
1143        let result = ctx.eval(r#""hello" != "world""#).unwrap();
1144        assert_eq!(result.as_bool(), Some(true));
1145
1146        // 字典序
1147        let result = ctx.eval(r#""apple" < "banana""#).unwrap();
1148        assert_eq!(result.as_bool(), Some(true));
1149
1150        let result = ctx.eval(r#""zebra" > "apple""#).unwrap();
1151        assert_eq!(result.as_bool(), Some(true));
1152    }
1153
1154    #[test]
1155    fn test_bool_comparison() {
1156        let mut ctx = Context::new();
1157
1158        let result = ctx.eval("True == True").unwrap();
1159        assert_eq!(result.as_bool(), Some(true));
1160
1161        let result = ctx.eval("True == False").unwrap();
1162        assert_eq!(result.as_bool(), Some(false));
1163
1164        let result = ctx.eval("False != True").unwrap();
1165        assert_eq!(result.as_bool(), Some(true));
1166    }
1167
1168    #[test]
1169    fn test_none_comparison() {
1170        let mut ctx = Context::new();
1171        ctx.eval("x = None").unwrap();
1172
1173        let result = ctx.eval("x == None").unwrap();
1174        assert_eq!(result.as_bool(), Some(true));
1175
1176        let result = ctx.eval("x != None").unwrap();
1177        assert_eq!(result.as_bool(), Some(false));
1178    }
1179
1180    #[test]
1181    fn test_different_types_equality() {
1182        let mut ctx = Context::new();
1183
1184        // 相等性比较返回 False
1185        let result = ctx.eval(r#""hello" == 5"#).unwrap();
1186        assert_eq!(result.as_bool(), Some(false));
1187
1188        let result = ctx.eval(r#"True == 5"#).unwrap();
1189        assert_eq!(result.as_bool(), Some(false));
1190    }
1191
1192    #[test]
1193    fn test_different_types_ordering_error() {
1194        let mut ctx = Context::new();
1195
1196        // 顺序比较抛出 TypeError
1197        let result = ctx.eval(r#""hello" < 5"#);
1198        assert!(result.is_err());
1199        let err = result.unwrap_err();
1200        assert!(err.contains("TypeError"));
1201        assert!(err.contains("unsupported operand types"));
1202    }
1203
1204    #[test]
1205    fn test_grade_function_with_float() {
1206        let mut ctx = Context::new();
1207        ctx.eval(
1208            r#"
1209def get_grade(score):
1210    if score >= 90.0:
1211        return "A"
1212    else:
1213        if score >= 80.0:
1214            return "B"
1215        else:
1216            if score >= 70.0:
1217                return "C"
1218            else:
1219                return "F"
1220
1221grade = get_grade(85.5)
1222        "#,
1223        )
1224        .unwrap();
1225
1226        let grade = ctx.get("grade").unwrap();
1227        assert_eq!(grade.as_string(), Some("B"));
1228    }
1229
1230    #[test]
1231    fn test_import_json() {
1232        let mut ctx = Context::new();
1233        ctx.eval("import json").unwrap();
1234    }
1235
1236    #[test]
1237    fn test_json_loads() {
1238        let mut ctx = Context::new();
1239        let result = ctx
1240            .eval(
1241                r#"
1242import json
1243data = json.loads('{"x": 1, "y": 2}')
1244data["x"]
1245        "#,
1246            )
1247            .unwrap();
1248        assert_eq!(result.as_int(), Some(1));
1249    }
1250
1251    #[test]
1252    fn test_json_dumps() {
1253        let mut ctx = Context::new();
1254        let result = ctx
1255            .eval(
1256                r#"
1257import json
1258obj = {"x": 1, "y": 2}
1259json.dumps(obj)
1260        "#,
1261            )
1262            .unwrap();
1263
1264        let json_str = result.as_string().unwrap();
1265        assert!(json_str.contains("\"x\""));
1266        assert!(json_str.contains("1"));
1267    }
1268
1269    #[test]
1270    fn test_from_import() {
1271        let mut ctx = Context::new();
1272        let result = ctx
1273            .eval(
1274                r#"
1275from json import loads
1276data = loads('{"value": 42}')
1277data["value"]
1278        "#,
1279            )
1280            .unwrap();
1281        assert_eq!(result.as_int(), Some(42));
1282    }
1283
1284    #[test]
1285    fn test_import_as() {
1286        let mut ctx = Context::new();
1287        let result = ctx
1288            .eval(
1289                r#"
1290import json as j
1291data = j.loads('{"test": true}')
1292data["test"]
1293        "#,
1294            )
1295            .unwrap();
1296        assert_eq!(result.as_bool(), Some(true));
1297    }
1298
1299    #[test]
1300    fn test_json_array() {
1301        let mut ctx = Context::new();
1302        let result = ctx
1303            .eval(
1304                r#"
1305import json
1306arr = json.loads('[1, 2, 3, 4, 5]')
1307len(arr)
1308        "#,
1309            )
1310            .unwrap();
1311        assert_eq!(result.as_int(), Some(5));
1312    }
1313
1314    #[test]
1315    fn test_json_nested() {
1316        let mut ctx = Context::new();
1317        let result = ctx
1318            .eval(
1319                r#"
1320import json
1321data = json.loads('{"user": {"name": "Bob", "id": 123}}')
1322data["user"]["name"]
1323        "#,
1324            )
1325            .unwrap();
1326        assert_eq!(result.as_string(), Some("Bob"));
1327    }
1328
1329    #[test]
1330    fn test_module_not_found() {
1331        let mut ctx = Context::new();
1332        let result = ctx.eval("import nonexistent");
1333        assert!(result.is_err());
1334    }
1335
1336    #[test]
1337    fn test_os_getcwd() {
1338        let mut ctx = Context::new();
1339        let result = ctx
1340            .eval(
1341                r#"
1342import os
1343cwd = os.getcwd()
1344len(cwd) > 0
1345        "#,
1346            )
1347            .unwrap();
1348        assert_eq!(result.as_bool(), Some(true));
1349    }
1350
1351    #[test]
1352    fn test_os_listdir() {
1353        let mut ctx = Context::new();
1354        let result = ctx
1355            .eval(
1356                r#"
1357import os
1358files = os.listdir(".")
1359len(files) > 0
1360        "#,
1361            )
1362            .unwrap();
1363        assert_eq!(result.as_bool(), Some(true));
1364    }
1365
1366    #[test]
1367    fn test_os_path_exists() {
1368        let mut ctx = Context::new();
1369        let result = ctx
1370            .eval(
1371                r#"
1372import os
1373os.path.exists("Cargo.toml")
1374        "#,
1375            )
1376            .unwrap();
1377        assert_eq!(result.as_bool(), Some(true));
1378    }
1379
1380    #[test]
1381    fn test_os_path_join() {
1382        let mut ctx = Context::new();
1383        let result = ctx
1384            .eval(
1385                r#"
1386import os
1387path = os.path.join("dir", "subdir", "file.txt")
1388len(path) > 0
1389        "#,
1390            )
1391            .unwrap();
1392        assert_eq!(result.as_bool(), Some(true));
1393    }
1394
1395    #[test]
1396    fn test_os_path_basename() {
1397        let mut ctx = Context::new();
1398        let result = ctx
1399            .eval(
1400                r#"
1401import os
1402os.path.basename("/path/to/file.txt")
1403        "#,
1404            )
1405            .unwrap();
1406        assert_eq!(result.as_string(), Some("file.txt"));
1407    }
1408
1409    #[test]
1410    fn test_os_path_dirname() {
1411        let mut ctx = Context::new();
1412        let result = ctx
1413            .eval(
1414                r#"
1415import os
1416os.path.dirname("/path/to/file.txt")
1417        "#,
1418            )
1419            .unwrap();
1420        assert_eq!(result.as_string(), Some("/path/to"));
1421    }
1422
1423    #[test]
1424    fn test_os_getenv() {
1425        let mut ctx = Context::new();
1426
1427        unsafe {
1428            std::env::set_var("TEST_VAR_OS", "test_value");
1429        }
1430
1431        let result = ctx
1432            .eval(
1433                r#"
1434import os
1435os.getenv("TEST_VAR_OS")
1436        "#,
1437            )
1438            .unwrap();
1439        assert_eq!(result.as_string(), Some("test_value"));
1440
1441        let result = ctx
1442            .eval(
1443                r#"
1444import os
1445os.getenv("NONEXISTENT_VAR_OS", "default")
1446        "#,
1447            )
1448            .unwrap();
1449        assert_eq!(result.as_string(), Some("default"));
1450    }
1451
1452    #[test]
1453    fn test_os_name() {
1454        let mut ctx = Context::new();
1455        let result = ctx
1456            .eval(
1457                r#"
1458import os
1459os.name
1460        "#,
1461            )
1462            .unwrap();
1463
1464        let name = result.as_string().unwrap();
1465        assert!(name == "posix" || name == "nt");
1466    }
1467
1468    #[test]
1469    fn test_os_mkdir_rmdir() {
1470        let mut ctx = Context::new();
1471        let result = ctx
1472            .eval(
1473                r#"
1474import os
1475os.mkdir("test_dir_quickpy")
1476exists = os.path.exists("test_dir_quickpy")
1477os.rmdir("test_dir_quickpy")
1478exists
1479        "#,
1480            )
1481            .unwrap();
1482        assert_eq!(result.as_bool(), Some(true));
1483    }
1484
1485    #[test]
1486    fn test_re_match() {
1487        let mut ctx = Context::new();
1488        let result = ctx
1489            .eval(
1490                r#"
1491import re
1492m = re.match(r"hello", "hello world")
1493m.group(0)
1494        "#,
1495            )
1496            .unwrap();
1497        assert_eq!(result.as_string(), Some("hello"));
1498    }
1499
1500    #[test]
1501    fn test_re_match_no_match() {
1502        let mut ctx = Context::new();
1503        let result = ctx
1504            .eval(
1505                r#"
1506import re
1507m = re.match(r"world", "hello world")
1508m
1509        "#,
1510            )
1511            .unwrap();
1512        assert_eq!(result, Value::None);
1513    }
1514
1515    #[test]
1516    fn test_re_search() {
1517        let mut ctx = Context::new();
1518        let result = ctx
1519            .eval(
1520                r#"
1521import re
1522m = re.search(r"world", "hello world")
1523m.group(0)
1524        "#,
1525            )
1526            .unwrap();
1527        assert_eq!(result.as_string(), Some("world"));
1528    }
1529
1530    #[test]
1531    fn test_re_findall() {
1532        let mut ctx = Context::new();
1533        let result = ctx
1534            .eval(
1535                r#"
1536import re
1537matches = re.findall(r"\d+", "abc 123 def 456 ghi")
1538len(matches)
1539        "#,
1540            )
1541            .unwrap();
1542        assert_eq!(result.as_int(), Some(2));
1543    }
1544
1545    #[test]
1546    fn test_re_sub() {
1547        let mut ctx = Context::new();
1548        let result = ctx
1549            .eval(
1550                r#"
1551import re
1552result = re.sub(r"\d+", "X", "abc 123 def 456")
1553result
1554        "#,
1555            )
1556            .unwrap();
1557        assert_eq!(result.as_string(), Some("abc X def X"));
1558    }
1559
1560    #[test]
1561    fn test_re_split() {
1562        let mut ctx = Context::new();
1563        let result = ctx
1564            .eval(
1565                r#"
1566import re
1567parts = re.split(r"\s+", "hello  world   test")
1568len(parts)
1569        "#,
1570            )
1571            .unwrap();
1572        assert_eq!(result.as_int(), Some(3));
1573    }
1574
1575    #[test]
1576    fn test_re_groups() {
1577        let mut ctx = Context::new();
1578        let result = ctx
1579            .eval(
1580                r#"
1581import re
1582m = re.search(r"(\d+)-(\d+)", "Phone: 123-456")
1583m.group(1)
1584        "#,
1585            )
1586            .unwrap();
1587        assert_eq!(result.as_string(), Some("123"));
1588    }
1589
1590    #[test]
1591    fn test_re_match_span() {
1592        let mut ctx = Context::new();
1593        let result = ctx
1594            .eval(
1595                r#"
1596import re
1597m = re.search(r"world", "hello world")
1598span = m.span()
1599span[0]
1600        "#,
1601            )
1602            .unwrap();
1603        assert_eq!(result.as_int(), Some(6));
1604    }
1605
1606    // === pyq bytecode API tests ===
1607
1608    #[test]
1609    fn test_compile_serialize_execute() {
1610        let source = "x = 1 + 2";
1611        let bytecode = Compiler::compile(source).unwrap();
1612        let bytes = serialize_bytecode(&bytecode).unwrap();
1613        let restored = deserialize_bytecode(&bytes).unwrap();
1614
1615        let mut ctx = Context::new();
1616        ctx.eval_bytecode(&restored).unwrap();
1617        assert_eq!(ctx.get("x"), Some(Value::Int(3)));
1618    }
1619
1620    #[test]
1621    fn test_compile_serialize_roundtrip() {
1622        let source = r#"
1623x = 10 + 20
1624y = x * 2
1625"#;
1626        let bytecode = Compiler::compile(source).unwrap();
1627        let bytes = serialize_bytecode(&bytecode).unwrap();
1628        let restored = deserialize_bytecode(&bytes).unwrap();
1629        assert_eq!(bytecode, restored);
1630    }
1631
1632    #[test]
1633    fn test_serialize_error_on_function() {
1634        let source = "def foo(): return 1";
1635        let bytecode = Compiler::compile(source).unwrap();
1636        assert!(serialize_bytecode(&bytecode).is_err());
1637    }
1638
1639    #[test]
1640    fn test_serialize_error_on_list() {
1641        let source = "x = [1, 2, 3]";
1642        let bytecode = Compiler::compile(source).unwrap();
1643        assert!(serialize_bytecode(&bytecode).is_err());
1644    }
1645
1646    #[test]
1647    fn test_eval_bytecode_with_string() {
1648        let source = r#"name = "hello""#;
1649        let bytecode = Compiler::compile(source).unwrap();
1650        let bytes = serialize_bytecode(&bytecode).unwrap();
1651        let restored = deserialize_bytecode(&bytes).unwrap();
1652
1653        let mut ctx = Context::new();
1654        ctx.eval_bytecode(&restored).unwrap();
1655        assert_eq!(ctx.get("name"), Some(Value::String("hello".to_string())));
1656    }
1657
1658    #[test]
1659    fn test_eval_bytecode_with_float() {
1660        let source = "pi = 3.15";
1661        let bytecode = Compiler::compile(source).unwrap();
1662        let bytes = serialize_bytecode(&bytecode).unwrap();
1663        let restored = deserialize_bytecode(&bytes).unwrap();
1664
1665        let mut ctx = Context::new();
1666        ctx.eval_bytecode(&restored).unwrap();
1667        assert_eq!(ctx.get("pi"), Some(Value::Float(3.15)));
1668    }
1669
1670    #[test]
1671    fn test_unary_minus_int() {
1672        let mut ctx = Context::new();
1673        let result = ctx.eval("-17").unwrap();
1674        assert_eq!(result, Value::Int(-17));
1675    }
1676
1677    #[test]
1678    fn test_unary_minus_float() {
1679        let mut ctx = Context::new();
1680        let result = ctx.eval("-3.15").unwrap();
1681        assert_eq!(result, Value::Float(-3.15));
1682    }
1683
1684    #[test]
1685    fn test_unary_minus_variable() {
1686        let mut ctx = Context::new();
1687        ctx.eval("x = 42").unwrap();
1688        let result = ctx.eval("-x").unwrap();
1689        assert_eq!(result, Value::Int(-42));
1690    }
1691
1692    #[test]
1693    fn test_unary_plus() {
1694        let mut ctx = Context::new();
1695        let result = ctx.eval("+17").unwrap();
1696        assert_eq!(result, Value::Int(17));
1697    }
1698
1699    #[test]
1700    fn test_double_negative() {
1701        let mut ctx = Context::new();
1702        let result = ctx.eval("--17").unwrap();
1703        assert_eq!(result, Value::Int(17));
1704    }
1705
1706    #[test]
1707    fn test_unary_minus_in_expression() {
1708        let mut ctx = Context::new();
1709        let result = ctx.eval("10 + -5").unwrap();
1710        assert_eq!(result, Value::Int(5));
1711    }
1712
1713    #[test]
1714    fn test_unary_minus_serialization() {
1715        let source = "-42";
1716        let bytecode = Compiler::compile(source).unwrap();
1717        let bytes = serialize_bytecode(&bytecode).unwrap();
1718        let restored = deserialize_bytecode(&bytes).unwrap();
1719
1720        let mut ctx = Context::new();
1721        let result = ctx.eval_bytecode(&restored).unwrap();
1722        assert_eq!(result, Value::Int(-42));
1723    }
1724
1725    #[test]
1726    fn test_modulo_int() {
1727        let mut ctx = Context::new();
1728        let result = ctx.eval("10 % 3").unwrap();
1729        assert_eq!(result, Value::Int(1));
1730    }
1731
1732    #[test]
1733    fn test_modulo_even_check() {
1734        let mut ctx = Context::new();
1735        let result = ctx.eval("10 % 2").unwrap();
1736        assert_eq!(result, Value::Int(0));
1737    }
1738
1739    #[test]
1740    fn test_modulo_float() {
1741        let mut ctx = Context::new();
1742        let result = ctx.eval("10.5 % 3.0").unwrap();
1743        assert_eq!(result, Value::Float(1.5));
1744    }
1745
1746    #[test]
1747    fn test_modulo_mixed() {
1748        let mut ctx = Context::new();
1749        let result = ctx.eval("10 % 3.0").unwrap();
1750        assert_eq!(result, Value::Float(1.0));
1751    }
1752
1753    #[test]
1754    fn test_modulo_zero_error() {
1755        let mut ctx = Context::new();
1756        let result = ctx.eval("10 % 0");
1757        assert!(result.is_err());
1758    }
1759
1760    #[test]
1761    fn test_exception_hierarchy_exception_catches_valueerror() {
1762        let mut ctx = Context::new();
1763        let result = ctx
1764            .eval(
1765                r#"
1766try:
1767    raise ValueError("test")
1768except Exception:
1769    x = "caught"
1770x
1771"#,
1772            )
1773            .unwrap();
1774        assert_eq!(result, Value::String("caught".to_string()));
1775    }
1776
1777    #[test]
1778    fn test_exception_hierarchy_exception_catches_all() {
1779        let mut ctx = Context::new();
1780        let result = ctx
1781            .eval(
1782                r#"
1783count = 0
1784try:
1785    raise ValueError("test")
1786except Exception:
1787    count = count + 1
1788try:
1789    raise TypeError("test")
1790except Exception:
1791    count = count + 1
1792try:
1793    raise IndexError("test")
1794except Exception:
1795    count = count + 1
1796count
1797"#,
1798            )
1799            .unwrap();
1800        assert_eq!(result, Value::Int(3));
1801    }
1802
1803    #[test]
1804    fn test_exception_hierarchy_specific_handler_works() {
1805        let mut ctx = Context::new();
1806        let result = ctx
1807            .eval(
1808                r#"
1809try:
1810    raise ValueError("test")
1811except ValueError:
1812    x = "caught ValueError"
1813x
1814"#,
1815            )
1816            .unwrap();
1817        assert_eq!(result, Value::String("caught ValueError".to_string()));
1818    }
1819
1820    #[test]
1821    fn test_exception_hierarchy_wrong_handler_doesnt_catch() {
1822        let mut ctx = Context::new();
1823        let result = ctx
1824            .eval(
1825                r#"
1826try:
1827    raise ValueError("test")
1828except TypeError:
1829    x = "caught TypeError"
1830except ValueError:
1831    x = "caught ValueError"
1832x
1833"#,
1834            )
1835            .unwrap();
1836        assert_eq!(result, Value::String("caught ValueError".to_string()));
1837    }
1838
1839    // Task 027: Augmented Assignment Operators
1840    #[test]
1841    fn test_augmented_add() {
1842        let mut ctx = Context::new();
1843        let result = ctx.eval("x = 10\nx += 5\nx").unwrap();
1844        assert_eq!(result, Value::Int(15));
1845    }
1846
1847    #[test]
1848    fn test_augmented_sub() {
1849        let mut ctx = Context::new();
1850        let result = ctx.eval("x = 10\nx -= 3\nx").unwrap();
1851        assert_eq!(result, Value::Int(7));
1852    }
1853
1854    #[test]
1855    fn test_augmented_mul() {
1856        let mut ctx = Context::new();
1857        let result = ctx.eval("x = 5\nx *= 3\nx").unwrap();
1858        assert_eq!(result, Value::Int(15));
1859    }
1860
1861    #[test]
1862    fn test_augmented_div() {
1863        let mut ctx = Context::new();
1864        let result = ctx.eval("x = 20\nx /= 4\nx").unwrap();
1865        assert_eq!(result, Value::Int(5));
1866    }
1867
1868    #[test]
1869    fn test_augmented_mod() {
1870        let mut ctx = Context::new();
1871        let result = ctx.eval("x = 17\nx %= 5\nx").unwrap();
1872        assert_eq!(result, Value::Int(2));
1873    }
1874
1875    #[test]
1876    fn test_augmented_float() {
1877        let mut ctx = Context::new();
1878        let result = ctx.eval("x = 10.0\nx += 2.5\nx").unwrap();
1879        assert_eq!(result, Value::Float(12.5));
1880    }
1881
1882    #[test]
1883    fn test_augmented_string() {
1884        let mut ctx = Context::new();
1885        let result = ctx.eval("s = \"Hello\"\ns += \" World\"\ns").unwrap();
1886        assert_eq!(result, Value::String("Hello World".to_string()));
1887    }
1888
1889    #[test]
1890    fn test_augmented_in_loop() {
1891        let mut ctx = Context::new();
1892        let result = ctx
1893            .eval(
1894                r#"
1895total = 0
1896for i in range(5):
1897    total += i
1898total
1899"#,
1900            )
1901            .unwrap();
1902        assert_eq!(result, Value::Int(10));
1903    }
1904
1905    // Task 028: Logical Operators
1906    #[test]
1907    fn test_logical_and_both_true() {
1908        let mut ctx = Context::new();
1909        let result = ctx.eval("True and True").unwrap();
1910        assert_eq!(result, Value::Bool(true));
1911    }
1912
1913    #[test]
1914    fn test_logical_and_first_false() {
1915        let mut ctx = Context::new();
1916        let result = ctx.eval("False and True").unwrap();
1917        assert_eq!(result, Value::Bool(false));
1918    }
1919
1920    #[test]
1921    fn test_logical_and_second_false() {
1922        let mut ctx = Context::new();
1923        let result = ctx.eval("True and False").unwrap();
1924        assert_eq!(result, Value::Bool(false));
1925    }
1926
1927    #[test]
1928    fn test_logical_or_both_false() {
1929        let mut ctx = Context::new();
1930        let result = ctx.eval("False or False").unwrap();
1931        assert_eq!(result, Value::Bool(false));
1932    }
1933
1934    #[test]
1935    fn test_logical_or_first_true() {
1936        let mut ctx = Context::new();
1937        let result = ctx.eval("True or False").unwrap();
1938        assert_eq!(result, Value::Bool(true));
1939    }
1940
1941    #[test]
1942    fn test_logical_or_second_true() {
1943        let mut ctx = Context::new();
1944        let result = ctx.eval("False or True").unwrap();
1945        assert_eq!(result, Value::Bool(true));
1946    }
1947
1948    #[test]
1949    fn test_logical_not_true() {
1950        let mut ctx = Context::new();
1951        let result = ctx.eval("not True").unwrap();
1952        assert_eq!(result, Value::Bool(false));
1953    }
1954
1955    #[test]
1956    fn test_logical_not_false() {
1957        let mut ctx = Context::new();
1958        let result = ctx.eval("not False").unwrap();
1959        assert_eq!(result, Value::Bool(true));
1960    }
1961
1962    #[test]
1963    fn test_logical_and_returns_value() {
1964        let mut ctx = Context::new();
1965        // Python's 'and' returns the last truthy value or first falsy value
1966        let result = ctx.eval("1 and 2").unwrap();
1967        assert_eq!(result, Value::Int(2));
1968
1969        let result = ctx.eval("0 and 5").unwrap();
1970        assert_eq!(result, Value::Int(0));
1971    }
1972
1973    #[test]
1974    fn test_logical_or_returns_value() {
1975        let mut ctx = Context::new();
1976        // Python's 'or' returns the first truthy value or last falsy value
1977        let result = ctx.eval("1 or 2").unwrap();
1978        assert_eq!(result, Value::Int(1));
1979
1980        let result = ctx.eval("0 or 5").unwrap();
1981        assert_eq!(result, Value::Int(5));
1982    }
1983
1984    #[test]
1985    fn test_logical_truthiness() {
1986        let mut ctx = Context::new();
1987        // Test truthiness of different types
1988        assert_eq!(ctx.eval("not 0").unwrap(), Value::Bool(true));
1989        assert_eq!(ctx.eval("not 1").unwrap(), Value::Bool(false));
1990        assert_eq!(ctx.eval("not \"\"").unwrap(), Value::Bool(true));
1991        assert_eq!(ctx.eval("not \"hello\"").unwrap(), Value::Bool(false));
1992        assert_eq!(ctx.eval("not []").unwrap(), Value::Bool(true));
1993        assert_eq!(ctx.eval("not [1]").unwrap(), Value::Bool(false));
1994    }
1995
1996    #[test]
1997    fn test_logical_in_condition() {
1998        let mut ctx = Context::new();
1999        let result = ctx
2000            .eval(
2001                r#"
2002x = 5
2003if x > 0 and x < 10:
2004    result = "in range"
2005else:
2006    result = "out of range"
2007result
2008"#,
2009            )
2010            .unwrap();
2011        assert_eq!(result, Value::String("in range".to_string()));
2012    }
2013
2014    #[test]
2015    fn test_logical_chaining() {
2016        let mut ctx = Context::new();
2017        let result = ctx.eval("True and True and True").unwrap();
2018        assert_eq!(result, Value::Bool(true));
2019
2020        let result = ctx.eval("False or False or True").unwrap();
2021        assert_eq!(result, Value::Bool(true));
2022    }
2023
2024    // Task 029: in Operator
2025    #[test]
2026    fn test_in_list_found() {
2027        let mut ctx = Context::new();
2028        let result = ctx.eval("2 in [1, 2, 3]").unwrap();
2029        assert_eq!(result, Value::Bool(true));
2030    }
2031
2032    #[test]
2033    fn test_in_list_not_found() {
2034        let mut ctx = Context::new();
2035        let result = ctx.eval("4 in [1, 2, 3]").unwrap();
2036        assert_eq!(result, Value::Bool(false));
2037    }
2038
2039    #[test]
2040    fn test_not_in_list() {
2041        let mut ctx = Context::new();
2042        let result = ctx.eval("4 not in [1, 2, 3]").unwrap();
2043        assert_eq!(result, Value::Bool(true));
2044    }
2045
2046    #[test]
2047    fn test_in_string() {
2048        let mut ctx = Context::new();
2049        let result = ctx.eval("\"world\" in \"hello world\"").unwrap();
2050        assert_eq!(result, Value::Bool(true));
2051
2052        let result = ctx.eval("\"xyz\" in \"hello world\"").unwrap();
2053        assert_eq!(result, Value::Bool(false));
2054    }
2055
2056    #[test]
2057    fn test_in_dict() {
2058        let mut ctx = Context::new();
2059        let result = ctx
2060            .eval(
2061                r#"
2062d = {"a": 1, "b": 2}
2063result = "a" in d
2064result
2065"#,
2066            )
2067            .unwrap();
2068        assert_eq!(result, Value::Bool(true));
2069
2070        let result = ctx
2071            .eval(
2072                r#"
2073d = {"a": 1, "b": 2}
2074result = "c" in d
2075result
2076"#,
2077            )
2078            .unwrap();
2079        assert_eq!(result, Value::Bool(false));
2080    }
2081
2082    #[test]
2083    fn test_in_empty_containers() {
2084        let mut ctx = Context::new();
2085        assert_eq!(ctx.eval("1 in []").unwrap(), Value::Bool(false));
2086        assert_eq!(ctx.eval("\"x\" in {}").unwrap(), Value::Bool(false));
2087        assert_eq!(ctx.eval("\"x\" in \"\"").unwrap(), Value::Bool(false));
2088    }
2089
2090    #[test]
2091    fn test_in_condition() {
2092        let mut ctx = Context::new();
2093        let result = ctx
2094            .eval(
2095                r#"
2096numbers = [1, 2, 3, 4, 5]
2097if 3 in numbers:
2098    result = "found"
2099else:
2100    result = "not found"
2101result
2102"#,
2103            )
2104            .unwrap();
2105        assert_eq!(result, Value::String("found".to_string()));
2106    }
2107
2108    #[test]
2109    fn test_in_loop() {
2110        let mut ctx = Context::new();
2111        let result = ctx
2112            .eval(
2113                r#"
2114count = 0
2115for i in range(10):
2116    if i in [2, 4, 6, 8]:
2117        count += 1
2118count
2119"#,
2120            )
2121            .unwrap();
2122        assert_eq!(result, Value::Int(4));
2123    }
2124
2125    // Task 030: String Methods
2126    #[test]
2127    fn test_string_split_whitespace() {
2128        let mut ctx = Context::new();
2129        let result = ctx
2130            .eval(
2131                r#"
2132s = "hello world python"
2133words = s.split()
2134len(words)
2135"#,
2136            )
2137            .unwrap();
2138        assert_eq!(result, Value::Int(3));
2139    }
2140
2141    #[test]
2142    fn test_string_split_separator() {
2143        let mut ctx = Context::new();
2144        let result = ctx
2145            .eval(
2146                r#"
2147s = "a,b,c"
2148parts = s.split(",")
2149len(parts)
2150"#,
2151            )
2152            .unwrap();
2153        assert_eq!(result, Value::Int(3));
2154    }
2155
2156    #[test]
2157    fn test_string_strip() {
2158        let mut ctx = Context::new();
2159        let result = ctx.eval(r#""  hello  ".strip()"#).unwrap();
2160        assert_eq!(result, Value::String("hello".to_string()));
2161    }
2162
2163    #[test]
2164    fn test_string_startswith() {
2165        let mut ctx = Context::new();
2166        let result = ctx.eval(r#""hello world".startswith("hello")"#).unwrap();
2167        assert_eq!(result, Value::Bool(true));
2168
2169        let result = ctx.eval(r#""hello world".startswith("world")"#).unwrap();
2170        assert_eq!(result, Value::Bool(false));
2171    }
2172
2173    #[test]
2174    fn test_string_endswith() {
2175        let mut ctx = Context::new();
2176        let result = ctx.eval(r#""hello world".endswith("world")"#).unwrap();
2177        assert_eq!(result, Value::Bool(true));
2178
2179        let result = ctx.eval(r#""hello world".endswith("hello")"#).unwrap();
2180        assert_eq!(result, Value::Bool(false));
2181    }
2182
2183    #[test]
2184    fn test_string_lower() {
2185        let mut ctx = Context::new();
2186        let result = ctx.eval(r#""Hello World".lower()"#).unwrap();
2187        assert_eq!(result, Value::String("hello world".to_string()));
2188    }
2189
2190    #[test]
2191    fn test_string_upper() {
2192        let mut ctx = Context::new();
2193        let result = ctx.eval(r#""Hello World".upper()"#).unwrap();
2194        assert_eq!(result, Value::String("HELLO WORLD".to_string()));
2195    }
2196
2197    #[test]
2198    fn test_string_replace() {
2199        let mut ctx = Context::new();
2200        let result = ctx
2201            .eval(r#""hello world".replace("world", "python")"#)
2202            .unwrap();
2203        assert_eq!(result, Value::String("hello python".to_string()));
2204    }
2205
2206    #[test]
2207    fn test_string_join() {
2208        let mut ctx = Context::new();
2209        let result = ctx
2210            .eval(
2211                r#"
2212words = ["hello", "world"]
2213" ".join(words)
2214"#,
2215            )
2216            .unwrap();
2217        assert_eq!(result, Value::String("hello world".to_string()));
2218
2219        let result = ctx
2220            .eval(
2221                r#"
2222words = ["hello", "world"]
2223",".join(words)
2224"#,
2225            )
2226            .unwrap();
2227        assert_eq!(result, Value::String("hello,world".to_string()));
2228    }
2229
2230    #[test]
2231    fn test_string_method_chaining() {
2232        let mut ctx = Context::new();
2233        let result = ctx.eval(r#""  HELLO WORLD  ".strip().lower()"#).unwrap();
2234        assert_eq!(result, Value::String("hello world".to_string()));
2235    }
2236
2237    #[test]
2238    fn test_string_split_empty() {
2239        let mut ctx = Context::new();
2240        let result = ctx
2241            .eval(
2242                r#"
2243parts = "".split()
2244len(parts)
2245"#,
2246            )
2247            .unwrap();
2248        assert_eq!(result, Value::Int(0));
2249    }
2250
2251    // Task 031: Dictionary .get() Method
2252    #[test]
2253    fn test_dict_get_existing_key() {
2254        let mut ctx = Context::new();
2255        let result = ctx
2256            .eval(
2257                r#"
2258d = {"a": 1, "b": 2}
2259d.get("a")
2260"#,
2261            )
2262            .unwrap();
2263        assert_eq!(result, Value::Int(1));
2264    }
2265
2266    #[test]
2267    fn test_dict_get_missing_key_no_default() {
2268        let mut ctx = Context::new();
2269        let result = ctx
2270            .eval(
2271                r#"
2272d = {"a": 1}
2273d.get("b")
2274"#,
2275            )
2276            .unwrap();
2277        assert_eq!(result, Value::None);
2278    }
2279
2280    #[test]
2281    fn test_dict_get_missing_key_with_default() {
2282        let mut ctx = Context::new();
2283        let result = ctx
2284            .eval(
2285                r#"
2286d = {"a": 1}
2287d.get("b", 0)
2288"#,
2289            )
2290            .unwrap();
2291        assert_eq!(result, Value::Int(0));
2292
2293        let result = ctx
2294            .eval(
2295                r#"
2296d = {"a": 1}
2297d.get("c", "default")
2298"#,
2299            )
2300            .unwrap();
2301        assert_eq!(result, Value::String("default".to_string()));
2302    }
2303
2304    #[test]
2305    fn test_dict_get_doesnt_modify() {
2306        let mut ctx = Context::new();
2307        ctx.eval(
2308            r#"
2309d = {"a": 1}
2310result = d.get("b", 0)
2311"#,
2312        )
2313        .unwrap();
2314
2315        let result = ctx.eval(r#""b" in d"#).unwrap();
2316        assert_eq!(result, Value::Bool(false));
2317    }
2318
2319    #[test]
2320    fn test_dict_get_different_key_types() {
2321        let mut ctx = Context::new();
2322        let result = ctx
2323            .eval(
2324                r#"
2325d = {1: "one", "two": 2}
2326d.get(1)
2327"#,
2328            )
2329            .unwrap();
2330        assert_eq!(result, Value::String("one".to_string()));
2331
2332        let result = ctx
2333            .eval(
2334                r#"
2335d = {1: "one", "two": 2}
2336d.get("two")
2337"#,
2338            )
2339            .unwrap();
2340        assert_eq!(result, Value::Int(2));
2341
2342        let result = ctx
2343            .eval(
2344                r#"
2345d = {1: "one", "two": 2}
2346d.get(3, "missing")
2347"#,
2348            )
2349            .unwrap();
2350        assert_eq!(result, Value::String("missing".to_string()));
2351    }
2352
2353    #[test]
2354    fn test_dict_get_real_usage() {
2355        let mut ctx = Context::new();
2356        ctx.eval(
2357            r#"
2358config = {"host": "localhost", "port": 8080}
2359host = config.get("host", "0.0.0.0")
2360timeout = config.get("timeout", 30)
2361"#,
2362        )
2363        .unwrap();
2364
2365        let host = ctx.get("host").unwrap();
2366        assert_eq!(host, Value::String("localhost".to_string()));
2367
2368        let timeout = ctx.get("timeout").unwrap();
2369        assert_eq!(timeout, Value::Int(30));
2370    }
2371
2372    #[test]
2373    fn test_dict_get_no_args_error() {
2374        let mut ctx = Context::new();
2375        let result = ctx.eval(
2376            r#"
2377d = {"a": 1}
2378d.get()
2379"#,
2380        );
2381        assert!(result.is_err());
2382        let err = result.unwrap_err();
2383        assert!(err.contains("TypeError"));
2384    }
2385
2386    // Task 032: Multiple Assignment and Tuple Unpacking
2387    #[test]
2388    fn test_tuple_unpacking_basic() {
2389        let mut ctx = Context::new();
2390        ctx.eval("a, b = 1, 2").unwrap();
2391        assert_eq!(ctx.get("a"), Some(Value::Int(1)));
2392        assert_eq!(ctx.get("b"), Some(Value::Int(2)));
2393    }
2394
2395    #[test]
2396    fn test_tuple_unpacking_from_list() {
2397        let mut ctx = Context::new();
2398        ctx.eval("x, y = [10, 20]").unwrap();
2399        assert_eq!(ctx.get("x"), Some(Value::Int(10)));
2400        assert_eq!(ctx.get("y"), Some(Value::Int(20)));
2401    }
2402
2403    #[test]
2404    fn test_tuple_unpacking_from_tuple() {
2405        let mut ctx = Context::new();
2406        ctx.eval("p, q = (100, 200)").unwrap();
2407        assert_eq!(ctx.get("p"), Some(Value::Int(100)));
2408        assert_eq!(ctx.get("q"), Some(Value::Int(200)));
2409    }
2410
2411    #[test]
2412    fn test_tuple_swap_variables() {
2413        let mut ctx = Context::new();
2414        ctx.eval(
2415            r#"
2416a = 5
2417b = 10
2418a, b = b, a
2419"#,
2420        )
2421        .unwrap();
2422        assert_eq!(ctx.get("a"), Some(Value::Int(10)));
2423        assert_eq!(ctx.get("b"), Some(Value::Int(5)));
2424    }
2425
2426    #[test]
2427    fn test_tuple_multiple_values() {
2428        let mut ctx = Context::new();
2429        ctx.eval("a, b, c = 1, 2, 3").unwrap();
2430        assert_eq!(ctx.get("a"), Some(Value::Int(1)));
2431        assert_eq!(ctx.get("b"), Some(Value::Int(2)));
2432        assert_eq!(ctx.get("c"), Some(Value::Int(3)));
2433    }
2434
2435    #[test]
2436    fn test_tuple_function_return() {
2437        let mut ctx = Context::new();
2438        ctx.eval(
2439            r#"
2440def get_coords():
2441    return 3, 4
2442
2443x, y = get_coords()
2444"#,
2445        )
2446        .unwrap();
2447        assert_eq!(ctx.get("x"), Some(Value::Int(3)));
2448        assert_eq!(ctx.get("y"), Some(Value::Int(4)));
2449    }
2450
2451    #[test]
2452    fn test_tuple_unpacking_too_many_values() {
2453        let mut ctx = Context::new();
2454        let result = ctx.eval("a, b = [1, 2, 3]");
2455        assert!(result.is_err());
2456        let err = result.unwrap_err();
2457        assert!(err.contains("ValueError") || err.contains("too many values"));
2458    }
2459
2460    #[test]
2461    fn test_tuple_unpacking_too_few_values() {
2462        let mut ctx = Context::new();
2463        let result = ctx.eval("a, b, c = [1, 2]");
2464        assert!(result.is_err());
2465        let err = result.unwrap_err();
2466        assert!(err.contains("ValueError") || err.contains("expected 3"));
2467    }
2468
2469    #[test]
2470    fn test_tuple_literal() {
2471        let mut ctx = Context::new();
2472        let result = ctx.eval("t = (1, 2, 3)").unwrap();
2473        assert_eq!(result, Value::None);
2474        // Tuple is stored in variable t
2475    }
2476
2477    #[test]
2478    fn test_tuple_in_expression() {
2479        let mut ctx = Context::new();
2480        let result = ctx.eval("(1, 2)").unwrap();
2481        // Should return a tuple
2482        match result {
2483            Value::Tuple(t) => {
2484                assert_eq!(t.len(), 2);
2485                assert_eq!(t[0], Value::Int(1));
2486                assert_eq!(t[1], Value::Int(2));
2487            }
2488            _ => panic!("Expected tuple"),
2489        }
2490    }
2491
2492    // Task 034: str() Builtin Function
2493    #[test]
2494    fn test_str_int() {
2495        let mut ctx = Context::new();
2496        let result = ctx.eval("str(123)").unwrap();
2497        assert_eq!(result, Value::String("123".to_string()));
2498    }
2499
2500    #[test]
2501    fn test_str_float() {
2502        let mut ctx = Context::new();
2503        let result = ctx.eval("str(3.14)").unwrap();
2504        assert_eq!(result, Value::String("3.14".to_string()));
2505    }
2506
2507    #[test]
2508    fn test_str_bool() {
2509        let mut ctx = Context::new();
2510        let result = ctx.eval("str(True)").unwrap();
2511        assert_eq!(result, Value::String("True".to_string()));
2512
2513        let result = ctx.eval("str(False)").unwrap();
2514        assert_eq!(result, Value::String("False".to_string()));
2515    }
2516
2517    #[test]
2518    fn test_str_none() {
2519        let mut ctx = Context::new();
2520        let result = ctx.eval("str(None)").unwrap();
2521        assert_eq!(result, Value::String("None".to_string()));
2522    }
2523
2524    #[test]
2525    fn test_str_string() {
2526        let mut ctx = Context::new();
2527        let result = ctx.eval(r#"str("hello")"#).unwrap();
2528        assert_eq!(result, Value::String("hello".to_string()));
2529    }
2530
2531    #[test]
2532    fn test_str_list() {
2533        let mut ctx = Context::new();
2534        let result = ctx.eval("str([1, 2, 3])").unwrap();
2535        assert_eq!(result, Value::String("[1, 2, 3]".to_string()));
2536    }
2537
2538    #[test]
2539    fn test_str_tuple() {
2540        let mut ctx = Context::new();
2541        let result = ctx.eval("str((1, 2))").unwrap();
2542        assert_eq!(result, Value::String("(1, 2)".to_string()));
2543    }
2544
2545    #[test]
2546    fn test_str_dict() {
2547        let mut ctx = Context::new();
2548        ctx.eval(r#"d = {"a": 1}"#).unwrap();
2549        let result = ctx.eval("str(d)").unwrap();
2550        // Dict order might vary, just check it contains the key-value
2551        let s = result.as_string().unwrap();
2552        assert!(s.contains("'a'"));
2553        assert!(s.contains("1"));
2554    }
2555
2556    #[test]
2557    fn test_str_concatenation() {
2558        let mut ctx = Context::new();
2559        let result = ctx.eval(r#""Number: " + str(42)"#).unwrap();
2560        assert_eq!(result, Value::String("Number: 42".to_string()));
2561    }
2562
2563    // Task 033: F-String Formatting
2564    #[test]
2565    fn test_fstring_simple_variable() {
2566        let mut ctx = Context::new();
2567        ctx.eval(r#"name = "Alice""#).unwrap();
2568        let result = ctx.eval(r#"f"Hello {name}""#).unwrap();
2569        assert_eq!(result, Value::String("Hello Alice".to_string()));
2570    }
2571
2572    #[test]
2573    fn test_fstring_multiple_variables() {
2574        let mut ctx = Context::new();
2575        ctx.eval("x = 10").unwrap();
2576        ctx.eval("y = 20").unwrap();
2577        let result = ctx.eval(r#"f"{x} + {y} = {x + y}""#).unwrap();
2578        assert_eq!(result, Value::String("10 + 20 = 30".to_string()));
2579    }
2580
2581    #[test]
2582    fn test_fstring_expressions() {
2583        let mut ctx = Context::new();
2584        ctx.eval("n = 5").unwrap();
2585        let result = ctx.eval(r#"f"Square of {n} is {n * n}""#).unwrap();
2586        assert_eq!(result, Value::String("Square of 5 is 25".to_string()));
2587    }
2588
2589    #[test]
2590    fn test_fstring_different_types() {
2591        let mut ctx = Context::new();
2592        ctx.eval("age = 30").unwrap();
2593        ctx.eval("height = 5.9").unwrap();
2594        let result = ctx.eval(r#"f"Age: {age}, Height: {height}""#).unwrap();
2595        assert_eq!(result, Value::String("Age: 30, Height: 5.9".to_string()));
2596    }
2597
2598    #[test]
2599    fn test_fstring_no_interpolation() {
2600        let mut ctx = Context::new();
2601        let result = ctx.eval(r#"f"Hello World""#).unwrap();
2602        assert_eq!(result, Value::String("Hello World".to_string()));
2603    }
2604
2605    #[test]
2606    fn test_fstring_only_expression() {
2607        let mut ctx = Context::new();
2608        ctx.eval("x = 42").unwrap();
2609        let result = ctx.eval(r#"f"{x}""#).unwrap();
2610        assert_eq!(result, Value::String("42".to_string()));
2611    }
2612
2613    #[test]
2614    fn test_fstring_function_call() {
2615        let mut ctx = Context::new();
2616        ctx.eval(
2617            r#"
2618def get_name():
2619    return "Bob"
2620"#,
2621        )
2622        .unwrap();
2623        let result = ctx.eval(r#"f"Hello {get_name()}""#).unwrap();
2624        assert_eq!(result, Value::String("Hello Bob".to_string()));
2625    }
2626
2627    #[test]
2628    fn test_fstring_nested_expression() {
2629        let mut ctx = Context::new();
2630        ctx.eval("items = [1, 2, 3]").unwrap();
2631        let result = ctx.eval(r#"f"Length: {len(items)}""#).unwrap();
2632        assert_eq!(result, Value::String("Length: 3".to_string()));
2633    }
2634
2635    // Task 035: Slicing tests
2636    #[test]
2637    fn test_list_slice_basic() {
2638        let mut ctx = Context::new();
2639        ctx.eval("items = [0, 1, 2, 3, 4]").unwrap();
2640        let result = ctx.eval("items[1:3]").unwrap();
2641        let expected = ctx.eval("[1, 2]").unwrap();
2642        assert_eq!(result, expected);
2643    }
2644
2645    #[test]
2646    fn test_list_slice_start_only() {
2647        let mut ctx = Context::new();
2648        ctx.eval("items = [0, 1, 2, 3, 4]").unwrap();
2649        let result = ctx.eval("items[2:]").unwrap();
2650        let expected = ctx.eval("[2, 3, 4]").unwrap();
2651        assert_eq!(result, expected);
2652    }
2653
2654    #[test]
2655    fn test_list_slice_stop_only() {
2656        let mut ctx = Context::new();
2657        ctx.eval("items = [0, 1, 2, 3, 4]").unwrap();
2658        let result = ctx.eval("items[:3]").unwrap();
2659        let expected = ctx.eval("[0, 1, 2]").unwrap();
2660        assert_eq!(result, expected);
2661    }
2662
2663    #[test]
2664    fn test_list_slice_full() {
2665        let mut ctx = Context::new();
2666        ctx.eval("items = [0, 1, 2, 3, 4]").unwrap();
2667        let result = ctx.eval("items[:]").unwrap();
2668        let expected = ctx.eval("[0, 1, 2, 3, 4]").unwrap();
2669        assert_eq!(result, expected);
2670    }
2671
2672    #[test]
2673    fn test_list_slice_step() {
2674        let mut ctx = Context::new();
2675        ctx.eval("items = [0, 1, 2, 3, 4, 5, 6]").unwrap();
2676        let result = ctx.eval("items[::2]").unwrap();
2677        let expected = ctx.eval("[0, 2, 4, 6]").unwrap();
2678        assert_eq!(result, expected);
2679    }
2680
2681    #[test]
2682    fn test_list_slice_negative_indices() {
2683        let mut ctx = Context::new();
2684        ctx.eval("items = [0, 1, 2, 3, 4]").unwrap();
2685        let result = ctx.eval("items[-3:-1]").unwrap();
2686        let expected = ctx.eval("[2, 3]").unwrap();
2687        assert_eq!(result, expected);
2688    }
2689
2690    #[test]
2691    fn test_list_slice_negative_step() {
2692        let mut ctx = Context::new();
2693        ctx.eval("items = [0, 1, 2, 3, 4]").unwrap();
2694        let result = ctx.eval("items[::-1]").unwrap();
2695        let expected = ctx.eval("[4, 3, 2, 1, 0]").unwrap();
2696        assert_eq!(result, expected);
2697    }
2698
2699    #[test]
2700    fn test_string_slice_basic() {
2701        let mut ctx = Context::new();
2702        let result = ctx.eval(r#""hello"[1:4]"#).unwrap();
2703        assert_eq!(result, Value::String("ell".to_string()));
2704    }
2705
2706    #[test]
2707    fn test_string_slice_start_only() {
2708        let mut ctx = Context::new();
2709        let result = ctx.eval(r#""hello"[2:]"#).unwrap();
2710        assert_eq!(result, Value::String("llo".to_string()));
2711    }
2712
2713    #[test]
2714    fn test_string_slice_stop_only() {
2715        let mut ctx = Context::new();
2716        let result = ctx.eval(r#""hello"[:3]"#).unwrap();
2717        assert_eq!(result, Value::String("hel".to_string()));
2718    }
2719
2720    #[test]
2721    fn test_string_slice_step() {
2722        let mut ctx = Context::new();
2723        let result = ctx.eval(r#""hello"[::2]"#).unwrap();
2724        assert_eq!(result, Value::String("hlo".to_string()));
2725    }
2726
2727    #[test]
2728    fn test_string_slice_negative_step() {
2729        let mut ctx = Context::new();
2730        let result = ctx.eval(r#""hello"[::-1]"#).unwrap();
2731        assert_eq!(result, Value::String("olleh".to_string()));
2732    }
2733
2734    #[test]
2735    fn test_tuple_slice_basic() {
2736        let mut ctx = Context::new();
2737        ctx.eval("t = (0, 1, 2, 3, 4)").unwrap();
2738        let result = ctx.eval("t[1:3]").unwrap();
2739        let expected = ctx.eval("(1, 2)").unwrap();
2740        assert_eq!(result, expected);
2741    }
2742
2743    #[test]
2744    fn test_slice_empty_result() {
2745        let mut ctx = Context::new();
2746        ctx.eval("items = [1, 2, 3]").unwrap();
2747        let result = ctx.eval("items[5:10]").unwrap();
2748        let expected = ctx.eval("[]").unwrap();
2749        assert_eq!(result, expected);
2750    }
2751
2752    // Task 036: isinstance() tests
2753    #[test]
2754    fn test_isinstance_int() {
2755        let mut ctx = Context::new();
2756        ctx.eval("x = 123").unwrap();
2757        let result = ctx.eval("isinstance(x, int)").unwrap();
2758        assert_eq!(result, Value::Bool(true));
2759        let result = ctx.eval("isinstance(x, str)").unwrap();
2760        assert_eq!(result, Value::Bool(false));
2761    }
2762
2763    #[test]
2764    fn test_isinstance_float() {
2765        let mut ctx = Context::new();
2766        ctx.eval("y = 3.14").unwrap();
2767        let result = ctx.eval("isinstance(y, float)").unwrap();
2768        assert_eq!(result, Value::Bool(true));
2769        let result = ctx.eval("isinstance(y, int)").unwrap();
2770        assert_eq!(result, Value::Bool(false));
2771    }
2772
2773    #[test]
2774    fn test_isinstance_string() {
2775        let mut ctx = Context::new();
2776        ctx.eval("s = 'hello'").unwrap();
2777        let result = ctx.eval("isinstance(s, str)").unwrap();
2778        assert_eq!(result, Value::Bool(true));
2779        let result = ctx.eval("isinstance(s, list)").unwrap();
2780        assert_eq!(result, Value::Bool(false));
2781    }
2782
2783    #[test]
2784    fn test_isinstance_bool() {
2785        let mut ctx = Context::new();
2786        ctx.eval("b = True").unwrap();
2787        let result = ctx.eval("isinstance(b, bool)").unwrap();
2788        assert_eq!(result, Value::Bool(true));
2789    }
2790
2791    #[test]
2792    fn test_isinstance_list() {
2793        let mut ctx = Context::new();
2794        ctx.eval("lst = [1, 2, 3]").unwrap();
2795        let result = ctx.eval("isinstance(lst, list)").unwrap();
2796        assert_eq!(result, Value::Bool(true));
2797        let result = ctx.eval("isinstance(lst, dict)").unwrap();
2798        assert_eq!(result, Value::Bool(false));
2799    }
2800
2801    #[test]
2802    fn test_isinstance_dict() {
2803        let mut ctx = Context::new();
2804        ctx.eval("d = {'a': 1}").unwrap();
2805        let result = ctx.eval("isinstance(d, dict)").unwrap();
2806        assert_eq!(result, Value::Bool(true));
2807        let result = ctx.eval("isinstance(d, list)").unwrap();
2808        assert_eq!(result, Value::Bool(false));
2809    }
2810
2811    #[test]
2812    fn test_isinstance_tuple() {
2813        let mut ctx = Context::new();
2814        ctx.eval("t = (1, 2, 3)").unwrap();
2815        let result = ctx.eval("isinstance(t, tuple)").unwrap();
2816        assert_eq!(result, Value::Bool(true));
2817        let result = ctx.eval("isinstance(t, list)").unwrap();
2818        assert_eq!(result, Value::Bool(false));
2819    }
2820
2821    #[test]
2822    fn test_isinstance_in_condition() {
2823        let mut ctx = Context::new();
2824        ctx.eval(
2825            r#"
2826def process(value):
2827    if isinstance(value, int):
2828        return value * 2
2829    elif isinstance(value, str):
2830        return value.upper()
2831    else:
2832        return None
2833"#,
2834        )
2835        .unwrap();
2836        let result = ctx.eval("process(5)").unwrap();
2837        assert_eq!(result, Value::Int(10));
2838        let result = ctx.eval("process('hi')").unwrap();
2839        assert_eq!(result, Value::String("HI".to_string()));
2840    }
2841
2842    #[test]
2843    fn test_isinstance_wrong_arg_count() {
2844        let mut ctx = Context::new();
2845        let result = ctx.eval("isinstance(1)");
2846        assert!(result.is_err());
2847    }
2848
2849    #[test]
2850    fn test_isinstance_second_arg_not_type() {
2851        let mut ctx = Context::new();
2852        let result = ctx.eval("isinstance(1, 'int')");
2853        assert!(result.is_err());
2854    }
2855
2856    // Task 037: List Comprehensions tests
2857    #[test]
2858    fn test_listcomp_basic() {
2859        let mut ctx = Context::new();
2860        let result = ctx.eval("[x*x for x in range(5)]").unwrap();
2861        let expected = ctx.eval("[0, 1, 4, 9, 16]").unwrap();
2862        assert_eq!(result, expected);
2863    }
2864
2865    #[test]
2866    fn test_listcomp_with_filter() {
2867        let mut ctx = Context::new();
2868        let result = ctx.eval("[x for x in range(10) if x % 2 == 0]").unwrap();
2869        let expected = ctx.eval("[0, 2, 4, 6, 8]").unwrap();
2870        assert_eq!(result, expected);
2871    }
2872
2873    #[test]
2874    fn test_listcomp_string_transformation() {
2875        let mut ctx = Context::new();
2876        ctx.eval("words = ['hello', 'world']").unwrap();
2877        let result = ctx.eval("[w.upper() for w in words]").unwrap();
2878        let expected = ctx.eval("['HELLO', 'WORLD']").unwrap();
2879        assert_eq!(result, expected);
2880    }
2881
2882    #[test]
2883    fn test_listcomp_expression() {
2884        let mut ctx = Context::new();
2885        ctx.eval("nums = [1, 2, 3]").unwrap();
2886        let result = ctx.eval("[n * 2 for n in nums]").unwrap();
2887        let expected = ctx.eval("[2, 4, 6]").unwrap();
2888        assert_eq!(result, expected);
2889    }
2890
2891    #[test]
2892    fn test_listcomp_empty_result() {
2893        let mut ctx = Context::new();
2894        let result = ctx.eval("[x for x in range(5) if x > 10]").unwrap();
2895        let expected = ctx.eval("[]").unwrap();
2896        assert_eq!(result, expected);
2897    }
2898
2899    #[test]
2900    fn test_listcomp_multiple_filters() {
2901        let mut ctx = Context::new();
2902        let result = ctx
2903            .eval("[x for x in range(20) if x % 2 == 0 if x % 3 == 0]")
2904            .unwrap();
2905        let expected = ctx.eval("[0, 6, 12, 18]").unwrap();
2906        assert_eq!(result, expected);
2907    }
2908
2909    #[test]
2910    fn test_listcomp_with_variable() {
2911        let mut ctx = Context::new();
2912        ctx.eval("n = 5").unwrap();
2913        let result = ctx.eval("[i for i in range(n)]").unwrap();
2914        let expected = ctx.eval("[0, 1, 2, 3, 4]").unwrap();
2915        assert_eq!(result, expected);
2916    }
2917
2918    #[test]
2919    fn test_listcomp_complex_expression() {
2920        let mut ctx = Context::new();
2921        let result = ctx.eval("[x*2 + 1 for x in range(5)]").unwrap();
2922        let expected = ctx.eval("[1, 3, 5, 7, 9]").unwrap();
2923        assert_eq!(result, expected);
2924    }
2925
2926    #[test]
2927    fn test_listcomp_from_list() {
2928        let mut ctx = Context::new();
2929        ctx.eval("items = [1, 2, 3, 4, 5]").unwrap();
2930        let result = ctx.eval("[x*x for x in items if x > 2]").unwrap();
2931        let expected = ctx.eval("[9, 16, 25]").unwrap();
2932        assert_eq!(result, expected);
2933    }
2934
2935    #[test]
2936    fn test_listcomp_string_iteration() {
2937        let mut ctx = Context::new();
2938        let result = ctx.eval("[c for c in 'hello']").unwrap();
2939        let expected = ctx.eval("['h', 'e', 'l', 'l', 'o']").unwrap();
2940        assert_eq!(result, expected);
2941    }
2942
2943    #[test]
2944    fn test_string_iteration_for_loop() {
2945        let mut ctx = Context::new();
2946        ctx.eval(
2947            r#"
2948result = []
2949for c in "abc":
2950    result.append(c)
2951"#,
2952        )
2953        .unwrap();
2954        let result = ctx.eval("result").unwrap();
2955        let expected = ctx.eval("['a', 'b', 'c']").unwrap();
2956        assert_eq!(result, expected);
2957    }
2958
2959    // Task 038: Async/Await Support
2960    #[test]
2961    fn test_async_function_basic() {
2962        let mut ctx = Context::new();
2963        ctx.eval(
2964            r#"
2965async def greet(name):
2966    return "Hello, " + name
2967
2968result = await greet("World")
2969"#,
2970        )
2971        .unwrap();
2972        let result = ctx.eval("result").unwrap();
2973        assert_eq!(result, Value::String("Hello, World".to_string()));
2974    }
2975
2976    #[test]
2977    fn test_async_function_with_computation() {
2978        let mut ctx = Context::new();
2979        ctx.eval(
2980            r#"
2981async def compute(x, y):
2982    return x * y + 10
2983
2984result = await compute(5, 3)
2985"#,
2986        )
2987        .unwrap();
2988        let result = ctx.eval("result").unwrap();
2989        assert_eq!(result, Value::Int(25));
2990    }
2991
2992    #[test]
2993    fn test_async_function_returns_coroutine() {
2994        let mut ctx = Context::new();
2995        ctx.eval(
2996            r#"
2997async def get_value():
2998    return 42
2999
3000coro = get_value()
3001"#,
3002        )
3003        .unwrap();
3004        let result = ctx.eval("coro").unwrap();
3005        // Should be a coroutine object, not the result
3006        match result {
3007            Value::Coroutine(_, _) => {} // Expected
3008            _ => panic!("Expected coroutine, got {:?}", result),
3009        }
3010    }
3011
3012    #[test]
3013    fn test_await_coroutine() {
3014        let mut ctx = Context::new();
3015        ctx.eval(
3016            r#"
3017async def get_value():
3018    return 42
3019
3020coro = get_value()
3021result = await coro
3022"#,
3023        )
3024        .unwrap();
3025        let result = ctx.eval("result").unwrap();
3026        assert_eq!(result, Value::Int(42));
3027    }
3028
3029    #[test]
3030    fn test_async_function_with_multiple_statements() {
3031        let mut ctx = Context::new();
3032        ctx.eval(
3033            r#"
3034async def process(x):
3035    y = x * 2
3036    z = y + 5
3037    return z
3038
3039result = await process(10)
3040"#,
3041        )
3042        .unwrap();
3043        let result = ctx.eval("result").unwrap();
3044        assert_eq!(result, Value::Int(25));
3045    }
3046
3047    #[test]
3048    fn test_await_non_coroutine_error() {
3049        let mut ctx = Context::new();
3050        let result = ctx.eval("await 42");
3051        assert!(result.is_err());
3052        let err = result.unwrap_err();
3053        assert!(err.contains("TypeError"));
3054        assert!(err.contains("cannot be awaited"));
3055    }
3056
3057    #[test]
3058    fn test_async_function_with_conditionals() {
3059        let mut ctx = Context::new();
3060        ctx.eval(
3061            r#"
3062async def check(x):
3063    if x > 10:
3064        return "big"
3065    else:
3066        return "small"
3067
3068result1 = await check(15)
3069result2 = await check(5)
3070"#,
3071        )
3072        .unwrap();
3073        let result1 = ctx.eval("result1").unwrap();
3074        let result2 = ctx.eval("result2").unwrap();
3075        assert_eq!(result1, Value::String("big".to_string()));
3076        assert_eq!(result2, Value::String("small".to_string()));
3077    }
3078
3079    #[test]
3080    fn test_async_function_nested_calls() {
3081        let mut ctx = Context::new();
3082        ctx.eval(
3083            r#"
3084async def inner(x):
3085    return x * 2
3086
3087async def outer(x):
3088    y = await inner(x)
3089    return y + 1
3090
3091result = await outer(5)
3092"#,
3093        )
3094        .unwrap();
3095        let result = ctx.eval("result").unwrap();
3096        assert_eq!(result, Value::Int(11));
3097    }
3098
3099    // Tests for asyncio.sleep - true async behavior
3100    #[test]
3101    fn test_asyncio_sleep_basic() {
3102        let mut ctx = Context::new();
3103        let start = std::time::Instant::now();
3104        ctx.eval(
3105            r#"
3106import asyncio
3107
3108async def test():
3109    await asyncio.sleep(0.1)
3110    return "done"
3111
3112result = await test()
3113"#,
3114        )
3115        .unwrap();
3116        let elapsed = start.elapsed();
3117        let result = ctx.eval("result").unwrap();
3118        assert_eq!(result, Value::String("done".to_string()));
3119        // Verify it actually slept (at least 100ms)
3120        assert!(elapsed.as_millis() >= 100);
3121    }
3122
3123    #[test]
3124    fn test_asyncio_sleep_with_int() {
3125        let mut ctx = Context::new();
3126        let start = std::time::Instant::now();
3127        ctx.eval(
3128            r#"
3129import asyncio
3130await asyncio.sleep(0)
3131"#,
3132        )
3133        .unwrap();
3134        let elapsed = start.elapsed();
3135        // Should complete quickly (runtime creation has overhead)
3136        assert!(elapsed.as_millis() < 100);
3137    }
3138
3139    #[test]
3140    fn test_asyncio_sleep_with_float() {
3141        let mut ctx = Context::new();
3142        let start = std::time::Instant::now();
3143        ctx.eval(
3144            r#"
3145import asyncio
3146await asyncio.sleep(0.05)
3147"#,
3148        )
3149        .unwrap();
3150        let elapsed = start.elapsed();
3151        // Should sleep at least 50ms
3152        assert!(elapsed.as_millis() >= 50);
3153    }
3154
3155    #[test]
3156    fn test_asyncio_sleep_negative_error() {
3157        let mut ctx = Context::new();
3158        let result = ctx.eval(
3159            r#"
3160import asyncio
3161await asyncio.sleep(-1)
3162"#,
3163        );
3164        assert!(result.is_err());
3165        let err = result.unwrap_err();
3166        assert!(err.contains("ValueError"));
3167        assert!(err.contains("non-negative"));
3168    }
3169
3170    #[test]
3171    fn test_asyncio_sleep_wrong_type_error() {
3172        let mut ctx = Context::new();
3173        let result = ctx.eval(
3174            r#"
3175import asyncio
3176await asyncio.sleep("hello")
3177"#,
3178        );
3179        assert!(result.is_err());
3180        let err = result.unwrap_err();
3181        assert!(err.contains("TypeError"));
3182        assert!(err.contains("must be a number"));
3183    }
3184
3185    #[test]
3186    fn test_asyncio_sleep_in_async_function() {
3187        let mut ctx = Context::new();
3188        let start = std::time::Instant::now();
3189        ctx.eval(
3190            r#"
3191import asyncio
3192
3193async def delayed_add(x, y):
3194    await asyncio.sleep(0.1)
3195    return x + y
3196
3197result = await delayed_add(3, 4)
3198"#,
3199        )
3200        .unwrap();
3201        let elapsed = start.elapsed();
3202        let result = ctx.eval("result").unwrap();
3203        assert_eq!(result, Value::Int(7));
3204        assert!(elapsed.as_millis() >= 100);
3205    }
3206
3207    #[test]
3208    fn test_asyncio_sleep_multiple_awaits() {
3209        let mut ctx = Context::new();
3210        let start = std::time::Instant::now();
3211        ctx.eval(
3212            r#"
3213import asyncio
3214
3215async def multi_sleep():
3216    await asyncio.sleep(0.05)
3217    await asyncio.sleep(0.05)
3218    return "done"
3219
3220result = await multi_sleep()
3221"#,
3222        )
3223        .unwrap();
3224        let elapsed = start.elapsed();
3225        let result = ctx.eval("result").unwrap();
3226        assert_eq!(result, Value::String("done".to_string()));
3227        // Should sleep at least 100ms total
3228        assert!(elapsed.as_millis() >= 100);
3229    }
3230}