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