expr/ast/
postfix_operator.rs
1use std::iter::once;
2use crate::ast::node::Node;
3use crate::Rule;
4use crate::{bail, Result};
5use crate::{Context, Parser, Value};
6use log::trace;
7use pest::iterators::Pair;
8
9#[derive(Debug, Clone, strum::Display)]
10pub enum PostfixOperator {
11 Index { idx: Box<Node>, optional: bool },
12 Range(Option<i64>, Option<i64>),
13 Default(Box<Node>),
14 Pipe(Box<Node>),
15 Ternary { left: Box<Node>, right: Box<Node> },
16}
17
18impl From<Pair<'_, Rule>> for PostfixOperator {
19 fn from(pair: Pair<Rule>) -> Self {
20 trace!("{:?}={}", pair.as_rule(), pair.as_str());
21 match pair.as_rule() {
22 Rule::index_op | Rule::membership_op => PostfixOperator::Index {
23 idx: Box::new(pair.into_inner().into()),
24 optional: false,
25 },
26 Rule::opt_index_op | Rule::opt_membership_op => PostfixOperator::Index {
27 idx: Box::new(pair.into_inner().into()),
28 optional: true,
29 },
30 Rule::range_start_op => {
31 let mut inner = pair.into_inner();
32 let start = inner.next().map(|p| p.as_str().parse().unwrap());
33 let end = inner.next().map(|p| p.as_str().parse().unwrap());
34 PostfixOperator::Range(start, end)
35 }
36 Rule::range_end_op => {
37 let mut inner = pair.into_inner();
38 let end = inner.next().map(|p| p.as_str().parse().unwrap());
39 PostfixOperator::Range(None, end)
40 }
41 Rule::default_op => PostfixOperator::Default(Box::new(pair.into_inner().into())),
42 Rule::ternary => {
43 let mut inner = pair.into_inner();
44 let left = Box::new(inner.next().unwrap().into());
45 let right = Box::new(inner.next().unwrap().into());
46 PostfixOperator::Ternary { left, right }
47 }
48 Rule::pipe => PostfixOperator::Pipe(Box::new(pair.into_inner().into())),
49 rule => unreachable!("Unexpected rule: {rule:?}"),
50 }
51 }
52}
53
54impl Parser<'_> {
55 pub fn eval_postfix_operator(
56 &self,
57 ctx: &Context,
58 operator: PostfixOperator,
59 node: Node,
60 ) -> Result<Value> {
61 let value = self.eval_expr(ctx, node)?;
62 let result = match operator {
63 PostfixOperator::Index { idx, optional } => match self.eval_index_key(ctx, *idx)? {
64 Value::Number(idx) => match value {
65 Value::Array(arr) => {
66 let idx = i64_to_idx(idx, arr.len());
67 arr.get(idx).cloned().unwrap_or(Value::Nil)
68 }
69 _ if optional => Value::Nil,
70 _ => bail!("Invalid operand for operator []"),
71 },
72 Value::String(key) => match value {
73 Value::Map(map) => map.get(&key).cloned().unwrap_or(Value::Nil),
74 _ if optional => Value::Nil,
75 _ => bail!("Invalid operand for operator []"),
76 },
77 v => bail!("Invalid operand for operator []: {v:?}"),
78 },
79 PostfixOperator::Range(start, end) => match value {
80 Value::Array(arr) => {
81 let start = i64_to_idx(start.unwrap_or(0), arr.len());
82 let end = i64_to_idx(end.unwrap_or(arr.len() as i64), arr.len());
83 let result = arr[start..end].to_vec();
84 Value::Array(result)
85 }
86 _ => bail!("Invalid operand for operator []"),
87 },
88 PostfixOperator::Default(default) => match value {
89 Value::Nil => self.eval_expr(ctx, *default)?,
90 value => value,
91 },
92 PostfixOperator::Ternary { left, right } => match value {
93 Value::Bool(true) => self.eval_expr(ctx, *left)?,
94 Value::Bool(false) => self.eval_expr(ctx, *right)?,
95 value => bail!("Invalid condition for ?: {value:?}"),
96 },
97 PostfixOperator::Pipe(func) => {
98 if let Node::Func {
99 ident,
100 args,
101 predicate,
102 } = *func
103 {
104 let args = args.into_iter()
105 .map(|arg| self.eval_expr(ctx, arg))
106 .chain(once(Ok(value)))
107 .collect::<Result<Vec<Value>>>()?;
108 self.exec_func(ctx, ident, args, predicate.map(|p| *p))?
109 } else {
110 bail!("Invalid operand for operator |");
111 }
112 }
113 };
114
115 Ok(result)
116 }
117
118 fn eval_index_key(&self, ctx: &Context, idx: Node) -> Result<Value> {
119 match idx {
120 Node::Value(v) => Ok(v),
121 Node::Ident(id) => Ok(Value::String(id)),
122 idx => self.eval_expr(ctx, idx),
123 }
124 }
125}
126
127fn i64_to_idx(idx: i64, len: usize) -> usize {
128 if idx < 0 {
129 (len as i64 + idx) as usize
130 } else {
131 idx as usize
132 }
133}