blob: 72a2f43a806a08fd4eebbd47d07ef0838d983b39 [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`
Alex Crichton2e0229c2017-05-23 09:34:50 -07005 #[cfg_attr(not(feature = "clone-impls"), derive(Clone))]
Alex Crichton62a0a592017-05-22 13:58:53 -07006 pub enum Lit {
7 /// A string literal (`"foo"`)
8 Str(String, StrStyle),
9 /// A byte string (`b"foo"`)
10 ByteStr(Vec<u8>, StrStyle),
11 /// A byte char (`b'f'`)
12 Byte(u8),
13 /// A character literal (`'a'`)
14 Char(char),
15 /// An integer literal (`1`)
16 Int(u64, IntTy),
17 /// A float literal (`1f64` or `1E10f64` or `1.0E10`)
18 Float(String, FloatTy),
19 /// A boolean literal
20 Bool(bool),
21 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070022}
23
Alex Crichton62a0a592017-05-22 13:58:53 -070024ast_enum! {
Alex Crichton2e0229c2017-05-23 09:34:50 -070025 #[cfg_attr(not(feature = "clone-impls"), derive(Clone))]
Alex Crichton62a0a592017-05-22 13:58:53 -070026 pub enum StrStyle {
27 /// A regular string, like `"foo"`
28 Cooked,
29 /// A raw string, like `r##"foo"##`
30 ///
31 /// The uint is the number of `#` symbols used
32 Raw(usize),
33 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070034}
35
Pascal Hertleif36342c52016-10-19 10:31:42 +020036impl From<String> for Lit {
37 fn from(input: String) -> Lit {
38 Lit::Str(input, StrStyle::Cooked)
39 }
40}
41
42impl<'a> From<&'a str> for Lit {
43 fn from(input: &str) -> Lit {
44 Lit::Str(input.into(), StrStyle::Cooked)
45 }
46}
47
48impl From<Vec<u8>> for Lit {
49 fn from(input: Vec<u8>) -> Lit {
David Tolnay4a658402016-10-24 00:21:41 -070050 Lit::ByteStr(input, StrStyle::Cooked)
Pascal Hertleif36342c52016-10-19 10:31:42 +020051 }
52}
53
54impl<'a> From<&'a [u8]> for Lit {
55 fn from(input: &[u8]) -> Lit {
David Tolnay4a658402016-10-24 00:21:41 -070056 Lit::ByteStr(input.into(), StrStyle::Cooked)
Pascal Hertleif36342c52016-10-19 10:31:42 +020057 }
58}
59
60impl From<char> for Lit {
61 fn from(input: char) -> Lit {
62 Lit::Char(input)
63 }
64}
65
66impl From<bool> for Lit {
67 fn from(input: bool) -> Lit {
68 Lit::Bool(input)
69 }
70}
71
Alex Crichton62a0a592017-05-22 13:58:53 -070072ast_enum! {
73 #[derive(Copy)]
Alex Crichton2e0229c2017-05-23 09:34:50 -070074 #[cfg_attr(not(feature = "clone-impls"), derive(Clone))]
Alex Crichton62a0a592017-05-22 13:58:53 -070075 pub enum IntTy {
76 Isize,
77 I8,
78 I16,
79 I32,
80 I64,
81 Usize,
82 U8,
83 U16,
84 U32,
85 U64,
86 Unsuffixed,
87 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070088}
89
Alex Crichton62a0a592017-05-22 13:58:53 -070090ast_enum! {
91 #[derive(Copy)]
Alex Crichton2e0229c2017-05-23 09:34:50 -070092 #[cfg_attr(not(feature = "clone-impls"), derive(Clone))]
Alex Crichton62a0a592017-05-22 13:58:53 -070093 pub enum FloatTy {
94 F32,
95 F64,
96 Unsuffixed,
97 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070098}
99
Pascal Hertleif36342c52016-10-19 10:31:42 +0200100macro_rules! impl_from_for_lit {
101 (Int, [$($rust_type:ty => $syn_type:expr),+]) => {
102 $(
103 impl From<$rust_type> for Lit {
104 fn from(input: $rust_type) -> Lit {
105 Lit::Int(input as u64, $syn_type)
106 }
107 }
108 )+
109 };
110 (Float, [$($rust_type:ty => $syn_type:expr),+]) => {
111 $(
112 impl From<$rust_type> for Lit {
113 fn from(input: $rust_type) -> Lit {
114 Lit::Float(format!("{}", input), $syn_type)
115 }
116 }
117 )+
118 };
119}
120
121impl_from_for_lit! {Int, [
122 isize => IntTy::Isize,
123 i8 => IntTy::I8,
124 i16 => IntTy::I16,
125 i32 => IntTy::I32,
126 i64 => IntTy::I64,
127 usize => IntTy::Usize,
128 u8 => IntTy::U8,
129 u16 => IntTy::U16,
130 u32 => IntTy::U32,
131 u64 => IntTy::U64
132]}
133
134impl_from_for_lit! {Float, [
135 f32 => FloatTy::F32,
136 f64 => FloatTy::F64
137]}
138
David Tolnayf4bbbd92016-09-23 14:41:55 -0700139#[cfg(feature = "parsing")]
Alex Crichton2e0229c2017-05-23 09:34:50 -0700140ast_struct! {
141 pub struct StrLit {
142 pub value: String,
143 pub style: StrStyle,
144 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800145}
146
147#[cfg(feature = "parsing")]
Alex Crichton2e0229c2017-05-23 09:34:50 -0700148ast_struct! {
149 pub struct ByteStrLit {
150 pub value: Vec<u8>,
151 pub style: StrStyle,
152 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800153}
154
155#[cfg(feature = "parsing")]
Alex Crichton2e0229c2017-05-23 09:34:50 -0700156ast_struct! {
157 pub struct IntLit {
158 pub value: u64,
159 pub suffix: IntTy,
160 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800161}
162
163#[cfg(feature = "parsing")]
Alex Crichton2e0229c2017-05-23 09:34:50 -0700164ast_struct! {
165 pub struct FloatLit {
166 pub value: String,
167 pub suffix: FloatTy,
168 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800169}
170
171#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700172pub mod parsing {
173 use super::*;
David Tolnayfe373a32016-10-26 23:51:19 -0700174 use escape::{cooked_byte, cooked_byte_string, cooked_char, cooked_string, raw_string};
David Tolnay5fe14fc2017-01-27 16:22:08 -0800175 use synom::space::skip_whitespace;
176 use synom::IResult;
David Tolnay4f5f60f2016-10-24 00:52:58 -0700177 use unicode_xid::UnicodeXID;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700178
179 named!(pub lit -> Lit, alt!(
David Tolnay5fe14fc2017-01-27 16:22:08 -0800180 string => { |StrLit { value, style }| Lit::Str(value, style) }
David Tolnay56d62132016-10-01 16:14:54 -0700181 |
David Tolnay5fe14fc2017-01-27 16:22:08 -0800182 byte_string => { |ByteStrLit { value, style }| Lit::ByteStr(value, style) }
David Tolnay615cf6a2016-10-08 23:07:02 -0700183 |
Michael Layzell5e107ff2017-01-24 19:58:39 -0500184 byte => { |b| Lit::Byte(b) }
David Tolnay615cf6a2016-10-08 23:07:02 -0700185 |
Michael Layzell5e107ff2017-01-24 19:58:39 -0500186 character => { |ch| Lit::Char(ch) }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700187 |
David Tolnay5fe14fc2017-01-27 16:22:08 -0800188 float => { |FloatLit { value, suffix }| Lit::Float(value, suffix) } // must be before int
David Tolnay4f5f60f2016-10-24 00:52:58 -0700189 |
David Tolnay5fe14fc2017-01-27 16:22:08 -0800190 int => { |IntLit { value, suffix }| Lit::Int(value, suffix) }
David Tolnay759d2ff2016-10-01 16:18:15 -0700191 |
Michael Layzell5e107ff2017-01-24 19:58:39 -0500192 boolean => { |value| Lit::Bool(value) }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700193 ));
194
David Tolnay5fe14fc2017-01-27 16:22:08 -0800195 named!(pub string -> StrLit, alt!(
196 quoted_string => { |s| StrLit { value: s, style: StrStyle::Cooked } }
David Tolnay210884d2016-10-01 08:18:42 -0700197 |
198 preceded!(
199 punct!("r"),
200 raw_string
David Tolnay5fe14fc2017-01-27 16:22:08 -0800201 ) => { |(s, n)| StrLit { value: s, style: StrStyle::Raw(n) }}
David Tolnayf4bbbd92016-09-23 14:41:55 -0700202 ));
203
David Tolnay42602292016-10-01 22:25:45 -0700204 named!(pub quoted_string -> String, delimited!(
205 punct!("\""),
206 cooked_string,
207 tag!("\"")
208 ));
209
David Tolnay5fe14fc2017-01-27 16:22:08 -0800210 named!(pub byte_string -> ByteStrLit, alt!(
David Tolnay56d62132016-10-01 16:14:54 -0700211 delimited!(
212 punct!("b\""),
David Tolnaya73e0f02016-10-26 23:25:49 -0700213 cooked_byte_string,
David Tolnay56d62132016-10-01 16:14:54 -0700214 tag!("\"")
David Tolnay5fe14fc2017-01-27 16:22:08 -0800215 ) => { |vec| ByteStrLit { value: vec, style: StrStyle::Cooked } }
David Tolnay56d62132016-10-01 16:14:54 -0700216 |
217 preceded!(
218 punct!("br"),
219 raw_string
David Tolnay5fe14fc2017-01-27 16:22:08 -0800220 ) => { |(s, n): (String, _)| ByteStrLit { value: s.into_bytes(), style: StrStyle::Raw(n) } }
David Tolnay56d62132016-10-01 16:14:54 -0700221 ));
222
Michael Layzell5e107ff2017-01-24 19:58:39 -0500223 named!(pub byte -> u8, do_parse!(
David Tolnay615cf6a2016-10-08 23:07:02 -0700224 punct!("b") >>
225 tag!("'") >>
David Tolnayfe373a32016-10-26 23:51:19 -0700226 b: cooked_byte >>
David Tolnay615cf6a2016-10-08 23:07:02 -0700227 tag!("'") >>
Michael Layzell5e107ff2017-01-24 19:58:39 -0500228 (b)
David Tolnay615cf6a2016-10-08 23:07:02 -0700229 ));
230
Michael Layzell5e107ff2017-01-24 19:58:39 -0500231 named!(pub character -> char, do_parse!(
David Tolnay615cf6a2016-10-08 23:07:02 -0700232 punct!("'") >>
233 ch: cooked_char >>
234 tag!("'") >>
Michael Layzell5e107ff2017-01-24 19:58:39 -0500235 (ch)
David Tolnay615cf6a2016-10-08 23:07:02 -0700236 ));
237
David Tolnay5fe14fc2017-01-27 16:22:08 -0800238 named!(pub float -> FloatLit, do_parse!(
239 value: float_string >>
240 suffix: alt!(
David Tolnay4f5f60f2016-10-24 00:52:58 -0700241 tag!("f32") => { |_| FloatTy::F32 }
242 |
243 tag!("f64") => { |_| FloatTy::F64 }
244 |
245 epsilon!() => { |_| FloatTy::Unsuffixed }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800246 ) >>
247 (FloatLit { value: value, suffix: suffix })
David Tolnay4f5f60f2016-10-24 00:52:58 -0700248 ));
249
David Tolnay5fe14fc2017-01-27 16:22:08 -0800250 named!(pub int -> IntLit, do_parse!(
251 value: digits >>
252 suffix: alt!(
David Tolnayde206222016-09-30 11:47:01 -0700253 tag!("isize") => { |_| IntTy::Isize }
254 |
255 tag!("i8") => { |_| IntTy::I8 }
256 |
257 tag!("i16") => { |_| IntTy::I16 }
258 |
259 tag!("i32") => { |_| IntTy::I32 }
260 |
261 tag!("i64") => { |_| IntTy::I64 }
262 |
263 tag!("usize") => { |_| IntTy::Usize }
264 |
265 tag!("u8") => { |_| IntTy::U8 }
266 |
267 tag!("u16") => { |_| IntTy::U16 }
268 |
269 tag!("u32") => { |_| IntTy::U32 }
270 |
271 tag!("u64") => { |_| IntTy::U64 }
272 |
273 epsilon!() => { |_| IntTy::Unsuffixed }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800274 ) >>
275 (IntLit { value: value, suffix: suffix })
David Tolnayf4bbbd92016-09-23 14:41:55 -0700276 ));
277
Michael Layzell5e107ff2017-01-24 19:58:39 -0500278 named!(pub boolean -> bool, alt!(
279 keyword!("true") => { |_| true }
David Tolnay3ce49d02016-10-23 22:29:19 -0700280 |
Michael Layzell5e107ff2017-01-24 19:58:39 -0500281 keyword!("false") => { |_| false }
David Tolnay3ce49d02016-10-23 22:29:19 -0700282 ));
283
David Tolnaydef66372016-10-24 21:51:32 -0700284 fn float_string(mut input: &str) -> IResult<&str, String> {
285 input = skip_whitespace(input);
286
David Tolnay4f5f60f2016-10-24 00:52:58 -0700287 let mut chars = input.chars().peekable();
288 match chars.next() {
289 Some(ch) if ch >= '0' && ch <= '9' => {}
290 _ => return IResult::Error,
291 }
292
293 let mut len = 1;
294 let mut has_dot = false;
295 let mut has_exp = false;
296 while let Some(&ch) = chars.peek() {
297 match ch {
298 '0'...'9' | '_' => {
299 chars.next();
300 len += 1;
301 }
302 '.' => {
303 if has_dot {
304 break;
305 }
306 chars.next();
307 if chars.peek()
David Tolnay05120ef2017-03-12 18:29:26 -0700308 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
309 .unwrap_or(false) {
David Tolnay4f5f60f2016-10-24 00:52:58 -0700310 return IResult::Error;
311 }
312 len += 1;
313 has_dot = true;
314 }
315 'e' | 'E' => {
316 chars.next();
317 len += 1;
318 has_exp = true;
319 break;
320 }
321 _ => break,
322 }
323 }
324
325 let rest = &input[len..];
326 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
327 return IResult::Error;
328 }
329
330 if has_exp {
331 let mut has_exp_value = false;
332 while let Some(&ch) = chars.peek() {
333 match ch {
334 '+' | '-' => {
335 if has_exp_value {
336 break;
337 }
338 chars.next();
339 len += 1;
340 }
341 '0'...'9' => {
342 chars.next();
343 len += 1;
344 has_exp_value = true;
345 }
346 '_' => {
347 chars.next();
348 len += 1;
349 }
350 _ => break,
351 }
352 }
353 if !has_exp_value {
354 return IResult::Error;
355 }
356 }
357
David Tolnayc7b636a2016-10-24 13:01:08 -0700358 IResult::Done(&input[len..], input[..len].replace("_", ""))
David Tolnay4f5f60f2016-10-24 00:52:58 -0700359 }
360
David Tolnay8a19e6d2016-10-24 01:23:40 -0700361 pub fn digits(mut input: &str) -> IResult<&str, u64> {
David Tolnaydef66372016-10-24 21:51:32 -0700362 input = skip_whitespace(input);
363
David Tolnay8a19e6d2016-10-24 01:23:40 -0700364 let base = if input.starts_with("0x") {
365 input = &input[2..];
366 16
367 } else if input.starts_with("0o") {
368 input = &input[2..];
369 8
370 } else if input.starts_with("0b") {
371 input = &input[2..];
372 2
373 } else {
374 10
375 };
376
David Tolnayf4bbbd92016-09-23 14:41:55 -0700377 let mut value = 0u64;
378 let mut len = 0;
David Tolnay24b5ff72016-10-24 01:05:05 -0700379 let mut empty = true;
380 for b in input.bytes() {
David Tolnay8a19e6d2016-10-24 01:23:40 -0700381 let digit = match b {
382 b'0'...b'9' => (b - b'0') as u64,
383 b'a'...b'f' => 10 + (b - b'a') as u64,
384 b'A'...b'F' => 10 + (b - b'A') as u64,
David Tolnay24b5ff72016-10-24 01:05:05 -0700385 b'_' => {
David Tolnayc814a762016-10-27 23:11:28 -0700386 if empty && base == 10 {
David Tolnay24b5ff72016-10-24 01:05:05 -0700387 return IResult::Error;
388 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700389 len += 1;
David Tolnay8a19e6d2016-10-24 01:23:40 -0700390 continue;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700391 }
David Tolnayfa0edf22016-09-23 22:58:24 -0700392 _ => break,
David Tolnay8a19e6d2016-10-24 01:23:40 -0700393 };
394 if digit >= base {
395 return IResult::Error;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700396 }
David Tolnay8a19e6d2016-10-24 01:23:40 -0700397 value = match value.checked_mul(base) {
398 Some(value) => value,
399 None => return IResult::Error,
400 };
401 value = match value.checked_add(digit) {
402 Some(value) => value,
403 None => return IResult::Error,
404 };
405 len += 1;
406 empty = false;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700407 }
David Tolnay24b5ff72016-10-24 01:05:05 -0700408 if empty {
David Tolnayfa0edf22016-09-23 22:58:24 -0700409 IResult::Error
David Tolnay24b5ff72016-10-24 01:05:05 -0700410 } else {
411 IResult::Done(&input[len..], value)
David Tolnayfa0edf22016-09-23 22:58:24 -0700412 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700413 }
414}
415
416#[cfg(feature = "printing")]
417mod printing {
418 use super::*;
419 use quote::{Tokens, ToTokens};
David Tolnay56d62132016-10-01 16:14:54 -0700420 use std::{ascii, iter};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700421 use std::fmt::{self, Display};
David Tolnay4a658402016-10-24 00:21:41 -0700422 use std::str;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700423
424 impl ToTokens for Lit {
425 fn to_tokens(&self, tokens: &mut Tokens) {
426 match *self {
427 Lit::Str(ref s, StrStyle::Cooked) => s.to_tokens(tokens),
David Tolnay627e3d52016-10-01 08:27:31 -0700428 Lit::Str(ref s, StrStyle::Raw(n)) => {
David Tolnay56d62132016-10-01 16:14:54 -0700429 tokens.append(&format!("r{delim}\"{string}\"{delim}",
David Tolnay05120ef2017-03-12 18:29:26 -0700430 delim = iter::repeat("#").take(n).collect::<String>(),
431 string = s));
David Tolnay56d62132016-10-01 16:14:54 -0700432 }
David Tolnay4a658402016-10-24 00:21:41 -0700433 Lit::ByteStr(ref v, StrStyle::Cooked) => {
David Tolnay56d62132016-10-01 16:14:54 -0700434 let mut escaped = "b\"".to_string();
435 for &ch in v.iter() {
David Tolnay289f4c72016-10-25 00:00:09 -0700436 match ch {
437 0 => escaped.push_str(r"\0"),
438 b'\'' => escaped.push('\''),
439 _ => escaped.extend(ascii::escape_default(ch).map(|c| c as char)),
440 }
David Tolnay627e3d52016-10-01 08:27:31 -0700441 }
David Tolnay56d62132016-10-01 16:14:54 -0700442 escaped.push('"');
443 tokens.append(&escaped);
David Tolnay627e3d52016-10-01 08:27:31 -0700444 }
David Tolnay4a658402016-10-24 00:21:41 -0700445 Lit::ByteStr(ref vec, StrStyle::Raw(n)) => {
446 tokens.append(&format!("br{delim}\"{string}\"{delim}",
David Tolnay05120ef2017-03-12 18:29:26 -0700447 delim = iter::repeat("#").take(n).collect::<String>(),
448 string = str::from_utf8(vec).unwrap()));
David Tolnay4a658402016-10-24 00:21:41 -0700449 }
David Tolnay289f4c72016-10-25 00:00:09 -0700450 Lit::Byte(b) => {
451 match b {
452 0 => tokens.append(r"b'\0'"),
453 b'\"' => tokens.append("b'\"'"),
454 _ => {
455 let mut escaped = "b'".to_string();
456 escaped.extend(ascii::escape_default(b).map(|c| c as char));
457 escaped.push('\'');
458 tokens.append(&escaped);
459 }
460 }
461 }
David Tolnayf17fd2f2016-10-07 23:38:08 -0700462 Lit::Char(ch) => ch.to_tokens(tokens),
David Tolnayf4bbbd92016-09-23 14:41:55 -0700463 Lit::Int(value, ty) => tokens.append(&format!("{}{}", value, ty)),
David Tolnayf17fd2f2016-10-07 23:38:08 -0700464 Lit::Float(ref value, ty) => tokens.append(&format!("{}{}", value, ty)),
David Tolnay759d2ff2016-10-01 16:18:15 -0700465 Lit::Bool(true) => tokens.append("true"),
466 Lit::Bool(false) => tokens.append("false"),
David Tolnayf4bbbd92016-09-23 14:41:55 -0700467 }
468 }
469 }
470
471 impl Display for IntTy {
472 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
473 match *self {
474 IntTy::Isize => formatter.write_str("isize"),
475 IntTy::I8 => formatter.write_str("i8"),
476 IntTy::I16 => formatter.write_str("i16"),
477 IntTy::I32 => formatter.write_str("i32"),
478 IntTy::I64 => formatter.write_str("i64"),
479 IntTy::Usize => formatter.write_str("usize"),
480 IntTy::U8 => formatter.write_str("u8"),
481 IntTy::U16 => formatter.write_str("u16"),
482 IntTy::U32 => formatter.write_str("u32"),
483 IntTy::U64 => formatter.write_str("u64"),
484 IntTy::Unsuffixed => Ok(()),
485 }
486 }
487 }
David Tolnayf17fd2f2016-10-07 23:38:08 -0700488
489 impl Display for FloatTy {
490 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
491 match *self {
492 FloatTy::F32 => formatter.write_str("f32"),
493 FloatTy::F64 => formatter.write_str("f64"),
494 FloatTy::Unsuffixed => Ok(()),
495 }
496 }
497 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700498}