1
use core::fmt;
2

            
3
use crate::aterm::ATerm;
4
use crate::aterm::ATermArgs;
5
use crate::aterm::ATermRef;
6
use crate::aterm::THREAD_TERM_POOL;
7
use mcrl2_macros::mcrl2_derive_terms;
8
use mcrl2_sys::data::ffi;
9

            
10
481232323
pub fn is_data_variable(term: &ATermRef<'_>) -> bool {
11
481232323
    term.require_valid();
12
481232323
    unsafe { ffi::is_data_variable(term.get()) }
13
481232323
}
14

            
15
469839133
pub fn is_data_expression(term: &ATermRef<'_>) -> bool {
16
469839133
    term.require_valid();
17
469839133
    is_data_variable(term)
18
469663117
        || is_data_function_symbol(term)
19
384760605
        || is_data_machine_number(term)
20
384760605
        || is_data_application(term)
21
267546
        || is_data_abstraction(term)
22
266454
        || is_data_where_clause(term)
23
469839133
}
24

            
25
5309951968
pub fn is_data_function_symbol(term: &ATermRef<'_>) -> bool {
26
5309951968
    term.require_valid();
27
5309951968
    unsafe { ffi::is_data_function_symbol(term.get()) }
28
5309951968
}
29

            
30
385295901
pub fn is_data_machine_number(term: &ATermRef<'_>) -> bool {
31
385295901
    term.require_valid();
32
385295901
    unsafe { ffi::is_data_machine_number(term.get()) }
33
385295901
}
34

            
35
3092682
pub fn is_data_where_clause(term: &ATermRef<'_>) -> bool {
36
3092682
    term.require_valid();
37
3092682
    unsafe { ffi::is_data_where_clause(term.get()) }
38
3092682
}
39

            
40
3094782
pub fn is_data_abstraction(term: &ATermRef<'_>) -> bool {
41
3094782
    term.require_valid();
42
3094782
    unsafe { ffi::is_data_abstraction(term.get()) }
43
3094782
}
44

            
45
2826228
pub fn is_data_untyped_identifier(term: &ATermRef<'_>) -> bool {
46
2826228
    term.require_valid();
47
2826228
    unsafe { ffi::is_data_untyped_identifier(term.get()) }
48
2826228
}
49

            
50
685791688
pub fn is_data_application(term: &ATermRef<'_>) -> bool {
51
685791688
    term.require_valid();
52
685791688

            
53
685791688
    THREAD_TERM_POOL.with_borrow_mut(|tp| tp.is_data_application(term))
54
685791688
}
55

            
56
// This module is only used internally to run the proc macro.
57
41875193973
#[mcrl2_derive_terms]
58
mod inner {
59
    use super::*;
60

            
61
    use std::borrow::Borrow;
62
    use std::ops::Deref;
63

            
64
    use crate::aterm::Markable;
65
    use crate::aterm::TermPool;
66
    use crate::aterm::Todo;
67
    use crate::data::SortExpression;
68
    use crate::data::SortExpressionRef;
69
    use mcrl2_macros::mcrl2_ignore;
70
    use mcrl2_macros::mcrl2_term;
71

            
72
    /// A data expression can be any of:
73
    ///     - a variable
74
    ///     - a function symbol, i.e. f without arguments.
75
    ///     - a term applied to a number of arguments, i.e., t_0(t1, ..., tn).
76
    ///     - an abstraction lambda x: Sort . e, or forall and exists.
77
    ///     - machine number, a value [0, ..., 2^64-1].
78
    ///
79
    /// Not supported:
80
    ///     - a where clause "e where [x := f, ...]"
81
    ///     - set enumeration
82
    ///     - bag enumeration
83
    ///
84
    #[mcrl2_term(is_data_expression)]
85
    pub struct DataExpression {
86
        term: ATerm,
87
    }
88

            
89
    impl DataExpression {
90
        /// Returns the head symbol a data expression
91
        ///     - function symbol                  f -> f
92
        ///     - application       f(t_0, ..., t_n) -> f
93
266169792
        pub fn data_function_symbol(&self) -> DataFunctionSymbolRef<'_> {
94
266169792
            if is_data_application(&self.term) {
95
218254506
                self.term.arg(0).upgrade(&self.term).into()
96
47915286
            } else if is_data_function_symbol(&self.term) {
97
47915286
                self.term.copy().into()
98
            } else {
99
                panic!("data_function_symbol not implemented for {}", self);
100
            }
101
266169792
        }
102

            
103
        /// Returns the arguments of a data expression
104
        ///     - function symbol                  f -> []
105
        ///     - application       f(t_0, ..., t_n) -> [t_0, ..., t_n]
106
31762140
        pub fn data_arguments(&self) -> ATermArgs<'_> {
107
31762140
            if is_data_application(&self.term) {
108
24564966
                let mut result = self.term.arguments();
109
24564966
                result.next();
110
24564966
                result
111
7197174
            } else if is_data_function_symbol(&self.term) {
112
7197174
                Default::default()
113
            } else {
114
                panic!("data_arguments not implemented for {}", self);
115
            }
116
31762140
        }
117

            
118
        /// Returns the arguments of a data expression
119
        ///     - function symbol                  f -> []
120
        ///     - application       f(t_0, ..., t_n) -> [t_0, ..., t_n]
121
        pub fn data_sort(&self) -> SortExpression {
122
            if is_data_function_symbol(&self.term) {
123
                DataFunctionSymbolRef::from(self.term.copy()).sort().protect()
124
            } else if is_data_variable(&self.term) {
125
                DataVariableRef::from(self.term.copy()).sort().protect()
126
            } else {
127
                panic!("data_sort not implemented for {}", self);
128
            }
129
        }
130
    }
131

            
132
    impl fmt::Display for DataExpression {
133
1
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134
1
            if is_data_function_symbol(&self.term) {
135
1
                write!(f, "{}", DataFunctionSymbolRef::from(self.term.copy()))
136
            } else if is_data_application(&self.term) {
137
                write!(f, "{}", DataApplicationRef::from(self.term.copy()))
138
            } else if is_data_variable(&self.term) {
139
                write!(f, "{}", DataVariableRef::from(self.term.copy()))
140
            } else if is_data_machine_number(&self.term) {
141
                write!(f, "{}", MachineNumberRef::from(self.term.copy()))
142
            } else {
143
                write!(f, "{}", self.term)
144
            }
145
1
        }
146
    }
147

            
148
    #[mcrl2_term(is_data_function_symbol)]
149
    pub struct DataFunctionSymbol {
150
        term: ATerm,
151
    }
152

            
153
    impl DataFunctionSymbol {
154
        #[mcrl2_ignore]
155
121696
        pub fn new(tp: &mut TermPool, name: &str) -> DataFunctionSymbol {
156
121696
            DataFunctionSymbol {
157
121696
                term: tp.create_with(|| mcrl2_sys::data::ffi::create_data_function_symbol(name.to_string())),
158
121696
            }
159
121696
        }
160

            
161
        /// Returns the sort of the function symbol.
162
        pub fn sort(&self) -> SortExpressionRef<'_> {
163
            self.term.arg(1).into()
164
        }
165

            
166
        /// Returns the name of the function symbol
167
12447
        pub fn name(&self) -> &str {
168
12447
            // We only change the lifetime, but that is fine since it is derived from the current term.
169
12447
            unsafe { std::mem::transmute(self.term.arg(0).get_head_symbol().name()) }
170
12447
        }
171

            
172
        /// Returns the internal operation id (a unique number) for the data::function_symbol.
173
182614380
        pub fn operation_id(&self) -> usize {
174
182614380
            debug_assert!(
175
182614380
                is_data_function_symbol(&self.term),
176
                "term {} is not a data function symbol",
177
                self.term
178
            );
179
182614380
            unsafe { ffi::get_data_function_symbol_index(self.term.get()) }
180
182614380
        }
181
    }
182

            
183
    impl fmt::Display for DataFunctionSymbol {
184
3
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185
3
            if !self.is_default() {
186
3
                write!(f, "{}", self.name())
187
            } else {
188
                write!(f, "<default>")
189
            }
190
3
        }
191
    }
192

            
193
    #[mcrl2_term(is_data_variable)]
194
    pub struct DataVariable {
195
        term: ATerm,
196
    }
197

            
198
    impl DataVariable {
199
        /// Create a new untyped variable with the given name.
200
        #[mcrl2_ignore]
201
11514
        pub fn new(tp: &mut TermPool, name: &str) -> DataVariable {
202
11514
            DataVariable {
203
11514
                term: tp.create_with(|| mcrl2_sys::data::ffi::create_data_variable(name.to_string())),
204
11514
            }
205
11514
        }
206

            
207
        /// Create a variable with the given sort and name.
208
        pub fn with_sort(tp: &mut TermPool, name: &str, sort: &SortExpressionRef<'_>) -> DataVariable {
209
            DataVariable {
210
                term: tp.create_with(|| unsafe {
211
                    mcrl2_sys::data::ffi::create_sorted_data_variable(name.to_string(), sort.term.get())
212
                }),
213
            }
214
        }
215

            
216
        /// Returns the name of the variable.
217
21504
        pub fn name(&self) -> &str {
218
21504
            // We only change the lifetime, but that is fine since it is derived from the current term.
219
21504
            unsafe { std::mem::transmute(self.term.arg(0).get_head_symbol().name()) }
220
21504
        }
221

            
222
        /// Returns the sort of the variable.
223
        pub fn sort(&self) -> SortExpressionRef<'_> {
224
            self.term.arg(1).into()
225
        }
226
    }
227

            
228
    impl fmt::Display for DataVariable {
229
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230
            write!(f, "{}", self.name())
231
        }
232
    }
233

            
234
    #[mcrl2_term(is_data_application)]
235
    pub struct DataApplication {
236
        term: ATerm,
237
    }
238

            
239
    impl DataApplication {
240
        #[mcrl2_ignore]
241
30785269
        pub fn new<'a, 'b>(
242
30785269
            tp: &mut TermPool,
243
30785269
            head: &impl Borrow<ATermRef<'a>>,
244
30785269
            arguments: &[impl Borrow<ATermRef<'b>>],
245
30785269
        ) -> DataApplication {
246
30785269
            DataApplication {
247
30785269
                term: tp.create_data_application(head, arguments),
248
30785269
            }
249
30785269
        }
250

            
251
        /// Returns the head symbol a data application
252
1
        pub fn data_function_symbol(&self) -> DataFunctionSymbolRef<'_> {
253
1
            self.term.arg(0).upgrade(&self.term).into()
254
1
        }
255

            
256
        /// Returns the arguments of a data application
257
1
        pub fn data_arguments(&self) -> ATermArgs<'_> {
258
1
            let mut result = self.term.arguments();
259
1
            result.next();
260
1
            result
261
1
        }
262

            
263
        /// Returns the sort of a data application.
264
        pub fn sort(&self) -> SortExpressionRef<'_> {
265
            // We only change the lifetime, but that is fine since it is derived from the current term.
266
            unsafe { std::mem::transmute(SortExpressionRef::from(self.term.arg(0))) }
267
        }
268
    }
269

            
270
    impl fmt::Display for DataApplication {
271
1
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272
1
            write!(f, "{}", self.data_function_symbol())?;
273

            
274
1
            let mut first = true;
275
1
            for arg in self.data_arguments() {
276
1
                if !first {
277
                    write!(f, ", ")?;
278
                } else {
279
1
                    write!(f, "(")?;
280
                }
281

            
282
1
                write!(f, "{}", DataExpressionRef::from(arg.copy()))?;
283
1
                first = false;
284
            }
285

            
286
1
            if !first {
287
1
                write!(f, ")")?;
288
            }
289

            
290
1
            Ok(())
291
1
        }
292
    }
293

            
294
    #[mcrl2_term(is_data_machine_number)]
295
    struct MachineNumber {
296
        pub term: ATerm,
297
    }
298

            
299
    impl MachineNumber {
300
        /// Obtain the underlying value of a machine number.
301
        pub fn value(&self) -> u64 {
302
            0
303
        }
304
    }
305

            
306
    impl fmt::Display for MachineNumber {
307
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308
            write!(f, "{}", self.value())
309
        }
310
    }
311

            
312
    #[mcrl2_ignore]
313
    impl From<DataFunctionSymbol> for DataExpression {
314
13210620
        fn from(value: DataFunctionSymbol) -> Self {
315
13210620
            value.term.into()
316
13210620
        }
317
    }
318

            
319
    #[mcrl2_ignore]
320
    impl From<DataApplication> for DataExpression {
321
36942354
        fn from(value: DataApplication) -> Self {
322
36942354
            value.term.into()
323
36942354
        }
324
    }
325

            
326
    #[mcrl2_ignore]
327
    impl From<DataVariable> for DataExpression {
328
        fn from(value: DataVariable) -> Self {
329
            value.term.into()
330
        }
331
    }
332
}
333

            
334
pub use inner::*;
335

            
336
#[cfg(test)]
337
mod tests {
338
    use crate::aterm::ATerm;
339
    use crate::aterm::TermPool;
340
    use crate::data::is_data_application;
341
    use crate::data::DataApplication;
342
    use crate::data::DataFunctionSymbol;
343

            
344
    #[test]
345
1
    fn test_print() {
346
1
        let mut tp = TermPool::new();
347
1

            
348
1
        let a = DataFunctionSymbol::new(&mut tp, "a");
349
1
        assert_eq!("a", format!("{}", a));
350

            
351
        // Check printing of data applications.
352
1
        let f = DataFunctionSymbol::new(&mut tp, "f");
353
1
        let a_term: ATerm = a.clone().into();
354
1
        let appl = DataApplication::new(&mut tp, &f, &[a_term]);
355
1
        assert_eq!("f(a)", format!("{}", appl));
356
1
    }
357

            
358
    #[test]
359
1
    fn test_recognizers() {
360
1
        let mut tp = TermPool::new();
361
1

            
362
1
        let a = DataFunctionSymbol::new(&mut tp, "a");
363
1
        let f = DataFunctionSymbol::new(&mut tp, "f");
364
1
        let a_term: ATerm = a.clone().into();
365
1
        let appl = DataApplication::new(&mut tp, &f, &[a_term]);
366
1

            
367
1
        let term: ATerm = appl.into();
368
1
        assert!(is_data_application(&term));
369
1
    }
370
}