hcl_edit/expr/
traversal.rs

1use crate::expr::Expression;
2use crate::{Decor, Decorate, Decorated, Ident};
3use std::fmt;
4use std::ops::Range;
5
6/// Traverse an expression to access attributes, object keys or element indices.
7#[derive(Debug, Clone, Eq)]
8pub struct Traversal {
9    /// The expression that the access operator is applied to.
10    pub expr: Expression,
11    /// The traversal operators to apply to `expr` one of the other.
12    pub operators: Vec<Decorated<TraversalOperator>>,
13
14    decor: Decor,
15    span: Option<Range<usize>>,
16}
17
18impl Traversal {
19    /// Creates a new `Traversal` structure from an expression and traversal operators that should
20    /// be applied to it.
21    pub fn new(
22        expr: impl Into<Expression>,
23        operators: Vec<Decorated<TraversalOperator>>,
24    ) -> Traversal {
25        Traversal {
26            expr: expr.into(),
27            operators,
28            decor: Decor::default(),
29            span: None,
30        }
31    }
32
33    pub(crate) fn despan(&mut self, input: &str) {
34        self.decor.despan(input);
35        self.expr.despan(input);
36
37        for operator in &mut self.operators {
38            operator.despan(input);
39        }
40    }
41}
42
43impl PartialEq for Traversal {
44    fn eq(&self, other: &Self) -> bool {
45        self.expr == other.expr && self.operators == other.operators
46    }
47}
48
49/// The expression traversal operators that are supported by HCL.
50#[derive(Debug, Clone, PartialEq, Eq)]
51pub enum TraversalOperator {
52    /// The attribute-only splat operator supports only attribute lookups into the elements from a
53    /// list, but supports an arbitrary number of them.
54    AttrSplat(Decorated<Splat>),
55    /// The full splat operator additionally supports indexing into the elements from a list, and
56    /// allows any combination of attribute access and index operations.
57    FullSplat(Decorated<Splat>),
58    /// The attribute access operator returns the value of a single attribute in an object value.
59    GetAttr(Decorated<Ident>),
60    /// The index operator returns the value of a single element of a collection value based on
61    /// the result of the expression.
62    Index(Expression),
63    /// The legacy index operator returns the value of a single element of a collection value.
64    /// Exists only for compatibility with the precursor language HIL. Use the `Index` variant
65    /// instead.
66    LegacyIndex(Decorated<u64>),
67}
68
69impl TraversalOperator {
70    pub(crate) fn despan(&mut self, input: &str) {
71        match self {
72            TraversalOperator::AttrSplat(splat) | TraversalOperator::FullSplat(splat) => {
73                splat.decor_mut().despan(input);
74            }
75            TraversalOperator::GetAttr(ident) => ident.decor_mut().despan(input),
76            TraversalOperator::Index(expr) => expr.despan(input),
77            TraversalOperator::LegacyIndex(index) => index.decor_mut().despan(input),
78        }
79    }
80}
81
82/// Represents the splat operator (`*`) that is used within a
83/// [`AttrSplat`](TraversalOperator::AttrSplat) or [`FullSplat`](TraversalOperator::FullSplat).
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85pub struct Splat;
86
87impl fmt::Display for Splat {
88    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89        write!(f, "*")
90    }
91}
92
93decorate_impl!(Traversal);
94span_impl!(Traversal);
95forward_decorate_impl!(TraversalOperator => { AttrSplat, FullSplat, GetAttr, Index, LegacyIndex });
96forward_span_impl!(TraversalOperator => { AttrSplat, FullSplat, GetAttr, Index, LegacyIndex });