mcrl2/data/
data_specification.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use std::error::Error;

use mcrl2_sys::cxx::UniquePtr;
use mcrl2_sys::cxx::{self};
use mcrl2_sys::data::ffi;
use utilities::lock_global;

use crate::aterm::ATerm;
use crate::aterm::ATermList;
use crate::aterm::ATermRef;

use super::DataExpression;
use super::DataFunctionSymbol;
use super::DataVariable;
use super::SortExpressionRef;

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

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

        Ok(DataSpecification { data_spec })
    }

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

        Ok(term.into())
    }

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

    /// Returns the equations of the data specification.
    pub fn equations(&self) -> Vec<DataEquation> {
        ffi::get_data_specification_equations(&self.data_spec)
            .iter()
            .map(|x| ATerm::from(x).into())
            .collect()
    }

    /// Returns the constructors for the given sort expression.
    pub fn constructors(&self, sort: &SortExpressionRef<'_>) -> Vec<DataFunctionSymbol> {
        let t: ATermRef<'_> = sort.copy().into();
        unsafe {
            ffi::get_data_specification_constructors(&self.data_spec, t.get())
                .iter()
                .map(|x| ATerm::from(x).into())
                .collect()
        }
    }
}

impl Clone for DataSpecification {
    fn clone(&self) -> Self {
        DataSpecification {
            data_spec: ffi::data_specification_clone(&self.data_spec),
        }
    }
}

#[derive(PartialEq, Eq, Hash, Clone, PartialOrd, Ord, Debug)]
pub struct DataEquation {
    pub variables: Vec<DataVariable>,
    pub condition: DataExpression,
    pub lhs: DataExpression,
    pub rhs: DataExpression,
}

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

        DataEquation {
            variables: variables.iter().collect(),
            condition: value.arg(1).protect().into(),
            lhs: value.arg(2).protect().into(),
            rhs: value.arg(3).protect().into(),
        }
    }
}

#[cfg(test)]
mod tests {
    use test_log::test;

    use super::*;

    #[test]
    fn test_parse_data_specification() {
        let text = "
            sort Xbool = struct
                Xfalse
            | Xtrue ;
            
            sort Bit = struct
                x0
            | x1 ;
            
            sort Octet = struct
                buildOctet (Bit, Bit, Bit, Bit, Bit, Bit, Bit, Bit) ;
            
            sort OctetSum = struct
                buildOctetSum (Bit, Octet) ;
            
            sort Half = struct
                buildHalf (Octet, Octet) ;
            
            sort HalfSum = struct
                buildHalfSum (Bit, Half) ;
            
            map
                notBool : Xbool -> Xbool ;
                andBool : Xbool # Xbool -> Xbool ;";

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