logic_parser/parsing/
node.rs

1use std::collections::HashSet;
2
3#[cfg(feature = "serde")]
4use serde::{Serialize, Deserialize};
5
6#[cfg(feature = "serde")]
7#[derive(Debug, Serialize, Deserialize)]
8#[serde(tag = "type", rename_all="snake_case")]
9pub enum ASTNode {
10    Identifier { name: String },
11    Literal { value: bool },
12    #[serde(rename = "operator.not")]
13    Not { operand: Box<ASTNode> },
14    #[serde(rename = "operator.and")]
15    And { left: Box<ASTNode>, right: Box<ASTNode> },
16    #[serde(rename = "operator.or")]
17    Or { left: Box<ASTNode>, right: Box<ASTNode> },
18    #[serde(rename = "operator.implies")]
19    Implies { left: Box<ASTNode>, right: Box<ASTNode> },
20    #[serde(rename = "operator.iff")]
21    IfAndOnlyIf { left: Box<ASTNode>, right: Box<ASTNode> },
22}
23
24// Serde Serialize and Deserialize traits are available when the
25// optional 'serde' feature is enabled
26
27#[cfg(not(feature = "serde"))]
28#[derive(Debug)]
29pub enum ASTNode {
30    Identifier { name: String },
31    Literal { value: bool },
32    Not { operand: Box<ASTNode> },
33    And { left: Box<ASTNode>, right: Box<ASTNode> },
34    Or { left: Box<ASTNode>, right: Box<ASTNode> },
35    Implies { left: Box<ASTNode>, right: Box<ASTNode> },
36    IfAndOnlyIf { left: Box<ASTNode>, right: Box<ASTNode> },
37}
38
39impl ASTNode {
40    pub fn as_string(&self) -> String {
41        format!("{:#?}", self)
42    }
43
44    pub fn repr(&self) -> &str {
45        match self {
46            ASTNode::Identifier { name } => name,
47            ASTNode::Literal { value } => if *value { "1" } else { "0" },
48            ASTNode::Not { .. } => "¬",
49            ASTNode::And { .. } => "∧",
50            ASTNode::Or { .. } => "∨",
51            ASTNode::Implies { .. } => "⇒",
52            ASTNode::IfAndOnlyIf { .. } => "⟷",
53        }
54    }
55
56    /// Returns a HashSet of unique identifiers in the AST by traversing it.
57    ///
58    /// There is no guarantee of ordering.
59    pub fn get_identifiers(&self) -> HashSet<&str> {
60        let mut variables = HashSet::new();
61        match self {
62            ASTNode::Identifier { name } => {
63                variables.insert(name.as_str());
64            },
65            ASTNode::Literal { .. } => {},
66            ASTNode::Not { operand } => {
67                variables.extend(operand.get_identifiers());
68            },
69            ASTNode::And { left, right } => {
70                variables.extend(left.get_identifiers());
71                variables.extend(right.get_identifiers());
72            },
73            ASTNode::Or { left, right } => {
74                variables.extend(left.get_identifiers());
75                variables.extend(right.get_identifiers());
76            },
77            ASTNode::Implies { left, right } => {
78                variables.extend(left.get_identifiers());
79                variables.extend(right.get_identifiers());
80            },
81            ASTNode::IfAndOnlyIf { left, right } => {
82                variables.extend(left.get_identifiers());
83                variables.extend(right.get_identifiers());
84            }
85        }
86        variables
87    }
88
89    #[cfg(not(feature = "serde"))]
90    pub fn as_json(&self) -> String {
91        match self {
92            ASTNode::Identifier { name } => {
93                format!(r###"{{
94                    "type": "identifier",
95                    "name": "{name}"
96                }}"###)
97            },
98            ASTNode::Literal { value } => {
99                format!(r###"{{
100                    "type": "literal",
101                    "value": {value}
102                }}"###)
103            },
104            ASTNode::Not { operand } => {
105                format!(r###"{{
106                    "type": "operator.not",
107                    "operand": {operand}
108                }}"###, operand=operand.as_json())
109            },
110            ASTNode::And { left, right } => {
111                format!(r###"{{
112                    "type": "operator.and",
113                    "left": {left},
114                    "right": {right}
115                }}"###, left=left.as_json(), right=right.as_json())
116            },
117            ASTNode::Or { left, right } => {
118                format!(r###"{{
119                    "type": "operator.or",
120                    "left": {left},
121                    "right": {right}
122                }}"###, left=left.as_json(), right=right.as_json())
123            },
124            ASTNode::Implies { left, right } => {
125                format!(r###"{{
126                    "type": "operator.implies",
127                    "left": {left},
128                    "right": {right}
129                }}"###, left=left.as_json(), right=right.as_json())
130            },
131            ASTNode::IfAndOnlyIf { left, right } => {
132                format!(r###"{{
133                    "type": "operator.iff",
134                    "left": {left},
135                    "right": {right}
136                }}"###, left=left.as_json(), right=right.as_json())
137            }
138        }
139    }
140
141    #[cfg(feature = "serde")]
142    pub fn as_json(&self) -> String {
143        serde_json::to_string(self).unwrap()
144    }
145}