1
use std::collections::BTreeMap;
2

            
3
use core::fmt::Debug;
4
use linkme::distributed_slice;
5

            
6
//TODO: write good documentation on this! ~niklasdewally
7

            
8
use crate::{
9
    ast::{DeclarationPtr, Expression, Literal, Name, SymbolTable},
10
    rule_engine::ApplicationError,
11
};
12

            
13
#[distributed_slice]
14
#[doc(hidden)]
15
pub static REPRESENTATION_RULES: [RepresentationRule];
16

            
17
#[doc(hidden)]
18
pub struct RepresentationRule {
19
    pub name: &'static str,
20
    pub init: fn(&Name, &SymbolTable) -> Option<Box<dyn Representation>>,
21
}
22

            
23
/// Gets the representation rule named `name`.
24
#[allow(clippy::type_complexity)]
25
pub fn get_repr_rule(
26
    name: &str,
27
) -> Option<fn(&Name, &SymbolTable) -> Option<Box<dyn Representation>>> {
28
    REPRESENTATION_RULES
29
        .iter()
30
        .find(|x| x.name == name)
31
        .map(|x| x.init)
32
}
33

            
34
#[macro_export]
35
macro_rules! register_representation {
36
    ($ruleType:ident, $ruleName:literal) => {
37
        paste::paste!{
38
        #[linkme::distributed_slice($crate::representation::REPRESENTATION_RULES)]
39
        pub static [<__ $ruleType:snake:upper _REPRESENTATION_RULE>]: $crate::representation::RepresentationRule = $crate::representation::RepresentationRule {
40
            name: $ruleName,
41
            init: [<__create_representation_ $ruleType:snake>]
42
        };
43

            
44

            
45
        fn [<__create_representation_ $ruleType:snake>] (name: &$crate::ast::Name, symtab: &$crate::ast::SymbolTable) -> Option<Box<dyn Representation>>  {
46
                $ruleType::init(name,symtab).map(|x| Box::new(x) as Box<dyn Representation>)
47
            }
48
        }
49
    };
50
}
51

            
52
// This alongside Representation::box_clone() allows Representation to be a trait-object but still
53
// cloneable.
54
impl Clone for Box<dyn Representation> {
55
    fn clone(&self) -> Self {
56
        self.box_clone()
57
    }
58
}
59

            
60
/// Encodes the two-way relationship between a non-atomic variable and multiple auxiliary variables.
61
///
62
/// For example, a 2x2 matrix X might be represented by a variable for each element X1_1 X1_2 X2_1 X2_2.
63
/// The [`Representation`] for X then allows us to set the value of the matrix, and takes care of
64
/// assigning the individual variables accordingly. Conversly, we can set the values of the elements, and
65
/// the [`Representation`] will return an assignment for the matrix as a whole.
66
pub trait Representation: Send + Sync + Debug {
67
    /// Creates a representation object for the given name.
68
    fn init(name: &Name, symtab: &SymbolTable) -> Option<Self>
69
    where
70
        Self: Sized;
71

            
72
    /// The variable being represented.
73
    fn variable_name(&self) -> &Name;
74

            
75
    /// Given an assignment for `self`, creates assignments for its representation variables.
76
    fn value_down(&self, value: Literal) -> Result<BTreeMap<Name, Literal>, ApplicationError>;
77

            
78
    /// Given assignments for its representation variables, creates an assignment for `self`.
79
    fn value_up(&self, values: &BTreeMap<Name, Literal>) -> Result<Literal, ApplicationError>;
80

            
81
    /// Returns [`Expression`]s representing each representation variable.
82
    fn expression_down(
83
        &self,
84
        symtab: &SymbolTable,
85
    ) -> Result<BTreeMap<Name, Expression>, ApplicationError>;
86

            
87
    /// Creates declarations for the representation variables of `self`.
88
    fn declaration_down(&self) -> Result<Vec<DeclarationPtr>, ApplicationError>;
89

            
90
    /// The rule name for this representaion.
91
    fn repr_name(&self) -> &str;
92

            
93
    /// Makes a clone of `self` into a `Representation` trait object.
94
    fn box_clone(&self) -> Box<dyn Representation>;
95
}