// // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // 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 final : public tl::TL_writer { int is_header_; public: TlWriterCCommon(const std::string &name, int is_header) : TL_writer(name), is_header_(is_header) { } int get_max_arity() const final { return 0; } bool is_built_in_simple_type(const std::string &name) const final { 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 final { return name == "Vector"; } bool is_type_bare(const tl::tl_type *t) const final { 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 final { return {}; } int get_parser_type(const tl::tl_combinator *t, const std::string &name) const final { return 0; } std::vector<std::string> get_storers() const final { return {}; } std::vector<std::string> get_additional_functions() const final { return {"TdConvertToInternal", "TdConvertFromInternal", "TdSerialize", "TdToString", "TdDestroyObject", "TdStackStorer", "TdStackFetcher", "enum"}; } int get_storer_type(const tl::tl_combinator *t, const std::string &name) const final { return name == "to_string" || name == "to_cpp_string"; } std::string gen_base_tl_class_name() const final { return "Object"; } std::string gen_base_type_class_name(int arity) const final { assert(arity == 0); return "Object"; } std::string gen_base_function_class_name() const final { 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 final { if (name == "Object" || name == "#") { assert(false); } return to_CamelCase(name); } std::string gen_field_name(std::string name) const final { 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 final { return gen_type_name(tree_type, false); } std::string gen_output_begin(const std::string &additional_imports) const final { if (is_header_ == 1) { return "#pragma once\n\n" + additional_imports + "#ifdef __cplusplus\n" "extern \"C\" {\n" "#endif\n"; } if (is_header_ == -1) { return "#pragma once\n\n" + gen_import_declaration("td/telegram/td_tdc_api.h", false) + gen_import_declaration("td/telegram/td_api.h", false) + "\n" + additional_imports; } return gen_import_declaration("td/telegram/td_tdc_api_inner.h", false) + "\n" + gen_import_declaration("td/utils/format.h", false) + gen_import_declaration("td/utils/logging.h", false) + gen_import_declaration("td/utils/misc.h", false) + gen_import_declaration("td/utils/Slice.h", false) + "\n" + additional_imports; } std::string gen_output_begin_once() const final { if (is_header_ == 1) { return "struct TdBytes {\n" " unsigned char *data;\n" " int len;\n" "};\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" "TDC_VECTOR(Bytes,struct TdBytes)\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"; } return std::string(); } std::string gen_output_end() const final { if (is_header_ == 1) { return "#ifdef __cplusplus\n" "}\n" "#endif\n"; } else if (is_header_ == -1) { return ""; } return ""; } std::string gen_import_declaration(const std::string &name, bool is_system) const final { if (is_system) { return "#include <" + name + ">\n"; } else { return "#include \"" + name + "\"\n"; } } std::string gen_package_suffix() const final { return ".h"; } std::string gen_forward_class_declaration(const std::string &class_name, bool is_proxy) const final { if (is_header_ != 1 || class_name == "") { return ""; } return "struct Td" + class_name + ";\n" "struct TdVector" + class_name + ";\n" "struct TdVectorVector" + class_name + ";\n"; } std::string gen_class_begin(const std::string &class_name, const std::string &base_class_name, bool is_proxy, const tl::tl_tree *result) const final { if (is_header_ != 1 || class_name == "") { return ""; } std::string tail = ""; if (class_name == "Function" || class_name == "Object") { tail = "};\n"; } return "TDC_VECTOR(" + class_name + ", struct Td" + class_name + " *);\n" "TDC_VECTOR(Vector" + class_name + ", struct TdVector" + class_name + " *);\n" "struct Td" + class_name + " {\n" + " int ID;\n int refcnt;\n" + tail; } std::string gen_class_end() const final { return ""; } std::string gen_field_definition(const std::string &class_name, const std::string &type_name, const std::string &field_name) const final { 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 final { return ""; } std::string gen_store_function_end(const std::vector<tl::var_description> &vars, int storer_type) const final { return ""; } std::string gen_constructor_begin(int field_count, const std::string &class_name, bool is_default) const final { 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) + " (" + (field_count ? "" : "void"); return ss.str(); } std::string gen_constructor_parameter(int field_num, const std::string &class_name, const tl::arg &a, bool is_default) const final { 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 std::string &class_name, const tl::arg &a, bool is_default) const final { return ""; } std::string gen_constructor_end(const tl::tl_combinator *t, int field_count, bool is_default) const final { 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 final { 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 final : 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 final { 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 final { 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 final { } void store_array_el(std::stringstream &ss, std::string offset, std::string res_var, std::string var, std::string idx) const final { 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 final { } void store_nil(std::stringstream &ss, std::string offset) const final { 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 final { 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 final { } void store_arg_finish(std::stringstream &ss, std::string offset, std::string arg_name, std::string res_var) const final { } void store_constructor_finish(std::stringstream &ss, std::string offset, const tl::tl_combinator *t, std::vector<std::string> res_var) const final { 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 final : 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 final { 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 final { 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 final { } void store_array_el(std::stringstream &ss, std::string offset, std::string res_var, std::string var, std::string idx) const final { } 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 final { ss << offset << "delete[] " << var << "->data;\n" << offset << "delete " << var << ";\n"; } void store_nil(std::stringstream &ss, std::string offset) const final { 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 final { return ""; } void store_field_finish(std::stringstream &ss, std::string offset, std::string res_var) const final { } void store_arg_finish(std::stringstream &ss, std::string offset, std::string arg_name, std::string res_var) const final { } void store_constructor_start(std::stringstream &ss, std::string offset, const tl::tl_combinator *t) const final { 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 final { ss << offset << "delete var;\n"; } const class TlWriterCCommon *cl; }; struct file_store_methods_stack final : 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 final { 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 final { 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 final { 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 final { 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 final { } void store_nil(std::stringstream &ss, std::string offset) const final { 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 final { return ""; } void store_field_finish(std::stringstream &ss, std::string offset, std::string res_var) const final { } void store_arg_finish(std::stringstream &ss, std::string offset, std::string arg_name, std::string res_var) const final { ss << offset << "M->new_field (\"" << arg_name << "\");\n"; } void store_constructor_start(std::stringstream &ss, std::string offset, const tl::tl_combinator *t) const final { 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 final { } 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 final : 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 final { return ""; } void fetch_simple_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var, std::string type_name) const final { 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 final { 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 final { 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 final { 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 final { 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 final { } const class TlWriterCCommon *cl; }; struct file_fetch_methods_stack final : 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 final { return ""; } void fetch_simple_type(std::stringstream &ss, std::string offset, std::string res_var, std::string var, std::string type_name) const final { 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 final { 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 final { 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 final { 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 final { 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 final { 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 final { assert(false); return std::string(); } std::string gen_var_type_name() const final { assert(false); return std::string(); } std::string gen_int_const(const tl::tl_tree *tree_c, const std::vector<tl::var_description> &vars) const final { assert(false); return std::string(); } std::string gen_var_name(const tl::var_description &desc) const final { assert(false); return ""; } std::string gen_parameter_name(int index) const final { assert(false); return ""; } std::string gen_class_alias(const std::string &class_name, const std::string &alias_name) const final { return ""; } std::string gen_vars(const tl::tl_combinator *t, const tl::tl_tree_type *result_type, std::vector<tl::var_description> &vars) const final { assert(vars.empty()); return ""; } std::string gen_function_vars(const tl::tl_combinator *t, std::vector<tl::var_description> &vars) const final { 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 final { assert(result_type->children.empty()); return ""; } std::string gen_constructor_id_store(std::int32_t id, int storer_type) const final { 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 final { return ""; } std::string gen_field_store(const tl::arg &a, std::vector<tl::var_description> &vars, bool flat, int storer_type) const final { 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 final { 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 final { return ""; } std::string gen_var_type_fetch(const tl::arg &a) const final { assert(false); return ""; } std::string gen_get_id(const std::string &class_name, std::int32_t id, bool is_proxy) const final { if (is_proxy || is_header_ != 1) { return ""; } return ""; } std::string gen_function_result_type(const tl::tl_tree *result) const final { return ""; } std::string gen_fetch_function_begin(const std::string &parser_name, const std::string &class_name, const std::string &parent_class_name, int arity, int field_count, std::vector<tl::var_description> &vars, int parser_type) const final { return ""; } std::string gen_fetch_function_end(bool has_parent, int field_count, const std::vector<tl::var_description> &vars, int parser_type) const final { return ""; } std::string gen_fetch_function_result_begin(const std::string &parser_name, const std::string &class_name, const tl::tl_tree *result) const final { return ""; } std::string gen_fetch_function_result_end() const final { return ""; } std::string gen_fetch_function_result_any_begin(const std::string &parser_name, const std::string &class_name, bool is_proxy) const final { return ""; } std::string gen_fetch_function_result_any_end(bool is_proxy) const final { return ""; } std::string gen_fetch_switch_begin() const final { return ""; } std::string gen_fetch_switch_case(const tl::tl_combinator *t, int arity) const final { return ""; } std::string gen_fetch_switch_end() const final { 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 final { 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 final { 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 final { 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 final { 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 final { return 2; } }; } // namespace td