blob: c7a647ff12b776c9b2579532906387fcc04287a0 [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"`)
9 ByteStr(Vec<u8>),
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}
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
29 Raw(usize)
30}
31
32#[derive(Debug, Copy, Clone, Eq, PartialEq)]
33pub enum IntTy {
34 Isize,
35 I8,
36 I16,
37 I32,
38 I64,
39 Usize,
40 U8,
41 U16,
42 U32,
43 U64,
44 Unsuffixed
45}
46
47#[derive(Debug, Copy, Clone, Eq, PartialEq)]
48pub enum FloatTy {
49 F32,
50 F64,
51 Unsuffixed,
52}
53
54#[cfg(feature = "parsing")]
55pub mod parsing {
56 use super::*;
David Tolnay210884d2016-10-01 08:18:42 -070057 use escape::{cooked_string, raw_string};
David Tolnay14cbdeb2016-10-01 12:13:59 -070058 use space::whitespace;
David Tolnayde206222016-09-30 11:47:01 -070059 use nom::IResult;
David Tolnayf4bbbd92016-09-23 14:41:55 -070060
61 named!(pub lit -> Lit, alt!(
David Tolnay210884d2016-10-01 08:18:42 -070062 string
David Tolnay56d62132016-10-01 16:14:54 -070063 |
64 byte_string
David Tolnay7de67d22016-09-24 07:23:32 -070065 // TODO: Byte
66 // TODO: Char
David Tolnayf4bbbd92016-09-23 14:41:55 -070067 |
68 int => { |(value, ty)| Lit::Int(value, ty) }
David Tolnay7de67d22016-09-24 07:23:32 -070069 // TODO: Float
70 // TODO: Bool
David Tolnayf4bbbd92016-09-23 14:41:55 -070071 ));
72
David Tolnay210884d2016-10-01 08:18:42 -070073 named!(string -> Lit, alt!(
74 delimited!(
75 punct!("\""),
76 cooked_string,
77 tag!("\"")
78 ) => { |s| Lit::Str(s, StrStyle::Cooked) }
79 |
80 preceded!(
81 punct!("r"),
82 raw_string
83 ) => { |(s, n)| Lit::Str(s, StrStyle::Raw(n)) }
David Tolnayf4bbbd92016-09-23 14:41:55 -070084 ));
85
David Tolnay56d62132016-10-01 16:14:54 -070086 named!(byte_string -> Lit, alt!(
87 delimited!(
88 punct!("b\""),
89 cooked_string,
90 tag!("\"")
91 ) => { |s: String| Lit::ByteStr(s.into_bytes()) }
92 |
93 preceded!(
94 punct!("br"),
95 raw_string
96 ) => { |(s, _): (String, _)| Lit::ByteStr(s.into_bytes()) }
97 ));
98
David Tolnayde206222016-09-30 11:47:01 -070099 named!(pub int -> (u64, IntTy), tuple!(
David Tolnay14cbdeb2016-10-01 12:13:59 -0700100 preceded!(
101 option!(whitespace),
102 digits
103 ),
David Tolnayde206222016-09-30 11:47:01 -0700104 alt!(
105 tag!("isize") => { |_| IntTy::Isize }
106 |
107 tag!("i8") => { |_| IntTy::I8 }
108 |
109 tag!("i16") => { |_| IntTy::I16 }
110 |
111 tag!("i32") => { |_| IntTy::I32 }
112 |
113 tag!("i64") => { |_| IntTy::I64 }
114 |
115 tag!("usize") => { |_| IntTy::Usize }
116 |
117 tag!("u8") => { |_| IntTy::U8 }
118 |
119 tag!("u16") => { |_| IntTy::U16 }
120 |
121 tag!("u32") => { |_| IntTy::U32 }
122 |
123 tag!("u64") => { |_| IntTy::U64 }
124 |
125 epsilon!() => { |_| IntTy::Unsuffixed }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700126 )
127 ));
128
David Tolnayde206222016-09-30 11:47:01 -0700129 pub fn digits(input: &str) -> IResult<&str, u64> {
David Tolnayf4bbbd92016-09-23 14:41:55 -0700130 let mut value = 0u64;
131 let mut len = 0;
132 let mut bytes = input.bytes().peekable();
133 while let Some(&b) = bytes.peek() {
134 match b {
135 b'0' ... b'9' => {
136 value = match value.checked_mul(10) {
137 Some(value) => value,
138 None => return IResult::Error,
139 };
140 value = match value.checked_add((b - b'0') as u64) {
141 Some(value) => value,
142 None => return IResult::Error,
143 };
144 bytes.next();
145 len += 1;
146 }
David Tolnayfa0edf22016-09-23 22:58:24 -0700147 _ => break,
David Tolnayf4bbbd92016-09-23 14:41:55 -0700148 }
149 }
David Tolnayfa0edf22016-09-23 22:58:24 -0700150 if len > 0 {
151 IResult::Done(&input[len..], value)
152 } else {
153 IResult::Error
154 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700155 }
156}
157
158#[cfg(feature = "printing")]
159mod printing {
160 use super::*;
161 use quote::{Tokens, ToTokens};
David Tolnay56d62132016-10-01 16:14:54 -0700162 use std::{ascii, iter};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700163 use std::fmt::{self, Display};
164
165 impl ToTokens for Lit {
166 fn to_tokens(&self, tokens: &mut Tokens) {
167 match *self {
168 Lit::Str(ref s, StrStyle::Cooked) => s.to_tokens(tokens),
David Tolnay627e3d52016-10-01 08:27:31 -0700169 Lit::Str(ref s, StrStyle::Raw(n)) => {
David Tolnay56d62132016-10-01 16:14:54 -0700170 tokens.append(&format!("r{delim}\"{string}\"{delim}",
171 delim = iter::repeat("#").take(n).collect::<String>(),
172 string = s));
173 }
174 Lit::ByteStr(ref v) => {
175 let mut escaped = "b\"".to_string();
176 for &ch in v.iter() {
177 escaped.extend(ascii::escape_default(ch).map(|c| c as char));
David Tolnay627e3d52016-10-01 08:27:31 -0700178 }
David Tolnay56d62132016-10-01 16:14:54 -0700179 escaped.push('"');
180 tokens.append(&escaped);
David Tolnay627e3d52016-10-01 08:27:31 -0700181 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700182 Lit::Int(value, ty) => tokens.append(&format!("{}{}", value, ty)),
183 _ => unimplemented!(),
184 }
185 }
186 }
187
188 impl Display for IntTy {
189 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
190 match *self {
191 IntTy::Isize => formatter.write_str("isize"),
192 IntTy::I8 => formatter.write_str("i8"),
193 IntTy::I16 => formatter.write_str("i16"),
194 IntTy::I32 => formatter.write_str("i32"),
195 IntTy::I64 => formatter.write_str("i64"),
196 IntTy::Usize => formatter.write_str("usize"),
197 IntTy::U8 => formatter.write_str("u8"),
198 IntTy::U16 => formatter.write_str("u16"),
199 IntTy::U32 => formatter.write_str("u32"),
200 IntTy::U64 => formatter.write_str("u64"),
201 IntTy::Unsuffixed => Ok(()),
202 }
203 }
204 }
205}