blob: c1a28763227d7f50fdc2814dd0e53570e8b5af97 [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
David Tolnaydaaf7742016-10-03 11:11:43 -070029 Raw(usize),
David Tolnayf4bbbd92016-09-23 14:41:55 -070030}
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,
David Tolnaydaaf7742016-10-03 11:11:43 -070044 Unsuffixed,
David Tolnayf4bbbd92016-09-23 14:41:55 -070045}
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 Tolnay615cf6a2016-10-08 23:07:02 -070057 use escape::{cooked_char, 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 Tolnay615cf6a2016-10-08 23:07:02 -070065 |
66 byte
67 |
68 character
David Tolnayf4bbbd92016-09-23 14:41:55 -070069 |
70 int => { |(value, ty)| Lit::Int(value, ty) }
David Tolnaydaaf7742016-10-03 11:11:43 -070071 // TODO: Float
David Tolnay759d2ff2016-10-01 16:18:15 -070072 |
73 keyword!("true") => { |_| Lit::Bool(true) }
74 |
75 keyword!("false") => { |_| Lit::Bool(false) }
David Tolnayf4bbbd92016-09-23 14:41:55 -070076 ));
77
David Tolnay210884d2016-10-01 08:18:42 -070078 named!(string -> Lit, alt!(
David Tolnay42602292016-10-01 22:25:45 -070079 quoted_string => { |s| Lit::Str(s, StrStyle::Cooked) }
David Tolnay210884d2016-10-01 08:18:42 -070080 |
81 preceded!(
82 punct!("r"),
83 raw_string
84 ) => { |(s, n)| Lit::Str(s, StrStyle::Raw(n)) }
David Tolnayf4bbbd92016-09-23 14:41:55 -070085 ));
86
David Tolnay42602292016-10-01 22:25:45 -070087 named!(pub quoted_string -> String, delimited!(
88 punct!("\""),
89 cooked_string,
90 tag!("\"")
91 ));
92
David Tolnay56d62132016-10-01 16:14:54 -070093 named!(byte_string -> Lit, alt!(
94 delimited!(
95 punct!("b\""),
96 cooked_string,
97 tag!("\"")
98 ) => { |s: String| Lit::ByteStr(s.into_bytes()) }
99 |
100 preceded!(
101 punct!("br"),
102 raw_string
103 ) => { |(s, _): (String, _)| Lit::ByteStr(s.into_bytes()) }
104 ));
105
David Tolnay615cf6a2016-10-08 23:07:02 -0700106 named!(byte -> Lit, do_parse!(
107 punct!("b") >>
108 tag!("'") >>
109 ch: cooked_char >>
110 tag!("'") >>
111 (Lit::Byte(ch as u8))
112 ));
113
114 named!(character -> Lit, do_parse!(
115 punct!("'") >>
116 ch: cooked_char >>
117 tag!("'") >>
118 (Lit::Char(ch))
119 ));
120
David Tolnayde206222016-09-30 11:47:01 -0700121 named!(pub int -> (u64, IntTy), tuple!(
David Tolnay14cbdeb2016-10-01 12:13:59 -0700122 preceded!(
123 option!(whitespace),
124 digits
125 ),
David Tolnayde206222016-09-30 11:47:01 -0700126 alt!(
127 tag!("isize") => { |_| IntTy::Isize }
128 |
129 tag!("i8") => { |_| IntTy::I8 }
130 |
131 tag!("i16") => { |_| IntTy::I16 }
132 |
133 tag!("i32") => { |_| IntTy::I32 }
134 |
135 tag!("i64") => { |_| IntTy::I64 }
136 |
137 tag!("usize") => { |_| IntTy::Usize }
138 |
139 tag!("u8") => { |_| IntTy::U8 }
140 |
141 tag!("u16") => { |_| IntTy::U16 }
142 |
143 tag!("u32") => { |_| IntTy::U32 }
144 |
145 tag!("u64") => { |_| IntTy::U64 }
146 |
147 epsilon!() => { |_| IntTy::Unsuffixed }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700148 )
149 ));
150
David Tolnayde206222016-09-30 11:47:01 -0700151 pub fn digits(input: &str) -> IResult<&str, u64> {
David Tolnayf4bbbd92016-09-23 14:41:55 -0700152 let mut value = 0u64;
153 let mut len = 0;
154 let mut bytes = input.bytes().peekable();
155 while let Some(&b) = bytes.peek() {
156 match b {
David Tolnaydaaf7742016-10-03 11:11:43 -0700157 b'0'...b'9' => {
David Tolnayf4bbbd92016-09-23 14:41:55 -0700158 value = match value.checked_mul(10) {
159 Some(value) => value,
160 None => return IResult::Error,
161 };
162 value = match value.checked_add((b - b'0') as u64) {
163 Some(value) => value,
164 None => return IResult::Error,
165 };
166 bytes.next();
167 len += 1;
168 }
David Tolnayfa0edf22016-09-23 22:58:24 -0700169 _ => break,
David Tolnayf4bbbd92016-09-23 14:41:55 -0700170 }
171 }
David Tolnayfa0edf22016-09-23 22:58:24 -0700172 if len > 0 {
173 IResult::Done(&input[len..], value)
174 } else {
175 IResult::Error
176 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700177 }
178}
179
180#[cfg(feature = "printing")]
181mod printing {
182 use super::*;
183 use quote::{Tokens, ToTokens};
David Tolnay56d62132016-10-01 16:14:54 -0700184 use std::{ascii, iter};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700185 use std::fmt::{self, Display};
186
187 impl ToTokens for Lit {
188 fn to_tokens(&self, tokens: &mut Tokens) {
189 match *self {
190 Lit::Str(ref s, StrStyle::Cooked) => s.to_tokens(tokens),
David Tolnay627e3d52016-10-01 08:27:31 -0700191 Lit::Str(ref s, StrStyle::Raw(n)) => {
David Tolnay56d62132016-10-01 16:14:54 -0700192 tokens.append(&format!("r{delim}\"{string}\"{delim}",
193 delim = iter::repeat("#").take(n).collect::<String>(),
194 string = s));
195 }
196 Lit::ByteStr(ref v) => {
197 let mut escaped = "b\"".to_string();
198 for &ch in v.iter() {
199 escaped.extend(ascii::escape_default(ch).map(|c| c as char));
David Tolnay627e3d52016-10-01 08:27:31 -0700200 }
David Tolnay56d62132016-10-01 16:14:54 -0700201 escaped.push('"');
202 tokens.append(&escaped);
David Tolnay627e3d52016-10-01 08:27:31 -0700203 }
David Tolnay615cf6a2016-10-08 23:07:02 -0700204 Lit::Byte(b) => tokens.append(&format!("b{:?}", b as char)),
David Tolnayf17fd2f2016-10-07 23:38:08 -0700205 Lit::Char(ch) => ch.to_tokens(tokens),
David Tolnayf4bbbd92016-09-23 14:41:55 -0700206 Lit::Int(value, ty) => tokens.append(&format!("{}{}", value, ty)),
David Tolnayf17fd2f2016-10-07 23:38:08 -0700207 Lit::Float(ref value, ty) => tokens.append(&format!("{}{}", value, ty)),
David Tolnay759d2ff2016-10-01 16:18:15 -0700208 Lit::Bool(true) => tokens.append("true"),
209 Lit::Bool(false) => tokens.append("false"),
David Tolnayf4bbbd92016-09-23 14:41:55 -0700210 }
211 }
212 }
213
214 impl Display for IntTy {
215 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
216 match *self {
217 IntTy::Isize => formatter.write_str("isize"),
218 IntTy::I8 => formatter.write_str("i8"),
219 IntTy::I16 => formatter.write_str("i16"),
220 IntTy::I32 => formatter.write_str("i32"),
221 IntTy::I64 => formatter.write_str("i64"),
222 IntTy::Usize => formatter.write_str("usize"),
223 IntTy::U8 => formatter.write_str("u8"),
224 IntTy::U16 => formatter.write_str("u16"),
225 IntTy::U32 => formatter.write_str("u32"),
226 IntTy::U64 => formatter.write_str("u64"),
227 IntTy::Unsuffixed => Ok(()),
228 }
229 }
230 }
David Tolnayf17fd2f2016-10-07 23:38:08 -0700231
232 impl Display for FloatTy {
233 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
234 match *self {
235 FloatTy::F32 => formatter.write_str("f32"),
236 FloatTy::F64 => formatter.write_str("f64"),
237 FloatTy::Unsuffixed => Ok(()),
238 }
239 }
240 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700241}