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::*;
19
use crate::parser::error::*;
20
use crate::parser::primitives::try_literal;
21
use crate::parser::ParseResult;
22
use crate::reader::Reader;
23

            
24
13140
pub fn natural(reader: &mut Reader) -> ParseResult<u64> {
25
13140
    let start = reader.cursor();
26
13140

            
27
13140
    if reader.is_eof() {
28
        let kind = ParseErrorKind::Expecting {
29
            value: String::from("natural"),
30
        };
31
        return Err(ParseError::new(start.pos, true, kind));
32
    }
33
13140
    let first_digit = reader.read().unwrap();
34
13140
    if !first_digit.is_ascii_digit() {
35
140
        let kind = ParseErrorKind::Expecting {
36
140
            value: String::from("natural"),
37
140
        };
38
140
        return Err(ParseError::new(start.pos, true, kind));
39
    }
40
13000

            
41
13000
    let save = reader.cursor();
42
40050
    let s = reader.read_while(|c| c.is_ascii_digit());
43
13000

            
44
13000
    // if the first digit is zero, you should not have any more digits
45
13000
    if first_digit == '0' && !s.is_empty() {
46
        let kind = ParseErrorKind::Expecting {
47
            value: String::from("natural"),
48
        };
49
        return Err(ParseError::new(save.pos, false, kind));
50
    }
51
13000
    match format!("{first_digit}{s}").parse() {
52
13000
        Ok(value) => Ok(value),
53
        Err(_) => {
54
            let kind = ParseErrorKind::Expecting {
55
                value: String::from("natural"),
56
            };
57
            Err(ParseError::new(save.pos, false, kind))
58
        }
59
    }
60
}
61

            
62
340
pub fn integer(reader: &mut Reader) -> ParseResult<i64> {
63
340
    let sign = match try_literal("-", reader) {
64
295
        Err(_) => 1,
65
45
        Ok(_) => -1,
66
    };
67
340
    let nat = natural(reader)?;
68
240
    Ok(sign * (nat as i64))
69
}
70

            
71
15675
pub fn number(reader: &mut Reader) -> ParseResult<Number> {
72
15675
    let start = reader.cursor();
73
15675
    let sign = match try_literal("-", reader) {
74
15655
        Err(_) => "",
75
20
        Ok(_) => "-",
76
    };
77
26440
    let integer_digits = reader.read_while(|c| c.is_ascii_digit());
78
15675
    if integer_digits.is_empty() {
79
11660
        let kind = ParseErrorKind::Expecting {
80
11660
            value: "number".to_string(),
81
11660
        };
82
11660
        return Err(ParseError::new(reader.cursor().pos, true, kind));
83

            
84
        // if the first digit is zero, you should not have any more digits
85
4015
    } else if integer_digits.len() > 1 && integer_digits.starts_with('0') {
86
        let save = reader.cursor();
87
        let kind = ParseErrorKind::Expecting {
88
            value: String::from("natural"),
89
        };
90
        return Err(ParseError::new(save.pos, false, kind));
91
    }
92
4015

            
93
4015
    // Float
94
4015
    if try_literal(".", reader).is_ok() {
95
810
        let save = reader.cursor();
96
6142
        let decimal_digits = reader.read_while(|c| c.is_ascii_digit());
97
810
        if decimal_digits.is_empty() {
98
            let kind = ParseErrorKind::Expecting {
99
                value: String::from("decimal digits"),
100
            };
101
            return Err(ParseError::new(save.pos, false, kind));
102
        }
103
810
        match format!("{sign}{integer_digits}.{decimal_digits}").parse() {
104
810
            Ok(value) => {
105
810
                let encoded = reader.read_from(start.index);
106
810
                Ok(Number::Float(Float { value, encoded }))
107
            }
108
            Err(_) => {
109
                let kind = ParseErrorKind::Expecting {
110
                    value: String::from("float"),
111
                };
112
                Err(ParseError::new(start.pos, false, kind))
113
            }
114
        }
115

            
116
    // Integer or BigInteger
117
    } else {
118
3205
        match format!("{sign}{integer_digits}").parse() {
119
3180
            Ok(value) => Ok(Number::Integer(value)),
120
25
            Err(_) => Ok(Number::BigInteger(integer_digits)),
121
        }
122
    }
123
}
124

            
125
#[cfg(test)]
126
mod tests {
127
    use super::*;
128
    use crate::reader::Pos;
129

            
130
    #[test]
131
    fn test_natural() {
132
        let mut reader = Reader::new("0");
133
        assert_eq!(natural(&mut reader).unwrap(), 0);
134
        assert_eq!(reader.cursor().index, 1);
135

            
136
        let mut reader = Reader::new("10x");
137
        assert_eq!(natural(&mut reader).unwrap(), 10);
138
        assert_eq!(reader.cursor().index, 2);
139
    }
140

            
141
    #[test]
142
    fn test_natural_error() {
143
        let mut reader = Reader::new("");
144
        let error = natural(&mut reader).err().unwrap();
145
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
146
        assert_eq!(
147
            error.kind,
148
            ParseErrorKind::Expecting {
149
                value: String::from("natural")
150
            }
151
        );
152
        assert!(error.recoverable);
153

            
154
        let mut reader = Reader::new("01");
155
        let error = natural(&mut reader).err().unwrap();
156
        assert_eq!(error.pos, Pos { line: 1, column: 2 });
157
        assert_eq!(
158
            error.kind,
159
            ParseErrorKind::Expecting {
160
                value: String::from("natural")
161
            }
162
        );
163
        assert!(!error.recoverable);
164

            
165
        let mut reader = Reader::new("x");
166
        let error = natural(&mut reader).err().unwrap();
167
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
168
        assert_eq!(
169
            error.kind,
170
            ParseErrorKind::Expecting {
171
                value: String::from("natural")
172
            }
173
        );
174
        assert!(error.recoverable);
175
    }
176

            
177
    #[test]
178
    fn test_integer() {
179
        let mut reader = Reader::new("0");
180
        assert_eq!(integer(&mut reader).unwrap(), 0);
181
        assert_eq!(reader.cursor().index, 1);
182

            
183
        let mut reader = Reader::new("-1");
184
        assert_eq!(integer(&mut reader).unwrap(), -1);
185
        assert_eq!(reader.cursor().index, 2);
186

            
187
        let mut reader = Reader::new("0");
188
        assert_eq!(number(&mut reader).unwrap(), Number::Integer(0));
189
        assert_eq!(reader.cursor().index, 1);
190

            
191
        let mut reader = Reader::new("10x");
192
        assert_eq!(number(&mut reader).unwrap(), Number::Integer(10));
193
        assert_eq!(reader.cursor().index, 2);
194

            
195
        let mut reader = Reader::new("-10x");
196
        assert_eq!(number(&mut reader).unwrap(), Number::Integer(-10));
197
        assert_eq!(reader.cursor().index, 3);
198
    }
199

            
200
    #[test]
201
    fn test_float() {
202
        let mut reader = Reader::new("1.0");
203
        assert_eq!(
204
            number(&mut reader).unwrap(),
205
            Number::Float(Float {
206
                value: 1.0,
207
                encoded: "1.0".to_string()
208
            })
209
        );
210
        assert_eq!(reader.cursor().index, 3);
211

            
212
        let mut reader = Reader::new("-1.0");
213
        assert_eq!(
214
            number(&mut reader).unwrap(),
215
            Number::Float(Float {
216
                value: -1.0,
217
                encoded: "-1.0".to_string()
218
            })
219
        );
220
        assert_eq!(reader.cursor().index, 4);
221

            
222
        let mut reader = Reader::new("1.1");
223
        assert_eq!(
224
            number(&mut reader).unwrap(),
225
            Number::Float(Float {
226
                value: 1.1,
227
                encoded: "1.1".to_string()
228
            })
229
        );
230
        assert_eq!(reader.cursor().index, 3);
231

            
232
        let mut reader = Reader::new("1.100");
233
        assert_eq!(
234
            number(&mut reader).unwrap(),
235
            Number::Float(Float {
236
                value: 1.1,
237
                encoded: "1.100".to_string()
238
            })
239
        );
240
        assert_eq!(reader.cursor().index, 5);
241

            
242
        let mut reader = Reader::new("1.01");
243
        assert_eq!(
244
            number(&mut reader).unwrap(),
245
            Number::Float(Float {
246
                value: 1.01,
247
                encoded: "1.01".to_string()
248
            })
249
        );
250
        assert_eq!(reader.cursor().index, 4);
251

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

            
262
        // provide more digits than necessary
263
        let mut reader = Reader::new("-0.3333333333333333333");
264
        assert_eq!(
265
            number(&mut reader).unwrap(),
266
            Number::Float(Float {
267
                value: -0.3333333333333333,
268
                encoded: "-0.3333333333333333333".to_string()
269
            })
270
        );
271
        assert_eq!(reader.cursor().index, 22);
272

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

            
284
    #[test]
285
    pub fn test_number_error() {
286
        let mut reader = Reader::new("");
287
        let error = number(&mut reader).err().unwrap();
288
        assert_eq!(
289
            error.kind,
290
            ParseErrorKind::Expecting {
291
                value: String::from("number")
292
            }
293
        );
294
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
295
        assert!(error.recoverable);
296

            
297
        let mut reader = Reader::new("-");
298
        let error = number(&mut reader).err().unwrap();
299
        assert_eq!(
300
            error.kind,
301
            ParseErrorKind::Expecting {
302
                value: String::from("number")
303
            }
304
        );
305
        assert_eq!(error.pos, Pos { line: 1, column: 2 });
306
        assert!(error.recoverable);
307

            
308
        let mut reader = Reader::new("x");
309
        let error = number(&mut reader).err().unwrap();
310
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
311
        assert_eq!(
312
            error.kind,
313
            ParseErrorKind::Expecting {
314
                value: String::from("number")
315
            }
316
        );
317
        assert!(error.recoverable);
318

            
319
        let mut reader = Reader::new("1.");
320
        let error = number(&mut reader).err().unwrap();
321
        assert_eq!(error.pos, Pos { line: 1, column: 3 });
322
        assert_eq!(
323
            error.kind,
324
            ParseErrorKind::Expecting {
325
                value: String::from("decimal digits")
326
            }
327
        );
328
        assert!(!error.recoverable);
329
    }
330
}