blocky_nbt/tag/parser/
mod.rs

1mod reader;
2
3use reader::*;
4
5use crate::{Tag, Nbt, Kind, Map};
6use regex::Regex;
7
8lazy_static! {
9    static ref DOUBLE_PATTERN_NOSUFFIX: Regex = Regex::new("^(?i)[-+]?(?:[0-9]+[.]|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?$").unwrap();
10    static ref DOUBLE_PATTERN: Regex = Regex::new("^(?i)[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?d$").unwrap();
11    static ref FLOAT_PATTERN: Regex = Regex::new("^(?i)[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?f$").unwrap();
12    static ref BYTE_PATTERN: Regex = Regex::new("^(?i)[-+]?(?:0|[1-9][0-9]*)b$").unwrap();
13    static ref LONG_PATTERN: Regex = Regex::new("^(?i)[-+]?(?:0|[1-9][0-9]*)l$").unwrap();
14    static ref SHORT_PATTERN: Regex = Regex::new("^(?i)[-+]?(?:0|[1-9][0-9]*)s$").unwrap();
15    static ref INT_PATTERN: Regex = Regex::new("^(?i)[-+]?(?:0|[1-9][0-9]*)$").unwrap();
16}
17
18macro_rules! read_array {
19    ($self:ident, $inner:ident, $typ:ty) => {
20        {
21            let mut v: Vec<$typ> = vec![];
22
23            while $self.reader.peek()? != ']' {
24                let start = $self.reader.position();
25                let tag = $self.read_value()?;
26
27                if tag.kind() != Kind::$inner {
28                    $self.reader.set_position(start);
29                    anyhow::bail!("array has mixed tags");
30                }
31
32                v.push(tag.into());
33
34                if !$self.has_separator()? {
35                    break;
36                }
37
38                if $self.reader.done() {
39                    anyhow::bail!("expected array closure")
40                }
41            }
42
43            v.into()
44        }
45    };
46}
47
48pub struct Parser {
49    reader: Reader,
50}
51
52impl Parser {
53    pub fn new<S: Into<String>>(s: S) -> Self {
54        Self { reader: Reader::new(s.into()) }
55    }
56
57    fn expect(&mut self, chr: char) -> anyhow::Result<()> {
58        self.reader.skip_whitespace()?;
59        self.reader.expect(chr)?;
60
61        Ok(())
62    }
63
64    fn read_key(&mut self) -> anyhow::Result<String> {
65        self.reader.skip_whitespace()?;
66
67        if self.reader.done() {
68            anyhow::bail!("missing expected key");
69        }
70
71        self.reader.read_string()
72    }
73
74    fn read_typed_value(&mut self) -> anyhow::Result<Tag> {
75        self.reader.skip_whitespace()?;
76
77        let start = self.reader.position();
78
79        if Reader::is_quote(self.reader.peek()?) {
80            Ok(self.reader.read_quoted_string()?.into())
81        } else {
82            let s = self.reader.read_unquoted_string()?;
83
84            if s.is_empty() {
85                self.reader.set_position(start);
86                Err(anyhow::anyhow!("missing expected value"))
87            } else {
88                Self::parse_type(&s).or_else(|_| Ok(Tag::String(s)))
89            }
90        }
91    }
92
93    fn parse_type(s: &str) -> anyhow::Result<Tag> {
94        let len = s.len();
95
96        Ok(if FLOAT_PATTERN.is_match(&s) {
97            Tag::Float(s[..len - 1].parse()?)
98        } else if BYTE_PATTERN.is_match(&s) {
99            Tag::Byte(s[..len - 1].parse()?)
100        } else if LONG_PATTERN.is_match(&s) {
101            Tag::Long(s[..len - 1].parse()?)
102        } else if SHORT_PATTERN.is_match(&s) {
103            Tag::Short(s[..len - 1].parse()?)
104        } else if INT_PATTERN.is_match(&s) {
105            Tag::Int(s.parse()?)
106        } else if DOUBLE_PATTERN.is_match(&s) {
107            Tag::Double(s[..len - 1].parse()?)
108        } else if DOUBLE_PATTERN_NOSUFFIX.is_match(&s) {
109            Tag::Double(s.parse()?)
110        } else if s.to_lowercase() == "true" {
111            Tag::Byte(1)
112        } else if s.to_lowercase() == "false" {
113            Tag::Byte(0)
114        } else {
115            anyhow::bail!("unknown type")
116        })
117    }
118
119    pub fn read_value(&mut self) -> anyhow::Result<Tag> {
120        self.reader.skip_whitespace()?;
121
122        if self.reader.done() {
123            anyhow::bail!("missing expected value");
124        }
125
126        let chr = self.reader.peek()?;
127
128        if chr == '{' {
129            self.read_struct()
130        } else if chr == '[' {
131            self.read_list()
132        } else {
133            self.read_typed_value()
134        }
135    }
136
137    fn has_separator(&mut self) -> anyhow::Result<bool> {
138        self.reader.skip_whitespace()?;
139
140        Ok(if !self.reader.done() && self.reader.peek()? == ',' {
141            self.reader.skip();
142            self.reader.skip_whitespace()?;
143
144            true
145        } else {
146            false
147        })
148    }
149
150    pub fn read_struct(&mut self) -> anyhow::Result<Tag> {
151        self.expect('{')?;
152        self.reader.skip_whitespace()?;
153
154        let mut m = Map::new();
155
156        while self.reader.peek()? != '}' {
157            let start = self.reader.position();
158            let key = self.read_key()?;
159
160            if key.is_empty() {
161                self.reader.set_position(start);
162                anyhow::bail!("missing expected key");
163            }
164
165            self.expect(':')?;
166
167            // map key to read value
168            m.insert(key, self.read_value()?);
169
170            if !self.has_separator()? {
171                break;
172            }
173
174            if self.reader.done() {
175                anyhow::bail!("expected struct closure");
176            }
177        }
178
179        self.expect('}')?;
180        Ok(Tag::Compound(m))
181    }
182
183    pub fn read_array_tag(&mut self) -> anyhow::Result<Tag> {
184        self.expect('[')?;
185
186        // store start position in case error
187        let start = self.reader.position();
188        let kind = self.reader.read()?;
189
190        self.reader.skip();
191        self.reader.skip_whitespace()?;
192
193        if self.reader.done() {
194            self.reader.set_position(start);
195            anyhow::bail!("missing expected array value");
196        }
197
198        let tag = if kind == 'B' {
199            read_array!(self, Byte, i8)
200        } else if kind == 'L' {
201            read_array!(self, Long, i64)
202        } else if kind == 'I' {
203            read_array!(self, Int, i32)
204        } else {
205            anyhow::bail!("unknown array type");
206        };
207
208        self.expect(']')?;
209        Ok(tag)
210    }
211
212
213    pub fn read_list_tag(&mut self) -> anyhow::Result<Tag> {
214        self.expect('[')?;
215        self.reader.skip_whitespace()?;
216
217        if self.reader.done() {
218            anyhow::bail!("missing expected array value");
219        }
220
221        let mut kind = Kind::End;
222        let mut v = vec![];
223
224        while self.reader.peek()? != ']' {
225            let start = self.reader.position();
226            let tag = self.read_value()?;
227
228            if kind == Kind::End {
229                kind = tag.kind();
230            } else if kind != tag.kind() {
231                self.reader.set_position(start);
232                anyhow::bail!("array has mixed types");
233            }
234
235            v.push(tag);
236
237            if !self.has_separator()? {
238                break;
239            }
240
241            if self.reader.done() {
242                anyhow::bail!("expected array closure")
243            }
244        }
245
246        self.expect(']')?;
247        Ok(Tag::List(v))
248    }
249
250    pub fn read_list(&mut self) -> anyhow::Result<Tag> {
251        if self.reader.has_remaining(3) && !Reader::is_quote(self.reader.peek_nth(1)?) && self.reader.peek_nth(2)? == ';' {
252            self.read_array_tag()
253        } else {
254            self.read_list_tag()
255        }
256    }
257}
258
259impl Nbt {
260    pub fn parse<S: Into<String>>(s: S) -> anyhow::Result<Tag> {
261        let mut parser = Parser::new(s);
262        let tag = parser.read_value()?;
263
264        Ok(tag)
265    }
266}