1use super::utils::unwrap_or_clone;
18use super::EstToAstError;
19use crate::ast;
20use crate::entities::{JSONValue, JsonDeserializationError, TypeAndId};
21use crate::parser::cst;
22use crate::parser::err::{ParseError, ParseErrors};
23use crate::parser::unescape;
24use crate::parser::ASTNode;
25use either::Either;
26use serde::{Deserialize, Serialize};
27use smol_str::SmolStr;
28use std::collections::HashMap;
29use std::sync::Arc;
30
31#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
33#[serde(untagged)]
34pub enum Expr {
35 ExprNoExt(ExprNoExt),
38 ExtFuncCall(ExtFuncCall),
42}
43
44#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
47#[serde(deny_unknown_fields)]
48pub enum ExprNoExt {
49 Value(JSONValue),
52 Var(ast::Var),
54 Slot(ast::SlotId),
56 Unknown {
58 name: SmolStr,
60 },
61 #[serde(rename = "!")]
63 Not {
64 arg: Arc<Expr>,
66 },
67 #[serde(rename = "neg")]
69 Neg {
70 arg: Arc<Expr>,
72 },
73 #[serde(rename = "==")]
75 Eq {
76 left: Arc<Expr>,
78 right: Arc<Expr>,
80 },
81 #[serde(rename = "!=")]
83 NotEq {
84 left: Arc<Expr>,
86 right: Arc<Expr>,
88 },
89 #[serde(rename = "in")]
91 In {
92 left: Arc<Expr>,
94 right: Arc<Expr>,
96 },
97 #[serde(rename = "<")]
99 Less {
100 left: Arc<Expr>,
102 right: Arc<Expr>,
104 },
105 #[serde(rename = "<=")]
107 LessEq {
108 left: Arc<Expr>,
110 right: Arc<Expr>,
112 },
113 #[serde(rename = ">")]
115 Greater {
116 left: Arc<Expr>,
118 right: Arc<Expr>,
120 },
121 #[serde(rename = ">=")]
123 GreaterEq {
124 left: Arc<Expr>,
126 right: Arc<Expr>,
128 },
129 #[serde(rename = "&&")]
131 And {
132 left: Arc<Expr>,
134 right: Arc<Expr>,
136 },
137 #[serde(rename = "||")]
139 Or {
140 left: Arc<Expr>,
142 right: Arc<Expr>,
144 },
145 #[serde(rename = "+")]
147 Add {
148 left: Arc<Expr>,
150 right: Arc<Expr>,
152 },
153 #[serde(rename = "-")]
155 Sub {
156 left: Arc<Expr>,
158 right: Arc<Expr>,
160 },
161 #[serde(rename = "*")]
163 Mul {
164 left: Arc<Expr>,
166 right: Arc<Expr>,
168 },
169 #[serde(rename = "contains")]
171 Contains {
172 left: Arc<Expr>,
174 right: Arc<Expr>,
176 },
177 #[serde(rename = "containsAll")]
179 ContainsAll {
180 left: Arc<Expr>,
182 right: Arc<Expr>,
184 },
185 #[serde(rename = "containsAny")]
187 ContainsAny {
188 left: Arc<Expr>,
190 right: Arc<Expr>,
192 },
193 #[serde(rename = ".")]
195 GetAttr {
196 left: Arc<Expr>,
198 attr: SmolStr,
200 },
201 #[serde(rename = "has")]
203 HasAttr {
204 left: Arc<Expr>,
206 attr: SmolStr,
208 },
209 #[serde(rename = "like")]
211 Like {
212 left: Arc<Expr>,
214 pattern: SmolStr,
216 },
217 #[serde(rename = "if-then-else")]
219 If {
220 #[serde(rename = "if")]
222 cond_expr: Arc<Expr>,
223 #[serde(rename = "then")]
225 then_expr: Arc<Expr>,
226 #[serde(rename = "else")]
228 else_expr: Arc<Expr>,
229 },
230 Set(Vec<Expr>),
234 Record(HashMap<SmolStr, Expr>),
238}
239
240#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
242pub struct ExtFuncCall {
243 #[serde(flatten)]
251 call: HashMap<SmolStr, Vec<Expr>>,
252}
253
254#[allow(clippy::should_implement_trait)] impl Expr {
256 pub fn lit(lit: JSONValue) -> Self {
258 Expr::ExprNoExt(ExprNoExt::Value(lit))
259 }
260
261 pub fn var(var: ast::Var) -> Self {
263 Expr::ExprNoExt(ExprNoExt::Var(var))
264 }
265
266 pub fn slot(slot: ast::SlotId) -> Self {
268 Expr::ExprNoExt(ExprNoExt::Slot(slot))
269 }
270
271 pub fn unknown(name: impl Into<SmolStr>) -> Self {
273 Expr::ExprNoExt(ExprNoExt::Unknown { name: name.into() })
274 }
275
276 pub fn not(e: Expr) -> Self {
278 Expr::ExprNoExt(ExprNoExt::Not { arg: Arc::new(e) })
279 }
280
281 pub fn neg(e: Expr) -> Self {
283 Expr::ExprNoExt(ExprNoExt::Neg { arg: Arc::new(e) })
284 }
285
286 pub fn eq(left: Expr, right: Expr) -> Self {
288 Expr::ExprNoExt(ExprNoExt::Eq {
289 left: Arc::new(left),
290 right: Arc::new(right),
291 })
292 }
293
294 pub fn noteq(left: Expr, right: Expr) -> Self {
296 Expr::ExprNoExt(ExprNoExt::NotEq {
297 left: Arc::new(left),
298 right: Arc::new(right),
299 })
300 }
301
302 pub fn _in(left: Expr, right: Expr) -> Self {
304 Expr::ExprNoExt(ExprNoExt::In {
305 left: Arc::new(left),
306 right: Arc::new(right),
307 })
308 }
309
310 pub fn less(left: Expr, right: Expr) -> Self {
312 Expr::ExprNoExt(ExprNoExt::Less {
313 left: Arc::new(left),
314 right: Arc::new(right),
315 })
316 }
317
318 pub fn lesseq(left: Expr, right: Expr) -> Self {
320 Expr::ExprNoExt(ExprNoExt::LessEq {
321 left: Arc::new(left),
322 right: Arc::new(right),
323 })
324 }
325
326 pub fn greater(left: Expr, right: Expr) -> Self {
328 Expr::ExprNoExt(ExprNoExt::Greater {
329 left: Arc::new(left),
330 right: Arc::new(right),
331 })
332 }
333
334 pub fn greatereq(left: Expr, right: Expr) -> Self {
336 Expr::ExprNoExt(ExprNoExt::GreaterEq {
337 left: Arc::new(left),
338 right: Arc::new(right),
339 })
340 }
341
342 pub fn and(left: Expr, right: Expr) -> Self {
344 Expr::ExprNoExt(ExprNoExt::And {
345 left: Arc::new(left),
346 right: Arc::new(right),
347 })
348 }
349
350 pub fn or(left: Expr, right: Expr) -> Self {
352 Expr::ExprNoExt(ExprNoExt::Or {
353 left: Arc::new(left),
354 right: Arc::new(right),
355 })
356 }
357
358 pub fn add(left: Expr, right: Expr) -> Self {
360 Expr::ExprNoExt(ExprNoExt::Add {
361 left: Arc::new(left),
362 right: Arc::new(right),
363 })
364 }
365
366 pub fn sub(left: Expr, right: Expr) -> Self {
368 Expr::ExprNoExt(ExprNoExt::Sub {
369 left: Arc::new(left),
370 right: Arc::new(right),
371 })
372 }
373
374 pub fn mul(left: Expr, right: Expr) -> Self {
376 Expr::ExprNoExt(ExprNoExt::Mul {
377 left: Arc::new(left),
378 right: Arc::new(right),
379 })
380 }
381
382 pub fn contains(left: Arc<Expr>, right: Expr) -> Self {
384 Expr::ExprNoExt(ExprNoExt::Contains {
385 left,
386 right: Arc::new(right),
387 })
388 }
389
390 pub fn contains_all(left: Arc<Expr>, right: Expr) -> Self {
392 Expr::ExprNoExt(ExprNoExt::ContainsAll {
393 left,
394 right: Arc::new(right),
395 })
396 }
397
398 pub fn contains_any(left: Arc<Expr>, right: Expr) -> Self {
400 Expr::ExprNoExt(ExprNoExt::ContainsAny {
401 left,
402 right: Arc::new(right),
403 })
404 }
405
406 pub fn get_attr(left: Expr, attr: SmolStr) -> Self {
408 Expr::ExprNoExt(ExprNoExt::GetAttr {
409 left: Arc::new(left),
410 attr,
411 })
412 }
413
414 pub fn has_attr(left: Expr, attr: SmolStr) -> Self {
416 Expr::ExprNoExt(ExprNoExt::HasAttr {
417 left: Arc::new(left),
418 attr,
419 })
420 }
421
422 pub fn like(left: Expr, pattern: SmolStr) -> Self {
424 Expr::ExprNoExt(ExprNoExt::Like {
425 left: Arc::new(left),
426 pattern,
427 })
428 }
429
430 pub fn ite(cond_expr: Expr, then_expr: Expr, else_expr: Expr) -> Self {
432 Expr::ExprNoExt(ExprNoExt::If {
433 cond_expr: Arc::new(cond_expr),
434 then_expr: Arc::new(then_expr),
435 else_expr: Arc::new(else_expr),
436 })
437 }
438
439 pub fn set(elements: Vec<Expr>) -> Self {
441 Expr::ExprNoExt(ExprNoExt::Set(elements))
442 }
443
444 pub fn record(map: HashMap<SmolStr, Expr>) -> Self {
446 Expr::ExprNoExt(ExprNoExt::Record(map))
447 }
448
449 pub fn ext_call(fn_name: SmolStr, args: Vec<Expr>) -> Self {
451 Expr::ExtFuncCall(ExtFuncCall {
452 call: [(fn_name, args)].into_iter().collect(),
453 })
454 }
455
456 pub fn into_string_literal(self) -> Option<SmolStr> {
458 match self {
459 Expr::ExprNoExt(ExprNoExt::Value(JSONValue::String(s))) => Some(s),
460 _ => None,
461 }
462 }
463}
464
465impl TryFrom<Expr> for ast::Expr {
466 type Error = EstToAstError;
467 fn try_from(expr: Expr) -> Result<ast::Expr, EstToAstError> {
468 match expr {
469 Expr::ExprNoExt(ExprNoExt::Value(jsonvalue)) => {
470 jsonvalue.into_expr().map(Into::into).map_err(Into::into)
471 }
472 Expr::ExprNoExt(ExprNoExt::Var(var)) => Ok(ast::Expr::var(var)),
473 Expr::ExprNoExt(ExprNoExt::Slot(slot)) => Ok(ast::Expr::slot(slot)),
474 Expr::ExprNoExt(ExprNoExt::Unknown { name }) => Ok(ast::Expr::unknown(name)),
475 Expr::ExprNoExt(ExprNoExt::Not { arg }) => {
476 Ok(ast::Expr::not((*arg).clone().try_into()?))
477 }
478 Expr::ExprNoExt(ExprNoExt::Neg { arg }) => {
479 Ok(ast::Expr::neg((*arg).clone().try_into()?))
480 }
481 Expr::ExprNoExt(ExprNoExt::Eq { left, right }) => Ok(ast::Expr::is_eq(
482 (*left).clone().try_into()?,
483 (*right).clone().try_into()?,
484 )),
485 Expr::ExprNoExt(ExprNoExt::NotEq { left, right }) => Ok(ast::Expr::noteq(
486 (*left).clone().try_into()?,
487 (*right).clone().try_into()?,
488 )),
489 Expr::ExprNoExt(ExprNoExt::In { left, right }) => Ok(ast::Expr::is_in(
490 (*left).clone().try_into()?,
491 (*right).clone().try_into()?,
492 )),
493 Expr::ExprNoExt(ExprNoExt::Less { left, right }) => Ok(ast::Expr::less(
494 (*left).clone().try_into()?,
495 (*right).clone().try_into()?,
496 )),
497 Expr::ExprNoExt(ExprNoExt::LessEq { left, right }) => Ok(ast::Expr::lesseq(
498 (*left).clone().try_into()?,
499 (*right).clone().try_into()?,
500 )),
501 Expr::ExprNoExt(ExprNoExt::Greater { left, right }) => Ok(ast::Expr::greater(
502 (*left).clone().try_into()?,
503 (*right).clone().try_into()?,
504 )),
505 Expr::ExprNoExt(ExprNoExt::GreaterEq { left, right }) => Ok(ast::Expr::greatereq(
506 (*left).clone().try_into()?,
507 (*right).clone().try_into()?,
508 )),
509 Expr::ExprNoExt(ExprNoExt::And { left, right }) => Ok(ast::Expr::and(
510 (*left).clone().try_into()?,
511 (*right).clone().try_into()?,
512 )),
513 Expr::ExprNoExt(ExprNoExt::Or { left, right }) => Ok(ast::Expr::or(
514 (*left).clone().try_into()?,
515 (*right).clone().try_into()?,
516 )),
517 Expr::ExprNoExt(ExprNoExt::Add { left, right }) => Ok(ast::Expr::add(
518 (*left).clone().try_into()?,
519 (*right).clone().try_into()?,
520 )),
521 Expr::ExprNoExt(ExprNoExt::Sub { left, right }) => Ok(ast::Expr::sub(
522 (*left).clone().try_into()?,
523 (*right).clone().try_into()?,
524 )),
525 Expr::ExprNoExt(ExprNoExt::Mul { left, right }) => {
526 let left: ast::Expr = (*left).clone().try_into()?;
527 let right: ast::Expr = (*right).clone().try_into()?;
528 let left_c = match left.expr_kind() {
529 ast::ExprKind::Lit(ast::Literal::Long(c)) => Some(c),
530 _ => None,
531 };
532 let right_c = match right.expr_kind() {
533 ast::ExprKind::Lit(ast::Literal::Long(c)) => Some(c),
534 _ => None,
535 };
536 match (left_c, right_c) {
537 (_, Some(c)) => Ok(ast::Expr::mul(left, *c)),
538 (Some(c), _) => Ok(ast::Expr::mul(right, *c)),
539 (None, None) => Err(EstToAstError::MultiplicationByNonConstant {
540 arg1: left,
541 arg2: right,
542 })?,
543 }
544 }
545 Expr::ExprNoExt(ExprNoExt::Contains { left, right }) => Ok(ast::Expr::contains(
546 (*left).clone().try_into()?,
547 (*right).clone().try_into()?,
548 )),
549 Expr::ExprNoExt(ExprNoExt::ContainsAll { left, right }) => Ok(ast::Expr::contains_all(
550 (*left).clone().try_into()?,
551 (*right).clone().try_into()?,
552 )),
553 Expr::ExprNoExt(ExprNoExt::ContainsAny { left, right }) => Ok(ast::Expr::contains_any(
554 (*left).clone().try_into()?,
555 (*right).clone().try_into()?,
556 )),
557 Expr::ExprNoExt(ExprNoExt::GetAttr { left, attr }) => {
558 Ok(ast::Expr::get_attr((*left).clone().try_into()?, attr))
559 }
560 Expr::ExprNoExt(ExprNoExt::HasAttr { left, attr }) => {
561 Ok(ast::Expr::has_attr((*left).clone().try_into()?, attr))
562 }
563 Expr::ExprNoExt(ExprNoExt::Like { left, pattern }) => {
564 match unescape::to_pattern(&pattern) {
565 Ok(pattern) => Ok(ast::Expr::like((*left).clone().try_into()?, pattern)),
566 Err(errs) => Err(EstToAstError::UnescapeError(errs)),
567 }
568 }
569 Expr::ExprNoExt(ExprNoExt::If {
570 cond_expr,
571 then_expr,
572 else_expr,
573 }) => Ok(ast::Expr::ite(
574 (*cond_expr).clone().try_into()?,
575 (*then_expr).clone().try_into()?,
576 (*else_expr).clone().try_into()?,
577 )),
578 Expr::ExprNoExt(ExprNoExt::Set(elements)) => Ok(ast::Expr::set(
579 elements
580 .into_iter()
581 .map(|el| el.try_into())
582 .collect::<Result<Vec<_>, EstToAstError>>()?,
583 )),
584 Expr::ExprNoExt(ExprNoExt::Record(map)) => Ok(ast::Expr::record(
585 map.into_iter()
586 .map(|(k, v)| Ok((k, v.try_into()?)))
587 .collect::<Result<HashMap<SmolStr, _>, EstToAstError>>()?,
588 )),
589 Expr::ExtFuncCall(ExtFuncCall { call }) => {
590 match call.len() {
591 0 => Err(EstToAstError::MissingOperator),
592 1 => {
593 let (fn_name, args) = call
594 .into_iter()
595 .next()
596 .expect("already checked that len was 1");
597 let fn_name = fn_name.parse().map_err(|errs|
598 JsonDeserializationError::ExtnParseError(ParseError::WithContext {
599 context: format!("expected valid operator or extension function name; got {fn_name}"),
600 errs,
601 })
602 )?;
603 Ok(ast::Expr::call_extension_fn(
604 fn_name,
605 args.into_iter()
606 .map(TryInto::try_into)
607 .collect::<Result<_, _>>()?,
608 ))
609 }
610 _ => Err(EstToAstError::MultipleOperators {
611 ops: call.into_keys().collect(),
612 }),
613 }
614 }
615 }
616 }
617}
618
619impl From<ast::Expr> for Expr {
620 fn from(expr: ast::Expr) -> Expr {
621 match expr.into_expr_kind() {
622 ast::ExprKind::Lit(lit) => lit.into(),
623 ast::ExprKind::Var(var) => var.into(),
624 ast::ExprKind::Slot(slot) => slot.into(),
625 ast::ExprKind::Unknown { name, .. } => Expr::unknown(name),
626 ast::ExprKind::If {
627 test_expr,
628 then_expr,
629 else_expr,
630 } => Expr::ite(
631 unwrap_or_clone(test_expr).into(),
632 unwrap_or_clone(then_expr).into(),
633 unwrap_or_clone(else_expr).into(),
634 ),
635 ast::ExprKind::And { left, right } => {
636 Expr::and(unwrap_or_clone(left).into(), unwrap_or_clone(right).into())
637 }
638 ast::ExprKind::Or { left, right } => {
639 Expr::or(unwrap_or_clone(left).into(), unwrap_or_clone(right).into())
640 }
641 ast::ExprKind::UnaryApp { op, arg } => {
642 let arg = unwrap_or_clone(arg).into();
643 match op {
644 ast::UnaryOp::Not => Expr::not(arg),
645 ast::UnaryOp::Neg => Expr::neg(arg),
646 }
647 }
648 ast::ExprKind::BinaryApp { op, arg1, arg2 } => {
649 let arg1 = unwrap_or_clone(arg1).into();
650 let arg2 = unwrap_or_clone(arg2).into();
651 match op {
652 ast::BinaryOp::Eq => Expr::eq(arg1, arg2),
653 ast::BinaryOp::In => Expr::_in(arg1, arg2),
654 ast::BinaryOp::Less => Expr::less(arg1, arg2),
655 ast::BinaryOp::LessEq => Expr::lesseq(arg1, arg2),
656 ast::BinaryOp::Add => Expr::add(arg1, arg2),
657 ast::BinaryOp::Sub => Expr::sub(arg1, arg2),
658 ast::BinaryOp::Contains => Expr::contains(Arc::new(arg1), arg2),
659 ast::BinaryOp::ContainsAll => Expr::contains_all(Arc::new(arg1), arg2),
660 ast::BinaryOp::ContainsAny => Expr::contains_any(Arc::new(arg1), arg2),
661 }
662 }
663 ast::ExprKind::MulByConst { arg, constant } => Expr::mul(
664 unwrap_or_clone(arg).into(),
665 Expr::lit(JSONValue::Long(constant)),
666 ),
667 ast::ExprKind::ExtensionFunctionApp {
668 op: ast::ExtensionFunctionOp { function_name },
669 args,
670 } => {
671 let args = unwrap_or_clone(args).into_iter().map(Into::into).collect();
672 Expr::ext_call(function_name.to_string().into(), args)
673 }
674 ast::ExprKind::GetAttr { expr, attr } => {
675 Expr::get_attr(unwrap_or_clone(expr).into(), attr)
676 }
677 ast::ExprKind::HasAttr { expr, attr } => {
678 Expr::has_attr(unwrap_or_clone(expr).into(), attr)
679 }
680 ast::ExprKind::Like { expr, pattern } => {
681 Expr::like(unwrap_or_clone(expr).into(), pattern.to_string().into())
682 }
683 ast::ExprKind::Set(set) => {
684 Expr::set(unwrap_or_clone(set).into_iter().map(Into::into).collect())
685 }
686 ast::ExprKind::Record { pairs } => Expr::record(
687 unwrap_or_clone(pairs)
688 .into_iter()
689 .map(|(k, v)| (k, v.into()))
690 .collect(),
691 ),
692 }
693 }
694}
695
696impl From<ast::Literal> for Expr {
697 fn from(lit: ast::Literal) -> Expr {
698 Expr::lit(JSONValue::from_lit(lit))
699 }
700}
701
702impl From<ast::Var> for Expr {
703 fn from(var: ast::Var) -> Expr {
704 Expr::var(var)
705 }
706}
707
708impl From<ast::SlotId> for Expr {
709 fn from(slot: ast::SlotId) -> Expr {
710 Expr::slot(slot)
711 }
712}
713
714impl TryFrom<cst::Expr> for Expr {
715 type Error = ParseErrors;
716 fn try_from(e: cst::Expr) -> Result<Expr, ParseErrors> {
717 match *e.expr {
718 cst::ExprData::Or(ASTNode { node, .. }) => match node {
719 Some(o) => o.try_into(),
720 None => Err(ParseError::ToAST("data should not be empty".to_string()).into()),
721 },
722 cst::ExprData::If(
723 ASTNode { node: if_node, .. },
724 ASTNode {
725 node: then_node, ..
726 },
727 ASTNode {
728 node: else_node, ..
729 },
730 ) => match (if_node, then_node, else_node) {
731 (Some(if_node), Some(then_node), Some(else_node)) => {
732 let cond_expr = if_node.try_into()?;
733 let then_expr = then_node.try_into()?;
734 let else_expr = else_node.try_into()?;
735 Ok(Expr::ite(cond_expr, then_expr, else_expr))
736 }
737 (_, _, _) => Err(ParseError::ToAST("data should not be empty".to_string()).into()),
738 },
739 }
740 }
741}
742
743impl TryFrom<cst::Or> for Expr {
744 type Error = ParseErrors;
745 fn try_from(o: cst::Or) -> Result<Expr, ParseErrors> {
746 let mut expr = match o.initial.node {
747 Some(a) => a.try_into(),
748 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
749 }?;
750 for node in o.extended {
751 let rhs = match node.node {
752 Some(a) => a.try_into(),
753 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
754 }?;
755 expr = Expr::or(expr, rhs);
756 }
757 Ok(expr)
758 }
759}
760
761impl TryFrom<cst::And> for Expr {
762 type Error = ParseErrors;
763 fn try_from(a: cst::And) -> Result<Expr, ParseErrors> {
764 let mut expr = match a.initial.node {
765 Some(r) => r.try_into(),
766 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
767 }?;
768 for node in a.extended {
769 let rhs = match node.node {
770 Some(r) => r.try_into(),
771 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
772 }?;
773 expr = Expr::and(expr, rhs);
774 }
775 Ok(expr)
776 }
777}
778
779impl TryFrom<cst::Relation> for Expr {
780 type Error = ParseErrors;
781 fn try_from(r: cst::Relation) -> Result<Expr, ParseErrors> {
782 match r {
783 cst::Relation::Common { initial, extended } => {
784 let mut expr = match initial.node {
785 Some(a) => a.try_into(),
786 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
787 }?;
788 for (op, ASTNode { node, .. }) in extended {
789 let rhs = match node {
790 Some(a) => a.try_into(),
791 None => {
792 Err(ParseError::ToAST("node should not be empty".to_string()).into())
793 }
794 }?;
795 match op {
796 cst::RelOp::Eq => {
797 expr = Expr::eq(expr, rhs);
798 }
799 cst::RelOp::NotEq => {
800 expr = Expr::noteq(expr, rhs);
801 }
802 cst::RelOp::In => {
803 expr = Expr::_in(expr, rhs);
804 }
805 cst::RelOp::Less => {
806 expr = Expr::less(expr, rhs);
807 }
808 cst::RelOp::LessEq => {
809 expr = Expr::lesseq(expr, rhs);
810 }
811 cst::RelOp::Greater => {
812 expr = Expr::greater(expr, rhs);
813 }
814 cst::RelOp::GreaterEq => {
815 expr = Expr::greatereq(expr, rhs);
816 }
817 }
818 }
819 Ok(expr)
820 }
821 cst::Relation::Has { target, field } => match (target, field) {
822 (
823 ASTNode {
824 node: Some(target), ..
825 },
826 ASTNode {
827 node: Some(field), ..
828 },
829 ) => {
830 let target_expr = target.try_into()?;
831 match Expr::try_from(field.clone()) {
832 Ok(field_expr) => {
833 let field_str = field_expr.into_string_literal().ok_or_else(|| {
834 ParseError::ToAST(
835 "`has` RHS should be a string literal".to_string(),
836 )
837 })?;
838 Ok(Expr::has_attr(target_expr, field_str))
839 }
840 Err(_) => match is_add_name(field) {
841 Some(name) => Ok(Expr::has_attr(target_expr, name.to_string().into())),
842 None => Err(ParseError::ToAST(
843 "`has` RHS should be an attribute name or string literal"
844 .to_string(),
845 )
846 .into()),
847 },
848 }
849 }
850 (_, _) => Err(ParseError::ToAST("data should not be empty".to_string()).into()),
851 },
852 cst::Relation::Like { target, pattern } => match (target, pattern) {
853 (
854 ASTNode {
855 node: Some(target), ..
856 },
857 ASTNode {
858 node: Some(pattern),
859 ..
860 },
861 ) => {
862 let target_expr = target.try_into()?;
863 let pat_expr: Expr = pattern.try_into()?;
864 let pat_str = pat_expr.into_string_literal().ok_or_else(|| {
865 ParseError::ToAST("`like` RHS should be a string literal".to_string())
866 })?;
867 Ok(Expr::like(target_expr, pat_str))
868 }
869 (_, _) => Err(ParseError::ToAST("data should not be empty".to_string()).into()),
870 },
871 }
872 }
873}
874
875impl TryFrom<cst::Add> for Expr {
876 type Error = ParseErrors;
877 fn try_from(a: cst::Add) -> Result<Expr, ParseErrors> {
878 let mut expr = match a.initial.node {
879 Some(m) => m.try_into(),
880 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
881 }?;
882 for (op, node) in a.extended {
883 let rhs = match node.node {
884 Some(m) => m.try_into(),
885 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
886 }?;
887 match op {
888 cst::AddOp::Plus => {
889 expr = Expr::add(expr, rhs);
890 }
891 cst::AddOp::Minus => {
892 expr = Expr::sub(expr, rhs);
893 }
894 }
895 }
896 Ok(expr)
897 }
898}
899
900fn is_add_name(add: cst::Add) -> Option<cst::Name> {
903 if add.extended.is_empty() {
904 match add.initial.node {
905 Some(mult) => is_mult_name(mult),
906 None => None,
907 }
908 } else {
909 None
910 }
911}
912
913fn is_mult_name(mult: cst::Mult) -> Option<cst::Name> {
916 if mult.extended.is_empty() {
917 match mult.initial.node {
918 Some(unary) => is_unary_name(unary),
919 None => None,
920 }
921 } else {
922 None
923 }
924}
925
926fn is_unary_name(unary: cst::Unary) -> Option<cst::Name> {
929 if unary.op.is_none() {
930 match unary.item.node {
931 Some(mem) => is_mem_name(mem),
932 None => None,
933 }
934 } else {
935 None
936 }
937}
938
939fn is_mem_name(mem: cst::Member) -> Option<cst::Name> {
942 if mem.access.is_empty() {
943 match mem.item.node {
944 Some(primary) => is_primary_name(primary),
945 None => None,
946 }
947 } else {
948 None
949 }
950}
951
952fn is_primary_name(primary: cst::Primary) -> Option<cst::Name> {
955 match primary {
956 cst::Primary::Name(node) => node.node,
957 _ => None,
958 }
959}
960
961impl TryFrom<cst::Mult> for Expr {
962 type Error = ParseErrors;
963 fn try_from(m: cst::Mult) -> Result<Expr, ParseErrors> {
964 let mut expr = match m.initial.node {
965 Some(u) => u.try_into(),
966 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
967 }?;
968 for (op, node) in m.extended {
969 let rhs = match node.node {
970 Some(u) => u.try_into(),
971 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
972 }?;
973 match op {
974 cst::MultOp::Times => {
975 expr = Expr::mul(expr, rhs);
976 }
977 cst::MultOp::Divide => {
978 return Err(ParseError::ToAST("division is not supported".to_string()).into())
979 }
980 cst::MultOp::Mod => {
981 return Err(ParseError::ToAST("modulo is not supported".to_string()).into())
982 }
983 }
984 }
985 Ok(expr)
986 }
987}
988
989impl TryFrom<cst::Unary> for Expr {
990 type Error = ParseErrors;
991 fn try_from(u: cst::Unary) -> Result<Expr, ParseErrors> {
992 let inner = match u.item.node {
993 Some(m) => m.try_into(),
994 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
995 }?;
996 match u.op {
997 Some(cst::NegOp::Bang(0)) => Ok(inner),
998 Some(cst::NegOp::Bang(1)) => Ok(Expr::not(inner)),
999 Some(cst::NegOp::Bang(2)) => {
1000 Ok(Expr::not(Expr::not(inner)))
1002 }
1003 Some(cst::NegOp::Bang(n)) => {
1004 if n % 2 == 0 {
1005 Ok(Expr::not(Expr::not(inner)))
1007 } else {
1008 Ok(Expr::not(inner))
1010 }
1011 }
1012 Some(cst::NegOp::Dash(0)) => Ok(inner),
1013 Some(cst::NegOp::Dash(mut num_dashes)) => {
1014 let inner = match inner {
1015 Expr::ExprNoExt(ExprNoExt::Value(JSONValue::Long(n))) if n != std::i64::MIN => {
1016 num_dashes -= 1;
1019 Expr::lit(JSONValue::Long(-n))
1020 }
1021 _ => inner,
1022 };
1023 match num_dashes {
1024 0 => Ok(inner),
1025 1 => Ok(Expr::neg(inner)),
1026 2 => {
1027 Ok(Expr::neg(Expr::neg(inner)))
1029 }
1030 n => {
1031 if n % 2 == 0 {
1032 Ok(Expr::neg(Expr::neg(inner)))
1034 } else {
1035 Ok(Expr::neg(inner))
1037 }
1038 }
1039 }
1040 }
1041 Some(cst::NegOp::OverBang) => Err(ParseError::ToAST("Too many !'s".to_string()).into()),
1042 Some(cst::NegOp::OverDash) => Err(ParseError::ToAST("Too many -'s".to_string()).into()),
1043 None => Ok(inner),
1044 }
1045 }
1046}
1047
1048fn interpret_primary(p: cst::Primary) -> Result<Either<ast::Name, Expr>, ParseErrors> {
1055 match p {
1056 cst::Primary::Literal(ASTNode { node, .. }) => match node {
1057 Some(lit) => Ok(Either::Right(lit.try_into()?)),
1058 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
1059 },
1060 cst::Primary::Ref(ASTNode { node, .. }) => match node {
1061 Some(cst::Ref::Uid { path, eid }) => {
1062 let mut errs = vec![];
1063 let maybe_name = path.to_name(&mut errs);
1064 let maybe_eid = eid.as_valid_string(&mut errs);
1065
1066 if errs.is_empty() {
1067 let name = maybe_name.expect("should be Some since errs.is_empty()");
1068 let eid = maybe_eid.expect("should be Some since errs.is_empty()");
1069 Ok(Either::Right(Expr::lit(JSONValue::EntityEscape {
1070 __entity: TypeAndId::from(ast::EntityUID::from_components(
1071 name,
1072 ast::Eid::new(eid.clone()),
1073 )),
1074 })))
1075 } else {
1076 Err(ParseErrors(errs))
1077 }
1078 }
1079 Some(cst::Ref::Ref { .. }) => {
1080 Err(ParseError::ToAST("entity-lookup syntax is not supported".to_string()).into())
1081 }
1082 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
1083 },
1084 cst::Primary::Name(ASTNode { node, .. }) => match node {
1085 Some(name) => match (&name.path[..], name.name.node) {
1086 (&[], Some(cst::Ident::Principal)) => {
1087 Ok(Either::Right(Expr::var(ast::Var::Principal)))
1088 }
1089 (&[], Some(cst::Ident::Action)) => Ok(Either::Right(Expr::var(ast::Var::Action))),
1090 (&[], Some(cst::Ident::Resource)) => {
1091 Ok(Either::Right(Expr::var(ast::Var::Resource)))
1092 }
1093 (&[], Some(cst::Ident::Context)) => Ok(Either::Right(Expr::var(ast::Var::Context))),
1094 (path, Some(cst::Ident::Ident(id))) => Ok(Either::Left(ast::Name::new(
1095 id.parse().map_err(ParseErrors)?,
1096 path.iter()
1097 .map(|ASTNode { node, .. }| {
1098 node.as_ref()
1099 .ok_or_else(|| {
1100 ParseErrors(vec![ParseError::ToAST(
1101 "node should not be empty".to_string(),
1102 )])
1103 })
1104 .and_then(|id| id.to_string().parse().map_err(ParseErrors))
1105 })
1106 .collect::<Result<Vec<ast::Id>, _>>()?,
1107 ))),
1108 (path, Some(id)) => Err(ParseError::ToAST(format!(
1109 "{} is not a valid expr",
1110 cst::Name {
1111 path: path.to_vec(),
1112 name: ASTNode::new(Some(id), 0, 0)
1113 }
1114 ))
1115 .into()),
1116 (_, None) => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
1117 },
1118 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
1119 },
1120 cst::Primary::Slot(ASTNode { node, .. }) => match node {
1121 Some(cst::Slot::Principal) => Ok(Either::Right(Expr::slot(ast::SlotId::principal()))),
1122 Some(cst::Slot::Resource) => Ok(Either::Right(Expr::slot(ast::SlotId::resource()))),
1123 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
1124 },
1125 cst::Primary::Expr(ASTNode { node, .. }) => match node {
1126 Some(e) => Ok(Either::Right(e.try_into()?)),
1127 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
1128 },
1129 cst::Primary::EList(nodes) => nodes
1130 .into_iter()
1131 .map(|node| match node.node {
1132 Some(e) => e.try_into(),
1133 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
1134 })
1135 .collect::<Result<Vec<Expr>, _>>()
1136 .map(Expr::set)
1137 .map(Either::Right),
1138 cst::Primary::RInits(nodes) => nodes
1139 .into_iter()
1140 .map(|node| match node.node {
1141 Some(cst::RecInit(k, v)) => {
1142 let mut errs = vec![];
1143 let s = k
1144 .to_expr_or_special(&mut errs)
1145 .and_then(|es| es.into_valid_attr(&mut errs));
1146 if !errs.is_empty() {
1147 Err(ParseErrors(errs))
1148 } else {
1149 match (s, v.node) {
1150 (Some(s), Some(e)) => Ok((s, e.try_into()?)),
1151 (_, _) => {
1152 Err(ParseError::ToAST("node should not be empty".to_string())
1153 .into())
1154 }
1155 }
1156 }
1157 }
1158 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
1159 })
1160 .collect::<Result<HashMap<SmolStr, Expr>, ParseErrors>>()
1161 .map(Expr::record)
1162 .map(Either::Right),
1163 }
1164}
1165
1166impl TryFrom<cst::Member> for Expr {
1167 type Error = ParseErrors;
1168 fn try_from(m: cst::Member) -> Result<Expr, ParseErrors> {
1169 let mut item: Either<ast::Name, Expr> = match m.item.node {
1170 Some(p) => interpret_primary(p),
1171 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
1172 }?;
1173 for access in m.access {
1174 match access.node {
1175 Some(cst::MemAccess::Field(ASTNode { node, .. })) => match node {
1176 Some(cst::Ident::Ident(i)) => {
1177 item = match item {
1178 Either::Left(name) => {
1179 return Err(ParseError::ToAST(format!(
1180 "{name}.{i} is not a valid expression"
1181 ))
1182 .into())
1183 }
1184 Either::Right(expr) => Either::Right(Expr::get_attr(expr, i)),
1185 };
1186 }
1187 Some(_i) => {
1188 return Err(ParseError::ToAST("Invalid Identifier".to_string()).into())
1189 }
1190 None => {
1191 return Err(ParseError::ToAST("node should not be empty".to_string()).into())
1192 }
1193 },
1194 Some(cst::MemAccess::Call(args)) => {
1195 item = match item {
1203 Either::Left(name) => Either::Right(Expr::ext_call(
1204 name.to_string().into(),
1205 args.into_iter()
1206 .map(|ASTNode { node, .. }| match node {
1207 Some(expr) => expr.try_into(),
1208 None => Err(ParseError::ToAST(
1209 "node should not be empty".to_string(),
1210 )
1211 .into()),
1212 })
1213 .collect::<Result<Vec<_>, _>>()?,
1214 )),
1215 Either::Right(Expr::ExprNoExt(ExprNoExt::GetAttr { left, attr })) => {
1216 let mut args = args
1217 .into_iter()
1218 .map(|node| match node.node {
1219 Some(arg) => arg.try_into(),
1220 None => Err(ParseError::ToAST(
1221 "node should not be empty".to_string(),
1222 )
1223 .into()),
1224 })
1225 .collect::<Result<Vec<Expr>, ParseErrors>>()?;
1226 match attr.as_str() {
1227 "contains" => match args.len() {
1228 1 => {
1229 let arg = args
1230 .into_iter()
1231 .next()
1232 .expect("already checked there is 1 arg");
1233 Either::Right(Expr::contains(left, arg))
1234 }
1235 0 => {
1236 return Err(ParseError::ToAST(
1237 "contains() must have an argument".to_string(),
1238 )
1239 .into())
1240 }
1241 _ => {
1242 return Err(ParseError::ToAST(
1243 "contains() must have only one argument".to_string(),
1244 )
1245 .into())
1246 }
1247 },
1248 "containsAll" => match args.len() {
1249 1 => {
1250 let arg = args
1251 .into_iter()
1252 .next()
1253 .expect("already checked there is 1 arg");
1254 Either::Right(Expr::contains_all(left, arg))
1255 }
1256 0 => {
1257 return Err(ParseError::ToAST(
1258 "containsAll() must have an argument".to_string(),
1259 )
1260 .into())
1261 }
1262 _ => {
1263 return Err(ParseError::ToAST(
1264 "containsAll() must have only one argument".to_string(),
1265 )
1266 .into())
1267 }
1268 },
1269 "containsAny" => match args.len() {
1270 1 => {
1271 let arg = args
1272 .into_iter()
1273 .next()
1274 .expect("already checked there is 1 arg");
1275 Either::Right(Expr::contains_any(left, arg))
1276 }
1277 0 => {
1278 return Err(ParseError::ToAST(
1279 "containsAny() must have an argument".to_string(),
1280 )
1281 .into())
1282 }
1283 _ => {
1284 return Err(ParseError::ToAST(
1285 "containsAny() must have only one argument".to_string(),
1286 )
1287 .into())
1288 }
1289 },
1290 _ => {
1291 args.insert(0, unwrap_or_clone(left));
1294 Either::Right(Expr::ext_call(attr, args))
1295 }
1296 }
1297 }
1298 _ => {
1299 return Err(
1300 ParseError::ToAST("malformed method call".to_string()).into()
1301 )
1302 }
1303 };
1304 }
1305 Some(cst::MemAccess::Index(ASTNode { node, .. })) if node.is_some() => {
1306 let s = Expr::try_from(node.unwrap())?
1307 .into_string_literal()
1308 .ok_or_else(|| {
1309 ParseError::ToAST(
1310 "attribute value must be a string literal".to_string(),
1311 )
1312 })?;
1313 item = match item {
1314 Either::Left(name) => {
1315 return Err(ParseError::ToAST(format!(
1316 "{name}[\"{s}\"] is not a valid expression"
1317 ))
1318 .into())
1319 }
1320 Either::Right(expr) => Either::Right(Expr::get_attr(expr, s)),
1321 };
1322 }
1323 _ => return Err(ParseError::ToAST("node should not be empty".to_string()).into()),
1324 }
1325 }
1326 match item {
1327 Either::Left(name) => Err(ParseError::ToAST(format!(
1328 "{name} is not a valid expression"
1329 )))?,
1330 Either::Right(expr) => Ok(expr),
1331 }
1332 }
1333}
1334
1335impl TryFrom<cst::Literal> for Expr {
1336 type Error = ParseErrors;
1337 fn try_from(lit: cst::Literal) -> Result<Expr, ParseErrors> {
1338 match lit {
1339 cst::Literal::True => Ok(Expr::lit(JSONValue::Bool(true))),
1340 cst::Literal::False => Ok(Expr::lit(JSONValue::Bool(false))),
1341 cst::Literal::Num(n) => {
1342 Ok(Expr::lit(JSONValue::Long(n.try_into().map_err(|_| {
1343 ParseError::ToAST("numeric literal out of range".to_string())
1344 })?)))
1345 }
1346 cst::Literal::Str(ASTNode { node, .. }) => match node {
1347 Some(cst::Str::String(s)) => Ok(Expr::lit(JSONValue::String(s))),
1348 Some(_) => Err(ParseError::ToAST("invalid string".to_string()).into()),
1349 None => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
1350 },
1351 }
1352 }
1353}
1354
1355impl TryFrom<cst::Name> for Expr {
1356 type Error = ParseErrors;
1357 fn try_from(name: cst::Name) -> Result<Expr, ParseErrors> {
1358 match (&name.path[..], name.name.node) {
1359 (&[], Some(cst::Ident::Principal)) => Ok(Expr::var(ast::Var::Principal)),
1360 (&[], Some(cst::Ident::Action)) => Ok(Expr::var(ast::Var::Action)),
1361 (&[], Some(cst::Ident::Resource)) => Ok(Expr::var(ast::Var::Resource)),
1362 (&[], Some(cst::Ident::Context)) => Ok(Expr::var(ast::Var::Context)),
1363 (path, Some(id)) => Err(ParseError::ToAST(format!(
1364 "{} is not a valid expr",
1365 cst::Name {
1366 path: path.to_vec(),
1367 name: ASTNode::new(Some(id), 0, 0)
1368 }
1369 ))
1370 .into()),
1371 (_, None) => Err(ParseError::ToAST("node should not be empty".to_string()).into()),
1372 }
1373 }
1374}