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