1use crate::{
8 aim::{ContextLike, Typedef, WriterLike, Writer, parse_literal_type},
9 expressions::{ExpressionLike, Postfix, Primary, parse_postfix},
10 literals::Literal,
11 values::Value,
12};
13use anyhow::{Result, anyhow};
14use nom::{
15 IResult, Parser,
16 branch::alt,
17 character::complete::{char, multispace0},
18 combinator::map,
19 multi::many1, sequence::delimited,
20};
21use std::{
22 fmt,
23 sync::Arc,
24};
25
26#[derive(Debug, Clone, PartialEq)]
30pub enum Unary {
31 Not(Box<Unary>),
33 Positive(Box<Unary>),
35 Negative(Box<Unary>),
37 CastBool(Box<Unary>),
39 CastDate(Box<Unary>),
41 CastNumber(Box<Unary>),
43 CastTask(Box<Unary>),
45 CastText(Box<Unary>),
47 Primary(Box<Primary>),
49}
50
51fn parse_cast_operator(input: &str) -> IResult<&str, Typedef> {
53 delimited(
54 char('('),
55 delimited(multispace0, parse_literal_type, multispace0),
56 char(')'),
57 ).parse(input)
58}
59
60enum UnaryOp {
62 Not,
63 Positive,
64 Negative,
65 Cast(Typedef),
66}
67
68fn parse_unary_operator(input: &str) -> IResult<&str, UnaryOp> {
70 delimited(
71 multispace0,
72 alt((
73 map(char('!'), |_| UnaryOp::Not),
74 map(char('+'), |_| UnaryOp::Positive),
75 map(char('-'), |_| UnaryOp::Negative),
76 map(parse_cast_operator, |typedef| UnaryOp::Cast(typedef)),
77 )),
78 multispace0,
79 ).parse(input)
80}
81
82impl Unary {
83 fn new(op: UnaryOp, unary: Unary) -> Self {
85 let boxed = Box::new(unary);
86 match op {
87 UnaryOp::Not => Unary::Not(boxed),
88 UnaryOp::Positive => Unary::Positive(boxed),
89 UnaryOp::Negative => Unary::Negative(boxed),
90 UnaryOp::Cast(typedef) => match typedef {
91 Typedef::Bool => Unary::CastBool(boxed),
92 Typedef::Date => Unary::CastDate(boxed),
93 Typedef::Number => Unary::CastNumber(boxed),
94 Typedef::Task => Unary::CastTask(boxed),
95 Typedef::Text => Unary::CastText(boxed),
96 _ => unreachable!(),
97 },
98 }
99 }
100
101 pub fn print(&self, writer: &mut Writer) {
102 match self {
103 Unary::Not(operand) => {
104 writer.write_unary_op("!", operand.as_ref());
105 }
106 Unary::Positive(operand) => {
107 writer.write_unary_op("+", operand.as_ref());
108 }
109 Unary::Negative(operand) => {
110 writer.write_unary_op("-", operand.as_ref());
111 }
112 Unary::CastBool(operand) => {
113 writer.write_str("(Bool)");
114 operand.print(writer);
115 }
116 Unary::CastDate(operand) => {
117 writer.write_str("(Date)");
118 operand.print(writer);
119 }
120 Unary::CastNumber(operand) => {
121 writer.write_str("(Number)");
122 operand.print(writer);
123 }
124 Unary::CastTask(operand) => {
125 writer.write_str("(Task)");
126 operand.print(writer);
127 }
128 Unary::CastText(operand) => {
129 writer.write_str("(Text)");
130 operand.print(writer);
131 }
132 Unary::Primary(primary) => primary.print(writer),
133 }
134 }
135}
136
137pub fn parse_unary(input: &str) -> IResult<&str, Unary> {
142 if let Ok((input, mut unary_chain)) = many1(parse_unary_operator).parse(input) {
144 let (input, postfix) = parse_postfix(input)?;
146 let mut unary = match postfix {
148 Postfix::Primary(primary) => Unary::Primary(primary),
149 _ => Unary::Primary(Box::new(Primary::Postfix(postfix))),
150 };
151 while let Some(op) = unary_chain.pop() {
153 unary = Unary::new(op, unary);
154 }
155 Ok((input, unary))
156 } else {
157 let (input, postfix) = parse_postfix(input)?;
159 let unary = match postfix {
160 Postfix::Primary(primary) => Unary::Primary(primary),
161 _ => Unary::Primary(Box::new(Primary::Postfix(postfix))),
162 };
163 Ok((input, unary))
164 }
165}
166
167impl ExpressionLike for Unary {
168 fn evaluate(&self, context: &mut dyn ContextLike) -> Result<Arc<Value>> {
170 match self {
171 Unary::Not(operand) => {
172 let val = operand.evaluate(context)?;
173 if val.is_error() {
174 return Ok(val);
175 }
176 let found = val.type_as_string();
177 match &*val.as_bool() {
178 Value::Literal(Literal::Bool(b)) => Ok(Arc::new(Value::Literal(Literal::Bool(!b)))),
179 _ => Err(anyhow!(
180 "Expected Bool, found {}~{}",
181 found,
182 self.to_formula(),
183 )),
184 }
185 }
186 Unary::Positive(operand) => {
187 let val = operand.evaluate(context)?;
188 if val.is_error() {
189 return Ok(val);
190 }
191 let found = val.type_as_string();
192 let number = val.as_number()?;
193 match &*number {
194 Value::Literal(Literal::Number(n)) => {
195 Ok(Arc::new(Value::Literal(Literal::Number(*n))))
196 }
197 _ => Err(anyhow!(
198 "Expected numeric operand, found {}~{}",
199 found,
200 self.to_formula(),
201 )),
202 }
203 }
204 Unary::Negative(operand) => {
205 let val = operand.evaluate(context)?;
206 if val.is_error() {
207 return Ok(val);
208 }
209 let found = val.type_as_string();
210 let number = val.as_number()?;
211 match &*number {
212 Value::Literal(Literal::Number(n)) => {
213 Ok(Arc::new(Value::Literal(Literal::Number(-n))))
214 }
215 _ => Err(anyhow!(
216 "Expected numeric operand, found {}~{}",
217 found,
218 self.to_formula(),
219 )),
220 }
221 }
222 Unary::CastBool(operand) => {
223 let val = operand.evaluate(context)?;
224 if val.is_error() {
225 return Ok(val);
226 }
227 Ok(val.as_bool())
228 }
229 Unary::CastDate(operand) => {
230 let val = operand.evaluate(context)?;
231 if val.is_error() {
232 return Ok(val);
233 }
234 val.as_date()
235 }
236 Unary::CastNumber(operand) => {
237 let val = operand.evaluate(context)?;
238 if val.is_error() {
239 return Ok(val);
240 }
241 val.as_number()
242 }
243 Unary::CastTask(operand) => {
244 let val = operand.evaluate(context)?;
245 if val.is_error() {
246 return Ok(val);
247 }
248 val.as_task()
249 }
250 Unary::CastText(operand) => {
251 let val = operand.evaluate(context)?;
252 if val.is_error() {
253 return Ok(val);
254 }
255 val.as_text()
256 }
257 Unary::Primary(primary) => primary.evaluate(context),
258 }
259 }
260
261 fn to_formula(&self) -> String {
263 let mut writer = Writer::formulizer();
264 self.print(&mut writer);
265 writer.finish()
266 }
267}
268
269impl WriterLike for Unary {
270 fn write(&self, writer: &mut Writer) {
271 self.print(writer);
272 }
273}
274
275impl fmt::Display for Unary {
276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277 write!(f, "{}", self.to_stringized())
278 }
279}