Skip to main content

formally_smt/
pretty.rs

1//
2// ::formally - the open-source formal methods toolchain
3//
4// Copyright (c) 2025 Nicola Gigante
5//
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to deal
8// in the Software without restriction, including without limitation the rights
9// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10// copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12//
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15//
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22// SOFTWARE.
23//
24
25use crate::*;
26
27use formally::{
28    io::print::{Pretty, RcDoc},
29    smt::smtlib::ast,
30    support::*,
31};
32
33use formally_io::print::Print;
34use std::fmt::{Display, Formatter};
35
36impl From<Identifier<'_>> for ast::Symbol {
37    fn from(value: Identifier<'_>) -> Self {
38        ast::Symbol::Quoted(ast::QuotedSymbol {
39            span: value.span().clone(),
40            value: value.into_string(),
41        })
42        .simplify()
43    }
44}
45
46impl From<Identifier<'_>> for ast::QualifiedIdentifier {
47    fn from(value: Identifier<'_>) -> Self {
48        let symbol = ast::Symbol::from(value);
49        ast::QualifiedIdentifier {
50            span: symbol.span(),
51            id: ast::Identifier::Symbol(symbol),
52            sort: None,
53        }
54    }
55}
56
57impl From<Constant> for ast::Constant {
58    fn from(cnst: Constant) -> Self {
59        match cnst {
60            Constant::Integer { value, span } => ast::Constant::Numeral(ast::Numeral {
61                value: (*value).clone(),
62                span,
63            }),
64            Constant::Rational { value, span } => ast::Constant::Decimal(ast::Decimal {
65                value: (*value).clone(),
66                span,
67            }),
68        }
69    }
70}
71
72impl From<Term> for ast::Term {
73    fn from(term: Term) -> Self {
74        match term.kind() {
75            TermKind::Constant(cnst) => ast::Term::Constant(ast::Constant::from(cnst.clone())),
76            TermKind::Atom(atom) => {
77                let (id, arguments) = match &atom.head {
78                    FunctionRef::Bound(BoundRef { function, .. }) => {
79                        (function.name().clone(), &*atom.arguments)
80                    }
81                    FunctionRef::Unbound(name) => {
82                        (name.clone(), &*atom.arguments)
83                    }
84                };
85
86                ast::Term::Application(ast::Application {
87                    head: ast::QualifiedIdentifier::from(id),
88                    args: arguments
89                        .iter()
90                        .map(|arg| ast::Term::from(arg.clone()))
91                        .collect(),
92                    span: None,
93                })
94            }
95            TermKind::Quantified(quant) => match quant.quantifier {
96                Quantifier::Forall => ast::Term::Forall(ast::Forall {
97                    bindings: quant
98                        .variables
99                        .iter()
100                        .map(|var| ast::SortedVar::from(var.clone()))
101                        .collect(),
102                    body: Box::new(ast::Term::from(quant.body.clone())),
103                    span: quant.span.clone(),
104                }),
105                Quantifier::Exists => ast::Term::Exists(ast::Exists {
106                    bindings: quant
107                        .variables
108                        .iter()
109                        .map(|var| ast::SortedVar::from(var.clone()))
110                        .collect(),
111                    body: Box::new(ast::Term::from(quant.body.clone())),
112                    span: quant.span.clone(),
113                }),
114            },
115            TermKind::Let(let_) => ast::Term::Let(ast::Let {
116                bindings: let_
117                    .bindings
118                    .iter()
119                    .map(|bind| ast::Binding::from(bind.clone()))
120                    .collect(),
121                body: Box::new(ast::Term::from(let_.body.clone())),
122                span: let_.span.clone(),
123            }),
124        }
125    }
126}
127
128impl From<Variable> for ast::SortedVar {
129    fn from(var: Variable) -> Self {
130        ast::SortedVar {
131            name: ast::Symbol::from(var.name().clone()),
132            sort: ast::Sort::from(var.sort().clone()),
133            span: var.span().clone(),
134        }
135    }
136}
137
138impl From<Binding> for ast::Binding {
139    fn from(bind: Binding) -> Self {
140        ast::Binding {
141            name: ast::Symbol::from(bind.variable.name().clone()),
142            body: ast::Term::from(bind.def.clone()),
143            span: bind.span.clone(),
144        }
145    }
146}
147
148impl From<Sort> for ast::Sort {
149    fn from(value: Sort) -> Self {
150        let head = ast::Identifier::Symbol(ast::Symbol::from(value.head.name().clone()));
151
152        if value.arguments.is_empty() {
153            ast::Sort::Simple(head)
154        } else {
155            let mut args = Vec::new();
156            for arg in &*value.arguments {
157                match arg {
158                    SortArgument::Value(_) => todo!(),
159                    SortArgument::Sort(arg) => args.push(ast::Sort::from(arg.clone())),
160                }
161            }
162            ast::Sort::Application(ast::SortApplication {
163                head,
164                args,
165                span: None,
166            })
167        }
168    }
169}
170
171impl Pretty for Term {
172    fn pretty(&self) -> RcDoc<'static> {
173        ast::Term::from(self.clone()).pretty()
174    }
175}
176
177impl Display for Term {
178    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
179        self.render_fmt(f, u16::MAX)
180    }
181}
182
183impl Pretty for Sort {
184    fn pretty(&self) -> RcDoc<'static> {
185        ast::Sort::from(self.clone()).pretty()
186    }
187}
188
189impl Display for Sort {
190    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
191        self.render_fmt(f, u16::MAX)
192    }
193}