2018-12-31 20:04:05 +01:00
|
|
|
//
|
2018-01-02 14:42:31 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
//
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "td/tl/tl_writer.h"
|
|
|
|
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <sstream>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace td {
|
|
|
|
|
|
|
|
class TlWriterCCommon : public tl::TL_writer {
|
|
|
|
public:
|
|
|
|
int is_header_;
|
|
|
|
std::string prefix_;
|
|
|
|
TlWriterCCommon(const std::string &name, int is_header, const std::string &prefix = "")
|
|
|
|
: TL_writer(name), is_header_(is_header), prefix_(prefix) {
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_max_arity() const override {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_built_in_simple_type(const std::string &name) const override {
|
|
|
|
return name == "Bool" || name == "Int32" || name == "Int53" || name == "Int64" || name == "Double" ||
|
|
|
|
name == "String" || name == "Bytes";
|
|
|
|
}
|
|
|
|
bool is_built_in_complex_type(const std::string &name) const override {
|
|
|
|
return name == "Vector";
|
|
|
|
}
|
|
|
|
bool is_type_bare(const tl::tl_type *t) const override {
|
|
|
|
return t->simple_constructors <= 1 || (is_built_in_simple_type(t->name) && t->name != "Bool") ||
|
|
|
|
is_built_in_complex_type(t->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> get_parsers() const override {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
int get_parser_type(const tl::tl_combinator *t, const std::string &name) const override {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
std::vector<std::string> get_storers() const override {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
std::vector<std::string> get_additional_functions() const override {
|
|
|
|
return {"TdConvertToInternal", "TdConvertFromInternal", "TdSerialize", "TdToString",
|
|
|
|
"TdDestroyObject", "TdStackStorer", "TdStackFetcher", "enum"};
|
|
|
|
}
|
|
|
|
int get_storer_type(const tl::tl_combinator *t, const std::string &name) const override {
|
|
|
|
return name == "to_string" || name == "to_cpp_string";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_base_tl_class_name() const override {
|
|
|
|
return "Object";
|
|
|
|
}
|
|
|
|
std::string gen_base_type_class_name(int arity) const override {
|
|
|
|
assert(arity == 0);
|
|
|
|
return "Object";
|
|
|
|
}
|
|
|
|
std::string gen_base_function_class_name() const override {
|
|
|
|
return "Function";
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string to_camelCase(const std::string &name) {
|
|
|
|
return to_cCamelCase(name, false);
|
|
|
|
}
|
|
|
|
static std::string to_CamelCase(const std::string &name) {
|
|
|
|
return to_cCamelCase(name, true);
|
|
|
|
}
|
|
|
|
static std::string to_cCamelCase(const std::string &name, bool flag) {
|
|
|
|
bool next_to_upper = flag;
|
|
|
|
std::string result;
|
|
|
|
for (std::size_t i = 0; i < name.size(); i++) {
|
|
|
|
if (!is_alnum(name[i])) {
|
|
|
|
next_to_upper = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (next_to_upper) {
|
|
|
|
result += to_upper(name[i]);
|
|
|
|
next_to_upper = false;
|
|
|
|
} else {
|
|
|
|
result += name[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_native_field_name(std::string name) const {
|
|
|
|
for (std::size_t i = 0; i < name.size(); i++) {
|
|
|
|
if (!is_alnum(name[i])) {
|
|
|
|
name[i] = '_';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(name.size() > 0);
|
|
|
|
assert(name[name.size() - 1] != '_');
|
|
|
|
return name + "_";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_native_class_name(std::string name) const {
|
|
|
|
if (name == "Object") {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
if (name == "#") {
|
|
|
|
return "int";
|
|
|
|
}
|
|
|
|
for (std::size_t i = 0; i < name.size(); i++) {
|
|
|
|
if (!is_alnum(name[i])) {
|
|
|
|
name[i] = '_';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_class_name(std::string name) const override {
|
|
|
|
if (name == "Object" || name == "#") {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
return to_CamelCase(name);
|
|
|
|
}
|
|
|
|
std::string gen_field_name(std::string name) const override {
|
|
|
|
return gen_native_field_name(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_native_type_name(const tl::tl_tree_type *tree_type, bool storage) const {
|
|
|
|
const tl::tl_type *t = tree_type->type;
|
|
|
|
const std::string &name = t->name;
|
|
|
|
|
|
|
|
if (name == "#") {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
if (name == "Bool") {
|
|
|
|
return "bool";
|
|
|
|
}
|
|
|
|
if (name == "Int32") {
|
|
|
|
return "std::int32_t";
|
|
|
|
}
|
|
|
|
if (name == "Int53" || name == "Int64") {
|
|
|
|
return "std::int64_t";
|
|
|
|
}
|
|
|
|
if (name == "Double") {
|
|
|
|
return "double";
|
|
|
|
}
|
|
|
|
if (name == "String") {
|
|
|
|
return "std::string";
|
|
|
|
}
|
|
|
|
if (name == "Bytes") {
|
|
|
|
return "std::string";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name == "Vector") {
|
|
|
|
assert(t->arity == 1);
|
|
|
|
assert(tree_type->children.size() == 1);
|
|
|
|
assert(tree_type->children[0]->get_type() == tl::NODE_TYPE_TYPE);
|
|
|
|
const tl::tl_tree_type *child = static_cast<const tl::tl_tree_type *>(tree_type->children[0]);
|
|
|
|
|
|
|
|
return "std::vector<" + gen_native_type_name(child, storage) + ">";
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!is_built_in_simple_type(name) && !is_built_in_complex_type(name));
|
|
|
|
|
|
|
|
for (std::size_t i = 0; i < tree_type->children.size(); i++) {
|
|
|
|
assert(tree_type->children[i]->get_type() == tl::NODE_TYPE_NAT_CONST);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string native_class_name = gen_native_class_name(t->name);
|
|
|
|
if (t->constructors_num == 1) {
|
|
|
|
native_class_name = gen_native_class_name(t->constructors[0]->name);
|
|
|
|
}
|
|
|
|
return storage ? "td::td_api::object_ptr<td::td_api::" + native_class_name + ">"
|
|
|
|
: "td::td_api::" + native_class_name + "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_type_name(const tl::tl_tree_type *tree_type, bool force) const {
|
|
|
|
const tl::tl_type *t = tree_type->type;
|
|
|
|
const std::string &name = t->name;
|
|
|
|
|
|
|
|
if (name == "#") {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
if (name == "Bool") {
|
|
|
|
return force ? "Int" : "int ";
|
|
|
|
}
|
|
|
|
if (name == "Int32") {
|
|
|
|
return force ? "Int" : "int ";
|
|
|
|
}
|
|
|
|
if (name == "Int53" || name == "Int64") {
|
|
|
|
return force ? "Long" : "long long ";
|
|
|
|
}
|
|
|
|
if (name == "Double") {
|
|
|
|
return force ? "Double" : "double ";
|
|
|
|
}
|
|
|
|
if (name == "String") {
|
|
|
|
return force ? "String" : "char *";
|
|
|
|
}
|
|
|
|
if (name == "Bytes") {
|
|
|
|
return force ? "Bytes" : "struct TdBytes ";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name == "Vector") {
|
|
|
|
assert(t->arity == 1);
|
|
|
|
assert(tree_type->children.size() == 1);
|
|
|
|
assert(tree_type->children[0]->get_type() == tl::NODE_TYPE_TYPE);
|
|
|
|
const tl::tl_tree_type *child = static_cast<const tl::tl_tree_type *>(tree_type->children[0]);
|
|
|
|
|
|
|
|
return !force ? ("struct TdVector" + gen_type_name(child, true) + " *") : ("Vector" + gen_type_name(child, true));
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!is_built_in_simple_type(name) && !is_built_in_complex_type(name));
|
|
|
|
|
|
|
|
for (std::size_t i = 0; i < tree_type->children.size(); i++) {
|
|
|
|
assert(tree_type->children[i]->get_type() == tl::NODE_TYPE_NAT_CONST);
|
|
|
|
}
|
|
|
|
|
|
|
|
return !force ? ("struct Td" + gen_main_class_name(t) + " *") : gen_main_class_name(t);
|
|
|
|
}
|
|
|
|
std::string gen_type_name(const tl::tl_tree_type *tree_type) const override {
|
|
|
|
return gen_type_name(tree_type, false);
|
|
|
|
}
|
|
|
|
std::string gen_output_begin() const override {
|
|
|
|
if (is_header_ == 1) {
|
|
|
|
return "#pragma once\n"
|
|
|
|
"#ifdef __cplusplus\n"
|
|
|
|
"extern \"C\" {\n"
|
|
|
|
"#endif\n"
|
|
|
|
"#define TDC_VECTOR(tdc_type_name,tdc_type) \\\n"
|
|
|
|
" struct TdVector ## tdc_type_name { \\\n"
|
|
|
|
" int len;\\\n"
|
|
|
|
" tdc_type *data;\\\n"
|
|
|
|
" };\\\n"
|
|
|
|
"\n"
|
|
|
|
"TDC_VECTOR(Int,int)\n"
|
|
|
|
"TDC_VECTOR(Long,long long)\n"
|
|
|
|
"TDC_VECTOR(String,char *)\n"
|
|
|
|
"struct TdStackStorerMethods {\n"
|
|
|
|
" void (*pack_string)(const char *s);\n"
|
|
|
|
" void (*pack_bytes)(const unsigned char *s, int len);\n"
|
|
|
|
" void (*pack_long)(long long x);\n"
|
|
|
|
" void (*pack_double)(double x);\n"
|
|
|
|
" void (*pack_bool)(int x);\n"
|
|
|
|
" void (*new_table)(void);\n"
|
|
|
|
" void (*new_array)(void);\n"
|
|
|
|
" void (*new_field)(const char *name);\n"
|
|
|
|
" void (*new_arr_field)(int idx);\n"
|
|
|
|
"};\n"
|
|
|
|
"struct TdStackFetcherMethods {\n"
|
|
|
|
" char *(*get_string)(void);\n"
|
|
|
|
" unsigned char *(*get_bytes)(int *len);\n"
|
|
|
|
" long long (*get_long)(void);\n"
|
|
|
|
" double (*get_double)(void);\n"
|
|
|
|
" void (*pop)(void);\n"
|
|
|
|
" void (*get_field)(const char *name);\n"
|
|
|
|
" void (*get_arr_field)(int idx);\n"
|
|
|
|
" int (*get_arr_size)(void);\n"
|
|
|
|
" int (*is_nil)(void);\n"
|
|
|
|
"};\n"
|
|
|
|
"struct TdBytes {\n"
|
|
|
|
" unsigned char *data;\n"
|
|
|
|
" int len;\n"
|
|
|
|
"};\n";
|
|
|
|
}
|
|
|
|
if (is_header_ == -1) {
|
|
|
|
return "#pragma once\n"
|
|
|
|
"#include \"td/telegram/td_tdc_api.h\"\n"
|
|
|
|
"#include \"td/telegram/td_api.h\"\n";
|
|
|
|
}
|
|
|
|
return "#include \"td/telegram/td_tdc_api_inner.h\"\n\n"
|
|
|
|
"#include \"td/utils/format.h\"\n"
|
|
|
|
"#include \"td/utils/logging.h\"\n"
|
|
|
|
"#include \"td/utils/misc.h\"\n"
|
|
|
|
"#include \"td/utils/Slice.h\"\n"
|
|
|
|
"#include \"td/utils/tl_storers.h\"\n"
|
|
|
|
"\n";
|
|
|
|
}
|
|
|
|
std::string gen_output_end() const override {
|
|
|
|
if (is_header_ == 1) {
|
|
|
|
return "#ifdef __cplusplus\n"
|
|
|
|
"}\n"
|
|
|
|
"#endif\n";
|
|
|
|
} else if (is_header_ == -1) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_forward_class_declaration(const std::string &class_name, bool is_proxy) const override {
|
|
|
|
if (is_header_ != 1 || class_name == "") {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
return "struct Td" + class_name +
|
|
|
|
";\n"
|
|
|
|
"TDC_VECTOR(" +
|
|
|
|
class_name + ", struct Td" + class_name +
|
|
|
|
" *);\n"
|
|
|
|
"TDC_VECTOR(Vector" +
|
|
|
|
class_name + ", struct TdVector" + class_name + " *);\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_class_begin(const std::string &class_name, const std::string &base_class_name,
|
|
|
|
bool is_proxy) const override {
|
|
|
|
if (is_header_ != 1 || class_name == "") {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string tail = "";
|
|
|
|
if (class_name == "Function" || class_name == "Object") {
|
|
|
|
tail = "};\n";
|
|
|
|
}
|
|
|
|
return "struct Td" + class_name + " {\n" + " int ID;\n int refcnt;\n" + tail;
|
|
|
|
}
|
|
|
|
std::string gen_class_end() const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_field_definition(const std::string &class_name, const std::string &type_name,
|
|
|
|
const std::string &field_name) const override {
|
|
|
|
if (is_header_ != 1 || class_name == "") {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
return " " + type_name + field_name + ";\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_store_function_begin(const std::string &storer_name, const std::string &class_name, int arity,
|
|
|
|
std::vector<tl::var_description> &vars, int storer_type) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_store_function_end(const std::vector<tl::var_description> &vars, int storer_type) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_constructor_begin(int fields_num, const std::string &class_name, bool is_default) const override {
|
|
|
|
if (!is_default || is_header_ == -1 || class_name == "") {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::stringstream ss;
|
|
|
|
if (is_header_ == 1) {
|
|
|
|
ss << "};\n";
|
|
|
|
}
|
|
|
|
ss << "struct Td" + gen_class_name(class_name) + " *TdCreateObject" + gen_class_name(class_name) + " (" +
|
|
|
|
(fields_num ? "" : "void");
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
std::string gen_constructor_parameter(int field_num, const tl::arg &a, bool is_default) const override {
|
|
|
|
if (!is_default || is_header_ == -1) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::stringstream ss;
|
|
|
|
auto field_type = gen_field_type(a);
|
|
|
|
ss << (field_num == 0 ? "" : ", ");
|
|
|
|
ss << field_type << gen_field_name(a.name);
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
std::string gen_constructor_field_init(int field_num, const tl::arg &a, bool is_default) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_constructor_end(const tl::tl_combinator *t, int fields_num, bool is_default) const override {
|
|
|
|
if (!is_default || is_header_ == -1) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
if (is_header_ == 1) {
|
|
|
|
return ");\n";
|
|
|
|
}
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << ") {\n";
|
|
|
|
auto type_name = "struct Td" + gen_class_name(t->name);
|
|
|
|
ss << " auto var = new " << type_name << " ();\n";
|
|
|
|
ss << " var->ID = CODE_" << gen_class_name(t->name) << ";\n";
|
|
|
|
ss << " var->refcnt = 1;\n";
|
|
|
|
for (auto &it : t->args) {
|
|
|
|
const tl::tl_tree_type *T = static_cast<const tl::tl_tree_type *>(it.type);
|
|
|
|
auto field_name = gen_field_name(it.name);
|
|
|
|
if (T->type->name == "String") {
|
|
|
|
ss << " var->" << field_name << " = (" << field_name << ") ? td::str_dup (td::Slice (" << field_name
|
|
|
|
<< ")) : nullptr;\n";
|
|
|
|
} else {
|
|
|
|
ss << " var->" << field_name << " = " << field_name << ";\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ss << " return var;\n}\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
std::string gen_additional_function(const std::string &function_name, const tl::tl_combinator *t,
|
|
|
|
bool is_function) const override {
|
|
|
|
std::stringstream ss;
|
|
|
|
if (function_name == "enum") {
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
if (function_name == "TdDestroyObject") {
|
|
|
|
auto class_name = gen_class_name(t->name);
|
|
|
|
if (is_header_ == 1) {
|
|
|
|
ss << "void TdDestroyObject" + class_name + " (struct Td" + class_name + " *var);\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
if (is_header_ == -1) {
|
|
|
|
ss << "void TdDestroyObject (struct Td" + class_name + " *var);\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
ss << "void TdDestroyObject" + class_name + " (struct Td" + class_name + " *var) {\n";
|
|
|
|
ss << " TdDestroyObject (var);\n";
|
|
|
|
ss << "}\n";
|
|
|
|
ss << "void TdDestroyObject (struct Td" + class_name + " *var)";
|
|
|
|
|
|
|
|
file_store_methods_destroy M(this);
|
|
|
|
gen_object_store(ss, t, M);
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
if (function_name == "TdSerialize" && is_header_ != -1) {
|
|
|
|
auto class_name = gen_class_name(t->name);
|
|
|
|
ss << "char *TdSerialize" + class_name + " (struct Td" + class_name + " *var)";
|
|
|
|
if (is_header_ == 1) {
|
|
|
|
ss << ";\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
ss << " {\n";
|
|
|
|
ss << " return td::str_dup (TdToString (var));\n";
|
|
|
|
ss << "}\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
if (function_name == "TdToString" && is_header_ != 1) {
|
|
|
|
auto class_name = gen_class_name(t->name);
|
|
|
|
ss << "std::string TdToString (struct Td" + class_name + " *var)";
|
|
|
|
if (is_header_ == -1) {
|
|
|
|
ss << ";\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
ss << " {\n";
|
|
|
|
ss << " return to_string (TdConvertToInternal (var));\n";
|
|
|
|
ss << "}\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
if (function_name == "TdConvertToInternal" && is_header_ != 1) {
|
|
|
|
auto class_name = gen_class_name(t->name);
|
|
|
|
auto native_class_name = gen_native_class_name(t->name);
|
|
|
|
ss << "td::td_api::object_ptr<td::td_api::" << native_class_name
|
|
|
|
<< "> TdConvertToInternal (struct Td" + class_name + " *var)";
|
|
|
|
if (is_header_ == -1) {
|
|
|
|
ss << ";\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
file_store_methods_to_td M(this);
|
|
|
|
gen_object_store(ss, t, M);
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
if (function_name == "TdConvertFromInternal" && is_header_ != 1) {
|
|
|
|
auto class_name = gen_class_name(t->name);
|
|
|
|
auto native_class_name = gen_native_class_name(t->name);
|
|
|
|
ss << "struct Td" << class_name << " *TdConvertFromInternal (const td::td_api::" << native_class_name
|
|
|
|
<< " &from)";
|
|
|
|
if (is_header_ == -1) {
|
|
|
|
ss << ";\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
file_fetch_methods_from_td M(this);
|
|
|
|
gen_object_fetch(ss, t, M);
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
if (function_name == "TdStackStorer") {
|
|
|
|
auto class_name = gen_class_name(t->name);
|
|
|
|
if (is_header_ == 1) {
|
|
|
|
ss << "void TdStackStorer" + class_name + " (struct Td" + class_name +
|
|
|
|
" *var, struct TdStackStorerMethods *M);\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
if (is_header_ == -1) {
|
|
|
|
ss << "void TdStackStorer (struct Td" + class_name + " *var, struct TdStackStorerMethods *M);\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
ss << "void TdStackStorer" + class_name + " (struct Td" + class_name +
|
|
|
|
" *var, struct TdStackStorerMethods *M) {\n";
|
|
|
|
ss << " TdStackStorer (var, M);\n";
|
|
|
|
ss << "}\n";
|
|
|
|
ss << "void TdStackStorer (struct Td" + class_name + " *var, struct TdStackStorerMethods *M)";
|
|
|
|
|
|
|
|
file_store_methods_stack M(this);
|
|
|
|
gen_object_store(ss, t, M);
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
if (function_name == "TdStackFetcher" && is_header_ != -1) {
|
|
|
|
auto class_name = gen_class_name(t->name);
|
|
|
|
ss << "struct Td" << class_name << " *TdStackFetcher" + class_name + " (struct TdStackFetcherMethods *M)";
|
|
|
|
if (is_header_ == 1) {
|
|
|
|
ss << ";\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
file_fetch_methods_stack M(this);
|
|
|
|
gen_object_fetch(ss, t, M);
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
struct file_store_methods {
|
|
|
|
file_store_methods() = default;
|
|
|
|
file_store_methods(const file_store_methods &) = delete;
|
|
|
|
file_store_methods &operator=(const file_store_methods &) = delete;
|
|
|
|
virtual ~file_store_methods() = default;
|
|
|
|
virtual void store_simple_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string type_name) const {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
virtual void store_common_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string type_name) const {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
virtual void store_array_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
virtual void store_array_el(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string idx) const {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
virtual void store_array_finish(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
virtual void store_nil(std::stringstream &ss, std::string offset) const {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
virtual std::string store_field_start(std::stringstream &ss, std::string offset, int depth,
|
|
|
|
const tl::tl_tree_type *tree_type) const {
|
|
|
|
assert(false);
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
virtual void store_field_finish(std::stringstream &ss, std::string offset, std::string res_var) const {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
virtual void store_arg_finish(std::stringstream &ss, std::string offset, std::string arg_name,
|
|
|
|
std::string res_var) const {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
virtual void store_constructor_start(std::stringstream &ss, std::string offset, const tl::tl_combinator *t) const {
|
|
|
|
}
|
|
|
|
virtual void store_constructor_finish(std::stringstream &ss, std::string offset, const tl::tl_combinator *t,
|
|
|
|
std::vector<std::string> res_var) const {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct file_store_methods_to_td : public file_store_methods {
|
|
|
|
explicit file_store_methods_to_td(const class TlWriterCCommon *cl) : cl(cl) {
|
|
|
|
}
|
|
|
|
void store_simple_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string type_name) const override {
|
|
|
|
if (type_name == "String") {
|
|
|
|
ss << offset << res_var << " = (" << var << ") ? " << var << ": \"\";\n";
|
|
|
|
} else if (type_name == "Bytes") {
|
|
|
|
ss << offset << res_var << " = std::string ((char *)" << var << ".data, " << var << ".len);\n";
|
|
|
|
} else if (type_name == "Bool") {
|
|
|
|
ss << offset << res_var << " = " << var << " != 0;\n";
|
|
|
|
} else {
|
|
|
|
ss << offset << res_var << " = " << var << ";\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void store_common_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string type_name) const override {
|
|
|
|
ss << offset << res_var << " = TdConvertToInternal (" << var << ");\n";
|
|
|
|
}
|
|
|
|
void store_array_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
}
|
|
|
|
void store_array_el(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string idx) const override {
|
|
|
|
ss << offset << res_var << ".push_back (std::move (" << var << "));\n";
|
|
|
|
}
|
|
|
|
void store_array_finish(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
}
|
|
|
|
void store_nil(std::stringstream &ss, std::string offset) const override {
|
|
|
|
ss << offset << "return nullptr;\n";
|
|
|
|
}
|
|
|
|
std::string store_field_start(std::stringstream &ss, std::string offset, int depth,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
std::string res_var = "v" + int_to_string(depth);
|
|
|
|
ss << offset << cl->gen_native_type_name(tree_type, true) << " " << res_var << ";\n";
|
|
|
|
return res_var;
|
|
|
|
}
|
|
|
|
void store_field_finish(std::stringstream &ss, std::string offset, std::string res_var) const override {
|
|
|
|
}
|
|
|
|
void store_arg_finish(std::stringstream &ss, std::string offset, std::string arg_name,
|
|
|
|
std::string res_var) const override {
|
|
|
|
}
|
|
|
|
void store_constructor_finish(std::stringstream &ss, std::string offset, const tl::tl_combinator *t,
|
|
|
|
std::vector<std::string> res_var) const override {
|
|
|
|
auto native_class_name = cl->gen_native_class_name(t->name);
|
|
|
|
ss << offset << "return td::td_api::make_object<td::td_api::" << native_class_name << ">(";
|
|
|
|
bool is_first = true;
|
|
|
|
for (auto &var_name : res_var) {
|
|
|
|
if (is_first) {
|
|
|
|
is_first = false;
|
|
|
|
} else {
|
|
|
|
ss << ", ";
|
|
|
|
}
|
|
|
|
|
|
|
|
ss << "std::move (" << var_name << ")";
|
|
|
|
}
|
|
|
|
ss << ");\n";
|
|
|
|
}
|
|
|
|
const class TlWriterCCommon *cl;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct file_store_methods_destroy : public file_store_methods {
|
|
|
|
explicit file_store_methods_destroy(const class TlWriterCCommon *cl) : cl(cl) {
|
|
|
|
}
|
|
|
|
void store_simple_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string type_name) const override {
|
|
|
|
if (type_name == "String") {
|
|
|
|
ss << offset << "free (" << var << ");\n";
|
|
|
|
} else if (type_name == "Bytes") {
|
|
|
|
ss << offset << "delete[]" << var << ".data;\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void store_common_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string type_name) const override {
|
|
|
|
ss << offset << "TdDestroyObject (" << var << ");\n";
|
|
|
|
}
|
|
|
|
void store_array_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
}
|
|
|
|
void store_array_el(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string idx) const override {
|
|
|
|
}
|
|
|
|
void store_array_finish(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
ss << offset << "delete[] " << var << "->data;\n" << offset << "delete " << var << ";\n";
|
|
|
|
}
|
|
|
|
void store_nil(std::stringstream &ss, std::string offset) const override {
|
|
|
|
ss << offset << "return;\n";
|
|
|
|
}
|
|
|
|
std::string store_field_start(std::stringstream &ss, std::string offset, int depth,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
void store_field_finish(std::stringstream &ss, std::string offset, std::string res_var) const override {
|
|
|
|
}
|
|
|
|
void store_arg_finish(std::stringstream &ss, std::string offset, std::string arg_name,
|
|
|
|
std::string res_var) const override {
|
|
|
|
}
|
|
|
|
void store_constructor_start(std::stringstream &ss, std::string offset, const tl::tl_combinator *t) const override {
|
|
|
|
ss << "#if TD_MSVC\n";
|
|
|
|
ss << offset << "static_assert (sizeof (long) == sizeof (var->refcnt), \"Illegal InterlockedDecrement\");\n";
|
|
|
|
ss << offset << "int ref = InterlockedDecrement (reinterpret_cast<long *>(&var->refcnt));\n";
|
|
|
|
ss << "#else\n";
|
|
|
|
ss << offset << "int ref = __sync_add_and_fetch (&var->refcnt, -1);\n";
|
|
|
|
ss << "#endif\n";
|
|
|
|
ss << offset << "if (ref < 0) {\n";
|
|
|
|
ss << offset << " LOG(FATAL) << \"Negative reference counter in Td C object struct\";\n";
|
|
|
|
ss << offset << "}\n";
|
|
|
|
ss << offset << "if (ref > 0) {\n";
|
|
|
|
ss << offset << " return;\n";
|
|
|
|
ss << offset << "}\n";
|
|
|
|
}
|
|
|
|
void store_constructor_finish(std::stringstream &ss, std::string offset, const tl::tl_combinator *t,
|
|
|
|
std::vector<std::string> res_var) const override {
|
|
|
|
ss << offset << "delete var;\n";
|
|
|
|
}
|
|
|
|
const class TlWriterCCommon *cl;
|
|
|
|
};
|
|
|
|
struct file_store_methods_stack : public file_store_methods {
|
|
|
|
explicit file_store_methods_stack(const class TlWriterCCommon *cl) : cl(cl) {
|
|
|
|
}
|
|
|
|
void store_simple_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string type_name) const override {
|
|
|
|
if (type_name == "String") {
|
|
|
|
ss << offset << "M->pack_string (" << var << ");\n";
|
|
|
|
} else if (type_name == "Bytes") {
|
|
|
|
ss << offset << "M->pack_bytes (" << var << ".data, " << var << ".len);\n";
|
|
|
|
} else if (type_name == "Int32" || type_name == "Int53" || type_name == "Int64") {
|
|
|
|
ss << offset << "M->pack_long (" << var << ");\n";
|
|
|
|
} else if (type_name == "Bool") {
|
|
|
|
ss << offset << "M->pack_bool (" << var << ");\n";
|
|
|
|
} else if (type_name == "Double") {
|
|
|
|
ss << offset << "M->pack_double (" << var << ");\n";
|
|
|
|
} else {
|
|
|
|
ss << "????" << type_name << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void store_common_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string type_name) const override {
|
|
|
|
ss << offset << "TdStackStorer (" << var << ", M);\n";
|
|
|
|
}
|
|
|
|
void store_array_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
ss << offset << "M->new_array ();\n";
|
|
|
|
}
|
|
|
|
void store_array_el(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string idx) const override {
|
|
|
|
ss << offset << "M->new_arr_field (" << idx << ");\n";
|
|
|
|
}
|
|
|
|
void store_array_finish(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
}
|
|
|
|
void store_nil(std::stringstream &ss, std::string offset) const override {
|
|
|
|
ss << offset << "M->pack_bool (0);\n" << offset << "return;\n";
|
|
|
|
}
|
|
|
|
std::string store_field_start(std::stringstream &ss, std::string offset, int depth,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
void store_field_finish(std::stringstream &ss, std::string offset, std::string res_var) const override {
|
|
|
|
}
|
|
|
|
void store_arg_finish(std::stringstream &ss, std::string offset, std::string arg_name,
|
|
|
|
std::string res_var) const override {
|
|
|
|
ss << offset << "M->new_field (\"" << arg_name << "\");\n";
|
|
|
|
}
|
|
|
|
void store_constructor_start(std::stringstream &ss, std::string offset, const tl::tl_combinator *t) const override {
|
|
|
|
ss << offset << "M->new_table ();\n";
|
|
|
|
auto class_name = cl->gen_class_name(t->name);
|
|
|
|
ss << offset << "M->pack_string (\"" << class_name << "\");\n";
|
|
|
|
ss << offset << "M->new_field (\"ID\");\n";
|
|
|
|
}
|
|
|
|
void store_constructor_finish(std::stringstream &ss, std::string offset, const tl::tl_combinator *t,
|
|
|
|
std::vector<std::string> res_var) const override {
|
|
|
|
}
|
|
|
|
const class TlWriterCCommon *cl;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct file_fetch_methods {
|
|
|
|
file_fetch_methods() = default;
|
|
|
|
file_fetch_methods(const file_fetch_methods &) = delete;
|
|
|
|
file_fetch_methods &operator=(const file_fetch_methods &) = delete;
|
|
|
|
|
|
|
|
virtual ~file_fetch_methods() = default;
|
|
|
|
|
|
|
|
virtual std::string fetch_field_start(std::stringstream &ss, std::string offset, int depth,
|
|
|
|
const tl::tl_tree_type *tree_type) const {
|
|
|
|
assert(false);
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
virtual void fetch_simple_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string type_name) const {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
virtual void fetch_common_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
virtual void fetch_array_size(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
virtual std::string fetch_array_field_start(std::stringstream &ss, std::string offset, std::string res_var,
|
|
|
|
std::string var, std::string idx,
|
|
|
|
const tl::tl_tree_type *tree_type) const {
|
|
|
|
assert(false);
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
virtual std::string fetch_dict_field_start(std::stringstream &ss, std::string offset, std::string res_var,
|
|
|
|
std::string var, std::string key,
|
|
|
|
const tl::tl_tree_type *tree_type) const {
|
|
|
|
assert(false);
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
virtual void fetch_field_finish(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct file_fetch_methods_from_td : public file_fetch_methods {
|
|
|
|
explicit file_fetch_methods_from_td(const class TlWriterCCommon *cl) : cl(cl) {
|
|
|
|
}
|
|
|
|
std::string fetch_field_start(std::stringstream &ss, std::string offset, int depth,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
void fetch_simple_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string type_name) const override {
|
|
|
|
if (type_name == "String") {
|
|
|
|
ss << offset << res_var << " = (" << var << ".length ()) ? td::str_dup (" << var << ") : nullptr;\n";
|
|
|
|
} else if (type_name == "Bytes") {
|
|
|
|
ss << offset << res_var << ".len = (int)" << var << ".length ();\n";
|
|
|
|
ss << offset << "if (" << res_var << ".len) {\n";
|
|
|
|
ss << offset << " " << res_var << ".data = new unsigned char[" << res_var << ".len];\n";
|
|
|
|
ss << offset << " memcpy (" << res_var << ".data, " << var << ".c_str (), " << res_var << ".len);\n";
|
|
|
|
ss << offset << "} else {\n";
|
|
|
|
ss << offset << " " << res_var << ".data = nullptr;\n";
|
|
|
|
ss << offset << "}\n";
|
|
|
|
} else {
|
|
|
|
ss << offset << res_var << " = " << var << ";\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void fetch_common_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
auto native_type_name = cl->gen_native_type_name(tree_type, false);
|
|
|
|
ss << offset << "if (!" << var << ") {\n"
|
|
|
|
<< offset << " " << res_var << " = nullptr;\n"
|
|
|
|
<< offset << "} else {\n"
|
|
|
|
<< offset << " " << res_var << " = TdConvertFromInternal (static_cast<const " << native_type_name << " &>(*"
|
|
|
|
<< var << "));\n"
|
|
|
|
<< offset << "}\n";
|
|
|
|
}
|
|
|
|
void fetch_array_size(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
ss << offset << res_var << " = (int)" << var << ".size ();\n";
|
|
|
|
}
|
|
|
|
std::string fetch_array_field_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string idx, const tl::tl_tree_type *tree_type) const override {
|
|
|
|
return var + "[" + idx + "]";
|
|
|
|
}
|
|
|
|
std::string fetch_dict_field_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string key, const tl::tl_tree_type *tree_type) const override {
|
|
|
|
return var + "." + key;
|
|
|
|
}
|
|
|
|
void fetch_field_finish(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
}
|
|
|
|
const class TlWriterCCommon *cl;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct file_fetch_methods_stack : public file_fetch_methods {
|
|
|
|
explicit file_fetch_methods_stack(const class TlWriterCCommon *cl) : cl(cl) {
|
|
|
|
}
|
|
|
|
std::string fetch_field_start(std::stringstream &ss, std::string offset, int depth,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
void fetch_simple_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string type_name) const override {
|
|
|
|
if (type_name == "String") {
|
|
|
|
ss << offset << res_var << " = M->get_string ();\n";
|
|
|
|
} else if (type_name == "Bytes") {
|
|
|
|
ss << offset << res_var << ".data = M->get_bytes (&" << res_var << ".len);\n";
|
|
|
|
} else if (type_name == "Int32" || type_name == "Bool") {
|
|
|
|
ss << offset << res_var << " = (int)M->get_long ();\n";
|
|
|
|
} else if (type_name == "Int53" || type_name == "Int64") {
|
|
|
|
ss << offset << res_var << " = M->get_long ();\n";
|
|
|
|
} else if (type_name == "Double") {
|
|
|
|
ss << offset << res_var << " = M->get_double ();\n";
|
|
|
|
} else {
|
|
|
|
ss << "??????" << type_name << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void fetch_common_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
auto class_name = cl->gen_main_class_name(tree_type->type);
|
|
|
|
ss << offset << "if (M->is_nil ()) {\n"
|
|
|
|
<< offset << " " << res_var << " = nullptr;\n"
|
|
|
|
<< offset << "} else {\n"
|
|
|
|
<< offset << " " << res_var << " = TdStackFetcher" << class_name << " (M);\n"
|
|
|
|
<< offset << "}\n";
|
|
|
|
}
|
|
|
|
void fetch_array_size(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
ss << offset << res_var << " = M->get_arr_size ();\n";
|
|
|
|
}
|
|
|
|
std::string fetch_array_field_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string idx, const tl::tl_tree_type *tree_type) const override {
|
|
|
|
ss << offset << " M->get_arr_field (" << idx << ");\n";
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string fetch_dict_field_start(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
std::string key, const tl::tl_tree_type *tree_type) const override {
|
|
|
|
ss << offset << "M->get_field (\"" << key << "\");\n";
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
void fetch_field_finish(std::stringstream &ss, std::string offset, std::string res_var, std::string var,
|
|
|
|
const tl::tl_tree_type *tree_type) const override {
|
|
|
|
ss << offset << "M->pop ();\n";
|
|
|
|
}
|
|
|
|
const class TlWriterCCommon *cl;
|
|
|
|
};
|
|
|
|
|
|
|
|
std::string gen_field_store(std::stringstream &ss, std::string offset, std::string var, int depth,
|
|
|
|
const tl::tl_tree_type *tree_type, const file_store_methods &M) const {
|
|
|
|
std::string res_var = M.store_field_start(ss, offset, depth, tree_type);
|
|
|
|
if (is_built_in_simple_type(tree_type->type->name)) {
|
|
|
|
M.store_simple_type(ss, offset, res_var, var, tree_type->type->name);
|
|
|
|
} else if (!is_built_in_complex_type(tree_type->type->name)) {
|
|
|
|
M.store_common_type(ss, offset, res_var, var, tree_type->type->name);
|
|
|
|
} else {
|
|
|
|
const tl::tl_tree_type *child = static_cast<const tl::tl_tree_type *>(tree_type->children[0]);
|
|
|
|
|
|
|
|
std::string it = "i" + int_to_string(depth);
|
|
|
|
|
|
|
|
M.store_array_start(ss, offset, res_var, var, tree_type);
|
|
|
|
ss << offset << "for (int " << it << " = 0; " << it << " < " << var << "->len; " << it << "++) {\n";
|
|
|
|
auto f_res_var = gen_field_store(ss, offset + " ", var + "->data[" + it + "]", depth + 1, child, M);
|
|
|
|
M.store_array_el(ss, offset + " ", res_var, f_res_var, it);
|
|
|
|
ss << offset << "}\n";
|
|
|
|
M.store_array_finish(ss, offset, res_var, var, tree_type);
|
|
|
|
}
|
|
|
|
M.store_field_finish(ss, offset, res_var);
|
|
|
|
return res_var;
|
|
|
|
}
|
|
|
|
void gen_object_store(std::stringstream &ss, const tl::tl_combinator *t, const file_store_methods &M) const {
|
|
|
|
ss << " {\n"
|
|
|
|
<< " if (!var) {\n";
|
|
|
|
M.store_nil(ss, " ");
|
|
|
|
ss << " }\n";
|
|
|
|
M.store_constructor_start(ss, " ", t);
|
|
|
|
|
|
|
|
std::vector<std::string> flds;
|
|
|
|
int d = 0;
|
|
|
|
for (auto &it : t->args) {
|
|
|
|
const tl::tl_tree_type *tree_type = static_cast<const tl::tl_tree_type *>(it.type);
|
|
|
|
flds.push_back(gen_field_store(ss, " ", "var->" + gen_field_name(it.name), 100 * d, tree_type, M));
|
|
|
|
d++;
|
|
|
|
M.store_arg_finish(ss, " ", gen_field_name(it.name), flds[d - 1]);
|
|
|
|
}
|
|
|
|
M.store_constructor_finish(ss, " ", t, flds);
|
|
|
|
ss << "}\n";
|
|
|
|
}
|
|
|
|
void gen_field_fetch(std::stringstream &ss, std::string offset, std::string res_var, std::string var, int depth,
|
|
|
|
const tl::tl_tree_type *tree_type, const file_fetch_methods &M) const {
|
|
|
|
if (is_built_in_simple_type(tree_type->type->name)) {
|
|
|
|
M.fetch_simple_type(ss, offset, res_var, var, tree_type->type->name);
|
|
|
|
} else if (!is_built_in_complex_type(tree_type->type->name)) {
|
|
|
|
M.fetch_common_type(ss, offset, res_var, var, tree_type);
|
|
|
|
} else {
|
|
|
|
const tl::tl_tree_type *child = static_cast<const tl::tl_tree_type *>(tree_type->children[0]);
|
|
|
|
|
|
|
|
ss << offset << res_var << " = new Td" << gen_type_name(tree_type, true) << " ();\n";
|
|
|
|
M.fetch_array_size(ss, offset, res_var + "->len", var, tree_type);
|
|
|
|
ss << offset << res_var << "->data = new " << gen_type_name(child) << " [" << res_var << "->len];\n";
|
|
|
|
|
|
|
|
std::string it = "i" + int_to_string(depth);
|
|
|
|
ss << offset << "for (int " << it << " = 0; " << it << " < " << res_var << "->len; " << it << "++) {\n";
|
|
|
|
auto new_var = M.fetch_array_field_start(ss, offset, res_var, var, it, child);
|
|
|
|
gen_field_fetch(ss, offset + " ", res_var + "->data[" + it + "]", new_var, depth + 1, child, M);
|
|
|
|
ss << offset << "}\n";
|
|
|
|
}
|
|
|
|
M.fetch_field_finish(ss, offset, res_var, var, tree_type);
|
|
|
|
}
|
|
|
|
void gen_object_fetch(std::stringstream &ss, const tl::tl_combinator *t, const file_fetch_methods &M) const {
|
|
|
|
auto type_name = gen_class_name(t->name);
|
|
|
|
ss << " {\n"
|
|
|
|
<< " auto res = new Td" << type_name << " ();\n"
|
|
|
|
<< " res->ID = CODE_" << type_name << ";\n"
|
|
|
|
<< " res->refcnt = 1;\n";
|
|
|
|
int d = 0;
|
|
|
|
for (auto &it : t->args) {
|
|
|
|
const tl::tl_tree_type *tree_type = static_cast<const tl::tl_tree_type *>(it.type);
|
|
|
|
auto new_var = M.fetch_dict_field_start(ss, " ", "res", "from", gen_field_name(it.name), tree_type);
|
|
|
|
gen_field_fetch(ss, " ", "res->" + gen_field_name(it.name), new_var, 100 * d, tree_type, M);
|
|
|
|
d++;
|
|
|
|
}
|
|
|
|
ss << " return res;\n"
|
|
|
|
<< "}\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_array_type_name(const tl::tl_tree_array *arr, const std::string &field_name) const override {
|
|
|
|
assert(false);
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
std::string gen_var_type_name() const override {
|
|
|
|
assert(false);
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_int_const(const tl::tl_tree *tree_c, const std::vector<tl::var_description> &vars) const override {
|
|
|
|
assert(false);
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_var_name(const tl::var_description &desc) const override {
|
|
|
|
assert(false);
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_parameter_name(int index) const override {
|
|
|
|
assert(false);
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_class_alias(const std::string &class_name, const std::string &alias_name) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_vars(const tl::tl_combinator *t, const tl::tl_tree_type *result_type,
|
|
|
|
std::vector<tl::var_description> &vars) const override {
|
|
|
|
assert(vars.empty());
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_function_vars(const tl::tl_combinator *t, std::vector<tl::var_description> &vars) const override {
|
|
|
|
assert(vars.empty());
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_uni(const tl::tl_tree_type *result_type, std::vector<tl::var_description> &vars,
|
|
|
|
bool check_negative) const override {
|
|
|
|
assert(result_type->children.empty());
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_constructor_id_store(std::int32_t id, int storer_type) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_field_fetch(int field_num, const tl::arg &a, std::vector<tl::var_description> &vars, bool flat,
|
|
|
|
int parser_type) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_field_store(const tl::arg &a, std::vector<tl::var_description> &vars, bool flat,
|
|
|
|
int storer_type) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_type_fetch(const std::string &field_name, const tl::tl_tree_type *tree_type,
|
|
|
|
const std::vector<tl::var_description> &vars, int parser_type) const override {
|
|
|
|
assert(vars.empty());
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_type_store(const std::string &field_name, const tl::tl_tree_type *tree_type,
|
|
|
|
const std::vector<tl::var_description> &vars, int storer_type) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_var_type_fetch(const tl::arg &a) const override {
|
|
|
|
assert(false);
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_get_id(const std::string &class_name, std::int32_t id, bool is_proxy) const override {
|
|
|
|
if (is_proxy || is_header_ != 1) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
// return "#define CODE_" + class_name + " " + int_to_string(id) + "\n";
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_function_result_type(const tl::tl_tree *result) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_fetch_function_begin(const std::string &parser_name, const std::string &class_name, int arity,
|
|
|
|
std::vector<tl::var_description> &vars, int parser_type) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_fetch_function_end(int field_num, const std::vector<tl::var_description> &vars,
|
|
|
|
int parser_type) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_fetch_function_result_begin(const std::string &parser_name, const std::string &class_name,
|
|
|
|
const tl::tl_tree *result) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_fetch_function_result_end() const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_fetch_function_result_any_begin(const std::string &parser_name, const std::string &class_name,
|
|
|
|
bool is_proxy) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_fetch_function_result_any_end(bool is_proxy) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_fetch_switch_begin() const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_fetch_switch_case(const tl::tl_combinator *t, int arity) const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
std::string gen_fetch_switch_end() const override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_additional_proxy_function_begin(const std::string &function_name, const tl::tl_type *type,
|
|
|
|
const std::string &name, int arity, bool is_function) const override {
|
|
|
|
std::stringstream ss;
|
|
|
|
std::string class_name;
|
|
|
|
std::string native_class_name;
|
|
|
|
|
|
|
|
if (type != nullptr) {
|
|
|
|
class_name = gen_main_class_name(type);
|
|
|
|
native_class_name = gen_native_class_name(type->name);
|
|
|
|
} else {
|
|
|
|
if (is_function) {
|
|
|
|
class_name = "Function";
|
|
|
|
native_class_name = "Function";
|
|
|
|
} else {
|
|
|
|
class_name = "Object";
|
|
|
|
native_class_name = "Object";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (is_header_ == 1 && function_name == "TdConvertToInternal" && type != nullptr && !is_function) {
|
|
|
|
ss << "};\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (function_name == "enum") {
|
|
|
|
if (is_header_ != 1) {
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
ss << "enum List_" + class_name << " {\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (function_name == "TdDestroyObject") {
|
|
|
|
if (is_header_ == 1) {
|
|
|
|
ss << "void TdDestroyObject" + class_name + " (struct Td" + class_name + " *var);\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
if (is_header_ == -1) {
|
|
|
|
ss << "void TdDestroyObject (struct Td" + class_name + " *var);\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
ss << "void TdDestroyObject" + class_name + " (struct Td" + class_name + " *var) {\n";
|
|
|
|
ss << " TdDestroyObject (var);\n";
|
|
|
|
ss << "}\n";
|
|
|
|
ss << "void TdDestroyObject (struct Td" + class_name + " *var)";
|
|
|
|
}
|
|
|
|
if (function_name == "TdSerialize" && is_header_ != -1) {
|
|
|
|
ss << "char *TdSerialize" + class_name + " (struct Td" + class_name + " *var)";
|
|
|
|
if (is_header_ == 1) {
|
|
|
|
ss << ";\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
ss << " {\n";
|
|
|
|
ss << " return td::str_dup (TdToString (var));\n";
|
|
|
|
ss << "}\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
if (function_name == "TdToString" && is_header_ != 1) {
|
|
|
|
ss << "std::string TdToString (struct Td" + class_name + " *var)";
|
|
|
|
if (is_header_ == -1) {
|
|
|
|
ss << ";\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
ss << " {\n";
|
|
|
|
ss << " return to_string (TdConvertToInternal (var));\n";
|
|
|
|
ss << "}\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
if (function_name == "TdConvertToInternal" && is_header_ != 1) {
|
|
|
|
ss << "td::td_api::object_ptr<td::td_api::" << native_class_name
|
|
|
|
<< "> TdConvertToInternal (struct Td" + class_name + " *var)";
|
|
|
|
if (is_header_ == -1) {
|
|
|
|
ss << ";\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (function_name == "TdConvertFromInternal" && is_header_ != 1) {
|
|
|
|
ss << "struct Td" << class_name << " *TdConvertFromInternal (const td::td_api::" << native_class_name
|
|
|
|
<< " &from)";
|
|
|
|
if (is_header_ == -1) {
|
|
|
|
ss << ";\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (function_name == "TdStackStorer") {
|
|
|
|
if (is_header_ == 1) {
|
|
|
|
ss << "void TdStackStorer" + class_name + " (struct Td" + class_name +
|
|
|
|
" *var, struct TdStackStorerMethods *M);\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
if (is_header_ == -1) {
|
|
|
|
ss << "void TdStackStorer (struct Td" + class_name + " *var, struct TdStackStorerMethods *M);\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
ss << "void TdStackStorer" + class_name + " (struct Td" + class_name +
|
|
|
|
" *var, struct TdStackStorerMethods *M) {\n";
|
|
|
|
ss << " TdStackStorer (var, M);\n";
|
|
|
|
ss << "}\n";
|
|
|
|
ss << "void TdStackStorer (struct Td" + class_name + " *var, struct TdStackStorerMethods *M)";
|
|
|
|
}
|
|
|
|
if (function_name == "TdStackFetcher" && is_header_ != -1) {
|
|
|
|
ss << "struct Td" << class_name << " *TdStackFetcher" + class_name + " (struct TdStackFetcherMethods *M)";
|
|
|
|
if (is_header_ == 1) {
|
|
|
|
ss << ";\n";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (is_header_ != 0) {
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (function_name == "TdDestroyObject" || function_name == "TdConvertToInternal" ||
|
|
|
|
function_name == "TdStackStorer") {
|
|
|
|
ss << " {\n";
|
|
|
|
std::string prefix = "";
|
|
|
|
if (function_name == "TdConvertToInternal") {
|
|
|
|
prefix = " if (!var) { return nullptr; }\n";
|
|
|
|
} else if (function_name == "TdDestroyObject") {
|
|
|
|
prefix = " if (!var) { return; }\n";
|
|
|
|
}
|
|
|
|
if (function_name == "TdStackStorer") {
|
|
|
|
prefix = " if (!var) { M->pack_bool (0); return; }\n";
|
|
|
|
}
|
|
|
|
ss << prefix
|
|
|
|
<< " int constructor = var->ID;\n"
|
|
|
|
" switch (constructor) {\n";
|
|
|
|
} else if (function_name == "TdConvertFromInternal") {
|
|
|
|
ss << " {\n"
|
|
|
|
//" if (!from) { return nullptr; }\n"
|
|
|
|
" int constructor = from.get_id ();\n"
|
|
|
|
" switch (constructor) {\n";
|
|
|
|
} else if (function_name == "TdStackFetcher") {
|
|
|
|
ss << " {\n"
|
|
|
|
" M->get_field (\"ID\");\n"
|
|
|
|
" char *constructor_old = M->get_string ();\n"
|
|
|
|
" M->pop ();\n"
|
|
|
|
" std::string constructor = constructor_old;\n"
|
|
|
|
" free (constructor_old);\n"
|
|
|
|
" ";
|
|
|
|
} else {
|
|
|
|
ss << "??????";
|
|
|
|
}
|
|
|
|
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_additional_proxy_function_case(const std::string &function_name, const tl::tl_type *type,
|
|
|
|
const std::string &class_name, int arity) const override {
|
|
|
|
if (is_header_ != (function_name == "enum" ? 1 : 0)) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(type != nullptr);
|
|
|
|
if (function_name == "TdDestroyObject" || function_name == "TdConvertToInternal" ||
|
|
|
|
function_name == "TdStackStorer") {
|
|
|
|
std::string extra_arg = "";
|
|
|
|
if (function_name == "TdStackStorer") {
|
|
|
|
extra_arg = ", M";
|
|
|
|
}
|
|
|
|
return " case CODE_" + class_name + ": return " + function_name + " ((struct Td" + class_name + " *)var" +
|
|
|
|
extra_arg + ");\n";
|
|
|
|
} else if (function_name == "TdConvertFromInternal") {
|
|
|
|
std::string native_class_name = class_name;
|
|
|
|
native_class_name[0] = to_lower(native_class_name[0]);
|
|
|
|
return " case CODE_" + class_name + ": return (struct TdNullaryObject *)" + function_name +
|
|
|
|
"(static_cast<const td::td_api::" + native_class_name + " &>(from));\n";
|
|
|
|
} else if (function_name == "TdStackFetcher") {
|
|
|
|
return "if (constructor == \"" + class_name +
|
|
|
|
"\") {\n"
|
|
|
|
" return (struct TdNullaryObject *)TdStackFetcher" +
|
|
|
|
class_name +
|
|
|
|
" (M);\n"
|
|
|
|
" }\n ";
|
|
|
|
} else if (function_name == "enum") {
|
|
|
|
// return " CODE_" + class_name + " = " + int_to_string (t->id) + ",\n";
|
|
|
|
return "????\n";
|
|
|
|
} else {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string gen_additional_proxy_function_case(const std::string &function_name, const tl::tl_type *type,
|
|
|
|
const tl::tl_combinator *t, int arity,
|
|
|
|
bool is_function) const override {
|
|
|
|
if (is_header_ != (function_name == "enum" ? 1 : 0)) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (function_name == "TdDestroyObject" || function_name == "TdConvertToInternal" ||
|
|
|
|
function_name == "TdStackStorer") {
|
|
|
|
auto class_name = gen_class_name(t->name);
|
|
|
|
std::string extra_arg = "";
|
|
|
|
if (function_name == "TdStackStorer") {
|
|
|
|
extra_arg = ", M";
|
|
|
|
}
|
|
|
|
return " case CODE_" + gen_class_name(t->name) + ": return " + function_name + " ((struct Td" + class_name +
|
|
|
|
" *)var" + extra_arg + ");\n";
|
|
|
|
} else if (function_name == "TdConvertFromInternal") {
|
|
|
|
const tl::tl_tree_type *tree_type = static_cast<const tl::tl_tree_type *>(t->result);
|
|
|
|
|
|
|
|
auto native_class_name = gen_native_class_name(t->name);
|
|
|
|
auto class_name = gen_main_class_name(tree_type->type);
|
|
|
|
if (type == nullptr) {
|
|
|
|
if (is_function) {
|
|
|
|
class_name = "Function";
|
|
|
|
} else {
|
|
|
|
class_name = "Object";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return " case CODE_" + gen_class_name(t->name) + ": return (struct Td" + class_name + " *)" + function_name +
|
|
|
|
"(static_cast<const td::td_api::" + native_class_name + " &>(from));\n";
|
|
|
|
} else if (function_name == "enum") {
|
|
|
|
const tl::tl_tree_type *tree_type = static_cast<const tl::tl_tree_type *>(t->result);
|
|
|
|
|
|
|
|
auto native_class_name = gen_native_class_name(t->name);
|
|
|
|
auto class_name = gen_main_class_name(tree_type->type);
|
|
|
|
if (type == nullptr) {
|
|
|
|
if (is_function) {
|
|
|
|
class_name = "Function";
|
|
|
|
} else {
|
|
|
|
class_name = "Object";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int flat = 0;
|
|
|
|
if (!is_function) {
|
|
|
|
if (tree_type->type->constructors_num == 1) {
|
|
|
|
flat = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (class_name == "Object" && !flat) {
|
|
|
|
return " CODE_Copy_" + gen_class_name(t->name) + " = " + int_to_string(t->id) + ",\n";
|
|
|
|
} else {
|
|
|
|
return " CODE_" + gen_class_name(t->name) + " = " + int_to_string(t->id) + ",\n";
|
|
|
|
}
|
|
|
|
} else if (function_name == "TdStackFetcher") {
|
|
|
|
const tl::tl_tree_type *tree_type = static_cast<const tl::tl_tree_type *>(t->result);
|
|
|
|
|
|
|
|
auto native_class_name = gen_native_class_name(t->name);
|
|
|
|
auto class_name = gen_main_class_name(tree_type->type);
|
|
|
|
if (type == nullptr) {
|
|
|
|
if (is_function) {
|
|
|
|
class_name = "Function";
|
|
|
|
} else {
|
|
|
|
class_name = "Object";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return "if (constructor == \"" + gen_class_name(t->name) +
|
|
|
|
"\") {\n"
|
|
|
|
" return (struct Td" +
|
|
|
|
class_name + " *)TdStackFetcher" + gen_class_name(t->name) +
|
|
|
|
" (M);\n"
|
|
|
|
" }\n ";
|
|
|
|
} else {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::string gen_additional_proxy_function_end(const std::string &function_name, const tl::tl_type *type,
|
|
|
|
bool is_function) const override {
|
|
|
|
if (is_header_ != (function_name == "enum" ? 1 : 0)) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (function_name == "TdDestroyObject" || function_name == "TdConvertToInternal" ||
|
|
|
|
function_name == "TdConvertFromInternal" || function_name == "TdStackStorer") {
|
|
|
|
std::string retval = "";
|
|
|
|
if (function_name == "TdConvertToInternal" || function_name == "TdConvertFromInternal") {
|
|
|
|
retval = "nullptr";
|
|
|
|
}
|
|
|
|
return " default:\n"
|
|
|
|
" LOG(FATAL) << \"Unknown constructor found \" << td::format::as_hex(constructor);\n"
|
|
|
|
" return " +
|
|
|
|
retval +
|
|
|
|
";\n"
|
|
|
|
" }\n"
|
|
|
|
"}\n";
|
|
|
|
} else if (function_name == "TdStackFetcher") {
|
|
|
|
return "{\n"
|
|
|
|
" LOG(FATAL) << \"Unknown constructor found \" << constructor;\n"
|
|
|
|
" return nullptr;\n"
|
|
|
|
" }\n"
|
|
|
|
"}\n";
|
|
|
|
} else if (function_name == "enum") {
|
|
|
|
return "};\n";
|
|
|
|
} else {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_additional_function_type(const std::string &additional_function_name) const override {
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace td
|