1use std::fmt::{self, Write};
18
19use super::cst::*;
20use super::node::Node;
21
22struct View<'a, T>(&'a Node<Option<T>>);
24impl<T: fmt::Display> fmt::Display for View<'_, T> {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 if let Some(n) = &self.0.as_inner() {
27 if f.alternate() {
28 write!(f, "{:#}", n)
29 } else {
30 write!(f, "{}", n)
31 }
32 } else {
33 write!(f, "[error]")
34 }
35 }
36}
37
38impl fmt::Display for Policies {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 let mut ps = self.0.iter();
41 if f.alternate() {
42 if let Some(p) = ps.next() {
43 write!(f, "{:#}", View(p))?;
44 }
45 for p in ps {
46 write!(f, "\n\n{:#}", View(p))?;
47 }
48 } else {
49 if let Some(p) = ps.next() {
50 write!(f, "{}", View(p))?;
51 }
52 for p in ps {
53 write!(f, " {}", View(p))?;
54 }
55 }
56 Ok(())
57 }
58}
59impl fmt::Display for Policy {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 let policy = match self {
62 Policy::Policy(p) => p,
63 #[cfg(feature = "tolerant-ast")]
64 Policy::PolicyError => {
65 writeln!(f, "Policy::PolicyError")?;
66 return Ok(());
67 }
68 };
69 for anno in policy.annotations.iter() {
71 if f.alternate() {
72 writeln!(f, "{:#}", View(anno))?;
74 } else {
75 write!(f, "{} ", View(anno))?;
76 }
77 }
78 if f.alternate() {
80 write!(f, "{:#}(", View(&policy.effect))?;
81 let mut vars = policy.variables.iter();
82 if let Some(v) = vars.next() {
84 write!(f, "\n {:#}", View(v))?;
86 for v in vars {
88 write!(f, ",\n {:#}", View(v))?;
89 }
90 write!(f, "\n)")?;
92 } else {
93 write!(f, ")")?;
95 }
96 for c in policy.conds.iter() {
98 write!(f, "\n{:#}", View(c))?;
99 }
100 write!(f, ";")?;
101 } else {
102 write!(f, "{}(", View(&policy.effect))?;
103 let mut vars = policy.variables.iter();
104 if let Some(v) = vars.next() {
106 write!(f, "{}", View(v))?;
108 for v in vars {
110 write!(f, ", {}", View(v))?;
111 }
112 }
113 write!(f, ")")?;
114
115 for c in policy.conds.iter() {
116 write!(f, " {}", View(c))?;
117 }
118 write!(f, ";")?;
119 }
120 Ok(())
121 }
122}
123
124impl fmt::Display for Annotation {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 match self.value.as_ref() {
127 Some(value) => write!(f, "@{}({})", View(&self.key), View(value)),
128 None => write!(f, "@{}", View(&self.key)),
129 }
130 }
131}
132
133impl fmt::Display for VariableDef {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 write!(f, "{}", View(&self.variable))?;
136 if let Some(name) = &self.unused_type_name {
137 write!(f, ": {}", View(name))?;
138 }
139 if let Some((op, expr)) = &self.ineq {
140 write!(f, " {} {}", op, View(expr))?;
141 }
142 Ok(())
143 }
144}
145impl fmt::Display for Cond {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 match self.expr.as_ref() {
148 Some(expr_ref) => {
149 if f.alternate() {
150 write!(f, "{} {{\n {:#}\n}}", View(&self.cond), View(expr_ref))
151 } else {
152 write!(f, "{} {{{}}}", View(&self.cond), View(expr_ref))
153 }
154 }
155 None => write!(f, "{} {{ }}", View(&self.cond)),
156 }
157 }
158}
159impl fmt::Display for Expr {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 let expr = match self {
163 Expr::Expr(expr_impl) => &*expr_impl.expr,
164 #[cfg(feature = "tolerant-ast")]
165 Expr::ErrorExpr => return write!(f, "Expr::Error"),
166 };
167 match expr {
168 ExprData::Or(or) => write!(f, "{}", View(or)),
169 ExprData::If(ex1, ex2, ex3) => {
170 write!(f, "if {} then {} else {}", View(ex1), View(ex2), View(ex3))
171 }
172 }
173 }
174}
175impl fmt::Display for Or {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 write!(f, "{}", View(&self.initial))?;
178 for or in self.extended.iter() {
179 write!(f, " || {}", View(or))?;
180 }
181 Ok(())
182 }
183}
184impl fmt::Display for And {
185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186 write!(f, "{}", View(&self.initial))?;
187 for and in self.extended.iter() {
188 write!(f, " && {}", View(and))?;
189 }
190 Ok(())
191 }
192}
193impl fmt::Display for Relation {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 match self {
196 Relation::Common { initial, extended } => {
197 write!(f, "{}", View(initial))?;
198 for (op, add) in extended.iter() {
199 write!(f, " {} {}", op, View(add))?;
200 }
201 }
202 Relation::Has { target, field } => {
203 write!(f, "{} has {}", View(target), View(field))?;
204 }
205 Relation::Like { target, pattern } => {
206 write!(f, "{} like {}", View(target), View(pattern))?;
207 }
208 Relation::IsIn {
209 target,
210 entity_type,
211 in_entity: None,
212 } => {
213 write!(f, "{} is {}", View(target), View(entity_type))?;
214 }
215 Relation::IsIn {
216 target,
217 entity_type,
218 in_entity: Some(in_entity),
219 } => {
220 write!(
221 f,
222 "{} is {} in {}",
223 View(target),
224 View(entity_type),
225 View(in_entity)
226 )?;
227 }
228 }
229 Ok(())
230 }
231}
232impl fmt::Display for RelOp {
233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 match self {
235 RelOp::Less => write!(f, "<"),
236 RelOp::LessEq => write!(f, "<="),
237 RelOp::GreaterEq => write!(f, ">="),
238 RelOp::Greater => write!(f, ">"),
239 RelOp::NotEq => write!(f, "!="),
240 RelOp::Eq => write!(f, "=="),
241 RelOp::In => write!(f, "in"),
242 RelOp::InvalidSingleEq => write!(f, "="),
243 }
244 }
245}
246impl fmt::Display for AddOp {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 match self {
249 AddOp::Plus => write!(f, "+"),
250 AddOp::Minus => write!(f, "-"),
251 }
252 }
253}
254impl fmt::Display for MultOp {
255 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256 match self {
257 MultOp::Times => write!(f, "*"),
258 MultOp::Divide => write!(f, "/"),
259 MultOp::Mod => write!(f, "%"),
260 }
261 }
262}
263impl fmt::Display for NegOp {
264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265 match self {
266 NegOp::Bang(cnt) => {
267 for _ in 0..*cnt {
268 write!(f, "!")?;
269 }
270 }
271 NegOp::OverBang => write!(f, "!!!!!!!!!!")?,
273 NegOp::Dash(cnt) => {
274 for _ in 0..*cnt {
275 write!(f, "-")?;
276 }
277 }
278 NegOp::OverDash => write!(f, "----------")?,
280 }
281 Ok(())
282 }
283}
284impl fmt::Display for Add {
285 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286 write!(f, "{}", View(&self.initial))?;
287 for (op, mult) in self.extended.iter() {
288 write!(f, " {} {}", op, View(mult))?;
289 }
290 Ok(())
291 }
292}
293impl fmt::Display for Mult {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 write!(f, "{}", View(&self.initial))?;
296 for (op, un) in self.extended.iter() {
297 write!(f, " {} {}", op, View(un))?;
298 }
299 Ok(())
300 }
301}
302impl fmt::Display for Unary {
303 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304 if let Some(op) = &self.op {
305 write!(f, "{}{}", op, View(&self.item))
306 } else {
307 write!(f, "{}", View(&self.item))
308 }
309 }
310}
311impl fmt::Display for Member {
312 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313 write!(f, "{}", View(&self.item))?;
314 for m in self.access.iter() {
315 write!(f, "{}", View(m))?;
316 }
317 Ok(())
318 }
319}
320impl fmt::Display for MemAccess {
321 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
322 match self {
323 MemAccess::Field(id) => write!(f, ".{}", View(id))?,
324 MemAccess::Call(exprs) => {
325 write!(f, "(")?;
326 let mut es = exprs.iter();
327 if let Some(ex) = es.next() {
328 write!(f, "{}", View(ex))?;
329 }
330 for e in es {
331 write!(f, ", {}", View(e))?;
332 }
333 write!(f, ")")?;
334 }
335 MemAccess::Index(e) => write!(f, "[{}]", View(e))?,
336 }
337 Ok(())
338 }
339}
340impl fmt::Display for Primary {
341 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
342 match self {
343 Primary::Literal(lit) => write!(f, "{}", View(lit)),
344 Primary::Ref(rf) => write!(f, "{}", View(rf)),
345 Primary::Name(nm) => write!(f, "{}", View(nm)),
346 Primary::Expr(expr) => write!(f, "({})", View(expr)),
347 Primary::EList(exs) => {
348 write!(f, "[")?;
349 let mut es = exs.iter();
350 if let Some(ex) = es.next() {
351 write!(f, "{}", View(ex))?;
352 }
353 for e in es {
354 write!(f, ", {}", View(e))?;
355 }
356 write!(f, "]")
357 }
358 Primary::RInits(mis) => {
359 write!(f, "{{")?;
360 let mut ms = mis.iter();
361 if let Some(i) = ms.next() {
362 write!(f, "{}", View(i))?;
363 }
364 for i in ms {
365 write!(f, ", {}", View(i))?;
366 }
367 write!(f, "}}")
368 }
369 Primary::Slot(s) => write!(f, "{}", View(s)),
370 }
371 }
372}
373impl fmt::Display for Name {
374 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375 for n in self.path.iter() {
376 write!(f, "{}::", View(n))?;
377 }
378 write!(f, "{}", View(&self.name))?;
379 Ok(())
380 }
381}
382impl fmt::Display for Ref {
383 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384 match self {
385 Ref::Uid { path, eid } => {
386 write!(f, "{}::{}", View(path), View(eid))?;
387 }
388 Ref::Ref { path, rinits } => {
389 write!(f, "{}::{{", View(path))?;
390 let mut ris = rinits.iter();
391 if let Some(r) = ris.next() {
392 write!(f, "{}", View(r))?;
393 }
394 for r in ris {
395 write!(f, ", {}", View(r))?;
396 }
397 write!(f, "}}")?;
398 }
399 }
400 Ok(())
401 }
402}
403impl fmt::Display for RefInit {
404 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
405 write!(f, "{}: {}", View(&self.0), View(&self.1))
406 }
407}
408impl fmt::Display for RecInit {
409 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
410 write!(f, "{}: {}", View(&self.0), View(&self.1))
411 }
412}
413impl fmt::Display for Ident {
414 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
415 match self {
416 Ident::Principal => write!(f, "principal"),
417 Ident::Action => write!(f, "action"),
418 Ident::Resource => write!(f, "resource"),
419 Ident::Context => write!(f, "context"),
420 Ident::True => write!(f, "true"),
421 Ident::False => write!(f, "false"),
422 Ident::Permit => write!(f, "permit"),
423 Ident::Forbid => write!(f, "forbid"),
424 Ident::When => write!(f, "when"),
425 Ident::Unless => write!(f, "unless"),
426 Ident::In => write!(f, "in"),
427 Ident::Has => write!(f, "has"),
428 Ident::Like => write!(f, "like"),
429 Ident::Is => write!(f, "is"),
430 Ident::If => write!(f, "if"),
431 Ident::Then => write!(f, "then"),
432 Ident::Else => write!(f, "else"),
433 Ident::Ident(s) => write!(f, "{}", s),
434 Ident::Invalid(s) => write!(f, "{}", s),
435 }
436 }
437}
438impl fmt::Display for Literal {
439 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
440 match self {
441 Literal::True => write!(f, "true"),
442 Literal::False => write!(f, "false"),
443 Literal::Num(n) => write!(f, "{}", n),
444 Literal::Str(s) => write!(f, "{}", View(s)),
445 }
446 }
447}
448impl fmt::Display for Str {
449 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
450 match self {
451 Str::String(s) | Str::Invalid(s) => {
452 write!(f, "\"{}\"", s)
453 }
454 }
455 }
456}
457
458impl std::fmt::Display for Slot {
459 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
460 let src = match self {
461 Slot::Principal => "?principal",
462 Slot::Resource => "?resource",
463 Slot::Other(slot) => slot.as_ref(),
464 };
465 write!(f, "{src}")
466 }
467}
468
469pub fn join_with_conjunction<T, W: Write>(
472 f: &mut W,
473 conjunction: &str,
474 items: impl IntoIterator<Item = T>,
475 fmt_item: impl Fn(&mut W, T) -> fmt::Result,
476) -> fmt::Result {
477 let mut iter = items.into_iter().peekable();
478
479 if let Some(first_item) = iter.next() {
480 fmt_item(f, first_item)?;
481
482 if let Some(second_item) = iter.next() {
483 match iter.peek() {
484 Some(_) => write!(f, ", "),
485 None => write!(f, " {conjunction} "),
486 }?;
487
488 fmt_item(f, second_item)?;
489
490 while let Some(item) = iter.next() {
491 match iter.peek() {
492 Some(_) => write!(f, ", "),
493 None => write!(f, ", {conjunction} "),
494 }?;
495
496 fmt_item(f, item)?;
497 }
498 }
499 }
500
501 Ok(())
502}
503
504#[cfg(test)]
505mod test {
506 use crate::parser::*;
507
508 #[test]
512 fn idempotent1() {
513 let cstnode1 = text_to_cst::parse_policies(
517 r#"
518
519 permit(principal,action,resource,context)
520 when {
521 -3 != !!2
522 };
523
524 "#,
525 )
526 .expect("parse fail");
527 let cst1 = cstnode1.as_inner().expect("no data");
528 let revert = format!("{}", cst1);
529 let cstnode2 = text_to_cst::parse_policies(&revert).expect("parse fail");
530 let cst2 = cstnode2.as_inner().expect("no data");
531 println!("{:#}", cst2);
532 assert!(cst1 == cst2);
533 }
534 #[test]
535 fn idempotent2() {
536 let cstnode1 = text_to_cst::parse_policies(
537 r#"
538
539 permit(principal,action,resource,context)
540 when {
541 context.contains(3,"four",five(6,7))
542 };
543
544 "#,
545 )
546 .expect("parse fail");
547 let cst1 = cstnode1.as_inner().expect("no data");
548 let revert = format!("{}", cst1);
549 let cstnode2 = text_to_cst::parse_policies(&revert).expect("parse fail");
550 let cst2 = cstnode2.as_inner().expect("no data");
551 assert!(cst1 == cst2);
552 }
553 #[test]
554 fn idempotent3() {
555 let cstnode1 = text_to_cst::parse_policies(
556 r#"
557
558 permit(principal,action,resource,context)
559 when {
560 context == {3: 14, "true": false || true }
561 };
562
563 "#,
564 )
565 .expect("parse fail");
566 let cst1 = cstnode1.as_inner().expect("no data");
567 let revert = format!("{}", cst1);
568 let cstnode2 = text_to_cst::parse_policies(&revert).expect("parse fail");
569 let cst2 = cstnode2.as_inner().expect("no data");
570 assert!(cst1 == cst2);
571 }
572 #[test]
573 fn idempotent4() {
574 let cstnode1 = text_to_cst::parse_policies(
575 r#"
576
577 permit(principal,action,resource,context)
578 when {
579 contains() ||
580 containsAll() ||
581 containsAny() ||
582 "sometext" like "some*" ||
583 Random::naming::of::foo()
584 };
585
586 "#,
587 )
588 .expect("parse fail");
589 let cst1 = cstnode1.as_inner().expect("no data");
590 let revert = format!("{}", cst1);
591 println!("{:#}", cst1);
592 let cstnode2 = text_to_cst::parse_policies(&revert).expect("parse fail");
593 let cst2 = cstnode2.as_inner().expect("no data");
594 assert!(cst1 == cst2);
595 }
596
597 #[test]
598 fn idempotent5() {
599 let cstnode1 = text_to_cst::parse_policies(
600 r#"
601
602 permit(principal,action,resource,context)
603 when {
604 principle == Group::{uid:"ajn34-3qg3-g5"}
605 };
606
607 "#,
608 )
609 .expect("parse fail");
610 let cst1 = cstnode1.as_inner().expect("no data");
611 let revert = format!("{}", cst1);
612 let cstnode2 = text_to_cst::parse_policies(&revert).expect("parse fail");
613 let cst2 = cstnode2.as_inner().expect("no data");
614 assert!(cst1 == cst2);
615 }
616}