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
use pest::{
    iterators::Pairs,
    pratt_parser::{Assoc, Op, PrattParser},
    Parser,
};
use pest_derive::Parser;

/// `PklParser` is a parser generated from the `pkl.pest` grammar file.
/// This struct is used to parse input strings according to the rules defined in the grammar.
#[derive(Parser)]
#[grammar = "pkl.pest"]
pub struct PklParser;

/// Parses the given source string using the `PklParser` and returns a `Pairs` iterator over the parsed tokens.
///
/// # Arguments
///
/// * `src` - A string slice that holds the source code to be parsed.
///
/// # Returns
///
/// * `Ok(Pairs<Rule>)` - A successful result containing a `Pairs` iterator over the parsed tokens.
/// * `Err(pest::error::Error<Rule>)` - An error that occurred during parsing, encapsulated in a `pest` error.
///
/// # Example
///
/// ```rust
/// let source = "your source code here";
/// let parsed = parse(source);
/// match parsed {
///     Ok(pairs) => {
///         for pair in pairs {
///             // handle parsed tokens
///         }
///     }
///     Err(error) => {
///         eprintln!("Parsing error: {:?}", error);
///     }
/// }
/// ```
pub fn parse(src: &str) -> Result<Pairs<Rule>, pest::error::Error<Rule>> {
    let result = PklParser::parse(Rule::file, src)?;

    Ok(result)
}

/// Constructs a `PrattParser` for parsing and evaluating expressions with operator precedence and associativity.
///
/// The `PrattParser` is configured with various infix, prefix, and postfix operators, as specified by the PKL grammar.
/// This is used to handle expressions like arithmetic operations, comparisons, and logical operators.
///
/// # Returns
///
/// * `PrattParser<Rule>` - A configured `PrattParser` for parsing expressions with the appropriate precedence and associativity.
///
/// # Example
///
/// ```rust
/// let pratt_parser = pratt();
/// // Use the pratt_parser to evaluate expressions
/// ```
/// // For how to use the pratt_parser, [see](https://pest.rs/book/precedence.html)
pub fn pratt() -> PrattParser<Rule> {
    PrattParser::new()
        .op(Op::infix(Rule::null_coalescing, Assoc::Left))
        .op(Op::infix(Rule::comp_equal, Assoc::Left)
            | Op::infix(Rule::and, Assoc::Left)
            | Op::infix(Rule::or, Assoc::Left)
            | Op::infix(Rule::comp_not_equal, Assoc::Left)
            | Op::infix(Rule::comp_greater, Assoc::Left)
            | Op::infix(Rule::comp_greater_equal, Assoc::Left)
            | Op::infix(Rule::comp_less, Assoc::Left)
            | Op::infix(Rule::comp_less_equal, Assoc::Left))
        .op(Op::infix(Rule::is_op, Assoc::Left) | Op::infix(Rule::as_op, Assoc::Left))
        .op(Op::infix(Rule::add, Assoc::Left) | Op::infix(Rule::sub, Assoc::Left))
        .op(Op::infix(Rule::mul, Assoc::Left)
            | Op::infix(Rule::modulo, Assoc::Left)
            | Op::infix(Rule::div, Assoc::Left)
            | Op::infix(Rule::div_r, Assoc::Left))
        .op(Op::infix(Rule::pow, Assoc::Right))
        .op(Op::postfix(Rule::non_null))
        .op(Op::prefix(Rule::neg) | Op::prefix(Rule::logical_not))
}