1
use std::error::Error;
2

            
3
use mcrl2_sys::cxx::UniquePtr;
4
use mcrl2_sys::cxx::{self};
5
use mcrl2_sys::data::ffi;
6
use utilities::lock_global;
7

            
8
use crate::aterm::ATerm;
9
use crate::aterm::ATermList;
10
use crate::aterm::ATermRef;
11

            
12
use super::DataExpression;
13
use super::DataFunctionSymbol;
14
use super::DataVariable;
15
use super::SortExpressionRef;
16

            
17
/// A safe abstraction for the mCRL2 data specification.
18
pub struct DataSpecification {
19
    pub(crate) data_spec: UniquePtr<ffi::data_specification>,
20
}
21

            
22
impl DataSpecification {
23
    /// Parses the given text into a data specification
24
128
    pub fn new(text: &str) -> Result<Self, cxx::Exception> {
25
128
        let _guard = lock_global();
26
128
        let data_spec = ffi::parse_data_specification(text)?;
27

            
28
128
        Ok(DataSpecification { data_spec })
29
128
    }
30

            
31
    /// Parses the given text as a data expression for the spec.
32
374
    pub fn parse(&self, text: &str) -> Result<DataExpression, Box<dyn Error>> {
33
374
        let _guard = lock_global();
34
374
        let term: ATerm = ffi::parse_data_expression(text, &self.data_spec)?.into();
35
374

            
36
374
        Ok(term.into())
37
374
    }
38

            
39
    /// Parses the given text as a data variable for the spec.
40
    pub fn parse_variable(&self, text: &str) -> Result<DataVariable, Box<dyn Error>> {
41
        let _guard = lock_global();
42
        let term: ATerm = ffi::parse_variable(text, &self.data_spec)?.into();
43
        Ok(term.into())
44
    }
45

            
46
    /// Returns the equations of the data specification.
47
126
    pub fn equations(&self) -> Vec<DataEquation> {
48
126
        ffi::get_data_specification_equations(&self.data_spec)
49
126
            .iter()
50
41286
            .map(|x| ATerm::from(x).into())
51
126
            .collect()
52
126
    }
53

            
54
    /// Returns the constructors for the given sort expression.
55
    pub fn constructors(&self, sort: &SortExpressionRef<'_>) -> Vec<DataFunctionSymbol> {
56
        let t: ATermRef<'_> = sort.copy().into();
57
        unsafe {
58
            ffi::get_data_specification_constructors(&self.data_spec, t.get())
59
                .iter()
60
                .map(|x| ATerm::from(x).into())
61
                .collect()
62
        }
63
    }
64
}
65

            
66
impl Clone for DataSpecification {
67
120
    fn clone(&self) -> Self {
68
120
        DataSpecification {
69
120
            data_spec: ffi::data_specification_clone(&self.data_spec),
70
120
        }
71
120
    }
72
}
73

            
74
#[derive(PartialEq, Eq, Hash, Clone, PartialOrd, Ord, Debug)]
75
pub struct DataEquation {
76
    pub variables: Vec<DataVariable>,
77
    pub condition: DataExpression,
78
    pub lhs: DataExpression,
79
    pub rhs: DataExpression,
80
}
81

            
82
impl From<ATerm> for DataEquation {
83
41286
    fn from(value: ATerm) -> Self {
84
41286
        let variables: ATermList<DataVariable> = value.arg(0).into();
85
41286

            
86
41286
        DataEquation {
87
41286
            variables: variables.iter().collect(),
88
41286
            condition: value.arg(1).protect().into(),
89
41286
            lhs: value.arg(2).protect().into(),
90
41286
            rhs: value.arg(3).protect().into(),
91
41286
        }
92
41286
    }
93
}
94

            
95
#[cfg(test)]
96
mod tests {
97
    use test_log::test;
98

            
99
    use super::*;
100

            
101
1
    #[test]
102
    fn test_parse_data_specification() {
103
        let text = "
104
            sort Xbool = struct
105
                Xfalse
106
            | Xtrue ;
107
            
108
            sort Bit = struct
109
                x0
110
            | x1 ;
111
            
112
            sort Octet = struct
113
                buildOctet (Bit, Bit, Bit, Bit, Bit, Bit, Bit, Bit) ;
114
            
115
            sort OctetSum = struct
116
                buildOctetSum (Bit, Octet) ;
117
            
118
            sort Half = struct
119
                buildHalf (Octet, Octet) ;
120
            
121
            sort HalfSum = struct
122
                buildHalfSum (Bit, Half) ;
123
            
124
            map
125
                notBool : Xbool -> Xbool ;
126
                andBool : Xbool # Xbool -> Xbool ;";
127

            
128
        let _data_spec = DataSpecification::new(text).unwrap();
129
    }
130
}