hcl_edit/expr/
mod.rs

1//! Types to represent the HCL expression sub-language.
2
3mod array;
4mod conditional;
5mod for_expr;
6mod func_call;
7mod object;
8mod operation;
9mod traversal;
10
11pub use self::array::{Array, IntoIter, Iter, IterMut};
12pub use self::conditional::Conditional;
13pub use self::for_expr::{ForCond, ForExpr, ForIntro};
14pub use self::func_call::{FuncArgs, FuncCall, FuncName};
15pub use self::object::{
16    Object, ObjectIntoIter, ObjectIter, ObjectIterMut, ObjectKey, ObjectKeyMut, ObjectValue,
17    ObjectValueAssignment, ObjectValueTerminator,
18};
19pub use self::operation::{BinaryOp, BinaryOperator, UnaryOp, UnaryOperator};
20pub use self::traversal::{Splat, Traversal, TraversalOperator};
21use crate::encode::{EncodeDecorated, EncodeState, NO_DECOR};
22use crate::template::{HeredocTemplate, StringTemplate, Template};
23use crate::{parser, Decor, Decorate, Decorated, Formatted, Ident, Number};
24use std::borrow::Cow;
25use std::fmt;
26use std::ops::Range;
27use std::str::FromStr;
28
29/// A type representing any expression from the expression sub-language.
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub enum Expression {
32    /// Represents a null value.
33    Null(Decorated<Null>),
34    /// Represents a boolean.
35    Bool(Decorated<bool>),
36    /// Represents a number, either integer or float.
37    Number(Formatted<Number>),
38    /// Represents a string that does not contain any template interpolations or template
39    /// directives.
40    String(Decorated<String>),
41    /// Represents an HCL array.
42    Array(Array),
43    /// Represents an HCL object.
44    Object(Object),
45    /// Represents a string containing template interpolations and template directives.
46    StringTemplate(StringTemplate),
47    /// Represents an HCL heredoc template.
48    HeredocTemplate(Box<HeredocTemplate>),
49    /// Represents a sub-expression wrapped in parenthesis.
50    Parenthesis(Box<Parenthesis>),
51    /// Represents a variable identifier.
52    Variable(Decorated<Ident>),
53    /// Represents conditional operator which selects one of two rexpressions based on the outcome
54    /// of a boolean expression.
55    Conditional(Box<Conditional>),
56    /// Represents a function call.
57    FuncCall(Box<FuncCall>),
58    /// Represents an attribute or element traversal.
59    Traversal(Box<Traversal>),
60    /// Represents an operation which applies a unary operator to an expression.
61    UnaryOp(Box<UnaryOp>),
62    /// Represents an operation which applies a binary operator to two expressions.
63    BinaryOp(Box<BinaryOp>),
64    /// Represents a construct for constructing a collection by projecting the items from another
65    /// collection.
66    ForExpr(Box<ForExpr>),
67}
68
69impl Expression {
70    /// Creates a `null` expression.
71    pub fn null() -> Expression {
72        Expression::Null(Decorated::new(Null))
73    }
74
75    /// Returns `true` if the expression represents `null`.
76    pub fn is_null(&self) -> bool {
77        matches!(self, Expression::Null(_))
78    }
79
80    /// Returns `true` if the expression is a bool.
81    pub fn is_bool(&self) -> bool {
82        self.as_bool().is_some()
83    }
84
85    /// If the expression is a bool, returns a reference to it, otherwise `None`.
86    pub fn as_bool(&self) -> Option<bool> {
87        match self {
88            Expression::Bool(value) => Some(*value.value()),
89            _ => None,
90        }
91    }
92
93    /// Returns `true` if the expression is a number.
94    pub fn is_number(&self) -> bool {
95        self.as_number().is_some()
96    }
97
98    /// If the expression is a number, returns a reference to it, otherwise `None`.
99    pub fn as_number(&self) -> Option<&Number> {
100        match self {
101            Expression::Number(value) => Some(value.value()),
102            _ => None,
103        }
104    }
105
106    /// Returns `true` if the expression is a string.
107    pub fn is_str(&self) -> bool {
108        self.as_str().is_some()
109    }
110
111    /// If the expression is a string, returns a reference to it, otherwise `None`.
112    pub fn as_str(&self) -> Option<&str> {
113        match self {
114            Expression::String(value) => Some(value.value()),
115            _ => None,
116        }
117    }
118
119    /// Returns `true` if the expression is an array.
120    pub fn is_array(&self) -> bool {
121        self.as_array().is_some()
122    }
123
124    /// If the expression is an array, returns a reference to it, otherwise `None`.
125    pub fn as_array(&self) -> Option<&Array> {
126        match self {
127            Expression::Array(value) => Some(value),
128            _ => None,
129        }
130    }
131
132    /// If the expression is an array, returns a mutable reference to it, otherwise `None`.
133    pub fn as_array_mut(&mut self) -> Option<&mut Array> {
134        match self {
135            Expression::Array(value) => Some(value),
136            _ => None,
137        }
138    }
139
140    /// Returns `true` if the expression is an object.
141    pub fn is_object(&self) -> bool {
142        self.as_object().is_some()
143    }
144
145    /// If the expression is an object, returns a reference to it, otherwise `None`.
146    pub fn as_object(&self) -> Option<&Object> {
147        match self {
148            Expression::Object(value) => Some(value),
149            _ => None,
150        }
151    }
152
153    /// If the expression is an object, returns a mutable reference to it, otherwise `None`.
154    pub fn as_object_mut(&mut self) -> Option<&mut Object> {
155        match self {
156            Expression::Object(value) => Some(value),
157            _ => None,
158        }
159    }
160
161    /// Returns `true` if the expression is either of variant `StringTemplate` or
162    /// `HeredocTemplate`.
163    pub fn is_template(&self) -> bool {
164        self.as_template().is_some()
165    }
166
167    /// If the expression is either of variant `StringTemplate` or `HeredocTemplate`, returns a
168    /// reference to the underlying `Template`, otherwise `None`.
169    pub fn as_template(&self) -> Option<&Template> {
170        match self {
171            Expression::StringTemplate(value) => Some(value),
172            Expression::HeredocTemplate(value) => Some(&value.template),
173            _ => None,
174        }
175    }
176
177    /// Returns `true` if the expression is a string template.
178    pub fn is_string_template(&self) -> bool {
179        self.as_string_template().is_some()
180    }
181
182    /// If the expression is a string template, returns a reference to it, otherwise `None`.
183    pub fn as_string_template(&self) -> Option<&StringTemplate> {
184        match self {
185            Expression::StringTemplate(value) => Some(value),
186            _ => None,
187        }
188    }
189
190    /// Returns `true` if the expression is a heredoc template.
191    pub fn is_heredoc_template(&self) -> bool {
192        self.as_heredoc_template().is_some()
193    }
194
195    /// If the expression is a heredoc template, returns a reference to it, otherwise `None`.
196    pub fn as_heredoc_template(&self) -> Option<&HeredocTemplate> {
197        match self {
198            Expression::HeredocTemplate(value) => Some(value),
199            _ => None,
200        }
201    }
202
203    /// Returns `true` if the expression is wrapped in parenthesis.
204    pub fn is_parenthesis(&self) -> bool {
205        self.as_parenthesis().is_some()
206    }
207
208    /// If the expression is an expression wrapped in parenthesis, returns a reference to it,
209    /// otherwise `None`.
210    pub fn as_parenthesis(&self) -> Option<&Parenthesis> {
211        match self {
212            Expression::Parenthesis(value) => Some(value),
213            _ => None,
214        }
215    }
216
217    /// Returns `true` if the expression is a variable.
218    pub fn is_variable(&self) -> bool {
219        self.as_variable().is_some()
220    }
221
222    /// If the expression is a variable, returns a reference to it, otherwise `None`.
223    pub fn as_variable(&self) -> Option<&Ident> {
224        match self {
225            Expression::Variable(value) => Some(value.value()),
226            _ => None,
227        }
228    }
229
230    /// Returns `true` if the expression is a conditional.
231    pub fn is_conditional(&self) -> bool {
232        self.as_conditional().is_some()
233    }
234
235    /// If the expression is a conditional, returns a reference to it, otherwise `None`.
236    pub fn as_conditional(&self) -> Option<&Conditional> {
237        match self {
238            Expression::Conditional(value) => Some(value),
239            _ => None,
240        }
241    }
242
243    /// Returns `true` if the expression is a function call.
244    pub fn is_func_call(&self) -> bool {
245        self.as_func_call().is_some()
246    }
247
248    /// If the expression is a function call, returns a reference to it, otherwise `None`.
249    pub fn as_func_call(&self) -> Option<&FuncCall> {
250        match self {
251            Expression::FuncCall(value) => Some(value),
252            _ => None,
253        }
254    }
255
256    /// Returns `true` if the expression is a traversal.
257    pub fn is_traversal(&self) -> bool {
258        self.as_traversal().is_some()
259    }
260
261    /// If the expression is a traversal, returns a reference to it, otherwise `None`.
262    pub fn as_traversal(&self) -> Option<&Traversal> {
263        match self {
264            Expression::Traversal(value) => Some(value),
265            _ => None,
266        }
267    }
268
269    /// Returns `true` if the expression is a unary op.
270    pub fn is_unary_op(&self) -> bool {
271        self.as_unary_op().is_some()
272    }
273
274    /// If the expression is a unary op, returns a reference to it, otherwise `None`.
275    pub fn as_unary_op(&self) -> Option<&UnaryOp> {
276        match self {
277            Expression::UnaryOp(value) => Some(value),
278            _ => None,
279        }
280    }
281
282    /// Returns `true` if the expression is a binary op.
283    pub fn is_binary_op(&self) -> bool {
284        self.as_binary_op().is_some()
285    }
286
287    /// If the expression is a binary op, returns a reference to it, otherwise `None`.
288    pub fn as_binary_op(&self) -> Option<&BinaryOp> {
289        match self {
290            Expression::BinaryOp(value) => Some(value),
291            _ => None,
292        }
293    }
294
295    /// Returns `true` if the expression is a `for` expression.
296    pub fn is_for_expr(&self) -> bool {
297        self.as_for_expr().is_some()
298    }
299
300    /// If the expression is a `for` expression, returns a reference to it, otherwise `None`.
301    pub fn as_for_expr(&self) -> Option<&ForExpr> {
302        match self {
303            Expression::ForExpr(value) => Some(value),
304            _ => None,
305        }
306    }
307
308    pub(crate) fn despan(&mut self, input: &str) {
309        match self {
310            Expression::Null(n) => n.decor_mut().despan(input),
311            Expression::Bool(b) => b.decor_mut().despan(input),
312            Expression::Number(n) => n.decor_mut().despan(input),
313            Expression::String(s) => s.decor_mut().despan(input),
314            Expression::Array(array) => array.despan(input),
315            Expression::Object(object) => object.despan(input),
316            Expression::StringTemplate(template) => template.despan(input),
317            Expression::HeredocTemplate(heredoc) => heredoc.despan(input),
318            Expression::Parenthesis(expr) => expr.despan(input),
319            Expression::Variable(var) => var.decor_mut().despan(input),
320            Expression::ForExpr(expr) => expr.despan(input),
321            Expression::Conditional(cond) => cond.despan(input),
322            Expression::FuncCall(call) => call.despan(input),
323            Expression::UnaryOp(op) => op.despan(input),
324            Expression::BinaryOp(op) => op.despan(input),
325            Expression::Traversal(traversal) => traversal.despan(input),
326        }
327    }
328}
329
330impl FromStr for Expression {
331    type Err = parser::Error;
332
333    fn from_str(s: &str) -> Result<Self, Self::Err> {
334        parser::parse_expr(s)
335    }
336}
337
338macro_rules! impl_from_integer {
339    ($($ty:ty),*) => {
340        $(
341            impl From<$ty> for Expression {
342                fn from(n: $ty) -> Self {
343                    Expression::from(Number::from(n))
344                }
345            }
346        )*
347    };
348}
349
350impl_from_integer!(i8, i16, i32, i64, isize);
351impl_from_integer!(u8, u16, u32, u64, usize);
352
353impl From<f32> for Expression {
354    fn from(f: f32) -> Self {
355        From::from(f64::from(f))
356    }
357}
358
359impl From<f64> for Expression {
360    fn from(f: f64) -> Self {
361        Number::from_f64(f).map_or_else(Expression::null, Into::into)
362    }
363}
364
365impl From<bool> for Expression {
366    fn from(value: bool) -> Self {
367        Expression::from(Decorated::new(value))
368    }
369}
370
371impl From<Decorated<bool>> for Expression {
372    fn from(value: Decorated<bool>) -> Self {
373        Expression::Bool(value)
374    }
375}
376
377impl From<Number> for Expression {
378    fn from(value: Number) -> Self {
379        Expression::from(Formatted::new(value))
380    }
381}
382
383impl From<Formatted<Number>> for Expression {
384    fn from(value: Formatted<Number>) -> Self {
385        Expression::Number(value)
386    }
387}
388
389impl From<&str> for Expression {
390    fn from(value: &str) -> Self {
391        Expression::from(String::from(value))
392    }
393}
394
395impl From<String> for Expression {
396    fn from(value: String) -> Self {
397        Expression::from(Decorated::new(value))
398    }
399}
400
401impl<'a> From<Cow<'a, str>> for Expression {
402    fn from(s: Cow<'a, str>) -> Self {
403        Expression::from(s.into_owned())
404    }
405}
406
407impl From<Decorated<String>> for Expression {
408    fn from(value: Decorated<String>) -> Self {
409        Expression::String(value)
410    }
411}
412
413impl From<Array> for Expression {
414    fn from(value: Array) -> Self {
415        Expression::Array(value)
416    }
417}
418
419impl From<Object> for Expression {
420    fn from(value: Object) -> Self {
421        Expression::Object(value)
422    }
423}
424
425impl From<StringTemplate> for Expression {
426    fn from(value: StringTemplate) -> Self {
427        Expression::StringTemplate(value)
428    }
429}
430
431impl From<HeredocTemplate> for Expression {
432    fn from(value: HeredocTemplate) -> Self {
433        Expression::HeredocTemplate(Box::new(value))
434    }
435}
436
437impl From<Parenthesis> for Expression {
438    fn from(value: Parenthesis) -> Self {
439        Expression::Parenthesis(Box::new(value))
440    }
441}
442
443impl From<Ident> for Expression {
444    fn from(value: Ident) -> Self {
445        Expression::from(Decorated::new(value))
446    }
447}
448
449impl From<Decorated<Ident>> for Expression {
450    fn from(value: Decorated<Ident>) -> Self {
451        Expression::Variable(value)
452    }
453}
454
455impl From<Conditional> for Expression {
456    fn from(value: Conditional) -> Self {
457        Expression::Conditional(Box::new(value))
458    }
459}
460
461impl From<FuncCall> for Expression {
462    fn from(value: FuncCall) -> Self {
463        Expression::FuncCall(Box::new(value))
464    }
465}
466
467impl From<Traversal> for Expression {
468    fn from(value: Traversal) -> Self {
469        Expression::Traversal(Box::new(value))
470    }
471}
472
473impl From<UnaryOp> for Expression {
474    fn from(value: UnaryOp) -> Self {
475        Expression::UnaryOp(Box::new(value))
476    }
477}
478
479impl From<BinaryOp> for Expression {
480    fn from(value: BinaryOp) -> Self {
481        Expression::BinaryOp(Box::new(value))
482    }
483}
484
485impl From<ForExpr> for Expression {
486    fn from(value: ForExpr) -> Self {
487        Expression::ForExpr(Box::new(value))
488    }
489}
490
491impl<T> From<Vec<T>> for Expression
492where
493    T: Into<Expression>,
494{
495    fn from(value: Vec<T>) -> Self {
496        Expression::from_iter(value)
497    }
498}
499
500impl<'a, T> From<&'a [T]> for Expression
501where
502    T: Clone + Into<Expression>,
503{
504    fn from(value: &'a [T]) -> Self {
505        value.iter().cloned().collect()
506    }
507}
508
509impl<T: Into<Expression>> FromIterator<T> for Expression {
510    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
511        Expression::Array(Array::from_iter(iter))
512    }
513}
514
515impl<K: Into<ObjectKey>, V: Into<ObjectValue>> FromIterator<(K, V)> for Expression {
516    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
517        Expression::Object(Object::from_iter(iter))
518    }
519}
520
521impl fmt::Display for Expression {
522    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
523        let mut state = EncodeState::new(f);
524        self.encode_decorated(&mut state, NO_DECOR)
525    }
526}
527
528/// Represents a sub-expression wrapped in parenthesis (`( <expr> )`).
529#[derive(Debug, Clone, Eq)]
530pub struct Parenthesis {
531    inner: Expression,
532    decor: Decor,
533    span: Option<Range<usize>>,
534}
535
536impl Parenthesis {
537    /// Creates a new `Parenthesis` value from an `Expression`.
538    pub fn new(inner: Expression) -> Parenthesis {
539        Parenthesis {
540            inner,
541            decor: Decor::default(),
542            span: None,
543        }
544    }
545
546    /// Returns a reference to the wrapped `Expression`.
547    pub fn inner(&self) -> &Expression {
548        &self.inner
549    }
550
551    /// Returns a mutable reference to the wrapped `Expression`.
552    pub fn inner_mut(&mut self) -> &mut Expression {
553        &mut self.inner
554    }
555
556    /// Consumes the `Parenthesis` and returns the wrapped `Expression`.
557    pub fn into_inner(self) -> Expression {
558        self.inner
559    }
560
561    pub(crate) fn despan(&mut self, input: &str) {
562        self.decor.despan(input);
563        self.inner.despan(input);
564    }
565}
566
567impl PartialEq for Parenthesis {
568    fn eq(&self, other: &Self) -> bool {
569        self.inner == other.inner
570    }
571}
572
573/// Represents a value that is `null`.
574#[derive(Debug, Clone, Copy, PartialEq, Eq)]
575pub struct Null;
576
577impl fmt::Display for Null {
578    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
579        write!(f, "null")
580    }
581}
582
583decorate_impl!(Parenthesis);
584span_impl!(Parenthesis);
585
586forward_decorate_impl!(Expression => {
587    Null, Bool, Number, String, Array, Object, StringTemplate, HeredocTemplate, Parenthesis,
588    Variable, ForExpr, Conditional, FuncCall, UnaryOp, BinaryOp, Traversal
589});
590forward_span_impl!(Expression => {
591    Null, Bool, Number, String, Array, Object, StringTemplate, HeredocTemplate, Parenthesis,
592    Variable, ForExpr, Conditional, FuncCall, UnaryOp, BinaryOp, Traversal
593});