1use simdnbt::{
2 Mutf8String,
3 owned::{NbtCompound, NbtList, NbtTag},
4};
5use uuid::Uuid;
6
7use crate::{UuidExt, java};
8
9use super::{
10 error::{SnbtError, SnbtErrorKind},
11 number::{
12 DefaultIntegerKind, IntegerKind, bool_tag_value, can_start_number, integer_tag_value,
13 is_allowed_in_unicode_name, is_allowed_in_unquoted_string,
14 is_unsuffixed_decimal_integer_token, parse_number_token, scan_number_token,
15 },
16};
17
18pub fn parse_snbt(input: &str) -> Result<NbtTag, SnbtError> {
24 let (tag, cursor) = parse_snbt_argument(input)?;
25 let mut parser = Parser::new(input);
26 parser.cursor = cursor;
27 parser.skip_whitespace();
28 if parser.can_read() {
29 return Err(parser.error(SnbtErrorKind::TrailingData));
30 }
31
32 Ok(tag)
33}
34
35pub fn parse_snbt_argument(input: &str) -> Result<(NbtTag, usize), SnbtError> {
45 let mut parser = Parser::new(input);
46 match parser.parse_tag() {
47 Ok(tag) => Ok((tag, parser.cursor)),
48 Err(error) => Err(parser.resolve_error(error)),
49 }
50}
51
52pub fn parse_snbt_compound(input: &str) -> Result<NbtCompound, SnbtError> {
59 let (compound, cursor) = parse_snbt_compound_argument(input)?;
60 let mut parser = Parser::new(input);
61 parser.cursor = cursor;
62 parser.skip_whitespace();
63 if parser.can_read() {
64 return Err(parser.error(SnbtErrorKind::TrailingData));
65 }
66
67 Ok(compound)
68}
69
70pub fn parse_snbt_compound_argument(input: &str) -> Result<(NbtCompound, usize), SnbtError> {
76 let mut parser = Parser::new(input);
77 match parser.parse_compound() {
78 Ok(compound) => Ok((compound, parser.cursor)),
79 Err(error) => Err(parser.resolve_error(error)),
80 }
81}
82struct Parser<'a> {
83 input: &'a str,
84 cursor: usize,
85 recorded_error: Option<SnbtError>,
86}
87
88impl<'a> Parser<'a> {
89 const fn new(input: &'a str) -> Self {
90 Self {
91 input,
92 cursor: 0,
93 recorded_error: None,
94 }
95 }
96
97 const fn can_read(&self) -> bool {
98 self.cursor < self.input.len()
99 }
100
101 const fn error(&self, kind: SnbtErrorKind) -> SnbtError {
102 SnbtError::new(self.cursor, kind)
103 }
104
105 const fn error_at(cursor: usize, kind: SnbtErrorKind) -> SnbtError {
106 SnbtError::new(cursor, kind)
107 }
108
109 fn record_error(&mut self, cursor: usize, kind: SnbtErrorKind) {
110 if self
111 .recorded_error
112 .as_ref()
113 .is_none_or(|error| cursor > error.cursor())
114 {
115 self.recorded_error = Some(Self::error_at(cursor, kind));
116 }
117 }
118
119 fn resolve_error(&mut self, error: SnbtError) -> SnbtError {
120 match self.recorded_error.take() {
121 Some(recorded) if recorded.cursor() >= error.cursor() => recorded,
122 _ => error,
123 }
124 }
125
126 fn peek(&self) -> Option<char> {
127 self.input[self.cursor..].chars().next()
128 }
129
130 fn read(&mut self) -> Option<char> {
131 let ch = self.peek()?;
132 self.cursor += ch.len_utf8();
133 Some(ch)
134 }
135
136 fn skip_whitespace(&mut self) {
137 while self.peek().is_some_and(java::is_whitespace) {
138 self.read();
139 }
140 }
141
142 fn consume_char(&mut self, expected: char) -> bool {
143 self.skip_whitespace();
144 if self.peek() == Some(expected) {
145 self.read();
146 return true;
147 }
148
149 false
150 }
151
152 fn consume_repeated_separator(&mut self, separator: char) -> bool {
153 self.skip_whitespace();
154 if self.peek() == Some(separator) {
155 self.read();
156 return true;
157 }
158
159 self.record_error(self.cursor, SnbtErrorKind::ExpectedSymbol(separator));
160 false
161 }
162
163 fn expect_char(&mut self, expected: char) -> Result<(), SnbtError> {
164 if self.consume_char(expected) {
165 return Ok(());
166 }
167
168 Err(self.error(SnbtErrorKind::ExpectedSymbol(expected)))
169 }
170
171 fn parse_tag(&mut self) -> Result<NbtTag, SnbtError> {
172 self.skip_whitespace();
173 let Some(ch) = self.peek() else {
174 return Err(self.error(SnbtErrorKind::ExpectedValue));
175 };
176
177 match ch {
178 '{' => Ok(NbtTag::Compound(self.parse_compound()?)),
179 '[' => self.parse_list_or_array(),
180 '"' | '\'' => Ok(NbtTag::String(self.parse_quoted_string()?.into())),
181 ch if can_start_number(ch) => self.parse_number(DefaultIntegerKind::Int, true),
182 ch if is_allowed_in_unquoted_string(ch) => self.parse_unquoted_value(),
183 _ => Err(self.error(SnbtErrorKind::ExpectedValue)),
184 }
185 }
186
187 fn parse_compound(&mut self) -> Result<NbtCompound, SnbtError> {
188 self.expect_char('{')?;
189 let mut compound = NbtCompound::new();
190 if self.consume_char('}') {
191 return Ok(compound);
192 }
193
194 loop {
195 let key = self.parse_map_key()?;
196 self.expect_char(':')?;
197 let tag = self.parse_tag()?;
198 compound.remove(&key);
199 compound.insert(key, tag);
200
201 if self.consume_repeated_separator(',') {
202 if self.consume_char('}') {
203 return Ok(compound);
204 }
205 continue;
206 }
207
208 self.expect_char('}')?;
209 return Ok(compound);
210 }
211 }
212
213 fn parse_map_key(&mut self) -> Result<String, SnbtError> {
214 self.skip_whitespace();
215 let key = match self.peek() {
216 Some('"' | '\'') => self.parse_quoted_string()?,
217 Some(ch) if is_allowed_in_unquoted_string(ch) => self.parse_unquoted_string()?,
218 _ => return Err(self.error(SnbtErrorKind::ExpectedKey)),
219 };
220
221 if key.is_empty() {
222 return Err(self.error(SnbtErrorKind::EmptyKey));
223 }
224
225 Ok(key)
226 }
227
228 fn parse_list_or_array(&mut self) -> Result<NbtTag, SnbtError> {
229 self.expect_char('[')?;
230 if self.consume_char(']') {
231 return Ok(NbtTag::List(NbtList::Empty));
232 }
233
234 let prefix_cursor = self.cursor;
235 self.skip_whitespace();
236 let array_type = match self.peek() {
237 Some('B') => Some(TypedArrayKind::Byte),
238 Some('I') => Some(TypedArrayKind::Int),
239 Some('L') => Some(TypedArrayKind::Long),
240 _ => None,
241 };
242 if let Some(array_type) = array_type {
243 self.read();
244 if self.consume_char(';') {
245 return self.parse_typed_array(array_type);
246 }
247 }
248 self.cursor = prefix_cursor;
249
250 let mut tags = Vec::new();
251 loop {
252 tags.push(self.parse_tag()?);
253 if self.consume_repeated_separator(',') {
254 if self.consume_char(']') {
255 break;
256 }
257 continue;
258 }
259
260 self.expect_char(']')?;
261 break;
262 }
263
264 Ok(NbtTag::List(NbtList::from(tags)))
265 }
266
267 fn parse_typed_array(&mut self, array_type: TypedArrayKind) -> Result<NbtTag, SnbtError> {
268 match array_type {
269 TypedArrayKind::Byte => {
270 let values =
271 self.parse_integer_array(DefaultIntegerKind::Byte, &[IntegerKind::Byte])?;
272 Ok(NbtTag::ByteArray(
273 values.into_iter().map(|value| value as u8).collect(),
274 ))
275 }
276 TypedArrayKind::Int => {
277 let values = self.parse_integer_array(
278 DefaultIntegerKind::Int,
279 &[IntegerKind::Byte, IntegerKind::Short, IntegerKind::Int],
280 )?;
281 Ok(NbtTag::IntArray(
282 values.into_iter().map(|value| value as i32).collect(),
283 ))
284 }
285 TypedArrayKind::Long => Ok(NbtTag::LongArray(self.parse_integer_array(
286 DefaultIntegerKind::Long,
287 &[
288 IntegerKind::Byte,
289 IntegerKind::Short,
290 IntegerKind::Int,
291 IntegerKind::Long,
292 ],
293 )?)),
294 }
295 }
296
297 fn parse_integer_array(
298 &mut self,
299 default_kind: DefaultIntegerKind,
300 allowed_kinds: &[IntegerKind],
301 ) -> Result<Vec<i64>, SnbtError> {
302 let mut values = Vec::new();
303 if self.consume_char(']') {
304 return Ok(values);
305 }
306
307 loop {
308 let cursor = self.cursor;
309 let tag = self.parse_number(default_kind, false)?;
310 let Some((kind, value)) = integer_tag_value(&tag) else {
311 return Err(Self::error_at(cursor, SnbtErrorKind::ExpectedArrayElement));
312 };
313 if !allowed_kinds.contains(&kind) {
314 return Err(Self::error_at(
315 cursor,
316 SnbtErrorKind::InvalidArrayElementType,
317 ));
318 }
319 values.push(value);
320
321 if self.consume_repeated_separator(',') {
322 if self.consume_char(']') {
323 return Ok(values);
324 }
325 continue;
326 }
327
328 self.expect_char(']')?;
329 return Ok(values);
330 }
331 }
332
333 fn parse_unquoted_value(&mut self) -> Result<NbtTag, SnbtError> {
334 let value = self.parse_unquoted_string()?;
335 let after_value = self.cursor;
336
337 self.skip_whitespace();
338 if self.peek() == Some('(') {
339 self.read();
340 return self.parse_builtin(&value);
341 }
342 self.record_error(self.cursor, SnbtErrorKind::ExpectedSymbol('('));
343 self.cursor = after_value;
344
345 if value.eq_ignore_ascii_case("true") {
346 Ok(NbtTag::Byte(1))
347 } else if value.eq_ignore_ascii_case("false") {
348 Ok(NbtTag::Byte(0))
349 } else {
350 Ok(NbtTag::String(Mutf8String::from(value)))
351 }
352 }
353
354 fn parse_builtin(&mut self, name: &str) -> Result<NbtTag, SnbtError> {
355 let arguments = self.parse_builtin_arguments()?;
356 let error_cursor = self.cursor;
357
358 if name == "bool" && arguments.len() == 1 {
359 let Some(value) = arguments.first() else {
360 return Err(Self::error_at(
361 error_cursor,
362 SnbtErrorKind::ExpectedNumberOrBoolean,
363 ));
364 };
365 return bool_tag_value(value)
366 .map(|value| NbtTag::Byte(i8::from(value)))
367 .ok_or_else(|| {
368 Self::error_at(error_cursor, SnbtErrorKind::ExpectedNumberOrBoolean)
369 });
370 }
371
372 if name == "uuid" && arguments.len() == 1 {
373 let Some(NbtTag::String(uuid)) = arguments.first() else {
374 return Err(Self::error_at(
375 error_cursor,
376 SnbtErrorKind::ExpectedStringUuid,
377 ));
378 };
379 let uuid = Uuid::parse_str(uuid.as_str().to_str().as_ref())
382 .map_err(|_| Self::error_at(error_cursor, SnbtErrorKind::ExpectedStringUuid))?;
383 return Ok(NbtTag::IntArray(uuid.to_int_array().to_vec()));
384 }
385
386 Err(Self::error_at(
387 error_cursor,
388 SnbtErrorKind::UnknownOperation {
389 name: name.to_owned(),
390 argument_count: arguments.len(),
391 },
392 ))
393 }
394
395 fn parse_builtin_arguments(&mut self) -> Result<Vec<NbtTag>, SnbtError> {
396 let mut arguments = Vec::new();
397 if self.consume_char(')') {
398 return Ok(arguments);
399 }
400
401 loop {
402 arguments.push(self.parse_tag()?);
403 if self.consume_repeated_separator(',') {
404 if self.consume_char(')') {
405 return Ok(arguments);
406 }
407 continue;
408 }
409
410 self.expect_char(')')?;
411 return Ok(arguments);
412 }
413 }
414
415 fn parse_number(
416 &mut self,
417 default_kind: DefaultIntegerKind,
418 allow_float: bool,
419 ) -> Result<NbtTag, SnbtError> {
420 let start = self.cursor;
421 let token_len = scan_number_token(&self.input[start..], allow_float)
422 .map_err(|error| Self::error_at(start + error.cursor, error.kind))?;
423 self.cursor += token_len;
424
425 let token = &self.input[start..self.cursor];
426 let result = parse_number_token(token, default_kind);
427 let records_float_candidate =
428 allow_float && result.is_ok() && is_unsuffixed_decimal_integer_token(token);
429 if records_float_candidate {
430 self.record_error(self.cursor, SnbtErrorKind::ExpectedSymbol('.'));
431 }
432
433 result.map_err(|kind| self.error(kind))
434 }
435
436 fn parse_quoted_string(&mut self) -> Result<String, SnbtError> {
437 let Some(terminator @ ('"' | '\'')) = self.read() else {
438 return Err(self.error(SnbtErrorKind::ExpectedQuotedString));
439 };
440
441 let mut value = String::new();
442 while let Some(ch) = self.read() {
443 match ch {
444 ch if ch == terminator => return Ok(value),
445 '\\' => value.push(self.parse_escape()?),
446 _ => value.push(ch),
447 }
448 }
449
450 Err(self.error(SnbtErrorKind::UnclosedQuotedString))
451 }
452
453 fn parse_escape(&mut self) -> Result<char, SnbtError> {
454 let escape_cursor = self.cursor;
455 let Some(ch) = self.read() else {
456 return Err(Self::error_at(
457 escape_cursor,
458 SnbtErrorKind::UnclosedEscapeSequence,
459 ));
460 };
461
462 match ch {
463 'b' => Ok('\u{0008}'),
464 's' => Ok(' '),
465 't' => Ok('\t'),
466 'n' => Ok('\n'),
467 'f' => Ok('\u{000C}'),
468 'r' => Ok('\r'),
469 '\\' | '\'' | '"' => Ok(ch),
470 'x' => self.parse_code_point_escape(2, self.cursor),
471 'u' => self.parse_code_point_escape(4, self.cursor),
472 'U' => self.parse_code_point_escape(8, self.cursor),
473 'N' => self.parse_named_escape(),
474 _ => Err(Self::error_at(
475 escape_cursor,
476 SnbtErrorKind::InvalidEscape(ch),
477 )),
478 }
479 }
480
481 fn parse_code_point_escape(
482 &mut self,
483 digits: usize,
484 digit_cursor: usize,
485 ) -> Result<char, SnbtError> {
486 let mut value = 0_u32;
487 for _ in 0..digits {
488 let Some(ch) = self.read() else {
489 return Err(Self::error_at(
490 digit_cursor,
491 SnbtErrorKind::ExpectedHexEscape { digits },
492 ));
493 };
494 let Some(digit) = ch.to_digit(16) else {
495 return Err(Self::error_at(
496 digit_cursor,
497 SnbtErrorKind::ExpectedHexEscape { digits },
498 ));
499 };
500 value = value * 16 + digit;
501 }
502
503 char::from_u32(value).ok_or_else(|| self.error(SnbtErrorKind::InvalidCodepoint(value)))
504 }
505
506 fn parse_named_escape(&mut self) -> Result<char, SnbtError> {
507 let brace_cursor = self.cursor;
508 if self.read() != Some('{') {
509 return Err(Self::error_at(
510 brace_cursor,
511 SnbtErrorKind::ExpectedCharacterName,
512 ));
513 }
514
515 let name_start = self.cursor;
516 while self.peek().is_some_and(is_allowed_in_unicode_name) {
517 self.read();
518 }
519 if self.cursor == name_start {
520 return Err(Self::error_at(
521 name_start,
522 SnbtErrorKind::InvalidCharacterName(String::new()),
523 ));
524 }
525 if self.peek() != Some('}') {
526 return Err(self.error(SnbtErrorKind::UnclosedCharacterName));
527 }
528
529 let name = self.input[name_start..self.cursor].to_owned();
530 self.read();
531 unicode_names2::character(&name)
532 .ok_or_else(|| Self::error_at(self.cursor, SnbtErrorKind::InvalidCharacterName(name)))
533 }
534
535 fn parse_unquoted_string(&mut self) -> Result<String, SnbtError> {
536 let start = self.cursor;
537 while self.peek().is_some_and(is_allowed_in_unquoted_string) {
538 self.read();
539 }
540
541 if self.cursor == start {
542 return Err(Self::error_at(start, SnbtErrorKind::ExpectedUnquotedString));
543 }
544
545 Ok(self.input[start..self.cursor].to_owned())
546 }
547}
548
549#[derive(Clone, Copy, Debug, PartialEq, Eq)]
550enum TypedArrayKind {
551 Byte,
552 Int,
553 Long,
554}