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
use std::mem;

use self::{
    action::{
        InsertBasicBlock, InsertStatement, IsAction, RemoveBasicBlock, RemoveStatement, RenameLocal,
    },
    analyzer::{BindedAnalyzer, IsAnalyzer},
};
use crate::ir::function::basic_block::BasicBlock;

use super::{
    function::{formalize, FunctionDefinitionIndex},
    quantity::Quantity,
    statement::IRStatement,
    RegisterName,
};

mod action;
/// Analyzers for providing information of an ir function.
pub mod analyzer;
pub use analyzer::Analyzer;
pub struct Editor {
    // todo: remove this pub
    pub content: super::FunctionDefinition,
    pub analyzer: analyzer::Analyzer,
}

impl Editor {
    pub fn new(content: super::FunctionDefinition) -> Self {
        Self {
            content: formalize(content),
            analyzer: analyzer::Analyzer::new(),
        }
    }

    pub fn insert_statement(
        &mut self,
        index: impl Into<FunctionDefinitionIndex>,
        statement: impl Into<IRStatement>,
    ) {
        self.perform_action(InsertStatement::at_index(index, statement));
    }

    pub fn push_front_statement(&mut self, index: usize, statement: impl Into<IRStatement>) {
        self.perform_action(InsertStatement::front_of(index, statement));
    }

    pub fn push_back_statement(&mut self, index: usize, statement: impl Into<IRStatement>) {
        self.perform_action(InsertStatement::back_of(index, statement));
    }

    pub fn remove_statement(&mut self, index: impl Into<FunctionDefinitionIndex>) {
        self.perform_action(RemoveStatement::new(index));
    }

    pub fn remove_statements<T: Into<FunctionDefinitionIndex> + Ord>(
        &mut self,
        indexes: impl IntoIterator<Item = T>,
    ) {
        let mut indexes = indexes.into_iter().collect::<Vec<_>>();
        indexes.sort();
        while let Some(index) = indexes.pop() {
            self.remove_statement(index);
        }
    }

    pub fn rename_local(&mut self, from: RegisterName, to: impl Into<Quantity>) {
        self.perform_action(RenameLocal::new(from, to));
    }

    fn perform_action(&mut self, action: impl Into<action::Action>) {
        let action = action.into();
        self.analyzer.on_action(&action);
        action.perform_on_function(&mut self.content);
    }

    pub fn binded_analyzer(&self) -> BindedAnalyzer {
        self.analyzer.bind(&self.content)
    }

    pub fn insert_basic_block(&mut self, name: String, index: impl Into<usize>) {
        self.perform_action(InsertBasicBlock::at_index(index, name));
    }

    pub fn create_basic_block(&mut self, name: String) -> usize {
        self.perform_action(InsertBasicBlock::back_of(name));
        self.content.content.len() - 1
    }

    pub fn remove_basic_block(&mut self, index: impl Into<usize>) -> BasicBlock {
        let index = index.into();
        let origin_content = mem::take(&mut self.content.content[index]);
        self.perform_action(RemoveBasicBlock::new(index));
        origin_content
    }

    pub fn replace_basic_block(
        &mut self,
        index: impl Into<usize>,
        block: BasicBlock,
    ) -> BasicBlock {
        let index = index.into();
        let removed_origin = self.remove_basic_block(index);
        self.perform_action(
            InsertBasicBlock::at_index(index, block.name.unwrap()).set_content(block.content),
        );
        removed_origin
    }
    pub fn swap_basic_block(&mut self, index0: impl Into<usize>, index1: impl Into<usize>) {
        let index0 = index0.into();
        let index1 = index1.into();
        if index1 < index0 {
            self.swap_basic_block(index1, index0)
        } else {
            let block0 = self.remove_basic_block(index0);
            let block1 = self.remove_basic_block(index1 - 1);
            self.perform_action(
                InsertBasicBlock::at_index(index0, block1.name.unwrap())
                    .set_content(block1.content),
            );
            self.perform_action(
                InsertBasicBlock::at_index(index1, block0.name.unwrap())
                    .set_content(block0.content),
            );
        }
    }

    pub fn direct_edit(&mut self, f: impl FnOnce(&mut super::FunctionDefinition)) {
        f(&mut self.content);
        self.analyzer.clear_all_cache();
    }
}