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
use crate::parser::helpers::{check_semi, check_colon};
use wagon_ident::Ident;
use wagon_macros::match_error;
use std::{collections::BTreeMap, fmt::Display};

use super::{Parse, LexerBridge, ParseResult, Tokens, WagParseError, atom::Atom, Peek, ResultNext, SpannableNode};

use wagon_macros::new_unspanned;

#[derive(PartialEq, Debug, Eq, Hash)]
#[new_unspanned]
/// The metadata of the WAG.
///
/// # Grammar
/// <span><pre>
/// [Metadata]  -> Meta* MetaDelim;
/// MetaDelim -> `"=="` `"="`+;
/// Meta      -> Include | Config;
/// Include   -> `"include"` Path;
/// Config    -> Identifier `":"` [Expression](super::expression::Expression) `";"`;
/// </pre></span>
pub struct Metadata {
    /// All imports for this grammar.
	pub includes: Vec<String>,
    /// Any extra key-value mappings.
	pub mappings: BTreeMap<String, SpannableNode<Atom>>
}

impl Parse for Metadata {
    fn parse(lexer: &mut LexerBridge) -> ParseResult<Self> {
        let mut includes = Vec::new();
        let mut mappings = BTreeMap::new();
        while let Some(Ok(Tokens::MetadataToken(_))) = lexer.peek() {
                match_error!(match lexer.next_result()? {
                    Tokens::MetadataToken(wagon_lexer::metadata::Metadata::Identifier(Ident::Unknown(s))) => {
                        check_colon(lexer)?;
                        let atom = SpannableNode::parse(lexer)?;
                        check_semi(lexer)?;
                        mappings.insert(s, atom);
                        Ok(())
                    },
                    Tokens::MetadataToken(wagon_lexer::metadata::Metadata::Delim) => break,
                    Tokens::MetadataToken(wagon_lexer::metadata::Metadata::Include) => {
                        match_error!(match lexer.next_result()? {
                            Tokens::MetadataToken(wagon_lexer::metadata::Metadata::Path(p)) => {
                                includes.push(p); 
                                check_semi(lexer)?;
                                Ok(())
                            }
                        })
                    }
                })?;
        }
        Ok(Self { includes, mappings })
    }
}

impl Display for Metadata {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for include in &self.includes {
            writeln!(f, "include {include};")?;
        }
        for (key, value) in &self.mappings {
            writeln!(f, "{key}: {value};")?;
        }
        writeln!(f, "================")
    }
}