semantic-analyzer 0.4.6

Semantic analyzer library for compilers written in Rust for semantic analysis of programming languages AST
Documentation
use crate::utils::SemanticTest;
use semantic_analyzer::ast::{self, CodeLocation, GetLocation, Ident};
use semantic_analyzer::types::error::StateErrorKind;
use semantic_analyzer::types::semantic::SemanticStackContext;

mod utils;

#[test]
fn function_transform_ast() {
    let fn_name = ast::FunctionName::new(Ident::new("fn1"));
    assert_eq!(fn_name.location(), CodeLocation::new(1, 0));
    assert_eq!(fn_name.to_string(), "fn1");
}

#[test]
fn function_declaration_without_body() {
    let mut t = SemanticTest::new();
    let fn_name = ast::FunctionName::new(Ident::new("fn1"));
    let fn_statement = ast::FunctionStatement::new(
        fn_name.clone(),
        vec![],
        ast::Type::Primitive(ast::PrimitiveTypes::I8),
        vec![],
    );
    t.state.function_declaration(&fn_statement);
    assert!(t.is_empty_error());
    assert!(t.state.global.functions.contains_key(&fn_name.into()));
    let state = t.state.global.context.clone().get();
    assert_eq!(state.len(), 1);
    assert_eq!(
        state[0],
        SemanticStackContext::FunctionDeclaration {
            fn_decl: fn_statement.clone().into()
        }
    );

    t.state.function_declaration(&fn_statement);
    assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len());
    assert!(
        t.check_error(StateErrorKind::FunctionAlreadyExist),
        "Errors: {:?}",
        t.state.errors[0]
    );
}

#[test]
fn function_declaration_wrong_type() {
    let mut t = SemanticTest::new();
    let fn_name = ast::FunctionName::new(Ident::new("fn2"));

    let type_decl = ast::StructTypes {
        name: Ident::new("type1"),
        attributes: vec![],
    };

    let fn_statement = ast::FunctionStatement::new(
        fn_name.clone(),
        vec![ast::FunctionParameter {
            name: ast::ParameterName::new(Ident::new("x")),
            parameter_type: ast::Type::Primitive(ast::PrimitiveTypes::I64),
        }],
        ast::Type::Struct(type_decl.clone()),
        vec![],
    );
    t.state.function_declaration(&fn_statement);
    assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len());
    assert!(
        t.check_error(StateErrorKind::TypeNotFound),
        "Errors: {:?}",
        t.state.errors[0]
    );

    assert!(!t
        .state
        .global
        .functions
        .contains_key(&fn_name.clone().into()));
    let state = t.state.global.context.clone().get();
    assert_eq!(state.len(), 0);

    let fn_statement2 = ast::FunctionStatement::new(
        fn_statement.name,
        vec![ast::FunctionParameter {
            name: ast::ParameterName::new(Ident::new("x")),
            parameter_type: ast::Type::Struct(type_decl.clone()),
        }],
        ast::Type::Primitive(ast::PrimitiveTypes::I64),
        fn_statement.body,
    );
    t.state.function_declaration(&fn_statement2);
    assert!(t.check_errors_len(2), "Errors: {:?}", t.state.errors.len());
    assert!(t.check_error_index(1, StateErrorKind::TypeNotFound));
    t.clean_errors();

    t.state.types(&type_decl);
    assert!(t.is_empty_error());
    t.state.function_declaration(&fn_statement2);
    assert!(t.is_empty_error());
    assert!(t.state.global.functions.contains_key(&fn_name.into()));
    let state = t.state.global.context.clone().get();
    assert_eq!(state.len(), 2);
    assert_eq!(
        state[1],
        SemanticStackContext::FunctionDeclaration {
            fn_decl: fn_statement2.into()
        }
    );
}