#include #include #include "term.h" #include "json_p.h" namespace RethinkDB { using TT = Protocol::Term::TermType; struct { Datum operator() (const Array& array) { Array copy; copy.reserve(array.size()); for (const auto& it : array) { copy.emplace_back(it.apply(*this)); } return Datum(Array{TT::MAKE_ARRAY, std::move(copy)}); } Datum operator() (const Object& object) { Object copy; for (const auto& it : object) { copy.emplace(it.first, it.second.apply(*this)); } return std::move(copy); } template Datum operator() (T&& atomic) { return Datum(std::forward(atomic)); } } datum_to_term; Term::Term(Datum&& datum_) : datum(datum_.apply(datum_to_term)) { } Term::Term(const Datum& datum_) : datum(datum_.apply(datum_to_term)) { } Term::Term(Term&& orig, OptArgs&& new_optargs) : datum(Nil()) { Datum* cur = orig.datum.get_nth(2); Object optargs; free_vars = std::move(orig.free_vars); if (cur) { optargs = std::move(cur->extract_object()); } for (auto& it : new_optargs) { optargs.emplace(std::move(it.first), alpha_rename(std::move(it.second))); } datum = Array{ std::move(orig.datum.extract_nth(0)), std::move(orig.datum.extract_nth(1)), std::move(optargs) }; } Term nil() { return Term(Nil()); } Cursor Term::run(Connection& conn, OptArgs&& opts) { if (!free_vars.empty()) { throw Error("run: term has free variables"); } return conn.start_query(this, std::move(opts)); } struct { Datum operator() (Object&& object, const std::map& subst, bool) { Object ret; for (auto& it : object) { ret.emplace(std::move(it.first), std::move(it.second).apply(*this, subst, false)); } return ret; } Datum operator() (Array&& array, const std::map& subst, bool args) { if (!args) { double cmd = array[0].extract_number(); if (cmd == static_cast(TT::VAR)) { double var = array[1].extract_nth(0).extract_number(); auto it = subst.find(static_cast(var)); if (it != subst.end()) { return Array{ TT::VAR, { it->second }}; } } if (array.size() == 2) { return Array{ std::move(array[0]), std::move(array[1]).apply(*this, subst, true) }; } else { return Array{ std::move(array[0]), std::move(array[1]).apply(*this, subst, true), std::move(array[2]).apply(*this, subst, false) }; } } else { Array ret; for (auto& it : array) { ret.emplace_back(std::move(it).apply(*this, subst, false)); } return ret; } } template Datum operator() (T&& a, const std::map&, bool) { return std::move(a); } } alpha_renamer; static int new_var_id(const std::map& vars) { while (true) { int id = gen_var_id(); if (vars.find(id) == vars.end()) { return id; } } } Datum Term::alpha_rename(Term&& term) { if (free_vars.empty()) { free_vars = std::move(term.free_vars); return std::move(term.datum); } std::map subst; for (auto it = term.free_vars.begin(); it != term.free_vars.end(); ++it) { auto var = free_vars.find(it->first); if (var == free_vars.end()) { free_vars.emplace(it->first, it->second); } else if (var->second != it->second) { int id = new_var_id(free_vars); subst.emplace(it->first, id); free_vars.emplace(id, it->second); } } if (subst.empty()) { return std::move(term.datum); } else { return term.datum.apply(alpha_renamer, subst, false); } } int gen_var_id() { return ::random() % (1<<30); } C0_IMPL(db_list, DB_LIST) C0_IMPL(table_list, TABLE_LIST) C0_IMPL(random, RANDOM) C0_IMPL(now, NOW) C0_IMPL(range, RANGE) C0_IMPL(error, ERROR) C0_IMPL(uuid, UUID) C0_IMPL(literal, LITERAL) CO0_IMPL(wait, WAIT) C0_IMPL(rebalance, REBALANCE) CO0_IMPL(random, RANDOM) Term row(TT::IMPLICIT_VAR, {}); Term minval(TT::MINVAL, {}); Term maxval(TT::MAXVAL, {}); Term binary(const std::string& data) { return expr(Binary(data)); } Term binary(std::string&& data) { return expr(Binary(data)); } Term binary(const char* data) { return expr(Binary(data)); } struct { bool operator() (const Object& object) { for (const auto& it : object) { if (it.second.apply(*this)) { return true; } } return false; } bool operator() (const Array& array) { int type = *array[0].get_number(); if (type == static_cast(TT::IMPLICIT_VAR)) { return true; } if (type == static_cast(TT::FUNC)) { return false; } for (const auto& it : *array[1].get_array()) { if (it.apply(*this)) { return true; } } if (array.size() == 3) { return array[2].apply(*this); } else { return false; } } template bool operator() (T) { return false; } } needs_func_wrap; Term Term::func_wrap(Term&& term) { if (term.datum.apply(needs_func_wrap)) { return Term(TT::FUNC, {expr(Array{new_var_id(term.free_vars)}), std::move(term)}); } return term; } Term Term::func_wrap(const Term& term) { if (term.datum.apply(needs_func_wrap)) { // TODO return Term(TT::FUNC, {expr(Array{new_var_id(Term.free_vars)}), Term.copy()}); return Term(Nil()); } return term; } Term Term::make_object(std::vector&& args) { if (args.size() % 2 != 0) { return Term(TT::OBJECT, std::move(args)); } std::set keys; for (auto it = args.begin(); it != args.end() && it + 1 != args.end(); it += 2) { std::string* key = it->datum.get_string(); if (!key || keys.count(*key)) { return Term(TT::OBJECT, std::move(args)); } keys.insert(*key); } Term ret{Nil()}; Object object; for (auto it = args.begin(); it != args.end(); it += 2) { std::string* key = it->datum.get_string(); object.emplace(std::move(*key), ret.alpha_rename(std::move(*(it + 1)))); } ret.datum = std::move(object); return ret; } Term Term::make_binary(Term&& term) { std::string* string = term.datum.get_string(); if (string) { return expr(Binary(std::move(*string))); } return Term(TT::BINARY, std::vector{term}); } Term::Term(OptArgs&& optargs) : datum(Nil()) { Object oargs; for (auto& it : optargs) { oargs.emplace(it.first, alpha_rename(std::move(it.second))); } datum = std::move(oargs); } OptArgs optargs() { return OptArgs{}; } Term january(TT::JANUARY, {}); Term february(TT::FEBRUARY, {}); Term march(TT::MARCH, {}); Term april(TT::APRIL, {}); Term may(TT::MAY, {}); Term june(TT::JUNE, {}); Term july(TT::JULY, {}); Term august(TT::AUGUST, {}); Term september(TT::SEPTEMBER, {}); Term october(TT::OCTOBER, {}); Term november(TT::NOVEMBER, {}); Term december(TT::DECEMBER, {}); Term monday(TT::MONDAY, {}); Term tuesday(TT::TUESDAY, {}); Term wednesday(TT::WEDNESDAY, {}); Term thursday(TT::THURSDAY, {}); Term friday(TT::FRIDAY, {}); Term saturday(TT::SATURDAY, {}); Term sunday(TT::SUNDAY, {}); Term Term::copy() const { return *this; } Datum Term::get_datum() const { return datum; } }