1use std::str;
4
5use super::{ParseErrorKind, CutParseResult};
6use super::bits::*;
7
8use ast::*;
9
10pub fn literal(input: &[u8]) -> CutParseResult<Literal> {
11 alt!(input,
12 literal_null(input)
13 ; literal_bool(input)
14 ; literal_currency(input)
15 ; literal_float(input)
16 ; literal_int(input)
17 ; literal_string(input)
18 )
21}
22
23fn literal_null(input: &[u8]) -> CutParseResult<Literal> {
24 alt!(input,
25 keyword(input, b"nullptr") => |_| Literal::NullPtr
26 ; keyword(input, b"nullvar") => |_| Literal::NullVar
27 ; keyword(input, b"emptyvar") => |_| Literal::EmptyVar
28 )
29}
30
31fn literal_bool(input: &[u8]) -> CutParseResult<Literal> {
32 alt!(input,
33 keyword(input, b"true") => |_| Literal::Bool(true)
34 ; keyword(input, b"false") => |_| Literal::Bool(false)
35 )
36}
37
38fn literal_int(input: &[u8]) -> CutParseResult<Literal> {
39 let (i, _) = opt(input, multispace)?;
40 let (i, num) = require!(digits(i));
41 let (i, tag) = require!(opt!(alt!(i,
42 keyword_immediate(i, b"u8")
43 ; keyword_immediate(i, b"i16")
44 ; keyword_immediate(i, b"i32")
45 ; keyword_immediate(i, b"isize")
46 )));
47
48 let num = unsafe { str::from_utf8_unchecked(num) };
49 let parsed = match tag {
50 None => num.parse::<i32>().map(Literal::Int32),
51 Some(b"u8") => num.parse::<u8>().map(Literal::UInt8),
52 Some(b"i16") => num.parse::<i16>().map(Literal::Int16),
53 Some(b"i32") => num.parse::<i32>().map(Literal::Int32),
54 Some(b"isize") => num.parse::<i64>().map(Literal::IntPtr),
55 _ => panic!("dumpster fire: bad tag in int literal"),
56 };
57
58 match parsed {
59 Ok(lit) => ok!(i, lit),
60 Err(_) => cut!(input, ParseErrorKind::InvalidLiteral),
63 }
64}
65
66fn literal_float(input: &[u8]) -> CutParseResult<Literal> {
67 let (i, _) = opt(input, multispace)?;
68 let (i, whole) = require!(digits(i));
69 let (i, _) = require!(byte(i, b'.'));
71 let (i, frac) = require!(opt(i, digits));
72 let (i, tag) = require!(opt!(alt!(i,
73 keyword_immediate(i, b"f32")
74 ; keyword_immediate(i, b"f64")
75 )));
76
77 let mut num = String::from(unsafe { str::from_utf8_unchecked(whole) });
78 match frac {
79 None => { },
80 Some(frac) => {
81 num.push_str(".");
82 num.push_str(unsafe { str::from_utf8_unchecked(frac) });
83 }
84 };
85
86 let parsed = match tag {
87 None => num.parse::<f64>().map(Literal::Float64),
88 Some(b"f32") => num.parse::<f32>().map(Literal::Float32),
89 Some(b"f64") => num.parse::<f64>().map(Literal::Float64),
90 _ => panic!("dumpster fire: bad tag in float literal"),
91 };
92
93 match parsed {
94 Ok(lit) => ok!(i, lit),
95 Err(_) => cut!(input, ParseErrorKind::InvalidLiteral),
98 }
99}
100
101fn literal_currency(input: &[u8]) -> CutParseResult<Literal> {
102 let (i, _) = opt(input, multispace)?;
103
104 let (i, whole) = require!(digits(i));
105
106 let (i, frac) = require!(opt!(chain!(i,
107 |i| byte(i, b'.') =>
108 digits
109 )));
110
111 let (i, _) = require!(keyword_immediate(i, b"currency"));
112
113 let whole = unsafe { str::from_utf8_unchecked(whole) }.parse::<i64>();
114 let frac = match frac {
115 None => Ok(0i16),
116 Some(frac) => {
117 unsafe { str::from_utf8_unchecked(frac) }.parse::<i16>()
118 },
119 };
120
121 let (whole, frac) = match (whole, frac) {
122 (Err(_), _) => return cut!(input, ParseErrorKind::InvalidLiteral),
123 (_, Err(_)) => return cut!(input, ParseErrorKind::InvalidLiteral),
124 (Ok(whole), Ok(frac)) => (whole, frac),
125 };
126
127 ok!(i, make_currency(whole, frac))
128}
129
130fn literal_string(input: &[u8]) -> CutParseResult<Literal> {
131 let (i, _) = opt(input, multispace)?;
132 let (i, _) = require!(byte(i, b'"'));
133 let (i, escaped) = require!(escaped_string(i));
134 let (i, _) = require!(byte(i, b'"'));
135
136 match String::from_utf8(escaped) {
137 Ok(s) => ok!(i, Literal::String(s)),
138 Err(_) => cut!(input, ParseErrorKind::InvalidLiteral)
139 }
140}
141
142#[inline]
143fn make_currency(whole: i64, frac: i16) -> Literal {
144 let frac_digits = (frac as f32).log10().ceil() as i16;
145 let frac_scalar = f32::powf(10.0, (4 - frac_digits) as f32);
146 Literal::Currency(whole * 10000 + (frac as f32 * frac_scalar) as i64)
147}
148
149fn escaped_string(input: &[u8]) -> CutParseResult<Vec<u8>> {
150 let mut s = Vec::new();
151 let mut bytes_consumed = 0;
152 let mut bytes = input.iter();
153 while let Some(c) = bytes.next() {
154 if *c == b'"' {
155 break;
156 }
157
158 if *c == b'\\' {
159 match bytes.next() {
160 Some(&b'n') => s.push(b'\n'),
161 Some(&b't') => s.push(b'\t'),
162 Some(&b'"') => s.push(b'"'),
163 _ => return cut!(&input[bytes_consumed..],
165 ParseErrorKind::InvalidEscape)
166 }
167 bytes_consumed += 2;
168 continue;
169 }
170
171 bytes_consumed += 1;
177 s.push(*c);
178 }
179
180 ok!(&input[bytes_consumed..], s)
181}
182
183#[cfg(test)]
184mod test {
185 use super::*;
186
187 #[test]
188 fn parse_literals() {
189 expect_parse!(literal(b"nullptr") => Literal::NullPtr);
190 expect_parse!(literal(b"123.45") => Literal::Float64(123.45));
191 expect_parse!(literal(b"\n123i16") => Literal::Int16(123i16));
192 expect_parse!(literal(b"\t123.45currency") =>
193 Literal::Currency(1234500i64));
194 expect_parse!(literal(b"\"hello\tworld\"") => Literal::String(_));
195 expect_parse_err!(literal(b"alskf") => ParseErrorKind::NoAltMatch);
196 expect_parse_cut!(literal(b" 123456789u8") =>
197 ParseErrorKind::InvalidLiteral);
198 }
199
200 #[test]
201 fn parse_nulls() {
202 expect_parse!(literal_null(b"nullptr") => Literal::NullPtr);
203 expect_parse!(literal_null(b" nullvar") => Literal::NullVar);
204 expect_parse!(literal_null(b"\nemptyvar") => Literal::EmptyVar);
205 }
206
207 #[test]
208 fn parse_bools() {
209 expect_parse!(literal_bool(b" true") => Literal::Bool(true));
210 expect_parse!(literal_bool(b"false") => Literal::Bool(false));
211 expect_parse_err!(literal_bool(b"fake") => _);
212 }
213
214 #[test]
215 fn parse_ints() {
216 expect_parse!(literal_int(b"721") => Literal::Int32(721));
217 expect_parse!(literal_int(b"123u8") => Literal::UInt8(123u8));
218 expect_parse_err!(literal_int(b"alskf") =>
219 ParseErrorKind::ExpectedDigit);
220 expect_parse_cut!(literal_int(b"123456789u8") =>
221 ParseErrorKind::InvalidLiteral);
222 }
223
224 #[test]
225 fn parse_floats() {
226 expect_parse!(literal_float(b"124.5") => Literal::Float64(124.5));
227 expect_parse!(literal_float(b"1234.56f32") => Literal::Float32(1234.56f32));
228 expect_parse_err!(literal_float(b"x.12") => ParseErrorKind::ExpectedDigit);
229 }
234
235 #[test]
236 fn parse_currency() {
237 expect_parse!(literal_currency(b" 12345.67currency") =>
238 Literal::Currency(123456700i64));
239 expect_parse_cut!(
240 literal_currency(b"999.9999999999999999999999999999currency") => _);
241 }
242
243 #[test]
244 fn parse_string() {
245 expect_parse!(literal_string(b"\"hello world\\nor whatever\"") =>
246 Literal::String(_));
247 expect_parse_err!(literal_string(b"\"unclosed") => _);
248 expect_parse_cut!(literal_string(b" \"invalid \\x escape\"") => _);
249 }
250}