1 /********************* */
4 ** Original author: Morgan Deters
5 ** Major contributors: none
6 ** Minor contributors (to current version): none
7 ** This file is part of the CVC4 project.
8 ** Copyright (c) 2009-2014 New York University and The University of Iowa
9 ** See the file COPYING in the top-level source directory for licensing
10 ** 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 consistent
21 ** with the previous version, the printing of SExprs in different languages is
22 ** 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
);
46 if(d_children
!= NULL
){
50 Assert(d_children
== NULL
);
53 SExpr
& SExpr::operator=(const SExpr
& other
) {
54 d_sexprType
= other
.d_sexprType
;
55 d_integerValue
= other
.d_integerValue
;
56 d_rationalValue
= other
.d_rationalValue
;
57 d_stringValue
= other
.d_stringValue
;
59 if(d_children
== NULL
&& other
.d_children
== NULL
){
61 } else if(d_children
== NULL
){
62 d_children
= new SExprVector(*other
.d_children
);
63 } else if(other
.d_children
== NULL
){
67 (*d_children
) = other
.getChildren();
69 Assert( isAtom() == other
.isAtom() );
70 Assert( (d_children
== NULL
) == isAtom() );
75 d_sexprType(SEXPR_STRING
),
83 SExpr::SExpr(const SExpr
& other
) :
84 d_sexprType(other
.d_sexprType
),
85 d_integerValue(other
.d_integerValue
),
86 d_rationalValue(other
.d_rationalValue
),
87 d_stringValue(other
.d_stringValue
),
90 d_children
= (other
.d_children
== NULL
) ? NULL
: new SExprVector(*other
.d_children
);
91 // d_children being NULL is equivalent to the node being an atom.
92 Assert( (d_children
== NULL
) == isAtom() );
96 SExpr::SExpr(const CVC4::Integer
& value
) :
97 d_sexprType(SEXPR_INTEGER
),
98 d_integerValue(value
),
104 SExpr::SExpr(int value
) :
105 d_sexprType(SEXPR_INTEGER
),
106 d_integerValue(value
),
112 SExpr::SExpr(long int value
) :
113 d_sexprType(SEXPR_INTEGER
),
114 d_integerValue(value
),
120 SExpr::SExpr(unsigned int value
) :
121 d_sexprType(SEXPR_INTEGER
),
122 d_integerValue(value
),
128 SExpr::SExpr(unsigned long int value
) :
129 d_sexprType(SEXPR_INTEGER
),
130 d_integerValue(value
),
136 SExpr::SExpr(const CVC4::Rational
& value
) :
137 d_sexprType(SEXPR_RATIONAL
),
139 d_rationalValue(value
),
144 SExpr::SExpr(const std::string
& value
) :
145 d_sexprType(SEXPR_STRING
),
148 d_stringValue(value
),
153 * This constructs a string expression from a const char* value.
154 * This cannot be removed in order to support SExpr("foo").
155 * Given the other constructors this SExpr("foo") converts to bool.
156 * instead of SExpr(string("foo")).
158 SExpr::SExpr(const char* value
) :
159 d_sexprType(SEXPR_STRING
),
162 d_stringValue(value
),
166 #warning "TODO: Discuss this change with Clark."
167 SExpr::SExpr(bool value
) :
168 d_sexprType(SEXPR_KEYWORD
),
171 d_stringValue(value
? "true" : "false"),
175 SExpr::SExpr(const Keyword
& value
) :
176 d_sexprType(SEXPR_KEYWORD
),
179 d_stringValue(value
.getString()),
183 SExpr::SExpr(const std::vector
<SExpr
>& children
) :
184 d_sexprType(SEXPR_NOT_ATOM
),
188 d_children(new SExprVector(children
)) {
191 std::string
SExpr::toString() const {
192 std::stringstream ss
;
197 /** Is this S-expression an atom? */
198 bool SExpr::isAtom() const {
199 return d_sexprType
!= SEXPR_NOT_ATOM
;
202 /** Is this S-expression an integer? */
203 bool SExpr::isInteger() const {
204 return d_sexprType
== SEXPR_INTEGER
;
207 /** Is this S-expression a rational? */
208 bool SExpr::isRational() const {
209 return d_sexprType
== SEXPR_RATIONAL
;
212 /** Is this S-expression a string? */
213 bool SExpr::isString() const {
214 return d_sexprType
== SEXPR_STRING
;
217 /** Is this S-expression a keyword? */
218 bool SExpr::isKeyword() const {
219 return d_sexprType
== SEXPR_KEYWORD
;
223 std::ostream
& operator<<(std::ostream
& out
, const SExpr
& sexpr
) {
224 SExpr::toStream(out
, sexpr
);
228 void SExpr::toStream(std::ostream
& out
, const SExpr
& sexpr
) throw() {
229 toStream(out
, sexpr
, language::SetLanguage::getLanguage(out
));
232 void SExpr::toStream(std::ostream
& out
, const SExpr
& sexpr
, OutputLanguage language
) throw() {
233 toStream(out
, sexpr
, language
, PrettySExprs::getPrettySExprs(out
) ? 2 : 0);
236 void SExpr::toStream(std::ostream
& out
, const SExpr
& sexpr
, OutputLanguage language
, int indent
) throw() {
237 if( sexpr
.isKeyword() && languageQuotesKeywords(language
) ){
238 out
<< quoteSymbol(sexpr
.getValue());
240 toStreamRec(out
, sexpr
, language
, indent
);
245 void SExpr::toStreamRec(std::ostream
& out
, const SExpr
& sexpr
, OutputLanguage language
, int indent
) throw() {
246 if(sexpr
.isInteger()) {
247 out
<< sexpr
.getIntegerValue();
248 } else if(sexpr
.isRational()) {
249 out
<< std::fixed
<< sexpr
.getRationalValue().getDouble();
250 } else if(sexpr
.isKeyword()) {
251 out
<< sexpr
.getValue();
252 } else if(sexpr
.isString()) {
253 std::string s
= sexpr
.getValue();
254 // escape backslash and quote
255 for(size_t i
= 0; i
< s
.length(); ++i
) {
257 s
.replace(i
, 1, "\\\"");
259 } else if(s
[i
] == '\\') {
260 s
.replace(i
, 1, "\\\\");
264 out
<< "\"" << s
<< "\"";
266 const std::vector
<SExpr
>& kids
= sexpr
.getChildren();
267 out
<< (indent
> 0 && kids
.size() > 1 ? "( " : "(");
269 for(std::vector
<SExpr
>::const_iterator i
= kids
.begin(); i
!= kids
.end(); ++i
) {
274 out
<< "\n" << std::string(indent
, ' ');
279 toStreamRec(out
, *i
, language
, indent
<= 0 || indent
> 2 ? 0 : indent
+ 2);
281 if(indent
> 0 && kids
.size() > 1) {
284 out
<< std::string(indent
- 2, ' ');
292 bool SExpr::languageQuotesKeywords(OutputLanguage language
) {
294 case language::output::LANG_SMTLIB_V1
:
295 case language::output::LANG_SMTLIB_V2_0
:
296 case language::output::LANG_SMTLIB_V2_5
:
297 case language::output::LANG_SYGUS
:
298 case language::output::LANG_TPTP
:
299 case language::output::LANG_Z3STR
:
301 case language::output::LANG_AST
:
302 case language::output::LANG_CVC3
:
303 case language::output::LANG_CVC4
:
311 std::string
SExpr::getValue() const {
312 PrettyCheckArgument( isAtom(), this );
313 switch(d_sexprType
) {
315 return d_integerValue
.toString();
316 case SEXPR_RATIONAL
: {
317 // We choose to represent rationals as decimal strings rather than
318 // "numerator/denominator." Perhaps an additional SEXPR_DECIMAL
319 // could be added if we need both styles, even if it's backed by
320 // the same Rational object.
321 std::stringstream ss
;
322 ss
<< std::fixed
<< d_rationalValue
.getDouble();
327 return d_stringValue
;
329 return std::string();
331 return std::string();
335 const CVC4::Integer
& SExpr::getIntegerValue() const {
336 PrettyCheckArgument( isInteger(), this );
337 return d_integerValue
;
340 const CVC4::Rational
& SExpr::getRationalValue() const {
341 PrettyCheckArgument( isRational(), this );
342 return d_rationalValue
;
345 const std::vector
<SExpr
>& SExpr::getChildren() const {
346 PrettyCheckArgument( !isAtom(), this );
347 Assert( d_children
!= NULL
);
351 bool SExpr::operator==(const SExpr
& s
) const {
352 if (d_sexprType
== s
.d_sexprType
&&
353 d_integerValue
== s
.d_integerValue
&&
354 d_rationalValue
== s
.d_rationalValue
&&
355 d_stringValue
== s
.d_stringValue
) {
356 if(d_children
== NULL
&& s
.d_children
== NULL
){
358 } else if(d_children
!= NULL
&& s
.d_children
!= NULL
){
359 return getChildren() == s
.getChildren();
365 bool SExpr::operator!=(const SExpr
& s
) const {
366 return !(*this == s
);
370 SExpr
SExpr::parseAtom(const std::string
& atom
) {
373 } else if(atom
== "false"){
379 }catch(std::invalid_argument
&){
380 // Fall through to the next case
385 }catch(std::invalid_argument
&){
386 // Fall through to the next case
392 SExpr
SExpr::parseListOfAtoms(const std::vector
<std::string
>& atoms
) {
393 std::vector
<SExpr
> parsedAtoms
;
394 typedef std::vector
<std::string
>::const_iterator const_iterator
;
395 for(const_iterator i
= atoms
.begin(), i_end
=atoms
.end(); i
!= i_end
; ++i
){
396 parsedAtoms
.push_back(parseAtom(*i
));
398 return SExpr(parsedAtoms
);
401 SExpr
SExpr::parseListOfListOfAtoms(const std::vector
< std::vector
<std::string
> >& atoms_lists
) {
402 std::vector
<SExpr
> parsedListsOfAtoms
;
403 typedef std::vector
< std::vector
<std::string
> >::const_iterator const_iterator
;
404 for(const_iterator i
= atoms_lists
.begin(), i_end
= atoms_lists
.end(); i
!= i_end
; ++i
){
405 parsedListsOfAtoms
.push_back(parseListOfAtoms(*i
));
407 return SExpr(parsedListsOfAtoms
);
412 }/* CVC4 namespace */