Add S-expressions

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-07-20 14:19:36 -07:00
parent eda1a337de
commit 05991c827b
9 changed files with 490 additions and 4 deletions

View file

@ -31,19 +31,27 @@ include(cmake/FindGMP.cmake)
set(EXTRA_LIBS ${EXTRA_LIBS} ${GMP_LIBRARIES}) set(EXTRA_LIBS ${EXTRA_LIBS} ${GMP_LIBRARIES})
# tcmalloc # tcmalloc
include(cmake/FindTcmalloc.cmake) option(tcmalloc "tcmalloc" ON)
if(${TCMALLOC_FOUND}) if("${tcmalloc}" MATCHES "ON")
set(EXTRA_LIBS ${EXTRA_LIBS} ${TCMALLOC_LIBRARIES}) include(cmake/FindTcmalloc.cmake)
if(${TCMALLOC_FOUND})
set(EXTRA_LIBS ${EXTRA_LIBS} ${TCMALLOC_LIBRARIES})
endif()
else()
message("-- Using standard malloc.")
endif() endif()
include_directories(${LEAN_SOURCE_DIR}/util) include_directories(${LEAN_SOURCE_DIR}/util)
include_directories(${LEAN_SOURCE_DIR}/numerics) include_directories(${LEAN_SOURCE_DIR}/numerics)
include_directories(${LEAN_SOURCE_DIR}/interval) include_directories(${LEAN_SOURCE_DIR}/interval)
include_directories(${LEAN_SOURCE_DIR}/sexpr)
add_subdirectory(util) add_subdirectory(util)
set(EXTRA_LIBS ${EXTRA_LIBS} util) set(EXTRA_LIBS ${EXTRA_LIBS} util)
add_subdirectory(numerics) add_subdirectory(numerics)
set(EXTRA_LIBS ${EXTRA_LIBS} numerics) set(EXTRA_LIBS ${EXTRA_LIBS} numerics)
add_subdirectory(sexpr)
set(EXTRA_LIBS ${EXTRA_LIBS} sexpr)
add_subdirectory(interval) add_subdirectory(interval)
set(EXTRA_LIBS ${EXTRA_LIBS} interval) set(EXTRA_LIBS ${EXTRA_LIBS} interval)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread")
@ -51,3 +59,4 @@ add_subdirectory(shell)
add_subdirectory(tests/util) add_subdirectory(tests/util)
add_subdirectory(tests/numerics) add_subdirectory(tests/numerics)
add_subdirectory(tests/interval) add_subdirectory(tests/interval)
add_subdirectory(tests/sexpr)

2
src/sexpr/CMakeLists.txt Normal file
View file

@ -0,0 +1,2 @@
add_library(sexpr sexpr.cpp)
target_link_libraries(sexpr ${EXTRA_LIBS})

227
src/sexpr/sexpr.cpp Normal file
View file

@ -0,0 +1,227 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include <cstring>
#include "rc.h"
#include "hash.h"
#include "sexpr.h"
#include "name.h"
#include "mpz.h"
#include "mpq.h"
namespace lean {
struct sexpr_cell {
void dealloc();
MK_LEAN_RC()
sexpr::kind m_kind;
unsigned m_hash;
sexpr_cell(sexpr::kind k, unsigned h):m_rc(1), m_kind(k), m_hash(h) {}
};
struct sexpr_string : public sexpr_cell {
std::string m_value;
sexpr_string(char const * v):
sexpr_cell(sexpr::kind::STRING, hash(v, strlen(v), 13)),
m_value(v) {}
sexpr_string(std::string const & v):
sexpr_cell(sexpr::kind::STRING, hash(v.c_str(), v.size(), 13)),
m_value(v) {}
};
struct sexpr_int : public sexpr_cell {
int m_value;
sexpr_int(int v):
sexpr_cell(sexpr::kind::INT, v),
m_value(v) {}
};
struct sexpr_double : public sexpr_cell {
double m_value;
sexpr_double(double v):
sexpr_cell(sexpr::kind::DOUBLE, static_cast<unsigned>(v)),
m_value(v) {}
};
struct sexpr_name : public sexpr_cell {
name m_value;
sexpr_name(name const & v):
sexpr_cell(sexpr::kind::NAME, v.hash()),
m_value(v) {}
};
struct sexpr_mpz : public sexpr_cell {
mpz m_value;
sexpr_mpz(mpz const & v):
sexpr_cell(sexpr::kind::MPZ, v.hash()),
m_value(v) {}
};
struct sexpr_mpq : public sexpr_cell {
mpq m_value;
sexpr_mpq(mpq const & v):
sexpr_cell(sexpr::kind::MPQ, v.hash()),
m_value(v) {}
};
struct sexpr_cons : public sexpr_cell {
sexpr m_head;
sexpr m_tail;
sexpr_cons(sexpr const & h, sexpr const & t):
sexpr_cell(sexpr::kind::CONS, hash(h.hash(), t.hash())),
m_head(h),
m_tail(t) {}
};
void sexpr_cell::dealloc() {
switch (m_kind) {
case sexpr::kind::NIL: lean_unreachable(); break;
case sexpr::kind::STRING: delete static_cast<sexpr_string*>(this); break;
case sexpr::kind::INT: delete static_cast<sexpr_int*>(this); break;
case sexpr::kind::DOUBLE: delete static_cast<sexpr_double*>(this); break;
case sexpr::kind::NAME: delete static_cast<sexpr_name*>(this); break;
case sexpr::kind::MPZ: delete static_cast<sexpr_mpz*>(this); break;
case sexpr::kind::MPQ: delete static_cast<sexpr_mpq*>(this); break;
case sexpr::kind::CONS: delete static_cast<sexpr_cons*>(this); break;
}
}
sexpr::sexpr(char const * v):m_ptr(new sexpr_string(v)) {}
sexpr::sexpr(std::string const & v):m_ptr(new sexpr_string(v)) {}
sexpr::sexpr(int v):m_ptr(new sexpr_int(v)) {}
sexpr::sexpr(double v):m_ptr(new sexpr_double(v)) {}
sexpr::sexpr(name const & v):m_ptr(new sexpr_name(v)) {}
sexpr::sexpr(mpz const & v):m_ptr(new sexpr_mpz(v)) {}
sexpr::sexpr(mpq const & v):m_ptr(new sexpr_mpq(v)) {}
sexpr::sexpr(sexpr const & h, sexpr const & t):m_ptr(new sexpr_cons(h, t)) {}
sexpr::sexpr(sexpr const & s):m_ptr(s.m_ptr) {
if (m_ptr)
m_ptr->inc_ref();
}
sexpr::sexpr(sexpr && s):m_ptr(s.m_ptr) {
s.m_ptr = 0;
}
sexpr::~sexpr() {
if (m_ptr)
m_ptr->dec_ref();
}
sexpr::kind sexpr::get_kind() const { return m_ptr ? m_ptr->m_kind : kind::NIL; }
sexpr const & head(sexpr const & s) { lean_assert(is_cons(s)); return static_cast<sexpr_cons*>(s.m_ptr)->m_head; }
sexpr const & tail(sexpr const & s) { lean_assert(is_cons(s)); return static_cast<sexpr_cons*>(s.m_ptr)->m_tail; }
std::string const & sexpr::get_string() const { return static_cast<sexpr_string*>(m_ptr)->m_value; }
int sexpr::get_int() const { return static_cast<sexpr_int*>(m_ptr)->m_value; }
double sexpr::get_double() const { return static_cast<sexpr_double*>(m_ptr)->m_value; }
name const & sexpr::get_name() const { return static_cast<sexpr_name*>(m_ptr)->m_value; }
mpz const & sexpr::get_mpz() const { return static_cast<sexpr_mpz*>(m_ptr)->m_value; }
mpq const & sexpr::get_mpq() const { return static_cast<sexpr_mpq*>(m_ptr)->m_value; }
unsigned sexpr::hash() const { return m_ptr == nullptr ? 23 : m_ptr->m_hash; }
sexpr & sexpr::operator=(sexpr const & s) {
if (s.m_ptr)
s.m_ptr->inc_ref();
if (m_ptr)
m_ptr->dec_ref();
m_ptr = s.m_ptr;
return *this;
}
sexpr & sexpr::operator=(sexpr && s) {
if (m_ptr)
m_ptr->dec_ref();
m_ptr = s.m_ptr;
s.m_ptr = 0;
return *this;
}
bool is_list(sexpr const & s) {
if (is_nil(s))
return true;
if (!is_cons(s))
return false;
sexpr const * curr = &s;
while (true) {
lean_assert(is_cons(*curr));
curr = &tail(*curr);
if (is_nil(*curr))
return true;
if (!is_cons(*curr))
return false;
}
}
unsigned length(sexpr const & s) {
unsigned r = 0;
sexpr const * curr = &s;
while (true) {
if (is_nil(*curr))
return r;
lean_assert(is_cons(*curr));
r++;
curr = &tail(*curr);
}
}
bool operator==(sexpr const & a, sexpr const & b) {
sexpr::kind ka = a.get_kind();
sexpr::kind kb = b.get_kind();
if (ka != kb)
return false;
// if (a.hash() != b.hash())
// return false;
switch (ka) {
case sexpr::kind::NIL: return true;
case sexpr::kind::STRING: return to_string(a) == to_string(b);
case sexpr::kind::INT: return to_int(a) == to_int(b);
case sexpr::kind::DOUBLE: return to_double(a) == to_double(b);
case sexpr::kind::NAME: return to_name(a) == to_name(b);
case sexpr::kind::MPZ: return to_mpz(a) == to_mpz(b);
case sexpr::kind::MPQ: return to_mpq(a) == to_mpq(b);
case sexpr::kind::CONS: return head(a) == head(b) && tail(a) == tail(b);
}
return false;
}
bool operator<(sexpr const & a, sexpr const & b) {
// TODO
return false;
}
std::ostream & operator<<(std::ostream & out, sexpr const & s) {
switch (s.get_kind()) {
case sexpr::kind::NIL: out << "nil"; break;
case sexpr::kind::STRING: out << "\"" << to_string(s) << "\""; break;
case sexpr::kind::INT: out << to_int(s); break;
case sexpr::kind::DOUBLE: out << to_double(s); break;
case sexpr::kind::NAME: out << to_name(s); break;
case sexpr::kind::MPZ: out << to_mpz(s); break;
case sexpr::kind::MPQ: out << to_mpq(s); break;
case sexpr::kind::CONS: {
out << "(";
sexpr const * curr = &s;
while (true) {
out << head(*curr);
curr = &tail(*curr);
if (is_nil(*curr)) {
break;
}
else if (!is_cons(*curr)) {
out << " . ";
out << *curr;
break;
}
else {
out << " ";
}
}
out << ")";
}}
return out;
}
}

121
src/sexpr/sexpr.h Normal file
View file

@ -0,0 +1,121 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include <iostream>
namespace lean {
class name;
class mpq;
class mpz;
struct sexpr_cell;
/**
\brief Simple LISP-like S-expressions.
1. Atoms: nil, string, int, name, mpz or mpq
2. Pair: (x . y) where x and y are S-expressions.
S-expressions are used for tracking configuration options, statistics, etc.
Remark: this datastructure does not allow destructive updates.
*/
class sexpr {
sexpr_cell * m_ptr;
public:
enum class kind { NIL, STRING, INT, DOUBLE, NAME, MPZ, MPQ, CONS };
sexpr():m_ptr(nullptr) {}
sexpr(char const * v);
sexpr(std::string const & v);
sexpr(int v);
sexpr(double v);
sexpr(name const & v);
sexpr(mpz const & v);
sexpr(mpq const & v);
sexpr(sexpr const & h, sexpr const & t);
sexpr(char const * v, sexpr const & t):sexpr(sexpr(v), t) {}
sexpr(std::string const & v, sexpr const & t):sexpr(sexpr(v), t) {}
sexpr(int v, sexpr const & t):sexpr(sexpr(v), t) {}
sexpr(double v, sexpr const & t):sexpr(sexpr(v), t) {}
sexpr(name const & v, sexpr const & t):sexpr(sexpr(v), t) {}
sexpr(mpz const & v, sexpr const & t):sexpr(sexpr(v), t) {}
sexpr(mpq const & v, sexpr const & t):sexpr(sexpr(v), t) {}
sexpr(sexpr const & s);
sexpr(sexpr && s);
template<typename T>
sexpr(std::initializer_list<T> const & l):sexpr() {
auto it = l.end();
while (it != l.begin()) {
--it;
*this = sexpr(*it, *this);
}
}
~sexpr();
kind get_kind() const;
friend bool is_nil(sexpr const & s) { return s.m_ptr == nullptr; }
friend sexpr const & head(sexpr const & s);
friend sexpr const & tail(sexpr const & s);
std::string const & get_string() const;
int get_int() const;
double get_double() const;
name const & get_name() const;
mpz const & get_mpz() const;
mpq const & get_mpq() const;
unsigned hash() const;
sexpr & operator=(sexpr const & s);
sexpr & operator=(sexpr&& s);
sexpr & operator=(char const * v) { return operator=(sexpr(v)); }
sexpr & operator=(std::string const & v) { return operator=(sexpr(v)); }
sexpr & operator=(int v) { return operator=(sexpr(v)); }
sexpr & operator=(mpz const & v) { return operator=(sexpr(v)); }
sexpr & operator=(mpq const & v) { return operator=(sexpr(v)); }
friend void swap(sexpr & a, sexpr & b) { std::swap(a.m_ptr, b.m_ptr); }
// Pointer equality
friend bool eqp(sexpr const & a, sexpr const & b) { return a.m_ptr == b.m_ptr; }
friend std::ostream & operator<<(std::ostream & out, sexpr const & s);
};
inline sexpr nil() { return sexpr(); }
inline sexpr cons(sexpr const & head, sexpr const & tail) { return sexpr(head, tail); }
inline sexpr const & car(sexpr const & s) { return head(s); }
inline sexpr const & cdr(sexpr const & s) { return tail(s); }
inline bool is_atom(sexpr const & s) { return s.get_kind() != sexpr::kind::CONS; }
inline bool is_cons(sexpr const & s) { return s.get_kind() == sexpr::kind::CONS; }
inline bool is_string(sexpr const & s) { return s.get_kind() == sexpr::kind::STRING; }
inline bool is_int(sexpr const & s) { return s.get_kind() == sexpr::kind::INT; }
inline bool is_double(sexpr const & s) { return s.get_kind() == sexpr::kind::DOUBLE; }
inline bool is_name(sexpr const & s) { return s.get_kind() == sexpr::kind::NAME; }
inline bool is_mpz(sexpr const & s) { return s.get_kind() == sexpr::kind::MPZ; }
inline bool is_mpq(sexpr const & s) { return s.get_kind() == sexpr::kind::MPQ; }
inline std::string const & to_string(sexpr const & s) { return s.get_string(); }
inline int to_int(sexpr const & s) { return s.get_int(); }
inline double to_double(sexpr const & s) { return s.get_double(); }
inline name const & to_name(sexpr const & s) { return s.get_name(); }
inline mpz const & to_mpz(sexpr const & s) { return s.get_mpz(); }
inline mpq const & to_mpq(sexpr const & s) { return s.get_mpq(); }
bool is_list(sexpr const & s);
unsigned length(sexpr const & s);
inline unsigned len(sexpr const & s) { return length(s); }
bool operator==(sexpr const & a, sexpr const & b);
bool operator<(sexpr const & a, sexpr const & b);
inline bool operator!=(sexpr const & a, sexpr const & b) { return !(a == b); }
inline bool operator>(sexpr const & a, sexpr const & b) { return b < a; }
inline bool operator<=(sexpr const & a, sexpr const & b) { return !(a > b); }
inline bool operator>=(sexpr const & a, sexpr const & b) { return !(a < b); }
}

View file

@ -0,0 +1,3 @@
add_executable(sexpr_tst sexpr.cpp)
target_link_libraries(sexpr_tst ${EXTRA_LIBS})
add_test(sexpr ${CMAKE_CURRENT_BINARY_DIR}/sexpr_tst)

57
src/tests/sexpr/sexpr.cpp Normal file
View file

@ -0,0 +1,57 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include "sexpr.h"
#include "mpq.h"
#include "name.h"
#include "test.h"
using namespace lean;
static void tst1() {
sexpr s1(30, nil());
sexpr s2("name", s1);
std::cout << s2 << "\n";
std::cout << sexpr(s2, s2) << "\n";
lean_assert(len(s2) == 2);
lean_assert(is_nil(nil()));
lean_assert(!is_nil(s2));
lean_assert(is_cons(s2));
lean_assert(is_cons(sexpr(s2, s2)));
lean_assert(is_list(s2));
lean_assert(is_cons(sexpr(s2, s2)));
lean_assert(is_list(sexpr(s2, s2)));
lean_assert(!is_list(sexpr(s2, sexpr(10))));
lean_assert(s2 == sexpr("name", sexpr(30, nil())));
lean_assert(s2 != sexpr("name", sexpr(11.2, nil())));
lean_assert(s2 != sexpr("name", sexpr(20, nil())));
lean_assert(s2 == sexpr("name", sexpr(30, nil())));
lean_assert(cdr(s2) == sexpr(30, nil()));
lean_assert(car(s2) == sexpr("name"));
std::cout << sexpr(name(name("foo"), 1), s2) << "\n";
lean_assert(to_mpq(sexpr(mpq("1/3"))) == mpq(1, 3));
lean_assert(to_int(sexpr(1)) == 1);
lean_assert(is_int(sexpr(1)));
lean_assert(!is_nil(sexpr(2)));
std::cout << sexpr(sexpr(10), sexpr(20)) << "\n";
std::cout << sexpr{10, 20, 30, 40} << "\n";
std::cout << sexpr{"foo", "bla", "tst"} << "\n";
std::cout << sexpr{10.20, 3.2, 4.3} << "\n";
std::cout << sexpr(10.2) << "\n";
std::cout << sexpr{10.2} << "\n";
lean_assert(!is_list(sexpr(10.2)));
lean_assert(is_list(sexpr{10.2}));
lean_assert(len(sexpr{10.2}) == 1);
// list of pairs
std::cout << sexpr{ sexpr(1,2), sexpr(2,3), sexpr(0,1) } << "\n";
// list of lists
std::cout << sexpr{ sexpr{1,2}, sexpr{2,3}, sexpr{0,1} } << "\n";
}
int main() {
continue_on_violation(true);
tst1();
return 0;
}

View file

@ -1 +1 @@
add_library(util trace.cpp debug.cpp name.cpp exception.cpp verbosity.cpp interrupt.cpp hash.cpp) add_library(util trace.cpp debug.cpp name.cpp exception.cpp verbosity.cpp interrupt.cpp hash.cpp escaped.cpp)

44
src/util/escaped.cpp Normal file
View file

@ -0,0 +1,44 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include "escaped.h"
namespace lean {
char const * escaped::end() const {
if (m_str == 0) return 0;
char const * it = m_str;
char const * e = m_str;
while (*it) {
if (!m_trim_nl || *it != '\n') {
++it;
e = it;
}
else {
++it;
}
}
return e;
}
std::ostream & operator<<(std::ostream & out, escaped const & s) {
char const * it = s.m_str;
char const * e = s.end();
for (; it != e; ++it) {
char c = *it;
if (c == '"') {
out << '\\';
}
out << c;
if (c == '\n') {
for (unsigned i = 0; i < s.m_indent; i++)
out << " ";
}
}
return out;
}
}

23
src/util/escaped.h Normal file
View file

@ -0,0 +1,23 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include <iostream>
namespace lean {
class escaped {
char const * m_str;
bool m_trim_nl; // if true -> eliminate '\n' in the end of m_str.
unsigned m_indent;
char const * end() const;
public:
escaped(char const * str, bool trim_nl = false, unsigned indent = 0):m_str(str), m_trim_nl(trim_nl), m_indent(indent) {}
friend std::ostream & operator<<(std::ostream & out, escaped const & s);
};
}