Skip to main content

rustidy_ast_tokens/
lib.rs

1//! Ast tokens
2
3// Features
4#![feature(
5	never_type,
6	coverage_attribute,
7	yeet_expr,
8	anonymous_lifetime_in_impl_trait,
9	decl_macro,
10	macro_metavar_expr
11)]
12
13// Imports
14use {
15	rustidy_format::{Format, Formattable},
16	rustidy_parse::{Parse, ParserTag},
17	rustidy_print::Print,
18	rustidy_util::{AstStr, Whitespace},
19};
20
21pub macro decl_tokens(
22	$ws:ident;
23	$token:ident;
24	$new:ident;
25
26	$(
27		$TokenName:ident = $Token:literal
28		$( , ends_with_xid_continue $ends_with_xid_continue:tt )?
29		$( , skip_if_tag $skip_if_tag:expr )?
30		$( , must_not_follow $( $must_not_follow:literal ),* $(,)? )?
31		;
32	)*
33) {
34	$(
35		#[derive(PartialEq, Eq, Clone, Debug)]
36		#[derive(serde::Serialize, serde::Deserialize)]
37		#[derive(Parse, Formattable, Format, Print)]
38		#[parse(error(name = NotFound, fmt("Expected `{}`", $Token)))]
39		$(
40			#[parse(skip_if_tag = $skip_if_tag)]
41		)?
42		pub struct $TokenName {
43			pub $ws: Whitespace,
44
45			#[parse(try_update_with = Self::parse)]
46			#[format(str)]
47			pub $token: AstStr,
48		}
49
50		impl $TokenName {
51			/// Creates a new token, not associated to the input
52			pub fn $new() -> Self {
53				Self {
54					$ws: Whitespace::empty(),
55					$token: AstStr::new($Token)
56				}
57			}
58
59			fn parse(s: &mut &str) -> Result<(), <Self as Parse>::Error> {
60				*s = s.strip_prefix($Token).ok_or(<Self as Parse>::Error::NotFound)?;
61
62				// Note: This checks prevents matching `match` on `matches`
63				$( ${ignore($ends_with_xid_continue)}
64					if s.starts_with(|ch: char| unicode_ident::is_xid_continue(ch))
65					{
66						return Err(<Self as Parse>::Error::NotFound);
67					}
68				)?
69
70				$(
71					$(
72						if s.starts_with($must_not_follow) {
73							return Err(<Self as Parse>::Error::NotFound);
74						}
75					)*
76				)?
77
78				Ok(())
79			}
80		}
81
82		#[expect(non_snake_case, reason = "This is a tuple constructor")]
83		pub const fn $TokenName($ws: Whitespace, $token: AstStr) -> $TokenName {
84			$TokenName {
85				$ws, $token
86			}
87		}
88
89		impl Default for $TokenName {
90			fn default() -> Self {
91				Self::$new()
92			}
93		}
94	)*
95}
96
97decl_tokens! {
98	ws;
99	token;
100	new;
101
102	InnerLineDoc = "//!";
103	OuterLineDoc = "///";
104	InnerBlockDoc = "/*!";
105	OuterBlockDoc = "/**";
106
107	Super = "super", ends_with_xid_continue ();
108	SelfLower = "self", ends_with_xid_continue ();
109	SelfUpper = "Self", ends_with_xid_continue ();
110	Crate = "crate", ends_with_xid_continue (), skip_if_tag ParserTag::SkipTokenCrate;
111	DollarCrate = "$crate", ends_with_xid_continue ();
112
113	As = "as", ends_with_xid_continue ();
114	Async = "async", ends_with_xid_continue ();
115	Attr = "attr", ends_with_xid_continue ();
116	Auto = "auto", ends_with_xid_continue ();
117	Await = "await", ends_with_xid_continue ();
118	Break = "break", ends_with_xid_continue ();
119	Const = "const", ends_with_xid_continue ();
120	Continue = "continue", ends_with_xid_continue ();
121	Derive = "derive", ends_with_xid_continue ();
122	Do = "do", ends_with_xid_continue ();
123	Dyn = "dyn", ends_with_xid_continue ();
124	Else = "else", ends_with_xid_continue ();
125	Enum = "enum", ends_with_xid_continue ();
126	Extern = "extern", ends_with_xid_continue ();
127	False = "false", ends_with_xid_continue ();
128	Fn = "fn", ends_with_xid_continue ();
129	For = "for", ends_with_xid_continue ();
130	If = "if", ends_with_xid_continue ();
131	Impl = "impl", ends_with_xid_continue ();
132	In = "in", ends_with_xid_continue ();
133	Let = "let", ends_with_xid_continue ();
134	Loop = "loop", ends_with_xid_continue ();
135	Macro = "macro", ends_with_xid_continue ();
136	MacroRules = "macro_rules", ends_with_xid_continue ();
137	Match = "match", ends_with_xid_continue ();
138	Mod = "mod", ends_with_xid_continue ();
139	Move = "move", ends_with_xid_continue ();
140	Mut = "mut", ends_with_xid_continue ();
141	Pub = "pub", ends_with_xid_continue ();
142	Raw = "raw", ends_with_xid_continue ();
143	Ref = "ref", ends_with_xid_continue ();
144	Return = "return", ends_with_xid_continue ();
145	Safe = "safe", ends_with_xid_continue ();
146	Static = "static", ends_with_xid_continue ();
147	Struct = "struct", ends_with_xid_continue ();
148	Trait = "trait", ends_with_xid_continue ();
149	True = "true", ends_with_xid_continue ();
150	Try = "try", ends_with_xid_continue ();
151	Type = "type", ends_with_xid_continue ();
152	Union = "union", ends_with_xid_continue ();
153	Unsafe = "unsafe", ends_with_xid_continue ();
154	Use = "use", ends_with_xid_continue ();
155	Where = "where", ends_with_xid_continue ();
156	While = "while", ends_with_xid_continue ();
157	Yeet = "yeet", ends_with_xid_continue ();
158
159	// Macro frag spec
160	Block = "block", ends_with_xid_continue ();
161	Expr = "expr", ends_with_xid_continue ();
162	Expr2021 = "expr_2021", ends_with_xid_continue ();
163	Ident = "ident", ends_with_xid_continue ();
164	Item = "item", ends_with_xid_continue ();
165	Lifetime = "lifetime", ends_with_xid_continue ();
166	Literal = "literal", ends_with_xid_continue ();
167	Meta = "meta", ends_with_xid_continue ();
168	Pat = "pat", ends_with_xid_continue ();
169	PatParam = "pat_param", ends_with_xid_continue ();
170	Path = "path", ends_with_xid_continue ();
171	Stmt = "stmt", ends_with_xid_continue ();
172	Tt = "tt", ends_with_xid_continue ();
173	Ty = "ty", ends_with_xid_continue ();
174	Vis = "vis", ends_with_xid_continue ();
175
176	// Punctuation
177	Eq = '=', must_not_follow '=', '>';
178	// TODO: This means we can't parse `let _:A<>=B`, despite it being
179	//       accepted by the compiler.
180	Lt = '<', must_not_follow '=';
181	Le = "<=";
182	EqEq = "==";
183	Ne = "!=";
184	Ge = ">=";
185	Gt = '>', must_not_follow '=';
186	AndAnd = "&&";
187	OrOr = "||";
188	Not = '!', must_not_follow '=';
189	Tilde = '~';
190	Plus = '+', skip_if_tag ParserTag::SkipTokenPlus, must_not_follow '=';
191	Minus = '-', must_not_follow '=', '>';
192	Star = '*', skip_if_tag ParserTag::SkipTokenStar, must_not_follow '=';
193	Slash = '/', must_not_follow '=';
194	Percent = '%', must_not_follow '=';
195	Caret = '^', must_not_follow '=';
196	And = '&', must_not_follow '&', '=';
197	AndTy = '&';
198	Or = '|', must_not_follow '|', '=';
199	Shl = "<<", must_not_follow '=';
200	Shr = ">>", must_not_follow '=';
201	PlusEq = "+=";
202	MinusEq = "-=";
203	StarEq = "*=";
204	SlashEq = "/=";
205	PercentEq = "%=";
206	CaretEq = "^=";
207	AndEq = "&=";
208	OrEq = "|=";
209	ShlEq = "<<=";
210	ShrEq = ">>=";
211	At = '@';
212	Dot = '.', must_not_follow '.';
213	DotDot = "..", must_not_follow '.', '=';
214	DotDotDot = "...";
215	DotDotEq = "..=";
216	Comma = ',';
217	Semi = ';';
218	Colon = ':', must_not_follow ':';
219	PathSep = "::";
220	RArrow = "->";
221	LArrow = "<-";
222	FatArrow = "=>";
223	Pound = '#';
224	Dollar = '$', skip_if_tag ParserTag::SkipTokenDollar;
225	Question = '?', skip_if_tag ParserTag::SkipTokenQuestion;
226	Underscore = '_';
227	Quote = '\'';
228	DoubleQuote = '"';
229
230	ParenOpen = '(', skip_if_tag ParserTag::SkipDelimiters;
231	ParenClose = ')', skip_if_tag ParserTag::SkipDelimiters;
232	BracketOpen = '[', skip_if_tag ParserTag::SkipDelimiters;
233	BracketClose = ']', skip_if_tag ParserTag::SkipDelimiters;
234	BracesOpen = '{', skip_if_tag ParserTag::SkipDelimiters;
235	BracesClose = '}', skip_if_tag ParserTag::SkipDelimiters;
236
237}