Pretty Good Sum Type  1.0.0
sexpr.t.cpp

Rough draft of a type for S-expressions

#include <pgs/pgs.hpp>
#include <gtest/gtest.h>
#include <string>
#include <iostream>
#include <list>
#include <algorithm>
#include <iterator>
#include <sstream>
namespace {
using namespace pgs;
struct atom_unit
{};
struct atom_bool {
bool val;
explicit atom_bool (bool val) : val {val}
{}
};
struct atom_int {
int val;
explicit atom_int (int val) : val {val}
{}
};
struct atom_float {
double val;
explicit atom_float (double val) : val {val}
{}
};
struct atom_string {
template <class S>
explicit atom_string (S&& val) : val {std::forward<S> (val)}
{}
};
using atom = sum_type<
atom_unit
, atom_bool
, atom_int
, atom_float
, atom_string
>;
std::string string_of_atom (atom const& a) {
return a.match<std::string>(
[](atom_unit const&) -> std::string { return "#u"; }
, [](atom_bool const& b) -> std::string { return b.val ? "#t" : "#f"; }
, [](atom_int const& i) -> std::string { return std::to_string (i.val); }
, [](atom_float const& f) -> std::string { return std::to_string (f.val); }
, [](atom_string const& s) -> std::string { return s.val; }
);
}
struct expr_atom {
atom val;
template <class A>
explicit expr_atom (A&& val) : val {std::forward<A> (val)}
{}
};
struct expr_list;
using expr = sum_type<
expr_atom
>;
struct expr_list {
template <class L>
explicit expr_list (L&& l) : val { std::forward<L> (l)}
{}
};
std::string string_of_expr (expr const& e) {
return e.match<std::string>(
[](expr_atom const& a) -> std::string { return string_of_atom (a.val); }
, [](expr_list const& l) -> std::string {
std::list<expr> const& exprs = l.val;
os << "(";
while (begin != end) {
if (begin != l.val.begin ())
os << " ";
os << string_of_expr (*begin);
++begin;
}
os << ")";
return os.str ();
}
);
}
struct sexpr {
private:
expr impl_;//implementation
public:
//Ctors
//Default constructor
sexpr ()
{}
//Construct from `bool`
explicit sexpr (bool b)
{}
//Construct from `int`
explicit sexpr (int i)
{}
//Construct from `double`
explicit sexpr (double d)
{}
//Construct from `char const*`
explicit sexpr (char const* s)
: sexpr{std::string{s}}
{}
//Construct from `std::string` (r-value ref)
explicit sexpr (std::string const& s)
{}
//Construct from `std::string` (r-value ref)
explicit sexpr (std::string&& s)
{}
//Construct from a `std::list<sexpr>`
explicit sexpr (std::list<sexpr> const& l)
: impl_{constructor<expr_list>{}, expr_list{std::list<expr>{}}}
{
l.begin (), l.end (), std::back_inserter (exprs)
, [](sexpr const& s) -> expr const& { return s.impl_; });
impl_ = expr{constructor<expr_list>{}, expr_list{std::move (exprs)}};
}
//Predicates
//Test for unit
bool is_unit () const {
return impl_.match<bool>(
[](expr_atom const& e) {
return e.val.match<bool>(
[](atom_unit const&) -> bool { return true; },
[](otherwise) -> bool { return false; }
); },
[](otherwise) -> bool { return false; }
);
}
//Test for bool
bool is_bool () const {
return impl_.match<bool>(
[](expr_atom const& e) {
return e.val.match<bool>(
[](atom_bool const&) -> bool { return true; },
[](otherwise) -> bool { return false; }
); },
[](otherwise) -> bool { return false; }
);
}
//Test for int
bool is_int () const {
return impl_.match<bool>(
[](expr_atom const& e) { return e.val.is<atom_int> (); },
[](otherwise) -> bool { return false; }
);
}
//Test for float
bool is_float () const {
return impl_.match<bool>(
[](expr_atom const& e) { return e.val.is<atom_float> (); },
[](otherwise) -> bool { return false; }
);
}
//Test for string
bool is_string () const {
return impl_.match<bool>(
[](expr_atom const& e) { return e.val.is<atom_string> (); },
[](otherwise) -> bool { return false; }
);
}
//Test for list
bool is_list () const {
return impl_.match<bool>(
[](expr_list const& e) { return true; },
[](otherwise) -> bool { return false; }
);
}
//Accessors
//This can't fail
expr const& get_expr () const {
return impl_;
}
//Attempt to get a `const` reference to the atom this s-expression
//represents. Throws a `pgs::invalid_sum_type_access` exception if
//the expression is not an atom
expr_atom const& get_atom () const {
return pgs::get<expr_atom> (impl_);
}
//Attempt to get a `const` reference to the list of expressions
//that this s-expression represents. Throw `std::runtime_error` if
//it's not a list
expr_list const& get_list () const {
return pgs::get<expr_list> (impl_);
}
//Conversions
//Obtain a string representation
std::string to_string () const { return string_of_expr (impl_); }
};
}//namespace<anonymous>
TEST (pgs, sexpr) {
using sexpr_list=std::list<sexpr>;
sexpr s_unit;
sexpr s_bool{true};
sexpr s_int{1};
sexpr s_float{1.0};
sexpr s_string{std::string{"McCarthy"}};
sexpr s_list{sexpr_list{s_unit, s_int, s_float, s_string}};
ASSERT_TRUE (s_bool.is_bool ());
ASSERT_FALSE (s_int.is_bool ());
sexpr xpr{sexpr_list{
sexpr{"+"}, sexpr{5}, sexpr{sexpr_list{sexpr{"+"}, sexpr{3}, sexpr{5}}}}
};
ASSERT_EQ (xpr.to_string (), std::string{"(+ 5 (+ 3 5))"});
}