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
//! An HCL parser which keeps track of whitespace, comments and span information.

mod context;
mod error;
mod expr;
mod number;
mod repr;
mod state;
mod string;
mod structure;
mod template;
#[cfg(test)]
mod tests;
mod trivia;

pub use self::error::{Error, Location};
use self::{error::ParseError, expr::expr, structure::body, template::template};
use crate::{expr::Expression, structure::Body, template::Template};
use winnow::{stream::Located, Parser};

type Input<'a> = Located<&'a [u8]>;

type IResult<I, O, E = ParseError<I>> = winnow::IResult<I, O, E>;

/// Parse an input into a [`Body`](crate::structure::Body).
///
/// # Errors
///
/// Returns an error if the input does not resemble a valid HCL body.
pub fn parse_body(input: &str) -> Result<Body, Error> {
    let mut body = parse_complete(input, body)?;
    body.despan(input);
    Ok(body)
}

/// Parse an input into an [`Expression`](crate::expr::Expression).
///
/// # Errors
///
/// Returns an error if the input does not resemble a valid HCL expression.
pub fn parse_expr(input: &str) -> Result<Expression, Error> {
    let mut expr = parse_complete(input, expr)?;
    expr.despan(input);
    Ok(expr)
}

/// Parse an input into a [`Template`](crate::template::Template).
///
/// # Errors
///
/// Returns an error if the input does not resemble a valid HCL template.
pub fn parse_template(input: &str) -> Result<Template, Error> {
    let mut template = parse_complete(input, template)?;
    template.despan(input);
    Ok(template)
}

fn parse_complete<'a, P, O>(input: &'a str, mut parser: P) -> Result<O, Error>
where
    P: Parser<Input<'a>, O, ParseError<Input<'a>>>,
{
    let input = Input::new(input.as_bytes());

    parser
        .parse(input)
        .map_err(|err| Error::from_parse_error(&input, &err))
}