1use super::err::ParseError;
39use super::node::{ASTNode, SourceInfo};
40use super::unescape::{to_pattern, to_unescaped_string};
41use super::{cst, err};
42use crate::ast::{
43 self, ActionConstraint, CallStyle, EntityReference, EntityType, EntityUID, PatternElem,
44 PolicySetError, PrincipalConstraint, PrincipalOrResourceConstraint, ResourceConstraint,
45};
46use itertools::Either;
47use smol_str::SmolStr;
48use std::cmp::Ordering;
49use std::collections::{BTreeMap, HashSet};
50use std::mem;
51use std::sync::Arc;
52
53type Errs<'a> = &'a mut Vec<err::ParseError>;
55
56struct ExtStyles<'a> {
58 functions: HashSet<&'a ast::Name>,
59 methods: HashSet<&'a str>,
60}
61
62lazy_static::lazy_static! {
64 static ref EXTENSION_STYLES: ExtStyles<'static> = load_styles();
65}
66fn load_styles() -> ExtStyles<'static> {
67 let mut functions = HashSet::new();
68 let mut methods = HashSet::new();
69 for func in crate::extensions::Extensions::all_available().all_funcs() {
70 match func.style() {
71 CallStyle::FunctionStyle => functions.insert(func.name()),
72 CallStyle::MethodStyle => methods.insert(func.name().basename().as_ref()),
73 };
74 }
75 ExtStyles { functions, methods }
76}
77
78impl ASTNode<Option<cst::Policies>> {
79 pub fn with_generated_policyids(
82 &self,
83 ) -> Option<impl Iterator<Item = (ast::PolicyID, &ASTNode<Option<cst::Policy>>)>> {
84 let maybe_policies = self.as_inner();
85 let policies = maybe_policies?;
87
88 Some(
89 policies
90 .0
91 .iter()
92 .enumerate()
93 .map(|(count, node)| (ast::PolicyID::from_string(format!("policy{count}")), node)),
94 )
95 }
96
97 pub fn to_policyset(&self, errs: Errs<'_>) -> Option<ast::PolicySet> {
99 let mut pset = ast::PolicySet::new();
100 let mut complete_set = true;
101 for (policy_id, policy) in self.with_generated_policyids()? {
102 match policy.to_policy_or_template(policy_id, errs) {
104 Some(Either::Right(template)) => {
105 if let Err(e) = pset.add_template(template) {
106 match e {
107 PolicySetError::Occupied => errs.push(ParseError::ToAST(
108 "A template with this ID already exists within the policy set"
109 .to_string(),
110 )),
111 };
112
113 complete_set = false
114 }
115 }
116 Some(Either::Left(inline_policy)) => {
117 if let Err(e) = pset.add_static(inline_policy) {
118 match e {
119 PolicySetError::Occupied => errs.push(ParseError::ToAST(
120 "A policy with this ID already exists within the policy set"
121 .to_string(),
122 )),
123 };
124
125 complete_set = false
126 }
127 }
128 None => complete_set = false,
129 };
130 }
131
132 if complete_set {
134 Some(pset)
135 } else {
136 None
137 }
138 }
139}
140
141impl ASTNode<Option<cst::Policy>> {
142 pub fn to_policy_or_template(
144 &self,
145 id: ast::PolicyID,
146 errs: Errs<'_>,
147 ) -> Option<Either<ast::StaticPolicy, ast::Template>> {
148 let t = self.to_policy_template(id, errs)?;
149 if t.slots().count() == 0 {
150 ast::StaticPolicy::try_from(t).ok().map(Either::Left)
152 } else {
153 Some(Either::Right(t))
154 }
155 }
156
157 pub fn to_policy(&self, id: ast::PolicyID, errs: Errs<'_>) -> Option<ast::StaticPolicy> {
159 let tp = self.to_policy_template(id, errs)?;
160 match ast::StaticPolicy::try_from(tp) {
161 Ok(p) => Some(p),
162 Err(e) => {
163 errs.push(err::ParseError::ToAST(format!("{e}")));
164 None
165 }
166 }
167 }
168
169 pub fn to_policy_template(&self, id: ast::PolicyID, errs: Errs<'_>) -> Option<ast::Template> {
172 let (src, maybe_policy) = self.as_inner_pair();
173 let policy = maybe_policy?;
175
176 let mut failure = false;
177
178 let maybe_effect = policy.effect.to_effect(errs);
180
181 let annotations: BTreeMap<_, _> = policy
183 .annotations
184 .iter()
185 .filter_map(|a| a.to_kv_pair(errs))
186 .collect();
187 if annotations.len() != policy.annotations.len() {
188 failure = true;
189 errs.push(err::ParseError::ToAST(
190 "This policy uses poorly formed or duplicate annotations".to_string(),
191 ));
192 }
193
194 let (maybe_principal, maybe_action, maybe_resource) = policy.extract_head(errs);
196
197 let conds: Vec<_> = policy
199 .conds
200 .iter()
201 .filter_map(|c| c.to_expr(errs))
202 .collect();
203 if conds.len() != policy.conds.len() {
204 failure = true
205 }
206
207 if failure || !errs.is_empty() {
209 return None;
210 };
211 let effect = maybe_effect?;
212 let principal = maybe_principal?;
213 let action = maybe_action?;
214 let resource = maybe_resource?;
215
216 Some(construct_template_policy(
217 id,
218 annotations,
219 effect,
220 principal,
221 action,
222 resource,
223 conds,
224 src.clone(),
225 ))
226 }
227}
228
229impl cst::Policy {
230 pub fn extract_head(
232 &self,
233 errs: Errs<'_>,
234 ) -> (
235 Option<PrincipalConstraint>,
236 Option<ActionConstraint>,
237 Option<ResourceConstraint>,
238 ) {
239 let mut vars = self.variables.iter();
240 let principal = if let Some(head1) = vars.next() {
241 head1.to_principal_constraint(errs)
242 } else {
243 errs.push(err::ParseError::ToAST(
244 "This policy requires the `principal` variable in the head".to_string(),
245 ));
246 None
247 };
248 let action = if let Some(head2) = vars.next() {
249 head2.to_action_constraint(errs)
250 } else {
251 errs.push(err::ParseError::ToAST(
252 "This policy requires the `action` variable in the head".to_string(),
253 ));
254 None
255 };
256 let resource = if let Some(head3) = vars.next() {
257 head3.to_resource_constraint(errs)
258 } else {
259 errs.push(err::ParseError::ToAST(
260 "This policy requires the `resource` variable in the head".to_string(),
261 ));
262 None
263 };
264 if vars.next().is_some() {
265 errs.push(err::ParseError::ToAST(
266 "This policy has extra variables in the head".to_string(),
267 ));
268 }
269 (principal, action, resource)
270 }
271}
272
273impl ASTNode<Option<cst::Annotation>> {
274 pub fn to_kv_pair(&self, errs: Errs<'_>) -> Option<(ast::Id, SmolStr)> {
277 let maybe_anno = self.as_inner();
278 let anno = maybe_anno?;
280
281 let maybe_key = anno.key.to_valid_ident(errs);
282 let maybe_value = anno.value.as_valid_string(errs);
283 let maybe_value = match maybe_value.map(|s| to_unescaped_string(s)).transpose() {
284 Ok(maybe_value) => maybe_value,
285 Err(unescape_errs) => {
286 errs.extend(
287 unescape_errs
288 .into_iter()
289 .map(|e| ParseError::ToAST(e.to_string())),
290 );
291 None
292 }
293 };
294
295 match (maybe_key, maybe_value) {
296 (Some(k), Some(v)) => Some((k, v)),
297 _ => None,
298 }
299 }
300}
301
302impl ASTNode<Option<cst::Ident>> {
303 pub fn to_valid_ident(&self, errs: Errs<'_>) -> Option<ast::Id> {
305 let maybe_ident = self.as_inner();
306 let ident = maybe_ident?;
308
309 match ident {
310 cst::Ident::If
311 | cst::Ident::True
312 | cst::Ident::False
313 | cst::Ident::Then
314 | cst::Ident::Else
315 | cst::Ident::In
316 | cst::Ident::Has
317 | cst::Ident::Like => {
318 errs.push(err::ParseError::ToAST(format!(
319 "This identifier is reserved and cannot be used: {ident}"
320 )));
321 None
322 }
323 cst::Ident::Invalid(i) => {
324 errs.push(err::ParseError::ToAST(format!(
325 "not a valid identifier: {i}"
326 )));
327 None
328 }
329 _ => Some(construct_id(format!("{ident}"))),
330 }
331 }
332
333 pub(crate) fn to_effect(&self, errs: Errs<'_>) -> Option<ast::Effect> {
335 let maybe_effect = self.as_inner();
336 let effect = maybe_effect?;
338
339 match effect {
340 cst::Ident::Permit => Some(ast::Effect::Permit),
341 cst::Ident::Forbid => Some(ast::Effect::Forbid),
342 _ => {
343 errs.push(err::ParseError::ToAST(format!(
344 "not a valid policy effect: {effect}"
345 )));
346 None
347 }
348 }
349 }
350 pub(crate) fn to_cond_is_when(&self, errs: Errs<'_>) -> Option<bool> {
351 let maybe_cond = self.as_inner();
352 let cond = maybe_cond?;
354
355 match cond {
356 cst::Ident::When => Some(true),
357 cst::Ident::Unless => Some(false),
358 _ => {
359 errs.push(err::ParseError::ToAST(format!(
360 "not a valid policy condition: {cond}"
361 )));
362 None
363 }
364 }
365 }
366
367 fn to_var(&self, errs: Errs<'_>) -> Option<ast::Var> {
368 let maybe_ident = self.as_inner();
369 match maybe_ident {
370 Some(cst::Ident::Principal) => Some(ast::Var::Principal),
371 Some(cst::Ident::Action) => Some(ast::Var::Action),
372 Some(cst::Ident::Resource) => Some(ast::Var::Resource),
373 Some(ident) => {
374 errs.push(err::ParseError::ToAST(format!(
375 "expected an identifier, got {ident}"
376 )));
377 None
378 }
379 None => {
380 errs.push(err::ParseError::ToAST("expected an identifier".to_string()));
381 None
382 }
383 }
384 }
385}
386
387impl ast::Id {
388 fn to_meth(
389 &self,
390 e: ast::Expr,
391 mut args: Vec<ast::Expr>,
392 errs: Errs<'_>,
393 l: SourceInfo,
394 ) -> Option<ast::Expr> {
395 let mut adj_args = args.iter_mut().peekable();
396 match (self.as_ref(), adj_args.next(), adj_args.peek()) {
397 ("contains", Some(a), None) => {
398 let arg = mem::replace(a, ast::Expr::val(false));
401 Some(construct_method_contains(e, arg, l))
402 }
403 ("containsAll", Some(a), None) => {
404 let arg = mem::replace(a, ast::Expr::val(false));
405 Some(construct_method_contains_all(e, arg, l))
406 }
407 ("containsAny", Some(a), None) => {
408 let arg = mem::replace(a, ast::Expr::val(false));
409 Some(construct_method_contains_any(e, arg, l))
410 }
411 (name, _, _) => {
412 if EXTENSION_STYLES.methods.contains(&name) {
413 args.insert(0, e);
414 Some(construct_ext_meth(name.to_string(), args, l))
416 } else {
417 errs.push(err::ParseError::ToAST(format!(
418 "expected method name, found {}",
419 name
420 )));
421 None
422 }
423 }
424 }
425 }
426}
427
428#[derive(Debug)]
429enum PrincipalOrResource {
430 Principal(PrincipalConstraint),
431 Resource(ResourceConstraint),
432}
433
434impl ASTNode<Option<cst::VariableDef>> {
435 fn to_principal_constraint(&self, errs: Errs<'_>) -> Option<PrincipalConstraint> {
436 match self.to_principal_or_resource_constraint(errs)? {
437 PrincipalOrResource::Principal(p) => Some(p),
438 PrincipalOrResource::Resource(_) => {
439 errs.push(err::ParseError::ToAST(
440 "expected principal constraint, found resource constraint".to_string(),
441 ));
442 None
443 }
444 }
445 }
446
447 fn to_resource_constraint(&self, errs: Errs<'_>) -> Option<ResourceConstraint> {
448 match self.to_principal_or_resource_constraint(errs)? {
449 PrincipalOrResource::Principal(_) => {
450 errs.push(err::ParseError::ToAST(
451 "expected resource constraint, found principal constraint".to_string(),
452 ));
453 None
454 }
455 PrincipalOrResource::Resource(r) => Some(r),
456 }
457 }
458
459 fn to_principal_or_resource_constraint(&self, errs: Errs<'_>) -> Option<PrincipalOrResource> {
460 let maybe_vardef = self.as_inner();
461 let vardef = maybe_vardef?;
463
464 let var = vardef.variable.to_var(errs)?;
465
466 match vardef.variable.to_var(errs) {
467 Some(v) if v == var => Some(()),
468 Some(other) => {
469 errs.push(err::ParseError::ToAST(format!(
470 "expected {var} found {other}"
471 )));
472 None
473 }
474 None => None,
475 }?;
476
477 if let Some(typename) = vardef.name.as_ref() {
478 typename.to_type_constraint(errs)?;
479 }
480
481 let c = if let Some((op, rel_expr)) = &vardef.ineq {
482 let eref = rel_expr.to_ref_or_slot(errs, var)?;
483 match op {
484 cst::RelOp::Eq => Some(PrincipalOrResourceConstraint::Eq(eref)),
485 cst::RelOp::In => Some(PrincipalOrResourceConstraint::In(eref)),
486 _ => {
487 errs.push(err::ParseError::ToAST(
488 "policy head constraints must be `in` or `==`".to_string(),
489 ));
490 None
491 }
492 }
493 } else {
494 Some(PrincipalOrResourceConstraint::Any)
495 }?;
496 match var {
497 ast::Var::Principal => {
498 Some(PrincipalOrResource::Principal(PrincipalConstraint::new(c)))
499 }
500 ast::Var::Action => {
501 errs.push(err::ParseError::ToAST("unexpected `action`".to_string()));
502 None
503 }
504 ast::Var::Resource => Some(PrincipalOrResource::Resource(ResourceConstraint::new(c))),
505 ast::Var::Context => {
506 errs.push(err::ParseError::ToAST("unexpected `context`".to_string()));
507 None
508 }
509 }
510 }
511
512 fn to_action_constraint(&self, errs: Errs<'_>) -> Option<ast::ActionConstraint> {
513 let maybe_vardef = self.as_inner();
514 let vardef = maybe_vardef?;
515
516 match vardef.variable.to_var(errs) {
517 Some(ast::Var::Action) => Some(()),
518 Some(other) => {
519 errs.push(err::ParseError::ToAST(format!(
520 "expected {}, found {other}",
521 ast::Var::Action
522 )));
523 None
524 }
525 None => None,
526 }?;
527
528 if let Some(typename) = vardef.name.as_ref() {
529 typename.to_type_constraint(errs)?;
530 }
531
532 let action_constraint = if let Some((op, rel_expr)) = &vardef.ineq {
533 let refs = rel_expr.to_refs(errs, ast::Var::Action)?;
534 match (op, refs) {
535 (cst::RelOp::In, OneOrMultipleRefs::Multiple(euids)) => {
536 Some(ActionConstraint::is_in(euids))
537 }
538 (cst::RelOp::In, OneOrMultipleRefs::Single(euid)) => {
539 Some(ActionConstraint::is_in([euid]))
540 }
541 (cst::RelOp::Eq, OneOrMultipleRefs::Single(euid)) => {
542 Some(ActionConstraint::is_eq(euid))
543 }
544 (cst::RelOp::Eq, OneOrMultipleRefs::Multiple(_)) => {
545 errs.push(err::ParseError::ToAST(
546 "constraints for `==` must be a single literal euid".to_string(),
547 ));
548 None
549 }
550 _ => {
551 errs.push(err::ParseError::ToAST(
552 "policy head constraints must be `in` or `==`".to_string(),
553 ));
554 None
555 }
556 }
557 } else {
558 Some(ActionConstraint::Any)
559 }?;
560
561 match action_constraint_contains_only_action_types(action_constraint) {
562 Ok(a) => Some(a),
563 Err(mut id_errs) => {
564 errs.append(&mut id_errs);
565 None
566 }
567 }
568 }
569}
570
571fn action_type_error_msg(euid: &EntityUID) -> ParseError {
572 let msg = format!("Expected an EntityUID with the type `Action`. Got: {euid}");
573 ParseError::ToCST(msg)
574}
575
576fn action_constraint_contains_only_action_types(
578 a: ActionConstraint,
579) -> Result<ActionConstraint, Vec<ParseError>> {
580 match a {
581 ActionConstraint::Any => Ok(a),
582 ActionConstraint::In(ref euids) => {
583 let non_actions = euids
584 .iter()
585 .filter(|euid| !euid_has_action_type(euid))
586 .collect::<Vec<_>>();
587 if non_actions.is_empty() {
588 Ok(a)
589 } else {
590 Err(non_actions
591 .into_iter()
592 .map(|euid| action_type_error_msg(euid.as_ref()))
593 .collect())
594 }
595 }
596 ActionConstraint::Eq(ref euid) => {
597 if euid_has_action_type(euid) {
598 Ok(a)
599 } else {
600 Err(vec![action_type_error_msg(euid)])
601 }
602 }
603 }
604}
605
606fn euid_has_action_type(euid: &EntityUID) -> bool {
608 if let EntityType::Concrete(name) = euid.entity_type() {
609 name.id.as_ref() == "Action"
610 } else {
611 false
612 }
613}
614
615impl ASTNode<Option<cst::Cond>> {
616 fn to_expr(&self, errs: Errs<'_>) -> Option<ast::Expr> {
618 let (src, maybe_cond) = self.as_inner_pair();
619 let cond = maybe_cond?;
621
622 let maybe_is_when = cond.cond.to_cond_is_when(errs);
623
624 let maybe_expr = match &cond.expr {
625 Some(expr) => expr.to_expr(errs),
626 None => {
627 errs.push(err::ParseError::ToAST(match cond.cond.as_ref().node {
628 Some(ident) => format!("{} clause should not be empty", &ident),
629 None => "bad use of {}".to_string(), }));
631 None
632 }
633 };
634
635 match (maybe_is_when, maybe_expr) {
636 (Some(true), Some(e)) => Some(e),
637 (Some(false), Some(e)) => Some(construct_expr_not(e, src.clone())),
638 _ => None,
639 }
640 }
641}
642
643impl ASTNode<Option<cst::Str>> {
644 pub(crate) fn as_valid_string(&self, errs: Errs<'_>) -> Option<&SmolStr> {
645 let id = self.as_inner();
646 let id = id?;
648
649 match id {
650 cst::Str::String(s) => Some(s),
651 cst::Str::Invalid(s) => {
653 errs.push(err::ParseError::ToAST(format!(
654 "this is an invalid string: {s}"
655 )));
656 None
657 }
658 }
659 }
660}
661
662pub(crate) enum ExprOrSpecial<'a> {
668 Expr(ast::Expr),
670 Var(ast::Var, SourceInfo),
672 Name(ast::Name),
674 StrLit(&'a SmolStr, SourceInfo),
677}
678
679impl ExprOrSpecial<'_> {
680 fn into_expr(self, errs: Errs<'_>) -> Option<ast::Expr> {
681 match self {
682 Self::Expr(e) => Some(e),
683 Self::Var(v, l) => Some(construct_expr_var(v, l)),
684 Self::Name(n) => {
685 errs.push(err::ParseError::ToAST(format!(
686 "Arbitrary variables are not supported; did you mean to enclose {n} in quotes to make a string?",
687 )));
688 None
689 }
690 Self::StrLit(s, l) => match to_unescaped_string(s) {
691 Ok(s) => Some(construct_expr_string(s, l)),
692 Err(escape_errs) => {
693 errs.extend(
694 escape_errs
695 .into_iter()
696 .map(|e| ParseError::ToAST(e.to_string())),
697 );
698 None
699 }
700 },
701 }
702 }
703
704 pub(crate) fn into_valid_attr(self, errs: Errs<'_>) -> Option<SmolStr> {
706 match self {
707 Self::Var(var, _) => Some(construct_string_from_var(var)),
708 Self::Name(name) => name.into_valid_attr(errs),
709 Self::StrLit(s, _) => match to_unescaped_string(s) {
710 Ok(s) => Some(s),
711 Err(escape_errs) => {
712 errs.extend(
713 escape_errs
714 .into_iter()
715 .map(|e| ParseError::ToAST(e.to_string())),
716 );
717 None
718 }
719 },
720 Self::Expr(e) => {
721 errs.push(err::ParseError::ToAST(format!("not a valid string: {e}")));
722 None
723 }
724 }
725 }
726
727 fn into_pattern(self, errs: Errs<'_>) -> Option<Vec<PatternElem>> {
728 match self {
729 Self::StrLit(s, _) => match to_pattern(s) {
730 Ok(pat) => Some(pat),
731 Err(escape_errs) => {
732 errs.extend(
733 escape_errs
734 .into_iter()
735 .map(|e| ParseError::ToAST(e.to_string())),
736 );
737 None
738 }
739 },
740 Self::Var(var, _) => {
741 errs.push(err::ParseError::ToAST(format!(
742 "not a string literal: {var}"
743 )));
744 None
745 }
746 Self::Name(name) => {
747 errs.push(err::ParseError::ToAST(format!(
748 "not a string literal: {name}"
749 )));
750 None
751 }
752 Self::Expr(e) => {
753 errs.push(err::ParseError::ToAST(format!("not a string literal: {e}")));
754 None
755 }
756 }
757 }
758 fn into_string_literal(self, errs: Errs<'_>) -> Option<SmolStr> {
760 match self {
761 Self::StrLit(s, _) => match to_unescaped_string(s) {
762 Ok(s) => Some(s),
763 Err(escape_errs) => {
764 errs.extend(
765 escape_errs
766 .into_iter()
767 .map(|e| ParseError::ToAST(e.to_string())),
768 );
769 None
770 }
771 },
772 Self::Var(var, _) => {
773 errs.push(err::ParseError::ToAST(format!(
774 "not a string literal: {var}"
775 )));
776 None
777 }
778 Self::Name(name) => {
779 errs.push(err::ParseError::ToAST(format!(
780 "not a string literal: {name}"
781 )));
782 None
783 }
784 Self::Expr(e) => {
785 errs.push(err::ParseError::ToAST(format!("not a string literal: {e}")));
786 None
787 }
788 }
789 }
790}
791
792impl ASTNode<Option<cst::Expr>> {
793 fn to_ref(&self, var: ast::Var, errs: Errs<'_>) -> Option<EntityUID> {
795 self.to_ref_or_refs::<SingleEntity>(errs, var).map(|x| x.0)
796 }
797
798 fn to_ref_or_slot(&self, errs: Errs<'_>, var: ast::Var) -> Option<EntityReference> {
799 self.to_ref_or_refs::<EntityReference>(errs, var)
800 }
801
802 fn to_refs(&self, errs: Errs<'_>, var: ast::Var) -> Option<OneOrMultipleRefs> {
803 self.to_ref_or_refs::<OneOrMultipleRefs>(errs, var)
804 }
805
806 fn to_ref_or_refs<T: RefKind>(&self, errs: Errs<'_>, var: ast::Var) -> Option<T> {
807 let maybe_expr = self.as_inner();
808 let expr = &*maybe_expr?.expr;
809 match expr {
810 cst::ExprData::Or(o) => o.to_ref_or_refs::<T>(errs, var),
811 cst::ExprData::If(_, _, _) => {
812 errs.push(err::ParseError::ToAST(format!(
813 "expected {}, found an if statement",
814 T::err_string()
815 )));
816 None
817 }
818 }
819 }
820
821 pub fn to_expr(&self, errs: Errs<'_>) -> Option<ast::Expr> {
823 self.to_expr_or_special(errs)?.into_expr(errs)
824 }
825 pub(crate) fn to_expr_or_special(&self, errs: Errs<'_>) -> Option<ExprOrSpecial<'_>> {
826 let (src, maybe_expr) = self.as_inner_pair();
827 let expr = &*maybe_expr?.expr;
829
830 match expr {
831 cst::ExprData::Or(or) => or.to_expr_or_special(errs),
832 cst::ExprData::If(i, t, e) => {
833 let maybe_guard = i.to_expr(errs);
834 let maybe_then = t.to_expr(errs);
835 let maybe_else = e.to_expr(errs);
836
837 match (maybe_guard, maybe_then, maybe_else) {
838 (Some(i), Some(t), Some(e)) => {
839 Some(ExprOrSpecial::Expr(construct_expr_if(i, t, e, src.clone())))
840 }
841 _ => None,
842 }
843 }
844 }
845 }
846}
847
848trait RefKind: Sized {
852 fn err_string() -> &'static str;
853 fn create_single_ref(e: EntityUID, errs: Errs<'_>) -> Option<Self>;
854 fn create_multiple_refs(es: Vec<EntityUID>, errs: Errs<'_>) -> Option<Self>;
855 fn create_slot(errs: Errs<'_>) -> Option<Self>;
856}
857
858struct SingleEntity(pub EntityUID);
859
860impl RefKind for SingleEntity {
861 fn err_string() -> &'static str {
862 "entity uid"
863 }
864
865 fn create_single_ref(e: EntityUID, _errs: Errs<'_>) -> Option<Self> {
866 Some(SingleEntity(e))
867 }
868
869 fn create_multiple_refs(_es: Vec<EntityUID>, errs: Errs<'_>) -> Option<Self> {
870 errs.push(err::ParseError::ToAST(
871 "expected single entity uid, got a set of entity uids".to_string(),
872 ));
873 None
874 }
875
876 fn create_slot(errs: Errs<'_>) -> Option<Self> {
877 errs.push(err::ParseError::ToAST(
878 "expected a single entity uid, got a template slot".to_string(),
879 ));
880 None
881 }
882}
883
884impl RefKind for EntityReference {
885 fn err_string() -> &'static str {
886 "entity uid or template slot"
887 }
888
889 fn create_slot(_: Errs<'_>) -> Option<Self> {
890 Some(EntityReference::Slot)
891 }
892
893 fn create_single_ref(e: EntityUID, _errs: Errs<'_>) -> Option<Self> {
894 Some(EntityReference::euid(e))
895 }
896
897 fn create_multiple_refs(_es: Vec<EntityUID>, errs: Errs<'_>) -> Option<Self> {
898 errs.push(err::ParseError::ToAST(
899 "expected single entity uid or template slot, got a set of entity uids".to_string(),
900 ));
901 None
902 }
903}
904
905#[derive(Debug)]
907enum OneOrMultipleRefs {
908 Single(EntityUID),
909 Multiple(Vec<EntityUID>),
910}
911
912impl RefKind for OneOrMultipleRefs {
913 fn err_string() -> &'static str {
914 "entity uid, set of entity uids, or template slot"
915 }
916
917 fn create_slot(errs: Errs<'_>) -> Option<Self> {
918 errs.push(err::ParseError::ToAST("Unexpected slot".to_string()));
919 None
920 }
921
922 fn create_single_ref(e: EntityUID, _errs: Errs<'_>) -> Option<Self> {
923 Some(OneOrMultipleRefs::Single(e))
924 }
925
926 fn create_multiple_refs(es: Vec<EntityUID>, _errs: Errs<'_>) -> Option<Self> {
927 Some(OneOrMultipleRefs::Multiple(es))
928 }
929}
930
931impl ASTNode<Option<cst::Or>> {
932 fn to_expr_or_special(&self, errs: Errs<'_>) -> Option<ExprOrSpecial<'_>> {
933 let (src, maybe_or) = self.as_inner_pair();
934 let or = maybe_or?;
936
937 let maybe_first = or.initial.to_expr_or_special(errs);
938 let mut more = or.extended.iter().filter_map(|i| i.to_expr(errs));
939 let maybe_second = more.next();
941 let rest: Vec<_> = more.collect();
943
944 match (maybe_first, maybe_second, rest.len(), or.extended.len()) {
945 (f, None, _, 0) => f,
946 (Some(f), Some(s), r, e) if 1 + r == e => f
947 .into_expr(errs)
948 .map(|e| ExprOrSpecial::Expr(construct_expr_or(e, s, rest, src.clone()))),
949 _ => None,
950 }
951 }
952
953 fn to_ref_or_refs<T: RefKind>(&self, errs: Errs<'_>, var: ast::Var) -> Option<T> {
954 let maybe_or = self.as_inner();
955 let or = maybe_or?;
956 match or.extended.len() {
957 0 => or.initial.to_ref_or_refs::<T>(errs, var),
958 _n => {
959 errs.push(err::ParseError::ToAST(format!(
960 "expected {}, found ||",
961 T::err_string()
962 )));
963 None
964 }
965 }
966 }
967}
968
969impl ASTNode<Option<cst::And>> {
970 fn to_ref_or_refs<T: RefKind>(&self, errs: Errs<'_>, var: ast::Var) -> Option<T> {
971 let maybe_and = self.as_inner();
972 let and = maybe_and?;
973 match and.extended.len() {
974 0 => and.initial.to_ref_or_refs::<T>(errs, var),
975 _n => {
976 errs.push(err::ParseError::ToAST(format!(
977 "expected {}, found &&",
978 T::err_string()
979 )));
980 None
981 }
982 }
983 }
984
985 fn to_expr(&self, errs: Errs<'_>) -> Option<ast::Expr> {
986 self.to_expr_or_special(errs)?.into_expr(errs)
987 }
988 fn to_expr_or_special(&self, errs: Errs<'_>) -> Option<ExprOrSpecial<'_>> {
989 let (src, maybe_and) = self.as_inner_pair();
990 let and = maybe_and?;
992
993 let maybe_first = and.initial.to_expr_or_special(errs);
994 let mut more = and.extended.iter().filter_map(|i| i.to_expr(errs));
995 let maybe_second = more.next();
997 let rest: Vec<_> = more.collect();
999
1000 match (maybe_first, maybe_second, rest.len(), and.extended.len()) {
1001 (f, None, _, 0) => f,
1002 (Some(f), Some(s), r, e) if 1 + r == e => f
1003 .into_expr(errs)
1004 .map(|e| ExprOrSpecial::Expr(construct_expr_and(e, s, rest, src.clone()))),
1005 _ => None,
1006 }
1007 }
1008}
1009
1010impl ASTNode<Option<cst::Relation>> {
1011 fn to_ref_or_refs<T: RefKind>(&self, errs: Errs<'_>, var: ast::Var) -> Option<T> {
1012 let maybe_rel = self.as_inner();
1013 match maybe_rel? {
1014 cst::Relation::Common { initial, extended } => match extended.len() {
1015 0 => initial.to_ref_or_refs::<T>(errs, var),
1016 _n => {
1017 errs.push(err::ParseError::ToAST(format!(
1018 "expected {}, found binary operation",
1019 T::err_string()
1020 )));
1021 None
1022 }
1023 },
1024 cst::Relation::Has { .. } => {
1025 errs.push(err::ParseError::ToAST(format!(
1026 "expected {}, found `has` relation",
1027 T::err_string()
1028 )));
1029 None
1030 }
1031 cst::Relation::Like { .. } => {
1032 errs.push(err::ParseError::ToAST(format!(
1033 "expected {}, found `like` relation",
1034 T::err_string()
1035 )));
1036 None
1037 }
1038 }
1039 }
1040
1041 fn to_expr(&self, errs: Errs<'_>) -> Option<ast::Expr> {
1042 self.to_expr_or_special(errs)?.into_expr(errs)
1043 }
1044 fn to_expr_or_special(&self, errs: Errs<'_>) -> Option<ExprOrSpecial<'_>> {
1045 let (src, maybe_rel) = self.as_inner_pair();
1046 let rel = maybe_rel?;
1048
1049 match rel {
1050 cst::Relation::Common { initial, extended } => {
1051 let maybe_first = initial.to_expr_or_special(errs);
1052 let mut more = extended
1053 .iter()
1054 .filter_map(|(op, i)| i.to_expr(errs).map(|e| (op, e)));
1055 let maybe_second = more.next();
1057 let _rest: Vec<_> = more.collect();
1059
1060 match (maybe_first, maybe_second, extended.len()) {
1061 (_, _, l) if l > 1 => {
1062 errs.push(err::ParseError::ToAST(
1063 "Multiple relational operators (>, ==, in, etc.) without parentheses"
1064 .to_string(),
1065 ));
1066 None
1067 }
1068 (_, None, 1) => None,
1070 (f, None, 0) => f,
1071 (Some(f), Some((op, s)), _) => f
1072 .into_expr(errs)
1073 .map(|e| ExprOrSpecial::Expr(construct_expr_rel(e, *op, s, src.clone()))),
1074 _ => None,
1075 }
1076 }
1077 cst::Relation::Has { target, field } => {
1078 match (
1079 target.to_expr(errs),
1080 field.to_expr_or_special(errs)?.into_valid_attr(errs),
1081 ) {
1082 (Some(t), Some(s)) => {
1083 Some(ExprOrSpecial::Expr(construct_expr_has(t, s, src.clone())))
1084 }
1085 _ => None,
1086 }
1087 }
1088 cst::Relation::Like { target, pattern } => {
1089 match (
1090 target.to_expr(errs),
1091 pattern.to_expr_or_special(errs)?.into_pattern(errs),
1092 ) {
1093 (Some(t), Some(s)) => {
1094 Some(ExprOrSpecial::Expr(construct_expr_like(t, s, src.clone())))
1095 }
1096 _ => None,
1097 }
1098 }
1099 }
1100 }
1101}
1102
1103impl ASTNode<Option<cst::Add>> {
1104 fn to_ref_or_refs<T: RefKind>(&self, errs: Errs<'_>, var: ast::Var) -> Option<T> {
1105 let maybe_add = self.as_inner();
1106 let add = maybe_add?;
1107 match add.extended.len() {
1108 0 => add.initial.to_ref_or_refs::<T>(errs, var),
1109 _n => {
1110 errs.push(err::ParseError::ToAST(format!(
1111 "expected {}, found arithmetic",
1112 T::err_string()
1113 )));
1114 None
1115 }
1116 }
1117 }
1118
1119 fn to_expr(&self, errs: Errs<'_>) -> Option<ast::Expr> {
1120 self.to_expr_or_special(errs)?.into_expr(errs)
1121 }
1122 fn to_expr_or_special(&self, errs: Errs<'_>) -> Option<ExprOrSpecial<'_>> {
1123 let (src, maybe_add) = self.as_inner_pair();
1124 let add = maybe_add?;
1126
1127 let maybe_first = add.initial.to_expr_or_special(errs);
1128 let more: Vec<(cst::AddOp, _)> = add
1130 .extended
1131 .iter()
1132 .filter_map(|&(op, ref i)| i.to_expr(errs).map(|e| (op, e)))
1133 .collect();
1134 if !more.is_empty() {
1135 Some(ExprOrSpecial::Expr(construct_expr_add(
1136 maybe_first?.into_expr(errs)?,
1137 more,
1138 src.clone(),
1139 )))
1140 } else {
1141 maybe_first
1142 }
1143 }
1144}
1145
1146impl ASTNode<Option<cst::Mult>> {
1147 fn to_ref_or_refs<T: RefKind>(&self, errs: Errs<'_>, var: ast::Var) -> Option<T> {
1148 let maybe_mult = self.as_inner();
1149 let mult = maybe_mult?;
1150 match mult.extended.len() {
1151 0 => mult.initial.to_ref_or_refs::<T>(errs, var),
1152 _n => {
1153 errs.push(err::ParseError::ToAST(format!(
1154 "expected {}, found arithmetic",
1155 T::err_string()
1156 )));
1157 None
1158 }
1159 }
1160 }
1161
1162 fn to_expr(&self, errs: Errs<'_>) -> Option<ast::Expr> {
1163 self.to_expr_or_special(errs)?.into_expr(errs)
1164 }
1165 fn to_expr_or_special(&self, errs: Errs<'_>) -> Option<ExprOrSpecial<'_>> {
1166 let (src, maybe_mult) = self.as_inner_pair();
1167 let mult = maybe_mult?;
1169
1170 let maybe_first = mult.initial.to_expr_or_special(errs);
1171 let more: Vec<(cst::MultOp, _)> = mult
1173 .extended
1174 .iter()
1175 .filter_map(|&(op, ref i)| i.to_expr(errs).map(|e| (op, e)))
1176 .collect();
1177
1178 if !more.is_empty() {
1179 let first = maybe_first?.into_expr(errs)?;
1180 for (op, _) in &more {
1182 match op {
1183 cst::MultOp::Times => {}
1184 cst::MultOp::Divide => {
1185 errs.push(ParseError::ToAST("division is not supported".to_string()));
1186 return None;
1187 }
1188 cst::MultOp::Mod => {
1189 errs.push(ParseError::ToAST(
1190 "remainder/modulo is not supported".to_string(),
1191 ));
1192 return None;
1193 }
1194 }
1195 }
1196 let (constantints, nonconstantints): (Vec<ast::Expr>, Vec<ast::Expr>) =
1200 std::iter::once(first)
1201 .chain(more.into_iter().map(|(_, e)| e))
1202 .partition(|e| {
1203 matches!(e.expr_kind(), ast::ExprKind::Lit(ast::Literal::Long(_)))
1204 });
1205 let constantints = constantints
1206 .into_iter()
1207 .map(|e| match e.expr_kind() {
1208 ast::ExprKind::Lit(ast::Literal::Long(i)) => *i,
1209 _ => unreachable!(
1210 "checked it matched ast::ExprKind::Lit(ast::Literal::Long(_)) above"
1211 ),
1212 })
1213 .collect::<Vec<i64>>();
1214 if nonconstantints.len() > 1 {
1215 errs.push(err::ParseError::ToAST(
1217 "Multiplication must be by a constant int".to_string(), ));
1219 None
1220 } else if nonconstantints.is_empty() {
1221 Some(ExprOrSpecial::Expr(construct_expr_mul(
1222 construct_expr_num(constantints[0], src.clone()),
1223 constantints[1..].iter().copied(),
1224 src.clone(),
1225 )))
1226 } else {
1227 let nonconstantint: ast::Expr = nonconstantints
1228 .into_iter()
1229 .next()
1230 .expect("already checked that it's not empty");
1231 Some(ExprOrSpecial::Expr(construct_expr_mul(
1232 nonconstantint,
1233 constantints,
1234 src.clone(),
1235 )))
1236 }
1237 } else {
1238 maybe_first
1239 }
1240 }
1241}
1242
1243impl ASTNode<Option<cst::Unary>> {
1244 fn to_ref_or_refs<T: RefKind>(&self, errs: Errs<'_>, var: ast::Var) -> Option<T> {
1245 let maybe_unary = self.as_inner();
1246 let unary = maybe_unary?;
1247 match &unary.op {
1248 Some(_op) => {
1249 errs.push(err::ParseError::ToAST(
1250 "expected entity uid found unary operation".to_string(),
1251 ));
1252 None
1253 }
1254 None => unary.item.to_ref_or_refs::<T>(errs, var),
1255 }
1256 }
1257
1258 fn to_expr(&self, errs: Errs<'_>) -> Option<ast::Expr> {
1259 self.to_expr_or_special(errs)?.into_expr(errs)
1260 }
1261 fn to_expr_or_special(&self, errs: Errs<'_>) -> Option<ExprOrSpecial<'_>> {
1262 let (src, maybe_unary) = self.as_inner_pair();
1263 let unary = maybe_unary?;
1265
1266 let mut maybe_item = || unary.item.to_expr_or_special(errs);
1268
1269 match unary.op {
1270 None => maybe_item(),
1271 Some(cst::NegOp::Bang(0)) => maybe_item(),
1272 Some(cst::NegOp::Dash(0)) => maybe_item(),
1273 Some(cst::NegOp::Bang(n)) => {
1274 let item = maybe_item().and_then(|i| i.into_expr(errs));
1275 if n % 2 == 0 {
1276 item.map(|i| {
1277 ExprOrSpecial::Expr(construct_expr_not(
1278 construct_expr_not(i, src.clone()),
1279 src.clone(),
1280 ))
1281 })
1282 } else {
1283 item.map(|i| ExprOrSpecial::Expr(construct_expr_not(i, src.clone())))
1285 }
1286 }
1287 Some(cst::NegOp::Dash(c)) => {
1288 let (last, rc) = if let Some(cst::Literal::Num(n)) = unary.item.to_lit() {
1294 match n.cmp(&(i64::MAX as u64 + 1)) {
1295 Ordering::Equal => (
1296 Some(construct_expr_num(i64::MIN, unary.item.info.clone())),
1297 c - 1,
1298 ),
1299 Ordering::Less => (
1300 Some(construct_expr_num(-(*n as i64), unary.item.info.clone())),
1301 c - 1,
1302 ),
1303 Ordering::Greater => {
1304 errs.push(err::ParseError::ToAST(
1305 "Integer constant is too large!".to_string(),
1306 ));
1307 (None, 0)
1308 }
1309 }
1310 } else {
1311 (maybe_item().and_then(|i| i.into_expr(errs)), c)
1314 };
1315 (0..rc)
1317 .fold(last, |r, _| r.map(|e| (construct_expr_neg(e, src.clone()))))
1318 .map(ExprOrSpecial::Expr)
1319 }
1320 Some(cst::NegOp::OverBang) => {
1321 errs.push(err::ParseError::ToAST("Too many '!'s".to_string()));
1322 None
1323 }
1324 Some(cst::NegOp::OverDash) => {
1325 errs.push(err::ParseError::ToAST("Too many '-'s".to_string()));
1326 None
1327 }
1328 }
1329 }
1330}
1331
1332enum AstAccessor {
1334 Field(ast::Id),
1335 Call(Vec<ast::Expr>),
1336 Index(SmolStr),
1337}
1338
1339impl ASTNode<Option<cst::Member>> {
1340 fn to_lit(&self) -> Option<&cst::Literal> {
1345 let m = self.as_ref().node.as_ref()?;
1346 if !m.access.is_empty() {
1347 return None;
1348 }
1349 match m.item.as_ref().node.as_ref()? {
1350 cst::Primary::Literal(l) => l.as_ref().node.as_ref(),
1351 _ => None,
1352 }
1353 }
1354
1355 fn to_ref_or_refs<T: RefKind>(&self, errs: Errs<'_>, var: ast::Var) -> Option<T> {
1356 let maybe_mem = self.as_inner();
1357 let mem = maybe_mem?;
1358 match mem.access.len() {
1359 0 => mem.item.to_ref_or_refs::<T>(errs, var),
1360 _n => {
1361 errs.push(err::ParseError::ToAST(
1362 "expected entity uid, found member access".to_string(),
1363 ));
1364 None
1365 }
1366 }
1367 }
1368
1369 fn to_expr_or_special(&self, errs: Errs<'_>) -> Option<ExprOrSpecial<'_>> {
1370 let (src, maybe_mem) = self.as_inner_pair();
1371 let mem = maybe_mem?;
1373
1374 let maybe_prim = mem.item.to_expr_or_special(errs);
1375
1376 let mut accessors: Vec<_> = mem.access.iter().map(|a| a.to_access(errs)).collect();
1378
1379 let mut head = maybe_prim;
1381 let mut tail = &mut accessors[..];
1385
1386 loop {
1396 use AstAccessor::*;
1397 use ExprOrSpecial::*;
1398 match (&mut head, tail) {
1399 (_, []) => break head,
1401 (_, [None, Some(Call(_)), rest @ ..]) => {
1403 head = None;
1404 tail = rest;
1405 }
1406 (_, [None, rest @ ..]) => {
1408 head = None;
1409 tail = rest;
1410 }
1411 (Some(Name(n)), [Some(Call(a)), rest @ ..]) => {
1413 let args = std::mem::take(a);
1415 let nn =
1417 mem::replace(n, ast::Name::unqualified_name(ast::Id::new_unchecked("")));
1418 head = nn.into_func(args, errs, src.clone()).map(Expr);
1419 tail = rest;
1420 }
1421 (Some(Var(_, _)), [Some(Call(_)), rest @ ..]) => {
1423 errs.push(err::ParseError::ToAST(
1424 "Variables cannot be used as functions".to_string(),
1425 ));
1426 head = None;
1427 tail = rest;
1428 }
1429 (_, [Some(Call(_)), rest @ ..]) => {
1431 errs.push(err::ParseError::ToAST(
1432 "All functions are named, this cannot be called".to_string(),
1433 ));
1434 head = None;
1435 tail = rest;
1436 }
1437 (None, [Some(Field(_)), Some(Call(_)), rest @ ..]) => {
1439 tail = rest;
1440 }
1441 (Some(Name(_)), [Some(Field(_)), Some(Call(_)), rest @ ..]) => {
1443 errs.push(err::ParseError::ToAST(
1444 "This item does not have methods".to_string(),
1445 ));
1446 head = None;
1447 tail = rest;
1448 }
1449 (Some(Var(v, vl)), [Some(Field(i)), Some(Call(a)), rest @ ..]) => {
1451 let var = mem::replace(v, ast::Var::Principal);
1453 let args = std::mem::take(a);
1454 let id = mem::replace(i, ast::Id::new_unchecked(""));
1456 head = id
1457 .to_meth(construct_expr_var(var, vl.clone()), args, errs, src.clone())
1458 .map(Expr);
1459 tail = rest;
1460 }
1461 (Some(Expr(e)), [Some(Field(i)), Some(Call(a)), rest @ ..]) => {
1463 let args = std::mem::take(a);
1465 let expr = mem::replace(e, ast::Expr::val(false));
1466 let id = mem::replace(i, ast::Id::new_unchecked(""));
1468 head = id.to_meth(expr, args, errs, src.clone()).map(Expr);
1469 tail = rest;
1470 }
1471 (Some(StrLit(s, sl)), [Some(Field(i)), Some(Call(a)), rest @ ..]) => {
1473 let args = std::mem::take(a);
1474 let id = mem::replace(i, ast::Id::new_unchecked(""));
1475 let maybe_expr = match to_unescaped_string(s) {
1476 Ok(s) => Some(construct_expr_string(s, sl.clone())),
1477 Err(escape_errs) => {
1478 errs.extend(
1479 escape_errs
1480 .into_iter()
1481 .map(|e| ParseError::ToAST(e.to_string())),
1482 );
1483 None
1484 }
1485 };
1486 head =
1487 maybe_expr.and_then(|e| id.to_meth(e, args, errs, src.clone()).map(Expr));
1488 tail = rest;
1489 }
1490 (None, [Some(Field(_)) | Some(Index(_)), rest @ ..]) => {
1492 tail = rest;
1493 }
1494 (Some(Name(_)), [Some(Field(_)) | Some(Index(_)), rest @ ..]) => {
1496 errs.push(err::ParseError::ToAST(
1497 "This item is not a data structure".to_string(),
1498 ));
1499 head = None;
1500 tail = rest;
1501 }
1502 (Some(Var(v, vl)), [Some(Field(i)), rest @ ..]) => {
1504 let var = mem::replace(v, ast::Var::Principal);
1505 let id = mem::replace(i, ast::Id::new_unchecked(""));
1506 head = Some(Expr(construct_expr_attr(
1507 construct_expr_var(var, vl.clone()),
1508 id.to_smolstr(),
1509 src.clone(),
1510 )));
1511 tail = rest;
1512 }
1513 (Some(Expr(e)), [Some(Field(i)), rest @ ..]) => {
1515 let expr = mem::replace(e, ast::Expr::val(false));
1516 let id = mem::replace(i, ast::Id::new_unchecked(""));
1517 head = Some(Expr(construct_expr_attr(
1518 expr,
1519 id.to_smolstr(),
1520 src.clone(),
1521 )));
1522 tail = rest;
1523 }
1524 (Some(StrLit(s, sl)), [Some(Field(i)), rest @ ..]) => {
1526 let id = mem::replace(i, ast::Id::new_unchecked(""));
1527 let maybe_expr = match to_unescaped_string(s) {
1528 Ok(s) => Some(construct_expr_string(s, sl.clone())),
1529 Err(escape_errs) => {
1530 errs.extend(
1531 escape_errs
1532 .into_iter()
1533 .map(|e| ParseError::ToAST(e.to_string())),
1534 );
1535 None
1536 }
1537 };
1538 head = maybe_expr
1539 .map(|e| Expr(construct_expr_attr(e, id.to_smolstr(), src.clone())));
1540 tail = rest;
1541 }
1542 (Some(Var(v, vl)), [Some(Index(i)), rest @ ..]) => {
1544 let var = mem::replace(v, ast::Var::Principal);
1545 let s = mem::take(i);
1546 head = Some(Expr(construct_expr_attr(
1547 construct_expr_var(var, vl.clone()),
1548 s,
1549 src.clone(),
1550 )));
1551 tail = rest;
1552 }
1553 (Some(Expr(e)), [Some(Index(i)), rest @ ..]) => {
1555 let expr = mem::replace(e, ast::Expr::val(false));
1556 let s = mem::take(i);
1557 head = Some(Expr(construct_expr_attr(expr, s, src.clone())));
1558 tail = rest;
1559 }
1560 (Some(StrLit(s, sl)), [Some(Index(i)), rest @ ..]) => {
1562 let id = mem::take(i);
1563 let maybe_expr = match to_unescaped_string(s) {
1564 Ok(s) => Some(construct_expr_string(s, sl.clone())),
1565 Err(escape_errs) => {
1566 errs.extend(
1567 escape_errs
1568 .into_iter()
1569 .map(|e| ParseError::ToAST(e.to_string())),
1570 );
1571 None
1572 }
1573 };
1574 head = maybe_expr.map(|e| Expr(construct_expr_attr(e, id, src.clone())));
1575 tail = rest;
1576 }
1577 }
1578 }
1579 }
1580}
1581
1582impl ASTNode<Option<cst::MemAccess>> {
1583 fn to_access(&self, errs: Errs<'_>) -> Option<AstAccessor> {
1584 let maybe_acc = self.as_inner();
1585 let acc = maybe_acc?;
1587
1588 match acc {
1589 cst::MemAccess::Field(i) => {
1590 let ident = i.to_valid_ident(errs);
1591 ident.map(AstAccessor::Field)
1592 }
1593 cst::MemAccess::Call(args) => {
1594 let conv_args: Vec<_> = args.iter().filter_map(|e| e.to_expr(errs)).collect();
1595 if conv_args.len() == args.len() {
1596 Some(AstAccessor::Call(conv_args))
1597 } else {
1598 None
1599 }
1600 }
1601 cst::MemAccess::Index(index) => {
1602 let s = index.to_expr_or_special(errs)?.into_string_literal(errs);
1603 s.map(AstAccessor::Index)
1604 }
1605 }
1606 }
1607}
1608
1609impl ASTNode<Option<cst::Primary>> {
1610 fn to_ref_or_refs<T: RefKind>(&self, errs: Errs<'_>, var: ast::Var) -> Option<T> {
1611 let maybe_prim = self.as_inner();
1612 let prim = maybe_prim?;
1613 let r: Result<Option<T>, String> = match prim {
1614 cst::Primary::Slot(s) => {
1615 let slot = s.as_inner()?;
1616 if slot.matches(var) {
1617 Ok(T::create_slot(errs))
1618 } else {
1619 Err(format!(
1620 "A slot here must be named ?{}, found ?{}",
1621 var, slot
1622 ))
1623 }
1624 }
1625 cst::Primary::Literal(_) => {
1626 Err(format!("expected {} found a literal", T::err_string()))
1627 }
1628 cst::Primary::Ref(x) => Ok(T::create_single_ref(x.to_ref(errs)?, errs)),
1629 cst::Primary::Name(_) => Err(format!("expected {} found a name", T::err_string())),
1630 cst::Primary::Expr(x) => Ok(x.to_ref_or_refs::<T>(errs, var)),
1631 cst::Primary::EList(lst) => {
1632 let v: Option<Vec<EntityUID>> =
1633 lst.iter().map(|expr| expr.to_ref(var, errs)).collect();
1634 Ok(T::create_multiple_refs(v?, errs))
1635 }
1636 cst::Primary::RInits(_) => Err("record initializer".to_string()),
1637 };
1638 match r {
1639 Ok(t) => t,
1640 Err(found) => {
1641 errs.push(err::ParseError::ToAST(format!(
1642 "expected {}, found {}",
1643 T::err_string(),
1644 found
1645 )));
1646 None
1647 }
1648 }
1649 }
1650
1651 pub(crate) fn to_expr(&self, errs: Errs<'_>) -> Option<ast::Expr> {
1652 self.to_expr_or_special(errs)?.into_expr(errs)
1653 }
1654 fn to_expr_or_special(&self, errs: Errs<'_>) -> Option<ExprOrSpecial<'_>> {
1655 let (src, maybe_prim) = self.as_inner_pair();
1656 let prim = maybe_prim?;
1658
1659 match prim {
1660 cst::Primary::Literal(l) => l.to_expr_or_special(errs),
1661 cst::Primary::Ref(r) => r.to_expr(errs).map(ExprOrSpecial::Expr),
1662 cst::Primary::Slot(s) => s.to_expr(errs).map(ExprOrSpecial::Expr),
1663 #[allow(clippy::manual_map)]
1664 cst::Primary::Name(n) => {
1665 if let Some(v) = n.to_var(&mut Vec::new()) {
1667 Some(ExprOrSpecial::Var(v, src.clone()))
1668 } else if let Some(n) = n.to_name(errs) {
1669 Some(ExprOrSpecial::Name(n))
1670 } else {
1671 None
1672 }
1673 }
1674 cst::Primary::Expr(e) => e.to_expr(errs).map(ExprOrSpecial::Expr),
1675 cst::Primary::EList(es) => {
1676 let list: Vec<_> = es.iter().filter_map(|e| e.to_expr(errs)).collect();
1677 if list.len() == es.len() {
1678 Some(ExprOrSpecial::Expr(construct_expr_set(list, src.clone())))
1679 } else {
1680 None
1681 }
1682 }
1683 cst::Primary::RInits(is) => {
1684 let rec: Vec<_> = is.iter().filter_map(|i| i.to_init(errs)).collect();
1685 if rec.len() == is.len() {
1686 Some(ExprOrSpecial::Expr(construct_expr_record(rec, src.clone())))
1687 } else {
1688 errs.push(err::ParseError::ToAST(
1689 "record literal has some invalid attributes".to_string(),
1690 ));
1691 None
1692 }
1693 }
1694 }
1695 }
1696
1697 pub fn to_string_literal(&self, errs: Errs<'_>) -> Option<SmolStr> {
1700 let maybe_prim = self.as_inner();
1701 let prim = maybe_prim?;
1703
1704 match prim {
1705 cst::Primary::Literal(l) => l.to_expr_or_special(errs)?.into_string_literal(errs),
1706 _ => {
1707 errs.push(err::ParseError::ToAST(format!(
1708 "{prim} is not a string literal"
1709 )));
1710 None
1711 }
1712 }
1713 }
1714}
1715
1716impl ASTNode<Option<cst::Slot>> {
1717 fn to_expr(&self, _errs: Errs<'_>) -> Option<ast::Expr> {
1718 let (src, s) = self.as_inner_pair();
1719 s.map(|s| {
1720 ast::ExprBuilder::new()
1721 .with_source_info(src.clone())
1722 .slot(match s {
1723 cst::Slot::Principal => ast::SlotId::principal(),
1724 cst::Slot::Resource => ast::SlotId::resource(),
1725 })
1726 })
1727 }
1728}
1729
1730impl ASTNode<Option<cst::Name>> {
1731 fn to_type_constraint(&self, errs: Errs<'_>) -> Option<ast::Expr> {
1733 let (src, maybe_name) = self.as_inner_pair();
1734 match maybe_name {
1735 Some(_) => {
1736 errs.push(err::ParseError::ToAST(
1737 "type constraints are not currently supported".to_string(),
1738 ));
1739 None
1740 }
1741 None => Some(construct_expr_bool(true, src.clone())),
1742 }
1743 }
1744
1745 pub(crate) fn to_name(&self, errs: Errs<'_>) -> Option<ast::Name> {
1746 let maybe_name = self.as_inner();
1747 let name = maybe_name?;
1749
1750 let path: Vec<_> = name
1751 .path
1752 .iter()
1753 .filter_map(|i| i.to_valid_ident(errs))
1754 .collect();
1755 let maybe_name = name.name.to_valid_ident(errs);
1756
1757 match (maybe_name, path.len()) {
1759 (Some(r), l) if l == name.path.len() => Some(construct_name(path, r)),
1760 _ => None,
1761 }
1762 }
1763 fn to_ident(&self, errs: Errs<'_>) -> Option<&cst::Ident> {
1764 let maybe_name = self.as_inner();
1765 let name = maybe_name?;
1767
1768 let path: Vec<_> = name
1769 .path
1770 .iter()
1771 .filter_map(|i| i.to_valid_ident(errs))
1772 .collect();
1773 if path.len() > 1 {
1774 errs.push(err::ParseError::ToAST(
1775 "A path is not valid in this context".to_string(),
1776 ));
1777 return None;
1778 }
1779
1780 name.name.as_inner()
1781 }
1782 fn to_var(&self, errs: Errs<'_>) -> Option<ast::Var> {
1783 let name = self.to_ident(errs)?;
1784
1785 match name {
1786 cst::Ident::Principal => Some(ast::Var::Principal),
1787 cst::Ident::Action => Some(ast::Var::Action),
1788 cst::Ident::Resource => Some(ast::Var::Resource),
1789 cst::Ident::Context => Some(ast::Var::Context),
1790 _ => {
1791 errs.push(err::ParseError::ToAST(
1792 "This is not a variable, use principal, action, resource, or context"
1793 .to_string(),
1794 ));
1795 None
1796 }
1797 }
1798 }
1799}
1800
1801impl ast::Name {
1802 fn into_valid_attr(self, errs: Errs<'_>) -> Option<SmolStr> {
1804 if !self.path.is_empty() {
1805 errs.push(err::ParseError::ToAST(
1806 "A name with a path is not a valid attribute".to_string(),
1807 ));
1808 None
1809 } else {
1810 Some(self.id.to_smolstr())
1811 }
1812 }
1813
1814 fn into_func(self, args: Vec<ast::Expr>, errs: Errs<'_>, l: SourceInfo) -> Option<ast::Expr> {
1815 if self.path.is_empty() {
1817 let id = self.id.as_ref();
1818 match id {
1819 "contains" | "containsAll" | "containsAny" => {
1820 errs.push(err::ParseError::ToAST(format!(
1821 "invalid syntax, use method-style function call like e.{}(...)",
1822 id
1823 )));
1824 return None;
1825 }
1826 _ => {}
1827 }
1828 }
1829 if EXTENSION_STYLES.functions.contains(&self) {
1830 Some(construct_ext_func(self, args, l))
1831 } else {
1832 errs.push(err::ParseError::ToAST(format!(
1833 "invalid syntax, expected function, found {}",
1834 self
1835 )));
1836 None
1837 }
1838 }
1839}
1840
1841impl ASTNode<Option<cst::Ref>> {
1842 pub fn to_ref(&self, errs: Errs<'_>) -> Option<ast::EntityUID> {
1844 let maybe_ref = self.as_inner();
1845 let refr = maybe_ref?;
1847
1848 match refr {
1849 cst::Ref::Uid { path, eid } => {
1850 let maybe_path = path.to_name(errs);
1851 let maybe_eid = match eid
1852 .as_valid_string(errs)
1853 .map(|s| to_unescaped_string(s))
1854 .transpose()
1855 {
1856 Ok(opt) => opt,
1857 Err(escape_errs) => {
1858 errs.extend(
1859 escape_errs
1860 .into_iter()
1861 .map(|e| ParseError::ToAST(e.to_string())),
1862 );
1863 None
1864 }
1865 };
1866
1867 match (maybe_path, maybe_eid) {
1868 (Some(p), Some(e)) => Some(construct_refr(p, e)),
1869 _ => None,
1870 }
1871 }
1872 cst::Ref::Ref { .. } => {
1873 errs.push(err::ParseError::ToAST(
1874 "arbitrary entity lookups are not currently supported".to_string(),
1875 ));
1876 None
1877 }
1878 }
1879 }
1880 fn to_expr(&self, errs: Errs<'_>) -> Option<ast::Expr> {
1881 self.to_ref(errs)
1882 .map(|euid| construct_expr_ref(euid, self.info.clone()))
1883 }
1884}
1885
1886impl ASTNode<Option<cst::Literal>> {
1887 fn to_expr_or_special(&self, errs: Errs<'_>) -> Option<ExprOrSpecial<'_>> {
1888 let (src, maybe_lit) = self.as_inner_pair();
1889 let lit = maybe_lit?;
1891
1892 match lit {
1893 cst::Literal::True => Some(ExprOrSpecial::Expr(construct_expr_bool(true, src.clone()))),
1894 cst::Literal::False => {
1895 Some(ExprOrSpecial::Expr(construct_expr_bool(false, src.clone())))
1896 }
1897 cst::Literal::Num(n) => match i64::try_from(*n) {
1898 Ok(i) => Some(ExprOrSpecial::Expr(construct_expr_num(i, src.clone()))),
1899 Err(_) => {
1900 errs.push(ParseError::ToAST(format!("Literal {n} is too large")));
1901 None
1902 }
1903 },
1904 cst::Literal::Str(s) => {
1905 let maybe_str = s.as_valid_string(errs);
1906 maybe_str.map(|s| ExprOrSpecial::StrLit(s, src.clone()))
1907 }
1908 }
1909 }
1910}
1911
1912impl ASTNode<Option<cst::RecInit>> {
1913 fn to_init(&self, errs: Errs<'_>) -> Option<(SmolStr, ast::Expr)> {
1914 let (_src, maybe_lit) = self.as_inner_pair();
1915 let lit = maybe_lit?;
1917
1918 let maybe_attr = lit.0.to_expr_or_special(errs)?.into_valid_attr(errs);
1919 let maybe_value = lit.1.to_expr(errs);
1920
1921 match (maybe_attr, maybe_value) {
1922 (Some(s), Some(v)) => Some((s, v)),
1923 _ => None,
1924 }
1925 }
1926}
1927
1928#[allow(clippy::too_many_arguments)]
1931fn construct_template_policy(
1932 id: ast::PolicyID,
1933 annotations: BTreeMap<ast::Id, SmolStr>,
1934 effect: ast::Effect,
1935 principal: ast::PrincipalConstraint,
1936 action: ast::ActionConstraint,
1937 resource: ast::ResourceConstraint,
1938 conds: Vec<ast::Expr>,
1939 l: SourceInfo,
1940) -> ast::Template {
1941 let construct_template = |non_head_constraint| {
1942 ast::Template::new(
1943 id,
1944 annotations,
1945 effect,
1946 principal,
1947 action,
1948 resource,
1949 non_head_constraint,
1950 )
1951 };
1952 let mut conds_iter = conds.into_iter();
1953 if let Some(first_expr) = conds_iter.next() {
1954 construct_template(match conds_iter.next() {
1957 Some(e) => construct_expr_and(first_expr, e, conds_iter, l),
1958 None => first_expr,
1959 })
1960 } else {
1961 construct_template(construct_expr_bool(true, l))
1963 }
1964}
1965fn construct_id(s: String) -> ast::Id {
1966 ast::Id::new_unchecked(s)
1967}
1968fn construct_string_from_var(v: ast::Var) -> SmolStr {
1969 match v {
1970 ast::Var::Principal => "principal".into(),
1971 ast::Var::Action => "action".into(),
1972 ast::Var::Resource => "resource".into(),
1973 ast::Var::Context => "context".into(),
1974 }
1975}
1976fn construct_name(path: Vec<ast::Id>, id: ast::Id) -> ast::Name {
1977 ast::Name {
1978 id,
1979 path: Arc::new(path),
1980 }
1981}
1982fn construct_refr(p: ast::Name, n: SmolStr) -> ast::EntityUID {
1983 let eid = ast::Eid::new(n);
1984 ast::EntityUID::from_components(p, eid)
1985}
1986fn construct_expr_ref(r: ast::EntityUID, l: SourceInfo) -> ast::Expr {
1987 ast::ExprBuilder::new().with_source_info(l).val(r)
1988}
1989fn construct_expr_num(n: i64, l: SourceInfo) -> ast::Expr {
1990 ast::ExprBuilder::new().with_source_info(l).val(n)
1991}
1992fn construct_expr_string(s: SmolStr, l: SourceInfo) -> ast::Expr {
1993 ast::ExprBuilder::new().with_source_info(l).val(s)
1994}
1995fn construct_expr_bool(b: bool, l: SourceInfo) -> ast::Expr {
1996 ast::ExprBuilder::new().with_source_info(l).val(b)
1997}
1998fn construct_expr_neg(e: ast::Expr, l: SourceInfo) -> ast::Expr {
1999 ast::ExprBuilder::new().with_source_info(l).neg(e)
2000}
2001fn construct_expr_not(e: ast::Expr, l: SourceInfo) -> ast::Expr {
2002 ast::ExprBuilder::new().with_source_info(l).not(e)
2003}
2004fn construct_expr_var(v: ast::Var, l: SourceInfo) -> ast::Expr {
2005 ast::ExprBuilder::new().with_source_info(l).var(v)
2006}
2007fn construct_expr_if(i: ast::Expr, t: ast::Expr, e: ast::Expr, l: SourceInfo) -> ast::Expr {
2008 ast::ExprBuilder::new().with_source_info(l).ite(i, t, e)
2009}
2010fn construct_expr_or(
2011 f: ast::Expr,
2012 s: ast::Expr,
2013 chained: impl IntoIterator<Item = ast::Expr>,
2014 l: SourceInfo,
2015) -> ast::Expr {
2016 let first = ast::ExprBuilder::new().with_source_info(l.clone()).or(f, s);
2017 chained.into_iter().fold(first, |a, n| {
2018 ast::ExprBuilder::new().with_source_info(l.clone()).or(a, n)
2019 })
2020}
2021fn construct_expr_and(
2022 f: ast::Expr,
2023 s: ast::Expr,
2024 chained: impl IntoIterator<Item = ast::Expr>,
2025 l: SourceInfo,
2026) -> ast::Expr {
2027 let first = ast::ExprBuilder::new()
2028 .with_source_info(l.clone())
2029 .and(f, s);
2030 chained.into_iter().fold(first, |a, n| {
2031 ast::ExprBuilder::new()
2032 .with_source_info(l.clone())
2033 .and(a, n)
2034 })
2035}
2036fn construct_expr_rel(f: ast::Expr, rel: cst::RelOp, s: ast::Expr, l: SourceInfo) -> ast::Expr {
2037 let builder = ast::ExprBuilder::new().with_source_info(l);
2038 match rel {
2039 cst::RelOp::Less => builder.less(f, s),
2040 cst::RelOp::LessEq => builder.lesseq(f, s),
2041 cst::RelOp::GreaterEq => builder.greatereq(f, s),
2042 cst::RelOp::Greater => builder.greater(f, s),
2043 cst::RelOp::NotEq => builder.noteq(f, s),
2044 cst::RelOp::Eq => builder.is_eq(f, s),
2045 cst::RelOp::In => builder.is_in(f, s),
2046 }
2047}
2048fn construct_expr_add(
2050 f: ast::Expr,
2051 chained: impl IntoIterator<Item = (cst::AddOp, ast::Expr)>,
2052 l: SourceInfo,
2053) -> ast::Expr {
2054 let mut expr = f;
2055 for (op, next_expr) in chained {
2056 let builder = ast::ExprBuilder::new().with_source_info(l.clone());
2057 expr = match op {
2058 cst::AddOp::Plus => builder.add(expr, next_expr),
2059 cst::AddOp::Minus => builder.sub(expr, next_expr),
2060 };
2061 }
2062 expr
2063}
2064fn construct_expr_mul(
2066 f: ast::Expr,
2067 chained: impl IntoIterator<Item = i64>,
2068 l: SourceInfo,
2069) -> ast::Expr {
2070 let mut expr = f;
2071 for next_expr in chained {
2072 expr = ast::ExprBuilder::new()
2073 .with_source_info(l.clone())
2074 .mul(expr, next_expr)
2075 }
2076 expr
2077}
2078fn construct_expr_has(t: ast::Expr, s: SmolStr, l: SourceInfo) -> ast::Expr {
2079 ast::ExprBuilder::new().with_source_info(l).has_attr(t, s)
2080}
2081fn construct_expr_attr(e: ast::Expr, s: SmolStr, l: SourceInfo) -> ast::Expr {
2082 ast::ExprBuilder::new().with_source_info(l).get_attr(e, s)
2083}
2084fn construct_expr_like(e: ast::Expr, s: Vec<PatternElem>, l: SourceInfo) -> ast::Expr {
2085 ast::ExprBuilder::new().with_source_info(l).like(e, s)
2086}
2087fn construct_ext_func(name: ast::Name, args: Vec<ast::Expr>, l: SourceInfo) -> ast::Expr {
2088 ast::ExprBuilder::new()
2090 .with_source_info(l)
2091 .call_extension_fn(name, args)
2092}
2093
2094fn construct_method_contains(e0: ast::Expr, e1: ast::Expr, l: SourceInfo) -> ast::Expr {
2095 ast::ExprBuilder::new().with_source_info(l).contains(e0, e1)
2096}
2097fn construct_method_contains_all(e0: ast::Expr, e1: ast::Expr, l: SourceInfo) -> ast::Expr {
2098 ast::ExprBuilder::new()
2099 .with_source_info(l)
2100 .contains_all(e0, e1)
2101}
2102fn construct_method_contains_any(e0: ast::Expr, e1: ast::Expr, l: SourceInfo) -> ast::Expr {
2103 ast::ExprBuilder::new()
2104 .with_source_info(l)
2105 .contains_any(e0, e1)
2106}
2107
2108fn construct_ext_meth(n: String, args: Vec<ast::Expr>, l: SourceInfo) -> ast::Expr {
2110 let id = ast::Id::new_unchecked(n);
2111 let name = ast::Name::unqualified_name(id);
2112 ast::ExprBuilder::new()
2114 .with_source_info(l)
2115 .call_extension_fn(name, args)
2116}
2117fn construct_expr_set(s: Vec<ast::Expr>, l: SourceInfo) -> ast::Expr {
2118 ast::ExprBuilder::new().with_source_info(l).set(s)
2119}
2120fn construct_expr_record(kvs: Vec<(SmolStr, ast::Expr)>, l: SourceInfo) -> ast::Expr {
2121 ast::ExprBuilder::new().with_source_info(l).record(kvs)
2122}
2123
2124#[cfg(test)]
2125mod tests {
2126 use super::*;
2127 use crate::{
2128 ast::Expr,
2129 parser::{err::MultipleParseErrors, *},
2130 };
2131 use std::str::FromStr;
2132
2133 #[test]
2134 fn show_expr1() {
2135 let mut errs = Vec::new();
2136 let expr: ast::Expr = text_to_cst::parse_expr(
2137 r#"
2138 if 7 then 6 > 5 else !5 || "thursday" && ((8) >= "fish")
2139 "#,
2140 )
2141 .expect("failed parser")
2142 .to_expr(&mut errs)
2143 .expect("failed convert");
2144 assert!(errs.is_empty());
2145 println!("{:?}", expr);
2147 }
2148
2149 #[test]
2150 fn show_expr2() {
2151 let mut errs = Vec::new();
2152 let expr: ast::Expr = text_to_cst::parse_expr(
2153 r#"
2154 [2,3,4].foo["hello"]
2155 "#,
2156 )
2157 .expect("failed parser")
2158 .to_expr(&mut errs)
2159 .expect("failed convert");
2160 println!("{:?}", expr);
2162 }
2163
2164 #[test]
2165 fn show_expr3() {
2166 let mut errs = Vec::new();
2168 let expr = text_to_cst::parse_expr(
2169 r#"
2170 "first".some_ident
2171 "#,
2172 )
2173 .expect("failed parser")
2174 .to_expr(&mut errs)
2175 .expect("failed convert");
2176 match expr.expr_kind() {
2177 ast::ExprKind::GetAttr { attr, .. } => {
2178 assert_eq!(attr, "some_ident");
2179 }
2180 _ => panic!("should be a get expr"),
2181 }
2182
2183 let expr = text_to_cst::parse_expr(
2184 r#"
2185 1.some_ident
2186 "#,
2187 )
2188 .expect("failed parser")
2189 .to_expr(&mut errs)
2190 .expect("failed convert");
2191 match expr.expr_kind() {
2192 ast::ExprKind::GetAttr { attr, .. } => {
2193 assert_eq!(attr, "some_ident");
2194 }
2195 _ => panic!("should be a get expr"),
2196 }
2197
2198 let expr = text_to_cst::parse_expr(
2199 r#"
2200 "first"["some string"]
2201 "#,
2202 )
2203 .expect("failed parser")
2204 .to_expr(&mut errs)
2205 .expect("failed convert");
2206 match expr.expr_kind() {
2207 ast::ExprKind::GetAttr { attr, .. } => {
2208 assert_eq!(attr, "some string");
2209 }
2210 _ => panic!("should be a get expr"),
2211 }
2212 }
2213
2214 #[test]
2215 fn show_expr4() {
2216 let mut errs = Vec::new();
2217 let expr: ast::Expr = text_to_cst::parse_expr(
2218 r#"
2219 {"one":1,"two":2} has one
2220 "#,
2221 )
2222 .expect("failed parser")
2223 .to_expr(&mut errs)
2224 .expect("failed convert");
2225
2226 match expr.expr_kind() {
2227 ast::ExprKind::HasAttr { attr, .. } => {
2228 assert_eq!(attr, "one");
2229 }
2230 _ => panic!("should be a has expr"),
2231 }
2232 }
2233
2234 #[test]
2235 fn show_expr5() {
2236 let mut errs = Vec::new();
2237 let expr = text_to_cst::parse_expr(
2238 r#"
2239 {"one":1,"two":2}.one
2240 "#,
2241 )
2242 .expect("failed parser")
2243 .to_expr(&mut errs)
2244 .expect("failed convert");
2245
2246 match expr.expr_kind() {
2247 ast::ExprKind::GetAttr { attr, .. } => {
2248 assert_eq!(attr, "one");
2249 }
2250 _ => panic!("should be a get expr"),
2251 }
2252
2253 let expr: ast::Expr = text_to_cst::parse_expr(
2255 r#"
2256 {"one":1,"two":2}["one"]
2257 "#,
2258 )
2259 .expect("failed parser")
2260 .to_expr(&mut errs)
2261 .expect("failed convert");
2262
2263 match expr.expr_kind() {
2264 ast::ExprKind::GetAttr { attr, .. } => {
2265 assert_eq!(attr, "one");
2266 }
2267 _ => panic!("should be a get expr"),
2268 }
2269
2270 let mut errs = Vec::new();
2272 let expr: ast::Expr = text_to_cst::parse_expr(
2273 r#"
2274 {"this is a valid map key+.-_%()":1,"two":2}["this is a valid map key+.-_%()"]
2275 "#,
2276 )
2277 .expect("failed parser")
2278 .to_expr(&mut errs)
2279 .expect("failed convert");
2280
2281 match expr.expr_kind() {
2282 ast::ExprKind::GetAttr { attr, .. } => {
2283 assert_eq!(attr, "this is a valid map key+.-_%()");
2284 }
2285 _ => panic!("should be a get expr"),
2286 }
2287 }
2288
2289 #[test]
2290 fn show_expr6_idents() {
2291 let mut errs = Vec::new();
2292 let expr = text_to_cst::parse_expr(
2293 r#"
2294 {if true then a else b:"b"} ||
2295 {if false then a else b:"b"}
2296 "#,
2297 )
2298 .expect("failed parser")
2299 .to_expr(&mut errs);
2300
2301 println!("{:?}", errs);
2302 assert!(expr.is_none());
2303 assert!(errs.len() == 6);
2306
2307 errs.clear();
2308 let expr = text_to_cst::parse_expr(
2309 r#"
2310 {principal:"principal"}
2311 "#,
2312 )
2313 .expect("failed parser")
2314 .to_expr(&mut errs)
2315 .expect("failed convert");
2316
2317 println!("{:?}", expr);
2318 match expr.expr_kind() {
2319 ast::ExprKind::Record { .. } => {}
2320 _ => panic!("should be record"),
2321 }
2322
2323 errs.clear();
2324 let expr = text_to_cst::parse_expr(
2325 r#"
2326 {"principal":"principal"}
2327 "#,
2328 )
2329 .expect("failed parser")
2330 .to_expr(&mut errs)
2331 .expect("failed convert");
2332
2333 println!("{:?}", expr);
2334 match expr.expr_kind() {
2335 ast::ExprKind::Record { .. } => {}
2336 _ => panic!("should be record"),
2337 }
2338 }
2339
2340 #[test]
2341 fn reserved_idents1() {
2342 let mut errs = Vec::new();
2343 let parse = text_to_cst::parse_expr(
2344 r#"
2345 The::true::path::to::"enlightenment".false
2346 "#,
2347 )
2348 .expect("failed parse");
2349
2350 let convert = parse.to_expr(&mut errs);
2351 println!("{:?}", errs);
2352 assert!(errs.len() == 2);
2354 assert!(convert.is_none());
2355
2356 let mut errs = Vec::new();
2357 let parse = text_to_cst::parse_expr(
2358 r#"
2359 if {if: true}.if then {"if":false}["if"] else {when:true}.permit
2360 "#,
2361 )
2362 .expect("failed parse");
2363
2364 let convert = parse.to_expr(&mut errs);
2365 println!("{:?}", errs);
2366 assert!(errs.len() == 3);
2368 assert!(convert.is_none());
2369 }
2370
2371 #[test]
2372 fn reserved_idents2() {
2373 let mut errs = Vec::new();
2374 let parse = text_to_cst::parse_expr(
2375 r#"
2376 if {where: true}.like || {has:false}.in then {"like":false}["in"] else {then:true}.else
2377 "#,
2378 )
2379 .expect("failed parse");
2380
2381 let convert = parse.to_expr(&mut errs);
2382 println!("{:?}", errs);
2383 assert!(errs.len() == 7);
2385 assert!(convert.is_none());
2386 }
2387
2388 #[test]
2389 fn show_policy1() {
2390 let mut errs = Vec::new();
2391 let parse = text_to_cst::parse_policy(
2392 r#"
2393 permit(principal:p,action:a,resource:r)when{w}unless{u}advice{"doit"};
2394 "#,
2395 )
2396 .expect("failed parse");
2397 println!("{:#}", parse.as_inner().expect("internal parse error"));
2398 let convert = parse.to_policy(ast::PolicyID::from_string("id"), &mut errs);
2399 println!("{:?}", errs);
2400 assert!(errs.len() == 6);
2402 assert!(convert.is_none());
2403 println!("{:?}", convert);
2405 }
2406
2407 #[test]
2408 fn show_policy2() {
2409 let mut errs = Vec::new();
2410 let parse = text_to_cst::parse_policy(
2411 r#"
2412 permit(principal,action,resource)when{true};
2413 "#,
2414 )
2415 .expect("failed parse");
2416 println!("{}", parse.as_inner().expect("internal parse error"));
2417 println!("{:?}", parse.as_inner().expect("internal parse error"));
2418 let convert = parse.to_policy(ast::PolicyID::from_string("id"), &mut errs);
2419 assert!(convert.is_some());
2420 println!("{:?}", convert);
2422 }
2423
2424 #[test]
2425 fn show_policy3() {
2426 let mut errs = Vec::new();
2427 let parse = text_to_cst::parse_policy(
2428 r#"
2429 permit(principal in User::"jane",action,resource);
2430 "#,
2431 )
2432 .expect("failed parse");
2433 println!("{}", parse.as_inner().expect("internal parse error"));
2434 println!("{:?}", parse.as_inner().expect("internal parse error"));
2435 let convert = parse
2436 .to_policy(ast::PolicyID::from_string("id"), &mut errs)
2437 .expect("failed convert");
2438 assert!(errs.is_empty());
2439 println!("{:?}", convert);
2441 }
2442
2443 #[test]
2444 fn show_policy4() {
2445 let mut errs = Vec::new();
2446 let parse = text_to_cst::parse_policy(
2447 r#"
2448 forbid(principal in User::"jane",action,resource)unless{
2449 context.group != "friends"
2450 };
2451 "#,
2452 )
2453 .expect("failed parse");
2454 let convert = parse
2455 .to_policy(ast::PolicyID::from_string("id"), &mut errs)
2456 .expect("failed convert");
2457 assert!(errs.is_empty());
2458 println!("\n{:?}", convert);
2460 }
2461
2462 #[test]
2463 fn policy_annotations() {
2464 let mut errs = Vec::new();
2466 let policy = text_to_cst::parse_policy(
2467 r#"
2468 @anno("good annotation")permit(principal,action,resource);
2469 "#,
2470 )
2471 .expect("should parse")
2472 .to_policy(ast::PolicyID::from_string("id"), &mut errs)
2473 .expect("should be valid");
2474 assert_eq!(
2475 policy.annotation(&ast::Id::new_unchecked("anno")),
2476 Some(&"good annotation".into())
2477 );
2478
2479 let mut errs = Vec::new();
2481 let policy = text_to_cst::parse_policy(
2482 r#"
2483 @anno("good annotation")
2484 @anno2("good annotation")
2485 @anno("oops, duplicate")
2486 permit(principal,action,resource);
2487 "#,
2488 )
2489 .expect("should parse")
2490 .to_policy(ast::PolicyID::from_string("id"), &mut errs);
2491 assert!(policy.is_none());
2492 assert!(errs.len() == 1);
2494
2495 let mut errs = Vec::new();
2497 let policyset = text_to_cst::parse_policies(
2498 r#"
2499 @anno1("first")
2500 permit(principal,action,resource);
2501
2502 @anno2("second")
2503 permit(principal,action,resource);
2504
2505 @anno3a("third-a")
2506 @anno3b("third-b")
2507 permit(principal,action,resource);
2508 "#,
2509 )
2510 .expect("should parse")
2511 .to_policyset(&mut errs)
2512 .expect("should be valid");
2513 assert_eq!(
2514 policyset
2515 .get(&ast::PolicyID::from_string("policy0"))
2516 .expect("should be a policy")
2517 .annotation(&ast::Id::new_unchecked("anno0")),
2518 None
2519 );
2520 assert_eq!(
2521 policyset
2522 .get(&ast::PolicyID::from_string("policy0"))
2523 .expect("should be a policy")
2524 .annotation(&ast::Id::new_unchecked("anno1")),
2525 Some(&"first".into())
2526 );
2527 assert_eq!(
2528 policyset
2529 .get(&ast::PolicyID::from_string("policy1"))
2530 .expect("should be a policy")
2531 .annotation(&ast::Id::new_unchecked("anno2")),
2532 Some(&"second".into())
2533 );
2534 assert_eq!(
2535 policyset
2536 .get(&ast::PolicyID::from_string("policy2"))
2537 .expect("should be a policy")
2538 .annotation(&ast::Id::new_unchecked("anno3a")),
2539 Some(&"third-a".into())
2540 );
2541 assert_eq!(
2542 policyset
2543 .get(&ast::PolicyID::from_string("policy2"))
2544 .expect("should be a policy")
2545 .annotation(&ast::Id::new_unchecked("anno3b")),
2546 Some(&"third-b".into())
2547 );
2548 assert_eq!(
2549 policyset
2550 .get(&ast::PolicyID::from_string("policy2"))
2551 .expect("should be a policy")
2552 .annotation(&ast::Id::new_unchecked("anno3c")),
2553 None
2554 );
2555 assert_eq!(
2556 policyset
2557 .get(&ast::PolicyID::from_string("policy2"))
2558 .expect("should be a policy")
2559 .annotations()
2560 .count(),
2561 2
2562 );
2563 }
2564
2565 #[test]
2566 fn fail_head1() {
2567 let mut errs = Vec::new();
2568 let parse = text_to_cst::parse_policy(
2569 r#"
2570 permit(
2571 principal in [User::"jane",Group::"friends"],
2572 action,
2573 resource
2574 );
2575 "#,
2576 )
2577 .expect("failed parse");
2578 println!("\n{:#}", parse.as_inner().expect("internal parse error"));
2579 let convert = parse.to_policy(ast::PolicyID::from_string("id"), &mut errs);
2580 println!("{:?}", errs);
2581 assert!(errs.len() == 1);
2582 assert!(convert.is_none());
2583 }
2584
2585 #[test]
2586 fn fail_head2() {
2587 let mut errs = Vec::new();
2588 let parse = text_to_cst::parse_policy(
2589 r#"
2590 permit(
2591 principal in User::"jane",
2592 action == if true then Photo::"view" else Photo::"edit",
2593 resource
2594 );
2595 "#,
2596 )
2597 .expect("failed parse");
2598 println!("{:#}", parse.as_inner().expect("internal parse error"));
2599 let convert = parse.to_policy(ast::PolicyID::from_string("id"), &mut errs);
2600 println!("{:?}", errs);
2601 assert!(errs.len() == 1);
2602 assert!(convert.is_none());
2603 }
2604
2605 #[test]
2606 fn fail_head3() {
2607 let mut errs = Vec::new();
2608 let parse = text_to_cst::parse_policy(
2609 r#"
2610 permit(principal,action,resource,context);
2611 "#,
2612 )
2613 .expect("failed parse");
2614 let convert = parse.to_policy(ast::PolicyID::from_string("id"), &mut errs);
2615 assert!(errs.len() == 1);
2616 assert!(convert.is_none());
2617 }
2618
2619 #[test]
2620 fn method_call2() {
2621 let mut errs = Vec::new();
2622 let e = text_to_cst::parse_expr(
2623 r#"
2624 principal.contains(resource)
2625 "#,
2626 )
2627 .expect("parse error")
2629 .to_expr(&mut errs);
2630 println!("{:?}", errs);
2632 assert!(e.is_some());
2633 assert!(errs.is_empty());
2634
2635 let e = text_to_cst::parse_expr(
2636 r#"
2637 contains(principal,resource)
2638 "#,
2639 )
2640 .expect("parse error")
2642 .to_expr(&mut errs);
2643 println!("{:?}", errs);
2645 assert!(e.is_none());
2646 assert!(errs.len() == 1);
2647 }
2648
2649 #[test]
2650 fn construct_record1() {
2651 let mut errs = Vec::new();
2652 let e = text_to_cst::parse_expr(
2653 r#"
2654 {one:"one"}
2655 "#,
2656 )
2657 .expect("parse error")
2659 .to_expr(&mut errs)
2660 .expect("convert fail");
2661 if let ast::ExprKind::Record { .. } = e.expr_kind() {
2663 } else {
2665 panic!("not a record")
2666 }
2667 println!("{e}");
2668
2669 let e = text_to_cst::parse_expr(
2670 r#"
2671 {"one":"one"}
2672 "#,
2673 )
2674 .expect("parse error")
2676 .to_expr(&mut errs)
2677 .expect("convert fail");
2678 if let ast::ExprKind::Record { .. } = e.expr_kind() {
2680 } else {
2682 panic!("not a record")
2683 }
2684 println!("{e}");
2685
2686 let e = text_to_cst::parse_expr(
2687 r#"
2688 {"one":"one",two:"two"}
2689 "#,
2690 )
2691 .expect("parse error")
2693 .to_expr(&mut errs)
2694 .expect("convert fail");
2695 if let ast::ExprKind::Record { .. } = e.expr_kind() {
2697 } else {
2699 panic!("not a record")
2700 }
2701 println!("{e}");
2702
2703 let e = text_to_cst::parse_expr(
2704 r#"
2705 {one:"one","two":"two"}
2706 "#,
2707 )
2708 .expect("parse error")
2710 .to_expr(&mut errs)
2711 .expect("convert fail");
2712 if let ast::ExprKind::Record { .. } = e.expr_kind() {
2714 } else {
2716 panic!("not a record")
2717 }
2718 println!("{e}");
2719
2720 let e = text_to_cst::parse_expr(
2721 r#"
2722 {one:"b\"","b\"":2}
2723 "#,
2724 )
2725 .expect("parse error")
2727 .to_expr(&mut errs)
2728 .expect("convert fail");
2729 if let ast::ExprKind::Record { .. } = e.expr_kind() {
2731 } else {
2733 panic!("not a record")
2734 }
2735 println!("{e}");
2736 }
2737
2738 #[test]
2739 fn construct_invalid_get() {
2740 let mut errs = Vec::new();
2741 let e = text_to_cst::parse_expr(
2742 r#"
2743 {"one":1, "two":"two"}[0]
2744 "#,
2745 )
2746 .expect("failed parser")
2747 .to_expr(&mut errs);
2748 println!("{:?}", errs);
2750 assert!(e.is_none());
2751 assert!(errs.len() == 1);
2752
2753 let e = text_to_cst::parse_expr(
2754 r#"
2755 {"one":1, "two":"two"}[-1]
2756 "#,
2757 )
2758 .expect("failed parser")
2759 .to_expr(&mut errs);
2760 println!("{:?}", errs);
2762 assert!(e.is_none());
2763
2764 let e = text_to_cst::parse_expr(
2765 r#"
2766 {"one":1, "two":"two"}[true]
2767 "#,
2768 )
2769 .expect("failed parser")
2770 .to_expr(&mut errs);
2771 println!("{:?}", errs);
2773 assert!(e.is_none());
2774
2775 let e = text_to_cst::parse_expr(
2776 r#"
2777 {"one":1, "two":"two"}[one]
2778 "#,
2779 )
2780 .expect("failed parser")
2781 .to_expr(&mut errs);
2782 println!("{:?}", errs);
2784 assert!(e.is_none());
2785 }
2786
2787 #[test]
2788 fn construct_has() {
2789 let mut errs = Vec::new();
2790 let expr: ast::Expr = text_to_cst::parse_expr(
2791 r#"
2792 {"one":1,"two":2} has "arbitrary+ _string"
2793 "#,
2794 )
2795 .expect("failed parser")
2796 .to_expr(&mut errs)
2797 .expect("failed convert");
2798
2799 match expr.expr_kind() {
2800 ast::ExprKind::HasAttr { attr, .. } => {
2801 assert_eq!(attr, "arbitrary+ _string");
2802 }
2803 _ => panic!("should be a has expr"),
2804 }
2805
2806 let mut errs = Vec::new();
2807 let e = text_to_cst::parse_expr(
2808 r#"
2809 {"one":1,"two":2} has 1
2810 "#,
2811 )
2812 .expect("failed parser")
2813 .to_expr(&mut errs);
2814 println!("{:?}", errs);
2816 assert!(e.is_none());
2817 assert!(errs.len() == 1);
2818 }
2819
2820 #[test]
2821 fn construct_like() {
2822 let mut errs = Vec::new();
2823 let expr: ast::Expr = text_to_cst::parse_expr(
2824 r#"
2825 "354 hams" like "*5*"
2826 "#,
2827 )
2828 .expect("failed parser")
2829 .to_expr(&mut errs)
2830 .expect("failed convert");
2831 match expr.expr_kind() {
2832 ast::ExprKind::Like { pattern, .. } => {
2833 assert_eq!(pattern.to_string(), "*5*");
2834 }
2835 _ => panic!("should be a like expr"),
2836 }
2837
2838 let e = text_to_cst::parse_expr(
2839 r#"
2840 "354 hams" like 354
2841 "#,
2842 )
2843 .expect("failed parser")
2844 .to_expr(&mut errs);
2845 println!("{:?}", errs);
2847 assert!(e.is_none());
2848 assert!(errs.len() == 1);
2849
2850 let mut errs = Vec::new();
2851 let expr: ast::Expr = text_to_cst::parse_expr(
2852 r#"
2853 "string\\with\\backslashes" like "string\\with\\backslashes"
2854 "#,
2855 )
2856 .expect("failed parser")
2857 .to_expr(&mut errs)
2858 .expect("failed convert");
2859 match expr.expr_kind() {
2860 ast::ExprKind::Like { pattern, .. } => {
2861 assert_eq!(pattern.to_string(), r#"string\\with\\backslashes"#);
2862 }
2863 _ => panic!("should be a like expr"),
2864 }
2865
2866 let expr: ast::Expr = text_to_cst::parse_expr(
2867 r#"
2868 "string\\with\\backslashes" like "string\*with\*backslashes"
2869 "#,
2870 )
2871 .expect("failed parser")
2872 .to_expr(&mut errs)
2873 .expect("failed convert");
2874 match expr.expr_kind() {
2875 ast::ExprKind::Like { pattern, .. } => {
2876 assert_eq!(pattern.to_string(), r#"string\*with\*backslashes"#);
2877 }
2878 _ => panic!("should be a like expr"),
2879 }
2880
2881 let e = text_to_cst::parse_expr(
2882 r#"
2883 "string\*with\*escaped\*stars" like "string\*with\*escaped\*stars"
2884 "#,
2885 )
2886 .expect("failed parser")
2887 .to_expr(&mut errs);
2888 println!("{:?}", errs);
2890 assert!(e.is_none());
2891 assert!(errs.len() == 3); let expr: ast::Expr = text_to_cst::parse_expr(
2894 r#"
2895 "string*with*stars" like "string\*with\*stars"
2896 "#,
2897 )
2898 .expect("failed parser")
2899 .to_expr(&mut errs)
2900 .expect("failed convert");
2901 match expr.expr_kind() {
2902 ast::ExprKind::Like { pattern, .. } => {
2903 assert_eq!(pattern.to_string(), "string\\*with\\*stars");
2904 }
2905 _ => panic!("should be a like expr"),
2906 }
2907
2908 let mut errs = Vec::new();
2909 let expr: ast::Expr = text_to_cst::parse_expr(
2910 r#"
2911 "string\\*with\\*backslashes\\*and\\*stars" like "string\\\*with\\\*backslashes\\\*and\\\*stars"
2912 "#,
2913 )
2914 .expect("failed parser")
2915 .to_expr(&mut errs)
2916 .expect("failed convert");
2917 match expr.expr_kind() {
2918 ast::ExprKind::Like { pattern, .. } => {
2919 assert_eq!(
2920 pattern.to_string(),
2921 r#"string\\\*with\\\*backslashes\\\*and\\\*stars"#
2922 );
2923 }
2924 _ => panic!("should be a like expr"),
2925 }
2926 let test_pattern = &vec![
2928 PatternElem::Char('h'),
2929 PatternElem::Char('e'),
2930 PatternElem::Char('l'),
2931 PatternElem::Char('l'),
2932 PatternElem::Char('o'),
2933 PatternElem::Char('\\'),
2934 PatternElem::Char('0'),
2935 PatternElem::Char('*'),
2936 PatternElem::Char('\\'),
2937 PatternElem::Char('*'),
2938 ];
2939 let e1 = ast::Expr::like(ast::Expr::val("hello"), test_pattern.clone());
2940 let s1 = format!("{e1}");
2941 assert_eq!(s1, r#""hello" like "hello\\0\*\\\*""#);
2943 let e2 = text_to_cst::parse_expr(&s1)
2944 .expect("failed parser")
2945 .to_expr(&mut errs)
2946 .expect("failed convert");
2947 match e2.expr_kind() {
2948 ast::ExprKind::Like { pattern, .. } => {
2949 assert_eq!(pattern.get_elems(), test_pattern);
2950 }
2951 _ => panic!("should be a like expr"),
2952 }
2953 let s2 = format!("{e2}");
2954 assert_eq!(s1, s2);
2955 }
2956
2957 #[test]
2958 fn issue_wf_5046() {
2959 let policy = parse_policy(
2960 Some("WF-5046".into()),
2961 r#"permit(
2962 principal,
2963 action in [Action::"action"],
2964 resource in G::""
2965 ) when {
2966 true && ("" like "/gisterNatives\\*D")
2967 };"#,
2968 );
2969 assert!(policy.is_ok());
2970 }
2971
2972 #[test]
2973 fn entity_access() {
2974 let mut errs = Vec::new();
2978 let expr: ast::Expr = text_to_cst::parse_expr(
2979 r#"
2980 User::"jane" has age
2981 "#,
2982 )
2983 .expect("failed parser")
2984 .to_expr(&mut errs)
2985 .expect("failed convert");
2986 match expr.expr_kind() {
2987 ast::ExprKind::HasAttr { attr, .. } => {
2988 assert_eq!(attr, "age");
2989 }
2990 _ => panic!("should be a has expr"),
2991 }
2992
2993 let mut errs = Vec::new();
2995 let expr: ast::Expr = text_to_cst::parse_expr(
2996 r#"
2997 User::"jane" has "arbitrary+ _string"
2998 "#,
2999 )
3000 .expect("failed parser")
3001 .to_expr(&mut errs)
3002 .expect("failed convert");
3003 match expr.expr_kind() {
3004 ast::ExprKind::HasAttr { attr, .. } => {
3005 assert_eq!(attr, "arbitrary+ _string");
3006 }
3007 _ => panic!("should be a has expr"),
3008 }
3009
3010 let mut errs = Vec::new();
3012 let e = text_to_cst::parse_expr(
3013 r#"
3014 User::"jane" has 1
3015 "#,
3016 )
3017 .expect("failed parser")
3018 .to_expr(&mut errs);
3019 assert!(e.is_none());
3020 assert!(errs.len() == 1);
3021
3022 let mut errs = Vec::new();
3024 let expr: ast::Expr = text_to_cst::parse_expr(
3025 r#"
3026 User::"jane".age
3027 "#,
3028 )
3029 .expect("failed parser")
3030 .to_expr(&mut errs)
3031 .expect("failed convert");
3032 match expr.expr_kind() {
3033 ast::ExprKind::GetAttr { attr, .. } => {
3034 assert_eq!(attr, "age");
3035 }
3036 _ => panic!("should be a get expr"),
3037 }
3038
3039 let mut errs = Vec::new();
3041 let expr: ast::Expr = text_to_cst::parse_expr(
3042 r#"
3043 User::"jane"["arbitrary+ _string"]
3044 "#,
3045 )
3046 .expect("failed parser")
3047 .to_expr(&mut errs)
3048 .expect("failed convert");
3049 match expr.expr_kind() {
3050 ast::ExprKind::GetAttr { attr, .. } => {
3051 assert_eq!(attr, "arbitrary+ _string");
3052 }
3053 _ => panic!("should be a get expr"),
3054 }
3055
3056 let mut errs = Vec::new();
3058 let e = text_to_cst::parse_expr(
3059 r#"
3060 User::"jane"[age]
3061 "#,
3062 )
3063 .expect("failed parser")
3064 .to_expr(&mut errs);
3065 assert!(e.is_none());
3066 assert!(errs.len() == 1);
3067 }
3068
3069 #[test]
3070 fn relational_ops1() {
3071 let mut errs = Vec::new();
3072 let e = text_to_cst::parse_expr(
3073 r#"
3074 3 >= 2 >= 1
3075 "#,
3076 )
3077 .expect("parse error")
3079 .to_expr(&mut errs);
3080 assert!(e.is_none());
3082
3083 let e = text_to_cst::parse_expr(
3084 r#"
3085 3 >= ("dad" in "dad")
3086 "#,
3087 )
3088 .expect("parse error")
3090 .to_expr(&mut errs);
3091 assert!(e.is_some());
3093
3094 let e = text_to_cst::parse_expr(
3095 r#"
3096 (3 >= 2) == true
3097 "#,
3098 )
3099 .expect("parse error")
3101 .to_expr(&mut errs);
3102 assert!(e.is_some());
3104
3105 let e = text_to_cst::parse_expr(
3106 r#"
3107 if 4 < 3 then 4 != 3 else 4 == 3 < 4
3108 "#,
3109 )
3110 .expect("parse error")
3112 .to_expr(&mut errs);
3113 assert!(e.is_none());
3115 }
3116
3117 #[test]
3118 fn arithmetic() {
3119 let mut errs = Vec::new();
3120 let e = text_to_cst::parse_expr(r#" 2 + 4 "#)
3121 .expect("parse error")
3123 .to_expr(&mut errs);
3124 assert!(e.is_some());
3126
3127 let e = text_to_cst::parse_expr(r#" 2 + -5 "#)
3128 .expect("parse error")
3130 .to_expr(&mut errs);
3131 assert!(e.is_some());
3133
3134 let e = text_to_cst::parse_expr(r#" 2 - 5 "#)
3135 .expect("parse error")
3137 .to_expr(&mut errs);
3138 assert!(e.is_some());
3140
3141 let e = text_to_cst::parse_expr(r#" 2 * 5 "#)
3142 .expect("parse error")
3144 .to_expr(&mut errs);
3145 assert!(e.is_some());
3147
3148 let e = text_to_cst::parse_expr(r#" 2 * -5 "#)
3149 .expect("parse error")
3151 .to_expr(&mut errs);
3152 assert!(e.is_some());
3154
3155 let e = text_to_cst::parse_expr(r#" context.size * 4 "#)
3156 .expect("parse error")
3158 .to_expr(&mut errs);
3159 assert!(e.is_some());
3161
3162 let e = text_to_cst::parse_expr(r#" 4 * context.size "#)
3163 .expect("parse error")
3165 .to_expr(&mut errs);
3166 assert!(e.is_some());
3168
3169 let e = text_to_cst::parse_expr(r#" context.size * context.scale "#)
3170 .expect("parse error")
3172 .to_expr(&mut errs);
3173 assert!(e.is_none());
3175
3176 let e = text_to_cst::parse_expr(r#" 5 + 10 + 90 "#)
3177 .expect("parse error")
3179 .to_expr(&mut errs);
3180 assert!(e.is_some());
3182
3183 let e = text_to_cst::parse_expr(r#" 5 + 10 - 90 * -2 "#)
3184 .expect("parse error")
3186 .to_expr(&mut errs);
3187 assert!(e.is_some());
3189
3190 let e = text_to_cst::parse_expr(r#" 5 + 10 * 90 - 2 "#)
3191 .expect("parse error")
3193 .to_expr(&mut errs);
3194 assert!(e.is_some());
3196
3197 let e = text_to_cst::parse_expr(r#" 5 - 10 - 90 - 2 "#)
3198 .expect("parse error")
3200 .to_expr(&mut errs);
3201 assert!(e.is_some());
3203
3204 let e = text_to_cst::parse_expr(r#" 5 * context.size * 10 "#)
3205 .expect("parse error")
3207 .to_expr(&mut errs);
3208 assert!(e.is_some());
3210
3211 let e = text_to_cst::parse_expr(r#" context.size * 3 * context.scale "#)
3212 .expect("parse error")
3214 .to_expr(&mut errs);
3215 assert!(e.is_none());
3217 }
3218
3219 const CORRECT_TEMPLATES: [&str; 7] = [
3220 r#"permit(principal == ?principal, action == Action::"action", resource == ?resource);"#,
3221 r#"permit(principal in ?principal, action == Action::"action", resource in ?resource);"#,
3222 r#"permit(principal in ?principal, action == Action::"action", resource in ?resource);"#,
3223 r#"permit(principal in p::"principal", action == Action::"action", resource in ?resource);"#,
3224 r#"permit(principal == p::"principal", action == Action::"action", resource in ?resource);"#,
3225 r#"permit(principal in ?principal, action == Action::"action", resource in r::"resource");"#,
3226 r#"permit(principal in ?principal, action == Action::"action", resource == r::"resource");"#,
3227 ];
3228
3229 #[test]
3230 fn template_tests() {
3231 for src in CORRECT_TEMPLATES {
3232 let mut errs = Vec::new();
3233 let e = text_to_cst::parse_policy(src)
3234 .expect("parse_error")
3235 .to_policy_template(ast::PolicyID::from_string("i0"), &mut errs);
3236 if e.is_none() {
3237 panic!("Failed to create a policy template: {:?}", errs);
3238 }
3239 }
3240 }
3241
3242 const WRONG_VAR_TEMPLATES: [&str; 16] = [
3243 r#"permit(principal == ?resource, action, resource);"#,
3244 r#"permit(principal in ?resource, action, resource);"#,
3245 r#"permit(principal, action, resource == ?principal);"#,
3246 r#"permit(principal, action, resource in ?principal);"#,
3247 r#"permit(principal, action == ?principal, resource);"#,
3248 r#"permit(principal, action in ?principal, resource);"#,
3249 r#"permit(principal, action == ?resource, resource);"#,
3250 r#"permit(principal, action in ?resource, resource);"#,
3251 r#"forbid(principal == ?resource, action, resource);"#,
3252 r#"forbid(principal in ?resource, action, resource);"#,
3253 r#"forbid(principal, action, resource == ?principal);"#,
3254 r#"forbid(principal, action, resource in ?principal);"#,
3255 r#"forbid(principal, action == ?principal, resource);"#,
3256 r#"forbid(principal, action in ?principal, resource);"#,
3257 r#"forbid(principal, action == ?resource, resource);"#,
3258 r#"forbid(principal, action in ?resource, resource);"#,
3259 ];
3260
3261 #[test]
3262 fn test_wrong_template_var() {
3263 for src in WRONG_VAR_TEMPLATES {
3264 let mut errs = vec![];
3265 let e = text_to_cst::parse_policy(src)
3266 .expect("Parse Error")
3267 .to_policy_template(ast::PolicyID::from_string("id0"), &mut errs);
3268 assert!(e.is_none());
3269 }
3270 }
3271
3272 #[test]
3273 fn var_type() {
3274 let mut errs = Vec::new();
3275 let e = text_to_cst::parse_policy(
3276 r#"
3277 permit(principal,action,resource);
3278 "#,
3279 )
3280 .expect("parse error")
3282 .to_policy(ast::PolicyID::from_string("0"), &mut errs);
3283 assert!(e.is_some());
3285 let e = text_to_cst::parse_policy(
3286 r#"
3287 permit(principal:User,action,resource);
3288 "#,
3289 )
3290 .expect("parse error")
3292 .to_policy(ast::PolicyID::from_string("1"), &mut errs);
3293 assert!(e.is_none());
3295 }
3296 #[test]
3297 fn string_escapes() {
3298 let test_valid = |s: &str| {
3305 let r = parse_literal(&format!("\"{}\"", s.escape_default()));
3306 assert!(r.is_ok());
3307 assert_eq!(r.unwrap(), ast::Literal::String(s.into()));
3308 };
3309 test_valid("\t");
3310 test_valid("\0");
3311 test_valid("👍");
3312 test_valid("🐈");
3313 test_valid("\u{1F408}");
3314 test_valid("abc\tde\\fg");
3315 test_valid("aaa\u{1F408}bcd👍👍👍");
3316 let test_invalid = |s: &str, en: usize| {
3318 let r = parse_literal(&format!("\"{}\"", s));
3319 assert!(r.is_err());
3320 assert!(r.unwrap_err().len() == en);
3321 };
3322 test_invalid("\\a", 1);
3324 test_invalid("\\b", 1);
3326 test_invalid("\\\\aa\\p", 1);
3328 test_invalid(r#"\aaa\u{}"#, 2);
3330 }
3331
3332 fn expect_action_error(test: &str, euid_strs: Vec<&str>) {
3333 let euids = euid_strs
3334 .into_iter()
3335 .map(|euid_str| {
3336 EntityUID::from_str(euid_str).expect("Test was provided with invalid euid")
3337 })
3338 .collect::<Vec<_>>();
3339 let p = parse_policyset(test);
3340 match p {
3341 Ok(pset) => panic!("Policy: {pset}, shouln't have parsed!"),
3342 Err(es) => {
3343 if es.len() != euids.len() {
3344 panic!(
3345 "Parse should have produced exactly {} parse errors, produced: {:?}",
3346 euids.len(),
3347 es
3348 );
3349 } else {
3350 for euid in euids {
3351 let err = action_type_error_msg(&euid);
3352 assert!(es.contains(&err));
3353 }
3354 }
3355 }
3356 }
3357 }
3358
3359 #[test]
3360 fn action_checker() {
3361 let euid = EntityUID::from_str("Action::\"view\"").unwrap();
3362 assert!(euid_has_action_type(&euid));
3363 let euid = EntityUID::from_str("Foo::Action::\"view\"").unwrap();
3364 assert!(euid_has_action_type(&euid));
3365 let euid = EntityUID::from_str("Foo::\"view\"").unwrap();
3366 assert!(!euid_has_action_type(&euid));
3367 let euid = EntityUID::from_str("Action::Foo::\"view\"").unwrap();
3368 assert!(!euid_has_action_type(&euid));
3369 }
3370
3371 #[test]
3372 fn action_must_be_action() {
3373 parse_policyset(r#"permit(principal, action == Action::"view", resource);"#)
3374 .expect("Valid policy failed to parse");
3375 parse_policyset(r#"permit(principal, action == Foo::Action::"view", resource);"#)
3376 .expect("Valid policy failed to parse");
3377 parse_policyset(r#"permit(principal, action in Action::"view", resource);"#)
3378 .expect("Valid policy failed to parse");
3379 parse_policyset(r#"permit(principal, action in Foo::Action::"view", resource);"#)
3380 .expect("Valid policy failed to parse");
3381 parse_policyset(r#"permit(principal, action in [Foo::Action::"view"], resource);"#)
3382 .expect("Valid policy failed to parse");
3383 parse_policyset(
3384 r#"permit(principal, action in [Foo::Action::"view", Action::"view"], resource);"#,
3385 )
3386 .expect("Valid policy failed to parse");
3387 expect_action_error(
3388 r#"permit(principal, action == Foo::"view", resource);"#,
3389 vec!["Foo::\"view\""],
3390 );
3391 expect_action_error(
3392 r#"permit(principal, action == Action::Foo::"view", resource);"#,
3393 vec!["Action::Foo::\"view\""],
3394 );
3395 expect_action_error(
3396 r#"permit(principal, action == Bar::Action::Foo::"view", resource);"#,
3397 vec!["Bar::Action::Foo::\"view\""],
3398 );
3399 expect_action_error(
3400 r#"permit(principal, action in Bar::Action::Foo::"view", resource);"#,
3401 vec!["Bar::Action::Foo::\"view\""],
3402 );
3403 expect_action_error(
3404 r#"permit(principal, action in [Bar::Action::Foo::"view"], resource);"#,
3405 vec!["Bar::Action::Foo::\"view\""],
3406 );
3407 expect_action_error(
3408 r#"permit(principal, action in [Bar::Action::Foo::"view", Action::"check"], resource);"#,
3409 vec!["Bar::Action::Foo::\"view\""],
3410 );
3411 expect_action_error(
3412 r#"permit(principal, action in [Bar::Action::Foo::"view", Foo::"delete", Action::"check"], resource);"#,
3413 vec!["Bar::Action::Foo::\"view\"", "Foo::\"delete\""],
3414 );
3415 }
3416
3417 #[test]
3418 fn method_style() {
3419 let policy = parse_policyset(
3420 r#"permit(principal, action, resource)
3421 when { contains(true) < 1 };"#,
3422 );
3423 assert!(
3424 policy.is_err()
3425 && matches!(
3426 policy.as_ref().unwrap_err().as_slice(),
3427 [err::ParseError::ToAST(_)]
3428 ),
3429 "builtin functions must be called in method-style"
3430 );
3431 }
3432
3433 #[test]
3434 fn test_mul() {
3435 for (es, expr) in [
3436 ("--2*3", Expr::mul(Expr::neg(Expr::val(-2)), 3)),
3437 (
3438 "1 * 2 * false",
3439 Expr::mul(Expr::mul(Expr::val(false), 1), 2),
3440 ),
3441 (
3442 "0 * 1 * principal",
3443 Expr::mul(Expr::mul(Expr::var(ast::Var::Principal), 0), 1),
3444 ),
3445 (
3446 "0 * (-1) * principal",
3447 Expr::mul(Expr::mul(Expr::var(ast::Var::Principal), 0), -1),
3448 ),
3449 ] {
3450 let mut errs = Vec::new();
3451 let e = text_to_cst::parse_expr(es)
3452 .expect("should construct a CST")
3453 .to_expr(&mut errs)
3454 .expect("should convert to AST");
3455 assert!(
3456 e.eq_shape(&expr),
3457 "{:?} and {:?} should have the same shape.",
3458 e,
3459 expr
3460 );
3461 }
3462
3463 for es in [
3464 r#"false * "bob""#,
3465 "principal * (1 + 2)",
3466 "principal * -(-1)",
3467 "principal * --1",
3470 ] {
3471 let mut errs = Vec::new();
3472 let e = text_to_cst::parse_expr(es)
3473 .expect("should construct a CST")
3474 .to_expr(&mut errs);
3475 assert!(e.is_none());
3476 }
3477 }
3478
3479 #[test]
3480 fn test_not() {
3481 for (es, expr) in [
3482 (
3483 "!1 + 2 == 3",
3484 Expr::is_eq(
3485 Expr::add(Expr::not(Expr::val(1)), Expr::val(2)),
3486 Expr::val(3),
3487 ),
3488 ),
3489 (
3490 "!!1 + 2 == 3",
3491 Expr::is_eq(
3492 Expr::add(Expr::not(Expr::not(Expr::val(1))), Expr::val(2)),
3493 Expr::val(3),
3494 ),
3495 ),
3496 (
3497 "!!!1 + 2 == 3",
3498 Expr::is_eq(
3499 Expr::add(Expr::not(Expr::val(1)), Expr::val(2)),
3500 Expr::val(3),
3501 ),
3502 ),
3503 (
3504 "!!!!1 + 2 == 3",
3505 Expr::is_eq(
3506 Expr::add(Expr::not(Expr::not(Expr::val(1))), Expr::val(2)),
3507 Expr::val(3),
3508 ),
3509 ),
3510 (
3511 "!!(-1) + 2 == 3",
3512 Expr::is_eq(
3513 Expr::add(Expr::not(Expr::not(Expr::val(-1))), Expr::val(2)),
3514 Expr::val(3),
3515 ),
3516 ),
3517 ] {
3518 let mut errs = Vec::new();
3519 let e = text_to_cst::parse_expr(es)
3520 .expect("should construct a CST")
3521 .to_expr(&mut errs)
3522 .expect("should convert to AST");
3523 assert!(
3524 e.eq_shape(&expr),
3525 "{:?} and {:?} should have the same shape.",
3526 e,
3527 expr
3528 );
3529 }
3530 }
3531
3532 #[test]
3533 fn test_neg() {
3534 for (es, expr) in [
3535 ("-(1 + 2)", Expr::neg(Expr::add(Expr::val(1), Expr::val(2)))),
3536 ("1-(2)", Expr::sub(Expr::val(1), Expr::val(2))),
3537 ("1-2", Expr::sub(Expr::val(1), Expr::val(2))),
3538 ("(-1)", Expr::val(-1)),
3539 ("-(-1)", Expr::neg(Expr::val(-1))),
3540 ("--1", Expr::neg(Expr::val(-1))),
3541 ("--(--1)", Expr::neg(Expr::neg(Expr::neg(Expr::val(-1))))),
3542 ("2--1", Expr::sub(Expr::val(2), Expr::val(-1))),
3543 ("-9223372036854775808", Expr::val(-(9223372036854775808))),
3544 (
3547 "--9223372036854775808",
3548 Expr::neg(Expr::val(-9223372036854775808)),
3549 ),
3550 (
3551 "-(9223372036854775807)",
3552 Expr::neg(Expr::val(9223372036854775807)),
3553 ),
3554 ] {
3555 let mut errs = Vec::new();
3556 let e = text_to_cst::parse_expr(es)
3557 .expect("should construct a CST")
3558 .to_expr(&mut errs)
3559 .expect("should convert to AST");
3560 assert!(
3561 e.eq_shape(&expr),
3562 "{:?} and {:?} should have the same shape.",
3563 e,
3564 expr
3565 );
3566 }
3567
3568 for (es, em) in [
3569 ("-9223372036854775809", "Integer constant is too large"),
3570 (
3574 "-(9223372036854775808)",
3575 "Literal 9223372036854775808 is too large",
3576 ),
3577 ] {
3578 let mut errs = Vec::new();
3579 let e = text_to_cst::parse_expr(es)
3580 .expect("should construct a CST")
3581 .to_expr(&mut errs);
3582 assert!(e.is_none());
3583 assert!(MultipleParseErrors(&errs).to_string().contains(em));
3584 }
3585 }
3586}