blob: 4aeec282b0ca8cb11473c3aed9c0c7fa86ac9acf [file] [log] [blame]
David Tolnayf4bbbd92016-09-23 14:41:55 -07001/// Literal kind.
2///
3/// E.g. `"foo"`, `42`, `12.34` or `bool`
David Tolnay9bf4af82017-01-07 11:17:46 -08004#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayf4bbbd92016-09-23 14:41:55 -07005pub 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
David Tolnay9bf4af82017-01-07 11:17:46 -080022#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
David Tolnayf4bbbd92016-09-23 14:41:55 -070023pub 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 Tolnay9bf4af82017-01-07 11:17:46 -080068#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
David Tolnayf4bbbd92016-09-23 14:41:55 -070069pub 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
David Tolnay9bf4af82017-01-07 11:17:46 -080083#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
David Tolnayf4bbbd92016-09-23 14:41:55 -070084pub 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")]
David Tolnay5fe14fc2017-01-27 16:22:08 -0800130#[derive(Debug, Clone)]
131pub struct StrLit {
Michael Layzell93336812017-01-28 16:16:15 -0500132 pub value: String,
133 pub style: StrStyle,
David Tolnay5fe14fc2017-01-27 16:22:08 -0800134}
135
136#[cfg(feature = "parsing")]
137#[derive(Debug, Clone)]
138pub struct ByteStrLit {
Michael Layzell93336812017-01-28 16:16:15 -0500139 pub value: Vec<u8>,
140 pub style: StrStyle,
David Tolnay5fe14fc2017-01-27 16:22:08 -0800141}
142
143#[cfg(feature = "parsing")]
144#[derive(Debug, Clone)]
145pub struct IntLit {
Michael Layzell93336812017-01-28 16:16:15 -0500146 pub value: u64,
147 pub suffix: IntTy,
David Tolnay5fe14fc2017-01-27 16:22:08 -0800148}
149
150#[cfg(feature = "parsing")]
151#[derive(Debug, Clone)]
152pub struct FloatLit {
Michael Layzell93336812017-01-28 16:16:15 -0500153 pub value: String,
154 pub suffix: FloatTy,
David Tolnay5fe14fc2017-01-27 16:22:08 -0800155}
156
157#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700158pub mod parsing {
159 use super::*;
Michael Layzell416724e2017-05-24 21:12:34 -0400160 use synom::{IResult, TokenTree, TokenKind};
161 use relex;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700162
Michael Layzell416724e2017-05-24 21:12:34 -0400163 pub fn lit(i: &[TokenTree]) -> IResult<&[TokenTree], Lit> {
164 match i.first() {
165 Some(&TokenTree{ kind: TokenKind::Literal(ref l), .. }) => {
166 // XXX: I'm using my lexer for this temporarially, as it makes
167 // my life easier. A final version shouldn't be this hacky,
168 // though we'll probably want `proc_macro::Literal` -> actual
169 // literal value conversions to be in a separate crate, rather
170 // than requiring syn (which seems a bit heavyweight for that).
171 let tok = if let Ok(tok) = relex::relex_literal(&l.to_string()) {
172 tok
173 } else {
174 return IResult::Error
175 };
176 let lit = match tok {
177 relex::LToken::Lit(relex::Lit::Byte(b)) => {
178 Lit::Byte(b)
David Tolnay4f5f60f2016-10-24 00:52:58 -0700179 }
Michael Layzell416724e2017-05-24 21:12:34 -0400180 relex::LToken::Lit(relex::Lit::Char(c)) => {
181 Lit::Char(c)
David Tolnay4f5f60f2016-10-24 00:52:58 -0700182 }
Michael Layzell416724e2017-05-24 21:12:34 -0400183 relex::LToken::Lit(relex::Lit::Integer(v, suffix)) => {
184 let suffix = match suffix {
185 relex::IntSuffix::Unsuffixed =>
186 IntTy::Unsuffixed,
187 relex::IntSuffix::Isize =>
188 IntTy::Isize,
189 relex::IntSuffix::Usize =>
190 IntTy::Usize,
191 relex::IntSuffix::I8 =>
192 IntTy::I8,
193 relex::IntSuffix::U8 =>
194 IntTy::U8,
195 relex::IntSuffix::I16 =>
196 IntTy::I16,
197 relex::IntSuffix::U16 =>
198 IntTy::U16,
199 relex::IntSuffix::I32 =>
200 IntTy::I32,
201 relex::IntSuffix::U32 =>
202 IntTy::U32,
203 relex::IntSuffix::I64 =>
204 IntTy::I64,
205 relex::IntSuffix::U64 =>
206 IntTy::U64,
207 };
208 Lit::Int(v, suffix)
209 }
210 relex::LToken::Lit(relex::Lit::Float(v, suffix)) => {
211 let suffix = match suffix {
212 relex::FloatSuffix::Unsuffixed =>
213 FloatTy::Unsuffixed,
214 relex::FloatSuffix::F32 =>
215 FloatTy::F32,
216 relex::FloatSuffix::F64 =>
217 FloatTy::F64,
218 };
219 Lit::Float(v, suffix)
220 }
221 relex::LToken::Lit(relex::Lit::Str(s, relex::StrStyle::Cooked)) => {
222 Lit::Str(s, StrStyle::Cooked)
223 }
224 relex::LToken::Lit(relex::Lit::Str(s, relex::StrStyle::Raw(n))) => {
225 Lit::Str(s, StrStyle::Raw(n))
226 }
227 relex::LToken::Lit(relex::Lit::ByteStr(s, relex::StrStyle::Cooked)) => {
228 Lit::ByteStr(s, StrStyle::Cooked)
229 }
230 relex::LToken::Lit(relex::Lit::ByteStr(s, relex::StrStyle::Raw(n))) => {
231 Lit::ByteStr(s, StrStyle::Raw(n))
232 }
233 _ => return IResult::Error
234 };
235
236 IResult::Done(&i[1..], lit)
David Tolnay4f5f60f2016-10-24 00:52:58 -0700237 }
Michael Layzell416724e2017-05-24 21:12:34 -0400238 Some(&TokenTree{ kind: TokenKind::Word(ref w), .. }) => {
239 if &**w == "true" {
240 IResult::Done(&i[1..], Lit::Bool(true))
241 } else if &**w == "false" {
242 IResult::Done(&i[1..], Lit::Bool(false))
243 } else {
244 IResult::Error
David Tolnay4f5f60f2016-10-24 00:52:58 -0700245 }
246 }
Michael Layzell416724e2017-05-24 21:12:34 -0400247 _ => IResult::Error
David Tolnay4f5f60f2016-10-24 00:52:58 -0700248 }
David Tolnay4f5f60f2016-10-24 00:52:58 -0700249 }
250
Michael Layzell416724e2017-05-24 21:12:34 -0400251 #[cfg(feature = "full")]
252 pub fn digits(i: &[TokenTree]) -> IResult<&[TokenTree], u64> {
253 if let IResult::Done(r, Lit::Int(v, IntTy::Unsuffixed)) = lit(i) {
254 IResult::Done(r, v)
David Tolnay8a19e6d2016-10-24 01:23:40 -0700255 } else {
David Tolnayfa0edf22016-09-23 22:58:24 -0700256 IResult::Error
Michael Layzell416724e2017-05-24 21:12:34 -0400257 }
258 }
259
260 pub fn string(i: &[TokenTree]) -> IResult<&[TokenTree], String> {
261 if let IResult::Done(r, Lit::Str(v, _)) = lit(i) {
262 IResult::Done(r, v)
David Tolnay24b5ff72016-10-24 01:05:05 -0700263 } else {
Michael Layzell416724e2017-05-24 21:12:34 -0400264 IResult::Error
265 }
266 }
267
268 pub fn byte_string(i: &[TokenTree]) -> IResult<&[TokenTree], Vec<u8>> {
269 if let IResult::Done(r, Lit::ByteStr(v, _)) = lit(i) {
270 IResult::Done(r, v)
271 } else {
272 IResult::Error
273 }
274 }
275
276 pub fn byte(i: &[TokenTree]) -> IResult<&[TokenTree], u8> {
277 if let IResult::Done(r, Lit::Byte(b)) = lit(i) {
278 IResult::Done(r, b)
279 } else {
280 IResult::Error
281 }
282 }
283
284 pub fn character(i: &[TokenTree]) -> IResult<&[TokenTree], char> {
285 if let IResult::Done(r, Lit::Char(c)) = lit(i) {
286 IResult::Done(r, c)
287 } else {
288 IResult::Error
289 }
290 }
291
292 pub fn float(i: &[TokenTree]) -> IResult<&[TokenTree], String> {
293 if let IResult::Done(r, Lit::Float(f, _)) = lit(i) {
294 IResult::Done(r, f)
295 } else {
296 IResult::Error
297 }
298 }
299
300 pub fn int(i: &[TokenTree]) -> IResult<&[TokenTree], u64> {
301 if let IResult::Done(r, Lit::Int(v, _)) = lit(i) {
302 IResult::Done(r, v)
303 } else {
304 IResult::Error
305 }
306 }
307
308 pub fn boolean(i: &[TokenTree]) -> IResult<&[TokenTree], bool> {
309 if let IResult::Done(r, Lit::Bool(b)) = lit(i) {
310 IResult::Done(r, b)
311 } else {
312 IResult::Error
David Tolnayfa0edf22016-09-23 22:58:24 -0700313 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700314 }
315}
316
317#[cfg(feature = "printing")]
318mod printing {
319 use super::*;
320 use quote::{Tokens, ToTokens};
David Tolnay56d62132016-10-01 16:14:54 -0700321 use std::{ascii, iter};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700322 use std::fmt::{self, Display};
David Tolnay4a658402016-10-24 00:21:41 -0700323 use std::str;
David Tolnayf4bbbd92016-09-23 14:41:55 -0700324
325 impl ToTokens for Lit {
326 fn to_tokens(&self, tokens: &mut Tokens) {
327 match *self {
328 Lit::Str(ref s, StrStyle::Cooked) => s.to_tokens(tokens),
David Tolnay627e3d52016-10-01 08:27:31 -0700329 Lit::Str(ref s, StrStyle::Raw(n)) => {
David Tolnay56d62132016-10-01 16:14:54 -0700330 tokens.append(&format!("r{delim}\"{string}\"{delim}",
David Tolnay05120ef2017-03-12 18:29:26 -0700331 delim = iter::repeat("#").take(n).collect::<String>(),
332 string = s));
David Tolnay56d62132016-10-01 16:14:54 -0700333 }
David Tolnay4a658402016-10-24 00:21:41 -0700334 Lit::ByteStr(ref v, StrStyle::Cooked) => {
David Tolnay56d62132016-10-01 16:14:54 -0700335 let mut escaped = "b\"".to_string();
336 for &ch in v.iter() {
David Tolnay289f4c72016-10-25 00:00:09 -0700337 match ch {
338 0 => escaped.push_str(r"\0"),
339 b'\'' => escaped.push('\''),
340 _ => escaped.extend(ascii::escape_default(ch).map(|c| c as char)),
341 }
David Tolnay627e3d52016-10-01 08:27:31 -0700342 }
David Tolnay56d62132016-10-01 16:14:54 -0700343 escaped.push('"');
344 tokens.append(&escaped);
David Tolnay627e3d52016-10-01 08:27:31 -0700345 }
David Tolnay4a658402016-10-24 00:21:41 -0700346 Lit::ByteStr(ref vec, StrStyle::Raw(n)) => {
347 tokens.append(&format!("br{delim}\"{string}\"{delim}",
David Tolnay05120ef2017-03-12 18:29:26 -0700348 delim = iter::repeat("#").take(n).collect::<String>(),
349 string = str::from_utf8(vec).unwrap()));
David Tolnay4a658402016-10-24 00:21:41 -0700350 }
David Tolnay289f4c72016-10-25 00:00:09 -0700351 Lit::Byte(b) => {
352 match b {
353 0 => tokens.append(r"b'\0'"),
354 b'\"' => tokens.append("b'\"'"),
355 _ => {
356 let mut escaped = "b'".to_string();
357 escaped.extend(ascii::escape_default(b).map(|c| c as char));
358 escaped.push('\'');
359 tokens.append(&escaped);
360 }
361 }
362 }
David Tolnayf17fd2f2016-10-07 23:38:08 -0700363 Lit::Char(ch) => ch.to_tokens(tokens),
David Tolnayf4bbbd92016-09-23 14:41:55 -0700364 Lit::Int(value, ty) => tokens.append(&format!("{}{}", value, ty)),
David Tolnayf17fd2f2016-10-07 23:38:08 -0700365 Lit::Float(ref value, ty) => tokens.append(&format!("{}{}", value, ty)),
David Tolnay759d2ff2016-10-01 16:18:15 -0700366 Lit::Bool(true) => tokens.append("true"),
367 Lit::Bool(false) => tokens.append("false"),
David Tolnayf4bbbd92016-09-23 14:41:55 -0700368 }
369 }
370 }
371
372 impl Display for IntTy {
373 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
374 match *self {
375 IntTy::Isize => formatter.write_str("isize"),
376 IntTy::I8 => formatter.write_str("i8"),
377 IntTy::I16 => formatter.write_str("i16"),
378 IntTy::I32 => formatter.write_str("i32"),
379 IntTy::I64 => formatter.write_str("i64"),
380 IntTy::Usize => formatter.write_str("usize"),
381 IntTy::U8 => formatter.write_str("u8"),
382 IntTy::U16 => formatter.write_str("u16"),
383 IntTy::U32 => formatter.write_str("u32"),
384 IntTy::U64 => formatter.write_str("u64"),
385 IntTy::Unsuffixed => Ok(()),
386 }
387 }
388 }
David Tolnayf17fd2f2016-10-07 23:38:08 -0700389
390 impl Display for FloatTy {
391 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
392 match *self {
393 FloatTy::F32 => formatter.write_str("f32"),
394 FloatTy::F64 => formatter.write_str("f64"),
395 FloatTy::Unsuffixed => Ok(()),
396 }
397 }
398 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700399}