fortrangoingonforty/firp / 8fdc984

Browse files

Expand test coverage for derived types, modules, and VM

Test additions:
- Derived type tests: enhanced type component and nested type tests
- Module tests: USE statement, module procedures, visibility
- VM tests: additional runtime behavior verification
- Minor fixes to existing test assertions
Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
8fdc984bf1e73403edb07ab50d44d7428f4a76c5
Parents
7afe19c
Tree
edad6bd

5 changed files

StatusFile+-
M tests/advanced_features_tests.rs 1 1
M tests/derived_type_tests.rs 48 0
M tests/module_tests.rs 133 0
M tests/semantic_tests.rs 3 1
M tests/vm_tests.rs 59 0
tests/advanced_features_tests.rsmodified
@@ -32,7 +32,7 @@ fn compile_and_run_with_semantic(source: &str) -> Result<VM, String> {
3232
 
3333
     // Run semantic analysis
3434
     let mut analyzer = SemanticAnalyzer::new();
35
-    let errors = analyzer.analyze(&program);
35
+    let (errors, _warnings) = analyzer.analyze(&program);
3636
     if !errors.is_empty() {
3737
         return Err(format!("Semantic error: {}", errors[0]));
3838
     }
tests/derived_type_tests.rsmodified
@@ -746,6 +746,54 @@ fn test_execute_generic_interface() {
746746
     assert!(output.contains("30"), "Output should contain 30: {}", output);
747747
 }
748748
 
749
+#[test]
750
+fn test_generic_interface_type_resolution() {
751
+    // Test that the correct procedure is selected based on argument types
752
+    let source = r#"
753
+        PROGRAM test_generic_types
754
+          IMPLICIT NONE
755
+
756
+          INTERFACE compute
757
+            MODULE PROCEDURE compute_int, compute_real
758
+          END INTERFACE compute
759
+
760
+          INTEGER :: i, iresult
761
+          REAL :: r, rresult
762
+
763
+          i = 5
764
+          r = 3.5
765
+
766
+          ! Call with INTEGER - should select compute_int
767
+          iresult = compute(i)
768
+          PRINT *, iresult
769
+
770
+          ! Call with REAL - should select compute_real
771
+          rresult = compute(r)
772
+          PRINT *, rresult
773
+
774
+        CONTAINS
775
+
776
+          FUNCTION compute_int(x) RESULT(y)
777
+            INTEGER :: x, y
778
+            y = x * 2
779
+          END FUNCTION compute_int
780
+
781
+          FUNCTION compute_real(x) RESULT(y)
782
+            REAL :: x, y
783
+            y = x * 3.0
784
+          END FUNCTION compute_real
785
+
786
+        END PROGRAM test_generic_types
787
+    "#;
788
+
789
+    let vm = compile_and_run(source).expect("Should run successfully");
790
+    let output = get_output(&vm);
791
+    // compute_int(5) = 5 * 2 = 10
792
+    assert!(output.contains("10"), "Output should contain 10 for integer computation: {}", output);
793
+    // compute_real(3.5) = 3.5 * 3.0 = 10.5
794
+    assert!(output.contains("10.5"), "Output should contain 10.5 for real computation: {}", output);
795
+}
796
+
749797
 // ========== POINTER TESTS (Sprint 14) ==========
750798
 
751799
 #[test]
tests/module_tests.rsmodified
@@ -482,3 +482,136 @@ fn test_program_use_statement_parsing() {
482482
     assert_eq!(program.uses[1].module_name, "ANOTHER_MODULE");
483483
     assert!(program.uses[1].only.is_some());
484484
 }
485
+
486
+#[test]
487
+fn test_use_only_rejects_private_symbols() {
488
+    // Attempting to import a PRIVATE symbol via USE...ONLY should fail
489
+    let source = r#"
490
+        MODULE my_module
491
+          PRIVATE
492
+          INTEGER :: secret_var = 42
493
+          PUBLIC :: public_var
494
+          INTEGER :: public_var = 100
495
+        END MODULE my_module
496
+
497
+        PROGRAM test_private
498
+          USE my_module, ONLY: secret_var
499
+          IMPLICIT NONE
500
+          PRINT *, secret_var
501
+        END PROGRAM
502
+    "#;
503
+
504
+    let mut lexer = Lexer::new(source);
505
+    let tokens = lexer.tokenize().expect("Should tokenize");
506
+    let mut parser = Parser::new(tokens);
507
+    let unit = parser.parse_compilation_unit().expect("Should parse");
508
+
509
+    let mut compiler = Compiler::new();
510
+    let result = compiler.compile_unit(&unit);
511
+
512
+    // Should fail because secret_var is PRIVATE
513
+    assert!(result.is_err(), "Should reject importing PRIVATE symbol");
514
+    let err_msg = format!("{:?}", result.unwrap_err());
515
+    assert!(
516
+        err_msg.contains("PRIVATE") || err_msg.contains("secret_var"),
517
+        "Error should mention PRIVATE visibility, got: {}", err_msg
518
+    );
519
+}
520
+
521
+#[test]
522
+fn test_use_only_allows_public_symbols() {
523
+    // Importing a PUBLIC symbol via USE...ONLY should succeed
524
+    let source = r#"
525
+        MODULE my_module
526
+          PRIVATE
527
+          INTEGER :: secret_var = 42
528
+          PUBLIC :: public_var
529
+          INTEGER :: public_var = 100
530
+        END MODULE my_module
531
+
532
+        PROGRAM test_public
533
+          USE my_module, ONLY: public_var
534
+          IMPLICIT NONE
535
+          PRINT *, public_var
536
+        END PROGRAM
537
+    "#;
538
+
539
+    let vm = compile_and_run_unit(source).expect("Should compile and run");
540
+    let output = vm.output().join("\n");
541
+    assert!(output.contains("100"), "Expected public_var value 100, got: {}", output);
542
+}
543
+
544
+#[test]
545
+fn test_parse_type_with_component_visibility() {
546
+    // Test that component visibility attributes are parsed correctly
547
+    let source = r#"
548
+        MODULE mymod
549
+          IMPLICIT NONE
550
+          TYPE :: MyType
551
+            INTEGER, PUBLIC :: x
552
+            INTEGER, PRIVATE :: y
553
+            REAL :: z
554
+          END TYPE MyType
555
+        END MODULE mymod
556
+    "#;
557
+
558
+    let module = parse_module(source).expect("Should parse successfully");
559
+    assert_eq!(module.name, "MYMOD");
560
+
561
+    // Find the type definition in the declarations
562
+    let type_decl = module.declarations.iter().find(|d| {
563
+        matches!(d, Declaration::DerivedType(t) if t.name == "MYTYPE")
564
+    });
565
+    assert!(type_decl.is_some(), "Should have a DerivedType declaration");
566
+
567
+    if let Some(Declaration::DerivedType(type_def)) = type_decl {
568
+        assert_eq!(type_def.components.len(), 3);
569
+
570
+        // Check component x has PUBLIC visibility
571
+        let comp_x = type_def.components.iter().find(|c| c.name == "X");
572
+        assert!(comp_x.is_some());
573
+        assert_eq!(comp_x.unwrap().visibility, Some(Visibility::Public));
574
+
575
+        // Check component y has PRIVATE visibility
576
+        let comp_y = type_def.components.iter().find(|c| c.name == "Y");
577
+        assert!(comp_y.is_some());
578
+        assert_eq!(comp_y.unwrap().visibility, Some(Visibility::Private));
579
+
580
+        // Check component z has no explicit visibility (None)
581
+        let comp_z = type_def.components.iter().find(|c| c.name == "Z");
582
+        assert!(comp_z.is_some());
583
+        assert_eq!(comp_z.unwrap().visibility, None);
584
+    }
585
+}
586
+
587
+#[test]
588
+fn test_type_component_visibility_in_runtime() {
589
+    // Test that component visibility is tracked in the runtime type definition
590
+    let source = r#"
591
+        MODULE test_mod
592
+          IMPLICIT NONE
593
+          TYPE :: Point
594
+            REAL, PUBLIC :: x
595
+            REAL, PRIVATE :: internal_val
596
+          END TYPE Point
597
+        CONTAINS
598
+          FUNCTION create_point() RESULT(p)
599
+            TYPE(Point) :: p
600
+            p%x = 10.0
601
+            p%internal_val = 5.0
602
+          END FUNCTION
603
+        END MODULE test_mod
604
+
605
+        PROGRAM test_visibility
606
+          USE test_mod
607
+          IMPLICIT NONE
608
+          TYPE(Point) :: pt
609
+          pt = create_point()
610
+          PRINT *, pt%x
611
+        END PROGRAM
612
+    "#;
613
+
614
+    let vm = compile_and_run_unit(source).expect("Should compile and run");
615
+    let output = vm.output().join("\n");
616
+    assert!(output.contains("10"), "Expected pt%x = 10, got: {}", output);
617
+}
tests/semantic_tests.rsmodified
@@ -9,16 +9,18 @@ fn analyze_program(source: &str) -> Result<(), Vec<SemanticError>> {
99
     let tokens = lexer.tokenize().map_err(|e| vec![SemanticError::UndeclaredVariable {
1010
         name: format!("Lexer error: {}", e),
1111
         location: firp::lexer::SourceLocation { line: 0, column: 0 },
12
+        suggestions: None,
1213
     }])?;
1314
 
1415
     let mut parser = Parser::new(tokens);
1516
     let program = parser.parse_program().map_err(|e| vec![SemanticError::UndeclaredVariable {
1617
         name: format!("Parser error: {}", e),
1718
         location: firp::lexer::SourceLocation { line: 0, column: 0 },
19
+        suggestions: None,
1820
     }])?;
1921
 
2022
     let mut analyzer = SemanticAnalyzer::new();
21
-    let errors = analyzer.analyze(&program);
23
+    let (errors, _warnings) = analyzer.analyze(&program);
2224
 
2325
     if errors.is_empty() {
2426
         Ok(())
tests/vm_tests.rsmodified
@@ -1655,3 +1655,62 @@ fn test_sprint15_success_criteria() {
16551655
     assert_eq!(vm.get_variable("IMG"), Some(&firp::bytecode::Value::Integer(1)));
16561656
     assert_eq!(vm.get_variable("NUM"), Some(&firp::bytecode::Value::Integer(1)));
16571657
 }
1658
+
1659
+fn compile_and_run_parallel(source: &str) -> Result<VM, String> {
1660
+    let mut lexer = Lexer::new(source);
1661
+    let tokens = lexer.tokenize().map_err(|e| format!("Lexer error: {}", e))?;
1662
+
1663
+    let mut parser = Parser::new(tokens);
1664
+    let program = parser.parse_program().map_err(|e| format!("Parser error: {}", e))?;
1665
+
1666
+    let mut compiler = Compiler::new();
1667
+    let chunk = compiler.compile(&program).map_err(|e| format!("Compile error: {}", e))?;
1668
+
1669
+    let mut vm = VM::new();
1670
+    vm.set_parallel_mode(true);  // Enable parallel execution
1671
+    vm.run(chunk).map_err(|e| format!("Runtime error: {}", e))?;
1672
+
1673
+    Ok(vm)
1674
+}
1675
+
1676
+#[test]
1677
+fn test_do_concurrent_parallel_mode() {
1678
+    // Test DO CONCURRENT with parallel mode enabled
1679
+    let source = r#"
1680
+        program test_parallel
1681
+          implicit none
1682
+          integer :: arr(10)
1683
+          integer :: i
1684
+          do concurrent (i = 1:10)
1685
+            arr(i) = i * 2
1686
+          end do
1687
+          print *, arr(5)
1688
+        end program test_parallel
1689
+    "#;
1690
+
1691
+    let vm = compile_and_run_parallel(source).expect("Should run successfully with parallel mode");
1692
+    let output = vm.output().join("\n");
1693
+    // arr(5) = 5 * 2 = 10
1694
+    assert!(output.contains("10"), "Expected arr(5) = 10, got: {}", output);
1695
+}
1696
+
1697
+#[test]
1698
+fn test_do_concurrent_parallel_output_order() {
1699
+    // Test that output is collected in correct order even with parallel execution
1700
+    let source = r#"
1701
+        program test_parallel_output
1702
+          implicit none
1703
+          integer :: i
1704
+          do concurrent (i = 1:5)
1705
+            print *, i
1706
+          end do
1707
+        end program test_parallel_output
1708
+    "#;
1709
+
1710
+    let vm = compile_and_run_parallel(source).expect("Should run successfully");
1711
+    let output = vm.output();
1712
+    // In parallel mode, output should still be in order
1713
+    assert_eq!(output.len(), 5, "Expected 5 lines of output");
1714
+    assert!(output[0].contains("1"), "Expected first line to contain 1");
1715
+    assert!(output[4].contains("5"), "Expected last line to contain 5");
1716
+}