blob: 4811485d66f6b743f549911ecb0e3562f1ddef6a [file] [log] [blame]
Alex Crichton62a0a592017-05-22 13:58:53 -07001ast_enum! {
2 /// Literal kind.
3 ///
4 /// E.g. `"foo"`, `42`, `12.34` or `bool`
5 pub enum Lit {
6 /// A string literal (`"foo"`)
7 Str(String, StrStyle),
8 /// A byte string (`b"foo"`)
9 ByteStr(Vec<u8>, StrStyle),
10 /// A byte char (`b'f'`)
11 Byte(u8),
12 /// A character literal (`'a'`)
13 Char(char),
14 /// An integer literal (`1`)
15 Int(u64, IntTy),
16 /// A float literal (`1f64` or `1E10f64` or `1.0E10`)
17 Float(String, FloatTy),
18 /// A boolean literal
19 Bool(bool),
20 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070021}
22
Alex Crichton62a0a592017-05-22 13:58:53 -070023ast_enum! {
24 pub enum StrStyle {
25 /// A regular string, like `"foo"`
26 Cooked,
27 /// A raw string, like `r##"foo"##`
28 ///
29 /// The uint is the number of `#` symbols used
30 Raw(usize),
31 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070032}
33
Pascal Hertleif36342c52016-10-19 10:31:42 +020034impl From<String> for Lit {
35 fn from(input: String) -> Lit {
36 Lit::Str(input, StrStyle::Cooked)
37 }
38}
39
40impl<'a> From<&'a str> for Lit {
41 fn from(input: &str) -> Lit {
42 Lit::Str(input.into(), StrStyle::Cooked)
43 }
44}
45
46impl From<Vec<u8>> for Lit {
47 fn from(input: Vec<u8>) -> Lit {
David Tolnay4a658402016-10-24 00:21:41 -070048 Lit::ByteStr(input, StrStyle::Cooked)
Pascal Hertleif36342c52016-10-19 10:31:42 +020049 }
50}
51
52impl<'a> From<&'a [u8]> for Lit {
53 fn from(input: &[u8]) -> Lit {
David Tolnay4a658402016-10-24 00:21:41 -070054 Lit::ByteStr(input.into(), StrStyle::Cooked)
Pascal Hertleif36342c52016-10-19 10:31:42 +020055 }
56}
57
58impl From<char> for Lit {
59 fn from(input: char) -> Lit {
60 Lit::Char(input)
61 }
62}
63
64impl From<bool> for Lit {
65 fn from(input: bool) -> Lit {
66 Lit::Bool(input)
67 }
68}
69
Alex Crichton62a0a592017-05-22 13:58:53 -070070ast_enum! {
71 #[derive(Copy)]
72 pub enum IntTy {
73 Isize,
74 I8,
75 I16,
76 I32,
77 I64,
78 Usize,
79 U8,
80 U16,
81 U32,
82 U64,
83 Unsuffixed,
84 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070085}
86
Alex Crichton62a0a592017-05-22 13:58:53 -070087ast_enum! {
88 #[derive(Copy)]
89 pub enum FloatTy {
90 F32,
91 F64,
92 Unsuffixed,
93 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070094}
95
Pascal Hertleif36342c52016-10-19 10:31:42 +020096macro_rules! impl_from_for_lit {
97 (Int, [$($rust_type:ty => $syn_type:expr),+]) => {
98 $(
99 impl From<$rust_type> for Lit {
100 fn from(input: $rust_type) -> Lit {
101 Lit::Int(input as u64, $syn_type)
102 }
103 }
104 )+
105 };
106 (Float, [$($rust_type:ty => $syn_type:expr),+]) => {
107 $(
108 impl From<$rust_type> for Lit {
109 fn from(input: $rust_type) -> Lit {
110 Lit::Float(format!("{}", input), $syn_type)
111 }
112 }
113 )+
114 };
115}
116
117impl_from_for_lit! {Int, [
118 isize => IntTy::Isize,
119 i8 => IntTy::I8,
120 i16 => IntTy::I16,
121 i32 => IntTy::I32,
122 i64 => IntTy::I64,
123 usize => IntTy::Usize,
124 u8 => IntTy::U8,
125 u16 => IntTy::U16,
126 u32 => IntTy::U32,
127 u64 => IntTy::U64
128]}
129
130impl_from_for_lit! {Float, [
131 f32 => FloatTy::F32,
132 f64 => FloatTy::F64
133]}
134
David Tolnayf4bbbd92016-09-23 14:41:55 -0700135#[cfg(feature = "parsing")]
David Tolnay5fe14fc2017-01-27 16:22:08 -0800136#[derive(Debug, Clone)]
137pub struct StrLit {
Michael Layzell93336812017-01-28 16:16:15 -0500138 pub value: String,
139 pub style: StrStyle,
David Tolnay5fe14fc2017-01-27 16:22:08 -0800140}
141
142#[cfg(feature = "parsing")]
143#[derive(Debug, Clone)]
144pub struct ByteStrLit {
Michael Layzell93336812017-01-28 16:16:15 -0500145 pub value: Vec<u8>,
146 pub style: StrStyle,
David Tolnay5fe14fc2017-01-27 16:22:08 -0800147}
148
149#[cfg(feature = "parsing")]
150#[derive(Debug, Clone)]
151pub struct IntLit {
Michael Layzell93336812017-01-28 16:16:15 -0500152 pub value: u64,
153 pub suffix: IntTy,
David Tolnay5fe14fc2017-01-27 16:22:08 -0800154}
155
156#[cfg(feature = "parsing")]
157#[derive(Debug, Clone)]
158pub struct FloatLit {
Michael Layzell93336812017-01-28 16:16:15 -0500159 pub value: String,
160 pub suffix: FloatTy,
David Tolnay5fe14fc2017-01-27 16:22:08 -0800161}
162
163#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700164pub mod parsing {
165 use super::*;
David Tolnayfe373a32016-10-26 23:51:19 -0700166 use escape::{cooked_byte, cooked_byte_string, cooked_char, cooked_string, raw_string};
David Tolnay5fe14fc2017-01-27 16:22:08 -0800167 use synom::space::skip_whitespace;
168 use synom::IResult;
David Tolnay4f5f60f2016-10-24 00:52:58 -0700169 use unicode_xid::UnicodeXID;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700170
171 named!(pub lit -> Lit, alt!(
David Tolnay5fe14fc2017-01-27 16:22:08 -0800172 string => { |StrLit { value, style }| Lit::Str(value, style) }
David Tolnay56d62132016-10-01 16:14:54 -0700173 |
David Tolnay5fe14fc2017-01-27 16:22:08 -0800174 byte_string => { |ByteStrLit { value, style }| Lit::ByteStr(value, style) }
David Tolnay615cf6a2016-10-08 23:07:02 -0700175 |
Michael Layzell5e107ff2017-01-24 19:58:39 -0500176 byte => { |b| Lit::Byte(b) }
David Tolnay615cf6a2016-10-08 23:07:02 -0700177 |
Michael Layzell5e107ff2017-01-24 19:58:39 -0500178 character => { |ch| Lit::Char(ch) }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700179 |
David Tolnay5fe14fc2017-01-27 16:22:08 -0800180 float => { |FloatLit { value, suffix }| Lit::Float(value, suffix) } // must be before int
David Tolnay4f5f60f2016-10-24 00:52:58 -0700181 |
David Tolnay5fe14fc2017-01-27 16:22:08 -0800182 int => { |IntLit { value, suffix }| Lit::Int(value, suffix) }
David Tolnay759d2ff2016-10-01 16:18:15 -0700183 |
Michael Layzell5e107ff2017-01-24 19:58:39 -0500184 boolean => { |value| Lit::Bool(value) }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700185 ));
186
David Tolnay5fe14fc2017-01-27 16:22:08 -0800187 named!(pub string -> StrLit, alt!(
188 quoted_string => { |s| StrLit { value: s, style: StrStyle::Cooked } }
David Tolnay210884d2016-10-01 08:18:42 -0700189 |
190 preceded!(
191 punct!("r"),
192 raw_string
David Tolnay5fe14fc2017-01-27 16:22:08 -0800193 ) => { |(s, n)| StrLit { value: s, style: StrStyle::Raw(n) }}
David Tolnayf4bbbd92016-09-23 14:41:55 -0700194 ));
195
David Tolnay42602292016-10-01 22:25:45 -0700196 named!(pub quoted_string -> String, delimited!(
197 punct!("\""),
198 cooked_string,
199 tag!("\"")
200 ));
201
David Tolnay5fe14fc2017-01-27 16:22:08 -0800202 named!(pub byte_string -> ByteStrLit, alt!(
David Tolnay56d62132016-10-01 16:14:54 -0700203 delimited!(
204 punct!("b\""),
David Tolnaya73e0f02016-10-26 23:25:49 -0700205 cooked_byte_string,
David Tolnay56d62132016-10-01 16:14:54 -0700206 tag!("\"")
David Tolnay5fe14fc2017-01-27 16:22:08 -0800207 ) => { |vec| ByteStrLit { value: vec, style: StrStyle::Cooked } }
David Tolnay56d62132016-10-01 16:14:54 -0700208 |
209 preceded!(
210 punct!("br"),
211 raw_string
David Tolnay5fe14fc2017-01-27 16:22:08 -0800212 ) => { |(s, n): (String, _)| ByteStrLit { value: s.into_bytes(), style: StrStyle::Raw(n) } }
David Tolnay56d62132016-10-01 16:14:54 -0700213 ));
214
Michael Layzell5e107ff2017-01-24 19:58:39 -0500215 named!(pub byte -> u8, do_parse!(
David Tolnay615cf6a2016-10-08 23:07:02 -0700216 punct!("b") >>
217 tag!("'") >>
David Tolnayfe373a32016-10-26 23:51:19 -0700218 b: cooked_byte >>
David Tolnay615cf6a2016-10-08 23:07:02 -0700219 tag!("'") >>
Michael Layzell5e107ff2017-01-24 19:58:39 -0500220 (b)
David Tolnay615cf6a2016-10-08 23:07:02 -0700221 ));
222
Michael Layzell5e107ff2017-01-24 19:58:39 -0500223 named!(pub character -> char, do_parse!(
David Tolnay615cf6a2016-10-08 23:07:02 -0700224 punct!("'") >>
225 ch: cooked_char >>
226 tag!("'") >>
Michael Layzell5e107ff2017-01-24 19:58:39 -0500227 (ch)
David Tolnay615cf6a2016-10-08 23:07:02 -0700228 ));
229
David Tolnay5fe14fc2017-01-27 16:22:08 -0800230 named!(pub float -> FloatLit, do_parse!(
231 value: float_string >>
232 suffix: alt!(
David Tolnay4f5f60f2016-10-24 00:52:58 -0700233 tag!("f32") => { |_| FloatTy::F32 }
234 |
235 tag!("f64") => { |_| FloatTy::F64 }
236 |
237 epsilon!() => { |_| FloatTy::Unsuffixed }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800238 ) >>
239 (FloatLit { value: value, suffix: suffix })
David Tolnay4f5f60f2016-10-24 00:52:58 -0700240 ));
241
David Tolnay5fe14fc2017-01-27 16:22:08 -0800242 named!(pub int -> IntLit, do_parse!(
243 value: digits >>
244 suffix: alt!(
David Tolnayde206222016-09-30 11:47:01 -0700245 tag!("isize") => { |_| IntTy::Isize }
246 |
247 tag!("i8") => { |_| IntTy::I8 }
248 |
249 tag!("i16") => { |_| IntTy::I16 }
250 |
251 tag!("i32") => { |_| IntTy::I32 }
252 |
253 tag!("i64") => { |_| IntTy::I64 }
254 |
255 tag!("usize") => { |_| IntTy::Usize }
256 |
257 tag!("u8") => { |_| IntTy::U8 }
258 |
259 tag!("u16") => { |_| IntTy::U16 }
260 |
261 tag!("u32") => { |_| IntTy::U32 }
262 |
263 tag!("u64") => { |_| IntTy::U64 }
264 |
265 epsilon!() => { |_| IntTy::Unsuffixed }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800266 ) >>
267 (IntLit { value: value, suffix: suffix })
David Tolnayf4bbbd92016-09-23 14:41:55 -0700268 ));
269
Michael Layzell5e107ff2017-01-24 19:58:39 -0500270 named!(pub boolean -> bool, alt!(
271 keyword!("true") => { |_| true }
David Tolnay3ce49d02016-10-23 22:29:19 -0700272 |
Michael Layzell5e107ff2017-01-24 19:58:39 -0500273 keyword!("false") => { |_| false }
David Tolnay3ce49d02016-10-23 22:29:19 -0700274 ));
275
David Tolnaydef66372016-10-24 21:51:32 -0700276 fn float_string(mut input: &str) -> IResult<&str, String> {
277 input = skip_whitespace(input);
278
David Tolnay4f5f60f2016-10-24 00:52:58 -0700279 let mut chars = input.chars().peekable();
280 match chars.next() {
281 Some(ch) if ch >= '0' && ch <= '9' => {}
282 _ => return IResult::Error,
283 }
284
285 let mut len = 1;
286 let mut has_dot = false;
287 let mut has_exp = false;
288 while let Some(&ch) = chars.peek() {
289 match ch {
290 '0'...'9' | '_' => {
291 chars.next();
292 len += 1;
293 }
294 '.' => {
295 if has_dot {
296 break;
297 }
298 chars.next();
299 if chars.peek()
David Tolnay05120ef2017-03-12 18:29:26 -0700300 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
301 .unwrap_or(false) {
David Tolnay4f5f60f2016-10-24 00:52:58 -0700302 return IResult::Error;
303 }
304 len += 1;
305 has_dot = true;
306 }
307 'e' | 'E' => {
308 chars.next();
309 len += 1;
310 has_exp = true;
311 break;
312 }
313 _ => break,
314 }
315 }
316
317 let rest = &input[len..];
318 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
319 return IResult::Error;
320 }
321
322 if has_exp {
323 let mut has_exp_value = false;
324 while let Some(&ch) = chars.peek() {
325 match ch {
326 '+' | '-' => {
327 if has_exp_value {
328 break;
329 }
330 chars.next();
331 len += 1;
332 }
333 '0'...'9' => {
334 chars.next();
335 len += 1;
336 has_exp_value = true;
337 }
338 '_' => {
339 chars.next();
340 len += 1;
341 }
342 _ => break,
343 }
344 }
345 if !has_exp_value {
346 return IResult::Error;
347 }
348 }
349
David Tolnayc7b636a2016-10-24 13:01:08 -0700350 IResult::Done(&input[len..], input[..len].replace("_", ""))
David Tolnay4f5f60f2016-10-24 00:52:58 -0700351 }
352
David Tolnay8a19e6d2016-10-24 01:23:40 -0700353 pub fn digits(mut input: &str) -> IResult<&str, u64> {
David Tolnaydef66372016-10-24 21:51:32 -0700354 input = skip_whitespace(input);
355
David Tolnay8a19e6d2016-10-24 01:23:40 -0700356 let base = if input.starts_with("0x") {
357 input = &input[2..];
358 16
359 } else if input.starts_with("0o") {
360 input = &input[2..];
361 8
362 } else if input.starts_with("0b") {
363 input = &input[2..];
364 2
365 } else {
366 10
367 };
368
David Tolnayf4bbbd92016-09-23 14:41:55 -0700369 let mut value = 0u64;
370 let mut len = 0;
David Tolnay24b5ff72016-10-24 01:05:05 -0700371 let mut empty = true;
372 for b in input.bytes() {
David Tolnay8a19e6d2016-10-24 01:23:40 -0700373 let digit = match b {
374 b'0'...b'9' => (b - b'0') as u64,
375 b'a'...b'f' => 10 + (b - b'a') as u64,
376 b'A'...b'F' => 10 + (b - b'A') as u64,
David Tolnay24b5ff72016-10-24 01:05:05 -0700377 b'_' => {
David Tolnayc814a762016-10-27 23:11:28 -0700378 if empty && base == 10 {
David Tolnay24b5ff72016-10-24 01:05:05 -0700379 return IResult::Error;
380 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700381 len += 1;
David Tolnay8a19e6d2016-10-24 01:23:40 -0700382 continue;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700383 }
David Tolnayfa0edf22016-09-23 22:58:24 -0700384 _ => break,
David Tolnay8a19e6d2016-10-24 01:23:40 -0700385 };
386 if digit >= base {
387 return IResult::Error;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700388 }
David Tolnay8a19e6d2016-10-24 01:23:40 -0700389 value = match value.checked_mul(base) {
390 Some(value) => value,
391 None => return IResult::Error,
392 };
393 value = match value.checked_add(digit) {
394 Some(value) => value,
395 None => return IResult::Error,
396 };
397 len += 1;
398 empty = false;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700399 }
David Tolnay24b5ff72016-10-24 01:05:05 -0700400 if empty {
David Tolnayfa0edf22016-09-23 22:58:24 -0700401 IResult::Error
David Tolnay24b5ff72016-10-24 01:05:05 -0700402 } else {
403 IResult::Done(&input[len..], value)
David Tolnayfa0edf22016-09-23 22:58:24 -0700404 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700405 }
406}
407
408#[cfg(feature = "printing")]
409mod printing {
410 use super::*;
411 use quote::{Tokens, ToTokens};
David Tolnay56d62132016-10-01 16:14:54 -0700412 use std::{ascii, iter};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700413 use std::fmt::{self, Display};
David Tolnay4a658402016-10-24 00:21:41 -0700414 use std::str;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700415
416 impl ToTokens for Lit {
417 fn to_tokens(&self, tokens: &mut Tokens) {
418 match *self {
419 Lit::Str(ref s, StrStyle::Cooked) => s.to_tokens(tokens),
David Tolnay627e3d52016-10-01 08:27:31 -0700420 Lit::Str(ref s, StrStyle::Raw(n)) => {
David Tolnay56d62132016-10-01 16:14:54 -0700421 tokens.append(&format!("r{delim}\"{string}\"{delim}",
David Tolnay05120ef2017-03-12 18:29:26 -0700422 delim = iter::repeat("#").take(n).collect::<String>(),
423 string = s));
David Tolnay56d62132016-10-01 16:14:54 -0700424 }
David Tolnay4a658402016-10-24 00:21:41 -0700425 Lit::ByteStr(ref v, StrStyle::Cooked) => {
David Tolnay56d62132016-10-01 16:14:54 -0700426 let mut escaped = "b\"".to_string();
427 for &ch in v.iter() {
David Tolnay289f4c72016-10-25 00:00:09 -0700428 match ch {
429 0 => escaped.push_str(r"\0"),
430 b'\'' => escaped.push('\''),
431 _ => escaped.extend(ascii::escape_default(ch).map(|c| c as char)),
432 }
David Tolnay627e3d52016-10-01 08:27:31 -0700433 }
David Tolnay56d62132016-10-01 16:14:54 -0700434 escaped.push('"');
435 tokens.append(&escaped);
David Tolnay627e3d52016-10-01 08:27:31 -0700436 }
David Tolnay4a658402016-10-24 00:21:41 -0700437 Lit::ByteStr(ref vec, StrStyle::Raw(n)) => {
438 tokens.append(&format!("br{delim}\"{string}\"{delim}",
David Tolnay05120ef2017-03-12 18:29:26 -0700439 delim = iter::repeat("#").take(n).collect::<String>(),
440 string = str::from_utf8(vec).unwrap()));
David Tolnay4a658402016-10-24 00:21:41 -0700441 }
David Tolnay289f4c72016-10-25 00:00:09 -0700442 Lit::Byte(b) => {
443 match b {
444 0 => tokens.append(r"b'\0'"),
445 b'\"' => tokens.append("b'\"'"),
446 _ => {
447 let mut escaped = "b'".to_string();
448 escaped.extend(ascii::escape_default(b).map(|c| c as char));
449 escaped.push('\'');
450 tokens.append(&escaped);
451 }
452 }
453 }
David Tolnayf17fd2f2016-10-07 23:38:08 -0700454 Lit::Char(ch) => ch.to_tokens(tokens),
David Tolnayf4bbbd92016-09-23 14:41:55 -0700455 Lit::Int(value, ty) => tokens.append(&format!("{}{}", value, ty)),
David Tolnayf17fd2f2016-10-07 23:38:08 -0700456 Lit::Float(ref value, ty) => tokens.append(&format!("{}{}", value, ty)),
David Tolnay759d2ff2016-10-01 16:18:15 -0700457 Lit::Bool(true) => tokens.append("true"),
458 Lit::Bool(false) => tokens.append("false"),
David Tolnayf4bbbd92016-09-23 14:41:55 -0700459 }
460 }
461 }
462
463 impl Display for IntTy {
464 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
465 match *self {
466 IntTy::Isize => formatter.write_str("isize"),
467 IntTy::I8 => formatter.write_str("i8"),
468 IntTy::I16 => formatter.write_str("i16"),
469 IntTy::I32 => formatter.write_str("i32"),
470 IntTy::I64 => formatter.write_str("i64"),
471 IntTy::Usize => formatter.write_str("usize"),
472 IntTy::U8 => formatter.write_str("u8"),
473 IntTy::U16 => formatter.write_str("u16"),
474 IntTy::U32 => formatter.write_str("u32"),
475 IntTy::U64 => formatter.write_str("u64"),
476 IntTy::Unsuffixed => Ok(()),
477 }
478 }
479 }
David Tolnayf17fd2f2016-10-07 23:38:08 -0700480
481 impl Display for FloatTy {
482 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
483 match *self {
484 FloatTy::F32 => formatter.write_str("f32"),
485 FloatTy::F64 => formatter.write_str("f64"),
486 FloatTy::Unsuffixed => Ok(()),
487 }
488 }
489 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700490}