blob: 9c9f2745933a22b58f857cf42196141704919568 [file] [log] [blame]
Alex Crichtonccbb45d2017-05-23 10:58:24 -07001use std::fmt;
2use std::hash::{Hash, Hasher};
3
4use proc_macro2::{self, Literal, TokenKind};
5
6use {Span, TokenTree};
7
8#[derive(Clone)]
9pub struct Lit {
10 pub value: LitKind,
11 pub span: Span,
12}
13
14#[derive(Clone)]
15pub enum LitKind {
16 Bool(bool),
17 Other(Literal),
18}
19
20impl Lit {
21 pub fn into_token_tree(self) -> TokenTree {
22 let kind = match self.value {
23 LitKind::Bool(true) => TokenKind::Word("true".into()),
24 LitKind::Bool(false) => TokenKind::Word("false".into()),
25 LitKind::Other(l) => TokenKind::Literal(l),
26 };
27 TokenTree(proc_macro2::TokenTree {
28 span: self.span.0,
29 kind: kind,
30 })
Alex Crichton62a0a592017-05-22 13:58:53 -070031 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070032}
33
Alex Crichtonccbb45d2017-05-23 10:58:24 -070034impl fmt::Display for Lit {
35 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36 fmt::Display::fmt(&self.value, f)
Alex Crichton62a0a592017-05-22 13:58:53 -070037 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070038}
39
Alex Crichtonccbb45d2017-05-23 10:58:24 -070040impl fmt::Debug for Lit {
41 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42 fmt::Display::fmt(&self.value, f)
Pascal Hertleif36342c52016-10-19 10:31:42 +020043 }
44}
45
Alex Crichtonccbb45d2017-05-23 10:58:24 -070046impl PartialEq for Lit {
47 fn eq(&self, other: &Lit) -> bool {
48 self.value == other.value
Pascal Hertleif36342c52016-10-19 10:31:42 +020049 }
50}
51
Alex Crichtonccbb45d2017-05-23 10:58:24 -070052impl Eq for Lit {}
53
54impl Hash for Lit {
55 fn hash<H: Hasher>(&self, hasher: &mut H) {
56 self.value.hash(hasher)
Pascal Hertleif36342c52016-10-19 10:31:42 +020057 }
58}
59
Alex Crichtonccbb45d2017-05-23 10:58:24 -070060impl fmt::Display for LitKind {
61 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62 match *self {
63 LitKind::Bool(b) => b.fmt(f),
64 LitKind::Other(ref l) => l.fmt(f),
65 }
Pascal Hertleif36342c52016-10-19 10:31:42 +020066 }
67}
68
Alex Crichtonccbb45d2017-05-23 10:58:24 -070069impl fmt::Debug for LitKind {
70 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71 match *self {
72 LitKind::Bool(b) => b.fmt(f),
73 LitKind::Other(ref l) => fmt::Display::fmt(l, f),
74 }
Pascal Hertleif36342c52016-10-19 10:31:42 +020075 }
76}
77
Alex Crichtonccbb45d2017-05-23 10:58:24 -070078impl PartialEq for LitKind {
79 fn eq(&self, other: &LitKind) -> bool {
80 match (self, other) {
81 (&LitKind::Bool(b1), &LitKind::Bool(b2)) => b1 == b2,
82 (&LitKind::Other(ref l1), &LitKind::Other(ref l2)) => {
83 l1.to_string() == l2.to_string()
Pascal Hertleif36342c52016-10-19 10:31:42 +020084 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -070085 _ => false,
86 }
Alex Crichton2e0229c2017-05-23 09:34:50 -070087 }
David Tolnay5fe14fc2017-01-27 16:22:08 -080088}
89
Alex Crichtonccbb45d2017-05-23 10:58:24 -070090impl Eq for LitKind {}
David Tolnay5fe14fc2017-01-27 16:22:08 -080091
Alex Crichtonccbb45d2017-05-23 10:58:24 -070092impl Hash for LitKind {
93 fn hash<H: Hasher>(&self, hasher: &mut H) {
94 match *self {
95 LitKind::Bool(b) => (0u8, b).hash(hasher),
96 LitKind::Other(ref l) => (1u8, l.to_string()).hash(hasher),
97 }
Alex Crichton2e0229c2017-05-23 09:34:50 -070098 }
David Tolnay5fe14fc2017-01-27 16:22:08 -080099}
100
101#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700102pub mod parsing {
103 use super::*;
David Tolnayfe373a32016-10-26 23:51:19 -0700104 use escape::{cooked_byte, cooked_byte_string, cooked_char, cooked_string, raw_string};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700105 use proc_macro2::Literal;
David Tolnay5fe14fc2017-01-27 16:22:08 -0800106 use synom::IResult;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700107 use synom::space::skip_whitespace;
David Tolnay4f5f60f2016-10-24 00:52:58 -0700108 use unicode_xid::UnicodeXID;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700109
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700110 fn l<T: Into<Literal>>(t: T) -> Lit {
111 Lit {
112 value: LitKind::Other(t.into()),
113 span: Default::default(),
114 }
115 }
116
David Tolnayf4bbbd92016-09-23 14:41:55 -0700117 named!(pub lit -> Lit, alt!(
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700118 string
David Tolnay56d62132016-10-01 16:14:54 -0700119 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700120 byte_string
David Tolnay615cf6a2016-10-08 23:07:02 -0700121 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700122 byte
David Tolnay615cf6a2016-10-08 23:07:02 -0700123 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700124 character
David Tolnayf4bbbd92016-09-23 14:41:55 -0700125 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700126 float
David Tolnay4f5f60f2016-10-24 00:52:58 -0700127 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700128 int
David Tolnay759d2ff2016-10-01 16:18:15 -0700129 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700130 boolean
David Tolnayf4bbbd92016-09-23 14:41:55 -0700131 ));
132
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700133 named!(pub string -> Lit, alt!(
134 quoted_string => { |s: String| l(&s[..]) }
David Tolnay210884d2016-10-01 08:18:42 -0700135 |
136 preceded!(
137 punct!("r"),
138 raw_string
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700139 ) => { |(s, n): (String, _)| l(Literal::raw_string(&s[..], n)) }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700140 ));
141
David Tolnay42602292016-10-01 22:25:45 -0700142 named!(pub quoted_string -> String, delimited!(
143 punct!("\""),
144 cooked_string,
145 tag!("\"")
146 ));
147
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700148 named!(pub byte_string -> Lit, alt!(
David Tolnay56d62132016-10-01 16:14:54 -0700149 delimited!(
150 punct!("b\""),
David Tolnaya73e0f02016-10-26 23:25:49 -0700151 cooked_byte_string,
David Tolnay56d62132016-10-01 16:14:54 -0700152 tag!("\"")
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700153 ) => { |vec: Vec<u8>| l(Literal::byte_string(&vec)) }
David Tolnay56d62132016-10-01 16:14:54 -0700154 |
155 preceded!(
156 punct!("br"),
157 raw_string
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700158 ) => { |(s, n): (String, _)| l(Literal::raw_byte_string(&s, n)) }
David Tolnay56d62132016-10-01 16:14:54 -0700159 ));
160
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700161 named!(pub byte -> Lit, do_parse!(
David Tolnay615cf6a2016-10-08 23:07:02 -0700162 punct!("b") >>
163 tag!("'") >>
David Tolnayfe373a32016-10-26 23:51:19 -0700164 b: cooked_byte >>
David Tolnay615cf6a2016-10-08 23:07:02 -0700165 tag!("'") >>
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700166 (l(Literal::byte_char(b)))
David Tolnay615cf6a2016-10-08 23:07:02 -0700167 ));
168
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700169 named!(pub character -> Lit, do_parse!(
David Tolnay615cf6a2016-10-08 23:07:02 -0700170 punct!("'") >>
171 ch: cooked_char >>
172 tag!("'") >>
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700173 (l(ch))
David Tolnay615cf6a2016-10-08 23:07:02 -0700174 ));
175
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700176 named!(pub float -> Lit, do_parse!(
David Tolnay5fe14fc2017-01-27 16:22:08 -0800177 value: float_string >>
178 suffix: alt!(
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700179 tag!("f32")
David Tolnay4f5f60f2016-10-24 00:52:58 -0700180 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700181 tag!("f64")
David Tolnay4f5f60f2016-10-24 00:52:58 -0700182 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700183 epsilon!() => { |_| "" }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800184 ) >>
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700185 (l(Literal::float(&format!("{}{}", value, suffix))))
David Tolnay4f5f60f2016-10-24 00:52:58 -0700186 ));
187
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700188 named!(pub int -> Lit, do_parse!(
David Tolnay5fe14fc2017-01-27 16:22:08 -0800189 value: digits >>
190 suffix: alt!(
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700191 tag!("isize")
David Tolnayde206222016-09-30 11:47:01 -0700192 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700193 tag!("i8")
David Tolnayde206222016-09-30 11:47:01 -0700194 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700195 tag!("i16")
David Tolnayde206222016-09-30 11:47:01 -0700196 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700197 tag!("i32")
David Tolnayde206222016-09-30 11:47:01 -0700198 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700199 tag!("i64")
David Tolnayde206222016-09-30 11:47:01 -0700200 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700201 tag!("usize")
David Tolnayde206222016-09-30 11:47:01 -0700202 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700203 tag!("u8")
David Tolnayde206222016-09-30 11:47:01 -0700204 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700205 tag!("u16")
David Tolnayde206222016-09-30 11:47:01 -0700206 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700207 tag!("u32")
David Tolnayde206222016-09-30 11:47:01 -0700208 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700209 tag!("u64")
David Tolnayde206222016-09-30 11:47:01 -0700210 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700211 epsilon!() => { |_| "" }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800212 ) >>
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700213 (l(Literal::integer(&format!("{}{}", value, suffix))))
David Tolnayf4bbbd92016-09-23 14:41:55 -0700214 ));
215
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700216 named!(pub boolean -> Lit, alt!(
217 keyword!("true") => { |_| Lit {
218 span: Span::default(),
219 value: LitKind::Bool(true),
220 } }
David Tolnay3ce49d02016-10-23 22:29:19 -0700221 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700222 keyword!("false") => { |_| Lit {
223 span: Span::default(),
224 value: LitKind::Bool(false),
225 } }
David Tolnay3ce49d02016-10-23 22:29:19 -0700226 ));
227
David Tolnaydef66372016-10-24 21:51:32 -0700228 fn float_string(mut input: &str) -> IResult<&str, String> {
229 input = skip_whitespace(input);
230
David Tolnay4f5f60f2016-10-24 00:52:58 -0700231 let mut chars = input.chars().peekable();
232 match chars.next() {
233 Some(ch) if ch >= '0' && ch <= '9' => {}
234 _ => return IResult::Error,
235 }
236
237 let mut len = 1;
238 let mut has_dot = false;
239 let mut has_exp = false;
240 while let Some(&ch) = chars.peek() {
241 match ch {
242 '0'...'9' | '_' => {
243 chars.next();
244 len += 1;
245 }
246 '.' => {
247 if has_dot {
248 break;
249 }
250 chars.next();
251 if chars.peek()
David Tolnay05120ef2017-03-12 18:29:26 -0700252 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
253 .unwrap_or(false) {
David Tolnay4f5f60f2016-10-24 00:52:58 -0700254 return IResult::Error;
255 }
256 len += 1;
257 has_dot = true;
258 }
259 'e' | 'E' => {
260 chars.next();
261 len += 1;
262 has_exp = true;
263 break;
264 }
265 _ => break,
266 }
267 }
268
269 let rest = &input[len..];
270 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
271 return IResult::Error;
272 }
273
274 if has_exp {
275 let mut has_exp_value = false;
276 while let Some(&ch) = chars.peek() {
277 match ch {
278 '+' | '-' => {
279 if has_exp_value {
280 break;
281 }
282 chars.next();
283 len += 1;
284 }
285 '0'...'9' => {
286 chars.next();
287 len += 1;
288 has_exp_value = true;
289 }
290 '_' => {
291 chars.next();
292 len += 1;
293 }
294 _ => break,
295 }
296 }
297 if !has_exp_value {
298 return IResult::Error;
299 }
300 }
301
David Tolnayc7b636a2016-10-24 13:01:08 -0700302 IResult::Done(&input[len..], input[..len].replace("_", ""))
David Tolnay4f5f60f2016-10-24 00:52:58 -0700303 }
304
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700305 pub fn digits(mut input: &str) -> IResult<&str, &str> {
David Tolnaydef66372016-10-24 21:51:32 -0700306 input = skip_whitespace(input);
307
David Tolnay8a19e6d2016-10-24 01:23:40 -0700308 let base = if input.starts_with("0x") {
David Tolnay8a19e6d2016-10-24 01:23:40 -0700309 16
310 } else if input.starts_with("0o") {
David Tolnay8a19e6d2016-10-24 01:23:40 -0700311 8
312 } else if input.starts_with("0b") {
David Tolnay8a19e6d2016-10-24 01:23:40 -0700313 2
314 } else {
315 10
316 };
317
David Tolnayf4bbbd92016-09-23 14:41:55 -0700318 let mut value = 0u64;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700319 let mut len = if base == 10 {0} else {2};
David Tolnay24b5ff72016-10-24 01:05:05 -0700320 let mut empty = true;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700321 for b in input[len..].bytes() {
David Tolnay8a19e6d2016-10-24 01:23:40 -0700322 let digit = match b {
323 b'0'...b'9' => (b - b'0') as u64,
324 b'a'...b'f' => 10 + (b - b'a') as u64,
325 b'A'...b'F' => 10 + (b - b'A') as u64,
David Tolnay24b5ff72016-10-24 01:05:05 -0700326 b'_' => {
David Tolnayc814a762016-10-27 23:11:28 -0700327 if empty && base == 10 {
David Tolnay24b5ff72016-10-24 01:05:05 -0700328 return IResult::Error;
329 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700330 len += 1;
David Tolnay8a19e6d2016-10-24 01:23:40 -0700331 continue;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700332 }
David Tolnayfa0edf22016-09-23 22:58:24 -0700333 _ => break,
David Tolnay8a19e6d2016-10-24 01:23:40 -0700334 };
335 if digit >= base {
336 return IResult::Error;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700337 }
David Tolnay8a19e6d2016-10-24 01:23:40 -0700338 value = match value.checked_mul(base) {
339 Some(value) => value,
340 None => return IResult::Error,
341 };
342 value = match value.checked_add(digit) {
343 Some(value) => value,
344 None => return IResult::Error,
345 };
346 len += 1;
347 empty = false;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700348 }
David Tolnay24b5ff72016-10-24 01:05:05 -0700349 if empty {
David Tolnayfa0edf22016-09-23 22:58:24 -0700350 IResult::Error
David Tolnay24b5ff72016-10-24 01:05:05 -0700351 } else {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700352 IResult::Done(&input[len..], &input[..len])
David Tolnayfa0edf22016-09-23 22:58:24 -0700353 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700354 }
355}
356
357#[cfg(feature = "printing")]
358mod printing {
359 use super::*;
360 use quote::{Tokens, ToTokens};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700361
362 use proc_macro2::{TokenTree, TokenKind};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700363
364 impl ToTokens for Lit {
365 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700366 let kind = match self.value {
367 LitKind::Bool(true) => TokenKind::Word("true".into()),
368 LitKind::Bool(false) => TokenKind::Word("false".into()),
369 LitKind::Other(ref l) => TokenKind::Literal(l.clone()),
370 };
371 tokens.append(TokenTree {
372 span: self.span.0,
373 kind: kind,
374 });
David Tolnayf17fd2f2016-10-07 23:38:08 -0700375 }
376 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700377}