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
use super::{
    helpers::{parsing_catch_all, Pair},
    parse_comments::*,
    parse_expression::parse_expression,
    Rule,
};
use crate::ast::*;
use diagnostics::{DatamodelError, Diagnostics};

#[track_caller]
pub(crate) fn parse_config_block(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Top {
    let pair_span = pair.as_span();
    let mut name: Option<Identifier> = None;
    let mut properties = Vec::new();
    let mut comment: Option<Comment> = None;
    let mut kw = None;
    let mut inner_span: Option<Span> = None;

    for current in pair.into_inner() {
        match current.as_rule() {
            Rule::config_contents => {
                inner_span = Some(current.as_span().into());
                for item in current.into_inner() {
                    match item.as_rule() {
                        Rule::key_value => properties.push(parse_key_value(item, diagnostics)),
                        Rule::comment_block => comment = parse_comment_block(item),
                        Rule::BLOCK_LEVEL_CATCH_ALL => {
                            let msg = format!(
                                "This line is not a valid definition within a {}.",
                                kw.unwrap_or("configuration block")
                            );

                            let err = DatamodelError::new_validation_error(&msg, item.as_span().into());
                            diagnostics.push_error(err);
                        }
                        _ => parsing_catch_all(&item, "source"),
                    }
                }
            }
            Rule::identifier => name = Some(current.into()),
            Rule::DATASOURCE_KEYWORD | Rule::GENERATOR_KEYWORD => kw = Some(current.as_str()),
            Rule::BLOCK_OPEN | Rule::BLOCK_CLOSE => {}

            _ => parsing_catch_all(&current, "source"),
        }
    }

    match kw {
        Some("datasource") => Top::Source(SourceConfig {
            name: name.unwrap(),
            properties,
            documentation: comment,
            span: Span::from(pair_span),
            inner_span: inner_span.unwrap(),
        }),
        Some("generator") => Top::Generator(GeneratorConfig {
            name: name.unwrap(),
            properties,
            documentation: comment,
            span: Span::from(pair_span),
        }),
        _ => unreachable!(),
    }
}

fn parse_key_value(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> ConfigBlockProperty {
    let mut name: Option<Identifier> = None;
    let mut value: Option<Expression> = None;
    let (pair_span, pair_str) = (pair.as_span(), pair.as_str());

    for current in pair.into_inner() {
        match current.as_rule() {
            Rule::identifier => name = Some(current.into()),
            Rule::expression => value = Some(parse_expression(current, diagnostics)),
            Rule::trailing_comment => (),
            _ => unreachable!(
                "Encountered impossible source property declaration during parsing: {:?}",
                current.tokens()
            ),
        }
    }

    match (name, value) {
        (Some(name), value) => ConfigBlockProperty {
            name,
            value,
            span: Span::from(pair_span),
        },
        _ => unreachable!(
            "Encountered impossible source property declaration during parsing: {:?}",
            pair_str,
        ),
    }
}