1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use super::IRGeneratingContext;
use crate::{
    ast::{self, expression::VariableRef},
    ir::function::statement::Alloca,
};

/// Generate IR from an [`ast::statement::Declare`] AST node.
pub fn from_ast(ast: &ast::statement::declare::Declare, ctx: &mut IRGeneratingContext) {
    let ast::statement::Declare {
        variable_name,
        data_type,
        init_value,
    } = ast;
    let variable_ref = VariableRef(variable_name.clone());
    let address_register = ctx
        .symbol_table
        .create_register_for(&variable_ref, data_type);
    ctx.current_basic_block.append_statement(Alloca {
        to: address_register,
        alloc_type: data_type.clone(),
    });
    if let Some(init_value) = init_value {
        // create a dummy assign node
        let assign_statement = ast::statement::Assign {
            lhs: ast::expression::lvalue::LValue::VariableRef(variable_ref),
            rhs: init_value.clone(),
        };
        // and generate its ast
        super::assign::from_ast(&assign_statement, ctx);
    }
}

#[cfg(test)]
mod tests {
    #![allow(clippy::borrow_interior_mutable_const)]
    use super::*;
    use crate::{
        ast::expression::IntegerLiteral,
        ir::{statement, RegisterName},
        utility::data_type,
    };

    #[test]
    fn test_from_ast() {
        let mut parent_ctx = crate::ir::IRGeneratingContext::new();
        let mut ctx = IRGeneratingContext::new(&mut parent_ctx);
        let ast = ast::statement::Declare {
            variable_name: "a".to_string(),
            data_type: data_type::I32.clone(),
            init_value: Some(IntegerLiteral(42).into()),
        };
        from_ast(&ast, &mut ctx);
        assert_eq!(ctx.current_basic_block.content.len(), 2);
        assert_eq!(
            ctx.current_basic_block.content[0],
            Alloca {
                to: RegisterName("a_0_addr".to_string()),
                alloc_type: data_type::I32.clone(),
            }
            .into()
        );
        assert_eq!(
            ctx.current_basic_block.content[1],
            statement::Store {
                source: 42.into(),
                target: RegisterName("a_0_addr".to_string()).into(),
                data_type: data_type::I32.clone(),
            }
            .into()
        );
    }
}