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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
use std::{
    collections::{btree_map::Entry, BTreeMap},
    fmt::{Debug, Display},
    path::{Path, PathBuf},
};

use crate::{error::munyo_error::PathItem, lang::processed::Processed, read_file};

use super::builder::{Builder, MetaBuilder};

/// A meta builder which builds DefaultBuilder
#[derive(Debug, Clone, Default)]
pub struct DefaultMetaBuilder;

impl MetaBuilder for DefaultMetaBuilder {
    type Item = DefaultBuilder;

    fn build(&self, typename: String, argument: String) -> Result<Self::Item, String> {
        Ok(DefaultBuilder::new(typename, argument))
    }
}

/// A builder which builds MunyoItem
#[derive(Debug)]
pub struct DefaultBuilder {
    pub(crate) typename: String,
    pub(crate) argument: String,
    pub(crate) params: BTreeMap<String, String>,
    pub(crate) children: Vec<MunyoItem>,
}

impl DefaultBuilder {
    /// Creates DefaultBuilder
    pub fn new(typename: String, argument: String) -> Self {
        Self {
            typename,
            argument,
            params: BTreeMap::new(),
            children: vec![],
        }
    }
}

impl Builder for DefaultBuilder {
    type Item = MunyoItem;

    fn set_param(&mut self, param_name: String, argument: String) -> Result<(), String> {
        match self.params.entry(param_name) {
            Entry::Occupied(e) => {
                return Err(format!("'{}' is applied multiple times", e.key()));
            }
            Entry::Vacant(e) => {
                e.insert(argument);
            }
        }
        Ok(())
    }

    fn set_child(&mut self, child: Self::Item) -> Result<(), String> {
        self.children.push(child);
        Ok(())
    }

    fn finish(self) -> Result<Self::Item, String> {
        Ok(Self::Item {
            typename: self.typename,
            argument: self.argument,
            params: self.params,
            children: self.children,
        })
    }
}

/// Untyped Munyo value which can be used without implementing Serialize/Deserialize
#[derive(Clone, Default, PartialEq)]
pub struct MunyoItem {
	/// The typename of the line of the Munyo language
    pub typename: String,
	/// The argument of the line of the Munyo language
    pub argument: String,
	/// The params of the line of the Munyo language
    pub params: BTreeMap<String, String>,
	/// The children of the line of the Munyo language
    pub children: Vec<MunyoItem>,
}

impl Debug for MunyoItem {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write_item(self, 0, f)
    }
}

impl Display for MunyoItem {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write_item(self, 0, f)
    }
}

fn write_item(
    item: &MunyoItem,
    indent_level: usize,
    f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
    for _ in 0..indent_level {
        write!(f, "\t")?;
    }
    write!(f, "{}", item_format(&item.typename, &item.argument))?;
    for (key, val) in &item.params {
        write!(f, "|{}", item_format(key, val))?;
    }
    for child in &item.children {
        writeln!(f)?;
        write_item(child, indent_level + 1, f)?;
    }
    Ok(())
}

fn item_format(name: &str, val: &str) -> String {
    if val.is_empty() {
        name.to_string()
    } else {
        format!("{} {}", name, val)
    }
}

impl MunyoItem {
    /// Deserialize `MunyoItem` from `&str` of the Munyo language.
    /// `path` is only used for error messages.
    ///
    /// See [from_str](Self::from_str) for details;
    pub fn from_str_with_path<P: AsRef<Path>>(
        s: &str,
        path: P,
    ) -> crate::Result<Processed<MunyoItem>> {
        Self::inner(s, Some(path.as_ref().to_path_buf()))
    }

    /// Deserialize `MunyoItem` from `&str` of the Munyo language.
    /// # Example
    /// ```
    /// # fn main() -> munyo::Result<()>{
    /// 	let v = munyo::MunyoItem::from_str("Typename  argu ment  |   param  value ")?.result;
    /// 	assert_eq!(&v[0].typename, "Typename");
    /// 	assert_eq!(&v[0].argument, " argu ment  ");
    /// 	assert_eq!(v[0].params.get("param").unwrap(), " value ");
    /// # 	Ok(())
    /// # }
    /// ```
    pub fn from_str(s: &str) -> crate::Result<Processed<MunyoItem>> {
        Self::inner(s, None)
    }

    /// Deserialize `MunyoItem` from `path` of the source file of the Munyo language.
    /// # Example
    /// ```
    /// # fn main() -> munyo::Result<()>{
    /// let s = "foo";
    /// // create a file with text "foo" and get the path
    /// # 	let file = munyo::temp(s)?;
    /// # 	let path = file.path();
    /// let v = munyo::MunyoItem::from_file(path)?.result;
    /// assert_eq!(&v[0].typename, "foo");
    /// # Ok(())
    /// # }
    /// ```
    pub fn from_file<P: AsRef<Path>>(path: P) -> crate::Result<Processed<MunyoItem>> {
        let buf = path.as_ref().to_path_buf();
        let s = read_file(&buf)?;
        Self::inner(&s, Some(buf))
    }

    fn inner(s: &str, path: Option<PathBuf>) -> crate::Result<Processed<MunyoItem>> {
        crate::from_str_with_metabuilder(s, &DefaultMetaBuilder)
            .map_err(|e| crate::Error::Parse(PathItem::new(path), e))
    }
}