11use proc_macro2:: { Delimiter , Ident , Span , TokenStream , TokenTree } ;
2- use std:: collections:: BTreeSet ;
2+ use std:: collections:: BTreeMap ;
33use std:: iter:: Peekable ;
44
55use crate :: ast:: { Cardinality , Pattern , Replacement , ReturnAnnotation , Rule } ;
66
77type Tokens = Peekable < proc_macro2:: token_stream:: IntoIter > ;
88type Result < T > = std:: result:: Result < T , syn:: Error > ;
9+ /// Maps each capture name to whether it uses `@@` and its identifier for diagnostics.
10+ type CaptureNames = BTreeMap < String , ( bool , Ident ) > ;
911
1012pub ( crate ) fn parse_pattern ( input : TokenStream ) -> Result < Pattern > {
1113 let mut tokens = input. into_iter ( ) . peekable ( ) ;
@@ -16,13 +18,13 @@ pub(crate) fn parse_pattern(input: TokenStream) -> Result<Pattern> {
1618 "unexpected token after query" ,
1719 ) ) ;
1820 }
19- validate_unique_capture_names ( & pattern, & mut BTreeSet :: new ( ) ) ?;
21+ validate_unique_capture_names ( & pattern, & mut CaptureNames :: new ( ) ) ?;
2022 Ok ( pattern)
2123}
2224
2325fn validate_unique_capture_names (
2426 pattern : & Pattern ,
25- capture_names : & mut BTreeSet < String > ,
27+ capture_names : & mut CaptureNames ,
2628) -> Result < ( ) > {
2729 match pattern {
2830 Pattern :: Any { .. } | Pattern :: Unnamed ( _) => { }
@@ -31,10 +33,12 @@ fn validate_unique_capture_names(
3133 validate_unique_capture_names ( pattern, capture_names) ?;
3234 }
3335 }
34- Pattern :: Capture { name, pattern, .. } => {
36+ Pattern :: Capture {
37+ name, raw, pattern, ..
38+ } => {
3539 validate_unique_capture_names ( pattern, capture_names) ?;
3640 let name_string = name. to_string ( ) ;
37- if ! capture_names. insert ( name_string. clone ( ) ) {
41+ if capture_names. contains_key ( & name_string) {
3842 return Err ( syn:: Error :: new_spanned (
3943 name,
4044 format ! (
@@ -43,6 +47,30 @@ fn validate_unique_capture_names(
4347 ) ,
4448 ) ) ;
4549 }
50+ capture_names. insert ( name_string, ( * raw, name. clone ( ) ) ) ;
51+ }
52+ Pattern :: Choice { alternatives } => {
53+ let mut unified_names = capture_names. clone ( ) ;
54+ for alternative in alternatives {
55+ let mut alternative_names = capture_names. clone ( ) ;
56+ validate_unique_capture_names ( alternative, & mut alternative_names) ?;
57+ for ( name, ( raw, identifier) ) in alternative_names {
58+ if let Some ( ( unified_raw, _) ) = unified_names. get ( & name) {
59+ if * unified_raw != raw {
60+ return Err ( syn:: Error :: new_spanned (
61+ identifier,
62+ format ! (
63+ "capture `{name}` must consistently use `@` or `@@` \
64+ across query choice alternatives"
65+ ) ,
66+ ) ) ;
67+ }
68+ } else {
69+ unified_names. insert ( name, ( raw, identifier) ) ;
70+ }
71+ }
72+ }
73+ * capture_names = unified_names;
4674 }
4775 Pattern :: Sequence ( patterns) => {
4876 for pattern in patterns {
@@ -60,22 +88,33 @@ pub(crate) fn parse_rule(input: TokenStream) -> Result<Rule> {
6088 let ( pattern_and_guard, replacement) = split_arrow ( input) ?;
6189 let ( pattern, guard) = split_guard ( pattern_and_guard) ?;
6290 let pattern = parse_pattern ( pattern) ?;
63- if let Pattern :: Capture {
64- name, raw : false , ..
65- } = & pattern
66- {
67- return Err ( syn:: Error :: new_spanned (
68- name,
69- "a capture of the rule root must use `@@`; the matched root cannot be eagerly translated" ,
70- ) ) ;
71- }
91+ validate_rule_root_captures ( & pattern) ?;
7292 Ok ( Rule {
7393 pattern,
7494 guard,
7595 replacement : parse_replacement ( replacement) ?,
7696 } )
7797}
7898
99+ fn validate_rule_root_captures ( pattern : & Pattern ) -> Result < ( ) > {
100+ match pattern {
101+ Pattern :: Capture {
102+ name, raw : false , ..
103+ } => Err ( syn:: Error :: new_spanned (
104+ name,
105+ "a capture of the rule root must use `@@`; the matched root cannot be eagerly translated" ,
106+ ) ) ,
107+ Pattern :: Capture { pattern, .. } => validate_rule_root_captures ( pattern) ,
108+ Pattern :: Choice { alternatives } => {
109+ for alternative in alternatives {
110+ validate_rule_root_captures ( alternative) ?;
111+ }
112+ Ok ( ( ) )
113+ }
114+ _ => Ok ( ( ) ) ,
115+ }
116+ }
117+
79118fn parse_pattern_with_capture ( tokens : & mut Tokens ) -> Result < Pattern > {
80119 let pattern = parse_pattern_atom ( tokens) ?;
81120 maybe_capture ( tokens, pattern, Cardinality :: SINGLE )
@@ -92,6 +131,10 @@ fn parse_pattern_atom(tokens: &mut Tokens) -> Result<Pattern> {
92131 let mut inner = group. stream ( ) . into_iter ( ) . peekable ( ) ;
93132 parse_parenthesized_pattern ( & mut inner, group. span ( ) )
94133 }
134+ Some ( TokenTree :: Group ( group) ) if group. delimiter ( ) == Delimiter :: Bracket => {
135+ let group = expect_group ( tokens, Delimiter :: Bracket ) ?;
136+ parse_choice ( group)
137+ }
95138 Some ( TokenTree :: Ident ( identifier) ) if * identifier == "_" => {
96139 tokens. next ( ) ;
97140 Ok ( Pattern :: Any {
@@ -101,11 +144,29 @@ fn parse_pattern_atom(tokens: &mut Tokens) -> Result<Pattern> {
101144 Some ( TokenTree :: Literal ( _) ) => Ok ( Pattern :: Unnamed ( expect_string_literal ( tokens) ?) ) ,
102145 Some ( token) => Err ( syn:: Error :: new_spanned (
103146 token. clone ( ) ,
104- "expected `(`, `_`, or string literal in query" ,
147+ "expected `(`, `[`, ` _`, or string literal in query" ,
105148 ) ) ,
106149 }
107150}
108151
152+ fn parse_choice ( group : proc_macro2:: Group ) -> Result < Pattern > {
153+ let span = group. span ( ) ;
154+ let mut tokens = group. stream ( ) . into_iter ( ) . peekable ( ) ;
155+ let mut alternatives = Vec :: new ( ) ;
156+ while tokens. peek ( ) . is_some ( ) {
157+ let pattern = parse_pattern_atom ( & mut tokens) ?;
158+ let pattern = maybe_repeat ( & mut tokens, pattern) ?;
159+ alternatives. push ( pattern) ;
160+ }
161+ if alternatives. is_empty ( ) {
162+ return Err ( syn:: Error :: new (
163+ span,
164+ "choice must contain at least one query" ,
165+ ) ) ;
166+ }
167+ Ok ( Pattern :: Choice { alternatives } )
168+ }
169+
109170fn parse_parenthesized_pattern ( tokens : & mut Tokens , span : Span ) -> Result < Pattern > {
110171 match tokens. peek ( ) {
111172 None => Err ( syn:: Error :: new ( span, "empty query groups are not allowed" ) ) ,
@@ -148,7 +209,12 @@ fn parse_parenthesized_pattern(tokens: &mut Tokens, span: Span) -> Result<Patter
148209 Ok ( pattern)
149210 }
150211 }
151- Some ( TokenTree :: Group ( group) ) if group. delimiter ( ) == Delimiter :: Parenthesis => {
212+ Some ( TokenTree :: Group ( group) )
213+ if matches ! (
214+ group. delimiter( ) ,
215+ Delimiter :: Parenthesis | Delimiter :: Bracket
216+ ) =>
217+ {
152218 let patterns = parse_pattern_list ( tokens) ?;
153219 finish_sequence ( tokens, patterns, span)
154220 }
@@ -222,6 +288,12 @@ fn push_field_pattern(fields: &mut Vec<(String, Pattern)>, name: String, pattern
222288fn parse_pattern_list ( tokens : & mut Tokens ) -> Result < Vec < Pattern > > {
223289 let mut patterns = Vec :: new ( ) ;
224290 while tokens. peek ( ) . is_some ( ) {
291+ if peek_is_group ( tokens, Delimiter :: Bracket ) {
292+ let pattern = parse_pattern_atom ( tokens) ?;
293+ patterns. push ( maybe_repeat ( tokens, pattern) ?) ;
294+ continue ;
295+ }
296+
225297 if peek_is_group ( tokens, Delimiter :: Parenthesis ) {
226298 let group = expect_group ( tokens, Delimiter :: Parenthesis ) ?;
227299 let mut inner = group. stream ( ) . into_iter ( ) . peekable ( ) ;
0 commit comments