1
/*
2
 * Hurl (https://hurl.dev)
3
 * Copyright (C) 2024 Orange
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *          http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
use crate::ast::U64;
19
use crate::ast::{Float, Number, I64};
20
use crate::parser::primitives::try_literal;
21
use crate::parser::{ParseError, ParseErrorKind, ParseResult};
22
use crate::reader::Reader;
23

            
24
855
pub fn natural(reader: &mut Reader) -> ParseResult<U64> {
25
855
    let start = reader.cursor();
26
855
    let s = parse_natural_str(reader, "natural")?;
27
790
    match s.parse() {
28
790
        Ok(value) => {
29
790
            let encoded = reader.read_from(start.index);
30
790
            Ok(U64::new(value, encoded))
31
        }
32
        Err(_) => {
33
            let kind = ParseErrorKind::Expecting {
34
                value: String::from("natural"),
35
            };
36
            Err(ParseError::new(start.pos, false, kind))
37
        }
38
    }
39
}
40

            
41
335
pub fn integer(reader: &mut Reader) -> ParseResult<I64> {
42
335
    let start = reader.cursor();
43
335
    let sign = match try_literal("-", reader) {
44
290
        Err(_) => 1,
45
45
        Ok(_) => -1,
46
    };
47
335
    let s = parse_natural_str(reader, "integer")?;
48
235
    match s.to_string().parse::<i64>() {
49
235
        Ok(value) => {
50
235
            let value = sign * value;
51
235
            let encoded = reader.read_from(start.index);
52
235
            Ok(I64::new(value, encoded))
53
        }
54
        Err(_) => {
55
            let kind = ParseErrorKind::Expecting {
56
                value: String::from("integer"),
57
            };
58
            Err(ParseError::new(start.pos, false, kind))
59
        }
60
    }
61
}
62

            
63
/// Parses a natural string.
64
/// This is common code between natural and integer parsers.
65
1190
fn parse_natural_str(reader: &mut Reader, expecting: &str) -> ParseResult<String> {
66
1190
    let mut save = reader.cursor();
67
1190
    if reader.is_eof() {
68
        let kind = ParseErrorKind::Expecting {
69
            value: expecting.to_string(),
70
        };
71
        return Err(ParseError::new(save.pos, true, kind));
72
    }
73
1190
    let first_digit = reader.read().unwrap();
74
1190
    if !first_digit.is_ascii_digit() {
75
165
        let kind = ParseErrorKind::Expecting {
76
165
            value: expecting.to_string(),
77
165
        };
78
165
        return Err(ParseError::new(save.pos, true, kind));
79
    }
80
1025
    save.pos = reader.cursor().pos;
81
1680
    let s = reader.read_while(|c| c.is_ascii_digit());
82
1025
    // if the first digit is zero, you should not have any more digits
83
1025
    if first_digit == '0' && !s.is_empty() {
84
        let kind = ParseErrorKind::Expecting {
85
            value: expecting.to_string(),
86
        };
87
        return Err(ParseError::new(save.pos, false, kind));
88
    }
89
1025
    Ok(format!("{first_digit}{s}"))
90
}
91

            
92
16180
pub fn number(reader: &mut Reader) -> ParseResult<Number> {
93
16180
    let start = reader.cursor();
94
16180
    let sign = match try_literal("-", reader) {
95
16160
        Err(_) => "",
96
20
        Ok(_) => "-",
97
    };
98
27296
    let integer_digits = reader.read_while(|c| c.is_ascii_digit());
99
16180
    if integer_digits.is_empty() {
100
12080
        let kind = ParseErrorKind::Expecting {
101
12080
            value: "number".to_string(),
102
12080
        };
103
12080
        return Err(ParseError::new(reader.cursor().pos, true, kind));
104

            
105
        // if the first digit is zero, you should not have any more digits
106
4100
    } else if integer_digits.len() > 1 && integer_digits.starts_with('0') {
107
        let save = reader.cursor();
108
        let kind = ParseErrorKind::Expecting {
109
            value: String::from("natural"),
110
        };
111
        return Err(ParseError::new(save.pos, false, kind));
112
    }
113
4100

            
114
4100
    // Float
115
4100
    if try_literal(".", reader).is_ok() {
116
810
        let save = reader.cursor();
117
6142
        let decimal_digits = reader.read_while(|c| c.is_ascii_digit());
118
810
        if decimal_digits.is_empty() {
119
            let kind = ParseErrorKind::Expecting {
120
                value: String::from("decimal digits"),
121
            };
122
            return Err(ParseError::new(save.pos, false, kind));
123
        }
124
810
        match format!("{sign}{integer_digits}.{decimal_digits}").parse() {
125
810
            Ok(value) => {
126
810
                let encoded = reader.read_from(start.index);
127
810
                Ok(Number::Float(Float { value, encoded }))
128
            }
129
            Err(_) => {
130
                let kind = ParseErrorKind::Expecting {
131
                    value: String::from("float"),
132
                };
133
                Err(ParseError::new(start.pos, false, kind))
134
            }
135
        }
136

            
137
    // Integer or BigInteger
138
    } else {
139
3290
        match format!("{sign}{integer_digits}").parse::<i64>() {
140
3265
            Ok(value) => {
141
3265
                let encoded = reader.read_from(start.index);
142
3265
                let integer = I64::new(value, encoded);
143
3265
                Ok(Number::Integer(integer))
144
            }
145
25
            Err(_) => Ok(Number::BigInteger(integer_digits)),
146
        }
147
    }
148
}
149

            
150
#[cfg(test)]
151
mod tests {
152
    use super::*;
153
    use crate::reader::Pos;
154

            
155
    #[test]
156
    fn test_natural() {
157
        let mut reader = Reader::new("0");
158
        assert_eq!(natural(&mut reader).unwrap(), U64::new(0, "0".to_string()));
159
        assert_eq!(reader.cursor().index, 1);
160

            
161
        let mut reader = Reader::new("10x");
162
        assert_eq!(
163
            natural(&mut reader).unwrap(),
164
            U64::new(10, "10".to_string())
165
        );
166
        assert_eq!(reader.cursor().index, 2);
167
    }
168

            
169
    #[test]
170
    fn test_natural_error() {
171
        let mut reader = Reader::new("");
172
        let error = natural(&mut reader).err().unwrap();
173
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
174
        assert_eq!(
175
            error.kind,
176
            ParseErrorKind::Expecting {
177
                value: String::from("natural")
178
            }
179
        );
180
        assert!(error.recoverable);
181

            
182
        let mut reader = Reader::new("01");
183
        let error = natural(&mut reader).err().unwrap();
184
        assert_eq!(error.pos, Pos { line: 1, column: 2 });
185
        assert_eq!(
186
            error.kind,
187
            ParseErrorKind::Expecting {
188
                value: String::from("natural")
189
            }
190
        );
191
        assert!(!error.recoverable);
192

            
193
        let mut reader = Reader::new("x");
194
        let error = natural(&mut reader).err().unwrap();
195
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
196
        assert_eq!(
197
            error.kind,
198
            ParseErrorKind::Expecting {
199
                value: String::from("natural")
200
            }
201
        );
202
        assert!(error.recoverable);
203
    }
204

            
205
    #[test]
206
    fn test_integer() {
207
        let mut reader = Reader::new("0");
208
        assert_eq!(integer(&mut reader).unwrap(), I64::new(0, "0".to_string()));
209
        assert_eq!(reader.cursor().index, 1);
210

            
211
        let mut reader = Reader::new("-1");
212
        assert_eq!(
213
            integer(&mut reader).unwrap(),
214
            I64::new(-1, "-1".to_string())
215
        );
216
        assert_eq!(reader.cursor().index, 2);
217

            
218
        let mut reader = Reader::new("0");
219
        assert_eq!(
220
            number(&mut reader).unwrap(),
221
            Number::Integer(I64::new(0, "0".to_string()))
222
        );
223
        assert_eq!(reader.cursor().index, 1);
224

            
225
        let mut reader = Reader::new("10x");
226
        assert_eq!(
227
            number(&mut reader).unwrap(),
228
            Number::Integer(I64::new(10, "10".to_string()))
229
        );
230
        assert_eq!(reader.cursor().index, 2);
231

            
232
        let mut reader = Reader::new("-10x");
233
        assert_eq!(
234
            number(&mut reader).unwrap(),
235
            Number::Integer(I64::new(-10, "-10".to_string()))
236
        );
237
        assert_eq!(reader.cursor().index, 3);
238
    }
239

            
240
    #[test]
241
    fn test_float() {
242
        let mut reader = Reader::new("1.0");
243
        assert_eq!(
244
            number(&mut reader).unwrap(),
245
            Number::Float(Float {
246
                value: 1.0,
247
                encoded: "1.0".to_string()
248
            })
249
        );
250
        assert_eq!(reader.cursor().index, 3);
251

            
252
        let mut reader = Reader::new("-1.0");
253
        assert_eq!(
254
            number(&mut reader).unwrap(),
255
            Number::Float(Float {
256
                value: -1.0,
257
                encoded: "-1.0".to_string()
258
            })
259
        );
260
        assert_eq!(reader.cursor().index, 4);
261

            
262
        let mut reader = Reader::new("1.1");
263
        assert_eq!(
264
            number(&mut reader).unwrap(),
265
            Number::Float(Float {
266
                value: 1.1,
267
                encoded: "1.1".to_string()
268
            })
269
        );
270
        assert_eq!(reader.cursor().index, 3);
271

            
272
        let mut reader = Reader::new("1.100");
273
        assert_eq!(
274
            number(&mut reader).unwrap(),
275
            Number::Float(Float {
276
                value: 1.1,
277
                encoded: "1.100".to_string()
278
            })
279
        );
280
        assert_eq!(reader.cursor().index, 5);
281

            
282
        let mut reader = Reader::new("1.01");
283
        assert_eq!(
284
            number(&mut reader).unwrap(),
285
            Number::Float(Float {
286
                value: 1.01,
287
                encoded: "1.01".to_string()
288
            })
289
        );
290
        assert_eq!(reader.cursor().index, 4);
291

            
292
        let mut reader = Reader::new("1.010");
293
        assert_eq!(
294
            number(&mut reader).unwrap(),
295
            Number::Float(Float {
296
                value: 1.01,
297
                encoded: "1.010".to_string()
298
            })
299
        );
300
        assert_eq!(reader.cursor().index, 5);
301

            
302
        // provide more digits than necessary
303
        let mut reader = Reader::new("-0.3333333333333333333");
304
        assert_eq!(
305
            number(&mut reader).unwrap(),
306
            Number::Float(Float {
307
                value: -0.3333333333333333,
308
                encoded: "-0.3333333333333333333".to_string()
309
            })
310
        );
311
        assert_eq!(reader.cursor().index, 22);
312

            
313
        let mut reader = Reader::new("1000000000000000000000.5");
314
        assert_eq!(
315
            number(&mut reader).unwrap(),
316
            Number::Float(Float {
317
                value: 1000000000000000000000.0,
318
                encoded: "1000000000000000000000.5".to_string()
319
            })
320
        );
321
        assert_eq!(reader.cursor().index, 24);
322
    }
323

            
324
    #[test]
325
    pub fn test_number_error() {
326
        let mut reader = Reader::new("");
327
        let error = number(&mut reader).err().unwrap();
328
        assert_eq!(
329
            error.kind,
330
            ParseErrorKind::Expecting {
331
                value: String::from("number")
332
            }
333
        );
334
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
335
        assert!(error.recoverable);
336

            
337
        let mut reader = Reader::new("-");
338
        let error = number(&mut reader).err().unwrap();
339
        assert_eq!(
340
            error.kind,
341
            ParseErrorKind::Expecting {
342
                value: String::from("number")
343
            }
344
        );
345
        assert_eq!(error.pos, Pos { line: 1, column: 2 });
346
        assert!(error.recoverable);
347

            
348
        let mut reader = Reader::new("x");
349
        let error = number(&mut reader).err().unwrap();
350
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
351
        assert_eq!(
352
            error.kind,
353
            ParseErrorKind::Expecting {
354
                value: String::from("number")
355
            }
356
        );
357
        assert!(error.recoverable);
358

            
359
        let mut reader = Reader::new("1.");
360
        let error = number(&mut reader).err().unwrap();
361
        assert_eq!(error.pos, Pos { line: 1, column: 3 });
362
        assert_eq!(
363
            error.kind,
364
            ParseErrorKind::Expecting {
365
                value: String::from("decimal digits")
366
            }
367
        );
368
        assert!(!error.recoverable);
369
    }
370
}