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