1use super::*;
2
3pub(crate) fn parse_entity_selector<S>(
4 reader: &mut StringReader<'_>,
5 source: &S,
6 single: bool,
7 players_only: bool,
8) -> Result<EntitySelector, CommandSyntaxError>
9where
10 S: CommandArgumentSource + ?Sized,
11{
12 let start = reader.checkpoint();
13 let raw = read_selector_argument(reader)?;
14 let allow_selectors = allow_selectors(source);
15 let allow_advanced = allow_advanced_selectors(source);
16 let selector = parse_selector_plan_with_permissions(&raw, allow_selectors, allow_advanced)
17 .map_err(|error| selector_syntax_error(reader, start, &raw, error))?;
18 selector
19 .validate_for_argument(single, players_only)
20 .map_err(|error| selector_syntax_error(reader, start, &raw, error))?;
21 Ok(selector)
22}
23
24pub(crate) fn parse_entity_selector_text(raw: &str) -> Result<EntitySelector, CommandSyntaxError> {
25 let mut command_reader = StringReader::new(raw);
26 if command_reader.peek() != Some('@') {
27 let name = command_reader.read_string()?;
28 if command_reader.can_read() {
29 return Err(
30 command_reader.error(CommandSyntaxErrorKind::Dynamic(Box::new(
31 TextComponent::plain("unexpected trailing selector data"),
32 ))),
33 );
34 }
35 return parse_name_or_uuid_value(name).map_err(|error| {
36 let mut error_reader = StringReader::new(raw);
37 let start = error_reader.checkpoint();
38 selector_syntax_error(&mut error_reader, start, raw, error)
39 });
40 }
41
42 let mut reader = StringReader::new(raw);
43 let start = reader.checkpoint();
44 parse_selector_plan_with_permissions(raw, true, true)
45 .map_err(|error| selector_syntax_error(&mut reader, start, raw, error))
46}
47
48fn selector_syntax_error(
49 reader: &mut StringReader<'_>,
50 start: ReaderCursor,
51 raw: &str,
52 error: SelectorParseError,
53) -> CommandSyntaxError {
54 reader.restore(start);
55 let end = error.cursor.min(raw.len());
56 if raw.is_char_boundary(end) {
57 for _ in raw[..end].chars() {
58 reader.skip();
59 }
60 }
61 reader.error(CommandSyntaxErrorKind::Dynamic(Box::new(error.message())))
62}
63
64pub(super) fn allow_selectors<S>(source: &S) -> bool
65where
66 S: CommandArgumentSource + ?Sized,
67{
68 source.allows_entity_selectors()
69}
70
71pub(super) fn allow_advanced_selectors<S>(source: &S) -> bool
72where
73 S: CommandArgumentSource + ?Sized,
74{
75 source.allows_advanced_entity_selectors()
76}
77
78pub(super) fn read_selector_argument(
79 reader: &mut StringReader<'_>,
80) -> Result<String, CommandSyntaxError> {
81 if reader.peek() != Some('@') {
82 return reader.read_string();
83 }
84
85 let mut value = String::new();
86 let mut option_depth = 0usize;
87 let mut quote = None;
88 let mut escaped = false;
89 while let Some(ch) = reader.peek() {
90 if option_depth == 0 && !value.is_empty() && java::is_whitespace(ch) {
91 break;
92 }
93 value.push(ch);
94 reader.skip();
95 if escaped {
96 escaped = false;
97 continue;
98 }
99 if quote.is_some() {
100 if ch == '\\' {
101 escaped = true;
102 } else if quote == Some(ch) {
103 quote = None;
104 }
105 continue;
106 }
107 match ch {
108 '"' | '\'' => quote = Some(ch),
109 '[' => option_depth += 1,
110 ']' if option_depth > 0 => {
111 option_depth -= 1;
112 if option_depth == 0 {
113 break;
114 }
115 }
116 _ => {}
117 }
118 }
119 if value.is_empty() {
120 return Err(reader.error(CommandSyntaxErrorKind::Dynamic(Box::new(
121 TextComponent::from(&translations::ARGUMENT_ENTITY_INVALID),
122 ))));
123 }
124 Ok(value)
125}
126
127fn is_valid_selector_name(name: &str) -> bool {
128 !name.is_empty() && name.encode_utf16().count() <= 16
129}
130
131#[cfg(test)]
132pub(super) fn parse_selector_plan(
133 raw: &str,
134 allow_selectors: bool,
135) -> Result<EntitySelector, SelectorParseError> {
136 parse_selector_plan_with_permissions(raw, allow_selectors, allow_selectors)
137}
138
139pub(super) fn parse_selector_plan_with_permissions(
140 raw: &str,
141 allow_selectors: bool,
142 allow_advanced_selectors: bool,
143) -> Result<EntitySelector, SelectorParseError> {
144 let mut reader = SelectorReader::new(raw);
145 if reader.peek() == Some('@') {
146 if !allow_selectors {
147 return Err(SelectorParseError::not_allowed(reader.cursor()));
148 }
149 reader.read();
150 parse_selector_type(&mut reader, allow_advanced_selectors)
151 } else {
152 parse_name_or_uuid(&mut reader)
153 }
154}
155
156fn parse_name_or_uuid(
157 reader: &mut SelectorReader<'_>,
158) -> Result<EntitySelector, SelectorParseError> {
159 let name = reader.read_remaining();
160 parse_name_or_uuid_value(name)
161}
162
163fn parse_name_or_uuid_value(name: String) -> Result<EntitySelector, SelectorParseError> {
164 if let Ok(uuid) = Uuid::parse_str(&name) {
165 return Ok(EntitySelector::new(
166 SelectorKind::EntityUuid(uuid),
167 1,
168 true,
169 false,
170 SelectorOrder::Arbitrary,
171 ));
172 }
173 if !is_valid_selector_name(&name) {
174 return Err(SelectorParseError::invalid_at(
175 "invalid player name or UUID",
176 0,
177 ));
178 }
179 Ok(EntitySelector::new(
180 SelectorKind::PlayerName(name),
181 1,
182 false,
183 false,
184 SelectorOrder::Arbitrary,
185 ))
186}
187
188fn parse_selector_type(
189 reader: &mut SelectorReader<'_>,
190 allow_advanced_selectors: bool,
191) -> Result<EntitySelector, SelectorParseError> {
192 let selector_start = reader.cursor();
193 let Some(selector_type) = reader.read() else {
194 return Err(SelectorParseError::invalid_at(
195 "missing selector type",
196 selector_start,
197 ));
198 };
199
200 let selector_type = match selector_type {
201 'a' => SelectorType::AllPlayers,
202 'e' => SelectorType::AllEntities,
203 'n' => SelectorType::NearestEntity,
204 'p' => SelectorType::NearestPlayer,
205 'r' => SelectorType::RandomPlayer,
206 's' => SelectorType::SelfEntity,
207 other => {
208 return Err(SelectorParseError::invalid_at(
209 format!("unknown selector type '@{other}'"),
210 selector_start,
211 ));
212 }
213 };
214 let mut selector = EntitySelector::for_selector_type(selector_type);
215
216 if reader.peek() == Some('[') {
217 reader.read();
218 parse_options(reader, &mut selector, allow_advanced_selectors)?;
219 }
220 if reader.can_read() {
221 return Err(SelectorParseError::invalid_at(
222 "unexpected trailing selector data",
223 reader.cursor(),
224 ));
225 }
226 Ok(selector)
227}
228
229fn parse_options(
230 reader: &mut SelectorReader<'_>,
231 selector: &mut EntitySelector,
232 allow_advanced_selectors: bool,
233) -> Result<(), SelectorParseError> {
234 let mut state = SelectorOptionState::default();
235 reader.skip_whitespace();
236 while reader.peek().is_some_and(|ch| ch != ']') {
237 if !allow_advanced_selectors {
238 return Err(SelectorParseError::advanced_not_allowed(reader.cursor()));
239 }
240 reader.skip_whitespace();
241 let key_cursor = reader.cursor();
242 let key = reader.read_key()?;
243 selector.uses_advanced_options = true;
244 reader.skip_whitespace();
245 reader.expect('=')?;
246 reader.skip_whitespace();
247 parse_option(reader, selector, &mut state, &key, key_cursor)?;
248 reader.skip_whitespace();
249 match reader.peek() {
250 Some(',') => {
251 reader.read();
252 reader.skip_whitespace();
253 }
254 Some(']') => break,
255 Some(_) => {
256 return Err(SelectorParseError::invalid_at(
257 "expected ',' or ']' after selector option",
258 reader.cursor(),
259 ));
260 }
261 None => {
262 return Err(SelectorParseError::invalid_at(
263 "expected ']' to end selector options",
264 reader.cursor(),
265 ));
266 }
267 }
268 }
269 reader.expect(']')?;
270 Ok(())
271}
272
273fn parse_option(
274 reader: &mut SelectorReader<'_>,
275 selector: &mut EntitySelector,
276 state: &mut SelectorOptionState,
277 key: &str,
278 key_cursor: usize,
279) -> Result<(), SelectorParseError> {
280 match key {
281 "name" => parse_name_option(reader, selector, state),
282 "distance" => parse_distance_option(reader, selector, state, key_cursor),
283 "level" => parse_level_option(reader, selector, state, key_cursor),
284 "x" => {
285 ensure_set_once(&mut state.x, "x", key_cursor)?;
286 selector.world_limited = true;
287 selector.position.x = Some(reader.read_f64()?);
288 Ok(())
289 }
290 "y" => {
291 ensure_set_once(&mut state.y, "y", key_cursor)?;
292 selector.world_limited = true;
293 selector.position.y = Some(reader.read_f64()?);
294 Ok(())
295 }
296 "z" => {
297 ensure_set_once(&mut state.z, "z", key_cursor)?;
298 selector.world_limited = true;
299 selector.position.z = Some(reader.read_f64()?);
300 Ok(())
301 }
302 "dx" => {
303 ensure_set_once(&mut state.dx, "dx", key_cursor)?;
304 selector.world_limited = true;
305 selector.delta.x = Some(reader.read_f64()?);
306 Ok(())
307 }
308 "dy" => {
309 ensure_set_once(&mut state.dy, "dy", key_cursor)?;
310 selector.world_limited = true;
311 selector.delta.y = Some(reader.read_f64()?);
312 Ok(())
313 }
314 "dz" => {
315 ensure_set_once(&mut state.dz, "dz", key_cursor)?;
316 selector.world_limited = true;
317 selector.delta.z = Some(reader.read_f64()?);
318 Ok(())
319 }
320 "x_rotation" => {
321 ensure_set_once(&mut state.x_rotation, "x_rotation", key_cursor)?;
322 let value_cursor = reader.cursor();
323 selector.x_rotation =
324 Some(parse_float_range(&reader.read_range_value(), value_cursor)?);
325 Ok(())
326 }
327 "y_rotation" => {
328 ensure_set_once(&mut state.y_rotation, "y_rotation", key_cursor)?;
329 let value_cursor = reader.cursor();
330 selector.y_rotation =
331 Some(parse_float_range(&reader.read_range_value(), value_cursor)?);
332 Ok(())
333 }
334 "limit" => parse_limit_option(reader, selector, state, key_cursor),
335 "sort" => parse_sort_option(reader, selector, state, key_cursor),
336 "gamemode" => parse_gamemode_option(reader, selector, state),
337 "type" => parse_type_option(reader, selector, state),
338 "tag" => {
339 parse_tag_option(reader, selector);
340 Ok(())
341 }
342 "team" => parse_team_option(reader, selector, state),
343 "nbt" => parse_nbt_option(reader, selector),
344 "scores" => parse_scores_option(reader, selector, state, key_cursor),
345 "predicate" => Err(SelectorParseError::unsupported(
346 "predicate needs a reloadable or plugin predicate registry",
347 key_cursor,
348 )),
349 "advancements" => Err(SelectorParseError::unsupported(
350 "advancements needs player advancement foundation",
351 key_cursor,
352 )),
353 _ => Err(SelectorParseError::invalid_at(
354 format!("unknown selector option '{key}'"),
355 key_cursor,
356 )),
357 }
358}
359
360fn parse_name_option(
361 reader: &mut SelectorReader<'_>,
362 selector: &mut EntitySelector,
363 state: &mut SelectorOptionState,
364) -> Result<(), SelectorParseError> {
365 let value_cursor = reader.cursor();
366 let inverted = reader.read_inversion();
367 state
368 .name
369 .parse_element(inverted, "name")
370 .map_err(|error| {
371 SelectorParseError::invalid_at(
372 match error.kind {
373 SelectorParseErrorKind::Invalid(message) => *message,
374 SelectorParseErrorKind::NotAllowed
375 | SelectorParseErrorKind::AdvancedNotAllowed
376 | SelectorParseErrorKind::Unsupported(_) => {
377 TextComponent::from("invalid name option")
378 }
379 },
380 value_cursor,
381 )
382 })?;
383 let value = reader.read_string()?;
384 selector
385 .filters
386 .push(SelectorFilter::Name { value, inverted });
387 Ok(())
388}
389
390fn parse_scores_option(
391 reader: &mut SelectorReader<'_>,
392 selector: &mut EntitySelector,
393 state: &mut SelectorOptionState,
394 key_cursor: usize,
395) -> Result<(), SelectorParseError> {
396 ensure_set_once(&mut state.scores, "scores", key_cursor)?;
397 let scores = reader.read_scores()?;
398 if !scores.is_empty() {
399 selector.filters.push(SelectorFilter::Scores(scores));
400 }
401 Ok(())
402}
403
404fn parse_distance_option(
405 reader: &mut SelectorReader<'_>,
406 selector: &mut EntitySelector,
407 state: &mut SelectorOptionState,
408 key_cursor: usize,
409) -> Result<(), SelectorParseError> {
410 ensure_set_once(&mut state.distance, "distance", key_cursor)?;
411 let value_cursor = reader.cursor();
412 let range = parse_double_range(&reader.read_range_value(), value_cursor)?;
413 if range.min.is_some_and(|value| value < 0.0) || range.max.is_some_and(|value| value < 0.0) {
414 return Err(SelectorParseError::invalid_at(
415 "distance cannot be negative",
416 key_cursor,
417 ));
418 }
419 selector.distance = Some(range);
420 selector.world_limited = true;
421 Ok(())
422}
423
424fn parse_level_option(
425 reader: &mut SelectorReader<'_>,
426 selector: &mut EntitySelector,
427 state: &mut SelectorOptionState,
428 key_cursor: usize,
429) -> Result<(), SelectorParseError> {
430 ensure_set_once(&mut state.level, "level", key_cursor)?;
431 let value_cursor = reader.cursor();
432 let range = parse_int_range(&reader.read_range_value(), value_cursor)?;
433 if range.min.is_some_and(|value| value < 0) || range.max.is_some_and(|value| value < 0) {
434 return Err(SelectorParseError::invalid_at(
435 "level cannot be negative",
436 key_cursor,
437 ));
438 }
439 selector.level = Some(range);
440 selector.includes_entities = false;
441 Ok(())
442}
443
444fn parse_limit_option(
445 reader: &mut SelectorReader<'_>,
446 selector: &mut EntitySelector,
447 state: &mut SelectorOptionState,
448 key_cursor: usize,
449) -> Result<(), SelectorParseError> {
450 if selector.current_entity {
451 return Err(SelectorParseError::invalid_at(
452 "limit cannot be used with @s",
453 key_cursor,
454 ));
455 }
456 ensure_set_once(&mut state.limit, "limit", key_cursor)?;
457 let value = reader.read_i32()?;
458 if value < 1 {
459 return Err(SelectorParseError::invalid_at(
460 "limit must be at least 1",
461 key_cursor,
462 ));
463 }
464 selector.max_results = value as usize;
465 Ok(())
466}
467
468fn parse_sort_option(
469 reader: &mut SelectorReader<'_>,
470 selector: &mut EntitySelector,
471 state: &mut SelectorOptionState,
472 key_cursor: usize,
473) -> Result<(), SelectorParseError> {
474 if selector.current_entity {
475 return Err(SelectorParseError::invalid_at(
476 "sort cannot be used with @s",
477 key_cursor,
478 ));
479 }
480 ensure_set_once(&mut state.sort, "sort", key_cursor)?;
481 let value = reader.read_required_unquoted_string()?;
482 selector.order = match value.as_str() {
483 SORT_NEAREST => SelectorOrder::Nearest,
484 SORT_FURTHEST => SelectorOrder::Furthest,
485 SORT_RANDOM => SelectorOrder::Random,
486 SORT_ARBITRARY => SelectorOrder::Arbitrary,
487 _ => {
488 return Err(SelectorParseError::invalid_at(
489 format!("unknown sort '{value}'"),
490 key_cursor,
491 ));
492 }
493 };
494 Ok(())
495}
496
497fn parse_gamemode_option(
498 reader: &mut SelectorReader<'_>,
499 selector: &mut EntitySelector,
500 state: &mut SelectorOptionState,
501) -> Result<(), SelectorParseError> {
502 let value_cursor = reader.cursor();
503 let inverted = reader.read_inversion();
504 state.gamemode.parse_element(inverted, "gamemode")?;
505 let value = reader.read_required_unquoted_string()?;
506 let Some(game_mode) = parse_game_mode(&value) else {
507 return Err(SelectorParseError::invalid_at(
508 format!("invalid game mode '{value}'"),
509 value_cursor,
510 ));
511 };
512 selector.includes_entities = false;
513 selector.filters.push(SelectorFilter::GameMode {
514 value: game_mode,
515 inverted,
516 });
517 Ok(())
518}
519
520fn parse_type_option(
521 reader: &mut SelectorReader<'_>,
522 selector: &mut EntitySelector,
523 state: &mut SelectorOptionState,
524) -> Result<(), SelectorParseError> {
525 let value_cursor = reader.cursor();
526 let inverted = reader.read_inversion();
527 if reader.peek() == Some('#') {
528 reader.read();
529 reader.skip_whitespace();
530 let value = read_identifier(reader, value_cursor)?;
531 state.entity_type.parse_tag(&value, "type")?;
532 selector
533 .filters
534 .push(SelectorFilter::EntityTypeTag { value, inverted });
535 return Ok(());
536 }
537
538 state.entity_type.parse_element(inverted, "type")?;
539 let key = read_identifier(reader, value_cursor)?;
540 let Some(entity_type) = REGISTRY.entity_types.by_key(&key) else {
541 return Err(SelectorParseError::invalid_at(
542 format!("invalid entity type '{key}'"),
543 value_cursor,
544 ));
545 };
546 if entity_type == &vanilla_entities::PLAYER && !inverted {
547 selector.includes_entities = false;
548 }
549 selector.filters.push(SelectorFilter::EntityType {
550 value: entity_type,
551 inverted,
552 });
553 Ok(())
554}
555
556fn parse_tag_option(reader: &mut SelectorReader<'_>, selector: &mut EntitySelector) {
557 let inverted = reader.read_inversion();
558 let value = reader.read_unquoted_string();
559 selector
560 .filters
561 .push(SelectorFilter::Tag { value, inverted });
562}
563
564fn parse_team_option(
565 reader: &mut SelectorReader<'_>,
566 selector: &mut EntitySelector,
567 state: &mut SelectorOptionState,
568) -> Result<(), SelectorParseError> {
569 let inverted = reader.read_inversion();
570 state.team.parse_element(inverted, "team")?;
571 let value = reader.read_unquoted_string();
572 selector
573 .filters
574 .push(SelectorFilter::Team { value, inverted });
575 Ok(())
576}
577
578fn parse_nbt_option(
579 reader: &mut SelectorReader<'_>,
580 selector: &mut EntitySelector,
581) -> Result<(), SelectorParseError> {
582 let inverted = reader.read_inversion();
583 let value = reader.read_nbt()?;
584 selector
585 .filters
586 .push(SelectorFilter::Nbt { value, inverted });
587 Ok(())
588}
589
590fn read_identifier(
591 reader: &mut SelectorReader<'_>,
592 value_cursor: usize,
593) -> Result<Identifier, SelectorParseError> {
594 let value = reader.read_identifier_string();
595 parse_resource_identifier_value(&value).ok_or_else(|| {
596 SelectorParseError::invalid_at(format!("invalid identifier '{value}'"), value_cursor)
597 })
598}
599
600pub(super) fn parse_resource_identifier_value(value: &str) -> Option<Identifier> {
601 let (namespace, path) = value.split_once(':').map_or(
602 (Identifier::VANILLA_NAMESPACE, value),
603 |(namespace, path)| {
604 if namespace.is_empty() {
605 (Identifier::VANILLA_NAMESPACE, path)
606 } else {
607 (namespace, path)
608 }
609 },
610 );
611 Identifier::validate(namespace, path)
612 .then(|| Identifier::new(namespace.to_owned(), path.to_owned()))
613}
614
615fn ensure_set_once(seen: &mut bool, option: &str, cursor: usize) -> Result<(), SelectorParseError> {
616 if *seen {
617 return Err(SelectorParseError::invalid_at(
618 format!("option '{option}' cannot be repeated"),
619 cursor,
620 ));
621 }
622 *seen = true;
623 Ok(())
624}
625
626fn parse_game_mode(value: &str) -> Option<GameType> {
627 match value {
628 "survival" => Some(GameType::Survival),
629 "creative" => Some(GameType::Creative),
630 "adventure" => Some(GameType::Adventure),
631 "spectator" => Some(GameType::Spectator),
632 _ => None,
633 }
634}
635
636fn parse_double_range(raw: &str, cursor: usize) -> Result<DoubleRange, SelectorParseError> {
637 let (min, max) = parse_range(raw, cursor, str::parse::<f64>)?;
638 if let (Some(min), Some(max)) = (min, max)
639 && min > max
640 {
641 return Err(SelectorParseError::invalid_at(
642 "range minimum exceeds maximum",
643 cursor,
644 ));
645 }
646 Ok(DoubleRange { min, max })
647}
648
649fn parse_float_range(raw: &str, cursor: usize) -> Result<FloatRange, SelectorParseError> {
650 let (min, max) = parse_range(raw, cursor, str::parse::<f32>)?;
651 Ok(FloatRange { min, max })
652}
653
654fn parse_int_range(raw: &str, cursor: usize) -> Result<IntRange, SelectorParseError> {
655 let (min, max) = parse_range(raw, cursor, str::parse::<i32>)?;
656 if let (Some(min), Some(max)) = (min, max)
657 && min > max
658 {
659 return Err(SelectorParseError::invalid_at(
660 "range minimum exceeds maximum",
661 cursor,
662 ));
663 }
664 Ok(IntRange { min, max })
665}
666
667fn parse_range<T: Copy, E>(
668 raw: &str,
669 cursor: usize,
670 parse: impl Fn(&str) -> Result<T, E>,
671) -> Result<(Option<T>, Option<T>), SelectorParseError> {
672 if raw.is_empty() {
673 return Err(SelectorParseError::invalid_at(
674 "missing range value",
675 cursor,
676 ));
677 }
678 let Some((left, right)) = raw.split_once("..") else {
679 let value = parse(raw)
680 .map_err(|_| SelectorParseError::invalid_at("invalid range value", cursor))?;
681 return Ok((Some(value), Some(value)));
682 };
683 if left.is_empty() && right.is_empty() {
684 return Err(SelectorParseError::invalid_at("empty range", cursor));
685 }
686 let right_cursor = cursor + left.len() + "..".len();
687 let min = if left.is_empty() {
688 None
689 } else {
690 Some(
691 parse(left)
692 .map_err(|_| SelectorParseError::invalid_at("invalid range minimum", cursor))?,
693 )
694 };
695 let max =
696 if right.is_empty() {
697 None
698 } else {
699 Some(parse(right).map_err(|_| {
700 SelectorParseError::invalid_at("invalid range maximum", right_cursor)
701 })?)
702 };
703 Ok((min, max))
704}
705
706pub(super) fn wrap_degrees(value: f32) -> f32 {
707 let mut value = value % 360.0;
708 if value >= 180.0 {
709 value -= 360.0;
710 }
711 if value < -180.0 {
712 value += 360.0;
713 }
714 value
715}
716
717#[derive(Clone)]
718struct SelectorReader<'a> {
719 input: &'a str,
720 cursor: usize,
721}
722
723impl<'a> SelectorReader<'a> {
724 const fn new(input: &'a str) -> Self {
725 Self { input, cursor: 0 }
726 }
727
728 const fn cursor(&self) -> usize {
729 self.cursor
730 }
731
732 const fn can_read(&self) -> bool {
733 self.cursor < self.input.len()
734 }
735
736 fn remaining(&self) -> &'a str {
737 &self.input[self.cursor..]
738 }
739
740 fn peek(&self) -> Option<char> {
741 self.remaining().chars().next()
742 }
743
744 fn read(&mut self) -> Option<char> {
745 let ch = self.peek()?;
746 self.cursor += ch.len_utf8();
747 Some(ch)
748 }
749
750 fn skip_whitespace(&mut self) {
751 while self.peek().is_some_and(java::is_whitespace) {
752 self.read();
753 }
754 }
755
756 fn expect(&mut self, expected: char) -> Result<(), SelectorParseError> {
757 if self.peek() == Some(expected) {
758 self.read();
759 Ok(())
760 } else {
761 Err(SelectorParseError::invalid_at(
762 format!("expected '{expected}'"),
763 self.cursor,
764 ))
765 }
766 }
767
768 fn read_remaining(&mut self) -> String {
769 let value = self.remaining().to_owned();
770 self.cursor = self.input.len();
771 value
772 }
773
774 fn read_key(&mut self) -> Result<String, SelectorParseError> {
775 let start = self.cursor;
776 if self.peek().is_some_and(is_quoted_string_start) {
777 return self.read_quoted_string();
778 }
779
780 let key = self.read_unquoted_string();
781 if key.is_empty() {
782 return Err(SelectorParseError::invalid_at(
783 "expected selector option name",
784 start,
785 ));
786 }
787 Ok(key)
788 }
789
790 fn read_scores(&mut self) -> Result<Vec<(String, IntRange)>, SelectorParseError> {
791 self.expect('{')?;
792 let mut scores = Vec::new();
793 self.skip_whitespace();
794 while self.peek().is_some_and(|ch| ch != '}') {
795 self.skip_whitespace();
796 let name = self.read_unquoted_string();
797 self.skip_whitespace();
798 self.expect('=')?;
799 self.skip_whitespace();
800 let range_cursor = self.cursor;
801 let range = parse_int_range(&self.read_range_value(), range_cursor)?;
802 upsert_score_filter(&mut scores, name, range);
803 self.skip_whitespace();
804 match self.peek() {
805 Some(',') => {
806 self.read();
807 self.skip_whitespace();
808 }
809 Some('}') | None => {}
810 Some(_) => {
811 return Err(SelectorParseError::invalid_at(
812 "expected ',' or '}' after score range",
813 self.cursor,
814 ));
815 }
816 }
817 }
818 self.expect('}')?;
819 Ok(scores)
820 }
821
822 fn read_unquoted_string(&mut self) -> String {
823 let start = self.cursor;
824 while self.peek().is_some_and(is_brigadier_unquoted_char) {
825 self.read();
826 }
827 self.input[start..self.cursor].to_owned()
828 }
829
830 fn read_required_unquoted_string(&mut self) -> Result<String, SelectorParseError> {
831 let start = self.cursor;
832 let value = self.read_unquoted_string();
833 if value.is_empty() {
834 return Err(SelectorParseError::invalid_at(
835 "expected selector option value",
836 start,
837 ));
838 }
839 Ok(value)
840 }
841
842 fn read_identifier_string(&mut self) -> String {
843 let start = self.cursor;
844 while self.peek().is_some_and(is_identifier_char) {
845 self.read();
846 }
847 self.input[start..self.cursor].to_owned()
848 }
849
850 fn read_number_string(&mut self) -> String {
851 self.skip_whitespace();
852 let start = self.cursor;
853 while self.peek().is_some_and(is_number_char) {
854 self.read();
855 }
856 self.input[start..self.cursor].to_owned()
857 }
858
859 fn read_range_value(&mut self) -> String {
860 self.skip_whitespace();
861 let start = self.cursor;
862 self.read_range_number();
863 if self.peek() == Some('.') && self.peek_next() == Some('.') {
864 self.read();
865 self.read();
866 self.read_range_number();
867 }
868 self.input[start..self.cursor].to_owned()
869 }
870
871 fn read_range_number(&mut self) {
872 while self
873 .peek()
874 .is_some_and(|ch| is_range_number_char(ch, self.peek_next()))
875 {
876 self.read();
877 }
878 }
879
880 fn peek_next(&self) -> Option<char> {
881 let mut chars = self.remaining().chars();
882 chars.next()?;
883 chars.next()
884 }
885
886 fn read_nbt(&mut self) -> Result<NbtCompound, SelectorParseError> {
887 let nbt_cursor = self.cursor;
888 let (nbt, consumed) =
889 parse_snbt_compound_argument(&self.input[self.cursor..]).map_err(|error| {
890 SelectorParseError::invalid_at(error.component(), nbt_cursor + error.cursor())
891 })?;
892 self.cursor += consumed;
893 Ok(nbt)
894 }
895
896 fn read_inversion(&mut self) -> bool {
897 self.skip_whitespace();
898 if self.peek() == Some('!') {
899 self.read();
900 self.skip_whitespace();
901 true
902 } else {
903 false
904 }
905 }
906
907 fn read_i32(&mut self) -> Result<i32, SelectorParseError> {
908 let cursor = self.cursor;
909 let value = self.read_number_string();
910 value.parse().map_err(|_| {
911 SelectorParseError::invalid_at(format!("invalid integer '{value}'"), cursor)
912 })
913 }
914
915 fn read_f64(&mut self) -> Result<f64, SelectorParseError> {
916 let cursor = self.cursor;
917 let value = self.read_number_string();
918 value.parse().map_err(|_| {
919 SelectorParseError::invalid_at(format!("invalid double '{value}'"), cursor)
920 })
921 }
922
923 fn read_string(&mut self) -> Result<String, SelectorParseError> {
924 self.skip_whitespace();
925 match self.peek() {
926 Some(ch) if is_quoted_string_start(ch) => self.read_quoted_string(),
927 _ => Ok(self.read_unquoted_string()),
928 }
929 }
930
931 fn read_quoted_string(&mut self) -> Result<String, SelectorParseError> {
932 let start = self.cursor;
933 let Some(quote) = self.read() else {
934 return Err(SelectorParseError::invalid_at(
935 "expected quoted string",
936 start,
937 ));
938 };
939 let mut value = String::new();
940 while let Some(ch) = self.read() {
941 match ch {
942 ch if ch == quote => return Ok(value),
943 '\\' => {
944 let Some(escaped) = self.read() else {
945 return Err(SelectorParseError::invalid_at("unclosed quote", start));
946 };
947 if escaped != quote && escaped != '\\' {
948 return Err(SelectorParseError::invalid_at(
949 format!("invalid escape '{escaped}'"),
950 self.cursor,
951 ));
952 }
953 value.push(escaped);
954 }
955 _ => value.push(ch),
956 }
957 }
958 Err(SelectorParseError::invalid_at("unclosed quote", start))
959 }
960}
961
962fn upsert_score_filter(scores: &mut Vec<(String, IntRange)>, name: String, range: IntRange) {
963 if let Some((_, existing)) = scores
964 .iter_mut()
965 .find(|(existing_name, _)| existing_name == &name)
966 {
967 *existing = range;
968 return;
969 }
970 scores.push((name, range));
971}
972
973const fn is_brigadier_unquoted_char(ch: char) -> bool {
974 ch.is_ascii_alphanumeric() || matches!(ch, '_' | '-' | '.' | '+')
975}
976
977const fn is_identifier_char(ch: char) -> bool {
978 ch.is_ascii_digit() || matches!(ch, 'a'..='z' | '_' | ':' | '/' | '.' | '-')
979}
980
981const fn is_number_char(ch: char) -> bool {
982 ch.is_ascii_digit() || matches!(ch, '.' | '-')
983}
984
985fn is_range_number_char(ch: char, next: Option<char>) -> bool {
986 ch.is_ascii_digit() || ch == '-' || (ch == '.' && next != Some('.'))
987}
988
989const fn is_quoted_string_start(ch: char) -> bool {
990 matches!(ch, '"' | '\'')
991}