blocky_nbt/tag/parser/
mod.rs1mod 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 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 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}