1use anyhow::Result;
6use proc_macro2::TokenStream;
7use quote::{format_ident, quote};
8
9use super::common::{
10 generate_inner_parse_function, safe_ident, Arity, CloneState, Codegen, CodegenSettings,
11 FieldDescriptor,
12};
13use crate::{
14 common::combine_field_types,
15 grammar::{Choice, Grammar},
16};
17
18impl Codegen for Choice {
19 fn generate_code_spec(
20 &self,
21 rule_fields: &[FieldDescriptor],
22 grammar: &Grammar,
23 settings: &CodegenSettings,
24 ) -> Result<TokenStream> {
25 if self.choices.len() < 2 {
26 return self.choices[0].generate_code_spec(rule_fields, grammar, settings);
27 }
28 let choice_bodies = self
29 .choices
30 .iter()
31 .enumerate()
32 .filter(|(_, choice)| {
33 choice
34 .generate_inline_body(rule_fields, grammar, settings, CloneState::Yes)
35 .ok()
36 .flatten()
37 .is_none()
38 })
39 .map(|(num, choice)| -> Result<TokenStream> {
40 let choice_mod = format_ident!("choice_{num}");
41 let sequence_body = choice.generate_code(rule_fields, grammar, settings)?;
42 Ok(quote!(
43 mod #choice_mod{
44 use super::*;
45 #sequence_body
46 }
47 ))
48 })
49 .collect::<Result<TokenStream>>()?;
50 let parse_body =
51 self.generate_parse_body(rule_fields, grammar, settings, CloneState::No)?;
52 let parse_function = generate_inner_parse_function(parse_body, settings);
53 Ok(quote!(
54 #choice_bodies
55 #parse_function
56 ))
57 }
58
59 fn generate_inline_body(
60 &self,
61 rule_fields: &[FieldDescriptor],
62 grammar: &Grammar,
63 settings: &CodegenSettings,
64 clone_state: CloneState,
65 ) -> Result<Option<TokenStream>> {
66 if self.choices.len() < 2 {
67 self.choices[0].generate_inline_body(rule_fields, grammar, settings, clone_state)
68 } else if self.choices.iter().all(|c| {
69 c.generate_inline_body(rule_fields, grammar, settings, CloneState::No)
70 .ok()
71 .flatten()
72 .is_some()
73 }) && self.get_filtered_rule_fields(rule_fields, grammar)?.len() <= 1
74 {
75 Ok(Some(self.generate_parse_body(
76 rule_fields,
77 grammar,
78 settings,
79 clone_state,
80 )?))
81 } else {
82 Ok(None)
83 }
84 }
85
86 fn get_fields<'a>(&'a self, grammar: &'a Grammar) -> Result<Vec<FieldDescriptor<'a>>> {
87 let mut all_fields = Vec::<FieldDescriptor>::new();
88 let mut first_iteration = true;
89 for choice in &self.choices {
90 let new_fields = choice.get_fields(grammar)?;
91
92 if !first_iteration {
93 for field in &mut all_fields {
94 if field.arity == Arity::One && !new_fields.iter().any(|f| f.name == field.name)
95 {
96 field.arity = Arity::Optional;
97 }
98 }
99 }
100
101 for new_field in new_fields {
102 if let Some(original) = all_fields.iter_mut().find(|f| f.name == new_field.name) {
103 original.arity = combine_arities_for_choice(&original.arity, &new_field.arity);
104 combine_field_types(&mut original.types, &new_field.types);
105 } else if first_iteration || new_field.arity != Arity::One {
106 all_fields.push(new_field);
107 } else {
108 all_fields.push(FieldDescriptor {
109 arity: Arity::Optional,
110 ..new_field
111 });
112 }
113 }
114
115 first_iteration = false;
116 }
117 Ok(all_fields)
118 }
119}
120
121impl Choice {
122 fn generate_parse_body(
123 &self,
124 rule_fields: &[FieldDescriptor],
125 grammar: &Grammar,
126 settings: &CodegenSettings,
127 clone_state: CloneState,
128 ) -> Result<TokenStream> {
129 let fields = self.get_filtered_rule_fields(rule_fields, grammar)?;
130 let calls = self
131 .choices
132 .iter()
133 .enumerate()
134 .map(|(num, choice)| {
135 let parse_call = if let Some(inline_body) = choice
136 .generate_inline_body(rule_fields, grammar, settings, CloneState::No)
137 .unwrap()
138 {
139 inline_body
140 } else {
141 let choice_mod = format_ident!("choice_{num}");
142 quote!(#choice_mod::parse(state, global))
143 };
144 let inner_fields = choice.get_fields(grammar).unwrap();
145 let postprocess = Self::generate_result_converter(&fields, &inner_fields);
146 quote!(
147 .choice(|state| #parse_call #postprocess)
148 )
149 })
150 .collect::<TokenStream>();
151 let state = match clone_state {
152 CloneState::No => quote!(state),
153 CloneState::Yes => quote!(state.clone()),
154 };
155 Ok(quote!(
156 ChoiceHelper::new(#state)
157 #calls
158 .end()
159 ))
160 }
161
162 fn generate_result_converter(
163 fields: &[FieldDescriptor],
164 inner_fields: &[FieldDescriptor],
165 ) -> TokenStream {
166 if fields.is_empty() {
167 TokenStream::new()
168 } else if fields.len() == 1 {
169 if inner_fields.is_empty() {
170 let default = Self::generate_default_field(&fields[0]);
171 quote!(.map_inner(|_| #default))
172 } else {
173 TokenStream::new()
174 }
175 } else {
176 let field_assignments: TokenStream = fields
177 .iter()
178 .map(|field| {
179 let name = safe_ident(field.name);
180 let inner_exists = inner_fields
181 .iter()
182 .any(|inner_field| inner_field.name == field.name);
183 let value = if inner_exists {
184 if inner_fields.len() == 1 {
185 quote!(r)
186 } else {
187 quote!(r.#name)
188 }
189 } else {
190 Self::generate_default_field(field)
191 };
192 quote!(#name: #value,)
193 })
194 .collect();
195 quote!(.map_inner(|r| Parsed{ #field_assignments }))
196 }
197 }
198
199 fn generate_default_field(field: &FieldDescriptor) -> TokenStream {
200 match field.arity {
201 Arity::One => {
202 panic!("Outer field ({field:?}) cannot be One if inner does not exist",)
203 }
204 Arity::Optional => quote!(None),
205 Arity::Multiple => quote!(Vec::new()),
206 }
207 }
208}
209
210fn combine_arities_for_choice(left: &Arity, right: &Arity) -> Arity {
211 match (left, right) {
212 (Arity::One, Arity::One) => Arity::One,
213 (Arity::One, Arity::Optional) => Arity::Optional,
214 (Arity::One, Arity::Multiple) => Arity::Multiple,
215 (Arity::Optional, Arity::One) => Arity::Optional,
216 (Arity::Optional, Arity::Optional) => Arity::Optional,
217 (Arity::Optional, Arity::Multiple) => Arity::Multiple,
218 (Arity::Multiple, Arity::One) => Arity::Multiple,
219 (Arity::Multiple, Arity::Optional) => Arity::Multiple,
220 (Arity::Multiple, Arity::Multiple) => Arity::Multiple,
221 }
222}