thrift/compiler/generate/t_mstch_objects.h (1,291 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <iomanip>
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
#include <thrift/compiler/detail/mustache/mstch.h>
#include <thrift/compiler/generate/t_generator.h>
namespace apache {
namespace thrift {
namespace compiler {
class mstch_base;
class mstch_generators;
enum ELEMENT_POSITION {
NONE = 0,
FIRST = 1,
LAST = 2,
FIRST_AND_LAST = 3,
};
struct mstch_cache {
std::map<std::string, std::string> parsed_options_;
std::unordered_map<std::string, std::shared_ptr<mstch_base>> enums_;
std::unordered_map<std::string, std::shared_ptr<mstch_base>> structs_;
std::unordered_map<std::string, std::shared_ptr<mstch_base>> services_;
std::unordered_map<std::string, std::shared_ptr<mstch_base>> programs_;
void clear() {
enums_.clear();
structs_.clear();
services_.clear();
programs_.clear();
}
};
class enum_value_generator {
public:
virtual ~enum_value_generator() = default;
virtual std::shared_ptr<mstch_base> generate(
t_enum_value const* enum_value,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0) const;
};
class enum_generator {
public:
virtual ~enum_generator() = default;
virtual std::shared_ptr<mstch_base> generate(
t_enum const* enm,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0) const;
};
class const_value_generator {
public:
const_value_generator() = default;
virtual ~const_value_generator() = default;
virtual std::shared_ptr<mstch_base> generate(
t_const_value const* const_value,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0,
t_const const* current_const = nullptr,
t_type const* expected_type = nullptr) const;
virtual std::shared_ptr<mstch_base> generate(
std::pair<t_const_value*, t_const_value*> const& value_pair,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0,
t_const const* current_const = nullptr,
std::pair<const t_type*, const t_type*> const& expected_types = {
nullptr, nullptr}) const;
};
class type_generator {
public:
type_generator() = default;
virtual ~type_generator() = default;
virtual std::shared_ptr<mstch_base> generate(
t_type const* type,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0) const;
};
struct field_generator_context {
const t_struct* strct = nullptr;
const t_field* serialization_prev = nullptr;
const t_field* serialization_next = nullptr;
int isset_index = -1;
};
class field_generator {
public:
field_generator() = default;
virtual ~field_generator() = default;
virtual std::shared_ptr<mstch_base> generate(
t_field const* field,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0,
field_generator_context const* field_context = nullptr) const;
};
class annotation_generator {
public:
annotation_generator() = default;
virtual ~annotation_generator() = default;
virtual std::shared_ptr<mstch_base> generate(
const t_annotation& annotation,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0) const;
};
class structured_annotation_generator {
public:
structured_annotation_generator() = default;
virtual ~structured_annotation_generator() = default;
virtual std::shared_ptr<mstch_base> generate(
const t_const* annotValue,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0) const;
};
class struct_generator {
public:
struct_generator() = default;
virtual ~struct_generator() = default;
virtual std::shared_ptr<mstch_base> generate(
t_struct const* strct,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0) const;
};
class function_generator {
public:
function_generator() = default;
virtual ~function_generator() = default;
virtual std::shared_ptr<mstch_base> generate(
t_function const* function,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0) const;
};
class service_generator {
public:
service_generator() = default;
virtual ~service_generator() = default;
virtual std::shared_ptr<mstch_base> generate(
t_service const* service,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0) const;
std::shared_ptr<mstch_base> generate_cached(
t_program const* program,
t_service const* service,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0) const {
std::string service_id = program->path() + service->get_name();
auto itr = cache->services_.find(service_id);
if (itr == cache->services_.end()) {
itr = cache->services_.emplace_hint(
itr, service_id, generate(service, generators, cache, pos, index));
}
return itr->second;
}
};
class typedef_generator {
public:
typedef_generator() = default;
virtual ~typedef_generator() = default;
virtual std::shared_ptr<mstch_base> generate(
t_typedef const* typedf,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0) const;
};
class const_generator {
public:
const_generator() = default;
virtual ~const_generator() = default;
virtual std::shared_ptr<mstch_base> generate(
t_const const* cnst,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0,
t_const const* current_const = nullptr,
t_type const* expected_type = nullptr,
t_field const* field = nullptr) const;
};
class program_generator {
public:
program_generator() = default;
virtual ~program_generator() = default;
virtual std::shared_ptr<mstch_base> generate(
t_program const* program,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0) const;
std::shared_ptr<mstch_base> generate_cached(
t_program const* program,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE,
int32_t index = 0) {
const auto& id = program->path();
auto itr = cache->programs_.find(id);
if (itr == cache->programs_.end()) {
itr = cache->programs_.emplace_hint(
itr, id, generate(program, generators, cache, pos, index));
}
return itr->second;
}
};
class mstch_generators {
public:
mstch_generators()
: enum_value_generator_(std::make_unique<enum_value_generator>()),
enum_generator_(std::make_unique<enum_generator>()),
const_value_generator_(std::make_unique<const_value_generator>()),
type_generator_(std::make_unique<type_generator>()),
field_generator_(std::make_unique<field_generator>()),
annotation_generator_(std::make_unique<annotation_generator>()),
structured_annotation_generator_(
std::make_unique<structured_annotation_generator>()),
struct_generator_(std::make_unique<struct_generator>()),
function_generator_(std::make_unique<function_generator>()),
service_generator_(std::make_unique<service_generator>()),
typedef_generator_(std::make_unique<typedef_generator>()),
const_generator_(std::make_unique<const_generator>()),
program_generator_(std::make_unique<program_generator>()) {}
~mstch_generators() = default;
void set_enum_value_generator(std::unique_ptr<enum_value_generator> g) {
enum_value_generator_ = std::move(g);
}
void set_enum_generator(std::unique_ptr<enum_generator> g) {
enum_generator_ = std::move(g);
}
void set_const_value_generator(std::unique_ptr<const_value_generator> g) {
const_value_generator_ = std::move(g);
}
void set_type_generator(std::unique_ptr<type_generator> g) {
type_generator_ = std::move(g);
}
void set_field_generator(std::unique_ptr<field_generator> g) {
field_generator_ = std::move(g);
}
void set_annotation_generator(std::unique_ptr<annotation_generator> g) {
annotation_generator_ = std::move(g);
}
void set_struct_generator(std::unique_ptr<struct_generator> g) {
struct_generator_ = std::move(g);
}
void set_function_generator(std::unique_ptr<function_generator> g) {
function_generator_ = std::move(g);
}
void set_service_generator(std::unique_ptr<service_generator> g) {
service_generator_ = std::move(g);
}
void set_typedef_generator(std::unique_ptr<typedef_generator> g) {
typedef_generator_ = std::move(g);
}
void set_const_generator(std::unique_ptr<const_generator> g) {
const_generator_ = std::move(g);
}
void set_program_generator(std::unique_ptr<program_generator> g) {
program_generator_ = std::move(g);
}
std::unique_ptr<enum_value_generator> enum_value_generator_;
std::unique_ptr<enum_generator> enum_generator_;
std::unique_ptr<const_value_generator> const_value_generator_;
std::unique_ptr<type_generator> type_generator_;
std::unique_ptr<field_generator> field_generator_;
std::unique_ptr<annotation_generator> annotation_generator_;
std::unique_ptr<structured_annotation_generator>
structured_annotation_generator_;
std::unique_ptr<struct_generator> struct_generator_;
std::unique_ptr<function_generator> function_generator_;
std::unique_ptr<service_generator> service_generator_;
std::unique_ptr<typedef_generator> typedef_generator_;
std::unique_ptr<const_generator> const_generator_;
std::unique_ptr<program_generator> program_generator_;
};
class mstch_base : public mstch::object {
protected:
// A range of t_field* to avoid copying between std::vector<t_field*>
// and std::vector<t_field const*>.
class field_range {
public:
/* implicit */ field_range(const std::vector<t_field*>& fields) noexcept
: begin_(const_cast<const t_field* const*>(fields.data())),
end_(const_cast<const t_field* const*>(
fields.data() + fields.size())) {}
/* implicit */ field_range(
const std::vector<t_field const*>& fields) noexcept
: begin_(fields.data()), end_(fields.data() + fields.size()) {}
constexpr size_t size() const noexcept { return end_ - begin_; }
constexpr const t_field* const* begin() const noexcept { return begin_; }
constexpr const t_field* const* end() const noexcept { return end_; }
private:
const t_field* const* begin_;
const t_field* const* end_;
};
public:
mstch_base(
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION const pos)
: generators_(generators), cache_(cache), pos_(pos) {
register_methods(
this,
{
{"first?", &mstch_base::first},
{"last?", &mstch_base::last},
});
}
virtual ~mstch_base() = default;
mstch::node first() {
return pos_ == ELEMENT_POSITION::FIRST ||
pos_ == ELEMENT_POSITION::FIRST_AND_LAST;
}
mstch::node last() {
return pos_ == ELEMENT_POSITION::LAST ||
pos_ == ELEMENT_POSITION::FIRST_AND_LAST;
}
mstch::node annotations(t_named const* annotated) {
return generate_annotations(annotated->annotations());
}
mstch::node structured_annotations(t_named const* annotated) {
return generate_elements(
annotated->structured_annotations(),
generators_->structured_annotation_generator_.get());
}
static ELEMENT_POSITION element_position(size_t index, size_t length) {
ELEMENT_POSITION pos = ELEMENT_POSITION::NONE;
if (index == 0) {
pos = ELEMENT_POSITION::FIRST;
}
if (index == length - 1) {
pos = ELEMENT_POSITION::LAST;
}
if (length == 1) {
pos = ELEMENT_POSITION::FIRST_AND_LAST;
}
return pos;
}
template <typename Container, typename Generator, typename... Args>
mstch::array generate_elements(
Container const& container,
Generator const* generator,
Args const&... args) {
mstch::array a;
size_t i = 0;
for (auto&& element : container) {
auto pos = element_position(i, container.size());
a.push_back(
generator->generate(element, generators_, cache_, pos, i, args...));
++i;
}
return a;
}
template <typename C, typename... Args>
mstch::array generate_services(C const& container, Args const&... args) {
return generate_elements(
container, generators_->service_generator_.get(), args...);
}
template <typename C, typename... Args>
mstch::array generate_annotations(C const& container, Args const&... args) {
return generate_elements(
container, generators_->annotation_generator_.get(), args...);
}
template <typename C, typename... Args>
mstch::array generate_enum_values(C const& container, Args const&... args) {
return generate_elements(
container, generators_->enum_value_generator_.get(), args...);
}
template <typename C, typename... Args>
mstch::array generate_consts(C const& container, Args const&... args) {
return generate_elements(
container, generators_->const_value_generator_.get(), args...);
}
virtual mstch::array generate_fields(const field_range& fields) {
return generate_elements(fields, generators_->field_generator_.get());
}
template <typename C, typename... Args>
mstch::array generate_functions(C const& container, Args const&... args) {
return generate_elements(
container, generators_->function_generator_.get(), args...);
}
template <typename C, typename... Args>
mstch::array generate_typedefs(C const& container, Args const&... args) {
return generate_elements(
container, generators_->typedef_generator_.get(), args...);
}
template <typename C, typename... Args>
mstch::array generate_types(C const& container, Args const&... args) {
return generate_elements(
container, generators_->type_generator_.get(), args...);
}
template <typename Item, typename Generator, typename Cache>
mstch::node generate_element_cached(
Item const& item,
Generator const* generator,
Cache& c,
std::string const& id,
size_t element_index,
size_t element_count) {
std::string elem_id = id + item->get_name();
auto pos = element_position(element_index, element_count);
auto itr = c.find(elem_id);
if (itr == c.end()) {
itr = c.emplace_hint(
itr,
elem_id,
generator->generate(item, generators_, cache_, pos, element_index));
}
return itr->second;
}
template <typename Container, typename Generator, typename Cache>
mstch::array generate_elements_cached(
Container const& container,
Generator const* generator,
Cache& c,
std::string const& id) {
mstch::array a;
for (size_t i = 0; i < container.size(); ++i) {
a.push_back(generate_element_cached(
container[i], generator, c, id, i, container.size()));
}
return a;
}
bool has_option(const std::string& option) const;
std::string get_option(const std::string& option) const;
// Registers has_option(option) under the given name.
void register_has_option(std::string key, std::string option);
protected:
std::shared_ptr<mstch_generators const> generators_;
std::shared_ptr<mstch_cache> cache_;
ELEMENT_POSITION const pos_;
};
class mstch_enum_value : public mstch_base {
public:
using node_type = t_enum_value;
mstch_enum_value(
t_enum_value const* enm_value,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos)
: mstch_base(generators, cache, pos), enm_value_(enm_value) {
register_methods(
this,
{
{"enum_value:name", &mstch_enum_value::name},
{"enum_value:value", &mstch_enum_value::value},
});
}
mstch::node name() { return enm_value_->get_name(); }
mstch::node value() { return std::to_string(enm_value_->get_value()); }
protected:
t_enum_value const* enm_value_;
};
class mstch_enum : public mstch_base {
public:
using node_type = t_enum;
mstch_enum(
t_enum const* enm,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos)
: mstch_base(generators, cache, pos), enm_(enm) {
register_methods(
this,
{
{"enum:name", &mstch_enum::name},
{"enum:values", &mstch_enum::values},
{"enum:structured_annotations",
&mstch_enum::structured_annotations},
});
}
mstch::node name() { return enm_->get_name(); }
mstch::node values();
mstch::node structured_annotations() {
return mstch_base::structured_annotations(enm_);
}
protected:
t_enum const* enm_;
};
class mstch_const_value : public mstch_base {
public:
using cv = t_const_value::t_const_value_type;
mstch_const_value(
t_const_value const* const_value,
t_const const* current_const,
t_type const* expected_type,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t index)
: mstch_base(generators, cache, pos),
const_value_(const_value),
current_const_(current_const),
expected_type_(expected_type),
type_(const_value->get_type()),
index_(index) {
register_methods(
this,
{
{"value:bool?", &mstch_const_value::is_bool},
{"value:double?", &mstch_const_value::is_double},
{"value:integer?", &mstch_const_value::is_integer},
{"value:enum?", &mstch_const_value::is_enum},
{"value:enum_value?", &mstch_const_value::has_enum_value},
{"value:string?", &mstch_const_value::is_string},
{"value:string_multi_line?",
&mstch_const_value::is_string_multi_line},
{"value:base?", &mstch_const_value::is_base},
{"value:map?", &mstch_const_value::is_map},
{"value:list?", &mstch_const_value::is_list},
{"value:container?", &mstch_const_value::is_container},
{"value:empty_container?", &mstch_const_value::is_empty_container},
{"value:value", &mstch_const_value::value},
{"value:integer_value", &mstch_const_value::integer_value},
{"value:double_value", &mstch_const_value::double_value},
{"value:bool_value", &mstch_const_value::bool_value},
{"value:nonzero?", &mstch_const_value::is_non_zero},
{"value:enum_name", &mstch_const_value::enum_name},
{"value:enum_value_name", &mstch_const_value::enum_value_name},
{"value:string_value", &mstch_const_value::string_value},
{"value:list_elements", &mstch_const_value::list_elems},
{"value:map_elements", &mstch_const_value::map_elems},
{"value:const_struct", &mstch_const_value::const_struct},
{"value:const_struct?", &mstch_const_value::is_const_struct},
{"value:const_struct_type", &mstch_const_value::const_struct_type},
{"value:referenceable?", &mstch_const_value::referenceable},
{"value:owning_const", &mstch_const_value::owning_const},
{"value:enable_referencing",
&mstch_const_value::enable_referencing},
});
}
std::string format_double_string(const double d) {
std::ostringstream oss;
oss << std::setprecision(std::numeric_limits<double>::digits10) << d;
return oss.str();
}
mstch::node is_bool() { return type_ == cv::CV_BOOL; }
mstch::node is_double() { return type_ == cv::CV_DOUBLE; }
mstch::node is_integer() {
return type_ == cv::CV_INTEGER && !const_value_->is_enum();
}
mstch::node is_enum() {
return type_ == cv::CV_INTEGER && const_value_->is_enum();
}
mstch::node has_enum_value() {
return const_value_->get_enum_value() != nullptr;
}
mstch::node is_string() { return type_ == cv::CV_STRING; }
mstch::node is_string_multi_line() {
return type_ == cv::CV_STRING &&
const_value_->get_string().find("\n") != std::string::npos;
}
mstch::node is_base() {
return type_ == cv::CV_BOOL || type_ == cv::CV_DOUBLE ||
type_ == cv::CV_INTEGER || type_ == cv::CV_STRING;
}
mstch::node is_map() { return type_ == cv::CV_MAP; }
mstch::node is_list() { return type_ == cv::CV_LIST; }
mstch::node is_container() {
return type_ == cv::CV_MAP || type_ == cv::CV_LIST;
}
mstch::node is_empty_container() {
return (type_ == cv::CV_MAP && const_value_->get_map().empty()) ||
(type_ == cv::CV_LIST && const_value_->get_list().empty());
}
mstch::node value();
mstch::node integer_value();
mstch::node double_value();
mstch::node bool_value();
mstch::node is_non_zero();
mstch::node enum_name();
mstch::node enum_value_name();
mstch::node string_value();
mstch::node list_elems();
mstch::node map_elems();
mstch::node const_struct();
mstch::node referenceable() {
return current_const_ && const_value_->get_owner() &&
current_const_ != const_value_->get_owner() && same_type_as_expected();
}
mstch::node owning_const();
mstch::node enable_referencing() {
return mstch::map{{"value:enable_referencing?", true}};
}
mstch::node is_const_struct();
mstch::node const_struct_type();
protected:
t_const_value const* const_value_;
t_const const* current_const_;
t_type const* expected_type_;
cv const type_;
int32_t index_;
virtual bool same_type_as_expected() const { return false; }
};
class mstch_const_value_key_mapped_pair : public mstch_base {
public:
mstch_const_value_key_mapped_pair(
std::pair<t_const_value*, t_const_value*> const& pair_values,
t_const const* current_const,
std::pair<const t_type*, const t_type*> const& expected_types,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t index)
: mstch_base(generators, cache, pos),
pair_(pair_values),
current_const_(current_const),
expected_types_(expected_types),
index_(index) {
register_methods(
this,
{
{"element:key", &mstch_const_value_key_mapped_pair::element_key},
{"element:value",
&mstch_const_value_key_mapped_pair::element_value},
});
}
mstch::node element_key();
mstch::node element_value();
protected:
std::pair<t_const_value*, t_const_value*> const pair_;
t_const const* current_const_;
std::pair<const t_type*, const t_type*> const expected_types_;
int32_t index_;
};
class mstch_type : public mstch_base {
public:
mstch_type(
t_type const* type,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos)
: mstch_base(generators, cache, pos),
type_(type),
resolved_type_(type->get_true_type()) {
register_methods(
this,
{
{"type:name", &mstch_type::name},
{"type:void?", &mstch_type::is_void},
{"type:string?", &mstch_type::is_string},
{"type:binary?", &mstch_type::is_binary},
{"type:bool?", &mstch_type::is_bool},
{"type:byte?", &mstch_type::is_byte},
{"type:i16?", &mstch_type::is_i16},
{"type:i32?", &mstch_type::is_i32},
{"type:i64?", &mstch_type::is_i64},
{"type:double?", &mstch_type::is_double},
{"type:float?", &mstch_type::is_float},
{"type:floating_point?", &mstch_type::is_floating_point},
{"type:struct?", &mstch_type::is_struct},
{"type:union?", &mstch_type::is_union},
{"type:enum?", &mstch_type::is_enum},
{"type:sink?", &mstch_type::is_sink},
{"type:sink_has_first_response?",
&mstch_type::sink_has_first_response},
{"type:stream_or_sink?", &mstch_type::is_stream_or_sink},
{"type:streamresponse?", &mstch_type::is_streamresponse},
{"type:stream_has_first_response?",
&mstch_type::stream_has_first_response},
{"type:service?", &mstch_type::is_service},
{"type:base?", &mstch_type::is_base},
{"type:container?", &mstch_type::is_container},
{"type:list?", &mstch_type::is_list},
{"type:set?", &mstch_type::is_set},
{"type:map?", &mstch_type::is_map},
{"type:typedef?", &mstch_type::is_typedef},
{"type:struct", &mstch_type::get_struct},
{"type:enum", &mstch_type::get_enum},
{"type:list_elem_type", &mstch_type::get_list_type},
{"type:set_elem_type", &mstch_type::get_set_type},
{"type:sink_elem_type", &mstch_type::get_sink_elem_type},
{"type:sink_final_response_type",
&mstch_type::get_sink_final_reponse_type},
{"type:sink_first_response_type",
&mstch_type::get_sink_first_response_type},
{"type:stream_elem_type", &mstch_type::get_stream_elem_type},
{"type:stream_first_response_type",
&mstch_type::get_stream_first_response_type},
{"type:key_type", &mstch_type::get_key_type},
{"type:value_type", &mstch_type::get_value_type},
{"type:typedef_type", &mstch_type::get_typedef_type},
{"type:typedef", &mstch_type::get_typedef},
{"type:interaction?", &mstch_type::is_interaction},
});
}
mstch::node name() { return type_->get_name(); }
mstch::node is_void() { return resolved_type_->is_void(); }
mstch::node is_string() { return resolved_type_->is_string(); }
mstch::node is_binary() { return resolved_type_->is_binary(); }
mstch::node is_bool() { return resolved_type_->is_bool(); }
mstch::node is_byte() { return resolved_type_->is_byte(); }
mstch::node is_i16() { return resolved_type_->is_i16(); }
mstch::node is_i32() { return resolved_type_->is_i32(); }
mstch::node is_i64() { return resolved_type_->is_i64(); }
mstch::node is_double() { return resolved_type_->is_double(); }
mstch::node is_float() { return resolved_type_->is_float(); }
mstch::node is_floating_point() {
return resolved_type_->is_floating_point();
}
mstch::node is_struct() {
return resolved_type_->is_struct() || resolved_type_->is_xception();
}
mstch::node is_union() { return resolved_type_->is_union(); }
mstch::node is_enum() { return resolved_type_->is_enum(); }
mstch::node is_sink() { return resolved_type_->is_sink(); }
mstch::node sink_has_first_response() {
return resolved_type_->is_sink() &&
dynamic_cast<const t_sink*>(resolved_type_)->sink_has_first_response();
}
mstch::node is_stream_or_sink() {
return resolved_type_->is_streamresponse() || resolved_type_->is_sink();
}
mstch::node is_streamresponse() {
return resolved_type_->is_streamresponse();
}
mstch::node stream_has_first_response() {
return resolved_type_->is_streamresponse() &&
dynamic_cast<const t_stream_response*>(resolved_type_)
->first_response_type() != boost::none;
}
mstch::node is_service() { return resolved_type_->is_service(); }
mstch::node is_base() { return resolved_type_->is_base_type(); }
mstch::node is_container() { return resolved_type_->is_container(); }
mstch::node is_list() { return resolved_type_->is_list(); }
mstch::node is_set() { return resolved_type_->is_set(); }
mstch::node is_map() { return resolved_type_->is_map(); }
mstch::node is_typedef() { return type_->is_typedef(); }
virtual std::string get_type_namespace(t_program const*) { return ""; }
mstch::node get_struct();
mstch::node get_enum();
mstch::node get_list_type();
mstch::node get_set_type();
mstch::node get_key_type();
mstch::node get_value_type();
mstch::node get_typedef_type();
mstch::node get_typedef();
mstch::node get_sink_first_response_type();
mstch::node get_sink_elem_type();
mstch::node get_sink_final_reponse_type();
mstch::node get_stream_elem_type();
mstch::node get_stream_first_response_type();
mstch::node is_interaction() { return type_->is_service(); }
protected:
t_type const* type_;
t_type const* resolved_type_;
};
class mstch_field : public mstch_base {
public:
mstch_field(
t_field const* field,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t index,
field_generator_context const* field_context)
: mstch_base(generators, cache, pos),
field_(field),
index_(index),
field_context_(field_context) {
register_methods(
this,
{
{"field:name", &mstch_field::name},
{"field:key", &mstch_field::key},
{"field:value", &mstch_field::value},
{"field:type", &mstch_field::type},
{"field:index", &mstch_field::index},
{"field:required?", &mstch_field::is_required},
{"field:optional?", &mstch_field::is_optional},
{"field:opt_in_req_out?", &mstch_field::is_optInReqOut},
{"field:annotations", &mstch_field::annotations},
{"field:structured_annotations",
&mstch_field::structured_annotations},
});
}
mstch::node name() { return field_->get_name(); }
mstch::node key() { return std::to_string(field_->get_key()); }
mstch::node value();
mstch::node type();
mstch::node index() { return std::to_string(index_); }
mstch::node is_required() {
return field_->get_req() == t_field::e_req::required;
}
mstch::node is_optional() {
return field_->get_req() == t_field::e_req::optional;
}
mstch::node is_optInReqOut() {
return field_->get_req() == t_field::e_req::opt_in_req_out;
}
mstch::node annotations() { return mstch_base::annotations(field_); }
mstch::node structured_annotations() {
return mstch_base::structured_annotations(field_);
}
protected:
t_field const* field_;
int32_t index_;
field_generator_context const* field_context_;
};
class mstch_annotation : public mstch_base {
public:
mstch_annotation(
const std::string& key,
const annotation_value& val,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t index)
: mstch_base(generators, cache, pos),
key_(key),
val_(val),
index_(index) {
register_methods(
this,
{
{"annotation:key", &mstch_annotation::key},
{"annotation:value", &mstch_annotation::value},
});
}
mstch::node key() { return key_; }
mstch::node value() { return val_.value; }
protected:
const std::string key_;
const annotation_value val_;
int32_t index_;
};
class mstch_structured_annotation : public mstch_base {
public:
mstch_structured_annotation(
const t_const& cnst,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t index)
: mstch_base(generators, cache, pos), cnst_(cnst), index_(index) {
register_methods(
this,
{{"structured_annotation:const",
&mstch_structured_annotation::constant},
{"structured_annotation:const_struct?",
&mstch_structured_annotation::is_const_struct}});
}
mstch::node constant() {
return generators_->const_generator_->generate(
&cnst_,
generators_,
cache_,
pos_,
index_,
&cnst_,
cnst_.type()->get_true_type());
}
mstch::node is_const_struct() {
return cnst_.type()->get_true_type()->is_struct();
}
protected:
const t_const& cnst_;
int32_t index_;
};
class mstch_struct : public mstch_base {
public:
mstch_struct(
t_struct const* strct,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos)
: mstch_base(generators, cache, pos), strct_(strct) {
register_methods(
this,
{
{"struct:name", &mstch_struct::name},
{"struct:fields?", &mstch_struct::has_fields},
{"struct:fields", &mstch_struct::fields},
{"struct:fields_in_serialization_order",
&mstch_struct::fields_in_serialization_order},
{"struct:exception?", &mstch_struct::is_exception},
{"struct:union?", &mstch_struct::is_union},
{"struct:plain?", &mstch_struct::is_plain},
{"struct:annotations", &mstch_struct::annotations},
{"struct:thrift_uri", &mstch_struct::thrift_uri},
{"struct:structured_annotations",
&mstch_struct::structured_annotations},
{"struct:exception_kind", &mstch_struct::exception_kind},
{"struct:exception_safety", &mstch_struct::exception_safety},
{"struct:exception_blame", &mstch_struct::exception_blame},
});
// Populate field_context_generator for each field.
auto ctx = field_generator_context{};
ctx.strct = strct_;
for (const t_field& field : strct->fields()) {
if (cpp2::field_has_isset(&field)) {
ctx.isset_index++;
}
context_map[&field] = ctx;
}
const t_field* prev = nullptr;
for (const t_field* curr : get_members_in_serialization_order()) {
if (prev) {
context_map[prev].serialization_next = curr;
context_map[curr].serialization_prev = prev;
}
prev = curr;
}
}
mstch::node name() { return strct_->get_name(); }
mstch::node has_fields() { return strct_->has_fields(); }
mstch::node fields();
mstch::node is_exception() { return strct_->is_xception(); }
mstch::node is_union() { return strct_->is_union(); }
mstch::node is_plain() {
return !strct_->is_xception() && !strct_->is_union();
}
mstch::node annotations() { return mstch_base::annotations(strct_); }
mstch::node structured_annotations() {
return mstch_base::structured_annotations(strct_);
}
mstch::node thrift_uri() { return strct_->uri(); }
mstch::node exception_safety();
mstch::node exception_blame();
mstch::node exception_kind();
mstch::array generate_fields(const field_range& fields) override {
mstch::array a;
size_t i = 0;
for (const auto* field : fields) {
auto pos = element_position(i, fields.size());
a.push_back(generators_->field_generator_.get()->generate(
field, generators_, cache_, pos, i, &context_map[field]));
++i;
}
return a;
}
// Returns the struct members ordered by the key.
const std::vector<const t_field*>& get_members_in_key_order();
field_range get_members_in_serialization_order() {
if (strct_->find_structured_annotation_or_null(
"facebook.com/thrift/annotation/thrift/SerializeInFieldIdOrder")) {
return get_members_in_key_order();
}
return strct_->get_members();
}
mstch::node fields_in_serialization_order() {
return generate_fields(get_members_in_serialization_order());
}
protected:
t_struct const* strct_;
// Although mstch_fields can be generated from different orders than the IDL
// order, field_generator_context should be always computed in the IDL order,
// as the context does not change by reordering. Without the map, each
// different reordering recomputes field_generator_context, and each
// field takes O(N) to loop through node_list_view<t_field> or
// std::vector<t_field*> to find the exact t_field to compute
// field_generator_context.
std::unordered_map<t_field const*, field_generator_context> context_map;
std::vector<const t_field*> fields_in_key_order_;
};
class mstch_function : public mstch_base {
public:
mstch_function(
t_function const* function,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos)
: mstch_base(generators, cache, pos), function_(function) {
register_methods(
this,
{
{"function:name", &mstch_function::name},
{"function:oneway?", &mstch_function::oneway},
{"function:return_type", &mstch_function::return_type},
{"function:exceptions", &mstch_function::exceptions},
{"function:stream_exceptions", &mstch_function::stream_exceptions},
{"function:sink_exceptions", &mstch_function::sink_exceptions},
{"function:sink_final_response_exceptions",
&mstch_function::sink_final_response_exceptions},
{"function:exceptions?", &mstch_function::has_exceptions},
{"function:stream_exceptions?",
&mstch_function::has_streamexceptions},
{"function:sink_exceptions?", &mstch_function::has_sinkexceptions},
{"function:sink_final_response_exceptions?",
&mstch_function::has_sink_final_response_exceptions},
{"function:args", &mstch_function::arg_list},
{"function:comma", &mstch_function::has_args},
{"function:priority", &mstch_function::priority},
{"function:returns_sink?", &mstch_function::returns_sink},
{"function:returns_streams?", &mstch_function::returns_stream},
{"function:returns_stream?", &mstch_function::returns_stream},
{"function:stream_has_first_response?",
&mstch_function::stream_has_first_response},
{"function:annotations", &mstch_function::annotations},
{"function:starts_interaction?",
&mstch_function::starts_interaction},
{"function:structured_annotations",
&mstch_function::structured_annotations},
{"function:qualifier", &mstch_function::qualifier},
});
}
mstch::node name() { return function_->get_name(); }
mstch::node oneway() {
return function_->qualifier() == t_function_qualifier::one_way;
}
mstch::node has_exceptions() {
return function_->get_xceptions()->has_fields();
}
mstch::node has_streamexceptions() {
return function_->get_stream_xceptions()->has_fields();
}
mstch::node has_sinkexceptions() {
return function_->get_sink_xceptions()->has_fields();
}
mstch::node has_sink_final_response_exceptions() {
return function_->get_sink_final_response_xceptions()->has_fields();
}
mstch::node stream_has_first_response() {
const auto& rettype = *function_->return_type();
auto stream = dynamic_cast<const t_stream_response*>(&rettype);
return stream && stream->first_response_type() != boost::none;
}
mstch::node has_args() {
if (function_->get_paramlist()->has_fields()) {
return std::string(", ");
}
return std::string();
}
mstch::node priority() {
return function_->get_annotation("priority", "NORMAL");
}
mstch::node returns_sink() { return function_->returns_sink(); }
mstch::node annotations() { return mstch_base::annotations(function_); }
mstch::node return_type();
mstch::node exceptions();
mstch::node stream_exceptions();
mstch::node sink_exceptions();
mstch::node sink_final_response_exceptions();
mstch::node arg_list();
mstch::node returns_stream();
mstch::node starts_interaction() {
return function_->get_returntype()->is_service();
}
mstch::node structured_annotations() {
return mstch_base::structured_annotations(function_);
}
mstch::node qualifier() {
auto q = function_->qualifier();
switch (q) {
case t_function_qualifier::one_way:
return std::string("OneWay");
case t_function_qualifier::idempotent:
return std::string("Idempotent");
case t_function_qualifier::read_only:
return std::string("ReadOnly");
default:
return std::string("Unspecified");
}
}
protected:
t_function const* function_;
};
class mstch_service : public mstch_base {
public:
mstch_service(
t_service const* service,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos)
: mstch_base(generators, cache, pos), service_(service) {
register_methods(
this,
{
{"service:name", &mstch_service::name},
{"service:functions", &mstch_service::functions},
{"service:functions?", &mstch_service::has_functions},
{"service:extends", &mstch_service::extends},
{"service:extends?", &mstch_service::has_extends},
{"service:streams?", &mstch_service::has_streams},
{"service:sinks?", &mstch_service::has_sinks},
{"service:annotations", &mstch_service::annotations},
{"service:thrift_uri", &mstch_service::thrift_uri},
{"service:parent", &mstch_service::parent},
{"service:interaction?", &mstch_service::is_interaction},
{"service:interactions", &mstch_service::interactions},
{"service:interactions?", &mstch_service::has_interactions},
{"service:structured_annotations",
&mstch_service::structured_annotations},
{"interaction:serial?", &mstch_service::is_serial_interaction},
{"interaction:eb?", &mstch_service::is_event_base_interaction},
});
// Collect performed interactions and cache them
for (auto const* function : get_functions()) {
if (function->get_returntype()->is_service()) {
interactions_.insert(
dynamic_cast<t_interaction const*>(function->get_returntype()));
} else if (auto interaction = function->returned_interaction()) {
interactions_.insert(dynamic_cast<t_interaction const*>(
(*interaction)->get_true_type()));
}
}
assert(interactions_.count(nullptr) == 0);
}
virtual std::string get_service_namespace(t_program const*) { return {}; }
mstch::node name() { return service_->get_name(); }
mstch::node has_functions() { return !get_functions().empty(); }
mstch::node has_extends() { return service_->get_extends() != nullptr; }
mstch::node functions();
mstch::node extends();
mstch::node annotations() { return mstch_base::annotations(service_); }
mstch::node thrift_uri() { return service_->uri(); }
mstch::node parent() {
return cache_->parsed_options_["parent_service_name"];
}
mstch::node has_streams() {
auto& funcs = get_functions();
return std::any_of(funcs.cbegin(), funcs.cend(), [](auto const& func) {
return func->returns_stream();
});
}
mstch::node has_sinks() {
auto& funcs = get_functions();
return std::any_of(funcs.cbegin(), funcs.cend(), [](auto const& func) {
return func->returns_sink();
});
}
mstch::node has_interactions() { return !interactions_.empty(); }
mstch::node interactions() {
if (!service_->is_interaction()) {
cache_->parsed_options_["parent_service_name"] = service_->get_name();
cache_->parsed_options_["parent_service_cpp_name"] =
cpp2::get_name(service_);
}
return generate_services(interactions_);
}
mstch::node structured_annotations() {
return mstch_base::structured_annotations(service_);
}
mstch::node is_interaction() { return service_->is_interaction(); }
mstch::node is_serial_interaction() {
return service_->is_serial_interaction();
}
mstch::node is_event_base_interaction() {
return service_->has_annotation("process_in_event_base");
}
virtual ~mstch_service() = default;
protected:
t_service const* service_;
std::set<t_interaction const*> interactions_;
mstch::node generate_cached_extended_service(const t_service* service);
virtual const std::vector<t_function*>& get_functions() const {
return service_->get_functions();
}
};
class mstch_typedef : public mstch_base {
public:
mstch_typedef(
t_typedef const* typedf,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos)
: mstch_base(generators, cache, pos), typedf_(typedf) {
register_methods(
this,
{
{"typedef:type", &mstch_typedef::type},
{"typedef:is_same_type", &mstch_typedef::is_same_type},
{"typedef:name", &mstch_typedef::name},
{"typedef:structured_annotations",
&mstch_typedef::structured_annotations},
});
}
mstch::node type();
mstch::node name() { return typedf_->name(); }
mstch::node is_same_type() {
return typedf_->get_name() == typedf_->get_type()->get_name();
}
mstch::node structured_annotations() {
return mstch_base::structured_annotations(typedf_);
}
protected:
t_typedef const* typedf_;
};
class mstch_const : public mstch_base {
public:
mstch_const(
t_const const* cnst,
t_const const* current_const,
t_type const* expected_type,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t index,
t_field const* field)
: mstch_base(generators, cache, pos),
cnst_(cnst),
current_const_(current_const),
expected_type_(expected_type),
index_(index),
field_(field) {
register_methods(
this,
{
{"constant:name", &mstch_const::name},
{"constant:index", &mstch_const::index},
{"constant:type", &mstch_const::type},
{"constant:value", &mstch_const::value},
{"constant:program", &mstch_const::program},
});
}
mstch::node name() { return cnst_->get_name(); }
mstch::node index() { return index_; }
mstch::node type();
mstch::node value();
mstch::node program();
protected:
t_const const* cnst_;
t_const const* current_const_;
t_type const* expected_type_;
int32_t index_;
t_field const* field_;
};
class mstch_program : public mstch_base {
public:
mstch_program(
t_program const* program,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos)
: mstch_base(generators, cache, pos), program_(program) {
register_methods(
this,
{
{"program:name", &mstch_program::name},
{"program:path", &mstch_program::path},
{"program:includePrefix", &mstch_program::include_prefix},
{"program:structs", &mstch_program::structs},
{"program:enums", &mstch_program::enums},
{"program:services", &mstch_program::services},
{"program:typedefs", &mstch_program::typedefs},
{"program:constants", &mstch_program::constants},
{"program:enums?", &mstch_program::has_enums},
{"program:structs?", &mstch_program::has_structs},
{"program:unions?", &mstch_program::has_unions},
{"program:services?", &mstch_program::has_services},
{"program:typedefs?", &mstch_program::has_typedefs},
{"program:constants?", &mstch_program::has_constants},
{"program:thrift_uris?", &mstch_program::has_thrift_uris},
});
register_has_option("program:frozen?", "frozen");
register_has_option("program:json?", "json");
register_has_option("program:nimble?", "nimble");
register_has_option("program:any?", "any");
register_has_option(
"program:unstructured_annotations_in_metadata?",
"deprecated_unstructured_annotations_in_metadata");
}
virtual std::string get_program_namespace(t_program const*) { return {}; }
mstch::node name() { return program_->name(); }
mstch::node path() { return program_->path(); }
mstch::node include_prefix() { return program_->include_prefix(); }
mstch::node has_enums() { return !program_->enums().empty(); }
mstch::node has_structs() {
return !program_->structs().empty() || !program_->xceptions().empty();
}
mstch::node has_services() { return !program_->services().empty(); }
mstch::node has_typedefs() { return !program_->typedefs().empty(); }
mstch::node has_constants() { return !program_->consts().empty(); }
mstch::node has_unions() {
auto& structs = program_->structs();
return std::any_of(
structs.cbegin(), structs.cend(), std::mem_fn(&t_struct::is_union));
}
mstch::node has_thrift_uris();
mstch::node structs();
mstch::node enums();
mstch::node services();
mstch::node typedefs();
mstch::node constants();
protected:
t_program const* program_;
virtual const std::vector<t_struct*>& get_program_objects();
virtual const std::vector<t_enum*>& get_program_enums();
};
} // namespace compiler
} // namespace thrift
} // namespace apache