1 /********************* */
4 ** Top contributors (to current version):
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS
8 ** in the top-level source directory) and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
12 ** \brief Simple representation of S-expressions
14 ** Simple representation of S-expressions.
16 ** SExprs have their own language specific printing procedures. The reason for
17 ** this being implemented on SExpr and not on the Printer class is that the
18 ** Printer class lives in libcvc4. It has to currently as it prints fairly
19 ** complicated objects, like Model, which in turn uses SmtEngine pointers.
20 ** However, SExprs need to be printed by Statistics. To get the output
21 ** consistent with the previous version, the printing of SExprs in different
22 ** languages is handled in the SExpr class and the libexpr library.
25 #include "util/sexpr.h"
31 #include "base/cvc4_assert.h"
32 #include "options/set_language.h"
33 #include "util/smt2_quote_string.h"
37 const int PrettySExprs::s_iosIndex
= std::ios_base::xalloc();
39 std::ostream
& operator<<(std::ostream
& out
, PrettySExprs ps
) {
40 ps
.applyPrettySExprs(out
);
45 if (d_children
!= NULL
) {
49 Assert(d_children
== NULL
);
52 SExpr
& SExpr::operator=(const SExpr
& other
) {
53 d_sexprType
= other
.d_sexprType
;
54 d_integerValue
= other
.d_integerValue
;
55 d_rationalValue
= other
.d_rationalValue
;
56 d_stringValue
= other
.d_stringValue
;
58 if (d_children
== NULL
&& other
.d_children
== NULL
) {
60 } else if (d_children
== NULL
) {
61 d_children
= new SExprVector(*other
.d_children
);
62 } else if (other
.d_children
== NULL
) {
66 (*d_children
) = other
.getChildren();
68 Assert(isAtom() == other
.isAtom());
69 Assert((d_children
== NULL
) == isAtom());
74 : d_sexprType(SEXPR_STRING
),
80 SExpr::SExpr(const SExpr
& other
)
81 : d_sexprType(other
.d_sexprType
),
82 d_integerValue(other
.d_integerValue
),
83 d_rationalValue(other
.d_rationalValue
),
84 d_stringValue(other
.d_stringValue
),
87 (other
.d_children
== NULL
) ? NULL
: new SExprVector(*other
.d_children
);
88 // d_children being NULL is equivalent to the node being an atom.
89 Assert((d_children
== NULL
) == isAtom());
92 SExpr::SExpr(const CVC4::Integer
& value
)
93 : d_sexprType(SEXPR_INTEGER
),
94 d_integerValue(value
),
99 SExpr::SExpr(int value
)
100 : d_sexprType(SEXPR_INTEGER
),
101 d_integerValue(value
),
106 SExpr::SExpr(long int value
)
107 : d_sexprType(SEXPR_INTEGER
),
108 d_integerValue(value
),
113 SExpr::SExpr(unsigned int value
)
114 : d_sexprType(SEXPR_INTEGER
),
115 d_integerValue(value
),
120 SExpr::SExpr(unsigned long int value
)
121 : d_sexprType(SEXPR_INTEGER
),
122 d_integerValue(value
),
127 SExpr::SExpr(const CVC4::Rational
& value
)
128 : d_sexprType(SEXPR_RATIONAL
),
130 d_rationalValue(value
),
134 SExpr::SExpr(const std::string
& value
)
135 : d_sexprType(SEXPR_STRING
),
138 d_stringValue(value
),
142 * This constructs a string expression from a const char* value.
143 * This cannot be removed in order to support SExpr("foo").
144 * Given the other constructors this SExpr("foo") converts to bool.
145 * instead of SExpr(string("foo")).
147 SExpr::SExpr(const char* value
)
148 : d_sexprType(SEXPR_STRING
),
151 d_stringValue(value
),
154 SExpr::SExpr(bool value
)
155 : d_sexprType(SEXPR_KEYWORD
),
158 d_stringValue(value
? "true" : "false"),
161 SExpr::SExpr(const Keyword
& value
)
162 : d_sexprType(SEXPR_KEYWORD
),
165 d_stringValue(value
.getString()),
168 SExpr::SExpr(const std::vector
<SExpr
>& children
)
169 : d_sexprType(SEXPR_NOT_ATOM
),
173 d_children(new SExprVector(children
)) {}
175 std::string
SExpr::toString() const {
176 std::stringstream ss
;
181 /** Is this S-expression an atom? */
182 bool SExpr::isAtom() const { return d_sexprType
!= SEXPR_NOT_ATOM
; }
184 /** Is this S-expression an integer? */
185 bool SExpr::isInteger() const { return d_sexprType
== SEXPR_INTEGER
; }
187 /** Is this S-expression a rational? */
188 bool SExpr::isRational() const { return d_sexprType
== SEXPR_RATIONAL
; }
190 /** Is this S-expression a string? */
191 bool SExpr::isString() const { return d_sexprType
== SEXPR_STRING
; }
193 /** Is this S-expression a keyword? */
194 bool SExpr::isKeyword() const { return d_sexprType
== SEXPR_KEYWORD
; }
196 std::ostream
& operator<<(std::ostream
& out
, const SExpr
& sexpr
) {
197 SExpr::toStream(out
, sexpr
);
201 void SExpr::toStream(std::ostream
& out
, const SExpr
& sexpr
) {
202 toStream(out
, sexpr
, language::SetLanguage::getLanguage(out
));
205 void SExpr::toStream(std::ostream
& out
, const SExpr
& sexpr
,
206 OutputLanguage language
) {
207 const int indent
= PrettySExprs::getPrettySExprs(out
) ? 2 : 0;
208 toStream(out
, sexpr
, language
, indent
);
211 void SExpr::toStream(std::ostream
& out
, const SExpr
& sexpr
,
212 OutputLanguage language
, int indent
) {
213 if (sexpr
.isKeyword() && languageQuotesKeywords(language
)) {
214 out
<< quoteSymbol(sexpr
.getValue());
216 toStreamRec(out
, sexpr
, language
, indent
);
220 void SExpr::toStreamRec(std::ostream
& out
, const SExpr
& sexpr
,
221 OutputLanguage language
, int indent
) {
222 if (sexpr
.isInteger()) {
223 out
<< sexpr
.getIntegerValue();
224 } else if (sexpr
.isRational()) {
225 const double approximation
= sexpr
.getRationalValue().getDouble();
226 out
<< std::fixed
<< approximation
;
227 } else if (sexpr
.isKeyword()) {
228 out
<< sexpr
.getValue();
229 } else if (sexpr
.isString()) {
230 std::string s
= sexpr
.getValue();
231 // escape backslash and quote
232 for (size_t i
= 0; i
< s
.length(); ++i
) {
234 s
.replace(i
, 1, "\\\"");
236 } else if (s
[i
] == '\\') {
237 s
.replace(i
, 1, "\\\\");
241 out
<< "\"" << s
<< "\"";
243 const std::vector
<SExpr
>& kids
= sexpr
.getChildren();
244 out
<< (indent
> 0 && kids
.size() > 1 ? "( " : "(");
246 for (std::vector
<SExpr
>::const_iterator i
= kids
.begin(); i
!= kids
.end();
252 out
<< "\n" << std::string(indent
, ' ');
257 toStreamRec(out
, *i
, language
,
258 indent
<= 0 || indent
> 2 ? 0 : indent
+ 2);
260 if (indent
> 0 && kids
.size() > 1) {
263 out
<< std::string(indent
- 2, ' ');
268 } /* toStreamRec() */
270 bool SExpr::languageQuotesKeywords(OutputLanguage language
) {
272 case language::output::LANG_SMTLIB_V1
:
273 case language::output::LANG_SMTLIB_V2_0
:
274 case language::output::LANG_SMTLIB_V2_5
:
275 case language::output::LANG_SMTLIB_V2_6
:
276 case language::output::LANG_SYGUS
:
277 case language::output::LANG_TPTP
:
278 case language::output::LANG_Z3STR
:
280 case language::output::LANG_AST
:
281 case language::output::LANG_CVC3
:
282 case language::output::LANG_CVC4
:
288 std::string
SExpr::getValue() const {
289 PrettyCheckArgument(isAtom(), this);
290 switch (d_sexprType
) {
292 return d_integerValue
.toString();
293 case SEXPR_RATIONAL
: {
294 // We choose to represent rationals as decimal strings rather than
295 // "numerator/denominator." Perhaps an additional SEXPR_DECIMAL
296 // could be added if we need both styles, even if it's backed by
297 // the same Rational object.
298 std::stringstream ss
;
299 ss
<< std::fixed
<< d_rationalValue
.getDouble();
304 return d_stringValue
;
306 return std::string();
308 return std::string();
311 const CVC4::Integer
& SExpr::getIntegerValue() const {
312 PrettyCheckArgument(isInteger(), this);
313 return d_integerValue
;
316 const CVC4::Rational
& SExpr::getRationalValue() const {
317 PrettyCheckArgument(isRational(), this);
318 return d_rationalValue
;
321 const std::vector
<SExpr
>& SExpr::getChildren() const {
322 PrettyCheckArgument(!isAtom(), this);
323 Assert(d_children
!= NULL
);
327 bool SExpr::operator==(const SExpr
& s
) const {
328 if (d_sexprType
== s
.d_sexprType
&& d_integerValue
== s
.d_integerValue
&&
329 d_rationalValue
== s
.d_rationalValue
&&
330 d_stringValue
== s
.d_stringValue
) {
331 if (d_children
== NULL
&& s
.d_children
== NULL
) {
333 } else if (d_children
!= NULL
&& s
.d_children
!= NULL
) {
334 return getChildren() == s
.getChildren();
340 bool SExpr::operator!=(const SExpr
& s
) const { return !(*this == s
); }
342 SExpr
SExpr::parseAtom(const std::string
& atom
) {
343 if (atom
== "true") {
345 } else if (atom
== "false") {
351 } catch (std::invalid_argument
&) {
352 // Fall through to the next case
357 } catch (std::invalid_argument
&) {
358 // Fall through to the next case
364 SExpr
SExpr::parseListOfAtoms(const std::vector
<std::string
>& atoms
) {
365 std::vector
<SExpr
> parsedAtoms
;
366 typedef std::vector
<std::string
>::const_iterator const_iterator
;
367 for (const_iterator i
= atoms
.begin(), i_end
= atoms
.end(); i
!= i_end
; ++i
) {
368 parsedAtoms
.push_back(parseAtom(*i
));
370 return SExpr(parsedAtoms
);
373 SExpr
SExpr::parseListOfListOfAtoms(
374 const std::vector
<std::vector
<std::string
> >& atoms_lists
) {
375 std::vector
<SExpr
> parsedListsOfAtoms
;
376 typedef std::vector
<std::vector
<std::string
> >::const_iterator const_iterator
;
377 for (const_iterator i
= atoms_lists
.begin(), i_end
= atoms_lists
.end();
379 parsedListsOfAtoms
.push_back(parseListOfAtoms(*i
));
381 return SExpr(parsedListsOfAtoms
);
384 } /* CVC4 namespace */