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
21pub 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
51pub 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
83pub 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
106pub 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
122pub 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
138pub 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
162pub 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
246pub 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
465fn 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
485pub 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
506fn 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
517fn 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
537fn 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
548fn 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
559fn 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
570fn 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
581fn 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
592fn expr8(i: &str) -> IResult<&str, Expr, Error> {
594 alt((unary_negate, expr9))(i)
595}
596
597fn 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 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
1197impl<'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}