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::combinator::choice;
20
use crate::parser::error::*;
21
use crate::parser::predicate_value::predicate_value;
22
use crate::parser::primitives::*;
23
use crate::parser::ParseResult;
24
use crate::reader::Reader;
25

            
26
17480
pub fn predicate(reader: &mut Reader) -> ParseResult<Predicate> {
27
17480
    let (not, space0) = predicate_not(reader);
28
17480
    let func = predicate_func(reader)?;
29
17450
    Ok(Predicate {
30
17450
        not,
31
17450
        space0,
32
17450
        predicate_func: func,
33
17450
    })
34
}
35

            
36
// can not fail
37
17480
fn predicate_not(reader: &mut Reader) -> (bool, Whitespace) {
38
17480
    let save = reader.cursor();
39
17480
    let no_whitespace = Whitespace {
40
17480
        value: String::new(),
41
17480
        source_info: SourceInfo {
42
17480
            start: save.pos,
43
17480
            end: save.pos,
44
17480
        },
45
17480
    };
46
17480
    if try_literal("not", reader).is_ok() {
47
875
        match one_or_more_spaces(reader) {
48
875
            Ok(space) => (true, space),
49
            Err(_) => {
50
                reader.seek(save);
51
                (false, no_whitespace)
52
            }
53
        }
54
    } else {
55
16605
        (false, no_whitespace)
56
    }
57
}
58

            
59
17480
fn predicate_func(reader: &mut Reader) -> ParseResult<PredicateFunc> {
60
17480
    let start = reader.cursor();
61
17480
    let value = predicate_func_value(reader)?;
62
17450
    let end = reader.cursor();
63
17450
    Ok(PredicateFunc {
64
17450
        source_info: SourceInfo::new(start.pos, end.pos),
65
17450
        value,
66
17450
    })
67
}
68

            
69
17480
fn predicate_func_value(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
70
17480
    let start = reader.cursor();
71
17480
    match choice(
72
17480
        &[
73
17480
            equal_predicate,
74
17480
            not_equal_predicate,
75
17480
            greater_or_equal_predicate,
76
17480
            greater_predicate,
77
17480
            less_or_equal_predicate,
78
17480
            less_predicate,
79
17480
            start_with_predicate,
80
17480
            end_with_predicate,
81
17480
            contain_predicate,
82
17480
            include_predicate,
83
17480
            match_predicate,
84
17480
            integer_predicate,
85
17480
            float_predicate,
86
17480
            boolean_predicate,
87
17480
            string_predicate,
88
17480
            collection_predicate,
89
17480
            date_predicate,
90
17480
            iso_date_predicate,
91
17480
            exist_predicate,
92
17480
            is_empty_predicate,
93
17480
            is_number_predicate,
94
17480
        ],
95
17480
        reader,
96
17480
    ) {
97
        Err(ParseError {
98
            recoverable: true, ..
99
5
        }) => Err(ParseError::new(start.pos, false, ParseErrorKind::Predicate)),
100
17475
        x => x,
101
    }
102
}
103

            
104
impl PredicateValue {
105
660
    pub fn is_number(&self) -> bool {
106
660
        matches!(self, PredicateValue::Number(_))
107
    }
108
1080
    pub fn is_string(&self) -> bool {
109
1080
        matches!(self, PredicateValue::String(_))
110
    }
111

            
112
440
    pub fn is_bytearray(&self) -> bool {
113
440
        matches!(self, PredicateValue::Hex(_)) | matches!(self, PredicateValue::Base64(_))
114
    }
115

            
116
40
    pub fn is_expression(&self) -> bool {
117
40
        matches!(self, PredicateValue::Expression(_))
118
    }
119
}
120

            
121
17480
fn equal_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
122
17480
    let operator = try_literals("equals", "==", reader)? == "==";
123
13085
    if !operator {
124
5
        eprintln!("'equals' predicate is now deprecated. Use '==' instead");
125
    }
126
13085
    let space0 = if operator {
127
13080
        zero_or_more_spaces(reader)?
128
    } else {
129
5
        one_or_more_spaces(reader)?
130
    };
131
13085
    let value = predicate_value(reader)?;
132
13065
    Ok(PredicateFuncValue::Equal {
133
13065
        space0,
134
13065
        value,
135
13065
        operator,
136
13065
    })
137
}
138

            
139
4395
fn not_equal_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
140
4395
    let operator = try_literals("notEquals", "!=", reader)? == "!=";
141
215
    if !operator {
142
        eprintln!("'notEquals' predicate is now deprecated. Use '!=' instead");
143
    }
144
215
    let space0 = if operator {
145
215
        zero_or_more_spaces(reader)?
146
    } else {
147
        one_or_more_spaces(reader)?
148
    };
149
215
    let value = predicate_value(reader)?;
150
215
    Ok(PredicateFuncValue::NotEqual {
151
215
        space0,
152
215
        value,
153
215
        operator,
154
215
    })
155
}
156

            
157
4125
fn greater_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
158
4125
    let operator = try_literals("greaterThan", ">", reader)? == ">";
159
305
    if !operator {
160
        eprintln!("'greaterThan' predicate is now deprecated. Use '>' instead");
161
    }
162
305
    let space0 = if operator {
163
305
        zero_or_more_spaces(reader)?
164
    } else {
165
        one_or_more_spaces(reader)?
166
    };
167
305
    let start = reader.cursor();
168
305
    let value = predicate_value(reader)?;
169
305
    if value.is_number() || value.is_string() || value.is_expression() {
170
305
        Ok(PredicateFuncValue::GreaterThan {
171
305
            space0,
172
305
            value,
173
305
            operator,
174
305
        })
175
    } else {
176
        Err(ParseError::new(
177
            start.pos,
178
            false,
179
            ParseErrorKind::PredicateValue,
180
        ))
181
    }
182
}
183

            
184
4180
fn greater_or_equal_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
185
4180
    let operator = try_literals("greaterThanOrEquals", ">=", reader)? == ">=";
186
55
    if !operator {
187
        eprintln!("'greaterThanOrEquals' predicate is now deprecated. Use '>=' instead");
188
    }
189
55
    let space0 = if operator {
190
55
        zero_or_more_spaces(reader)?
191
    } else {
192
        one_or_more_spaces(reader)?
193
    };
194
55
    let start = reader.cursor();
195
55
    let value = predicate_value(reader)?;
196
55
    if value.is_number() || value.is_string() || value.is_expression() {
197
55
        Ok(PredicateFuncValue::GreaterThanOrEqual {
198
55
            space0,
199
55
            value,
200
55
            operator,
201
55
        })
202
    } else {
203
        Err(ParseError::new(
204
            start.pos,
205
            false,
206
            ParseErrorKind::PredicateValue,
207
        ))
208
    }
209
}
210

            
211
3715
fn less_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
212
3715
    let operator = try_literals("lessThan", "<", reader)? == "<";
213
195
    if !operator {
214
        eprintln!("'lessThan' predicate is now deprecated. Use '<' instead");
215
    }
216
195
    let space0 = if operator {
217
195
        zero_or_more_spaces(reader)?
218
    } else {
219
        one_or_more_spaces(reader)?
220
    };
221
195
    let start = reader.cursor();
222
195
    let value = predicate_value(reader)?;
223
195
    if value.is_number() || value.is_string() || value.is_expression() {
224
195
        Ok(PredicateFuncValue::LessThan {
225
195
            space0,
226
195
            value,
227
195
            operator,
228
195
        })
229
    } else {
230
        Err(ParseError::new(
231
            start.pos,
232
            false,
233
            ParseErrorKind::PredicateValue,
234
        ))
235
    }
236
}
237

            
238
3820
fn less_or_equal_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
239
3820
    let operator = try_literals("lessThanOrEquals", "<=", reader)? == "<=";
240
105
    if !operator {
241
        eprintln!("'lessThanOrEquals' predicate is now deprecated. Use '<=' instead");
242
    }
243
105
    let space0 = if operator {
244
105
        zero_or_more_spaces(reader)?
245
    } else {
246
        one_or_more_spaces(reader)?
247
    };
248
105
    let start = reader.cursor();
249
105
    let value = predicate_value(reader)?;
250
105
    if value.is_number() || value.is_string() || value.is_expression() {
251
105
        Ok(PredicateFuncValue::LessThanOrEqual {
252
105
            space0,
253
105
            value,
254
105
            operator,
255
105
        })
256
    } else {
257
        Err(ParseError::new(
258
            start.pos,
259
            false,
260
            ParseErrorKind::PredicateValue,
261
        ))
262
    }
263
}
264

            
265
3520
fn start_with_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
266
3520
    try_literal("startsWith", reader)?;
267
540
    let space0 = one_or_more_spaces(reader)?;
268
540
    let save = reader.cursor();
269
540
    let value = predicate_value(reader)?;
270
540
    if !value.is_string() && !value.is_bytearray() {
271
5
        return Err(ParseError::new(
272
5
            save.pos,
273
5
            false,
274
5
            ParseErrorKind::PredicateValue,
275
5
        ));
276
    }
277
535
    Ok(PredicateFuncValue::StartWith { space0, value })
278
}
279

            
280
2980
fn end_with_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
281
2980
    try_literal("endsWith", reader)?;
282
130
    let space0 = one_or_more_spaces(reader)?;
283
130
    let save = reader.cursor();
284
130
    let value = predicate_value(reader)?;
285
130
    if !value.is_string() && !value.is_bytearray() {
286
        return Err(ParseError::new(
287
            save.pos,
288
            false,
289
            ParseErrorKind::PredicateValue,
290
        ));
291
    }
292
130
    Ok(PredicateFuncValue::EndWith { space0, value })
293
}
294

            
295
2850
fn contain_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
296
2850
    try_literal("contains", reader)?;
297
250
    let space0 = one_or_more_spaces(reader)?;
298
250
    let save = reader.cursor();
299
250
    let value = predicate_value(reader)?;
300
250
    if !value.is_string() && !value.is_bytearray() {
301
        return Err(ParseError::new(
302
            save.pos,
303
            false,
304
            ParseErrorKind::PredicateValue,
305
        ));
306
    }
307
250
    Ok(PredicateFuncValue::Contain { space0, value })
308
}
309

            
310
2600
fn include_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
311
2600
    try_literal("includes", reader)?;
312
315
    let space0 = one_or_more_spaces(reader)?;
313
315
    let value = predicate_value(reader)?;
314
315
    Ok(PredicateFuncValue::Include { space0, value })
315
}
316

            
317
2285
fn match_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
318
2285
    try_literal("matches", reader)?;
319
335
    let space0 = one_or_more_spaces(reader)?;
320
335
    let save = reader.cursor();
321
335
    let value = predicate_value(reader)?;
322
335
    if !matches!(value, PredicateValue::String(_)) && !matches!(value, PredicateValue::Regex(_)) {
323
        return Err(ParseError::new(
324
            save.pos,
325
            false,
326
            ParseErrorKind::PredicateValue,
327
        ));
328
    }
329
335
    Ok(PredicateFuncValue::Match { space0, value })
330
}
331

            
332
1950
fn integer_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
333
1950
    try_literal("isInteger", reader)?;
334
70
    Ok(PredicateFuncValue::IsInteger)
335
}
336

            
337
1880
fn float_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
338
1880
    try_literal("isFloat", reader)?;
339
95
    Ok(PredicateFuncValue::IsFloat)
340
}
341

            
342
1785
fn boolean_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
343
1785
    try_literal("isBoolean", reader)?;
344
55
    Ok(PredicateFuncValue::IsBoolean)
345
}
346

            
347
1730
fn string_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
348
1730
    try_literal("isString", reader)?;
349
55
    Ok(PredicateFuncValue::IsString)
350
}
351

            
352
1675
fn collection_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
353
1675
    try_literal("isCollection", reader)?;
354
155
    Ok(PredicateFuncValue::IsCollection)
355
}
356

            
357
1520
fn date_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
358
1520
    try_literal("isDate", reader)?;
359
80
    Ok(PredicateFuncValue::IsDate)
360
}
361

            
362
1440
fn iso_date_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
363
1440
    try_literal("isIsoDate", reader)?;
364
155
    Ok(PredicateFuncValue::IsIsoDate)
365
}
366

            
367
1285
fn exist_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
368
1285
    try_literal("exists", reader)?;
369
1000
    Ok(PredicateFuncValue::Exist)
370
}
371

            
372
285
fn is_empty_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
373
285
    try_literal("isEmpty", reader)?;
374
205
    Ok(PredicateFuncValue::IsEmpty)
375
}
376

            
377
80
fn is_number_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
378
80
    try_literal("isNumber", reader)?;
379
75
    Ok(PredicateFuncValue::IsNumber)
380
}
381

            
382
#[cfg(test)]
383
mod tests {
384
    use super::*;
385
    use crate::reader::Pos;
386

            
387
    #[test]
388
    fn test_predicate_not() {
389
        let mut reader = Reader::new("notXX");
390
        assert_eq!(
391
            predicate_not(&mut reader),
392
            (
393
                false,
394
                Whitespace {
395
                    value: String::new(),
396
                    source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 1)),
397
                }
398
            )
399
        );
400
        assert_eq!(reader.cursor().pos, Pos { line: 1, column: 1 });
401

            
402
        let mut reader = Reader::new("not XX");
403
        assert_eq!(
404
            predicate_not(&mut reader),
405
            (
406
                true,
407
                Whitespace {
408
                    value: String::from(" "),
409
                    source_info: SourceInfo::new(Pos::new(1, 4), Pos::new(1, 5)),
410
                }
411
            )
412
        );
413
        assert_eq!(reader.cursor().pos, Pos { line: 1, column: 5 });
414
    }
415

            
416
    #[test]
417
    fn test_predicate() {
418
        let mut reader = Reader::new("not == true");
419
        assert_eq!(
420
            predicate(&mut reader).unwrap(),
421
            Predicate {
422
                not: true,
423
                space0: Whitespace {
424
                    value: String::from(" "),
425
                    source_info: SourceInfo::new(Pos::new(1, 4), Pos::new(1, 5)),
426
                },
427
                predicate_func: PredicateFunc {
428
                    source_info: SourceInfo::new(Pos::new(1, 5), Pos::new(1, 12)),
429
                    value: PredicateFuncValue::Equal {
430
                        space0: Whitespace {
431
                            value: String::from(" "),
432
                            source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 8)),
433
                        },
434
                        value: PredicateValue::Bool(true),
435
                        operator: true,
436
                    },
437
                },
438
            }
439
        );
440
    }
441

            
442
    #[test]
443
    fn test_predicate_func() {
444
        let mut reader = Reader::new("tata == 1");
445
        let error = predicate_func(&mut reader).err().unwrap();
446
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
447
        assert!(!error.recoverable);
448
        assert_eq!(error.kind, ParseErrorKind::Predicate);
449
    }
450

            
451
    #[test]
452
    fn test_equal_predicate() {
453
        let mut reader = Reader::new("==  true");
454
        assert_eq!(
455
            equal_predicate(&mut reader).unwrap(),
456
            PredicateFuncValue::Equal {
457
                value: PredicateValue::Bool(true),
458
                space0: Whitespace {
459
                    value: String::from("  "),
460
                    source_info: SourceInfo::new(Pos::new(1, 3), Pos::new(1, 5)),
461
                },
462

            
463
                operator: true,
464
            }
465
        );
466

            
467
        let mut reader = Reader::new("== 1.1");
468
        assert_eq!(
469
            equal_predicate(&mut reader).unwrap(),
470
            PredicateFuncValue::Equal {
471
                value: PredicateValue::Number(Number::Float(Float {
472
                    value: 1.1,
473
                    encoded: "1.1".to_string(),
474
                })),
475
                space0: Whitespace {
476
                    value: String::from(" "),
477
                    source_info: SourceInfo::new(Pos::new(1, 3), Pos::new(1, 4)),
478
                },
479
                operator: true,
480
            }
481
        );
482

            
483
        let mut reader = Reader::new("== 2");
484
        assert_eq!(
485
            equal_predicate(&mut reader).unwrap(),
486
            PredicateFuncValue::Equal {
487
                value: PredicateValue::Number(Number::Integer(2)),
488
                space0: Whitespace {
489
                    value: String::from(" "),
490
                    source_info: SourceInfo::new(Pos::new(1, 3), Pos::new(1, 4)),
491
                },
492
                operator: true,
493
            },
494
        );
495

            
496
        let mut reader = Reader::new("== \"Bob\"");
497
        assert_eq!(
498
            equal_predicate(&mut reader).unwrap(),
499
            PredicateFuncValue::Equal {
500
                value: PredicateValue::String(Template {
501
                    delimiter: Some('"'),
502
                    elements: vec![TemplateElement::String {
503
                        value: "Bob".to_string(),
504
                        encoded: "Bob".to_string(),
505
                    }],
506
                    source_info: SourceInfo::new(Pos::new(1, 4), Pos::new(1, 9)),
507
                }),
508
                space0: Whitespace {
509
                    value: String::from(" "),
510
                    source_info: SourceInfo::new(Pos::new(1, 3), Pos::new(1, 4)),
511
                },
512
                operator: true,
513
            }
514
        );
515
    }
516

            
517
    #[test]
518
    fn test_equal_expression_predicate() {
519
        let mut reader = Reader::new("== {{count}}");
520
        assert_eq!(
521
            equal_predicate(&mut reader).unwrap(),
522
            PredicateFuncValue::Equal {
523
                value: PredicateValue::Expression(Expr {
524
                    space0: Whitespace {
525
                        value: String::new(),
526
                        source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 6)),
527
                    },
528
                    variable: Variable {
529
                        name: "count".to_string(),
530
                        source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 11)),
531
                    },
532
                    space1: Whitespace {
533
                        value: String::new(),
534
                        source_info: SourceInfo::new(Pos::new(1, 11), Pos::new(1, 11)),
535
                    },
536
                }),
537
                space0: Whitespace {
538
                    value: String::from(" "),
539
                    source_info: SourceInfo::new(Pos::new(1, 3), Pos::new(1, 4)),
540
                },
541
                operator: true,
542
            }
543
        );
544
    }
545

            
546
    #[test]
547
    fn test_start_with_predicate() {
548
        let mut reader = Reader::new("startsWith 2");
549
        let error = start_with_predicate(&mut reader).err().unwrap();
550
        assert_eq!(
551
            error.pos,
552
            Pos {
553
                line: 1,
554
                column: 12,
555
            }
556
        );
557
        assert!(!error.recoverable);
558
        assert_eq!(error.kind, ParseErrorKind::PredicateValue);
559
    }
560

            
561
    #[test]
562
    fn test_date_predicate() {
563
        let mut reader = Reader::new("isDate");
564
        let result = date_predicate(&mut reader);
565
        assert_eq!(result.unwrap(), PredicateFuncValue::IsDate);
566
    }
567
}