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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
use std::{
    collections::HashMap,
    fmt::{self, Debug},
};

use enum_dispatch::enum_dispatch;
use serde::{Deserialize, Serialize};

/// Data structure, parser and ir generator for functions.
pub mod function;
/// Data structure and parser for variables (global or local) and literals.
pub mod quantity;

mod global_definition;
mod integer_literal;
pub mod optimize;
mod type_definition;

use crate::{
    ast::{ASTNode, Ast},
    utility::data_type::{self, Integer},
};
pub use function::{statement, FunctionDefinition, FunctionHeader};
pub use global_definition::GlobalDefinition;
use nom::{
    branch::alt, character::complete::multispace0, combinator::map, multi::many0,
    sequence::delimited, IResult,
};
pub use quantity::RegisterName;
pub use type_definition::TypeDefinition;
use type_definition::TypeDefinitionMapping;

pub mod editor;
use self::function::parameter::Parameter;
pub use editor::analyzer;

/// The root nodes of IR.
#[enum_dispatch]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum IR {
    TypeDefinition,
    FunctionDefinition,
    GlobalDefinition,
}

impl IR {
    pub fn as_function_definition(&self) -> &FunctionDefinition {
        if let IR::FunctionDefinition(f) = self {
            f
        } else {
            panic!("This is not a function definition!")
        }
    }
}

impl fmt::Display for IR {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            IR::TypeDefinition(type_definition) => fmt::Display::fmt(&type_definition, f),
            IR::FunctionDefinition(function_definition) => {
                fmt::Display::fmt(&function_definition, f)
            }
            IR::GlobalDefinition(global_definition) => fmt::Display::fmt(&global_definition, f),
        }
    }
}

/// Parses the ir code to get an [`IR`].
pub fn parse(code: &str) -> IResult<&str, IR> {
    alt((
        map(type_definition::parse, IR::TypeDefinition),
        map(function::parse, IR::FunctionDefinition),
        map(global_definition::parse, IR::GlobalDefinition),
    ))(code)
}

/// Parses all the ir code to get a list of [`IR`].
pub fn from_ir_code(source: &str) -> IResult<&str, Vec<IR>> {
    many0(delimited(multispace0, parse, multispace0))(source)
}

/// Context for generating IR.
#[derive(Debug)]
pub struct IRGeneratingContext {
    /// Known function definitions.
    pub function_definitions: HashMap<String, FunctionHeader>,
    /// Known struct types.
    pub type_definitions: HashMap<String, TypeDefinitionMapping>,
    /// Known global variables.
    pub global_definitions: HashMap<String, GlobalDefinition>,
    /// Next local variable id.
    pub next_register_id: usize,
    /// Next `if` statement's id, used in generating label.
    pub next_if_id: usize,
    /// Next `while` statement's id, used in generating label.
    pub next_loop_id: usize,
}

impl IRGeneratingContext {
    /// Creates a new, empty [`IRGeneratingContext`].
    pub fn new() -> Self {
        let mut built_in_functions = HashMap::new();
        built_in_functions.insert(
            "load_u32".to_string(),
            FunctionHeader {
                name: "load_u32".to_string(),
                parameters: vec![Parameter {
                    name: RegisterName("address".to_string()),
                    data_type: data_type::Type::Address,
                }],
                return_type: Integer {
                    signed: false,
                    width: 32,
                }
                .into(),
            },
        );
        built_in_functions.insert(
            "store_u32".to_string(),
            FunctionHeader {
                name: "store_u32".to_string(),
                parameters: vec![
                    Parameter {
                        name: RegisterName("address".to_string()),
                        data_type: data_type::Type::Address,
                    },
                    Parameter {
                        name: RegisterName("value".to_string()),
                        data_type: Integer {
                            signed: false,
                            width: 32,
                        }
                        .into(),
                    },
                ],
                return_type: data_type::Type::None,
            },
        );
        Self {
            type_definitions: HashMap::new(),
            global_definitions: HashMap::new(),
            next_register_id: 0,
            next_if_id: 0,
            next_loop_id: 0,
            function_definitions: built_in_functions,
        }
    }

    /// Generate a new local variable name.
    pub fn next_register(&mut self) -> RegisterName {
        let register_id = self.next_register_id;
        self.next_register_id += 1;
        RegisterName(format!("{register_id}"))
    }
}

impl Default for IRGeneratingContext {
    fn default() -> Self {
        Self::new()
    }
}

/// Generate IR from AST.
pub fn from_ast(ast: &Ast) -> Vec<IR> {
    let mut context = IRGeneratingContext::new();
    ast.iter()
        .map(|node| match node {
            ASTNode::TypeDefinition(type_definition) => {
                IR::TypeDefinition(type_definition::from_ast(type_definition, &mut context))
            }
            ASTNode::GlobalVariableDefinition(global_variable_definition) => IR::GlobalDefinition(
                global_definition::from_ast(global_variable_definition, &mut context),
            ),
            ASTNode::FunctionDefinition(ast) => {
                IR::FunctionDefinition(function::from_ast(ast, &mut context))
            }
        })
        .collect()
}

#[cfg(test)]
mod tests {
    use super::*;
    // todo: more tests
    #[test]
    fn test_parse() {
        let code = r"fn main() -> () {
              %0 = add i32 1, 2
            }";
        assert!(parse(code).is_ok());
    }
}