conjure_core/ast/
declaration.rs

1use std::sync::atomic::{AtomicU32, Ordering};
2
3use derivative::Derivative;
4use serde::{Deserialize, Serialize};
5use uniplate::derive::Uniplate;
6use uniplate::{Biplate, Tree};
7
8use super::name::Name;
9use super::serde::{DefaultWithId, HasId, ObjId};
10use super::types::Typeable;
11use super::{DecisionVariable, Domain, Expression, ReturnType};
12
13static 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])]
20pub 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...
37impl 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)]
48pub enum DeclarationKind {
49    DecisionVariable(DecisionVariable),
50    ValueLetting(Expression),
51    DomainLetting(Domain),
52    Given(Domain),
53}
54
55impl Declaration {
56    /// Creates a new declaration.
57    pub fn new(name: Name, kind: DeclarationKind) -> Declaration {
58        let id = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
59        Declaration { name, kind, id }
60    }
61
62    /// Creates a new decision variable declaration.
63    pub fn new_var(name: Name, domain: Domain) -> Declaration {
64        let id = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
65        Declaration {
66            name,
67            kind: DeclarationKind::DecisionVariable(DecisionVariable::new(domain)),
68            id,
69        }
70    }
71
72    /// Creates a new domain letting declaration.
73    pub fn new_domain_letting(name: Name, domain: Domain) -> Declaration {
74        let id = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
75        Declaration {
76            name,
77            kind: DeclarationKind::DomainLetting(domain),
78            id,
79        }
80    }
81
82    /// Creates a new value letting declaration.
83    pub fn new_value_letting(name: Name, value: Expression) -> Declaration {
84        let id = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
85        Declaration {
86            name,
87            kind: DeclarationKind::ValueLetting(value),
88            id,
89        }
90    }
91
92    /// Creates a new given declaration.
93    pub fn new_given(name: Name, domain: Domain) -> Declaration {
94        let id = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
95        Declaration {
96            name,
97            kind: DeclarationKind::Given(domain),
98            id,
99        }
100    }
101
102    /// The name of this declaration.
103    pub fn name(&self) -> &Name {
104        &self.name
105    }
106
107    /// The kind of this declaration.
108    pub fn kind(&self) -> &DeclarationKind {
109        &self.kind
110    }
111
112    /// The domain of this declaration, if it is known.
113    pub fn domain(&self) -> Option<&Domain> {
114        match self.kind() {
115            DeclarationKind::DecisionVariable(var) => Some(&var.domain),
116            DeclarationKind::ValueLetting(_) => None,
117            DeclarationKind::DomainLetting(domain) => Some(domain),
118            DeclarationKind::Given(domain) => Some(domain),
119        }
120    }
121
122    /// This declaration as a decision variable, if it is one.
123    pub fn as_var(&self) -> Option<&DecisionVariable> {
124        if let DeclarationKind::DecisionVariable(var) = self.kind() {
125            Some(var)
126        } else {
127            None
128        }
129    }
130
131    /// This declaration as a mutable decision variable, if it is one.
132    pub fn as_var_mut(&mut self) -> Option<&mut DecisionVariable> {
133        if let DeclarationKind::DecisionVariable(var) = &mut self.kind {
134            Some(var)
135        } else {
136            None
137        }
138    }
139
140    /// This declaration as a domain letting, if it is one.
141    pub fn as_domain_letting(&self) -> Option<&Domain> {
142        if let DeclarationKind::DomainLetting(domain) = self.kind() {
143            Some(domain)
144        } else {
145            None
146        }
147    }
148
149    /// This declaration as a mutable domain letting, if it is one.
150    pub fn as_domain_letting_mut(&mut self) -> Option<&mut Domain> {
151        if let DeclarationKind::DomainLetting(domain) = &mut self.kind {
152            Some(domain)
153        } else {
154            None
155        }
156    }
157
158    /// This declaration as a value letting, if it is one.
159    pub fn as_value_letting(&self) -> Option<&Expression> {
160        if let DeclarationKind::ValueLetting(expr) = &self.kind {
161            Some(expr)
162        } else {
163            None
164        }
165    }
166
167    /// This declaration as a mutable value letting, if it is one.
168    pub fn as_value_letting_mut(&mut self) -> Option<&mut Expression> {
169        if let DeclarationKind::ValueLetting(expr) = &mut self.kind {
170            Some(expr)
171        } else {
172            None
173        }
174    }
175
176    /// Returns a clone of this declaration with a new name.
177    pub fn with_new_name(mut self, name: Name) -> Declaration {
178        self.name = name;
179        self
180    }
181}
182
183impl HasId for Declaration {
184    fn id(&self) -> ObjId {
185        self.id
186    }
187}
188
189impl DefaultWithId for Declaration {
190    fn default_with_id(id: ObjId) -> Self {
191        Self {
192            name: Name::User("_UNKNOWN".into()),
193            kind: DeclarationKind::ValueLetting(false.into()),
194            id,
195        }
196    }
197}
198
199impl Clone for Declaration {
200    fn clone(&self) -> Self {
201        Self {
202            name: self.name.clone(),
203            kind: self.kind.clone(),
204            id: ID_COUNTER.fetch_add(1, Ordering::Relaxed),
205        }
206    }
207}
208
209impl Typeable for Declaration {
210    fn return_type(&self) -> Option<ReturnType> {
211        match self.kind() {
212            DeclarationKind::DecisionVariable(var) => var.return_type(),
213            DeclarationKind::ValueLetting(expression) => expression.return_type(),
214            DeclarationKind::DomainLetting(domain) => domain.return_type(),
215            DeclarationKind::Given(domain) => domain.return_type(),
216        }
217    }
218}