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