]>
Commit | Line | Data |
---|---|---|
83c7162d XL |
1 | // Copyright 2018 Syn Developers |
2 | // | |
3 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
4 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
5 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
6 | // option. This file may not be copied, modified, or distributed | |
7 | // except according to those terms. | |
8 | ||
9 | use std::cmp::Ordering; | |
10 | use std::fmt::{self, Display}; | |
11 | use std::hash::{Hash, Hasher}; | |
12 | ||
13 | use proc_macro2::{Span, Term}; | |
14 | use unicode_xid::UnicodeXID; | |
15 | ||
16 | /// A Rust lifetime: `'a`. | |
17 | /// | |
18 | /// Lifetime names must conform to the following rules: | |
19 | /// | |
20 | /// - Must start with an apostrophe. | |
21 | /// - Must not consist of just an apostrophe: `'`. | |
22 | /// - Character after the apostrophe must be `_` or a Unicode code point with | |
23 | /// the XID_Start property. | |
24 | /// - All following characters must be Unicode code points with the XID_Continue | |
25 | /// property. | |
26 | /// | |
27 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
28 | /// feature.* | |
29 | #[cfg_attr(feature = "extra-traits", derive(Debug))] | |
30 | #[derive(Copy, Clone)] | |
31 | pub struct Lifetime { | |
32 | term: Term, | |
33 | pub span: Span, | |
34 | } | |
35 | ||
36 | impl Lifetime { | |
37 | pub fn new(term: Term, span: Span) -> Self { | |
38 | let s = term.as_str(); | |
39 | ||
40 | if !s.starts_with('\'') { | |
41 | panic!( | |
42 | "lifetime name must start with apostrophe as in \"'a\", \ | |
43 | got {:?}", | |
44 | s | |
45 | ); | |
46 | } | |
47 | ||
48 | if s == "'" { | |
49 | panic!("lifetime name must not be empty"); | |
50 | } | |
51 | ||
52 | fn xid_ok(s: &str) -> bool { | |
53 | let mut chars = s.chars(); | |
54 | let first = chars.next().unwrap(); | |
55 | if !(UnicodeXID::is_xid_start(first) || first == '_') { | |
56 | return false; | |
57 | } | |
58 | for ch in chars { | |
59 | if !UnicodeXID::is_xid_continue(ch) { | |
60 | return false; | |
61 | } | |
62 | } | |
63 | true | |
64 | } | |
65 | ||
66 | if !xid_ok(&s[1..]) { | |
67 | panic!("{:?} is not a valid lifetime name", s); | |
68 | } | |
69 | ||
70 | Lifetime { | |
71 | term: term, | |
72 | span: span, | |
73 | } | |
74 | } | |
75 | } | |
76 | ||
77 | impl Display for Lifetime { | |
78 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | |
79 | self.term.as_str().fmt(formatter) | |
80 | } | |
81 | } | |
82 | ||
83 | impl PartialEq for Lifetime { | |
84 | fn eq(&self, other: &Lifetime) -> bool { | |
85 | self.term.as_str() == other.term.as_str() | |
86 | } | |
87 | } | |
88 | ||
89 | impl Eq for Lifetime {} | |
90 | ||
91 | impl PartialOrd for Lifetime { | |
92 | fn partial_cmp(&self, other: &Lifetime) -> Option<Ordering> { | |
93 | Some(self.cmp(other)) | |
94 | } | |
95 | } | |
96 | ||
97 | impl Ord for Lifetime { | |
98 | fn cmp(&self, other: &Lifetime) -> Ordering { | |
99 | self.term.as_str().cmp(other.term.as_str()) | |
100 | } | |
101 | } | |
102 | ||
103 | impl Hash for Lifetime { | |
104 | fn hash<H: Hasher>(&self, h: &mut H) { | |
105 | self.term.as_str().hash(h) | |
106 | } | |
107 | } | |
108 | ||
109 | #[cfg(feature = "parsing")] | |
110 | pub mod parsing { | |
111 | use super::*; | |
112 | use synom::Synom; | |
113 | use buffer::Cursor; | |
114 | use parse_error; | |
115 | use synom::PResult; | |
116 | ||
117 | impl Synom for Lifetime { | |
118 | fn parse(input: Cursor) -> PResult<Self> { | |
119 | let (span, term, rest) = match input.term() { | |
120 | Some(term) => term, | |
121 | _ => return parse_error(), | |
122 | }; | |
123 | if !term.as_str().starts_with('\'') { | |
124 | return parse_error(); | |
125 | } | |
126 | ||
127 | Ok(( | |
128 | Lifetime { | |
129 | term: term, | |
130 | span: span, | |
131 | }, | |
132 | rest, | |
133 | )) | |
134 | } | |
135 | ||
136 | fn description() -> Option<&'static str> { | |
137 | Some("lifetime") | |
138 | } | |
139 | } | |
140 | } | |
141 | ||
142 | #[cfg(feature = "printing")] | |
143 | mod printing { | |
144 | use super::*; | |
145 | use quote::{ToTokens, Tokens}; | |
146 | use proc_macro2::{TokenNode, TokenTree}; | |
147 | ||
148 | impl ToTokens for Lifetime { | |
149 | fn to_tokens(&self, tokens: &mut Tokens) { | |
150 | tokens.append(TokenTree { | |
151 | span: self.span, | |
152 | kind: TokenNode::Term(self.term), | |
153 | }) | |
154 | } | |
155 | } | |
156 | } |