blob: a427ae8f83f15da08070ec6d05a6080e627d47ef [file] [log] [blame]
David Tolnayf4bbbd92016-09-23 14:41:55 -07001/// Literal kind.
2///
3/// E.g. `"foo"`, `42`, `12.34` or `bool`
4#[derive(Debug, Clone, Eq, PartialEq)]
5pub enum Lit {
6 /// A string literal (`"foo"`)
7 Str(String, StrStyle),
8 /// A byte string (`b"foo"`)
David Tolnay4a658402016-10-24 00:21:41 -07009 ByteStr(Vec<u8>, StrStyle),
David Tolnayf4bbbd92016-09-23 14:41:55 -070010 /// 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}
21
22#[derive(Debug, Copy, Clone, Eq, PartialEq)]
23pub enum StrStyle {
24 /// A regular string, like `"foo"`
25 Cooked,
26 /// A raw string, like `r##"foo"##`
27 ///
28 /// The uint is the number of `#` symbols used
David Tolnaydaaf7742016-10-03 11:11:43 -070029 Raw(usize),
David Tolnayf4bbbd92016-09-23 14:41:55 -070030}
31
Pascal Hertleif36342c52016-10-19 10:31:42 +020032impl From<String> for Lit {
33 fn from(input: String) -> Lit {
34 Lit::Str(input, StrStyle::Cooked)
35 }
36}
37
38impl<'a> From<&'a str> for Lit {
39 fn from(input: &str) -> Lit {
40 Lit::Str(input.into(), StrStyle::Cooked)
41 }
42}
43
44impl From<Vec<u8>> for Lit {
45 fn from(input: Vec<u8>) -> Lit {
David Tolnay4a658402016-10-24 00:21:41 -070046 Lit::ByteStr(input, StrStyle::Cooked)
Pascal Hertleif36342c52016-10-19 10:31:42 +020047 }
48}
49
50impl<'a> From<&'a [u8]> for Lit {
51 fn from(input: &[u8]) -> Lit {
David Tolnay4a658402016-10-24 00:21:41 -070052 Lit::ByteStr(input.into(), StrStyle::Cooked)
Pascal Hertleif36342c52016-10-19 10:31:42 +020053 }
54}
55
56impl From<char> for Lit {
57 fn from(input: char) -> Lit {
58 Lit::Char(input)
59 }
60}
61
62impl From<bool> for Lit {
63 fn from(input: bool) -> Lit {
64 Lit::Bool(input)
65 }
66}
67
David Tolnayf4bbbd92016-09-23 14:41:55 -070068#[derive(Debug, Copy, Clone, Eq, PartialEq)]
69pub enum IntTy {
70 Isize,
71 I8,
72 I16,
73 I32,
74 I64,
75 Usize,
76 U8,
77 U16,
78 U32,
79 U64,
David Tolnaydaaf7742016-10-03 11:11:43 -070080 Unsuffixed,
David Tolnayf4bbbd92016-09-23 14:41:55 -070081}
82
83#[derive(Debug, Copy, Clone, Eq, PartialEq)]
84pub enum FloatTy {
85 F32,
86 F64,
87 Unsuffixed,
88}
89
Pascal Hertleif36342c52016-10-19 10:31:42 +020090macro_rules! impl_from_for_lit {
91 (Int, [$($rust_type:ty => $syn_type:expr),+]) => {
92 $(
93 impl From<$rust_type> for Lit {
94 fn from(input: $rust_type) -> Lit {
95 Lit::Int(input as u64, $syn_type)
96 }
97 }
98 )+
99 };
100 (Float, [$($rust_type:ty => $syn_type:expr),+]) => {
101 $(
102 impl From<$rust_type> for Lit {
103 fn from(input: $rust_type) -> Lit {
104 Lit::Float(format!("{}", input), $syn_type)
105 }
106 }
107 )+
108 };
109}
110
111impl_from_for_lit! {Int, [
112 isize => IntTy::Isize,
113 i8 => IntTy::I8,
114 i16 => IntTy::I16,
115 i32 => IntTy::I32,
116 i64 => IntTy::I64,
117 usize => IntTy::Usize,
118 u8 => IntTy::U8,
119 u16 => IntTy::U16,
120 u32 => IntTy::U32,
121 u64 => IntTy::U64
122]}
123
124impl_from_for_lit! {Float, [
125 f32 => FloatTy::F32,
126 f64 => FloatTy::F64
127]}
128
David Tolnayf4bbbd92016-09-23 14:41:55 -0700129#[cfg(feature = "parsing")]
130pub mod parsing {
131 use super::*;
David Tolnay615cf6a2016-10-08 23:07:02 -0700132 use escape::{cooked_char, cooked_string, raw_string};
David Tolnay14cbdeb2016-10-01 12:13:59 -0700133 use space::whitespace;
David Tolnayde206222016-09-30 11:47:01 -0700134 use nom::IResult;
David Tolnay4f5f60f2016-10-24 00:52:58 -0700135 use unicode_xid::UnicodeXID;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700136
137 named!(pub lit -> Lit, alt!(
David Tolnay210884d2016-10-01 08:18:42 -0700138 string
David Tolnay56d62132016-10-01 16:14:54 -0700139 |
140 byte_string
David Tolnay615cf6a2016-10-08 23:07:02 -0700141 |
142 byte
143 |
144 character
David Tolnayf4bbbd92016-09-23 14:41:55 -0700145 |
David Tolnay4f5f60f2016-10-24 00:52:58 -0700146 float // must be before int
147 |
David Tolnayf4bbbd92016-09-23 14:41:55 -0700148 int => { |(value, ty)| Lit::Int(value, ty) }
David Tolnay759d2ff2016-10-01 16:18:15 -0700149 |
David Tolnay3ce49d02016-10-23 22:29:19 -0700150 boolean
David Tolnayf4bbbd92016-09-23 14:41:55 -0700151 ));
152
David Tolnay210884d2016-10-01 08:18:42 -0700153 named!(string -> Lit, alt!(
David Tolnay42602292016-10-01 22:25:45 -0700154 quoted_string => { |s| Lit::Str(s, StrStyle::Cooked) }
David Tolnay210884d2016-10-01 08:18:42 -0700155 |
156 preceded!(
157 punct!("r"),
158 raw_string
159 ) => { |(s, n)| Lit::Str(s, StrStyle::Raw(n)) }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700160 ));
161
David Tolnay42602292016-10-01 22:25:45 -0700162 named!(pub quoted_string -> String, delimited!(
163 punct!("\""),
164 cooked_string,
165 tag!("\"")
166 ));
167
David Tolnay56d62132016-10-01 16:14:54 -0700168 named!(byte_string -> Lit, alt!(
169 delimited!(
170 punct!("b\""),
171 cooked_string,
172 tag!("\"")
David Tolnay4a658402016-10-24 00:21:41 -0700173 ) => { |s: String| Lit::ByteStr(s.into_bytes(), StrStyle::Cooked) }
David Tolnay56d62132016-10-01 16:14:54 -0700174 |
175 preceded!(
176 punct!("br"),
177 raw_string
David Tolnay4a658402016-10-24 00:21:41 -0700178 ) => { |(s, n): (String, _)| Lit::ByteStr(s.into_bytes(), StrStyle::Raw(n)) }
David Tolnay56d62132016-10-01 16:14:54 -0700179 ));
180
David Tolnay615cf6a2016-10-08 23:07:02 -0700181 named!(byte -> Lit, do_parse!(
182 punct!("b") >>
183 tag!("'") >>
184 ch: cooked_char >>
185 tag!("'") >>
186 (Lit::Byte(ch as u8))
187 ));
188
189 named!(character -> Lit, do_parse!(
190 punct!("'") >>
191 ch: cooked_char >>
192 tag!("'") >>
193 (Lit::Char(ch))
194 ));
195
David Tolnay4f5f60f2016-10-24 00:52:58 -0700196 named!(float -> Lit, do_parse!(
197 option!(whitespace) >>
198 value: float_string >>
199 suffix: alt!(
200 tag!("f32") => { |_| FloatTy::F32 }
201 |
202 tag!("f64") => { |_| FloatTy::F64 }
203 |
204 epsilon!() => { |_| FloatTy::Unsuffixed }
205 ) >>
206 (Lit::Float(value, suffix))
207 ));
208
David Tolnayde206222016-09-30 11:47:01 -0700209 named!(pub int -> (u64, IntTy), tuple!(
David Tolnay14cbdeb2016-10-01 12:13:59 -0700210 preceded!(
211 option!(whitespace),
212 digits
213 ),
David Tolnayde206222016-09-30 11:47:01 -0700214 alt!(
215 tag!("isize") => { |_| IntTy::Isize }
216 |
217 tag!("i8") => { |_| IntTy::I8 }
218 |
219 tag!("i16") => { |_| IntTy::I16 }
220 |
221 tag!("i32") => { |_| IntTy::I32 }
222 |
223 tag!("i64") => { |_| IntTy::I64 }
224 |
225 tag!("usize") => { |_| IntTy::Usize }
226 |
227 tag!("u8") => { |_| IntTy::U8 }
228 |
229 tag!("u16") => { |_| IntTy::U16 }
230 |
231 tag!("u32") => { |_| IntTy::U32 }
232 |
233 tag!("u64") => { |_| IntTy::U64 }
234 |
235 epsilon!() => { |_| IntTy::Unsuffixed }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700236 )
237 ));
238
David Tolnay3ce49d02016-10-23 22:29:19 -0700239 named!(boolean -> Lit, alt!(
240 keyword!("true") => { |_| Lit::Bool(true) }
241 |
242 keyword!("false") => { |_| Lit::Bool(false) }
243 ));
244
David Tolnay4f5f60f2016-10-24 00:52:58 -0700245 fn float_string(input: &str) -> IResult<&str, String> {
246 let mut chars = input.chars().peekable();
247 match chars.next() {
248 Some(ch) if ch >= '0' && ch <= '9' => {}
249 _ => return IResult::Error,
250 }
251
252 let mut len = 1;
253 let mut has_dot = false;
254 let mut has_exp = false;
255 while let Some(&ch) = chars.peek() {
256 match ch {
257 '0'...'9' | '_' => {
258 chars.next();
259 len += 1;
260 }
261 '.' => {
262 if has_dot {
263 break;
264 }
265 chars.next();
266 if chars.peek()
267 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
268 .unwrap_or(false) {
269 return IResult::Error;
270 }
271 len += 1;
272 has_dot = true;
273 }
274 'e' | 'E' => {
275 chars.next();
276 len += 1;
277 has_exp = true;
278 break;
279 }
280 _ => break,
281 }
282 }
283
284 let rest = &input[len..];
285 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
286 return IResult::Error;
287 }
288
289 if has_exp {
290 let mut has_exp_value = false;
291 while let Some(&ch) = chars.peek() {
292 match ch {
293 '+' | '-' => {
294 if has_exp_value {
295 break;
296 }
297 chars.next();
298 len += 1;
299 }
300 '0'...'9' => {
301 chars.next();
302 len += 1;
303 has_exp_value = true;
304 }
305 '_' => {
306 chars.next();
307 len += 1;
308 }
309 _ => break,
310 }
311 }
312 if !has_exp_value {
313 return IResult::Error;
314 }
315 }
316
317 IResult::Done(&input[len..], input[..len].into())
318 }
319
David Tolnayde206222016-09-30 11:47:01 -0700320 pub fn digits(input: &str) -> IResult<&str, u64> {
David Tolnayf4bbbd92016-09-23 14:41:55 -0700321 let mut value = 0u64;
322 let mut len = 0;
323 let mut bytes = input.bytes().peekable();
324 while let Some(&b) = bytes.peek() {
325 match b {
David Tolnaydaaf7742016-10-03 11:11:43 -0700326 b'0'...b'9' => {
David Tolnayf4bbbd92016-09-23 14:41:55 -0700327 value = match value.checked_mul(10) {
328 Some(value) => value,
329 None => return IResult::Error,
330 };
331 value = match value.checked_add((b - b'0') as u64) {
332 Some(value) => value,
333 None => return IResult::Error,
334 };
335 bytes.next();
336 len += 1;
337 }
David Tolnayfa0edf22016-09-23 22:58:24 -0700338 _ => break,
David Tolnayf4bbbd92016-09-23 14:41:55 -0700339 }
340 }
David Tolnayfa0edf22016-09-23 22:58:24 -0700341 if len > 0 {
342 IResult::Done(&input[len..], value)
343 } else {
344 IResult::Error
345 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700346 }
347}
348
349#[cfg(feature = "printing")]
350mod printing {
351 use super::*;
352 use quote::{Tokens, ToTokens};
David Tolnay56d62132016-10-01 16:14:54 -0700353 use std::{ascii, iter};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700354 use std::fmt::{self, Display};
David Tolnay4a658402016-10-24 00:21:41 -0700355 use std::str;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700356
357 impl ToTokens for Lit {
358 fn to_tokens(&self, tokens: &mut Tokens) {
359 match *self {
360 Lit::Str(ref s, StrStyle::Cooked) => s.to_tokens(tokens),
David Tolnay627e3d52016-10-01 08:27:31 -0700361 Lit::Str(ref s, StrStyle::Raw(n)) => {
David Tolnay56d62132016-10-01 16:14:54 -0700362 tokens.append(&format!("r{delim}\"{string}\"{delim}",
363 delim = iter::repeat("#").take(n).collect::<String>(),
364 string = s));
365 }
David Tolnay4a658402016-10-24 00:21:41 -0700366 Lit::ByteStr(ref v, StrStyle::Cooked) => {
David Tolnay56d62132016-10-01 16:14:54 -0700367 let mut escaped = "b\"".to_string();
368 for &ch in v.iter() {
369 escaped.extend(ascii::escape_default(ch).map(|c| c as char));
David Tolnay627e3d52016-10-01 08:27:31 -0700370 }
David Tolnay56d62132016-10-01 16:14:54 -0700371 escaped.push('"');
372 tokens.append(&escaped);
David Tolnay627e3d52016-10-01 08:27:31 -0700373 }
David Tolnay4a658402016-10-24 00:21:41 -0700374 Lit::ByteStr(ref vec, StrStyle::Raw(n)) => {
375 tokens.append(&format!("br{delim}\"{string}\"{delim}",
376 delim = iter::repeat("#").take(n).collect::<String>(),
377 string = str::from_utf8(vec).unwrap()));
378 }
David Tolnay615cf6a2016-10-08 23:07:02 -0700379 Lit::Byte(b) => tokens.append(&format!("b{:?}", b as char)),
David Tolnayf17fd2f2016-10-07 23:38:08 -0700380 Lit::Char(ch) => ch.to_tokens(tokens),
David Tolnayf4bbbd92016-09-23 14:41:55 -0700381 Lit::Int(value, ty) => tokens.append(&format!("{}{}", value, ty)),
David Tolnayf17fd2f2016-10-07 23:38:08 -0700382 Lit::Float(ref value, ty) => tokens.append(&format!("{}{}", value, ty)),
David Tolnay759d2ff2016-10-01 16:18:15 -0700383 Lit::Bool(true) => tokens.append("true"),
384 Lit::Bool(false) => tokens.append("false"),
David Tolnayf4bbbd92016-09-23 14:41:55 -0700385 }
386 }
387 }
388
389 impl Display for IntTy {
390 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
391 match *self {
392 IntTy::Isize => formatter.write_str("isize"),
393 IntTy::I8 => formatter.write_str("i8"),
394 IntTy::I16 => formatter.write_str("i16"),
395 IntTy::I32 => formatter.write_str("i32"),
396 IntTy::I64 => formatter.write_str("i64"),
397 IntTy::Usize => formatter.write_str("usize"),
398 IntTy::U8 => formatter.write_str("u8"),
399 IntTy::U16 => formatter.write_str("u16"),
400 IntTy::U32 => formatter.write_str("u32"),
401 IntTy::U64 => formatter.write_str("u64"),
402 IntTy::Unsuffixed => Ok(()),
403 }
404 }
405 }
David Tolnayf17fd2f2016-10-07 23:38:08 -0700406
407 impl Display for FloatTy {
408 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
409 match *self {
410 FloatTy::F32 => formatter.write_str("f32"),
411 FloatTy::F64 => formatter.write_str("f64"),
412 FloatTy::Unsuffixed => Ok(()),
413 }
414 }
415 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700416}