1
use std::sync::atomic::{AtomicU32, Ordering};
2

            
3
use derivative::Derivative;
4
use serde::{Deserialize, Serialize};
5
use uniplate::derive::Uniplate;
6
use uniplate::{Biplate, Tree};
7

            
8
use super::name::Name;
9
use super::serde::{DefaultWithId, HasId, ObjId};
10
use super::types::Typeable;
11
use super::{DecisionVariable, Domain, Expression, ReturnType};
12

            
13
static ID_COUNTER: AtomicU32 = AtomicU32::new(0);
14

            
15
#[derive(Derivative)]
16
#[derivative(PartialEq)]
17
#[derive(Debug, Serialize, Deserialize, Eq, Uniplate)]
18
#[biplate(to=Expression)]
19
#[uniplate(walk_into=[DeclarationKind])]
20
pub struct Declaration {
21
    /// The name of the declared symbol.
22
    name: Name,
23

            
24
    /// The kind of the declaration.
25
    kind: DeclarationKind,
26

            
27
    /// A unique id for this declaration.
28
    ///
29
    /// This is mainly used for serialisation and debugging.
30
    #[derivative(PartialEq = "ignore")] // eq by value not id.
31
    id: ObjId,
32
}
33

            
34
// I don't know why I need this one -- nd
35
//
36
// Without it, the derive macro for Declaration errors...
37
impl Biplate<Declaration> for DeclarationKind {
38
    fn biplate(&self) -> (Tree<Declaration>, Box<dyn Fn(Tree<Declaration>) -> Self>) {
39
        let self2 = self.clone();
40
        (Tree::Zero, Box::new(move |_| self2.clone()))
41
    }
42
}
43

            
44
/// A specific kind of declaration.
45
#[non_exhaustive]
46
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate)]
47
#[biplate(to=Expression)]
48
pub enum DeclarationKind {
49
    DecisionVariable(DecisionVariable),
50
    ValueLetting(Expression),
51
    DomainLetting(Domain),
52
}
53

            
54
impl Declaration {
55
    /// Creates a new declaration.
56
    pub fn new(name: Name, kind: DeclarationKind) -> Declaration {
57
        let id = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
58
        Declaration { name, kind, id }
59
    }
60

            
61
    /// Creates a new decision variable declaration.
62
7905
    pub fn new_var(name: Name, domain: Domain) -> Declaration {
63
7905
        let id = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
64
7905
        Declaration {
65
7905
            name,
66
7905
            kind: DeclarationKind::DecisionVariable(DecisionVariable::new(domain)),
67
7905
            id,
68
7905
        }
69
7905
    }
70

            
71
    /// Creates a new domain letting declaration.
72
90
    pub fn new_domain_letting(name: Name, domain: Domain) -> Declaration {
73
90
        let id = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
74
90
        Declaration {
75
90
            name,
76
90
            kind: DeclarationKind::DomainLetting(domain),
77
90
            id,
78
90
        }
79
90
    }
80

            
81
    /// Creates a new value letting declaration.
82
126
    pub fn new_value_letting(name: Name, value: Expression) -> Declaration {
83
126
        let id = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
84
126
        Declaration {
85
126
            name,
86
126
            kind: DeclarationKind::ValueLetting(value),
87
126
            id,
88
126
        }
89
126
    }
90

            
91
    /// The name of this declaration.
92
5192481
    pub fn name(&self) -> &Name {
93
5192481
        &self.name
94
5192481
    }
95

            
96
    /// The kind of this declaration.
97
5222597
    pub fn kind(&self) -> &DeclarationKind {
98
5222597
        &self.kind
99
5222597
    }
100

            
101
    /// The domain of this declaration, if it is known.
102
4631
    pub fn domain(&self) -> Option<&Domain> {
103
4631
        match self.kind() {
104
4505
            DeclarationKind::DecisionVariable(var) => Some(&var.domain),
105
            // TODO: this needs a symbol table :(
106
36
            DeclarationKind::ValueLetting(_) => None,
107
90
            DeclarationKind::DomainLetting(domain) => Some(domain),
108
        }
109
4631
    }
110

            
111
    /// This declaration as a decision variable, if it is one.
112
5206554
    pub fn as_var(&self) -> Option<&DecisionVariable> {
113
5206554
        if let DeclarationKind::DecisionVariable(var) = self.kind() {
114
5202126
            Some(var)
115
        } else {
116
4428
            None
117
        }
118
5206554
    }
119

            
120
    /// This declaration as a mutable decision variable, if it is one.
121
126
    pub fn as_var_mut(&mut self) -> Option<&mut DecisionVariable> {
122
126
        if let DeclarationKind::DecisionVariable(var) = &mut self.kind {
123
126
            Some(var)
124
        } else {
125
            None
126
        }
127
126
    }
128

            
129
    /// This declaration as a domain letting, if it is one.
130
468
    pub fn as_domain_letting(&self) -> Option<&Domain> {
131
468
        if let DeclarationKind::DomainLetting(domain) = self.kind() {
132
468
            Some(domain)
133
        } else {
134
            None
135
        }
136
468
    }
137

            
138
    /// This declaration as a mutable domain letting, if it is one.
139
    pub fn as_domain_letting_mut(&mut self) -> Option<&mut Domain> {
140
        if let DeclarationKind::DomainLetting(domain) = &mut self.kind {
141
            Some(domain)
142
        } else {
143
            None
144
        }
145
    }
146

            
147
    /// This declaration as a value letting, if it is one.
148
71172
    pub fn as_value_letting(&self) -> Option<&Expression> {
149
71172
        if let DeclarationKind::ValueLetting(expr) = &self.kind {
150
324
            Some(expr)
151
        } else {
152
70848
            None
153
        }
154
71172
    }
155

            
156
    /// This declaration as a mutable value letting, if it is one.
157
    pub fn as_value_letting_mut(&mut self) -> Option<&mut Expression> {
158
        if let DeclarationKind::ValueLetting(expr) = &mut self.kind {
159
            Some(expr)
160
        } else {
161
            None
162
        }
163
    }
164
}
165

            
166
impl HasId for Declaration {
167
    fn id(&self) -> ObjId {
168
        self.id
169
    }
170
}
171

            
172
impl DefaultWithId for Declaration {
173
    fn default_with_id(id: ObjId) -> Self {
174
        Self {
175
            name: Name::UserName("_UNKNOWN".into()),
176
            kind: DeclarationKind::ValueLetting(false.into()),
177
            id,
178
        }
179
    }
180
}
181

            
182
impl Clone for Declaration {
183
126
    fn clone(&self) -> Self {
184
126
        Self {
185
126
            name: self.name.clone(),
186
126
            kind: self.kind.clone(),
187
126
            id: ID_COUNTER.fetch_add(1, Ordering::Relaxed),
188
126
        }
189
126
    }
190
}
191

            
192
impl Typeable for Declaration {
193
    fn return_type(&self) -> Option<ReturnType> {
194
        match self.kind() {
195
            DeclarationKind::DecisionVariable(var) => var.return_type(),
196
            DeclarationKind::ValueLetting(expression) => expression.return_type(),
197
            DeclarationKind::DomainLetting(domain) => domain.return_type(),
198
        }
199
    }
200
}