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
//! Contains all the core function that are common across
//! different modules.

use crate::kparser::KParserTracer;
use crate::kproc_macros::KTokenStream;
use crate::proc_macro::TokenTree;
use crate::trace;

use super::ast_nodes::{GenericParam, GenericParams, LifetimeParam, TyToken};
use super::ty::parse_ty;

/// parsing the declaration of the lifetimes and generics for a
/// declaration of a impl block or struct.
pub fn check_and_parse_generics_params(
    ast: &mut KTokenStream,
    trace: &dyn KParserTracer,
) -> Option<GenericParams> {
    trace.log("parsing generics params");
    // compliant to this https://doc.rust-lang.org/stable/reference/items/generics.html
    if ast.match_tok("<") {
        ast.next(); // consume `<``
        let mut generics = vec![];
        while !ast.match_tok(">") {
            trace.log(&format!("iterate over geeneric, stuck on {:?}", ast.peek()));
            if let Some(lifetime) = check_and_parse_lifetime(ast) {
                if ast.match_tok("+") {
                    trace.log("bouds parsing not supported");
                } else {
                    let param = LifetimeParam {
                        lifetime_or_label: lifetime,
                        bounds: None,
                    };
                    generics.push(GenericParam::LifetimeParam(param));
                }
            } else {
                let ty = parse_ty(ast, trace);
                generics.push(GenericParam::TypeParam(ty));
            }
        }
        ast.next(); // consume the `>` toks
        return Some(GenericParams { params: generics });
    }
    None
}

/// helper function that check and parse the reference token `&`, if
/// is not present return `None`.
pub fn check_and_parse_ref<'c>(ast: &'c mut KTokenStream) -> Option<TokenTree> {
    let token = ast.peek();
    match token.to_string().as_str() {
        "&" => Some(ast.advance().to_owned()),
        _ => None,
    }
}

/// helper function that check and parse the lifetime symbol `'`, if
/// is not present return `None`.
pub fn check_and_parse_lifetime<'c>(ast: &'c mut KTokenStream) -> Option<TokenTree> {
    let token = ast.peek().to_string();
    match token.as_str() {
        "'" => {
            ast.next();
            Some(ast.advance().to_owned())
        }
        _ => None,
    }
}

/// helper function that check and parse the `mut` token, if is not
/// present return `None`.
pub fn check_and_parse_mut<'c>(ast: &'c mut KTokenStream) -> Option<TokenTree> {
    let token = ast.peek().to_string();
    match token.as_str() {
        "mut" => Some(ast.advance().to_owned()),
        _ => None,
    }
}

/// helper function that check and parser the `dyn` token, if is not
/// present return `None`.
pub fn check_and_parse_dyn<'c>(ast: &'c mut KTokenStream) -> Option<TokenTree> {
    let token = ast.peek().to_string();
    match token.as_str() {
        "dyn" => Some(ast.advance().to_owned()),
        _ => None,
    }
}

#[macro_export]
macro_rules! parse_visibility {
    ($ast:expr) => {{
        $crate::rust::core::check_and_parse_visibility($ast)
    }};
}

/// parse visibility identifier like `pub(crate)`` and return an option
/// value in case it is not defined.
pub fn check_and_parse_visibility<'c>(toks: &'c mut KTokenStream) -> Option<TokenTree> {
    if check_identifier(toks, "pub", 0) {
        return Some(toks.advance());
    }
    None
}

pub fn check_and_parse_fn_qualifier(toks: &mut KTokenStream) -> Option<TokenTree> {
    if check_identifiers(toks, &["async", "const", "unsafe"], 0) {
        return Some(toks.advance());
    }
    None
}

pub fn check_and_parse_fn_tok(toks: &mut KTokenStream) -> Option<TokenTree> {
    if check_identifier(toks, "fn", 0) {
        return Some(toks.advance());
    }
    None
}

pub fn check_is_fun_with_visibility(toks: &mut KTokenStream) -> bool {
    if check_identifier(toks, "pub", 0) {
        if check_identifiers(toks, &["async", "const", "unsafe"], 1) {
            return check_identifier(&toks, "fn", 2);
        } else if check_identifier(toks, "fn", 1) {
            return true;
        }
    }
    return false;
}

pub fn check_identifier(toks: &KTokenStream, ident: &str, step: usize) -> bool {
    let tok = toks.lookup(step);
    if let TokenTree::Ident(val) = tok {
        if val.to_string().contains(ident) {
            return true;
        }
    }
    false
}

pub fn check_tok(toks: &KTokenStream, ident: &str, step: usize) -> bool {
    let tok = toks.lookup(step);
    tok.to_string().contains(ident)
}

pub fn check_identifiers(toks: &KTokenStream, ident: &[&str], step: usize) -> bool {
    let tok = toks.lookup(step);
    if let TokenTree::Ident(val) = tok {
        if ident.contains(&val.to_string().as_str()) {
            return true;
        }
    }
    false
}

pub fn check_raw_toks(toks: &KTokenStream, ident: &[&str], step: usize) -> bool {
    let tok = toks.lookup(step);
    ident.contains(&tok.to_string().as_str())
}

pub fn check_and_parse_return_type(
    toks: &mut KTokenStream,
    tracer: &dyn KParserTracer,
) -> Option<TyToken> {
    if check_tok(toks, "-", 0) {
        toks.next();
        trace!(tracer, "ok parsed the `-`, now the next is {}", toks.peek());
        if check_tok(toks, ">", 0) {
            toks.next();
            trace!(tracer, "found the `>` no the next is {:?}", toks.peek());
            // FIXME: add a method to consube by steps
            let ty = parse_ty(toks, tracer);
            return Some(ty);
        }
    }
    return None;
}