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
use std::fmt;
use std::hash::{Hash, Hasher};

use proc_macro2::{self, Literal, TokenNode, Term};

use {Span, TokenTree};

#[derive(Clone)]
pub struct Lit {
    pub value: LitKind,
    pub span: Span,
}

#[derive(Clone)]
pub enum LitKind {
    Bool(bool),
    Other(Literal),
}

impl Lit {
    pub fn into_token_tree(self) -> TokenTree {
        let kind = match self.value {
            LitKind::Bool(true) => TokenNode::Term(Term::intern("true")),
            LitKind::Bool(false) => TokenNode::Term(Term::intern("false")),
            LitKind::Other(l) => TokenNode::Literal(l),
        };
        TokenTree(proc_macro2::TokenTree {
            span: self.span.0,
            kind: kind,
        })
    }
}

impl fmt::Display for Lit {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.value, f)
    }
}

impl fmt::Debug for Lit {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.value, f)
    }
}

impl PartialEq for Lit {
    fn eq(&self, other: &Lit) -> bool {
        self.value == other.value
    }
}

impl Eq for Lit {}

impl Hash for Lit {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.value.hash(hasher)
    }
}

impl fmt::Display for LitKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            LitKind::Bool(b) => b.fmt(f),
            LitKind::Other(ref l) => l.fmt(f),
        }
    }
}

impl fmt::Debug for LitKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            LitKind::Bool(b) => b.fmt(f),
            LitKind::Other(ref l) => fmt::Display::fmt(l, f),
        }
    }
}

impl PartialEq for LitKind {
    fn eq(&self, other: &LitKind) -> bool {
        match (self, other) {
            (&LitKind::Bool(b1), &LitKind::Bool(b2)) => b1 == b2,
            (&LitKind::Other(ref l1), &LitKind::Other(ref l2)) => {
                l1.to_string() == l2.to_string()
            }
            _ => false,
        }
    }
}

impl Eq for LitKind {}

impl Hash for LitKind {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        match *self {
            LitKind::Bool(b) => (0u8, b).hash(hasher),
            LitKind::Other(ref l) => (1u8, l.to_string()).hash(hasher),
        }
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use synom::{Synom, PResult, Cursor, parse_error};

    impl Synom for Lit {
        fn parse(input: Cursor) -> PResult<Self> {
            match input.literal() {
                Some((rest, span, lit)) => {
                    Ok((rest, Lit {
                        span: Span(span),
                        value: LitKind::Other(lit)
                    }))
                }
                _ => match input.word() {
                    Some((rest, span, sym)) => {
                        let kind = if sym.as_str() == "true" {
                            LitKind::Bool(true)
                        } else if sym.as_str() == "false" {
                            LitKind::Bool(false)
                        } else {
                            return parse_error();
                        };

                        Ok((rest, Lit {
                            span: Span(span),
                            value: kind
                        }))
                    }
                    _ => parse_error(),
                }
            }
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};

    impl ToTokens for Lit {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.clone().into_token_tree().to_tokens(tokens)
        }
    }
}