ironplc_dsl/
ast.rs

1use crate::core::Id;
2use crate::dsl::{Constant, DirectVariable};
3use std::cmp::Ordering;
4use std::fmt;
5
6#[derive(Debug, PartialEq, Clone)]
7pub enum Variable {
8    DirectVariable(DirectVariable),
9    SymbolicVariable(SymbolicVariable),
10    // A structured variable that may be nested. This data type is definitely
11    // incorrect because it doesn't support array types
12    MultiElementVariable(Vec<Id>),
13}
14
15impl Variable {
16    pub fn symbolic(name: &str) -> Variable {
17        Variable::SymbolicVariable(SymbolicVariable {
18            name: Id::from(name),
19        })
20    }
21}
22
23#[derive(Debug, PartialEq, Clone)]
24pub struct SymbolicVariable {
25    pub name: Id,
26}
27
28#[derive(Debug, PartialEq, Clone)]
29pub struct Assignment {
30    pub target: Variable,
31    pub value: ExprKind,
32}
33
34#[derive(Debug, PartialEq, Clone)]
35pub struct FbCall {
36    /// Name of the variable that is associated with the function block
37    /// call.
38    pub var_name: Id,
39    pub params: Vec<ParamAssignment>,
40}
41
42#[derive(Debug, PartialEq, Clone)]
43pub enum StmtKind {
44    Assignment(Assignment),
45    If(If),
46    FbCall(FbCall),
47}
48
49impl StmtKind {
50    pub fn if_then(condition: ExprKind, body: Vec<StmtKind>) -> StmtKind {
51        StmtKind::If(If {
52            expr: condition,
53            body: body,
54            else_body: vec![],
55        })
56    }
57
58    pub fn if_then_else(
59        condition: ExprKind,
60        body: Vec<StmtKind>,
61        else_body: Vec<StmtKind>,
62    ) -> StmtKind {
63        StmtKind::If(If {
64            expr: condition,
65            body: body,
66            else_body: else_body,
67        })
68    }
69}
70
71#[derive(Debug, PartialEq, Clone)]
72pub struct If {
73    // TODO how to handle else else if (that should probably be a nested if)
74    pub expr: ExprKind,
75    pub body: Vec<StmtKind>,
76    pub else_body: Vec<StmtKind>,
77}
78
79impl StmtKind {
80    pub fn fb_assign(fb_name: &str, inputs: Vec<&str>, output: &str) -> StmtKind {
81        let assignments = inputs
82            .into_iter()
83            .map(|input| ParamAssignment::positional(ExprKind::symbolic_variable(input)))
84            .collect::<Vec<ParamAssignment>>();
85
86        StmtKind::assignment(
87            Variable::symbolic(output),
88            ExprKind::Function {
89                name: Id::from(fb_name),
90                param_assignment: assignments,
91            },
92        )
93    }
94    pub fn fb_call_mapped(fb_name: &str, inputs: Vec<(&str, &str)>) -> StmtKind {
95        let assignments = inputs
96            .into_iter()
97            .map(|pair| {
98                ParamAssignment::named(pair.0, ExprKind::Variable(Variable::symbolic(pair.1)))
99            })
100            .collect::<Vec<ParamAssignment>>();
101
102        StmtKind::FbCall(FbCall {
103            var_name: Id::from(fb_name),
104            params: assignments,
105        })
106    }
107
108    pub fn assignment(target: Variable, value: ExprKind) -> StmtKind {
109        StmtKind::Assignment(Assignment {
110            target: target,
111            value: value,
112        })
113    }
114
115    pub fn simple_assignment(target: &str, src: Vec<&str>) -> StmtKind {
116        let variable = match src.len() {
117            1 => Variable::symbolic(src[0]),
118            _ => {
119                let src = src
120                    .into_iter()
121                    .map(|part| Id::from(part))
122                    .collect::<Vec<Id>>();
123                Variable::MultiElementVariable(src)
124            }
125        };
126
127        StmtKind::Assignment(Assignment {
128            target: Variable::symbolic(target),
129            value: ExprKind::Variable(variable),
130        })
131    }
132}
133
134#[derive(Debug, PartialEq, Clone)]
135pub enum CompareOp {
136    Or,
137    Xor,
138    And,
139    Eq,
140    Ne,
141    Lt,
142    Gt,
143    LtEq,
144    GtEq,
145}
146
147#[derive(Debug, PartialEq, Clone)]
148pub enum Operator {
149    Add,
150    Sub,
151    Mul,
152    Div,
153    Mod,
154    Pow,
155}
156
157#[derive(Debug, PartialEq, Clone)]
158pub enum UnaryOp {
159    Neg,
160    Not,
161}
162
163#[derive(Debug, PartialEq, Clone)]
164pub enum ExprKind {
165    Compare {
166        op: CompareOp,
167        terms: Vec<ExprKind>,
168    },
169    BinaryOp {
170        ops: Vec<Operator>,
171        terms: Vec<ExprKind>,
172    },
173    UnaryOp {
174        op: UnaryOp,
175        term: Box<ExprKind>,
176    },
177    Const(Constant),
178    Variable(Variable),
179    Function {
180        name: Id,
181        param_assignment: Vec<ParamAssignment>,
182    },
183}
184
185impl ExprKind {
186    pub fn boxed_symbolic_variable(name: &str) -> Box<ExprKind> {
187        Box::new(ExprKind::symbolic_variable(name))
188    }
189
190    pub fn symbolic_variable(name: &str) -> ExprKind {
191        ExprKind::Variable(Variable::symbolic(name))
192    }
193
194    pub fn integer_literal(value: i128) -> ExprKind {
195        ExprKind::Const(Constant::IntegerLiteral(1))
196    }
197}
198#[derive(Debug, PartialEq, Clone)]
199pub struct PositionalInput {
200    pub expr: ExprKind,
201}
202
203#[derive(Debug, PartialEq, Clone)]
204pub struct NamedInput {
205    pub name: Id,
206    pub expr: ExprKind,
207}
208
209#[derive(Debug, PartialEq, Clone)]
210pub enum ParamAssignment {
211    PositionalInput(PositionalInput),
212    NamedInput(NamedInput),
213    Output { not: bool, src: Id, tgt: Variable },
214}
215
216impl ParamAssignment {
217    pub fn positional(expr: ExprKind) -> ParamAssignment {
218        ParamAssignment::PositionalInput(PositionalInput { expr: expr })
219    }
220
221    pub fn named(name: &str, expr: ExprKind) -> ParamAssignment {
222        ParamAssignment::NamedInput(NamedInput {
223            name: Id::from(name),
224            expr: expr,
225        })
226    }
227}
228
229pub struct InputParamAssignment {
230    pub name: Option<String>,
231    pub expr: ExprKind,
232}