1use derive_more::From;
2use galvan_ast_macro::PrintAst;
3
4use crate::{Expression, Ident, PrintAst};
5
6use super::ExpressionKind;
7
8pub trait InfixOperator {
9 fn symbol(&self) -> &str;
10}
11
12#[derive(Clone, Debug, PartialEq, Eq, From, PrintAst)]
13pub enum InfixExpression {
14 Logical(InfixOperation<LogicalOperator>),
15 Arithmetic(InfixOperation<ArithmeticOperator>),
16 Collection(InfixOperation<CollectionOperator>),
17 Range(InfixOperation<RangeOperator>),
18 Comparison(InfixOperation<ComparisonOperator>),
19 Member(InfixOperation<MemberOperator>),
20 Unwrap(InfixOperation<UnwrapOperator>),
21 Custom(InfixOperation<CustomInfix>),
22}
23
24impl InfixExpression {
25 pub fn is_comparison(&self) -> bool {
26 matches!(self, Self::Comparison(_))
27 }
28}
29
30#[derive(Clone, Debug, PartialEq, Eq, From)]
31pub struct InfixOperation<Op: InfixOperator> {
32 pub lhs: Expression,
33 pub operator: Op,
34 pub rhs: Expression,
35}
36
37impl<T: InfixOperator> PrintAst for InfixOperation<T> {
38 fn print_ast(&self, indent: usize) -> String {
39 let indent_str = " ".repeat(indent);
40 let mut result = format!("{}{}\n", indent_str, stringify!(#struct_name));
41
42 let field_value = self.lhs.print_ast(indent + 2);
43 result.push_str(&format!("{} {}{}\n", indent_str, "lhs", field_value));
44
45 result.push_str(&format!(
46 "{} {}{}\n",
47 indent_str,
48 "op",
49 self.operator.symbol()
50 ));
51
52 let field_value = self.lhs.print_ast(indent + 2);
53 result.push_str(&format!("{} {}{}\n", indent_str, "rhs", field_value));
54
55 result
56 }
57}
58
59impl InfixOperation<MemberOperator> {
60 pub fn is_field(&self) -> bool {
61 match self.rhs.kind {
62 ExpressionKind::Ident(_) => true,
63 _ => false,
66 }
67 }
68
69 pub fn field_ident(&self) -> Option<&Ident> {
70 match &self.rhs.kind {
71 ExpressionKind::Ident(ident) => Some(ident),
72 _ => None,
73 }
74 }
75}
76
77#[derive(Clone, Debug, PartialEq, Eq)]
78pub enum LogicalOperator {
79 Or,
80 And,
81 Xor,
82}
83
84impl InfixOperator for LogicalOperator {
85 fn symbol(&self) -> &str {
86 match self {
87 LogicalOperator::Or => "||",
88 LogicalOperator::And => "&&",
89 LogicalOperator::Xor => "^",
90 }
91 }
92}
93
94#[derive(Clone, Debug, PartialEq, Eq)]
95pub enum ArithmeticOperator {
96 Add,
97 Sub,
98 Mul,
99 Div,
100 Rem,
101 Exp,
102}
103
104impl InfixOperator for ArithmeticOperator {
105 fn symbol(&self) -> &str {
106 match self {
107 ArithmeticOperator::Add => "+",
108 ArithmeticOperator::Sub => "-",
109 ArithmeticOperator::Mul => "*",
110 ArithmeticOperator::Div => "/",
111 ArithmeticOperator::Rem => "%",
112 ArithmeticOperator::Exp => "^",
113 }
114 }
115}
116
117#[derive(Clone, Debug, PartialEq, Eq)]
118pub enum CollectionOperator {
119 Concat,
120 Remove,
121 Contains,
122}
123
124impl InfixOperator for CollectionOperator {
125 fn symbol(&self) -> &str {
126 match self {
127 CollectionOperator::Concat => "++",
128 CollectionOperator::Remove => "--",
129 CollectionOperator::Contains => "in",
130 }
131 }
132}
133
134#[derive(Clone, Debug, PartialEq, Eq)]
135pub enum ComparisonOperator {
136 LessEqual,
137 Less,
138 GreaterEqual,
139 Greater,
140 Equal,
141 NotEqual,
142 Identical,
143 NotIdentical,
144}
145
146impl InfixOperator for ComparisonOperator {
147 fn symbol(&self) -> &str {
148 match self {
149 ComparisonOperator::LessEqual => "≤",
150 ComparisonOperator::Less => "<",
151 ComparisonOperator::GreaterEqual => "≥",
152 ComparisonOperator::Greater => ">",
153 ComparisonOperator::Equal => "==",
154 ComparisonOperator::NotEqual => "≠",
155 ComparisonOperator::Identical => "===",
156 ComparisonOperator::NotIdentical => "!==",
157 }
158 }
159}
160
161#[derive(Clone, Debug, PartialEq, Eq)]
162pub enum MemberOperator {
163 Dot,
164 SafeCall,
165}
166
167impl InfixOperator for MemberOperator {
168 fn symbol(&self) -> &str {
169 match self {
170 MemberOperator::Dot => ".",
171 MemberOperator::SafeCall => "?.",
172 }
173 }
174}
175
176#[derive(Copy, Clone, Debug, PartialEq, Eq)]
177pub struct UnwrapOperator;
178
179impl InfixOperator for UnwrapOperator {
180 fn symbol(&self) -> &str {
181 "?"
182 }
183}
184
185#[derive(Clone, Debug, PartialEq, Eq)]
186pub struct CustomInfix(String);
187
188impl InfixOperator for CustomInfix {
189 fn symbol(&self) -> &str {
190 &self.0
191 }
192}
193
194#[derive(Clone, Debug, PartialEq, Eq)]
195pub enum RangeOperator {
196 Inclusive,
197 Exclusive,
198 Tolerance,
199 Interval,
200}
201
202impl InfixOperator for RangeOperator {
203 fn symbol(&self) -> &str {
204 match self {
205 RangeOperator::Inclusive => "..=",
206 RangeOperator::Exclusive => "..<",
207 RangeOperator::Tolerance => "±",
208 RangeOperator::Interval => "..+",
209 }
210 }
211}