biscuit_parser/
parser.rs

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