biscuit_parser/
parser.rs

1/*
2 * Copyright (c) 2019 Geoffroy Couprie <contact@geoffroycouprie.com> and Contributors to the Eclipse Foundation.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5use crate::builder::{self, CheckKind, PublicKey};
6use nom::{
7    branch::alt,
8    bytes::complete::{escaped_transform, tag, tag_no_case, take_until, take_while, take_while1},
9    character::{
10        complete::{char, digit1, multispace0 as space0, satisfy},
11        is_alphabetic, is_alphanumeric,
12    },
13    combinator::{consumed, cut, eof, map, map_res, opt, recognize, value},
14    error::{ErrorKind, FromExternalError, ParseError},
15    multi::{many0, separated_list0, separated_list1},
16    sequence::{delimited, pair, preceded, separated_pair, terminated, tuple},
17    IResult, Offset, Parser,
18};
19use std::{
20    collections::{BTreeMap, BTreeSet},
21    convert::TryInto,
22};
23use thiserror::Error;
24
25/// parse a Datalog fact
26pub fn fact(i: &str) -> IResult<&str, builder::Fact, Error> {
27    let (i, fact) = fact_inner(i)?;
28
29    let (i, _) = error(
30        preceded(space0, eof),
31        |input| format!("unexpected trailing data after fact: '{}'", input),
32        " ,\n",
33    )(i)?;
34
35    Ok((i, fact))
36}
37
38pub fn fact_inner(i: &str) -> IResult<&str, builder::Fact, Error> {
39    let (i, _) = space0(i)?;
40    let (i, fact_name) = name(i)?;
41
42    let (i, _) = space0(i)?;
43    let (i, terms) = delimited(
44        char('('),
45        cut(separated_list1(
46            preceded(space0, char(',')),
47            cut(term_in_fact),
48        )),
49        preceded(space0, char(')')),
50    )(i)?;
51
52    Ok((i, builder::Fact::new(fact_name.to_string(), terms)))
53}
54
55/// parse a Datalog check
56pub fn check(i: &str) -> IResult<&str, builder::Check, Error> {
57    let (i, check) = check_inner(i)?;
58
59    let (i, _) = error(
60        preceded(space0, eof),
61        |input| {
62            match input.chars().next() {
63            Some(')') => "unexpected parens".to_string(),
64            _ => format!("expected either the next term after ',' or the next check variant after 'or', but got '{}'",
65                     input)
66        }
67        },
68        " ,\n",
69    )(i)?;
70
71    Ok((i, check))
72}
73
74fn check_inner(i: &str) -> IResult<&str, builder::Check, Error> {
75    let (i, _) = space0(i)?;
76
77    let (i, kind) = alt((
78        map(tag_no_case("check if"), |_| CheckKind::One),
79        map(tag_no_case("check all"), |_| CheckKind::All),
80        map(tag_no_case("reject if"), |_| CheckKind::Reject),
81    ))(i)?;
82
83    let (i, queries) = cut(check_body)(i)?;
84    Ok((i, builder::Check { queries, kind }))
85}
86
87/// parse an allow or deny rule
88pub fn policy(i: &str) -> IResult<&str, builder::Policy, Error> {
89    let (i, policy) = policy_inner(i)?;
90
91    let (i, _) = error(
92        preceded(space0, eof),
93        |input| {
94            match input.chars().next() {
95            Some(')') => "unexpected parens".to_string(),
96            _ => format!("expected either the next term after ',' or the next policy variant after 'or', but got '{}'",
97                     input)
98        }
99        },
100        " ,\n",
101    )(i)?;
102
103    Ok((i, policy))
104}
105
106fn policy_inner(i: &str) -> IResult<&str, builder::Policy, Error> {
107    alt((allow, deny))(i)
108}
109
110/// parse an allow rule
111pub fn allow(i: &str) -> IResult<&str, builder::Policy, Error> {
112    let (i, _) = space0(i)?;
113
114    let (i, _) = tag_no_case("allow if")(i)?;
115
116    let (i, queries) = cut(check_body)(i)?;
117    Ok((
118        i,
119        builder::Policy {
120            queries,
121            kind: builder::PolicyKind::Allow,
122        },
123    ))
124}
125
126/// parse a deny rule
127pub fn deny(i: &str) -> IResult<&str, builder::Policy, Error> {
128    let (i, _) = space0(i)?;
129
130    let (i, _) = tag_no_case("deny if")(i)?;
131
132    let (i, queries) = cut(check_body)(i)?;
133    Ok((
134        i,
135        builder::Policy {
136            queries,
137            kind: builder::PolicyKind::Deny,
138        },
139    ))
140}
141
142/// parse a Datalog check body
143pub fn check_body(i: &str) -> IResult<&str, Vec<builder::Rule>, Error> {
144    let (i, mut queries) = separated_list1(
145        preceded(space0, tag_no_case("or")),
146        preceded(space0, cut(rule_body)),
147    )(i)?;
148
149    let queries = queries
150        .drain(..)
151        .map(|(predicates, expressions, scopes)| {
152            builder::Rule::new(
153                builder::Predicate {
154                    name: "query".to_string(),
155                    terms: Vec::new(),
156                },
157                predicates,
158                expressions,
159                scopes,
160            )
161        })
162        .collect();
163    Ok((i, queries))
164}
165
166/// parse a Datalog rule
167pub fn rule(i: &str) -> IResult<&str, builder::Rule, Error> {
168    let (i, rule) = rule_inner(i)?;
169
170    let (i, _) = error(
171        preceded(space0, eof),
172        |input| match input.chars().next() {
173            Some(')') => "unexpected parens".to_string(),
174            _ => format!(
175                "expected the next term or expression after ',', but got '{}'",
176                input
177            ),
178        },
179        " ,\n",
180    )(i)?;
181
182    Ok((i, rule))
183}
184
185pub fn rule_inner(i: &str) -> IResult<&str, builder::Rule, Error> {
186    let (i, (input, (head, body, expressions, scopes))) = consumed(|i| {
187        let (i, head) = rule_head(i)?;
188        let (i, _) = space0(i)?;
189
190        let (i, _) = tag("<-")(i)?;
191
192        let (i, (body, expressions, scopes)) = cut(rule_body)(i)?;
193
194        Ok((i, (head, body, expressions, scopes)))
195    })(i)?;
196
197    let rule = builder::Rule::new(head, body, expressions, scopes);
198
199    if let Err(message) = rule.validate_variables() {
200        return Err(nom::Err::Failure(Error {
201            input,
202            code: ErrorKind::Satisfy,
203            message: Some(message),
204        }));
205    }
206
207    Ok((i, rule))
208}
209
210fn predicate(i: &str) -> IResult<&str, builder::Predicate, Error> {
211    let (i, _) = space0(i)?;
212    let (i, fact_name) = name(i)?;
213
214    let (i, _) = space0(i)?;
215    let (i, terms) = delimited(
216        char('('),
217        cut(separated_list1(preceded(space0, char(',')), cut(term))),
218        preceded(space0, char(')')),
219    )(i)?;
220
221    Ok((
222        i,
223        builder::Predicate {
224            name: fact_name.to_string(),
225            terms,
226        },
227    ))
228}
229
230fn rule_head(i: &str) -> IResult<&str, builder::Predicate, Error> {
231    let (i, _) = space0(i)?;
232    let (i, fact_name) = name(i)?;
233
234    let (i, _) = space0(i)?;
235    let (i, terms) = delimited(
236        char('('),
237        cut(separated_list0(preceded(space0, char(',')), cut(term))),
238        preceded(space0, char(')')),
239    )(i)?;
240
241    Ok((
242        i,
243        builder::Predicate {
244            name: fact_name.to_string(),
245            terms,
246        },
247    ))
248}
249
250/// parse a Datalog rule body
251pub fn rule_body(
252    i: &str,
253) -> IResult<
254    &str,
255    (
256        Vec<builder::Predicate>,
257        Vec<builder::Expression>,
258        Vec<builder::Scope>,
259    ),
260    Error,
261> {
262    let (i, mut elements) = separated_list1(
263        preceded(space0, char(',')),
264        preceded(space0, cut(predicate_or_expression)),
265    )(i)?;
266
267    let mut predicates = Vec::new();
268    let mut expressions = Vec::new();
269
270    for el in elements.drain(..) {
271        match el {
272            PredOrExpr::P(predicate) => predicates.push(predicate),
273            PredOrExpr::E(expression) => {
274                let ops = expression.opcodes();
275                let e = builder::Expression { ops };
276                expressions.push(e);
277            }
278        }
279    }
280
281    let (i, scopes) = scopes(i)?;
282
283    Ok((i, (predicates, expressions, scopes)))
284}
285
286enum PredOrExpr {
287    P(builder::Predicate),
288    E(Expr),
289}
290
291fn predicate_or_expression(i: &str) -> IResult<&str, PredOrExpr, Error> {
292    reduce(
293        alt((map(predicate, PredOrExpr::P), map(expr, PredOrExpr::E))),
294        ",;",
295    )(i)
296}
297
298fn scopes(i: &str) -> IResult<&str, Vec<builder::Scope>, Error> {
299    if let Ok((i, _)) = preceded(space0, tag::<_, _, ()>("trusting"))(i) {
300        separated_list1(preceded(space0, char(',')), preceded(space0, cut(scope)))(i)
301    } else {
302        Ok((i, vec![]))
303    }
304}
305
306fn scope(i: &str) -> IResult<&str, builder::Scope, Error> {
307    alt((
308        map(tag("authority"), |_| builder::Scope::Authority),
309        map(tag("previous"), |_| builder::Scope::Previous),
310        map(public_key, builder::Scope::PublicKey),
311        map(delimited(char('{'), name, char('}')), |n| {
312            builder::Scope::Parameter(n.to_string())
313        }),
314    ))(i)
315}
316
317pub fn public_key(i: &str) -> IResult<&str, builder::PublicKey, Error> {
318    alt((
319        preceded(tag("ed25519/"), parse_hex).map(|key| PublicKey {
320            key,
321            algorithm: builder::Algorithm::Ed25519,
322        }),
323        preceded(tag("secp256r1/"), parse_hex).map(|key| PublicKey {
324            key,
325            algorithm: builder::Algorithm::Secp256r1,
326        }),
327    ))(i)
328}
329
330#[derive(Debug, PartialEq)]
331pub enum Expr {
332    Value(builder::Term),
333    Unary(builder::Op, Box<Expr>),
334    Binary(builder::Op, Box<Expr>, Box<Expr>),
335    Closure(Vec<String>, Box<Expr>),
336}
337
338impl Expr {
339    pub fn opcodes(self) -> Vec<builder::Op> {
340        let mut v = Vec::new();
341        self.into_opcodes(&mut v);
342        v
343    }
344
345    fn into_opcodes(self, v: &mut Vec<builder::Op>) {
346        match self {
347            Expr::Value(t) => v.push(builder::Op::Value(t)),
348            Expr::Unary(op, expr) => {
349                expr.into_opcodes(v);
350                v.push(op);
351            }
352            Expr::Binary(op, left, right) => {
353                left.into_opcodes(v);
354                right.into_opcodes(v);
355                v.push(op);
356            }
357            Expr::Closure(params, expr) => {
358                let mut ops = vec![];
359                expr.into_opcodes(&mut ops);
360                v.push(builder::Op::Closure(params, ops))
361            }
362        }
363    }
364}
365
366fn unary_negate(i: &str) -> IResult<&str, Expr, Error> {
367    let (i, _) = space0(i)?;
368    let (i, _) = tag("!")(i)?;
369    let (i, _) = space0(i)?;
370    let (i, value) = expr6(i)?;
371
372    Ok((
373        i,
374        Expr::Unary(builder::Op::Unary(builder::Unary::Negate), Box::new(value)),
375    ))
376}
377
378fn unary_parens(i: &str) -> IResult<&str, Expr, Error> {
379    let (i, _) = space0(i)?;
380    let (i, _) = tag("(")(i)?;
381    let (i, _) = space0(i)?;
382    let (i, value) = expr(i)?;
383    let (i, _) = space0(i)?;
384    let (i, _) = tag(")")(i)?;
385
386    Ok((
387        i,
388        Expr::Unary(builder::Op::Unary(builder::Unary::Parens), Box::new(value)),
389    ))
390}
391
392fn binary_op_0(i: &str) -> IResult<&str, builder::Binary, Error> {
393    use builder::Binary;
394    value(Binary::LazyOr, tag("||"))(i)
395}
396
397fn binary_op_1(i: &str) -> IResult<&str, builder::Binary, Error> {
398    use builder::Binary;
399    value(Binary::LazyAnd, tag("&&"))(i)
400}
401
402fn binary_op_2(i: &str) -> IResult<&str, builder::Binary, Error> {
403    use builder::Binary;
404    alt((
405        value(Binary::LessOrEqual, tag("<=")),
406        value(Binary::GreaterOrEqual, tag(">=")),
407        value(Binary::LessThan, tag("<")),
408        value(Binary::GreaterThan, tag(">")),
409        value(Binary::Equal, tag("===")),
410        value(Binary::NotEqual, tag("!==")),
411        value(Binary::HeterogeneousEqual, tag("==")),
412        value(Binary::HeterogeneousNotEqual, tag("!=")),
413    ))(i)
414}
415
416fn binary_op_3(i: &str) -> IResult<&str, builder::Binary, Error> {
417    use builder::Binary;
418    value(Binary::BitwiseXor, tag("^"))(i)
419}
420
421fn binary_op_4(i: &str) -> IResult<&str, builder::Binary, Error> {
422    use builder::Binary;
423    value(Binary::BitwiseOr, tag("|"))(i)
424}
425
426fn binary_op_5(i: &str) -> IResult<&str, builder::Binary, Error> {
427    use builder::Binary;
428    value(Binary::BitwiseAnd, tag("&"))(i)
429}
430
431fn binary_op_6(i: &str) -> IResult<&str, builder::Binary, Error> {
432    use builder::Binary;
433    alt((value(Binary::Add, tag("+")), value(Binary::Sub, tag("-"))))(i)
434}
435
436fn binary_op_7(i: &str) -> IResult<&str, builder::Binary, Error> {
437    use builder::Binary;
438    alt((value(Binary::Mul, tag("*")), value(Binary::Div, tag("/"))))(i)
439}
440
441fn extern_un(i: &str) -> IResult<&str, builder::Unary, Error> {
442    let (i, func) = preceded(tag("extern::"), name)(i)?;
443    Ok((i, builder::Unary::Ffi(func.to_string())))
444}
445
446fn extern_bin(i: &str) -> IResult<&str, builder::Binary, Error> {
447    let (i, func) = preceded(tag("extern::"), name)(i)?;
448    Ok((i, builder::Binary::Ffi(func.to_string())))
449}
450
451fn binary_op_8(i: &str) -> IResult<&str, builder::Binary, Error> {
452    use builder::Binary;
453
454    alt((
455        value(Binary::Contains, tag("contains")),
456        value(Binary::Prefix, tag("starts_with")),
457        value(Binary::Suffix, tag("ends_with")),
458        value(Binary::Regex, tag("matches")),
459        value(Binary::Intersection, tag("intersection")),
460        value(Binary::Union, tag("union")),
461        value(Binary::All, tag("all")),
462        value(Binary::Any, tag("any")),
463        value(Binary::Get, tag("get")),
464        value(Binary::TryOr, tag("try_or")),
465        extern_bin,
466    ))(i)
467}
468
469/// Innermost parser for an expression: either a parenthesised expression,
470/// or a single term.
471fn expr_term(i: &str) -> IResult<&str, Expr, Error> {
472    alt((unary_parens, reduce(map(term, Expr::Value), " ,\n);")))(i)
473}
474
475fn fold_exprs(initial: Expr, remainder: Vec<(builder::Binary, Expr)>) -> Expr {
476    remainder.into_iter().fold(initial, |acc, pair| {
477        let (op, expr) = pair;
478        match op {
479            builder::Binary::LazyAnd | builder::Binary::LazyOr => Expr::Binary(
480                builder::Op::Binary(op),
481                Box::new(acc),
482                Box::new(Expr::Closure(vec![], Box::new(expr))),
483            ),
484            _ => Expr::Binary(builder::Op::Binary(op), Box::new(acc), Box::new(expr)),
485        }
486    })
487}
488
489/// Top-lever parser for an expression. Expression parsers are layered in
490/// order to support operator precedence (see <https://en.wikipedia.org/wiki/Operator-precedence_parser>).
491///
492/// See <https://github.com/biscuit-auth/biscuit/blob/master/SPECIFICATIONS.md#grammar>
493/// for the precedence order of operators in biscuit datalog.
494///
495/// The operators with the lowest precedence are parsed at the outer level,
496/// and their operands delegate to parsers that progressively handle more
497/// tightly binding operators.
498///
499/// This level handles the last operator in the precedence list: `||`
500/// `||` is left associative, so multiple `||` expressions can be combined:
501/// `a || b || c <=> (a || b) || c`
502pub fn expr(i: &str) -> IResult<&str, Expr, Error> {
503    let (i, initial) = expr1(i)?;
504
505    let (i, remainder) = many0(tuple((preceded(space0, binary_op_0), expr1)))(i)?;
506
507    Ok((i, fold_exprs(initial, remainder)))
508}
509
510/// This level handles `&&`
511/// `&&` is left associative, so multiple `&&` expressions can be combined:
512/// `a && b && c <=> (a && b) && c`
513fn expr1(i: &str) -> IResult<&str, Expr, Error> {
514    let (i, initial) = expr2(i)?;
515
516    let (i, remainder) = many0(tuple((preceded(space0, binary_op_1), expr2)))(i)?;
517
518    Ok((i, fold_exprs(initial, remainder)))
519}
520
521/// This level handles comparison operators (`==`, `>`, `>=`, `<`, `<=`).
522/// Those operators are _not_ associative and require explicit grouping
523/// with parentheses.
524fn expr2(i: &str) -> IResult<&str, Expr, Error> {
525    let (i, initial) = expr3(i)?;
526
527    if let Ok((i, (op, remainder))) = tuple((preceded(space0, binary_op_2), expr3))(i) {
528        Ok((
529            i,
530            Expr::Binary(
531                builder::Op::Binary(op),
532                Box::new(initial),
533                Box::new(remainder),
534            ),
535        ))
536    } else {
537        Ok((i, initial))
538    }
539}
540
541/// This level handles `|`.
542/// It is left associative, so multiple expressions can be combined:
543/// `a | b | c <=> (a | b) | c`
544fn expr3(i: &str) -> IResult<&str, Expr, Error> {
545    let (i, initial) = expr4(i)?;
546
547    let (i, remainder) = many0(tuple((preceded(space0, binary_op_3), expr4)))(i)?;
548
549    Ok((i, fold_exprs(initial, remainder)))
550}
551
552/// This level handles `^`.
553/// It is left associative, so multiple expressions can be combined:
554/// `a ^ b ^ c <=> (a ^ b) ^ c`
555fn expr4(i: &str) -> IResult<&str, Expr, Error> {
556    let (i, initial) = expr5(i)?;
557
558    let (i, remainder) = many0(tuple((preceded(space0, binary_op_4), expr5)))(i)?;
559
560    Ok((i, fold_exprs(initial, remainder)))
561}
562
563/// This level handles `&`.
564/// It is left associative, so multiple expressions can be combined:
565/// `a & b & c <=> (a & b) & c`
566fn expr5(i: &str) -> IResult<&str, Expr, Error> {
567    let (i, initial) = expr6(i)?;
568
569    let (i, remainder) = many0(tuple((preceded(space0, binary_op_5), expr6)))(i)?;
570
571    Ok((i, fold_exprs(initial, remainder)))
572}
573
574/// This level handles `+` and `-`.
575/// They are left associative, so multiple expressions can be combined:
576/// `a + b - c <=> (a + b) - c`
577fn expr6(i: &str) -> IResult<&str, Expr, Error> {
578    let (i, initial) = expr7(i)?;
579
580    let (i, remainder) = many0(tuple((preceded(space0, binary_op_6), expr7)))(i)?;
581
582    Ok((i, fold_exprs(initial, remainder)))
583}
584
585/// This level handles `*` and `/`.
586/// They are left associative, so multiple expressions can be combined:
587/// `a * b / c <=> (a * b) / c`
588fn expr7(i: &str) -> IResult<&str, Expr, Error> {
589    let (i, initial) = expr8(i)?;
590
591    let (i, remainder) = many0(tuple((preceded(space0, binary_op_7), expr8)))(i)?;
592
593    Ok((i, fold_exprs(initial, remainder)))
594}
595
596/// This level handles `!` (prefix negation)
597fn expr8(i: &str) -> IResult<&str, Expr, Error> {
598    alt((unary_negate, expr9))(i)
599}
600
601/// This level handles methods. Methods can take either zero or one
602/// argument in addition to the expression they are called on.
603/// The name of the method decides its arity.
604fn expr9(i: &str) -> IResult<&str, Expr, Error> {
605    let (mut input, mut initial) = expr_term(i)?;
606
607    loop {
608        if let Ok((i, _)) = char::<_, ()>('.')(input) {
609            let bin_result = binary_method(i);
610            let un_result = unary_method(i);
611            match (bin_result, un_result) {
612                (Ok((i, (op, params, arg))), _) => {
613                    input = i;
614                    match (params, &op) {
615                        (_, builder::Binary::TryOr) => {
616                            initial = Expr::Binary(
617                                builder::Op::Binary(op),
618                                Box::new(Expr::Closure(vec![], Box::new(initial))),
619                                Box::new(arg),
620                            );
621                        }
622                        (Some(params), _) => {
623                            initial = Expr::Binary(
624                                builder::Op::Binary(op),
625                                Box::new(initial),
626                                Box::new(Expr::Closure(params, Box::new(arg))),
627                            );
628                        }
629                        (None, _) => {
630                            initial = Expr::Binary(
631                                builder::Op::Binary(op),
632                                Box::new(initial),
633                                Box::new(arg),
634                            );
635                        }
636                    }
637                }
638                (_, Ok((i, op))) => {
639                    input = i;
640
641                    initial = Expr::Unary(builder::Op::Unary(op), Box::new(initial));
642                }
643                (_, Err(e)) => return Err(e),
644            }
645        } else {
646            return Ok((input, initial));
647        }
648    }
649}
650
651fn binary_method(i: &str) -> IResult<&str, (builder::Binary, Option<Vec<String>>, Expr), Error> {
652    let (i, op) = binary_op_8(i)?;
653
654    let (i, _) = char('(')(i)?;
655    let (i, _) = space0(i)?;
656    // we only support a single argument for now
657    match op {
658        builder::Binary::All | builder::Binary::Any => {
659            let (i, param) = preceded(char('$'), name)(i)?;
660            let (i, _) = space0(i)?;
661            let (i, _) = tag("->")(i)?;
662            let (i, _) = space0(i)?;
663            let (i, arg) = expr(i)?;
664            let (i, _) = space0(i)?;
665            let (i, _) = char(')')(i)?;
666            Ok((i, (op, Some(vec![param.to_owned()]), arg)))
667        }
668        _ => {
669            let (i, arg) = expr(i)?;
670            let (i, _) = space0(i)?;
671            let (i, _) = char(')')(i)?;
672
673            Ok((i, (op, None, arg)))
674        }
675    }
676}
677
678fn unary_method(i: &str) -> IResult<&str, builder::Unary, Error> {
679    use builder::Unary;
680    let (i, op) = alt((
681        value(Unary::Length, tag("length")),
682        value(Unary::TypeOf, tag("type")),
683        extern_un,
684    ))(i)?;
685
686    let (i, _) = char('(')(i)?;
687    let (i, _) = space0(i)?;
688    let (i, _) = char(')')(i)?;
689
690    Ok((i, op))
691}
692
693fn name(i: &str) -> IResult<&str, &str, Error> {
694    let is_name_char = |c: char| is_alphanumeric(c as u8) || c == '_' || c == ':';
695
696    reduce(take_while1(is_name_char), " ,:(\n;")(i)
697}
698
699fn parameter_name(i: &str) -> IResult<&str, &str, Error> {
700    let is_name_char = |c: char| is_alphanumeric(c as u8) || c == '_' || c == ':';
701
702    error(
703        recognize(preceded(
704            satisfy(|c: char| is_alphabetic(c as u8)),
705            take_while(is_name_char),
706        )),
707        |_| {
708            "invalid parameter name: it must start with an alphabetic character, followed by alphanumeric characters, underscores or colons".to_string()
709        },
710        " ,:(\n;",
711    )(i)
712}
713
714fn printable(i: &str) -> IResult<&str, &str, Error> {
715    take_while1(|c: char| c != '\\' && c != '"')(i)
716}
717
718fn parse_string_internal(i: &str) -> IResult<&str, String, Error> {
719    escaped_transform(
720        printable,
721        '\\',
722        alt((
723            map(char('\\'), |_| "\\"),
724            map(char('"'), |_| "\""),
725            map(char('n'), |_| "\n"),
726        )),
727    )(i)
728}
729
730fn parse_string(i: &str) -> IResult<&str, String, Error> {
731    alt((
732        value("".to_string(), tag("\"\"")),
733        delimited(char('"'), parse_string_internal, char('"')),
734    ))(i)
735}
736
737fn string(i: &str) -> IResult<&str, builder::Term, Error> {
738    parse_string(i).map(|(i, s)| (i, builder::Term::Str(s)))
739}
740
741fn parse_integer(i: &str) -> IResult<&str, i64, Error> {
742    map_res(recognize(pair(opt(char('-')), digit1)), |s: &str| s.parse())(i)
743}
744
745fn integer(i: &str) -> IResult<&str, builder::Term, Error> {
746    parse_integer(i).map(|(i, n)| (i, builder::int(n)))
747}
748
749fn parse_date(i: &str) -> IResult<&str, u64, Error> {
750    map_res(
751        map_res(
752            take_while1(|c: char| {
753                c != ',' && c != ' ' && c != ')' && c != ']' && c != ';' && c != '}'
754            }),
755            |s| time::OffsetDateTime::parse(s, &time::format_description::well_known::Rfc3339),
756        ),
757        |t| t.unix_timestamp().try_into(),
758    )(i)
759}
760
761fn date(i: &str) -> IResult<&str, builder::Term, Error> {
762    parse_date(i).map(|(i, t)| (i, builder::Term::Date(t)))
763}
764
765fn parse_bytes(i: &str) -> IResult<&str, Vec<u8>, Error> {
766    preceded(tag("hex:"), parse_hex)(i)
767}
768
769fn parse_hex(i: &str) -> IResult<&str, Vec<u8>, Error> {
770    map_res(
771        take_while1(|c| {
772            let c = c as u8;
773            c.is_ascii_digit() || (b'a'..=b'f').contains(&c) || (b'A'..=b'F').contains(&c)
774        }),
775        hex::decode,
776    )(i)
777}
778
779fn bytes(i: &str) -> IResult<&str, builder::Term, Error> {
780    parse_bytes(i).map(|(i, s)| (i, builder::Term::Bytes(s)))
781}
782
783fn variable(i: &str) -> IResult<&str, builder::Term, Error> {
784    map(preceded(char('$'), name), builder::variable)(i)
785}
786
787fn parameter(i: &str) -> IResult<&str, builder::Term, Error> {
788    map(
789        delimited(char('{'), parameter_name, char('}')),
790        builder::parameter,
791    )(i)
792}
793
794fn parse_bool(i: &str) -> IResult<&str, bool, Error> {
795    alt((value(true, tag("true")), value(false, tag("false"))))(i)
796}
797
798fn boolean(i: &str) -> IResult<&str, builder::Term, Error> {
799    parse_bool(i).map(|(i, b)| (i, builder::boolean(b)))
800}
801
802fn null(i: &str) -> IResult<&str, builder::Term, Error> {
803    tag("null")(i).map(|(i, _)| (i, builder::null()))
804}
805
806fn set(i: &str) -> IResult<&str, builder::Term, Error> {
807    alt((empty_set, non_empty_set))(i)
808}
809
810fn empty_set(i: &str) -> IResult<&str, builder::Term, Error> {
811    tag("{,}")(i).map(|(i, _)| (i, builder::set(BTreeSet::new())))
812}
813
814fn non_empty_set(i: &str) -> IResult<&str, builder::Term, Error> {
815    let (i, _) = preceded(space0, char('{'))(i)?;
816    let (i, mut list) = cut(separated_list1(preceded(space0, char(',')), term_in_set))(i)?;
817
818    let mut set = BTreeSet::new();
819
820    let mut kind: Option<u8> = None;
821    for term in list.drain(..) {
822        let index = match term {
823            builder::Term::Variable(_) => {
824                return Err(nom::Err::Failure(Error {
825                    input: i,
826                    code: ErrorKind::Fail,
827                    message: Some("variables are not permitted in sets".to_string()),
828                }))
829            }
830            builder::Term::Integer(_) => 2,
831            builder::Term::Str(_) => 3,
832            builder::Term::Date(_) => 4,
833            builder::Term::Bytes(_) => 5,
834            builder::Term::Bool(_) => 6,
835            builder::Term::Set(_) => {
836                return Err(nom::Err::Failure(Error {
837                    input: i,
838                    code: ErrorKind::Fail,
839                    message: Some("sets cannot contain other sets".to_string()),
840                }))
841            }
842            builder::Term::Parameter(_) => 7,
843            builder::Term::Null => 8,
844            builder::Term::Array(_) => 9,
845            builder::Term::Map(_) => 10,
846        };
847
848        if let Some(k) = kind {
849            if k != index {
850                return Err(nom::Err::Failure(Error {
851                    input: i,
852                    code: ErrorKind::Fail,
853                    message: Some("set elements must have the same type".to_string()),
854                }));
855            }
856        } else {
857            kind = Some(index);
858        }
859
860        set.insert(term);
861    }
862
863    let (i, _) = preceded(space0, char('}'))(i)?;
864
865    Ok((i, builder::set(set)))
866}
867
868fn array(i: &str) -> IResult<&str, builder::Term, Error> {
869    let (i, _) = preceded(space0, char('['))(i)?;
870    let (i, array) = cut(separated_list0(preceded(space0, char(',')), term_in_fact))(i)?;
871    let (i, _) = preceded(space0, char(']'))(i)?;
872
873    Ok((i, builder::array(array)))
874}
875
876fn parse_map(i: &str) -> IResult<&str, builder::Term, Error> {
877    let (i, _) = preceded(space0, char('{'))(i)?;
878    let (i, mut list) = cut(separated_list0(
879        preceded(space0, char(',')),
880        separated_pair(map_key, preceded(space0, char(':')), term_in_fact),
881    ))(i)?;
882
883    let mut map = BTreeMap::new();
884
885    for (key, term) in list.drain(..) {
886        map.insert(key, term);
887    }
888
889    let (i, _) = preceded(space0, char('}'))(i)?;
890
891    Ok((i, builder::map(map)))
892}
893
894fn map_key(i: &str) -> IResult<&str, builder::MapKey, Error> {
895    preceded(
896        space0,
897        alt((
898            map(delimited(char('{'), parameter_name, char('}')), |s| {
899                builder::MapKey::Parameter(s.to_string())
900            }),
901            map(parse_string, |s| builder::MapKey::Str(s.to_string())),
902            map(parse_integer, builder::MapKey::Integer),
903        )),
904    )(i)
905}
906
907fn term(i: &str) -> IResult<&str, builder::Term, Error> {
908    preceded(
909        space0,
910        alt((
911            parameter, string, date, variable, integer, bytes, boolean, null, array, parse_map, set,
912        )),
913    )(i)
914}
915
916fn term_in_fact(i: &str) -> IResult<&str, builder::Term, Error> {
917    preceded(
918        space0,
919        error(
920            alt((
921                parameter, string, date, integer, bytes, boolean, null, set, array, parse_map,
922            )),
923            |input| match input.chars().next() {
924                None | Some(',') | Some(')') => "missing term".to_string(),
925                Some('$') => "variables are not allowed in facts".to_string(),
926                _ => "expected a valid term".to_string(),
927            },
928            " ,)\n;",
929        ),
930    )(i)
931}
932
933fn term_in_set(i: &str) -> IResult<&str, builder::Term, Error> {
934    preceded(
935        space0,
936        error(
937            alt((
938                parameter, string, date, integer, bytes, boolean, null, parse_map,
939            )),
940            |input| match input.chars().next() {
941                None | Some(',') | Some('}') => "missing term".to_string(),
942                Some('$') => "variables are not allowed in sets".to_string(),
943                _ => "expected a valid term".to_string(),
944            },
945            " ,}\n;",
946        ),
947    )(i)
948}
949
950fn line_comment(i: &str) -> IResult<&str, (), Error> {
951    let (i, _) = space0(i)?;
952    let (i, _) = tag("//")(i)?;
953    let (i, _) = take_while(|c| c != '\r' && c != '\n')(i)?;
954    let (i, _) = alt((tag("\n"), tag("\r\n"), eof))(i)?;
955
956    Ok((i, ()))
957}
958
959fn multiline_comment(i: &str) -> IResult<&str, (), Error> {
960    let (i, _) = space0(i)?;
961    let (i, _) = tag("/*")(i)?;
962    let (i, _) = take_until("*/")(i)?;
963    let (i, _) = tag("*/")(i)?;
964
965    Ok((i, ()))
966}
967
968#[derive(Clone, Debug, PartialEq, Default)]
969pub struct SourceResult<'a> {
970    pub scopes: Vec<builder::Scope>,
971    pub facts: Vec<(&'a str, builder::Fact)>,
972    pub rules: Vec<(&'a str, builder::Rule)>,
973    pub checks: Vec<(&'a str, builder::Check)>,
974    pub policies: Vec<(&'a str, builder::Policy)>,
975}
976
977enum SourceElement<'a> {
978    Fact(&'a str, builder::Fact),
979    Rule(&'a str, builder::Rule),
980    Check(&'a str, builder::Check),
981    Policy(&'a str, builder::Policy),
982    Comment,
983}
984
985pub fn sep(i: &str) -> IResult<&str, &str, Error> {
986    let (i, _) = space0(i)?;
987    alt((tag(";"), eof))(i)
988}
989
990pub fn parse_source(mut i: &str) -> Result<SourceResult, Vec<Error>> {
991    let mut result = SourceResult::default();
992    let mut errors = Vec::new();
993
994    loop {
995        if i.is_empty() {
996            if errors.is_empty() {
997                return Ok(result);
998            } else {
999                return Err(errors);
1000            }
1001        }
1002
1003        match terminated(
1004            alt((
1005                map(terminated(consumed(rule_inner), sep), |(i, r)| {
1006                    SourceElement::Rule(i, r)
1007                }),
1008                map(terminated(consumed(fact_inner), sep), |(i, f)| {
1009                    SourceElement::Fact(i, f)
1010                }),
1011                map(terminated(consumed(check_inner), sep), |(i, c)| {
1012                    SourceElement::Check(i, c)
1013                }),
1014                map(terminated(consumed(policy_inner), sep), |(i, p)| {
1015                    SourceElement::Policy(i, p)
1016                }),
1017                map(line_comment, |_| SourceElement::Comment),
1018                map(multiline_comment, |_| SourceElement::Comment),
1019            )),
1020            space0,
1021        )(i)
1022        {
1023            Ok((i2, o)) => {
1024                match o {
1025                    SourceElement::Fact(i, f) => result.facts.push((i, f)),
1026                    SourceElement::Rule(i, r) => result.rules.push((i, r)),
1027                    SourceElement::Check(i, c) => result.checks.push((i, c)),
1028                    SourceElement::Policy(i, p) => result.policies.push((i, p)),
1029                    SourceElement::Comment => {}
1030                }
1031
1032                i = i2;
1033            }
1034            Err(nom::Err::Incomplete(_)) => panic!(),
1035            Err(nom::Err::Error(mut e)) => {
1036                if let Some(index) = e.input.find(|c| c == ';') {
1037                    e.input = &(e.input)[..index];
1038                }
1039
1040                let offset = i.offset(e.input);
1041                if let Some(index) = &i[offset..].find(|c| c == ';') {
1042                    i = &i[offset + index + 1..];
1043                } else {
1044                    i = &i[i.len()..];
1045                }
1046
1047                errors.push(e);
1048            }
1049            Err(nom::Err::Failure(mut e)) => {
1050                if let Some(index) = e.input.find(|c| c == ';') {
1051                    e.input = &(e.input)[..index];
1052                }
1053
1054                let offset = i.offset(e.input);
1055                if let Some(index) = &i[offset..].find(|c| c == ';') {
1056                    i = &i[offset + index + 1..];
1057                } else {
1058                    i = &i[i.len()..];
1059                }
1060
1061                errors.push(e);
1062            }
1063        }
1064    }
1065}
1066
1067pub fn parse_block_source(mut i: &str) -> Result<SourceResult, Vec<Error>> {
1068    let mut result = SourceResult::default();
1069    let mut errors = Vec::new();
1070
1071    match opt(terminated(consumed(scopes), sep))(i) {
1072        Ok((i2, opt_scopes)) => {
1073            if let Some((_, scopes)) = opt_scopes {
1074                i = i2;
1075                result.scopes = scopes;
1076            }
1077        }
1078        Err(nom::Err::Incomplete(_)) => panic!(),
1079        Err(nom::Err::Error(mut e)) => {
1080            if let Some(index) = e.input.find(|c| c == ';') {
1081                e.input = &(e.input)[..index];
1082            }
1083
1084            let offset = i.offset(e.input);
1085            if let Some(index) = &i[offset..].find(|c| c == ';') {
1086                i = &i[offset + index + 1..];
1087            } else {
1088                i = &i[i.len()..];
1089            }
1090
1091            errors.push(e);
1092        }
1093        Err(nom::Err::Failure(mut e)) => {
1094            if let Some(index) = e.input.find(|c| c == ';') {
1095                e.input = &(e.input)[..index];
1096            }
1097
1098            let offset = i.offset(e.input);
1099            if let Some(index) = &i[offset..].find(|c| c == ';') {
1100                i = &i[offset + index + 1..];
1101            } else {
1102                i = &i[i.len()..];
1103            }
1104
1105            errors.push(e);
1106        }
1107    }
1108
1109    loop {
1110        if i.is_empty() {
1111            if errors.is_empty() {
1112                return Ok(result);
1113            } else {
1114                return Err(errors);
1115            }
1116        }
1117
1118        match terminated(
1119            alt((
1120                map(terminated(consumed(rule_inner), sep), |(i, r)| {
1121                    SourceElement::Rule(i, r)
1122                }),
1123                map(terminated(consumed(fact_inner), sep), |(i, f)| {
1124                    SourceElement::Fact(i, f)
1125                }),
1126                map(terminated(consumed(check_inner), sep), |(i, c)| {
1127                    SourceElement::Check(i, c)
1128                }),
1129                map(line_comment, |_| SourceElement::Comment),
1130                map(multiline_comment, |_| SourceElement::Comment),
1131            )),
1132            space0,
1133        )(i)
1134        {
1135            Ok((i2, o)) => {
1136                match o {
1137                    SourceElement::Fact(i, f) => result.facts.push((i, f)),
1138                    SourceElement::Rule(i, r) => result.rules.push((i, r)),
1139                    SourceElement::Check(i, c) => result.checks.push((i, c)),
1140                    SourceElement::Policy(_, _) => {}
1141                    SourceElement::Comment => {}
1142                }
1143
1144                i = i2;
1145            }
1146            Err(nom::Err::Incomplete(_)) => panic!(),
1147            Err(nom::Err::Error(mut e)) => {
1148                if let Some(index) = e.input.find(|c| c == ';') {
1149                    e.input = &(e.input)[..index];
1150                }
1151
1152                let offset = i.offset(e.input);
1153                if let Some(index) = &i[offset..].find(|c| c == ';') {
1154                    i = &i[offset + index + 1..];
1155                } else {
1156                    i = &i[i.len()..];
1157                }
1158
1159                errors.push(e);
1160            }
1161            Err(nom::Err::Failure(mut e)) => {
1162                if let Some(index) = e.input.find(|c| c == ';') {
1163                    e.input = &(e.input)[..index];
1164                }
1165
1166                let offset = i.offset(e.input);
1167                if let Some(index) = &i[offset..].find(|c| c == ';') {
1168                    i = &i[offset + index + 1..];
1169                } else {
1170                    i = &i[i.len()..];
1171                }
1172
1173                errors.push(e);
1174            }
1175        }
1176    }
1177}
1178
1179#[derive(Error, Debug, PartialEq, Eq)]
1180#[error("Parse error on input: {input}. Message: {message:?}")]
1181pub struct Error<'a> {
1182    pub input: &'a str,
1183    pub code: ErrorKind,
1184    pub message: Option<String>,
1185}
1186
1187impl<'a> ParseError<&'a str> for Error<'a> {
1188    fn from_error_kind(input: &'a str, kind: ErrorKind) -> Self {
1189        Self {
1190            input,
1191            code: kind,
1192            message: None,
1193        }
1194    }
1195
1196    fn append(_: &'a str, _: ErrorKind, other: Self) -> Self {
1197        other
1198    }
1199}
1200
1201//FIXME: properly handle other errors
1202impl<'a, E> FromExternalError<&'a str, E> for Error<'a> {
1203    fn from_external_error(input: &'a str, kind: ErrorKind, _e: E) -> Self {
1204        Self {
1205            input,
1206            code: kind,
1207            message: None,
1208        }
1209    }
1210}
1211
1212fn error<'a, F, O, P>(
1213    mut parser: P,
1214    context: F,
1215    reducer: &'static str,
1216) -> impl FnMut(&'a str) -> IResult<&'a str, O, Error<'a>>
1217where
1218    P: nom::Parser<&'a str, O, Error<'a>>,
1219    F: Fn(&'a str) -> String,
1220{
1221    move |i: &str| match parser.parse(i) {
1222        Ok(res) => Ok(res),
1223        Err(nom::Err::Incomplete(i)) => Err(nom::Err::Incomplete(i)),
1224        Err(nom::Err::Error(mut e)) => {
1225            if let Some(index) = e.input.find(|c| reducer.contains(c)) {
1226                e.input = &(e.input)[..index];
1227            }
1228
1229            if e.message.is_none() {
1230                e.message = Some(context(e.input));
1231            }
1232
1233            Err(nom::Err::Error(e))
1234        }
1235        Err(nom::Err::Failure(mut e)) => {
1236            if let Some(index) = e.input.find(|c| reducer.contains(c)) {
1237                e.input = &(e.input)[..index];
1238            }
1239
1240            if e.message.is_none() {
1241                e.message = Some(context(e.input));
1242            }
1243
1244            Err(nom::Err::Failure(e))
1245        }
1246    }
1247}
1248
1249fn reduce<'a, O, P>(
1250    mut parser: P,
1251    reducer: &'static str,
1252) -> impl FnMut(&'a str) -> IResult<&'a str, O, Error<'a>>
1253where
1254    P: nom::Parser<&'a str, O, Error<'a>>,
1255{
1256    move |i: &str| match parser.parse(i) {
1257        Ok(res) => Ok(res),
1258        Err(nom::Err::Incomplete(i)) => Err(nom::Err::Incomplete(i)),
1259        Err(nom::Err::Error(mut e)) => {
1260            if let Some(index) = e.input.find(|c| reducer.contains(c)) {
1261                e.input = &(e.input)[..index];
1262            }
1263
1264            Err(nom::Err::Error(e))
1265        }
1266        Err(nom::Err::Failure(mut e)) => {
1267            if let Some(index) = e.input.find(|c| reducer.contains(c)) {
1268                e.input = &(e.input)[..index];
1269            }
1270
1271            Err(nom::Err::Failure(e))
1272        }
1273    }
1274}
1275
1276#[cfg(test)]
1277mod tests {
1278    use nom::error::ErrorKind;
1279
1280    use crate::{
1281        builder::{self, array, int, var, Binary, CheckKind, Op, Unary},
1282        parser::Error,
1283    };
1284
1285    #[test]
1286    fn name() {
1287        assert_eq!(
1288            super::name("operation(\"read\")"),
1289            Ok(("(\"read\")", "operation"))
1290        );
1291    }
1292
1293    #[test]
1294    fn string() {
1295        assert_eq!(
1296            super::string("\"file1 a hello - 123_\""),
1297            Ok(("", builder::string("file1 a hello - 123_")))
1298        );
1299    }
1300
1301    #[test]
1302    fn empty_string() {
1303        assert_eq!(super::string("\"\""), Ok(("", builder::string(""))));
1304    }
1305
1306    #[test]
1307    fn integer() {
1308        assert_eq!(super::integer("123"), Ok(("", builder::int(123))));
1309        assert_eq!(super::integer("-42"), Ok(("", builder::int(-42))));
1310    }
1311
1312    #[test]
1313    fn date() {
1314        assert_eq!(
1315            super::date("2019-12-02T13:49:53Z"),
1316            Ok(("", builder::Term::Date(1575294593)))
1317        );
1318    }
1319
1320    #[test]
1321    fn variable() {
1322        assert_eq!(super::variable("$1"), Ok(("", builder::variable("1"))));
1323    }
1324
1325    #[test]
1326    fn parameter() {
1327        assert_eq!(
1328            super::parameter("{param}"),
1329            Ok(("", builder::parameter("param")))
1330        );
1331
1332        assert_eq!(
1333            super::parameter("{1param}"),
1334            Err(nom::Err::Error(crate::parser::Error {
1335                input: "1param}",
1336                code: nom::error::ErrorKind::Satisfy,
1337                message:  Some("invalid parameter name: it must start with an alphabetic character, followed by alphanumeric characters, underscores or colons".to_string())
1338            }))
1339        );
1340
1341        assert_eq!(super::parameter("{p}"), Ok(("", builder::parameter("p"))));
1342    }
1343
1344    #[test]
1345    fn constraint() {
1346        use builder::{boolean, date, int, set, string, var, Binary, Op, Unary};
1347        use std::collections::BTreeSet;
1348        use std::time::{Duration, SystemTime};
1349
1350        assert_eq!(
1351            super::expr("$0 <= 2030-12-31T12:59:59+00:00").map(|(i, o)| (i, o.opcodes())),
1352            Ok((
1353                "",
1354                vec![
1355                    Op::Value(var("0")),
1356                    Op::Value(date(
1357                        &(SystemTime::UNIX_EPOCH + Duration::from_secs(1924952399))
1358                    )),
1359                    Op::Binary(Binary::LessOrEqual),
1360                ],
1361            ))
1362        );
1363
1364        assert_eq!(
1365            super::expr("$0 >= 2030-12-31T12:59:59+00:00").map(|(i, o)| (i, o.opcodes())),
1366            Ok((
1367                "",
1368                vec![
1369                    Op::Value(var("0")),
1370                    Op::Value(date(
1371                        &(SystemTime::UNIX_EPOCH + Duration::from_secs(1924952399))
1372                    )),
1373                    Op::Binary(Binary::GreaterOrEqual),
1374                ],
1375            ))
1376        );
1377
1378        assert_eq!(
1379            super::expr("$0 < 1234").map(|(i, o)| (i, o.opcodes())),
1380            Ok((
1381                "",
1382                vec![
1383                    Op::Value(var("0")),
1384                    Op::Value(int(1234)),
1385                    Op::Binary(Binary::LessThan),
1386                ],
1387            ))
1388        );
1389
1390        assert_eq!(
1391            super::expr("$0 > 1234").map(|(i, o)| (i, o.opcodes())),
1392            Ok((
1393                "",
1394                vec![
1395                    Op::Value(var("0")),
1396                    Op::Value(int(1234)),
1397                    Op::Binary(Binary::GreaterThan),
1398                ],
1399            ))
1400        );
1401
1402        assert_eq!(
1403            super::expr("$0 <= 1234").map(|(i, o)| (i, o.opcodes())),
1404            Ok((
1405                "",
1406                vec![
1407                    Op::Value(var("0")),
1408                    Op::Value(int(1234)),
1409                    Op::Binary(Binary::LessOrEqual),
1410                ],
1411            ))
1412        );
1413
1414        assert_eq!(
1415            super::expr("$0 >= -1234").map(|(i, o)| (i, o.opcodes())),
1416            Ok((
1417                "",
1418                vec![
1419                    Op::Value(var("0")),
1420                    Op::Value(int(-1234)),
1421                    Op::Binary(Binary::GreaterOrEqual),
1422                ],
1423            ))
1424        );
1425
1426        assert_eq!(
1427            super::expr("$0 === 1").map(|(i, o)| (i, o.opcodes())),
1428            Ok((
1429                "",
1430                vec![
1431                    Op::Value(var("0")),
1432                    Op::Value(int(1)),
1433                    Op::Binary(Binary::Equal),
1434                ],
1435            ))
1436        );
1437
1438        assert_eq!(
1439            super::expr("$0 == 1").map(|(i, o)| (i, o.opcodes())),
1440            Ok((
1441                "",
1442                vec![
1443                    Op::Value(var("0")),
1444                    Op::Value(int(1)),
1445                    Op::Binary(Binary::HeterogeneousEqual),
1446                ],
1447            ))
1448        );
1449
1450        assert_eq!(
1451            super::expr("$0 !== 1").map(|(i, o)| (i, o.opcodes())),
1452            Ok((
1453                "",
1454                vec![
1455                    Op::Value(var("0")),
1456                    Op::Value(int(1)),
1457                    Op::Binary(Binary::NotEqual),
1458                ],
1459            ))
1460        );
1461
1462        assert_eq!(
1463            super::expr("$0 != 1").map(|(i, o)| (i, o.opcodes())),
1464            Ok((
1465                "",
1466                vec![
1467                    Op::Value(var("0")),
1468                    Op::Value(int(1)),
1469                    Op::Binary(Binary::HeterogeneousNotEqual),
1470                ],
1471            ))
1472        );
1473
1474        assert_eq!(
1475            super::expr("$0.length() === $1").map(|(i, o)| (i, o.opcodes())),
1476            Ok((
1477                "",
1478                vec![
1479                    Op::Value(var("0")),
1480                    Op::Unary(Unary::Length),
1481                    Op::Value(var("1")),
1482                    Op::Binary(Binary::Equal),
1483                ],
1484            ))
1485        );
1486
1487        assert_eq!(
1488            super::expr("$0.length() == $1").map(|(i, o)| (i, o.opcodes())),
1489            Ok((
1490                "",
1491                vec![
1492                    Op::Value(var("0")),
1493                    Op::Unary(Unary::Length),
1494                    Op::Value(var("1")),
1495                    Op::Binary(Binary::HeterogeneousEqual),
1496                ],
1497            ))
1498        );
1499
1500        assert_eq!(
1501            super::expr("$0.length() !== $1").map(|(i, o)| (i, o.opcodes())),
1502            Ok((
1503                "",
1504                vec![
1505                    Op::Value(var("0")),
1506                    Op::Unary(Unary::Length),
1507                    Op::Value(var("1")),
1508                    Op::Binary(Binary::NotEqual),
1509                ],
1510            ))
1511        );
1512
1513        assert_eq!(
1514            super::expr("$0.length() != $1").map(|(i, o)| (i, o.opcodes())),
1515            Ok((
1516                "",
1517                vec![
1518                    Op::Value(var("0")),
1519                    Op::Unary(Unary::Length),
1520                    Op::Value(var("1")),
1521                    Op::Binary(Binary::HeterogeneousNotEqual),
1522                ],
1523            ))
1524        );
1525
1526        assert_eq!(
1527            super::expr("!$0 === $1").map(|(i, o)| (i, o.opcodes())),
1528            Ok((
1529                "",
1530                vec![
1531                    Op::Value(var("0")),
1532                    Op::Unary(Unary::Negate),
1533                    Op::Value(var("1")),
1534                    Op::Binary(Binary::Equal),
1535                ],
1536            ))
1537        );
1538
1539        assert_eq!(
1540            super::expr("!$0 == $1").map(|(i, o)| (i, o.opcodes())),
1541            Ok((
1542                "",
1543                vec![
1544                    Op::Value(var("0")),
1545                    Op::Unary(Unary::Negate),
1546                    Op::Value(var("1")),
1547                    Op::Binary(Binary::HeterogeneousEqual),
1548                ],
1549            ))
1550        );
1551
1552        assert_eq!(
1553            super::expr("!$0 !== $1").map(|(i, o)| (i, o.opcodes())),
1554            Ok((
1555                "",
1556                vec![
1557                    Op::Value(var("0")),
1558                    Op::Unary(Unary::Negate),
1559                    Op::Value(var("1")),
1560                    Op::Binary(Binary::NotEqual),
1561                ],
1562            ))
1563        );
1564
1565        assert_eq!(
1566            super::expr("!$0 != $1").map(|(i, o)| (i, o.opcodes())),
1567            Ok((
1568                "",
1569                vec![
1570                    Op::Value(var("0")),
1571                    Op::Unary(Unary::Negate),
1572                    Op::Value(var("1")),
1573                    Op::Binary(Binary::HeterogeneousNotEqual),
1574                ],
1575            ))
1576        );
1577
1578        assert_eq!(
1579            super::expr("!false && true").map(|(i, o)| (i, o.opcodes())),
1580            Ok((
1581                "",
1582                vec![
1583                    Op::Value(boolean(false)),
1584                    Op::Unary(Unary::Negate),
1585                    Op::Closure(vec![], vec![Op::Value(boolean(true)),]),
1586                    Op::Binary(Binary::LazyAnd),
1587                ],
1588            ))
1589        );
1590
1591        assert_eq!(
1592            super::expr("true || true && true").map(|(i, o)| (i, o.opcodes())),
1593            Ok((
1594                "",
1595                vec![
1596                    Op::Value(boolean(true)),
1597                    Op::Closure(
1598                        vec![],
1599                        vec![
1600                            Op::Value(boolean(true)),
1601                            Op::Closure(vec![], vec![Op::Value(boolean(true)),]),
1602                            Op::Binary(Binary::LazyAnd),
1603                        ]
1604                    ),
1605                    Op::Binary(Binary::LazyOr),
1606                ],
1607            ))
1608        );
1609
1610        assert_eq!(
1611            super::expr("(1 > 2) === 3").map(|(i, o)| (i, o.opcodes())),
1612            Ok((
1613                "",
1614                vec![
1615                    Op::Value(int(1)),
1616                    Op::Value(int(2)),
1617                    Op::Binary(Binary::GreaterThan),
1618                    Op::Unary(Unary::Parens),
1619                    Op::Value(int(3)),
1620                    Op::Binary(Binary::Equal),
1621                ]
1622            ))
1623        );
1624
1625        assert_eq!(
1626            super::expr("(1 > 2) == 3").map(|(i, o)| (i, o.opcodes())),
1627            Ok((
1628                "",
1629                vec![
1630                    Op::Value(int(1)),
1631                    Op::Value(int(2)),
1632                    Op::Binary(Binary::GreaterThan),
1633                    Op::Unary(Unary::Parens),
1634                    Op::Value(int(3)),
1635                    Op::Binary(Binary::HeterogeneousEqual),
1636                ]
1637            ))
1638        );
1639
1640        assert_eq!(
1641            super::expr("(1 > 2) !== 3").map(|(i, o)| (i, o.opcodes())),
1642            Ok((
1643                "",
1644                vec![
1645                    Op::Value(int(1)),
1646                    Op::Value(int(2)),
1647                    Op::Binary(Binary::GreaterThan),
1648                    Op::Unary(Unary::Parens),
1649                    Op::Value(int(3)),
1650                    Op::Binary(Binary::NotEqual),
1651                ]
1652            ))
1653        );
1654
1655        assert_eq!(
1656            super::expr("(1 > 2) != 3").map(|(i, o)| (i, o.opcodes())),
1657            Ok((
1658                "",
1659                vec![
1660                    Op::Value(int(1)),
1661                    Op::Value(int(2)),
1662                    Op::Binary(Binary::GreaterThan),
1663                    Op::Unary(Unary::Parens),
1664                    Op::Value(int(3)),
1665                    Op::Binary(Binary::HeterogeneousNotEqual),
1666                ]
1667            ))
1668        );
1669
1670        assert_eq!(
1671            super::expr("1 > 2 + 3").map(|(i, o)| (i, o.opcodes())),
1672            Ok((
1673                "",
1674                vec![
1675                    Op::Value(int(1)),
1676                    Op::Value(int(2)),
1677                    Op::Value(int(3)),
1678                    Op::Binary(Binary::Add),
1679                    Op::Binary(Binary::GreaterThan),
1680                ]
1681            ))
1682        );
1683
1684        assert_eq!(
1685            super::expr("1 > 2 == 3").map(|(i, o)| (i, o.opcodes())),
1686            Ok((
1687                " == 3",
1688                vec![
1689                    Op::Value(int(1)),
1690                    Op::Value(int(2)),
1691                    Op::Binary(Binary::GreaterThan),
1692                ]
1693            ))
1694        );
1695
1696        let h = [int(1), int(2)].iter().cloned().collect::<BTreeSet<_>>();
1697        assert_eq!(
1698            super::expr("{1, 2}.contains($0)").map(|(i, o)| (i, o.opcodes())),
1699            Ok((
1700                "",
1701                vec![
1702                    Op::Value(set(h.clone())),
1703                    Op::Value(var("0")),
1704                    Op::Binary(Binary::Contains),
1705                ],
1706            ))
1707        );
1708
1709        assert_eq!(
1710            super::expr("!{ 1, 2}.contains($0)").map(|(i, o)| (i, o.opcodes())),
1711            Ok((
1712                "",
1713                vec![
1714                    Op::Value(set(h)),
1715                    Op::Value(var("0")),
1716                    Op::Binary(Binary::Contains),
1717                    Op::Unary(Unary::Negate),
1718                ],
1719            ))
1720        );
1721
1722        let h = [
1723            builder::Term::Date(1575452801),
1724            builder::Term::Date(1607075201),
1725        ]
1726        .iter()
1727        .cloned()
1728        .collect::<BTreeSet<builder::Term>>();
1729        assert_eq!(
1730            super::expr("{2020-12-04T09:46:41+00:00, 2019-12-04T09:46:41+00:00}.contains(2020-12-04T09:46:41+00:00)").map(|(i, o)| (i, o.opcodes())),
1731            Ok((
1732                "",
1733                vec![
1734                    Op::Value(set(h)),
1735                    Op::Value(builder::Term::Date(1607075201)),
1736                    Op::Binary(Binary::Contains),
1737                ],
1738            ))
1739        );
1740
1741        assert_eq!(
1742            super::expr("$0 === \"abc\"").map(|(i, o)| (i, o.opcodes())),
1743            Ok((
1744                "",
1745                vec![
1746                    Op::Value(var("0")),
1747                    Op::Value(string("abc")),
1748                    Op::Binary(Binary::Equal),
1749                ],
1750            ))
1751        );
1752
1753        assert_eq!(
1754            super::expr("$0 == \"abc\"").map(|(i, o)| (i, o.opcodes())),
1755            Ok((
1756                "",
1757                vec![
1758                    Op::Value(var("0")),
1759                    Op::Value(string("abc")),
1760                    Op::Binary(Binary::HeterogeneousEqual),
1761                ],
1762            ))
1763        );
1764
1765        assert_eq!(
1766            super::expr("$0 !== \"abc\"").map(|(i, o)| (i, o.opcodes())),
1767            Ok((
1768                "",
1769                vec![
1770                    Op::Value(var("0")),
1771                    Op::Value(string("abc")),
1772                    Op::Binary(Binary::NotEqual),
1773                ],
1774            ))
1775        );
1776
1777        assert_eq!(
1778            super::expr("$0 != \"abc\"").map(|(i, o)| (i, o.opcodes())),
1779            Ok((
1780                "",
1781                vec![
1782                    Op::Value(var("0")),
1783                    Op::Value(string("abc")),
1784                    Op::Binary(Binary::HeterogeneousNotEqual),
1785                ],
1786            ))
1787        );
1788
1789        assert_eq!(
1790            super::expr("$0.ends_with(\"abc\")").map(|(i, o)| (i, o.opcodes())),
1791            Ok((
1792                "",
1793                vec![
1794                    Op::Value(var("0")),
1795                    Op::Value(string("abc")),
1796                    Op::Binary(Binary::Suffix),
1797                ],
1798            ))
1799        );
1800
1801        assert_eq!(
1802            super::expr("$0.starts_with(\"abc\")").map(|(i, o)| (i, o.opcodes())),
1803            Ok((
1804                "",
1805                vec![
1806                    Op::Value(var("0")),
1807                    Op::Value(string("abc")),
1808                    Op::Binary(Binary::Prefix),
1809                ],
1810            ))
1811        );
1812
1813        assert_eq!(
1814            super::expr("$0.matches(\"abc[0-9]+\")").map(|(i, o)| (i, o.opcodes())),
1815            Ok((
1816                "",
1817                vec![
1818                    Op::Value(var("0")),
1819                    Op::Value(string("abc[0-9]+")),
1820                    Op::Binary(Binary::Regex),
1821                ],
1822            ))
1823        );
1824
1825        let h = [string("abc"), string("def")]
1826            .iter()
1827            .cloned()
1828            .collect::<BTreeSet<_>>();
1829        assert_eq!(
1830            super::expr("{\"abc\", \"def\"}.contains($0)").map(|(i, o)| (i, o.opcodes())),
1831            Ok((
1832                "",
1833                vec![
1834                    Op::Value(set(h.clone())),
1835                    Op::Value(var("0")),
1836                    Op::Binary(Binary::Contains),
1837                ],
1838            ))
1839        );
1840
1841        assert_eq!(
1842            super::expr("!{\"abc\", \"def\"}.contains($0)").map(|(i, o)| (i, o.opcodes())),
1843            Ok((
1844                "",
1845                vec![
1846                    Op::Value(set(h.clone())),
1847                    Op::Value(var("0")),
1848                    Op::Binary(Binary::Contains),
1849                    Op::Unary(Unary::Negate),
1850                ],
1851            ))
1852        );
1853
1854        let h = [string("abc"), string("def")]
1855            .iter()
1856            .cloned()
1857            .collect::<BTreeSet<_>>();
1858        assert_eq!(
1859            super::expr("{\"abc\", \"def\"}.contains($0)").map(|(i, o)| (i, o.opcodes())),
1860            Ok((
1861                "",
1862                vec![
1863                    Op::Value(set(h.clone())),
1864                    Op::Value(var("0")),
1865                    Op::Binary(Binary::Contains),
1866                ],
1867            ))
1868        );
1869
1870        assert_eq!(
1871            super::expr("!{\"abc\", \"def\"}.contains($0)").map(|(i, o)| (i, o.opcodes())),
1872            Ok((
1873                "",
1874                vec![
1875                    Op::Value(set(h.clone())),
1876                    Op::Value(var("0")),
1877                    Op::Binary(Binary::Contains),
1878                    Op::Unary(Unary::Negate),
1879                ],
1880            ))
1881        );
1882
1883        assert_eq!(
1884            super::expr("1 + 2 | 4 * 3 & 4").map(|(i, o)| (i, o.opcodes())),
1885            Ok((
1886                "",
1887                vec![
1888                    Op::Value(int(1)),
1889                    Op::Value(int(2)),
1890                    Op::Binary(Binary::Add),
1891                    Op::Value(int(4)),
1892                    Op::Value(int(3)),
1893                    Op::Binary(Binary::Mul),
1894                    Op::Value(int(4)),
1895                    Op::Binary(Binary::BitwiseAnd),
1896                    Op::Binary(Binary::BitwiseOr),
1897                ],
1898            ))
1899        );
1900    }
1901
1902    #[test]
1903    fn fact() {
1904        assert_eq!(
1905            super::fact("right( \"file1\", \"read\" )"),
1906            Ok((
1907                "",
1908                builder::fact(
1909                    "right",
1910                    &[builder::string("file1"), builder::string("read")]
1911                )
1912            ))
1913        );
1914    }
1915
1916    #[test]
1917    fn fact_with_variable() {
1918        use nom::error::ErrorKind;
1919        assert_eq!(
1920            super::fact("right( \"file1\", $operation )"),
1921            Err(nom::Err::Failure(super::Error {
1922                code: ErrorKind::Char,
1923                input: "$operation",
1924                message: Some("variables are not allowed in facts".to_string()),
1925            }))
1926        );
1927    }
1928
1929    #[test]
1930    fn fact_with_date() {
1931        assert_eq!(
1932            super::fact("date(2019-12-02T13:49:53Z)"),
1933            Ok((
1934                "",
1935                builder::fact("date", &[builder::Term::Date(1575294593)])
1936            ))
1937        );
1938    }
1939
1940    #[test]
1941    fn rule() {
1942        assert_eq!(
1943            super::rule("right($0, \"read\") <- resource( $0), operation(\"read\")"),
1944            Ok((
1945                "",
1946                builder::rule(
1947                    "right",
1948                    &[builder::variable("0"), builder::string("read"),],
1949                    &[
1950                        builder::pred("resource", &[builder::variable("0")]),
1951                        builder::pred("operation", &[builder::string("read")]),
1952                    ],
1953                )
1954            ))
1955        );
1956    }
1957
1958    #[test]
1959    fn constrained_rule() {
1960        use builder::{date, var, Binary, Expression, Op};
1961        use std::time::{Duration, SystemTime};
1962
1963        assert_eq!(
1964            super::rule("valid_date(\"file1\") <- time($0 ), resource(\"file1\"), $0 <= 2019-12-04T09:46:41+00:00"),
1965            Ok((
1966                "",
1967                builder::constrained_rule(
1968                    "valid_date",
1969                    &[builder::string("file1")],
1970                    &[
1971                        builder::pred("time", &[builder::variable("0")]),
1972                        builder::pred("resource", &[builder::string("file1")]),
1973                    ],
1974                    &[Expression {
1975                        ops: vec![
1976                            Op::Value(var("0")),
1977                            Op::Value(date(&(SystemTime::UNIX_EPOCH + Duration::from_secs(1575452801)))),
1978                            Op::Binary(Binary::LessOrEqual),
1979                        ]
1980                    }],
1981                )
1982            ))
1983        );
1984    }
1985
1986    #[test]
1987    fn constrained_rule_ordering() {
1988        use builder::{date, var, Binary, Expression, Op};
1989        use std::time::{Duration, SystemTime};
1990
1991        assert_eq!(
1992            super::rule("valid_date(\"file1\") <- time( $0 ), $0 <= 2019-12-04T09:46:41+00:00, resource(\"file1\")"),
1993            Ok((
1994                "",
1995                builder::constrained_rule(
1996                    "valid_date",
1997                    &[
1998                        builder::string("file1"),
1999                    ],
2000                    &[
2001                        builder::pred("time", &[builder::variable("0")]),
2002                        builder::pred("resource", &[builder::string("file1")]),
2003                    ],
2004                    &[Expression {
2005                        ops: vec![
2006                            Op::Value(var("0")),
2007                            Op::Value(date(&(SystemTime::UNIX_EPOCH + Duration::from_secs(1575452801)))),
2008                            Op::Binary(Binary::LessOrEqual),
2009                        ]
2010                    }],
2011                )
2012            ))
2013        );
2014    }
2015
2016    #[test]
2017    fn rule_with_unused_head_variables() {
2018        assert_eq!(
2019            super::rule("right($0, $test) <- resource($0), operation(\"read\")"),
2020            Err( nom::Err::Failure(Error {
2021                input: "right($0, $test) <- resource($0), operation(\"read\")",
2022                code: ErrorKind::Satisfy,
2023                message: Some("the rule contains variables that are not bound by predicates in the rule's body: $test".to_string()),
2024            }))
2025        );
2026    }
2027
2028    #[test]
2029    fn check() {
2030        let empty: &[builder::Term] = &[];
2031        assert_eq!(
2032            super::check("check if resource( $0), operation(\"read\") or admin(\"authority\")"),
2033            Ok((
2034                "",
2035                builder::Check {
2036                    kind: builder::CheckKind::One,
2037                    queries: vec![
2038                        builder::rule(
2039                            "query",
2040                            empty,
2041                            &[
2042                                builder::pred("resource", &[builder::variable("0")]),
2043                                builder::pred("operation", &[builder::string("read")]),
2044                            ]
2045                        ),
2046                        builder::rule(
2047                            "query",
2048                            empty,
2049                            &[builder::pred("admin", &[builder::string("authority")]),]
2050                        ),
2051                    ]
2052                }
2053            ))
2054        );
2055    }
2056
2057    #[test]
2058    fn invalid_check() {
2059        assert_eq!(
2060            super::check(
2061                "check if resource($0) and operation(\"read\") or admin(\"authority\")"
2062            ),
2063            Err( nom::Err::Error(Error {
2064                input: "and",
2065                code: ErrorKind::Eof,
2066                message: Some("expected either the next term after ',' or the next check variant after 'or', but got 'and'".to_string()),
2067            }))
2068        );
2069
2070        assert_eq!(
2071            super::check("check if resource(\"{}\"), operation(\"write\")) or operation(\"read\")"),
2072            Err(nom::Err::Error(Error {
2073                input: ")",
2074                code: ErrorKind::Eof,
2075                message: Some("unexpected parens".to_string()),
2076            }))
2077        );
2078
2079        assert_eq!(
2080            super::check(
2081                "check if resource(\"{}\") && operation(\"write\")) || operation(\"read\")"
2082            ),
2083            Err( nom::Err::Error(Error {
2084                input: "&&",
2085                code: ErrorKind::Eof,
2086                message: Some("expected either the next term after ',' or the next check variant after 'or', but got '&&'".to_string()),
2087            }))
2088        );
2089    }
2090
2091    #[test]
2092    fn expression() {
2093        use super::Expr;
2094        use builder::{date, int, string, var, Binary, Op, Term};
2095        use std::time::{Duration, SystemTime};
2096
2097        let input = " -1 ";
2098        println!("parsing: {}", input);
2099        let res = super::expr(input);
2100        assert_eq!(res, Ok((" ", Expr::Value(Term::Integer(-1)))));
2101
2102        let ops = res.unwrap().1.opcodes();
2103        println!("ops: {:#?}", ops);
2104
2105        let input = " $0 <= 2019-12-04T09:46:41+00:00";
2106        println!("parsing: {}", input);
2107        let res = super::expr(input);
2108        assert_eq!(
2109            res,
2110            Ok((
2111                "",
2112                Expr::Binary(
2113                    Op::Binary(Binary::LessOrEqual),
2114                    Box::new(Expr::Value(var("0"))),
2115                    Box::new(Expr::Value(date(
2116                        &(SystemTime::UNIX_EPOCH + Duration::from_secs(1575452801))
2117                    )))
2118                )
2119            ))
2120        );
2121
2122        let ops = res.unwrap().1.opcodes();
2123        println!("ops: {:#?}", ops);
2124        let input = " 1 < $test + 2 ";
2125        println!("parsing: {}", input);
2126        let res = super::expr(input);
2127        assert_eq!(
2128            res,
2129            Ok((
2130                " ",
2131                Expr::Binary(
2132                    Op::Binary(Binary::LessThan),
2133                    Box::new(Expr::Value(int(1))),
2134                    Box::new(Expr::Binary(
2135                        Op::Binary(Binary::Add),
2136                        Box::new(Expr::Value(var("test"))),
2137                        Box::new(Expr::Value(int(2))),
2138                    ))
2139                )
2140            ))
2141        );
2142
2143        let ops = res.unwrap().1.opcodes();
2144        println!("ops: {:#?}", ops);
2145
2146        let input = " 2 < $test && $var2.starts_with(\"test\") && true ";
2147        println!("parsing: {}", input);
2148        let res = super::expr(input);
2149        assert_eq!(
2150            res,
2151            Ok((
2152                " ",
2153                Expr::Binary(
2154                    Op::Binary(Binary::LazyAnd),
2155                    Box::new(Expr::Binary(
2156                        Op::Binary(Binary::LazyAnd),
2157                        Box::new(Expr::Binary(
2158                            Op::Binary(Binary::LessThan),
2159                            Box::new(Expr::Value(int(2))),
2160                            Box::new(Expr::Value(var("test"))),
2161                        )),
2162                        Box::new(Expr::Closure(
2163                            vec![],
2164                            Box::new(Expr::Binary(
2165                                Op::Binary(Binary::Prefix),
2166                                Box::new(Expr::Value(var("var2"))),
2167                                Box::new(Expr::Value(string("test"))),
2168                            ))
2169                        )),
2170                    )),
2171                    Box::new(Expr::Closure(
2172                        vec![],
2173                        Box::new(Expr::Value(Term::Bool(true))),
2174                    ))
2175                )
2176            ))
2177        );
2178        let ops = res.unwrap().1.opcodes();
2179        println!("ops: {:#?}", ops);
2180    }
2181
2182    #[test]
2183    fn parens() {
2184        use builder::{int, Binary, Op, Unary};
2185
2186        let input = " 1 + 2 * 3 ";
2187        println!("parsing: {}", input);
2188        let (_, res) = super::expr(input).unwrap();
2189
2190        let ops = res.opcodes();
2191        println!("ops: {:#?}", ops);
2192
2193        assert_eq!(
2194            ops,
2195            vec![
2196                Op::Value(int(1)),
2197                Op::Value(int(2)),
2198                Op::Value(int(3)),
2199                Op::Binary(Binary::Mul),
2200                Op::Binary(Binary::Add),
2201            ]
2202        );
2203
2204        let input = " (1 + 2) * 3 ";
2205        println!("parsing: {}", input);
2206        let (_, res) = super::expr(input).unwrap();
2207
2208        let ops = res.opcodes();
2209        println!("ops: {:#?}", ops);
2210
2211        assert_eq!(
2212            ops,
2213            vec![
2214                Op::Value(int(1)),
2215                Op::Value(int(2)),
2216                Op::Binary(Binary::Add),
2217                Op::Unary(Unary::Parens),
2218                Op::Value(int(3)),
2219                Op::Binary(Binary::Mul),
2220            ]
2221        );
2222    }
2223
2224    #[test]
2225    fn source_file() {
2226        use builder::{
2227            boolean, constrained_rule, fact, int, pred, rule, string, var, Binary, Check,
2228            Expression, Op, Policy, PolicyKind,
2229        };
2230        use std::time::{Duration, SystemTime};
2231
2232        let input = r#"
2233          fact("string");
2234          fact2(1234);
2235
2236          rule_head($var0) <- fact($var0, $var1), 1 < 2;
2237
2238          // line comment
2239          check if 1 === 2;
2240
2241          allow if rule_head("string");
2242
2243          /*
2244           other comment
2245          */
2246    check if
2247              fact(5678)
2248              or fact(1234), "test".starts_with("abc");
2249
2250          check if 2021-01-01T00:00:00Z <= 2021-01-01T00:00:00Z;
2251
2252          deny if true;
2253        "#;
2254
2255        let res = super::parse_source(input);
2256        println!("parse_source res:\n{:#?}", res);
2257
2258        let empty_terms: &[builder::Term] = &[];
2259        let empty_preds: &[builder::Predicate] = &[];
2260
2261        let expected_facts = vec![
2262            fact("fact", &[string("string")]),
2263            fact("fact2", &[int(1234)]),
2264        ];
2265
2266        let expected_rules = vec![constrained_rule(
2267            "rule_head",
2268            &[var("var0")],
2269            &[pred("fact", &[var("var0"), var("var1")])],
2270            &[Expression {
2271                ops: vec![
2272                    Op::Value(int(1)),
2273                    Op::Value(int(2)),
2274                    Op::Binary(Binary::LessThan),
2275                ],
2276            }],
2277        )];
2278
2279        let expected_checks = vec![
2280            Check {
2281                kind: CheckKind::One,
2282                queries: vec![constrained_rule(
2283                    "query",
2284                    empty_terms,
2285                    empty_preds,
2286                    &[Expression {
2287                        ops: vec![
2288                            Op::Value(int(1)),
2289                            Op::Value(int(2)),
2290                            Op::Binary(Binary::Equal),
2291                        ],
2292                    }],
2293                )],
2294            },
2295            Check {
2296                kind: CheckKind::One,
2297                queries: vec![
2298                    rule("query", empty_terms, &[pred("fact", &[int(5678)])]),
2299                    constrained_rule(
2300                        "query",
2301                        empty_terms,
2302                        &[pred("fact", &[int(1234)])],
2303                        &[Expression {
2304                            ops: vec![
2305                                Op::Value(string("test")),
2306                                Op::Value(string("abc")),
2307                                Op::Binary(Binary::Prefix),
2308                            ],
2309                        }],
2310                    ),
2311                ],
2312            },
2313            Check {
2314                kind: CheckKind::One,
2315                queries: vec![constrained_rule(
2316                    "query",
2317                    empty_terms,
2318                    empty_preds,
2319                    &[Expression {
2320                        ops: vec![
2321                            Op::Value(builder::date(
2322                                &(SystemTime::UNIX_EPOCH + Duration::from_secs(1609459200)),
2323                            )),
2324                            Op::Value(builder::date(
2325                                &(SystemTime::UNIX_EPOCH + Duration::from_secs(1609459200)),
2326                            )),
2327                            Op::Binary(Binary::LessOrEqual),
2328                        ],
2329                    }],
2330                )],
2331            },
2332        ];
2333
2334        let expected_policies = vec![
2335            Policy {
2336                kind: PolicyKind::Allow,
2337                queries: vec![rule(
2338                    "query",
2339                    empty_terms,
2340                    &[pred("rule_head", &[string("string")])],
2341                )],
2342            },
2343            Policy {
2344                kind: PolicyKind::Deny,
2345                queries: vec![constrained_rule(
2346                    "query",
2347                    empty_terms,
2348                    empty_preds,
2349                    &[Expression {
2350                        ops: vec![Op::Value(boolean(true))],
2351                    }],
2352                )],
2353            },
2354        ];
2355
2356        let mut result = res.unwrap();
2357        assert_eq!(
2358            result.facts.drain(..).map(|(_, r)| r).collect::<Vec<_>>(),
2359            expected_facts
2360        );
2361        assert_eq!(
2362            result.rules.drain(..).map(|(_, r)| r).collect::<Vec<_>>(),
2363            expected_rules
2364        );
2365        assert_eq!(
2366            result.checks.drain(..).map(|(_, r)| r).collect::<Vec<_>>(),
2367            expected_checks
2368        );
2369        assert_eq!(
2370            result
2371                .policies
2372                .drain(..)
2373                .map(|(_, r)| r)
2374                .collect::<Vec<_>>(),
2375            expected_policies
2376        );
2377    }
2378
2379    #[test]
2380    fn block_source_file() {
2381        use builder::{
2382            constrained_rule, fact, int, pred, rule, string, var, Binary, Check, Expression, Op,
2383        };
2384        use std::time::{Duration, SystemTime};
2385
2386        let input = r#"
2387          fact("string");
2388          fact2(1234);
2389
2390    rule_head($var0) <- fact($var0, $var1), 1 < 2; // line comment
2391    check if 1 === 2; /*
2392                      other comment
2393                     */
2394    check if
2395              fact(5678)
2396              or fact(1234), "test".starts_with("abc");
2397
2398          check if 2021-01-01T00:00:00Z <= 2021-01-01T00:00:00Z;
2399        "#;
2400
2401        let res = super::parse_block_source(input);
2402        println!("parse_block_source res:\n{:#?}", res);
2403
2404        let empty_terms: &[builder::Term] = &[];
2405        let empty_preds: &[builder::Predicate] = &[];
2406
2407        let expected_facts = vec![
2408            fact("fact", &[string("string")]),
2409            fact("fact2", &[int(1234)]),
2410        ];
2411
2412        let expected_rules = vec![constrained_rule(
2413            "rule_head",
2414            &[var("var0")],
2415            &[pred("fact", &[var("var0"), var("var1")])],
2416            &[Expression {
2417                ops: vec![
2418                    Op::Value(int(1)),
2419                    Op::Value(int(2)),
2420                    Op::Binary(Binary::LessThan),
2421                ],
2422            }],
2423        )];
2424
2425        let expected_checks = vec![
2426            Check {
2427                kind: CheckKind::One,
2428                queries: vec![constrained_rule(
2429                    "query",
2430                    empty_terms,
2431                    empty_preds,
2432                    &[Expression {
2433                        ops: vec![
2434                            Op::Value(int(1)),
2435                            Op::Value(int(2)),
2436                            Op::Binary(Binary::Equal),
2437                        ],
2438                    }],
2439                )],
2440            },
2441            Check {
2442                kind: CheckKind::One,
2443                queries: vec![
2444                    rule("query", empty_terms, &[pred("fact", &[int(5678)])]),
2445                    constrained_rule(
2446                        "query",
2447                        empty_terms,
2448                        &[pred("fact", &[int(1234)])],
2449                        &[Expression {
2450                            ops: vec![
2451                                Op::Value(string("test")),
2452                                Op::Value(string("abc")),
2453                                Op::Binary(Binary::Prefix),
2454                            ],
2455                        }],
2456                    ),
2457                ],
2458            },
2459            Check {
2460                kind: CheckKind::One,
2461                queries: vec![constrained_rule(
2462                    "query",
2463                    empty_terms,
2464                    empty_preds,
2465                    &[Expression {
2466                        ops: vec![
2467                            Op::Value(builder::date(
2468                                &(SystemTime::UNIX_EPOCH + Duration::from_secs(1609459200)),
2469                            )),
2470                            Op::Value(builder::date(
2471                                &(SystemTime::UNIX_EPOCH + Duration::from_secs(1609459200)),
2472                            )),
2473                            Op::Binary(Binary::LessOrEqual),
2474                        ],
2475                    }],
2476                )],
2477            },
2478        ];
2479
2480        let mut result = res.unwrap();
2481        assert_eq!(
2482            result.facts.drain(..).map(|(_, r)| r).collect::<Vec<_>>(),
2483            expected_facts
2484        );
2485        assert_eq!(
2486            result.rules.drain(..).map(|(_, r)| r).collect::<Vec<_>>(),
2487            expected_rules
2488        );
2489        assert_eq!(
2490            result.checks.drain(..).map(|(_, r)| r).collect::<Vec<_>>(),
2491            expected_checks
2492        );
2493    }
2494
2495    #[test]
2496    fn chained_calls() {
2497        use builder::{int, set, Binary, Op};
2498
2499        assert_eq!(
2500            super::expr("{1}.intersection({2}).contains(3)").map(|(i, o)| (i, o.opcodes())),
2501            Ok((
2502                "",
2503                vec![
2504                    Op::Value(set([int(1)].into_iter().collect())),
2505                    Op::Value(set([int(2)].into_iter().collect())),
2506                    Op::Binary(Binary::Intersection),
2507                    Op::Value(int(3)),
2508                    Op::Binary(Binary::Contains)
2509                ],
2510            ))
2511        );
2512
2513        assert_eq!(
2514            super::expr("{1}.intersection({2}).union({3}).length()").map(|(i, o)| (i, o.opcodes())),
2515            Ok((
2516                "",
2517                vec![
2518                    Op::Value(set([int(1)].into_iter().collect())),
2519                    Op::Value(set([int(2)].into_iter().collect())),
2520                    Op::Binary(Binary::Intersection),
2521                    Op::Value(set([int(3)].into_iter().collect())),
2522                    Op::Binary(Binary::Union),
2523                    Op::Unary(Unary::Length),
2524                ],
2525            ))
2526        );
2527
2528        assert_eq!(
2529            super::expr("{1}.intersection({2}).length().union({3})").map(|(i, o)| (i, o.opcodes())),
2530            Ok((
2531                "",
2532                vec![
2533                    Op::Value(set([int(1)].into_iter().collect())),
2534                    Op::Value(set([int(2)].into_iter().collect())),
2535                    Op::Binary(Binary::Intersection),
2536                    Op::Unary(Unary::Length),
2537                    Op::Value(set([int(3)].into_iter().collect())),
2538                    Op::Binary(Binary::Union),
2539                ],
2540            ))
2541        );
2542    }
2543
2544    #[test]
2545    fn arrays() {
2546        let h = vec![int(1), int(2)];
2547        assert_eq!(
2548            super::expr("[1, 2].contains($0)").map(|(i, o)| (i, o.opcodes())),
2549            Ok((
2550                "",
2551                vec![
2552                    Op::Value(array(h.clone())),
2553                    Op::Value(var("0")),
2554                    Op::Binary(Binary::Contains),
2555                ]
2556            ))
2557        )
2558    }
2559
2560    #[test]
2561    fn extern_funcs() {
2562        use builder::{int, Binary, Op};
2563
2564        assert_eq!(
2565            super::expr("2.extern::toto()").map(|(i, o)| (i, o.opcodes())),
2566            Ok((
2567                "",
2568                vec![Op::Value(int(2)), Op::Unary(Unary::Ffi("toto".to_string()))],
2569            ))
2570        );
2571
2572        assert_eq!(
2573            super::expr("2.extern::toto(3)").map(|(i, o)| (i, o.opcodes())),
2574            Ok((
2575                "",
2576                vec![
2577                    Op::Value(int(2)),
2578                    Op::Value(int(3)),
2579                    Op::Binary(Binary::Ffi("toto".to_string())),
2580                ],
2581            ))
2582        );
2583    }
2584
2585    #[test]
2586    fn empty_set_map() {
2587        use builder::{map, set};
2588
2589        assert_eq!(
2590            super::expr("{,}").map(|(i, o)| (i, o.opcodes())),
2591            Ok(("", vec![Op::Value(set(Default::default()))],))
2592        );
2593        assert_eq!(
2594            super::expr("{}").map(|(i, o)| (i, o.opcodes())),
2595            Ok(("", vec![Op::Value(map(Default::default()))],))
2596        );
2597    }
2598
2599    #[test]
2600    fn try_expr() {
2601        use builder::{boolean, Binary, Op, Unary};
2602        assert_eq!(
2603            super::expr("true.length().try_or(false)").map(|(i, o)| (i, o.opcodes())),
2604            Ok((
2605                "",
2606                vec![
2607                    Op::Closure(
2608                        vec![],
2609                        vec![Op::Value(boolean(true)), Op::Unary(Unary::Length)]
2610                    ),
2611                    Op::Value(boolean(false)),
2612                    Op::Binary(Binary::TryOr)
2613                ],
2614            ))
2615        );
2616    }
2617}