carbon-parser 0.1.2

A parser for Google's Carbon programming language, supporting basic syntax including function, variable, and type declarations.
Documentation
use anyhow::Result;
use carbon_parser::{
    parse_carbon, parse_expression, parse_function_decl, parse_type_name, parse_var_decl,
};
mod function_decl_tests {
    use super::*;

    #[test]
    fn test_simple_function_without_params() -> Result<()> {
        let code = r#"fn test() -> i32 { return 42; }"#;
        let result = parse_function_decl(code);
        assert!(
            result.is_ok(),
            "A simple function without parameters should parse successfully"
        );
        Ok(())
    }

    #[test]
    fn test_function_with_single_param() -> Result<()> {
        let code = r#"fn square(x: i32) -> i32 { return x; }"#;
        let result = parse_function_decl(code);
        assert!(
            result.is_ok(),
            "A function with a single parameter should parse successfully"
        );
        Ok(())
    }

    #[test]
    fn test_function_with_multiple_params() -> Result<()> {
        let code = r#"fn add(x: i32, y: i32, z: i32) -> i32 { return x; }"#;
        let result = parse_function_decl(code);
        assert!(
            result.is_ok(),
            "A function with multiple parameters should parse successfully"
        );
        Ok(())
    }

    #[test]
    fn test_function_without_return_type() -> Result<()> {
        let code = r#"fn print_hello() { return 0; }"#;
        let result = parse_function_decl(code);
        assert!(
            result.is_ok(),
            "A function without a return type should parse successfully"
        );
        Ok(())
    }

    #[test]
    fn test_function_with_different_types() -> Result<()> {
        let code =
            r#"fn process(name: String, age: i32, active: bool) -> bool { return active; }"#;
        let result = parse_function_decl(code);
        assert!(
            result.is_ok(),
            "A function with different parameter types should parse successfully"
        );
        Ok(())
    }
}

mod var_decl_tests {
    use super::*;

    #[test]
    fn test_var_with_initialization() -> Result<()> {
        let code = "var x: i32 = 42;";
        let result = parse_var_decl(code);
        assert!(result.is_ok(), "A variable with initialization should parse successfully");
        Ok(())
    }

    #[test]
    fn test_var_without_initialization() -> Result<()> {
        let code = "var y: bool;";
        let result = parse_var_decl(code);
        assert!(
            result.is_ok(),
            "A variable without initialization should parse successfully"
        );
        Ok(())
    }

    #[test]
    fn test_var_with_string_type() -> Result<()> {
        let code = r#"var name: String = "John";"#;
        let result = parse_var_decl(code);
        assert!(
            result.is_ok(),
            "A variable of type String with initialization should parse successfully"
        );
        Ok(())
    }

    #[test]
    fn test_var_with_float() -> Result<()> {
        let code = "var pi: f64 = 3.14;";
        let result = parse_var_decl(code);
        assert!(
            result.is_ok(),
            "A variable with a float value should parse successfully"
        );
        Ok(())
    }

    #[test]
    fn test_var_with_expression() -> Result<()> {
        let code = "var sum: i32 = 10 + 20;";
        let result = parse_var_decl(code);
        assert!(result.is_ok(), "A variable with an expression should parse successfully");
        Ok(())
    }
}

mod expression_tests {
    use super::*;

    #[test]
    fn test_integer_literal() -> Result<()> {
        let code = "42";
        let result = parse_expression(code);
        assert!(result.is_ok(), "An integer literal should parse successfully");
        Ok(())
    }

    #[test]
    fn test_float_literal() -> Result<()> {
        let code = "3.14";
        let result = parse_expression(code);
        assert!(result.is_ok(), "A float literal should parse successfully");
        Ok(())
    }

    #[test]
    fn test_boolean_literal() -> Result<()> {
        assert!(parse_expression("true").is_ok());
        assert!(parse_expression("false").is_ok());
        Ok(())
    }

    #[test]
    fn test_string_literal() -> Result<()> {
        let code = r#""Hello, World!""#;
        let result = parse_expression(code);
        assert!(result.is_ok(), "A string literal should parse successfully");
        Ok(())
    }

    #[test]
    fn test_identifier() -> Result<()> {
        let code = "variable_name";
        let result = parse_expression(code);
        assert!(result.is_ok(), "An identifier should parse successfully");
        Ok(())
    }

    #[test]
    fn test_binary_addition() -> Result<()> {
        let code = "10 + 20";
        let result = parse_expression(code);
        assert!(result.is_ok(), "Binary addition should parse successfully");
        Ok(())
    }

    #[test]
    fn test_complex_binary_expression() -> Result<()> {
        let code = "10 + 20 * 30 - 5";
        let result = parse_expression(code);
        assert!(
            result.is_ok(),
            "A complex binary expression should parse successfully"
        );
        Ok(())
    }

    #[test]
    fn test_function_call() -> Result<()> {
        let code = "calculate(x, y)";
        let result = parse_expression(code);
        assert!(result.is_ok(), "A function call should parse successfully");
        Ok(())
    }

    #[test]
    fn test_comparison_operators() -> Result<()> {
        assert!(parse_expression("x == y").is_ok());
        assert!(parse_expression("x != y").is_ok());
        assert!(parse_expression("x < y").is_ok());
        assert!(parse_expression("x > y").is_ok());
        Ok(())
    }
}

mod type_name_tests {
    use super::*;

    #[test]
    fn test_integer_types() -> Result<()> {
        assert!(parse_type_name("i32").is_ok());
        assert!(parse_type_name("i64").is_ok());
        Ok(())
    }

    #[test]
    fn test_float_types() -> Result<()> {
        assert!(parse_type_name("f32").is_ok());
        assert!(parse_type_name("f64").is_ok());
        Ok(())
    }

    #[test]
    fn test_boolean_type() -> Result<()> {
        let result = parse_type_name("bool");
        assert!(result.is_ok(), "The type bool should parse successfully");
        Ok(())
    }

    #[test]
    fn test_string_type() -> Result<()> {
        let result = parse_type_name("String");
        assert!(result.is_ok(), "The type String should parse successfully");
        Ok(())
    }

    #[test]
    fn test_custom_type() -> Result<()> {
        let result = parse_type_name("CustomType");
        assert!(result.is_ok(), "A custom type should parse successfully");
        Ok(())
    }
}

mod program_tests {
    use super::*;

    #[test]
    fn test_empty_program() -> Result<()> {
        let code = "";
        let result = parse_carbon(code);
        assert!(result.is_ok(), "An empty program should parse successfully");
        Ok(())
    }

    #[test]
    fn test_single_function_program() -> Result<()> {
        let code = r#"
            fn main() -> i32 {
                return 0;
            }
        "#;
        let result = parse_carbon(code);
        assert!(
            result.is_ok(),
            "A program with a single function should parse successfully"
        );
        Ok(())
    }

    #[test]
    fn test_multiple_functions_program() -> Result<()> {
        let code = r#"
            fn add(x: i32, y: i32) -> i32 {
                return x;
            }
            
            fn main() -> i32 {
                return 0;
            }
        "#;
        let result = parse_carbon(code);
        assert!(
            result.is_ok(),
            "A program with multiple functions should parse successfully"
        );
        Ok(())
    }

    #[test]
    fn test_program_with_variables() -> Result<()> {
        let code = r#"
            var global_x: i32 = 100;
            
            fn main() -> i32 {
                var local_y: i32 = 200;
                return 0;
            }
        "#;
        let result = parse_carbon(code);
        assert!(result.is_ok(), "A program with variables should parse successfully");
        Ok(())
    }

    #[test]
    fn test_program_with_comments() -> Result<()> {
        let code = r#"
            // This is a comment
            fn main() -> i32 {
                /* Multi-line
                   comment */
                return 0;
            }
        "#;
        let result = parse_carbon(code);
        assert!(result.is_ok(), "A program with comments should parse successfully");
        Ok(())
    }

    #[test]
    fn test_complex_program() -> Result<()> {
        let code = r#"
            var counter: i32 = 0;
            
            fn increment(x: i32) -> i32 {
                return x;
            }
            
            fn main() -> i32 {
                var result: i32 = 42;
                return result;
            }
        "#;
        let result = parse_carbon(code);
        assert!(result.is_ok(), "A complex program should parse successfully");
        Ok(())
    }
}

mod error_tests {
    use super::*;

    #[test]
    fn test_invalid_syntax() {
        let code = "fn main( { }";
        let result = parse_carbon(code);
        assert!(
            result.is_err(),
            "Invalid syntax should produce an error"
        );
    }

    #[test]
    fn test_missing_semicolon() {
        let code = "var x: i32 = 42";
        let result = parse_var_decl(code);
        assert!(
            result.is_err(),
            "A missing semicolon should produce an error"
        );
    }

    #[test]
    fn test_invalid_identifier() {
        let code = "var 123invalid: i32 = 0;";
        let result = parse_var_decl(code);
        assert!(
            result.is_err(),
            "An invalid identifier should produce an error"
        );
    }
}