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

            
6
use std::fmt::Display;
7

            
8
use super::{CnfClause, Expression, Name, SymbolTable};
9
use crate::ast::domains::HasDomain;
10
use itertools::Itertools;
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.
24
pub 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<CnfClause>` as a list of clauses as disjunctions
29
///
30
/// Each clause is printed on a new line, and expressions are delimited by commas.
31
///
32
/// For some input expressions A,B,C:
33
/// ```text
34
/// (a_0 \/ ¬a_1 ...),
35
/// (b_0 \/ b_1 ...),
36
/// (¬c_0 \/ c_1 ...)
37
/// ```
38
///
39
/// Each `Expression` is printed using its underlying `Display` implementation.
40
pub fn pretty_clauses(clauses: &[CnfClause]) -> String {
41
    clauses.iter().map(|clause| format!("{clause}")).join(",\n")
42
}
43

            
44
/// Pretty prints a `Vec<Expression>` as if it were a conjunction.
45
///
46
/// For some input expressions A,B,C:
47
///
48
/// ```text
49
/// (A /\ B /\ C)
50
/// ```
51
///
52
/// Each `Expression` is printed using its underlying `Display` implementation.
53
pub fn pretty_expressions_as_conjunction(expressions: &[Expression]) -> String {
54
    let mut str = expressions.iter().map(|x| format!("{x}")).join(" /\\ ");
55

            
56
    str.insert(0, '(');
57
    str.push(')');
58

            
59
    str
60
}
61

            
62
/// Pretty prints a `Vec<T>` in a vector like syntax.
63
///
64
/// For some input values A,B,C:
65
///
66
/// ```text
67
/// [A,B,C]
68
/// ````
69
///
70
/// Each element is printed using its underlying `Display` implementation.
71
pub fn pretty_vec<T: Display>(elems: &[T]) -> String {
72
    let mut str = elems.iter().map(|x| format!("{x}")).join(", ");
73
    str.insert(0, '[');
74
    str.push(']');
75

            
76
    str
77
}
78

            
79
/// Pretty prints, in essence syntax, the variable declaration for the given symbol.
80
///
81
/// E.g.
82
///
83
/// ```text
84
/// find a: int(1..5)
85
/// ```
86
///
87
/// Returns None if the symbol is not in the symbol table, or if it is not a variable.
88
pub fn pretty_variable_declaration(symbol_table: &SymbolTable, var_name: &Name) -> Option<String> {
89
    let decl = symbol_table.lookup(var_name)?;
90
    let var = decl.as_var()?;
91
    let domain = &var.domain_of();
92
    Some(format!("find {var_name}: {domain}"))
93
}
94

            
95
/// Pretty prints, in essence syntax, the declaration for the given value letting.
96
///
97
/// E.g.
98
///
99
/// ```text
100
/// letting A be 1+2+3
101
/// ```
102
///
103
/// Returns None if the symbol is not in the symbol table, or if it is not a value letting.
104
pub fn pretty_value_letting_declaration(symbol_table: &SymbolTable, name: &Name) -> Option<String> {
105
    let decl = symbol_table.lookup(name)?;
106
    let letting = decl.as_value_letting()?;
107
    Some(format!("letting {name} be {letting}"))
108
}
109

            
110
/// Pretty prints, in essence syntax, the declaration for the given domain letting.
111
///
112
/// E.g.
113
///
114
/// ```text
115
/// letting A be domain bool
116
/// ```
117
///
118
/// Returns None if the symbol is not in the symbol table, or if it is not a domain letting.
119
pub fn pretty_domain_letting_declaration(
120
    symbol_table: &SymbolTable,
121
    name: &Name,
122
) -> Option<String> {
123
    let decl = symbol_table.lookup(name)?;
124
    let letting = decl.as_domain_letting()?;
125
    Some(format!("letting {name} be domain {letting}"))
126
}