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