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
use std::{
    cmp::Ordering,
    collections::VecDeque,
    ops::{Deref, DerefMut},
};

use crate::{
    block_id::BlockId,
    item_id::ItemId,
    llir_nodes::{Condition, Node},
    minecraft_utils::ScoreboardValue,
};

use super::NodeId;

/// Optimizing functions output commands that tell the optimizer what to do,
/// this is done so that there are no troubles with mutability
#[derive(Debug)]
pub enum OptimizeCommandKind {
    /// Deletes a single node
    Delete,
    /// Converts the [FastStoreFromResult](crate::llir_nodes::FastStoreFromResult) node into its command, discarding
    /// the result
    DiscardResult,
    /// Discards the node and only keeps the branch that matches the bool.
    /// (true => pos_branch, false => neg_branch)
    InlineBranch(bool),
    /// Updates the specified branch with the new node
    UpdateBranch { branch: bool, new_node: Node },
    /// Updates the condition of a branch
    UpdateBranchCondition(Condition),
    /// Inlines the function of this function call.
    InlineFunction,
    /// Removes all aliases to a function which only redirects to another function
    /// The argument specifies the aliased function.
    RemoveAliasFunction(BlockId),
    /// Changes the variable this node writes to
    ChangeWrite(ItemId),
    /// Replaces all variables `.0` with `.1`
    ChangeReads(ItemId, ScoreboardValue),
    /// Changes the condition of this branch to a new condition
    /// Vec usize contains the exact index of the condition to replace
    /// (Vec since conditions can be nested)
    SetCondition(Condition, Vec<usize>),
    /// Replaces the old node completely
    Replace(Node),
    /// Inserts this node after
    InsertAfter(Node),
    /// Modifies a [`Node::Execute`]
    /// IMPORTANT: Right now the indices don't get normalized after a component is deleted
    /// This means that this command should not get used anywhere else other than in the one branch in redundancy_optimizer
    UpdateExecuteRaw(usize, ExecuteRawUpdate),
}

#[derive(Debug)]
pub enum ExecuteRawUpdate {
    Delete,
    Replace(Node),
}

#[derive(Debug)]
pub struct OptimizeCommand {
    pub id: NodeId,
    pub kind: OptimizeCommandKind,
}

impl OptimizeCommand {
    pub fn new(id: NodeId, kind: OptimizeCommandKind) -> Self {
        OptimizeCommand { id, kind }
    }

    /// Shifts the node id of this command one back
    #[allow(clippy::cast_sign_loss)]
    pub fn shift(&mut self, amt: i8) {
        match amt.cmp(&0) {
            Ordering::Greater => self.id.1 += amt as usize,
            Ordering::Less => self.id.1 -= amt.unsigned_abs() as usize,
            Ordering::Equal => {}
        }
    }

    pub fn shift_back(&mut self) {
        self.shift(-1);
    }
    pub fn shift_forward(&mut self) {
        self.shift(1);
    }
}

/// Just a wrapper around deque with a simple push method
#[derive(Debug)]
pub struct OptimizeCommandDeque<T>(VecDeque<T>);

impl<T> OptimizeCommandDeque<T> {
    pub fn push(&mut self, value: T) {
        self.0.push_back(value);
    }
}

impl<T> Deref for OptimizeCommandDeque<T> {
    type Target = VecDeque<T>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T> DerefMut for OptimizeCommandDeque<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl<T> Default for OptimizeCommandDeque<T> {
    fn default() -> Self {
        OptimizeCommandDeque(VecDeque::default())
    }
}