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
17900
pub fn predicate(reader: &mut Reader) -> ParseResult<Predicate> {
27
17900
    let (not, space0) = predicate_not(reader);
28
17900
    let func = predicate_func(reader)?;
29
17870
    Ok(Predicate {
30
17870
        not,
31
17870
        space0,
32
17870
        predicate_func: func,
33
17870
    })
34
}
35

            
36
// can not fail
37
17900
fn predicate_not(reader: &mut Reader) -> (bool, Whitespace) {
38
17900
    let save = reader.cursor();
39
17900
    let no_whitespace = Whitespace {
40
17900
        value: String::new(),
41
17900
        source_info: SourceInfo {
42
17900
            start: save.pos,
43
17900
            end: save.pos,
44
17900
        },
45
17900
    };
46
17900
    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
17025
        (false, no_whitespace)
56
    }
57
}
58

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

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

            
104
impl PredicateValue {
105
685
    pub fn is_number(&self) -> bool {
106
685
        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::Placeholder(_))
118
    }
119
}
120

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

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

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

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

            
265
3555
fn start_with_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
266
3555
    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
3015
fn end_with_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
281
3015
    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
2885
fn contain_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
296
2885
    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
2635
fn include_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
311
2635
    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
2320
fn match_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
318
2320
    try_literal("matches", reader)?;
319
340
    let space0 = one_or_more_spaces(reader)?;
320
340
    let save = reader.cursor();
321
340
    let value = predicate_value(reader)?;
322
340
    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
340
    Ok(PredicateFuncValue::Match { space0, value })
330
}
331

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

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

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

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

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

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

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

            
367
1315
fn exist_predicate(reader: &mut Reader) -> ParseResult<PredicateFuncValue> {
368
1315
    try_literal("exists", reader)?;
369
1030
    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::Placeholder(Placeholder {
524
                    space0: Whitespace {
525
                        value: String::new(),
526
                        source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 6)),
527
                    },
528
                    expr: Expr {
529
                        kind: ExprKind::Variable(Variable {
530
                            name: "count".to_string(),
531
                            source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 11)),
532
                        }),
533
                        source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 11)),
534
                    },
535
                    space1: Whitespace {
536
                        value: String::new(),
537
                        source_info: SourceInfo::new(Pos::new(1, 11), Pos::new(1, 11)),
538
                    },
539
                }),
540
                space0: Whitespace {
541
                    value: String::from(" "),
542
                    source_info: SourceInfo::new(Pos::new(1, 3), Pos::new(1, 4)),
543
                },
544
                operator: true,
545
            }
546
        );
547
    }
548

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

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