Skip to main content

steel_core/command/execution/selector/
parser.rs

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
706#[derive(Clone)]
707struct SelectorReader<'a> {
708    input: &'a str,
709    cursor: usize,
710}
711
712impl<'a> SelectorReader<'a> {
713    const fn new(input: &'a str) -> Self {
714        Self { input, cursor: 0 }
715    }
716
717    const fn cursor(&self) -> usize {
718        self.cursor
719    }
720
721    const fn can_read(&self) -> bool {
722        self.cursor < self.input.len()
723    }
724
725    fn remaining(&self) -> &'a str {
726        &self.input[self.cursor..]
727    }
728
729    fn peek(&self) -> Option<char> {
730        self.remaining().chars().next()
731    }
732
733    fn read(&mut self) -> Option<char> {
734        let ch = self.peek()?;
735        self.cursor += ch.len_utf8();
736        Some(ch)
737    }
738
739    fn skip_whitespace(&mut self) {
740        while self.peek().is_some_and(java::is_whitespace) {
741            self.read();
742        }
743    }
744
745    fn expect(&mut self, expected: char) -> Result<(), SelectorParseError> {
746        if self.peek() == Some(expected) {
747            self.read();
748            Ok(())
749        } else {
750            Err(SelectorParseError::invalid_at(
751                format!("expected '{expected}'"),
752                self.cursor,
753            ))
754        }
755    }
756
757    fn read_remaining(&mut self) -> String {
758        let value = self.remaining().to_owned();
759        self.cursor = self.input.len();
760        value
761    }
762
763    fn read_key(&mut self) -> Result<String, SelectorParseError> {
764        let start = self.cursor;
765        if self.peek().is_some_and(is_quoted_string_start) {
766            return self.read_quoted_string();
767        }
768
769        let key = self.read_unquoted_string();
770        if key.is_empty() {
771            return Err(SelectorParseError::invalid_at(
772                "expected selector option name",
773                start,
774            ));
775        }
776        Ok(key)
777    }
778
779    fn read_scores(&mut self) -> Result<Vec<(String, IntRange)>, SelectorParseError> {
780        self.expect('{')?;
781        let mut scores = Vec::new();
782        self.skip_whitespace();
783        while self.peek().is_some_and(|ch| ch != '}') {
784            self.skip_whitespace();
785            let name = self.read_unquoted_string();
786            self.skip_whitespace();
787            self.expect('=')?;
788            self.skip_whitespace();
789            let range_cursor = self.cursor;
790            let range = parse_int_range(&self.read_range_value(), range_cursor)?;
791            upsert_score_filter(&mut scores, name, range);
792            self.skip_whitespace();
793            match self.peek() {
794                Some(',') => {
795                    self.read();
796                    self.skip_whitespace();
797                }
798                Some('}') | None => {}
799                Some(_) => {
800                    return Err(SelectorParseError::invalid_at(
801                        "expected ',' or '}' after score range",
802                        self.cursor,
803                    ));
804                }
805            }
806        }
807        self.expect('}')?;
808        Ok(scores)
809    }
810
811    fn read_unquoted_string(&mut self) -> String {
812        let start = self.cursor;
813        while self.peek().is_some_and(is_brigadier_unquoted_char) {
814            self.read();
815        }
816        self.input[start..self.cursor].to_owned()
817    }
818
819    fn read_required_unquoted_string(&mut self) -> Result<String, SelectorParseError> {
820        let start = self.cursor;
821        let value = self.read_unquoted_string();
822        if value.is_empty() {
823            return Err(SelectorParseError::invalid_at(
824                "expected selector option value",
825                start,
826            ));
827        }
828        Ok(value)
829    }
830
831    fn read_identifier_string(&mut self) -> String {
832        let start = self.cursor;
833        while self.peek().is_some_and(is_identifier_char) {
834            self.read();
835        }
836        self.input[start..self.cursor].to_owned()
837    }
838
839    fn read_number_string(&mut self) -> String {
840        self.skip_whitespace();
841        let start = self.cursor;
842        while self.peek().is_some_and(is_number_char) {
843            self.read();
844        }
845        self.input[start..self.cursor].to_owned()
846    }
847
848    fn read_range_value(&mut self) -> String {
849        self.skip_whitespace();
850        let start = self.cursor;
851        self.read_range_number();
852        if self.peek() == Some('.') && self.peek_next() == Some('.') {
853            self.read();
854            self.read();
855            self.read_range_number();
856        }
857        self.input[start..self.cursor].to_owned()
858    }
859
860    fn read_range_number(&mut self) {
861        while self
862            .peek()
863            .is_some_and(|ch| is_range_number_char(ch, self.peek_next()))
864        {
865            self.read();
866        }
867    }
868
869    fn peek_next(&self) -> Option<char> {
870        let mut chars = self.remaining().chars();
871        chars.next()?;
872        chars.next()
873    }
874
875    fn read_nbt(&mut self) -> Result<NbtCompound, SelectorParseError> {
876        let nbt_cursor = self.cursor;
877        let (nbt, consumed) =
878            parse_snbt_compound_argument(&self.input[self.cursor..]).map_err(|error| {
879                SelectorParseError::invalid_at(error.component(), nbt_cursor + error.cursor())
880            })?;
881        self.cursor += consumed;
882        Ok(nbt)
883    }
884
885    fn read_inversion(&mut self) -> bool {
886        self.skip_whitespace();
887        if self.peek() == Some('!') {
888            self.read();
889            self.skip_whitespace();
890            true
891        } else {
892            false
893        }
894    }
895
896    fn read_i32(&mut self) -> Result<i32, SelectorParseError> {
897        let cursor = self.cursor;
898        let value = self.read_number_string();
899        value.parse().map_err(|_| {
900            SelectorParseError::invalid_at(format!("invalid integer '{value}'"), cursor)
901        })
902    }
903
904    fn read_f64(&mut self) -> Result<f64, SelectorParseError> {
905        let cursor = self.cursor;
906        let value = self.read_number_string();
907        value.parse().map_err(|_| {
908            SelectorParseError::invalid_at(format!("invalid double '{value}'"), cursor)
909        })
910    }
911
912    fn read_string(&mut self) -> Result<String, SelectorParseError> {
913        self.skip_whitespace();
914        match self.peek() {
915            Some(ch) if is_quoted_string_start(ch) => self.read_quoted_string(),
916            _ => Ok(self.read_unquoted_string()),
917        }
918    }
919
920    fn read_quoted_string(&mut self) -> Result<String, SelectorParseError> {
921        let start = self.cursor;
922        let Some(quote) = self.read() else {
923            return Err(SelectorParseError::invalid_at(
924                "expected quoted string",
925                start,
926            ));
927        };
928        let mut value = String::new();
929        while let Some(ch) = self.read() {
930            match ch {
931                ch if ch == quote => return Ok(value),
932                '\\' => {
933                    let Some(escaped) = self.read() else {
934                        return Err(SelectorParseError::invalid_at("unclosed quote", start));
935                    };
936                    if escaped != quote && escaped != '\\' {
937                        return Err(SelectorParseError::invalid_at(
938                            format!("invalid escape '{escaped}'"),
939                            self.cursor,
940                        ));
941                    }
942                    value.push(escaped);
943                }
944                _ => value.push(ch),
945            }
946        }
947        Err(SelectorParseError::invalid_at("unclosed quote", start))
948    }
949}
950
951fn upsert_score_filter(scores: &mut Vec<(String, IntRange)>, name: String, range: IntRange) {
952    if let Some((_, existing)) = scores
953        .iter_mut()
954        .find(|(existing_name, _)| existing_name == &name)
955    {
956        *existing = range;
957        return;
958    }
959    scores.push((name, range));
960}
961
962const fn is_brigadier_unquoted_char(ch: char) -> bool {
963    ch.is_ascii_alphanumeric() || matches!(ch, '_' | '-' | '.' | '+')
964}
965
966const fn is_identifier_char(ch: char) -> bool {
967    ch.is_ascii_digit() || matches!(ch, 'a'..='z' | '_' | ':' | '/' | '.' | '-')
968}
969
970const fn is_number_char(ch: char) -> bool {
971    ch.is_ascii_digit() || matches!(ch, '.' | '-')
972}
973
974fn is_range_number_char(ch: char, next: Option<char>) -> bool {
975    ch.is_ascii_digit() || ch == '-' || (ch == '.' && next != Some('.'))
976}
977
978const fn is_quoted_string_start(ch: char) -> bool {
979    matches!(ch, '"' | '\'')
980}