1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
#[cfg(feature = "module_disambiguation")]
use crate::module_disambiguation::try_substitute_mod;
use crate::{
	disambiguate_module, error::Error, new_group, token_iter::SubGroupIter, Result,
	SubstitutionGroup, Token, TokenIter,
};
use proc_macro::{Delimiter, Ident, Span, TokenStream, TokenTree};

/// The types of sub-substitutions composing a single substitution.
#[derive(Debug)]
pub enum SubType
{
	/// A simple substitution with the TokenStream
	Token(TokenStream),
	/// Substitute with the TokenStream in the argument of given index.
	Argument(usize),
	/// Substitution with a group with the specified delimiter and the contents
	/// being what is produced by the nested substitution.
	Group(Delimiter, Substitution),
}

/// A substitution for an identifier.
///
/// A substitution takes a specific number of arguments as TokenStreams and
/// produces a TokenStream that is to be substituted for the identifier.
///
/// To create a substitution for an identifier, `new` is given the list of
/// arguments and the tokens to be used as a substitution. The `apply` method
/// can then be given a set of substitution arguments as TokenStreams (the
/// number of arguments must match the number given to `new`,) which will yield
/// the final TokenStream that should be substituted for the identifier ( +
/// arguments).
#[derive(Debug)]
pub struct Substitution
{
	/// The number of arguments to the substitution
	arg_count: usize,
	/// The substitution. The list is ordered, with the result of an application
	/// being the concatenation of each sub-substitution.
	sub: Vec<SubType>,
}

impl Substitution
{
	/// Create a new substitution that takes no arguments.
	pub fn new_simple(substitution: TokenStream) -> Self
	{
		Self {
			arg_count: 0,
			sub: vec![SubType::Token(substitution)],
		}
	}

	/// Create a new substitution.
	///
	/// The given argument list is assumed to be ordered and its length is the
	/// number of arguments to the substitution.
	/// The tokens produced by the iterator will be the basis for applying a
	/// substitution, where each instance of an argument identifier being
	/// replaced by the arguments passed to the a substitution identifier.
	pub(crate) fn new<'a, T: SubGroupIter<'a>>(
		arguments: &Vec<String>,
		mut stream: TokenIter<'a, T>,
	) -> Result<Self>
	{
		let mut substitutions = Vec::new();
		// Group tokens that aren't substitution identifiers or groups
		let mut saved_tokens = None;

		let find_argument =
			|ident: &Ident| arguments.iter().position(|arg| *arg == ident.to_string());

		while let Some(token) = stream.next_fallible()?
		{
			match token
			{
				Token::Simple(TokenTree::Ident(ident)) if find_argument(&ident).is_some() =>
				{
					if let Some(sub_stream) = saved_tokens.take()
					{
						substitutions.push(SubType::Token(sub_stream));
					}
					substitutions.push(SubType::Argument(find_argument(&ident).unwrap()));
				},
				Token::Group(del, iter, _) =>
				{
					if let Some(sub_stream) = saved_tokens.take()
					{
						substitutions.push(SubType::Token(sub_stream));
					}
					substitutions.push(SubType::Group(del, Substitution::new(arguments, iter)?));
				},
				token =>
				{
					saved_tokens
						.get_or_insert_with(|| TokenStream::new())
						.extend(Some(TokenTree::from(token)).into_iter())
				},
			}
		}
		if let Some(sub_stream) = saved_tokens
		{
			substitutions.push(SubType::Token(sub_stream));
		}
		let substitution = Self {
			arg_count: arguments.len(),
			sub: substitutions,
		};
		Ok(substitution)
	}

	/// Apply the substitution, assuming it takes no arguments.
	pub fn apply_simple(&self, err_span: Span) -> Result<TokenStream>
	{
		self.apply(&Vec::new(), err_span)
	}

	/// Apply the substitution to the given arguments.
	///
	/// The number of arguments must match the exact number accepted by the
	/// substitution.
	pub fn apply(&self, arguments: &Vec<TokenStream>, err_span: Span) -> Result<TokenStream>
	{
		if arguments.len() == self.arg_count
		{
			let mut result = TokenStream::new();
			for sub in self.sub.iter()
			{
				result.extend(
					match sub
					{
						SubType::Token(stream) => stream.clone(),
						SubType::Argument(idx) => arguments[*idx].clone(),
						SubType::Group(delimiter, subst) =>
						{
							TokenStream::from(TokenTree::Group(new_group(
								delimiter.clone(),
								subst.apply(arguments, err_span)?,
								Span::call_site(),
							)))
						},
					}
					.into_iter(),
				)
			}
			Ok(result)
		}
		else
		{
			Err(Error::new(format!(
				"Expected {} substitution arguments but got {}",
				self.arg_count,
				arguments.len()
			))
			.span(err_span))
		}
	}

	#[cfg(feature = "module_disambiguation")]
	/// If this substitution simply produces an identifier and nothing else,
	/// then that identifier is returned, otherwise None
	pub fn substitutes_identifier(&self) -> Option<Ident>
	{
		if self.sub.len() == 1
		{
			if let SubType::Token(token) = &self.sub[0]
			{
				let mut iter = token.clone().into_iter();
				if let TokenTree::Ident(ident) = iter.next()?
				{
					// Ensure there are no more tokens, since we only allow 1 identifier.
					if iter.next().is_none()
					{
						return Some(ident);
					}
				}
			}
		}
		None
	}

	pub fn argument_count(&self) -> usize
	{
		self.arg_count
	}
}

/// Duplicates the given token stream, substituting any identifiers found.
pub(crate) fn duplicate_and_substitute<'a>(
	item: TokenStream,
	global_subs: &'a SubstitutionGroup,
	mut sub_groups: impl Iterator<Item = &'a SubstitutionGroup> + Clone,
) -> Result<TokenStream>
{
	let mut result = TokenStream::new();
	#[allow(unused_variables)]
	let mod_and_postfix_sub = disambiguate_module(&item, sub_groups.clone())?;

	let sub_groups_clone = sub_groups.clone();
	let mut duplicate_and_substitute_one = |substitutions: &SubstitutionGroup| -> Result<()> {
		let mut item_iter = TokenIter::new(item.clone(), global_subs, sub_groups_clone.clone());

		#[cfg(feature = "module_disambiguation")]
		let mut substituted_mod = false;
		loop
		{
			#[cfg(feature = "module_disambiguation")]
			{
				if !substituted_mod
				{
					let stream =
						try_substitute_mod(&mod_and_postfix_sub, substitutions, &mut item_iter);
					substituted_mod = !stream.is_empty();
					result.extend(stream);
				}
			}

			if let Some(stream) = substitute_next_token(&mut item_iter, global_subs, substitutions)?
			{
				result.extend(stream);
			}
			else
			{
				break;
			}
		}
		Ok(())
	};

	// We always want at least 1 duplicate.
	// If no groups are given, we just want to run the global substitutions
	let empty_sub = SubstitutionGroup::new();
	duplicate_and_substitute_one(sub_groups.next().unwrap_or(&empty_sub))?;

	for substitutions in sub_groups
	{
		duplicate_and_substitute_one(&substitutions)?;
	}

	Ok(result)
}

/// Recursively checks the given token for any use of the given substitution
/// identifiers and substitutes them, returning the resulting token stream.
fn substitute_next_token<'a, T: SubGroupIter<'a>>(
	tree: &mut TokenIter<'a, T>,
	global_subs: &SubstitutionGroup,
	substitutions: &SubstitutionGroup,
) -> Result<Option<TokenStream>>
{
	let mut result = None;
	match tree.next_fallible()?
	{
		Some(Token::Simple(TokenTree::Ident(ident))) =>
		{
			match (
				substitutions.substitution_of(&ident.to_string()),
				global_subs.substitution_of(&ident.to_string()),
			)
			{
				(Some(subst), None) | (None, Some(subst)) =>
				{
					let stream = if subst.arg_count > 0
					{
						let (mut group_iter, span) =
							tree.next_group(Some(Delimiter::Parenthesis))?;
						let mut args = Vec::new();
						loop
						{
							match group_iter.next_group(Some(Delimiter::Bracket))
							{
								Ok((group, _)) =>
								{
									args.push(duplicate_and_substitute(
										group.to_token_stream(),
										global_subs,
										Some(substitutions).into_iter(),
									)?);
									if group_iter.has_next()?
									{
										group_iter.expect_comma()?;
									}
								},
								Err(err) =>
								{
									if group_iter.has_next()?
									{
										return Err(
											err.hint(crate::pretty_errors::BRACKET_SUB_PARAM)
										);
									}
									else
									{
										break;
									}
								},
							}
						}
						subst.apply(&args, span)?
					}
					else
					{
						subst.apply_simple(ident.span())?
					};
					result
						.get_or_insert_with(|| TokenStream::new())
						.extend(stream.into_iter());
				},
				(None, None) =>
				{
					result
						.get_or_insert_with(|| TokenStream::new())
						.extend(TokenStream::from(TokenTree::Ident(ident)).into_iter());
				},
				_ =>
				{
					return Err(
						Error::new("Multiple substitutions for identifier").span(ident.span())
					)
				},
			}
		},
		Some(Token::Group(del, mut group_iter, span)) =>
		{
			let mut substituted = TokenStream::new();
			while let Some(stream) =
				substitute_next_token(&mut group_iter, global_subs, substitutions)?
			{
				substituted.extend(stream)
			}
			result.get_or_insert_with(|| TokenStream::new()).extend(
				TokenStream::from(TokenTree::Group(new_group(del, substituted, span))).into_iter(),
			);
		},
		Some(token) =>
		{
			result
				.get_or_insert_with(|| TokenStream::new())
				.extend(Some(TokenTree::from(token)).into_iter())
		},
		_ => (),
	}
	Ok(result)
}