semantic_analyzer/types/
condition.rs

1//! # Condition types
2//! Condition types for Semantic analyzer result state.
3
4use super::expression::Expression;
5use super::{Binding, FunctionCall, LetBinding};
6use crate::ast;
7use crate::types::semantic::{ExtendedExpression, SemanticContextInstruction};
8#[cfg(feature = "codec")]
9use serde::{Deserialize, Serialize};
10
11/// Basic logical conditions mostly for compare expressions
12#[derive(Debug, Clone, PartialEq, Eq)]
13#[cfg_attr(
14    feature = "codec",
15    derive(Serialize, Deserialize),
16    serde(tag = "type", content = "content")
17)]
18pub enum Condition {
19    Great,
20    Less,
21    Eq,
22    GreatEq,
23    LessEq,
24    NotEq,
25}
26
27impl From<ast::Condition> for Condition {
28    fn from(value: ast::Condition) -> Self {
29        match value {
30            ast::Condition::Great => Self::Great,
31            ast::Condition::Less => Self::Less,
32            ast::Condition::Eq => Self::Eq,
33            ast::Condition::GreatEq => Self::GreatEq,
34            ast::Condition::LessEq => Self::LessEq,
35            ast::Condition::NotEq => Self::NotEq,
36        }
37    }
38}
39
40/// Logical conditions type representation.
41/// Usefulf for logical expressions.
42#[derive(Debug, Clone, PartialEq, Eq)]
43#[cfg_attr(
44    feature = "codec",
45    derive(Serialize, Deserialize),
46    serde(tag = "type", content = "content")
47)]
48pub enum LogicCondition {
49    And,
50    Or,
51}
52
53impl From<ast::LogicCondition> for LogicCondition {
54    fn from(value: ast::LogicCondition) -> Self {
55        match value {
56            ast::LogicCondition::And => Self::And,
57            ast::LogicCondition::Or => Self::Or,
58        }
59    }
60}
61
62/// Expression condition for two expressions
63#[derive(Debug, Clone, PartialEq)]
64#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
65pub struct ExpressionCondition {
66    /// Left expression
67    pub left: Expression,
68    /// Condition for expressions
69    pub condition: Condition,
70    /// Right expression
71    pub right: Expression,
72}
73
74impl<I: SemanticContextInstruction, E: ExtendedExpression<I>>
75    From<ast::ExpressionCondition<'_, I, E>> for ExpressionCondition
76{
77    fn from(value: ast::ExpressionCondition<'_, I, E>) -> Self {
78        Self {
79            left: value.left.into(),
80            condition: value.condition.into(),
81            right: value.right.into(),
82        }
83    }
84}
85
86/// Expression logic condition for expression conditions.
87/// It's build chain of expression conditions and
88/// expression logic conditions as flat tree.
89#[derive(Debug, Clone, PartialEq)]
90#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
91pub struct ExpressionLogicCondition {
92    /// Left expression condition
93    pub left: ExpressionCondition,
94    /// Optional right expression condition with logic condition
95    pub right: Option<(LogicCondition, Box<ExpressionLogicCondition>)>,
96}
97
98impl<I: SemanticContextInstruction, E: ExtendedExpression<I>>
99    From<ast::ExpressionLogicCondition<'_, I, E>> for ExpressionLogicCondition
100{
101    fn from(value: ast::ExpressionLogicCondition<'_, I, E>) -> Self {
102        Self {
103            left: value.left.into(),
104            right: value
105                .right
106                .map(|(v, expr)| (v.into(), Box::new(expr.as_ref().clone().into()))),
107        }
108    }
109}
110
111/// If-condition representation. It can be:
112/// - simple - just expression
113/// - logic - represented through `ExpressionLogicCondition`
114#[derive(Debug, Clone, PartialEq)]
115#[cfg_attr(
116    feature = "codec",
117    derive(Serialize, Deserialize),
118    serde(tag = "type", content = "content")
119)]
120pub enum IfCondition {
121    Single(Expression),
122    Logic(ExpressionLogicCondition),
123}
124
125impl<I: SemanticContextInstruction, E: ExtendedExpression<I>> From<ast::IfCondition<'_, I, E>>
126    for IfCondition
127{
128    fn from(value: ast::IfCondition<'_, I, E>) -> Self {
129        match value {
130            ast::IfCondition::Single(v) => Self::Single(v.into()),
131            ast::IfCondition::Logic(v) => Self::Logic(v.into()),
132        }
133    }
134}
135
136/// # If statement
137/// Basic entity that represent if-statement.
138#[derive(Debug, Clone, PartialEq)]
139#[cfg_attr(feature = "codec", derive(Serialize, Deserialize))]
140pub struct IfStatement {
141    /// If-condition
142    pub condition: IfCondition,
143    /// Basic if-body, if if-condition is true
144    pub body: IfBodyStatements,
145    /// Basic else-body, if if-condition is false
146    pub else_statement: Option<IfBodyStatements>,
147    /// Basic else-if-body
148    pub else_if_statement: Option<Box<IfStatement>>,
149}
150
151impl<I: SemanticContextInstruction, E: ExtendedExpression<I>> From<ast::IfStatement<'_, I, E>>
152    for IfStatement
153{
154    fn from(value: ast::IfStatement<'_, I, E>) -> Self {
155        Self {
156            condition: value.condition.into(),
157            body: value.body.into(),
158            else_statement: value.else_statement.map(Into::into),
159            else_if_statement: value
160                .else_if_statement
161                .map(|v| Box::new(v.as_ref().clone().into())),
162        }
163    }
164}
165
166/// If-body statement can be:
167/// - if-body-statement related only
168/// - loop-body-statement related - special case for the loops
169#[derive(Debug, Clone, PartialEq)]
170#[cfg_attr(
171    feature = "codec",
172    derive(Serialize, Deserialize),
173    serde(tag = "type", content = "content")
174)]
175pub enum IfBodyStatements {
176    If(Vec<IfBodyStatement>),
177    Loop(Vec<IfLoopBodyStatement>),
178}
179
180impl<I: SemanticContextInstruction, E: ExtendedExpression<I>> From<ast::IfBodyStatements<'_, I, E>>
181    for IfBodyStatements
182{
183    fn from(value: ast::IfBodyStatements<'_, I, E>) -> Self {
184        match value {
185            ast::IfBodyStatements::If(v) => Self::If(v.iter().map(|v| v.clone().into()).collect()),
186            ast::IfBodyStatements::Loop(v) => {
187                Self::Loop(v.iter().map(|v| v.clone().into()).collect())
188            }
189        }
190    }
191}
192
193/// Loop body statement represents body for the loop
194#[derive(Debug, Clone, PartialEq)]
195#[cfg_attr(
196    feature = "codec",
197    derive(Serialize, Deserialize),
198    serde(tag = "type", content = "content")
199)]
200pub enum LoopBodyStatement {
201    LetBinding(LetBinding),
202    Binding(Binding),
203    FunctionCall(FunctionCall),
204    If(IfStatement),
205    Loop(Vec<LoopBodyStatement>),
206    Return(Expression),
207    Break,
208    Continue,
209}
210
211impl<I: SemanticContextInstruction, E: ExtendedExpression<I>> From<ast::LoopBodyStatement<'_, I, E>>
212    for LoopBodyStatement
213{
214    fn from(value: ast::LoopBodyStatement<'_, I, E>) -> Self {
215        match value {
216            ast::LoopBodyStatement::LetBinding(v) => Self::LetBinding(v.into()),
217            ast::LoopBodyStatement::Binding(v) => Self::Binding(v.into()),
218            ast::LoopBodyStatement::FunctionCall(v) => Self::FunctionCall(v.into()),
219            ast::LoopBodyStatement::If(v) => Self::If(v.into()),
220            ast::LoopBodyStatement::Loop(v) => {
221                Self::Loop(v.iter().map(|v| v.clone().into()).collect())
222            }
223            ast::LoopBodyStatement::Return(v) => Self::Return(v.into()),
224            ast::LoopBodyStatement::Break => Self::Break,
225            ast::LoopBodyStatement::Continue => Self::Continue,
226        }
227    }
228}
229
230/// If-body statement represents body for the if-body
231#[derive(Debug, Clone, PartialEq)]
232#[cfg_attr(
233    feature = "codec",
234    derive(Serialize, Deserialize),
235    serde(tag = "type", content = "content")
236)]
237pub enum IfBodyStatement {
238    LetBinding(LetBinding),
239    Binding(Binding),
240    FunctionCall(FunctionCall),
241    If(IfStatement),
242    Loop(Vec<LoopBodyStatement>),
243    Return(Expression),
244}
245
246impl<I: SemanticContextInstruction, E: ExtendedExpression<I>> From<ast::IfBodyStatement<'_, I, E>>
247    for IfBodyStatement
248{
249    fn from(value: ast::IfBodyStatement<'_, I, E>) -> Self {
250        match value {
251            ast::IfBodyStatement::LetBinding(v) => Self::LetBinding(v.into()),
252            ast::IfBodyStatement::Binding(v) => Self::Binding(v.into()),
253            ast::IfBodyStatement::FunctionCall(v) => Self::FunctionCall(v.into()),
254            ast::IfBodyStatement::If(v) => Self::If(v.into()),
255            ast::IfBodyStatement::Loop(v) => {
256                Self::Loop(v.iter().map(|v| v.clone().into()).collect())
257            }
258            ast::IfBodyStatement::Return(v) => Self::Return(v.into()),
259        }
260    }
261}
262
263/// If-loop body statements represent body of if-body
264/// in the loops
265#[derive(Debug, Clone, PartialEq)]
266#[cfg_attr(
267    feature = "codec",
268    derive(Serialize, Deserialize),
269    serde(tag = "type", content = "content")
270)]
271pub enum IfLoopBodyStatement {
272    LetBinding(LetBinding),
273    Binding(Binding),
274    FunctionCall(FunctionCall),
275    If(IfStatement),
276    Loop(Vec<LoopBodyStatement>),
277    Return(Expression),
278    Break,
279    Continue,
280}
281
282impl<I: SemanticContextInstruction, E: ExtendedExpression<I>>
283    From<ast::IfLoopBodyStatement<'_, I, E>> for IfLoopBodyStatement
284{
285    fn from(value: ast::IfLoopBodyStatement<'_, I, E>) -> Self {
286        match value {
287            ast::IfLoopBodyStatement::LetBinding(v) => Self::LetBinding(v.into()),
288            ast::IfLoopBodyStatement::Binding(v) => Self::Binding(v.into()),
289            ast::IfLoopBodyStatement::FunctionCall(v) => Self::FunctionCall(v.into()),
290            ast::IfLoopBodyStatement::If(v) => Self::If(v.into()),
291            ast::IfLoopBodyStatement::Loop(v) => {
292                Self::Loop(v.iter().map(|v| v.clone().into()).collect())
293            }
294            ast::IfLoopBodyStatement::Return(v) => Self::Return(v.into()),
295            ast::IfLoopBodyStatement::Break => Self::Break,
296            ast::IfLoopBodyStatement::Continue => Self::Continue,
297        }
298    }
299}