kproc_parser/rust/
ast_nodes.rs

1//! Crate that implement an abstraction of all
2//! the AST nodes like
3//! `struct`, `fields`, `FielsTypes`
4//!
5//! Each implementation contains information
6//! regarding the position in `KDiagnostic`.
7use crate::proc_macro::TokenStream;
8
9use crate::{
10    kparser::{DummyTracer, KParserError},
11    kproc_macros::KTokenStream,
12    proc_macro::TokenTree,
13};
14use std::collections::HashMap;
15use std::fmt::Display;
16
17use super::{
18    fmt::{fmt_generics, fmt_ty},
19    kimpl::parse_impl,
20    kstruct::parse_struct,
21    ktrait::parse_trait,
22};
23
24pub trait TopLevelAST {
25    fn span(&self) -> TokenTree;
26
27    fn is_trait(&self) -> bool {
28        false
29    }
30
31    fn is_struct(&self) -> bool {
32        false
33    }
34
35    fn is_impl(&self) -> bool {
36        false
37    }
38
39    fn is_fn(&self) -> bool {
40        false
41    }
42}
43
44pub enum TopLevelNode {
45    Struct(StructToken),
46    Trait(TraitToken),
47    Impl(ImplToken),
48    Fn(MethodDeclToken),
49}
50
51impl Display for TopLevelNode {
52    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53        match self {
54            Self::Impl(node) => write!(f, "{node}"),
55            Self::Struct(node) => write!(f, "{node}"),
56            Self::Trait(node) => write!(f, "{node}"),
57            Self::Fn(node) => write!(f, "{node}"),
58        }
59    }
60}
61
62impl From<StructToken> for TopLevelNode {
63    fn from(value: StructToken) -> Self {
64        TopLevelNode::Struct(value)
65    }
66}
67
68impl From<ImplToken> for TopLevelNode {
69    fn from(value: ImplToken) -> Self {
70        TopLevelNode::Impl(value)
71    }
72}
73
74impl From<TraitToken> for TopLevelNode {
75    fn from(value: TraitToken) -> Self {
76        TopLevelNode::Trait(value)
77    }
78}
79
80impl From<MethodDeclToken> for TopLevelNode {
81    fn from(value: MethodDeclToken) -> Self {
82        TopLevelNode::Fn(value)
83    }
84}
85
86/// Strung token that allow to
87/// decode a `struct` block.
88///
89/// Defined as described in
90/// https://doc.rust-lang.org/stable/reference/items/structs.html
91///
92// FIXME: parse and add where clause
93// FIXME: parse the TupleStruct
94#[derive(Debug)]
95pub struct StructToken {
96    pub attrs: HashMap<String, AttrToken>,
97    pub visibility: Option<TokenTree>,
98    pub name: TokenTree,
99    pub fields: Vec<FieldToken>,
100    pub generics: Option<GenericParams>,
101}
102
103impl TopLevelAST for StructToken {
104    fn span(&self) -> TokenTree {
105        self.name.clone()
106    }
107
108    fn is_struct(&self) -> bool {
109        true
110    }
111}
112
113impl Default for StructToken {
114    fn default() -> Self {
115        panic!()
116    }
117}
118
119impl TryFrom<&TokenStream> for StructToken {
120    type Error = KParserError;
121
122    fn try_from(value: &TokenStream) -> Result<Self, Self::Error> {
123        let mut stream = KTokenStream::new(value);
124        parse_struct(&mut stream, &DummyTracer {})
125    }
126}
127
128impl Display for StructToken {
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        write!(f, "")
131    }
132}
133
134/// Generic Parameters token allow to
135/// decode stream of token defined as described
136/// in https://doc.rust-lang.org/stable/reference/items/generics.html
137#[derive(Debug, Clone)]
138pub struct GenericParams {
139    pub params: Vec<GenericParam>,
140}
141
142#[derive(Debug, Clone)]
143pub enum GenericParam {
144    LifetimeParam(LifetimeParam),
145    TypeParam(TyToken),
146    Bounds(Bound), // FIXME: support the const params
147}
148
149impl GenericParam {
150    pub fn add_bound(&mut self, bound: Bound) {
151        match self {
152            Self::TypeParam(param) => param.bounds.push(bound),
153            Self::LifetimeParam(param) => param.bounds.push(bound),
154            Self::Bounds(params) => params.add_bound(bound),
155        }
156    }
157}
158
159impl Display for GenericParam {
160    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161        match self {
162            Self::LifetimeParam(param) => write!(f, "{param}"),
163            Self::TypeParam(param) => write!(f, "{param}"),
164            Self::Bounds(bounds) => write!(f, "{bounds}"),
165        }
166    }
167}
168
169#[derive(Clone, Debug)]
170pub enum Bound {
171    Lifetime(LifetimeParam),
172    Trait(TypeParam),
173}
174
175impl Bound {
176    pub fn add_bound(&mut self, bound: Bound) {
177        match self {
178            Self::Trait(param) => param.bounds.push(bound),
179            Self::Lifetime(param) => param.bounds.push(bound),
180        }
181    }
182}
183
184impl std::fmt::Display for Bound {
185    fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186        unimplemented!()
187    }
188}
189
190/// 'a: 'static
191#[derive(Debug, Clone)]
192pub struct LifetimeParam {
193    pub lifetime_or_label: TokenTree,
194    pub bounds: Vec<Bound>,
195}
196
197impl std::fmt::Display for LifetimeParam {
198    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199        let mut code = format!("'{}", self.lifetime_or_label);
200        if !self.bounds.is_empty() {
201            code += &format!(
202                " {}",
203                self.bounds
204                    .iter()
205                    .map(|bound| format!("{bound} +"))
206                    .collect::<String>()
207            );
208            code = code.strip_suffix('+').unwrap_or(&code).to_owned();
209        }
210        write!(f, "{code}")
211    }
212}
213
214#[derive(Debug, Clone)]
215pub struct TypeParam {
216    pub identifier: TokenTree,
217    pub bounds: Vec<Bound>,
218}
219
220impl Display for GenericParams {
221    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222        let gen = fmt_generics(self);
223        write!(f, "{gen}")
224    }
225}
226
227/// struct filed token allow to decode the
228/// struct fields defined as described in
229/// https://doc.rust-lang.org/stable/reference/items/structs.html
230#[derive(Debug)]
231pub struct FieldToken {
232    pub attrs: HashMap<String, AttrToken>,
233    pub visibility: Option<TokenTree>,
234    pub identifier: TokenTree,
235    pub ty: TyToken,
236}
237
238impl Display for FieldToken {
239    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
240        let mut vis = String::new();
241        if let Some(viss) = &self.visibility {
242            vis = viss.to_string()
243        }
244        write!(f, "{} {}: {}", vis, self.identifier, self.ty)
245    }
246}
247
248/// TyKidn definition for the Rust language.
249///
250/// a formal defintion of it is available at
251/// https://doc.rust-lang.org/stable/reference/types.html#type-expressions
252#[derive(Debug, Clone)]
253pub enum TyKind {
254    ImplTrait,
255    Parenthesized,
256    TraitObject,
257    TypePath,
258    TupleType,
259    NeverType,
260    RawPointerType,
261    ReferenceType,
262    ArrayType,
263    SliceType,
264    InferredType,
265    QualifiedPathInType,
266    BareFunctionType,
267    MacroInvocation,
268}
269
270/// parsing the type of the filed, where this will be
271/// defined with the following grammar
272/// https://doc.rust-lang.org/stable/reference/types.html#type-expressions
273///
274// FIXME(vincenzopalazzo): I am not happy with this solution, so
275// happy to receive some feedback regarding it. In this case
276// would be good an enum or a filed regarding the kind of the type
277#[derive(Debug, Clone)]
278pub struct TyToken {
279    pub kind: TyKind,
280    pub ref_tok: Option<TokenTree>,
281    pub mut_tok: Option<TokenTree>,
282    pub identifier: TokenTree,
283    pub dyn_tok: Option<TokenTree>,
284    pub lifetime: Option<LifetimeParam>,
285    pub generics: Option<Vec<TyToken>>,
286    pub bounds: Vec<Bound>,
287}
288
289impl Display for TyToken {
290    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
291        let code = fmt_ty(self);
292        write!(f, "{code}")
293    }
294}
295
296/// An attribute is a general, free-form metadatum that is
297/// interpreted according to name, convention, language,
298/// and compiler version. Attributes are modeled
299/// on Attributes in ECMA-335, with the syntax coming
300/// from ECMA-334 (C#).
301///
302/// A list of possible attribute syntax is:
303///
304/// ```rust
305/// #![allow(unused)]
306/// fn main() {
307///     // General metadata applied to the enclosing module or crate.
308///     #![crate_type = "lib"]
309///     // A function marked as a unit test
310///     #[test]
311///     fn test_foo() {
312///         /* ... */
313///     }
314///
315///     // A conditionally-compiled module
316///     #[cfg(target_os = "linux")]
317///     mod bar {
318///     /* ... */
319///     }
320///
321///     // A lint attribute used to suppress a warning/error
322///     #[allow(non_camel_case_types)]
323///     type int8_t = i8;
324///
325///     // Inner attribute applies to the entire function.
326///     fn some_unused_variables() {
327///         #![allow(unused_variables)]
328///             let x = ();
329///             let y = ();
330///             let z = ();
331///      }
332/// }
333/// ```
334#[derive(Debug, Clone)]
335pub struct CondAttributeToken {
336    /// name of the attribute
337    pub name: TokenTree,
338    /// value of the attribut contained inside the `()`
339    pub value: AttributeToken,
340}
341
342/// Inner attribute is the simplest attribute that you can find
343/// inside the sintax, in fact this kind of struct contains
344/// information regarding the attribute itself.
345///
346/// ```rust
347/// // #[pin_project]
348/// // #[key = value]
349/// // #![pin_project]
350/// // #![key = value]
351/// ```
352#[derive(Debug, Clone)]
353pub struct AttributeToken {
354    /// name of the attribute
355    pub name: TokenTree,
356    /// an optional value of the attribute
357    pub value: Option<TokenTree>,
358}
359
360#[derive(Debug, Clone)]
361pub enum AttrToken {
362    Attr(AttributeToken),
363    CondAttr(CondAttributeToken),
364}
365
366impl AttrToken {
367    // return the name of the current attribute,
368    // to inspect the value please considerer to
369    // call the `self.attribute` method.
370    pub fn name(&self) -> String {
371        match self {
372            Self::Attr(tok) => tok.name.to_string(),
373            Self::CondAttr(tok) => tok.name.to_string(),
374        }
375    }
376
377    /// return the attribute value in the case the item is
378    /// an attribute, or return the conditional attributes
379    /// in case the enum is `CondAttributeToken`.
380    pub fn attribute(&self) -> AttributeToken {
381        match self {
382            Self::Attr(attr) => attr.to_owned(),
383            Self::CondAttr(attr) => attr.value.clone(),
384        }
385    }
386
387    /// check is current element is an conditional item
388    pub fn is_conditional(&self) -> bool {
389        match self {
390            Self::Attr(_) => false,
391            Self::CondAttr(_) => true,
392        }
393    }
394}
395
396/// AST Token to store information about an
397/// `impl` block.
398///
399/// Reference: <https://doc.rust-lang.org/stable/reference/items/implementations.html>
400#[derive(Debug)]
401pub struct ImplToken {
402    pub attributes: HashMap<String, AttrToken>,
403    pub generics: Option<GenericParams>,
404    /// The name of the impl Block
405    pub name: TokenTree,
406    /// for the type where the impl block is implemented for
407    // FIXME: we should abstract this token in a better way?
408    // or just rename it?
409    pub for_ty: Option<TyToken>,
410    /// Content of the impl block
411    ///
412    /// It is stored the raw block because
413    /// the kparser library expose all the primitive
414    /// to parse this kind of token tree, and this
415    /// will make a slim version of the library.
416    pub raw_block: TokenStream,
417    pub functions: Vec<MethodDeclToken>,
418}
419
420impl TopLevelAST for ImplToken {
421    fn span(&self) -> TokenTree {
422        self.name.clone()
423    }
424
425    fn is_impl(&self) -> bool {
426        true
427    }
428}
429
430impl TryFrom<&TokenStream> for ImplToken {
431    type Error = KParserError;
432
433    fn try_from(value: &TokenStream) -> Result<Self, Self::Error> {
434        let mut stream = KTokenStream::new(value);
435        parse_impl(&mut stream, &DummyTracer {})
436    }
437}
438
439impl Default for ImplToken {
440    fn default() -> Self {
441        panic!()
442    }
443}
444
445impl Display for ImplToken {
446    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
447        // FIXME: print the attributes
448        write!(f, "impl {} {{ {} }}", self.name, self.raw_block)
449    }
450}
451
452/// AST token to store information about a
453/// `Trait`.
454///
455/// Reference <https://doc.rust-lang.org/stable/reference/items/traits.html>
456#[derive(Debug)]
457pub struct TraitToken {
458    pub attrs: HashMap<String, AttrToken>,
459    pub visibility: Option<TokenTree>,
460    pub ident: TokenTree,
461    pub generics: Option<GenericParams>,
462    pub inn_attrs: Option<AttrToken>,
463    pub associated_items: Vec<AssociatedItem>,
464    pub raw_block: TokenStream,
465    pub functions: Vec<MethodDeclToken>,
466}
467
468impl TopLevelAST for TraitToken {
469    fn span(&self) -> TokenTree {
470        self.ident.clone()
471    }
472
473    fn is_trait(&self) -> bool {
474        true
475    }
476}
477
478impl TryFrom<&TokenStream> for TraitToken {
479    type Error = KParserError;
480
481    fn try_from(value: &TokenStream) -> Result<Self, Self::Error> {
482        let mut stream = KTokenStream::new(value);
483        parse_trait(&mut stream, &DummyTracer {})
484    }
485}
486
487impl Default for TraitToken {
488    fn default() -> Self {
489        panic!()
490    }
491}
492
493impl Display for TraitToken {
494    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
495        write!(f, "")
496    }
497}
498
499/// Enum that contans all the Associated Items
500/// supported by the parser.
501///
502/// Reference <https://doc.rust-lang.org/stable/reference/items/associated-items.html>
503#[derive(Debug)]
504pub enum AssociatedItem {
505    AssociatedFn(FnDeclTok),
506    AssociatedMethod(MethodDeclToken),
507    // FIXME: add the other associatedItems missing
508}
509
510/// AST token to store the information about the
511/// a function or method declaration
512///
513/// Reference <https://doc.rust-lang.org/stable/reference/items/functions.html>
514#[derive(Debug)]
515pub struct MethodDeclToken {
516    pub attrs: HashMap<String, AttrToken>,
517    pub visibility: Option<TokenTree>,
518    // FIXME: use a better way to be able to
519    // identify what kind of qualifiers is
520    // specified.
521    pub qualifier: Option<TokenTree>,
522    pub ident: TokenTree,
523    pub generics: Option<GenericParams>,
524    pub raw_params: TokenStream,
525    /// method/function parameters parser
526    /// from the `raw_params` in a tuple
527    /// of `(identifier, Type Token)`
528    /// and the position is identified by
529    /// vector index.
530    pub params: Vec<(TokenTree, TyToken)>,
531    pub return_ty: Option<TyToken>,
532    pub raw_body: Option<TokenStream>,
533}
534
535impl Default for MethodDeclToken {
536    fn default() -> Self {
537        unimplemented!()
538    }
539}
540
541impl Display for MethodDeclToken {
542    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
543        write!(f, "")
544    }
545}
546
547impl TopLevelAST for MethodDeclToken {
548    fn span(&self) -> TokenTree {
549        self.ident.clone()
550    }
551
552    fn is_fn(&self) -> bool {
553        true
554    }
555}
556
557/// from a parser point of view this
558/// should not change much because it is
559/// missing just a self param
560pub type FnDeclTok = MethodDeclToken;