1use crate::kparser::KParserError;
5use crate::kparser::{self, KParserTracer};
6use crate::kproc_macros::{KTokenStream, MatchTok};
7use crate::proc_macro::TokenTree;
8use crate::rust::ast_nodes::{self, TypeParam};
9use crate::{build_error, check, trace};
10
11use super::ast_nodes::{GenericParam, GenericParams, LifetimeParam, TyToken};
12use super::ty::parse_ty;
13
14pub fn check_and_parse_generics_params(
17 ast: &mut KTokenStream,
18 tracer: &dyn KParserTracer,
19) -> kparser::Result<Option<GenericParams>> {
20 trace!(tracer, "parsing generics params");
21 if ast.match_tok("<") {
23 ast.next(); let mut generics = vec![];
25 while !ast.match_tok(">") {
26 trace!(tracer, "iterate over geeneric, stuck on {:?}", ast.peek());
27 if let Some(lifetime) = check_and_parse_lifetime(ast) {
28 let param = LifetimeParam {
29 lifetime_or_label: lifetime,
30 bounds: Vec::new(),
31 };
32 generics.push(GenericParam::LifetimeParam(param));
33 } else if let Some(ty) = parse_ty(ast, tracer)? {
34 generics.push(GenericParam::TypeParam(ty));
35 }
36 }
37 ast.next(); return Ok(Some(GenericParams { params: generics }));
39 }
40 Ok(None)
41}
42
43pub fn check_and_parse_bounds(
44 stream: &mut KTokenStream,
45 tracer: &dyn KParserTracer,
46) -> kparser::Result<Option<GenericParams>> {
47 let is_starting_tok = stream.match_tok("<");
48 if !is_starting_tok && !stream.is_group() {
49 trace!(
50 tracer,
51 "while checking the parameter we do not find a token group"
52 );
53 return Ok(None);
54 }
55 if !is_starting_tok && !stream.peek().clone().to_token_stream().match_tok("<") {
56 trace!(tracer, "not a `<...>` token group`");
57 return Ok(None);
58 }
59
60 let inner_stream = stream;
61 if !is_starting_tok {
62 trace!(tracer, "in a `<...>` token group, uwrapping it ...");
63 *inner_stream = inner_stream.advance().to_token_stream();
64 }
65
66 if inner_stream.match_tok("<") {
67 trace!(tracer, "check and parsing the type bounds");
68 inner_stream.next(); let mut generics = vec![];
71 while !inner_stream.is_end() && !inner_stream.match_tok(">") {
72 trace!(
73 tracer,
74 "iterate over tokens, current token is: `{:?}`",
75 inner_stream.peek()
76 );
77 let mut generic: Option<GenericParam> = None;
78 while !inner_stream.match_tok(",") && !inner_stream.match_tok(">") {
79 trace!(tracer, "checking bound");
80 match inner_stream.peek().to_string().as_str() {
81 "+" | ":" => {
82 let tok = inner_stream.advance();
83 assert!(
84 ["+", ":"].contains(&tok.to_string().as_str()),
85 "unexpected token {:?}",
86 tok.to_string()
87 );
88 trace!(tracer, "new bound for the current trait");
89 let bound = if let Some(lifetime) = check_and_parse_lifetime(inner_stream) {
90 ast_nodes::Bound::Lifetime(LifetimeParam {
91 lifetime_or_label: lifetime,
92 bounds: Vec::new(),
93 })
94 } else {
95 let trait_bound = inner_stream.advance();
96 ast_nodes::Bound::Trait(TypeParam {
97 identifier: trait_bound,
98 bounds: Vec::new(),
99 })
100 };
101 assert!(
102 generic.is_some(),
103 "concatenation bound `+` on generic used in the wrong way"
104 );
105 trace!(tracer, "bound found `{:?}`", bound);
106 let Some(generic) = generic.as_mut() else {
107 return Err(build_error!(inner_stream.peek().clone(), "concatenation bound `+` on generic used in the wrong way"));
108 };
109 generic.add_bound(bound);
110 }
111 _ => {
112 assert!(
113 generic.is_none(),
114 "declaration bound with `:` used in the wrong way"
115 );
116 trace!(tracer, "parising token {:?}", inner_stream.peek());
117 if let Some(lifetime) = check_and_parse_lifetime(inner_stream) {
118 trace!(tracer, "life bound found {:?}", lifetime);
119 generic = Some(GenericParam::LifetimeParam(LifetimeParam {
120 lifetime_or_label: lifetime,
121 bounds: vec![],
122 }));
123 continue;
124 }
125 let identifier = inner_stream.advance();
126 trace!(tracer, "Trait `{identifier}`");
127 generic = Some(GenericParam::Bounds(ast_nodes::Bound::Trait(TypeParam {
128 identifier,
129 bounds: vec![],
130 })))
131 }
132 }
133 trace!(tracer, "next token `{:?}`", inner_stream.peek());
134 }
135 trace!(
136 tracer,
137 "conclude to parse the generic bound `{:?}`",
138 generic
139 );
140 generics.push(generic.unwrap());
141 if inner_stream.match_tok(",") {
142 check!(",", inner_stream.advance())?;
143 }
144 }
145 trace!(
146 tracer,
147 "finish to parse the generics bounds `{:?}`",
148 generics
149 );
150 if !inner_stream.is_end() {
151 check!(">", inner_stream.advance())?; }
153 return Ok(Some(GenericParams { params: generics }));
154 }
155 Ok(None)
156}
157
158pub fn check_and_parse_ref(ast: &mut KTokenStream) -> Option<TokenTree> {
161 let token = ast.peek();
162 match token.to_string().as_str() {
163 "&" => Some(ast.advance()),
164 _ => None,
165 }
166}
167
168pub fn check_and_parse_lifetime(ast: &mut KTokenStream) -> Option<TokenTree> {
171 let token = ast.peek().to_string();
172 match token.as_str() {
173 "'" => {
174 ast.next();
175 Some(ast.advance())
176 }
177 _ => None,
178 }
179}
180
181pub fn check_and_parse_mut(ast: &mut KTokenStream) -> Option<TokenTree> {
184 let token = ast.peek().to_string();
185 match token.as_str() {
186 "mut" => Some(ast.advance()),
187 _ => None,
188 }
189}
190
191pub fn check_and_parse_dyn(ast: &mut KTokenStream) -> Option<TokenTree> {
194 let token = ast.peek().to_string();
195 match token.as_str() {
196 "dyn" => Some(ast.advance()),
197 _ => None,
198 }
199}
200
201#[macro_export]
202macro_rules! parse_visibility {
203 ($ast:expr) => {{
204 $crate::rust::core::check_and_parse_visibility($ast)
205 }};
206}
207
208pub fn check_and_parse_visibility(toks: &mut KTokenStream) -> Option<TokenTree> {
211 if check_identifier(toks, "pub", 0) {
212 return Some(toks.advance());
213 }
214 None
215}
216
217pub fn check_and_parse_fn_qualifier(toks: &mut KTokenStream) -> Option<TokenTree> {
218 if check_identifiers(toks, &["async", "const", "unsafe"], 0) {
219 return Some(toks.advance());
220 }
221 None
222}
223
224pub fn check_and_parse_fn_tok(toks: &mut KTokenStream) -> Option<TokenTree> {
225 if check_identifier(toks, "fn", 0) {
226 return Some(toks.advance());
227 }
228 None
229}
230
231pub fn check_is_fun_with_visibility(toks: &mut KTokenStream) -> bool {
232 if check_identifier(toks, "pub", 0) {
233 if check_identifiers(toks, &["async", "const", "unsafe"], 1) {
234 return check_identifier(toks, "fn", 2);
235 } else if check_identifier(toks, "fn", 1) {
236 return true;
237 }
238 }
239 false
240}
241
242pub fn check_identifier(toks: &KTokenStream, ident: &str, step: usize) -> bool {
243 let tok = toks.lookup(step);
244 if let TokenTree::Ident(val) = tok {
245 if val.to_string().contains(ident) {
246 return true;
247 }
248 }
249 false
250}
251
252pub fn check_tok(toks: &KTokenStream, ident: &str, step: usize) -> bool {
253 let tok = toks.lookup(step);
254 tok.to_string().contains(ident)
255}
256
257pub fn check_identifiers(toks: &KTokenStream, ident: &[&str], step: usize) -> bool {
258 let tok = toks.lookup(step);
259 if let TokenTree::Ident(val) = tok {
260 if ident.contains(&val.to_string().as_str()) {
261 return true;
262 }
263 }
264 false
265}
266
267pub fn check_raw_toks(toks: &KTokenStream, ident: &[&str], step: usize) -> bool {
268 let tok = toks.lookup(step);
269 ident.contains(&tok.to_string().as_str())
270}
271
272pub fn check_and_parse_return_type(
273 toks: &mut KTokenStream,
274 tracer: &dyn KParserTracer,
275) -> kparser::Result<Option<TyToken>> {
276 if toks.is_end() {
277 return Ok(None);
278 }
279 if check_tok(toks, "-", 0) {
280 toks.next();
281 trace!(tracer, "ok parsed the `-`, now the next is {}", toks.peek());
282 if check_tok(toks, ">", 0) {
283 toks.next();
284 trace!(tracer, "found the `>` no the next is {:?}", toks.peek());
285 let ty = parse_ty(toks, tracer)?;
287 return Ok(ty);
288 }
289 }
290 Ok(None)
291}