kproc_parser/rust/
kfunc.rs

1//! kfunc is the module that it is used to
2//! parse the function like rust syntax.
3use crate::kparser::{KParserError, KParserTracer};
4use crate::kproc_macros::KTokenStream;
5use crate::proc_macro::TokenTree;
6use crate::rust::core::{check_and_parse_bounds, check_and_parse_return_type};
7use crate::rust::kattr::check_and_parse_cond_attribute;
8use crate::rust::ty::parse_ty;
9use crate::{build_error, check, parse_visibility, trace};
10
11use super::ast_nodes::{MethodDeclToken, TyToken};
12use super::core::{check_and_parse_fn_qualifier, check_is_fun_with_visibility};
13
14/// helper function to parse the method/function declaration
15///
16/// ```norun
17/// fn answer_to_life_the_universe_and_everything() -> i32 {
18///     return 42;
19/// }
20///
21/// fn foo<A, B>(x: A, y: B);
22///
23/// fn foo<T>(x: &[T]) where T: Debug {
24/// // details elided
25/// }
26///
27/// async fn regular_example() { }
28///
29/// async unsafe fn unsafe_example() { }
30/// ```
31pub fn parse_fn(
32    toks: &mut KTokenStream,
33    tracer: &dyn KParserTracer,
34) -> Result<MethodDeclToken, KParserError> {
35    trace!(tracer, "Start parsing fn");
36
37    let attrs = check_and_parse_cond_attribute(toks, tracer);
38    let visibility = check_is_fun_with_visibility(toks).then(|| parse_visibility!(toks).unwrap());
39    let qualifier = check_and_parse_fn_qualifier(toks);
40    let fn_tok = toks.advance();
41    check!("fn", fn_tok)?;
42
43    let ident = toks.advance();
44    trace!(
45        tracer,
46        "function name {ident} and next tok: {:?}",
47        toks.peek()
48    );
49    let generics = check_and_parse_bounds(toks, tracer)?;
50    trace!(tracer, "starting parsing fn params");
51    let raw_params = toks.unwrap_group_as_stream();
52    let mut params_stream: KTokenStream = raw_params.clone().into();
53    let params = parse_fn_params(&mut params_stream, tracer)?;
54    trace!(tracer, "fn parametes {:?}", params);
55    toks.next();
56
57    // FIXME: parse where clouse
58    let rt_ty = check_and_parse_return_type(toks, tracer)?;
59    trace!(
60        tracer,
61        "return type {:?} next should be the body function: {:?}",
62        rt_ty,
63        toks.peek()
64    );
65
66    // The trait has a function declaration without
67    // body.
68    let body = if toks.is_group() {
69        let body = toks.unwrap_group_as_stream();
70        toks.next();
71        Some(body)
72    } else {
73        let toks = toks.advance();
74        check!(";", toks)?;
75        None
76    };
77
78    let method = MethodDeclToken {
79        attrs,
80        visibility,
81        qualifier,
82        ident,
83        generics,
84        raw_params,
85        params,
86        raw_body: body,
87        return_ty: rt_ty,
88    };
89    Ok(method)
90}
91
92pub fn parse_fn_params(
93    raw_params: &mut KTokenStream,
94    tracer: &dyn KParserTracer,
95) -> Result<Vec<(TokenTree, TyToken)>, KParserError> {
96    trace!(
97        tracer,
98        "parsing fn params from the following source: {:?}",
99        raw_params
100    );
101    let mut params = Vec::new();
102    // the stream of token that we get in
103    // are the token that are inside a `(...)`
104    // when in rust is a `TokenTree::Group` token
105    while !raw_params.is_end() {
106        // FIXME here we need to check the special case of
107        // `&mut self`
108        if raw_params.match_tok("&") || raw_params.match_tok("self") | raw_params.match_tok("mut") {
109            while !raw_params.is_end() && !raw_params.match_tok(",") {
110                trace!(tracer, "`self` found `{:?}`", raw_params.advance());
111            }
112            if raw_params.is_end() {
113                trace!(tracer, "end of the params stream.");
114                break;
115            }
116            if raw_params.match_tok(",") {
117                check!(",", raw_params.advance())?;
118            }
119        }
120        let ident = raw_params.advance();
121        trace!(tracer, "parameters name `{ident}`");
122        check!(":", raw_params.advance())?;
123        let ty = parse_ty(raw_params, tracer)?.ok_or(build_error!(
124            ident.clone(),
125            "fails to parse the rust type, this is a bug, please open a issue"
126        ))?;
127        trace!(tracer, "param found `{ident}: {ty}`");
128        params.push((ident, ty));
129        // keep going, or there are more token, or we finish the stream
130        // but the while will check the last case.
131    }
132    Ok(params)
133}