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
use std::cmp::{Ord, Ordering};
use std::fmt::{self, Debug};

use syn::{Ident, spanned::Spanned};
use proc_macro2::{TokenStream, Span};

use crate::graph::{Node, Disambiguate};
use crate::util::MaybeVoid;

#[derive(Clone)]
pub struct Leaf<'t> {
    pub ident: &'t Ident,
    pub span: Span,
    pub priority: usize,
    pub field: MaybeVoid,
    pub callback: Option<Callback>,
}

#[derive(Clone)]
pub enum Callback {
    Label(TokenStream),
    Inline(Box<InlineCallback>),
}

#[derive(Clone)]
pub struct InlineCallback {
    pub arg: Ident,
    pub body: TokenStream,
    pub span: Span,
}

impl From<InlineCallback> for Callback {
    fn from(inline: InlineCallback) -> Callback {
        Callback::Inline(Box::new(inline))
    }
}

impl Callback {
    pub fn span(&self) -> Span {
        match self {
            Callback::Label(tokens) => tokens.span(),
            Callback::Inline(inline) => inline.span,
        }
    }
}

impl<'t> Leaf<'t> {
    pub fn new(ident: &'t Ident, span: Span) -> Self {
        Leaf {
            ident,
            span,
            priority: 0,
            field: MaybeVoid::Void,
            callback: None,
        }
    }

    pub fn callback(mut self, callback: Option<Callback>) -> Self {
        self.callback = callback;
        self
    }

    pub fn field(mut self, field: MaybeVoid) -> Self {
        self.field = field;
        self
    }

    pub fn priority(mut self, priority: usize) -> Self {
        self.priority = priority;
        self
    }
}

impl Disambiguate for Leaf<'_> {
    fn cmp(left: &Leaf, right: &Leaf) -> Ordering {
        Ord::cmp(&left.priority, &right.priority)
    }
}

impl<'t> From<Leaf<'t>> for Node<Leaf<'t>> {
    fn from(leaf: Leaf<'t>) -> Self {
        Node::Leaf(leaf)
    }
}

impl Debug for Leaf<'_> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "::{}", self.ident)?;

        match self.callback {
            Some(Callback::Label(ref label)) => write!(f, " ({})", label),
            Some(Callback::Inline(_)) => f.write_str(" (<inline>)"),
            None => Ok(()),
        }
    }
}