conjure_core/ast/pretty.rs
1//! Functions for pretty printing Conjure models.
2//!
3//! Most things can be pretty printed using `Display`; however some, notably collections
4//! can not, for example, Vec<Expression>
5
6use std::fmt::Display;
7
8use itertools::Itertools;
9
10use super::{Expression, Name, SymbolTable};
11
12/// Pretty prints a `Vec<Expression>` as if it were a top level constraint list in a `such that`.
13///
14/// Each expression is printed on a new line, and expressions are delimited by commas.
15///
16/// For some input expressions A,B,C:
17/// ```text
18/// A,
19/// B,
20/// C
21/// ```
22///
23/// Each `Expression` is printed using its underlying `Display` implementation.
24pub fn pretty_expressions_as_top_level(expressions: &[Expression]) -> String {
25 expressions.iter().map(|x| format!("{}", x)).join(",\n")
26}
27
28/// Pretty prints a `Vec<Expression>` as if it were a conjunction.
29///
30/// For some input expressions A,B,C:
31///
32/// ```text
33/// (A /\ B /\ C)
34/// ```
35///
36/// Each `Expression` is printed using its underlying `Display` implementation.
37pub fn pretty_expressions_as_conjunction(expressions: &[Expression]) -> String {
38 let mut str = expressions.iter().map(|x| format!("{}", x)).join(" /\\ ");
39
40 str.insert(0, '(');
41 str.push(')');
42
43 str
44}
45
46/// Pretty prints a `Vec<T>` in a vector like syntax.
47///
48/// For some input values A,B,C:
49///
50/// ```text
51/// [A,B,C]
52/// ````
53///
54/// Each element is printed using its underlying `Display` implementation.
55pub fn pretty_vec<T: Display>(elems: &[T]) -> String {
56 let mut str = elems.iter().map(|x| format!("{}", x)).join(", ");
57 str.insert(0, '[');
58 str.push(']');
59
60 str
61}
62
63/// Pretty prints, in essence syntax, the variable declaration for the given symbol.
64///
65/// E.g.
66///
67/// ```text
68/// find a: int(1..5)
69/// ```
70///
71/// Returns None if the symbol is not in the symbol table, or if it is not a variable.
72pub fn pretty_variable_declaration(symbol_table: &SymbolTable, var_name: &Name) -> Option<String> {
73 let decl = symbol_table.lookup(var_name)?;
74 let var = decl.as_var()?;
75 let domain = &var.domain;
76 Some(format!("find {var_name}: {domain}"))
77}
78
79/// Pretty prints, in essence syntax, the declaration for the given value letting.
80///
81/// E.g.
82///
83/// ```text
84/// letting A be 1+2+3
85/// ```
86///
87/// Returns None if the symbol is not in the symbol table, or if it is not a value letting.
88pub fn pretty_value_letting_declaration(symbol_table: &SymbolTable, name: &Name) -> Option<String> {
89 let decl = symbol_table.lookup(name)?;
90 let letting = decl.as_value_letting()?;
91 Some(format!("letting {name} be {letting}"))
92}
93
94/// Pretty prints, in essence syntax, the declaration for the given domain letting.
95///
96/// E.g.
97///
98/// ```text
99/// letting A be domain bool
100/// ```
101///
102/// Returns None if the symbol is not in the symbol table, or if it is not a domain letting.
103pub fn pretty_domain_letting_declaration(
104 symbol_table: &SymbolTable,
105 name: &Name,
106) -> Option<String> {
107 let decl = symbol_table.lookup(name)?;
108 let letting = decl.as_domain_letting()?;
109 Some(format!("letting {name} be domain {letting}"))
110}