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}
53
54impl 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    pub fn new_var(name: Name, domain: Domain) -> Declaration {
63        let id = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
64        Declaration {
65            name,
66            kind: DeclarationKind::DecisionVariable(DecisionVariable::new(domain)),
67            id,
68        }
69    }
70
71    /// Creates a new domain letting declaration.
72    pub fn new_domain_letting(name: Name, domain: Domain) -> Declaration {
73        let id = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
74        Declaration {
75            name,
76            kind: DeclarationKind::DomainLetting(domain),
77            id,
78        }
79    }
80
81    /// Creates a new value letting declaration.
82    pub fn new_value_letting(name: Name, value: Expression) -> Declaration {
83        let id = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
84        Declaration {
85            name,
86            kind: DeclarationKind::ValueLetting(value),
87            id,
88        }
89    }
90
91    /// The name of this declaration.
92    pub fn name(&self) -> &Name {
93        &self.name
94    }
95
96    /// The kind of this declaration.
97    pub fn kind(&self) -> &DeclarationKind {
98        &self.kind
99    }
100
101    /// The domain of this declaration, if it is known.
102    pub fn domain(&self) -> Option<&Domain> {
103        match self.kind() {
104            DeclarationKind::DecisionVariable(var) => Some(&var.domain),
105            // TODO: this needs a symbol table :(
106            DeclarationKind::ValueLetting(_) => None,
107            DeclarationKind::DomainLetting(domain) => Some(domain),
108        }
109    }
110
111    /// This declaration as a decision variable, if it is one.
112    pub fn as_var(&self) -> Option<&DecisionVariable> {
113        if let DeclarationKind::DecisionVariable(var) = self.kind() {
114            Some(var)
115        } else {
116            None
117        }
118    }
119
120    /// This declaration as a mutable decision variable, if it is one.
121    pub fn as_var_mut(&mut self) -> Option<&mut DecisionVariable> {
122        if let DeclarationKind::DecisionVariable(var) = &mut self.kind {
123            Some(var)
124        } else {
125            None
126        }
127    }
128
129    /// This declaration as a domain letting, if it is one.
130    pub fn as_domain_letting(&self) -> Option<&Domain> {
131        if let DeclarationKind::DomainLetting(domain) = self.kind() {
132            Some(domain)
133        } else {
134            None
135        }
136    }
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    pub fn as_value_letting(&self) -> Option<&Expression> {
149        if let DeclarationKind::ValueLetting(expr) = &self.kind {
150            Some(expr)
151        } else {
152            None
153        }
154    }
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
166impl HasId for Declaration {
167    fn id(&self) -> ObjId {
168        self.id
169    }
170}
171
172impl 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
182impl Clone for Declaration {
183    fn clone(&self) -> Self {
184        Self {
185            name: self.name.clone(),
186            kind: self.kind.clone(),
187            id: ID_COUNTER.fetch_add(1, Ordering::Relaxed),
188        }
189    }
190}
191
192impl 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}