summaryrefslogtreecommitdiff
path: root/protocols/Telegram/tdlib/td/tdtl
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Telegram/tdlib/td/tdtl')
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/CMakeLists.txt29
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_config.cpp363
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_config.h87
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_core.cpp21
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_core.h159
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_outputer.cpp41
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_outputer.h33
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_utils.cpp92
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_utils.h21
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_generate.cpp843
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_generate.h24
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_outputer.cpp16
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_outputer.h22
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_simple.h204
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_simple_parser.h107
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_string_outputer.cpp21
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_string_outputer.h26
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_writer.cpp231
-rw-r--r--protocols/Telegram/tdlib/td/tdtl/td/tl/tl_writer.h162
19 files changed, 2502 insertions, 0 deletions
diff --git a/protocols/Telegram/tdlib/td/tdtl/CMakeLists.txt b/protocols/Telegram/tdlib/td/tdtl/CMakeLists.txt
new file mode 100644
index 0000000000..b0f83cd98d
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
+
+#SOURCE SETS
+set(TDTL_SOURCE
+ td/tl/tl_config.cpp
+ td/tl/tl_core.cpp
+ td/tl/tl_file_outputer.cpp
+ td/tl/tl_file_utils.cpp
+ td/tl/tl_generate.cpp
+ td/tl/tl_outputer.cpp
+ td/tl/tl_string_outputer.cpp
+ td/tl/tl_writer.cpp
+
+ td/tl/tl_config.h
+ td/tl/tl_core.h
+ td/tl/tl_file_outputer.h
+ td/tl/tl_file_utils.h
+ td/tl/tl_generate.h
+ td/tl/tl_outputer.h
+ td/tl/tl_simple.h
+ td/tl/tl_simple_parser.h
+ td/tl/tl_string_outputer.h
+ td/tl/tl_writer.h
+)
+
+add_library(tdtl STATIC ${TDTL_SOURCE})
+target_include_directories(tdtl PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
+#TODO
+#target_compile_options(tdtl PRIVATE "-std=c++03")
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_config.cpp b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_config.cpp
new file mode 100644
index 0000000000..e796596760
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_config.cpp
@@ -0,0 +1,363 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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)
+//
+#include "tl_config.h"
+
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+
+namespace td {
+namespace tl {
+
+const std::int32_t TLS_SCHEMA_V2 = 0x3a2f9be2;
+const std::int32_t TLS_SCHEMA_V3 = 0xe4a8604b;
+const std::int32_t TLS_SCHEMA_V4 = 0x90ac88d7;
+const std::int32_t TLS_TYPE = 0x12eb4386;
+const std::int32_t TLS_COMBINATOR = 0x5c0a1ed5;
+const std::int32_t TLS_COMBINATOR_LEFT_BUILTIN = 0xcd211f63;
+const std::int32_t TLS_COMBINATOR_LEFT = 0x4c12c6d9;
+const std::int32_t TLS_COMBINATOR_RIGHT_V2 = 0x2c064372;
+const std::int32_t TLS_ARG_V2 = 0x29dfe61b;
+
+const std::int32_t TLS_EXPR_NAT = 0xdcb49bd8;
+const std::int32_t TLS_EXPR_TYPE = 0xecc9da78;
+
+const std::int32_t TLS_NAT_CONST_OLD = 0xdcb49bd8;
+const std::int32_t TLS_NAT_CONST = 0x8ce940b1;
+const std::int32_t TLS_NAT_VAR = 0x4e8a14f0;
+const std::int32_t TLS_TYPE_VAR = 0x0142ceae;
+const std::int32_t TLS_ARRAY = 0xd9fb20de;
+const std::int32_t TLS_TYPE_EXPR = 0xc1863d08;
+
+void tl_config::add_type(tl_type *type) {
+ types.push_back(type);
+ id_to_type[type->id] = type;
+ name_to_type[type->name] = type;
+}
+
+tl_type *tl_config::get_type(std::int32_t type_id) const {
+ auto it = id_to_type.find(type_id);
+ assert(it != id_to_type.end());
+ return it->second;
+}
+
+tl_type *tl_config::get_type(const std::string &type_name) {
+ return name_to_type[type_name];
+}
+
+void tl_config::add_function(tl_combinator *function) {
+ functions.push_back(function);
+ id_to_function[function->id] = function;
+ name_to_function[function->name] = function;
+}
+
+tl_combinator *tl_config::get_function(std::int32_t function_id) {
+ return id_to_function[function_id];
+}
+
+tl_combinator *tl_config::get_function(const std::string &function_name) {
+ return name_to_function[function_name];
+}
+
+std::size_t tl_config::get_type_count() const {
+ return types.size();
+}
+
+tl_type *tl_config::get_type_by_num(std::size_t num) const {
+ return types[num];
+}
+
+std::size_t tl_config::get_function_count() const {
+ return functions.size();
+}
+
+tl_combinator *tl_config::get_function_by_num(std::size_t num) const {
+ return functions[num];
+}
+
+std::int32_t tl_config_parser::try_parse_int() {
+ return try_parse(p.fetch_int());
+}
+
+std::int64_t tl_config_parser::try_parse_long() {
+ return try_parse(p.fetch_long());
+}
+
+std::string tl_config_parser::try_parse_string() {
+ return try_parse(p.fetch_string());
+}
+
+template <class T>
+T tl_config_parser::try_parse(const T &res) const {
+ if (p.get_error() != NULL) {
+ std::fprintf(stderr, "Wrong TL-scheme specified: %s at %d\n", p.get_error(), static_cast<int>(p.get_error_pos()));
+ std::abort();
+ }
+
+ return res;
+}
+
+int tl_config_parser::get_schema_version(std::int32_t version_id) {
+ if (version_id == TLS_SCHEMA_V4) {
+ return 4;
+ }
+ if (version_id == TLS_SCHEMA_V3) {
+ return 3;
+ }
+ if (version_id == TLS_SCHEMA_V2) {
+ return 2;
+ }
+ return -1;
+}
+
+tl_tree *tl_config_parser::read_num_const() {
+ int num = static_cast<int>(try_parse_int());
+
+ return new tl_tree_nat_const(FLAG_NOVAR, num);
+}
+
+tl_tree *tl_config_parser::read_num_var(int *var_count) {
+ std::int32_t diff = try_parse_int();
+ int var_num = static_cast<int>(try_parse_int());
+
+ if (var_num >= *var_count) {
+ *var_count = var_num + 1;
+ }
+
+ return new tl_tree_var_num(0, var_num, diff);
+}
+
+tl_tree *tl_config_parser::read_type_var(int *var_count) {
+ int var_num = static_cast<int>(try_parse_int());
+ std::int32_t flags = try_parse_int();
+
+ if (var_num >= *var_count) {
+ *var_count = var_num + 1;
+ }
+ assert(!(flags & (FLAG_NOVAR | FLAG_BARE)));
+
+ return new tl_tree_var_type(flags, var_num);
+}
+
+tl_tree *tl_config_parser::read_array(int *var_count) {
+ std::int32_t flags = FLAG_NOVAR;
+ tl_tree *multiplicity = read_nat_expr(var_count);
+
+ tl_tree_array *T = new tl_tree_array(flags, multiplicity, read_args_list(var_count));
+
+ for (std::size_t i = 0; i < T->args.size(); i++) {
+ if (!(T->args[i].flags & FLAG_NOVAR)) {
+ T->flags &= ~FLAG_NOVAR;
+ }
+ }
+ return T;
+}
+
+tl_tree *tl_config_parser::read_type(int *var_count) {
+ tl_type *type = config.get_type(try_parse_int());
+ assert(type != NULL);
+ std::int32_t flags = try_parse_int() | FLAG_NOVAR;
+ int arity = static_cast<int>(try_parse_int());
+ assert(type->arity == arity);
+
+ tl_tree_type *T = new tl_tree_type(flags, type, arity);
+ for (std::int32_t i = 0; i < arity; i++) {
+ tl_tree *child = read_expr(var_count);
+
+ T->children[i] = child;
+ if (!(child->flags & FLAG_NOVAR)) {
+ T->flags &= ~FLAG_NOVAR;
+ }
+ }
+ return T;
+}
+
+tl_tree *tl_config_parser::read_type_expr(int *var_count) {
+ std::int32_t tree_type = try_parse_int();
+ switch (tree_type) {
+ case TLS_TYPE_VAR:
+ return read_type_var(var_count);
+ case TLS_TYPE_EXPR:
+ return read_type(var_count);
+ case TLS_ARRAY:
+ return read_array(var_count);
+ default:
+ std::fprintf(stderr, "tree_type = %d\n", static_cast<int>(tree_type));
+ std::abort();
+ }
+}
+
+tl_tree *tl_config_parser::read_nat_expr(int *var_count) {
+ std::int32_t tree_type = try_parse_int();
+ switch (tree_type) {
+ case TLS_NAT_CONST_OLD:
+ case TLS_NAT_CONST:
+ return read_num_const();
+ case TLS_NAT_VAR:
+ return read_num_var(var_count);
+ default:
+ std::fprintf(stderr, "tree_type = %d\n", static_cast<int>(tree_type));
+ std::abort();
+ }
+}
+
+tl_tree *tl_config_parser::read_expr(int *var_count) {
+ std::int32_t tree_type = try_parse_int();
+ switch (tree_type) {
+ case TLS_EXPR_NAT:
+ return read_nat_expr(var_count);
+ case TLS_EXPR_TYPE:
+ return read_type_expr(var_count);
+ default:
+ std::fprintf(stderr, "tree_type = %d\n", static_cast<int>(tree_type));
+ std::abort();
+ }
+}
+
+std::vector<arg> tl_config_parser::read_args_list(int *var_count) {
+ const int schema_flag_opt_field = 2 << static_cast<int>(schema_version >= 3);
+ const int schema_flag_has_vars = schema_flag_opt_field ^ 6;
+
+ std::size_t args_num = static_cast<size_t>(try_parse_int());
+ std::vector<arg> args(args_num);
+ for (std::size_t i = 0; i < args_num; i++) {
+ arg cur_arg;
+
+ std::int32_t arg_v = try_parse_int();
+ if (arg_v != TLS_ARG_V2) {
+ std::fprintf(stderr, "Wrong tls_arg magic %d\n", static_cast<int>(arg_v));
+ std::abort();
+ }
+
+ cur_arg.name = try_parse_string();
+ cur_arg.flags = try_parse_int();
+
+ bool is_optional = false;
+ if (cur_arg.flags & schema_flag_opt_field) {
+ cur_arg.flags &= ~schema_flag_opt_field;
+ is_optional = true;
+ }
+ if (cur_arg.flags & schema_flag_has_vars) {
+ cur_arg.flags &= ~schema_flag_has_vars;
+ cur_arg.var_num = static_cast<int>(try_parse_int());
+ } else {
+ cur_arg.var_num = -1;
+ }
+
+ if (cur_arg.var_num >= *var_count) {
+ *var_count = cur_arg.var_num + 1;
+ }
+ if (is_optional) {
+ cur_arg.exist_var_num = static_cast<int>(try_parse_int());
+ cur_arg.exist_var_bit = static_cast<int>(try_parse_int());
+ } else {
+ cur_arg.exist_var_num = -1;
+ cur_arg.exist_var_bit = 0;
+ }
+ cur_arg.type = read_type_expr(var_count);
+ if (/*cur_arg.var_num < 0 && cur_arg.exist_var_num < 0 && */ (cur_arg.type->flags & FLAG_NOVAR)) {
+ cur_arg.flags |= FLAG_NOVAR;
+ }
+
+ args[i] = cur_arg;
+ }
+ return args;
+}
+
+tl_combinator *tl_config_parser::read_combinator() {
+ std::int32_t t = try_parse_int();
+ if (t != TLS_COMBINATOR) {
+ std::fprintf(stderr, "Wrong tls_combinator magic %d\n", static_cast<int>(t));
+ std::abort();
+ }
+
+ tl_combinator *combinator = new tl_combinator();
+ combinator->id = try_parse_int();
+ combinator->name = try_parse_string();
+ combinator->type_id = try_parse_int();
+ combinator->var_count = 0;
+
+ std::int32_t left_type = try_parse_int();
+ if (left_type == TLS_COMBINATOR_LEFT) {
+ combinator->args = read_args_list(&combinator->var_count);
+ } else {
+ if (left_type != TLS_COMBINATOR_LEFT_BUILTIN) {
+ std::fprintf(stderr, "Wrong tls_combinator_left magic %d\n", static_cast<int>(left_type));
+ std::abort();
+ }
+ }
+
+ std::int32_t right_ver = try_parse_int();
+ if (right_ver != TLS_COMBINATOR_RIGHT_V2) {
+ std::fprintf(stderr, "Wrong tls_combinator_right magic %d\n", static_cast<int>(right_ver));
+ std::abort();
+ }
+ combinator->result = read_type_expr(&combinator->var_count);
+
+ return combinator;
+}
+
+tl_type *tl_config_parser::read_type() {
+ std::int32_t t = try_parse_int();
+ if (t != TLS_TYPE) {
+ std::fprintf(stderr, "Wrong tls_type magic %d\n", t);
+ std::abort();
+ }
+
+ tl_type *type = new tl_type();
+ type->id = try_parse_int();
+ type->name = try_parse_string();
+ type->constructors_num = static_cast<std::size_t>(try_parse_int());
+ type->constructors.reserve(type->constructors_num);
+ type->flags = try_parse_int();
+ type->flags &= ~(1 | 8 | 16 | 1024);
+ if (type->flags != 0) {
+ std::fprintf(stderr, "Type %s has non-zero flags: %d\n", type->name.c_str(), static_cast<int>(type->flags));
+ }
+ type->arity = static_cast<int>(try_parse_int());
+
+ try_parse_long(); // unused
+ return type;
+}
+
+tl_config tl_config_parser::parse_config() {
+ schema_version = get_schema_version(try_parse_int());
+ if (schema_version < 2) {
+ std::fprintf(stderr, "Unsupported tl-schema verdion %d\n", static_cast<int>(schema_version));
+ std::abort();
+ }
+
+ try_parse_int(); // date
+ try_parse_int(); // version
+
+ std::int32_t types_n = try_parse_int();
+ std::size_t constructors_total = 0;
+ for (std::int32_t i = 0; i < types_n; i++) {
+ tl_type *type = read_type();
+ config.add_type(type);
+ constructors_total += type->constructors_num;
+ }
+
+ std::int32_t constructors_n = try_parse_int();
+ assert(static_cast<std::size_t>(constructors_n) == constructors_total);
+ for (std::int32_t i = 0; i < constructors_n; i++) {
+ tl_combinator *constructor = read_combinator();
+ config.get_type(constructor->type_id)->add_constructor(constructor);
+ }
+
+ std::int32_t functions_n = try_parse_int();
+ for (std::int32_t i = 0; i < functions_n; i++) {
+ config.add_function(read_combinator());
+ }
+ p.fetch_end();
+ try_parse(0);
+
+ return config;
+}
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_config.h b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_config.h
new file mode 100644
index 0000000000..6a25a9cd09
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_config.h
@@ -0,0 +1,87 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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 "tl_core.h"
+#include "tl_simple_parser.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace td {
+namespace tl {
+
+class tl_config {
+ std::vector<tl_type *> types;
+ std::map<std::int32_t, tl_type *> id_to_type;
+ std::map<std::string, tl_type *> name_to_type;
+
+ std::vector<tl_combinator *> functions;
+ std::map<std::int32_t, tl_combinator *> id_to_function;
+ std::map<std::string, tl_combinator *> name_to_function;
+
+ public:
+ void add_type(tl_type *type);
+
+ tl_type *get_type(std::int32_t type_id) const;
+
+ tl_type *get_type(const std::string &type_name);
+
+ void add_function(tl_combinator *function);
+
+ tl_combinator *get_function(std::int32_t function_id);
+
+ tl_combinator *get_function(const std::string &function_name);
+
+ std::size_t get_type_count() const;
+
+ tl_type *get_type_by_num(std::size_t num) const;
+
+ std::size_t get_function_count() const;
+
+ tl_combinator *get_function_by_num(std::size_t num) const;
+};
+
+class tl_config_parser {
+ tl_simple_parser p;
+ int schema_version;
+ tl_config config;
+
+ static int get_schema_version(std::int32_t version_id);
+
+ tl_tree *read_num_const();
+ tl_tree *read_num_var(int *var_count);
+ tl_tree *read_type_var(int *var_count);
+ tl_tree *read_array(int *var_count);
+ tl_tree *read_type(int *var_count);
+ tl_tree *read_type_expr(int *var_count);
+ tl_tree *read_nat_expr(int *var_count);
+ tl_tree *read_expr(int *var_count);
+ std::vector<arg> read_args_list(int *var_count);
+
+ tl_combinator *read_combinator();
+ tl_type *read_type();
+
+ template <class T>
+ T try_parse(const T &res) const;
+
+ std::int32_t try_parse_int();
+ std::int64_t try_parse_long();
+ std::string try_parse_string();
+
+ public:
+ tl_config_parser(const char *s, std::size_t len) : p(s, len) {
+ }
+
+ tl_config parse_config();
+};
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_core.cpp b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_core.cpp
new file mode 100644
index 0000000000..f8aa6eb10d
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_core.cpp
@@ -0,0 +1,21 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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)
+//
+#include "tl_core.h"
+
+#include <cassert>
+
+namespace td {
+namespace tl {
+
+void tl_type::add_constructor(tl_combinator *new_constructor) {
+ constructors.push_back(new_constructor);
+
+ assert(constructors.size() <= constructors_num);
+}
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_core.h b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_core.h
new file mode 100644
index 0000000000..04fabe1168
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_core.h
@@ -0,0 +1,159 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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 <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace td {
+namespace tl {
+
+const int NODE_TYPE_TYPE = 1;
+const int NODE_TYPE_NAT_CONST = 2;
+const int NODE_TYPE_VAR_TYPE = 3;
+const int NODE_TYPE_VAR_NUM = 4;
+const int NODE_TYPE_ARRAY = 5;
+
+const std::int32_t ID_VAR_NUM = 0x70659eff;
+const std::int32_t ID_VAR_TYPE = 0x2cecf817;
+const std::int32_t ID_INT = 0xa8509bda;
+const std::int32_t ID_LONG = 0x22076cba;
+const std::int32_t ID_DOUBLE = 0x2210c154;
+const std::int32_t ID_STRING = 0xb5286e24;
+const std::int32_t ID_VECTOR = 0x1cb5c415;
+const std::int32_t ID_DICTIONARY = 0x1f4c618f;
+const std::int32_t ID_MAYBE_TRUE = 0x3f9c8ef8;
+const std::int32_t ID_MAYBE_FALSE = 0x27930a7b;
+const std::int32_t ID_BOOL_FALSE = 0xbc799737;
+const std::int32_t ID_BOOL_TRUE = 0x997275b5;
+
+const std::int32_t FLAG_OPT_VAR = (1 << 17);
+const std::int32_t FLAG_EXCL = (1 << 18);
+const std::int32_t FLAG_NOVAR = (1 << 21);
+const std::int32_t FLAG_DEFAULT_CONSTRUCTOR = (1 << 25);
+const std::int32_t FLAG_BARE = (1 << 0);
+const std::int32_t FLAG_COMPLEX = (1 << 1);
+const std::int32_t FLAGS_MASK = ((1 << 16) - 1);
+
+class tl_combinator;
+
+class tl_tree;
+
+class tl_type {
+ public:
+ std::int32_t id;
+ std::string name;
+ int arity;
+ std::int32_t flags;
+ int simple_constructors;
+ std::size_t constructors_num;
+ std::vector<tl_combinator *> constructors;
+
+ void add_constructor(tl_combinator *new_constructor);
+};
+
+class arg {
+ public:
+ std::string name;
+ std::int32_t flags;
+ int var_num;
+ int exist_var_num;
+ int exist_var_bit;
+ tl_tree *type;
+};
+
+class tl_combinator {
+ public:
+ std::int32_t id;
+ std::string name;
+ int var_count;
+ std::int32_t type_id;
+ std::vector<arg> args;
+ tl_tree *result;
+};
+
+class tl_tree {
+ public:
+ std::int32_t flags;
+
+ explicit tl_tree(std::int32_t flags) : flags(flags) {
+ }
+
+ virtual int get_type() const = 0;
+
+ virtual ~tl_tree() {
+ }
+};
+
+class tl_tree_type : public tl_tree {
+ public:
+ tl_type *type;
+ std::vector<tl_tree *> children;
+
+ tl_tree_type(std::int32_t flags, tl_type *type, int child_count) : tl_tree(flags), type(type), children(child_count) {
+ }
+
+ virtual int get_type() const {
+ return NODE_TYPE_TYPE;
+ }
+};
+
+class tl_tree_nat_const : public tl_tree {
+ public:
+ int num;
+
+ tl_tree_nat_const(std::int32_t flags, int num) : tl_tree(flags), num(num) {
+ }
+
+ virtual int get_type() const {
+ return NODE_TYPE_NAT_CONST;
+ }
+};
+
+class tl_tree_var_type : public tl_tree {
+ public:
+ int var_num;
+
+ tl_tree_var_type(std::int32_t flags, int var_num) : tl_tree(flags), var_num(var_num) {
+ }
+
+ virtual int get_type() const {
+ return NODE_TYPE_VAR_TYPE;
+ }
+};
+
+class tl_tree_var_num : public tl_tree {
+ public:
+ int var_num;
+ int diff;
+
+ tl_tree_var_num(std::int32_t flags, int var_num, int diff) : tl_tree(flags), var_num(var_num), diff(diff) {
+ }
+
+ virtual int get_type() const {
+ return NODE_TYPE_VAR_NUM;
+ }
+};
+
+class tl_tree_array : public tl_tree {
+ public:
+ tl_tree *multiplicity;
+ std::vector<arg> args;
+
+ tl_tree_array(std::int32_t flags, tl_tree *multiplicity, const std::vector<arg> &a)
+ : tl_tree(flags), multiplicity(multiplicity), args(a) {
+ }
+
+ virtual int get_type() const {
+ return NODE_TYPE_ARRAY;
+ }
+};
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_outputer.cpp b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_outputer.cpp
new file mode 100644
index 0000000000..046a1ce84e
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_outputer.cpp
@@ -0,0 +1,41 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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)
+//
+#include "tl_file_outputer.h"
+
+#include <cassert>
+
+namespace td {
+namespace tl {
+
+void tl_file_outputer::append(const std::string &str) {
+ assert(f != NULL);
+ std::fprintf(f, "%s", str.c_str());
+}
+
+tl_file_outputer::tl_file_outputer() : f(NULL) {
+}
+
+void tl_file_outputer::close() {
+ if (f) {
+ std::fclose(f);
+ }
+}
+
+bool tl_file_outputer::open(const std::string &file_name) {
+ close();
+
+ f = std::fopen(file_name.c_str(), "w");
+
+ return (f != NULL);
+}
+
+tl_file_outputer::~tl_file_outputer() {
+ close();
+}
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_outputer.h b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_outputer.h
new file mode 100644
index 0000000000..3b9c66caaf
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_outputer.h
@@ -0,0 +1,33 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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 "tl_outputer.h"
+
+#include <cstdio>
+#include <string>
+
+namespace td {
+namespace tl {
+
+class tl_file_outputer : public tl_outputer {
+ FILE *f;
+
+ void close();
+
+ public:
+ tl_file_outputer();
+
+ bool open(const std::string &file_name);
+
+ virtual void append(const std::string &str);
+
+ virtual ~tl_file_outputer();
+};
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_utils.cpp b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_utils.cpp
new file mode 100644
index 0000000000..bc79d7254e
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_utils.cpp
@@ -0,0 +1,92 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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)
+//
+#include "tl_file_utils.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+namespace td {
+namespace tl {
+
+std::string get_file_contents(const std::string &file_name, const std::string &mode) {
+ FILE *f = std::fopen(file_name.c_str(), mode.c_str());
+ if (f == NULL) {
+ return std::string();
+ }
+
+ int fseek_res = std::fseek(f, 0, SEEK_END);
+ if (fseek_res != 0) {
+ std::fprintf(stderr, "Can't seek to the end of the file \"%s\"", file_name.c_str());
+ std::abort();
+ }
+ long size_long = std::ftell(f);
+ if (size_long < 0 || size_long >= (1 << 25)) {
+ std::fprintf(stderr, "Wrong file \"%s\" has wrong size = %ld", file_name.c_str(), size_long);
+ std::abort();
+ }
+ std::size_t size = static_cast<std::size_t>(size_long);
+
+ std::string result(size, ' ');
+ std::rewind(f);
+ std::size_t fread_res = std::fread(&result[0], size, 1, f);
+ if (size != 0 && fread_res != 1) {
+ std::fprintf(stderr, "Can't read file \"%s\"", file_name.c_str());
+ std::abort();
+ }
+ std::fclose(f);
+
+ return result;
+}
+
+bool put_file_contents(const std::string &file_name, const std::string &mode, const std::string &contents) {
+ FILE *f = std::fopen(file_name.c_str(), mode.c_str());
+ if (f == NULL) {
+ std::fprintf(stderr, "Can't open file \"%s\"\n", file_name.c_str());
+ return false;
+ }
+
+ std::size_t fwrite_res = std::fwrite(contents.c_str(), contents.size(), 1, f);
+ if (fwrite_res != 1) {
+ std::fclose(f);
+ return false;
+ }
+ if (std::fclose(f) != 0) {
+ return false;
+ }
+ return true;
+}
+
+std::string remove_documentation(const std::string &str) {
+ std::size_t line_begin = 0;
+ std::string result;
+ bool inside_documentation = false;
+ while (line_begin < str.size()) {
+ std::size_t line_end = str.find('\n', line_begin);
+ if (line_end == std::string::npos) {
+ line_end = str.size() - 1;
+ }
+ std::string line = str.substr(line_begin, line_end - line_begin + 1);
+ line_begin = line_end + 1;
+
+ std::size_t pos = line.find_first_not_of(' ');
+ if (pos != std::string::npos && ((line[pos] == '/' && line[pos + 1] == '/' && line[pos + 2] == '/') ||
+ (line[pos] == '/' && line[pos + 1] == '*' && line[pos + 2] == '*') ||
+ (inside_documentation && line[pos] == '*'))) {
+ inside_documentation = !(line[pos] == '/' && line[pos + 1] == '/' && line[pos + 2] == '/') &&
+ !(line[pos] == '*' && line[pos + 1] == '/');
+ continue;
+ }
+
+ inside_documentation = false;
+ result += line;
+ }
+ return result;
+}
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_utils.h b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_utils.h
new file mode 100644
index 0000000000..50e40b4418
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_file_utils.h
@@ -0,0 +1,21 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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 <string>
+
+namespace td {
+namespace tl {
+
+std::string get_file_contents(const std::string &file_name, const std::string &mode);
+
+bool put_file_contents(const std::string &file_name, const std::string &mode, const std::string &contents);
+
+std::string remove_documentation(const std::string &str);
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_generate.cpp b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_generate.cpp
new file mode 100644
index 0000000000..401d451cd6
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_generate.cpp
@@ -0,0 +1,843 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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)
+//
+#include "tl_generate.h"
+
+#include "tl_config.h"
+#include "tl_core.h"
+#include "tl_file_utils.h"
+#include "tl_outputer.h"
+#include "tl_string_outputer.h"
+#include "tl_writer.h"
+
+#include <cassert>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <set>
+#include <string>
+#include <vector>
+
+namespace td {
+namespace tl {
+
+static bool is_reachable_for_parser(int parser_type, const std::string &name,
+ const std::set<std::string> &request_types,
+ const std::set<std::string> &result_types, const TL_writer &w) {
+ TL_writer::Mode mode = w.get_parser_mode(parser_type);
+ if (mode == TL_writer::Client) {
+ return result_types.count(name) > 0;
+ }
+ if (mode == TL_writer::Server) {
+ return request_types.count(name) > 0;
+ }
+ return true;
+}
+
+static bool is_reachable_for_storer(int storer_type, const std::string &name,
+ const std::set<std::string> &request_types,
+ const std::set<std::string> &result_types, const TL_writer &w) {
+ TL_writer::Mode mode = w.get_storer_mode(storer_type);
+ if (mode == TL_writer::Client) {
+ return request_types.count(name) > 0;
+ }
+ if (mode == TL_writer::Server) {
+ return result_types.count(name) > 0;
+ }
+ return true;
+}
+
+static void write_class_constructor(tl_outputer &out, const tl_combinator *t, const std::string &class_name,
+ bool is_default, const TL_writer &w) {
+ // std::fprintf(stderr, "Gen constructor %s\n", class_name.c_str());
+ int fields_num = 0;
+ for (std::size_t i = 0; i < t->args.size(); i++) {
+ fields_num += !w.gen_constructor_parameter(0, class_name, t->args[i], is_default).empty();
+ }
+
+ out.append(w.gen_constructor_begin(fields_num, class_name, is_default));
+ int field_num = 0;
+ for (std::size_t i = 0; i < t->args.size(); i++) {
+ std::string parameter_init = w.gen_constructor_parameter(field_num, class_name, t->args[i], is_default);
+ if (parameter_init.size()) {
+ out.append(parameter_init);
+ field_num++;
+ }
+ }
+ assert(field_num == fields_num);
+
+ field_num = 0;
+ for (std::size_t i = 0; i < t->args.size(); i++) {
+ std::string field_init = w.gen_constructor_field_init(field_num, class_name, t->args[i], is_default);
+ if (field_init.size()) {
+ out.append(field_init);
+ field_num++;
+ }
+ }
+
+ out.append(w.gen_constructor_end(t, field_num, is_default));
+}
+
+static void write_function_fetch(tl_outputer &out, const std::string &parser_name, const tl_combinator *t,
+ const std::string &class_name, const std::set<std::string> &request_types,
+ const std::set<std::string> &result_types, const TL_writer &w) {
+ // std::fprintf(stderr, "Write function fetch %s\n", class_name.c_str());
+ std::vector<var_description> vars(t->var_count);
+ int parser_type = w.get_parser_type(t, parser_name);
+
+ if (!is_reachable_for_parser(parser_type, t->name, request_types, result_types, w)) {
+ return;
+ }
+
+ out.append(w.gen_fetch_function_begin(parser_name, class_name, 0, vars, parser_type));
+ out.append(w.gen_vars(t, NULL, vars));
+ int field_num = 0;
+ for (std::size_t i = 0; i < t->args.size(); i++) {
+ std::string field_fetch = w.gen_field_fetch(field_num, t->args[i], vars, false, parser_type);
+ if (field_fetch.size()) {
+ out.append(field_fetch);
+ field_num++;
+ }
+ }
+
+ out.append(w.gen_fetch_function_end(field_num, vars, parser_type));
+}
+
+static std::vector<var_description> write_function_store(tl_outputer &out, const std::string &storer_name,
+ const tl_combinator *t, const std::string &class_name,
+ std::vector<var_description> &vars,
+ const std::set<std::string> &request_types,
+ const std::set<std::string> &result_types,
+ const TL_writer &w) {
+ // std::fprintf(stderr, "Write function store %s\n", class_name.c_str());
+ int storer_type = w.get_storer_type(t, storer_name);
+
+ if (!is_reachable_for_storer(storer_type, t->name, request_types, result_types, w)) {
+ return vars;
+ }
+
+ out.append(w.gen_store_function_begin(storer_name, class_name, 0, vars, storer_type));
+ out.append(w.gen_constructor_id_store(t->id, storer_type));
+ for (std::size_t i = 0; i < t->args.size(); i++) {
+ out.append(w.gen_field_store(t->args[i], vars, false, storer_type));
+ }
+
+ out.append(w.gen_store_function_end(vars, storer_type));
+
+ return vars;
+}
+
+static void write_function_result_fetch(tl_outputer &out, const std::string &parser_name, const tl_combinator *t,
+ const std::string &class_name, const tl_tree *result,
+ const std::vector<var_description> &vars, const TL_writer &w) {
+ // std::fprintf(stderr, "Write function result fetch %s\n", class_name.c_str());
+ int parser_type = w.get_parser_type(t, parser_name);
+
+ out.append(w.gen_fetch_function_result_begin(parser_name, class_name, result));
+
+ if (result->get_type() == NODE_TYPE_VAR_TYPE) {
+ const tl_tree_var_type *result_var_type = static_cast<const tl_tree_var_type *>(result);
+
+ for (std::size_t i = 0; i < t->args.size(); i++) {
+ const arg &a = t->args[i];
+
+ int arg_type = a.type->get_type();
+ if (arg_type == NODE_TYPE_VAR_TYPE) {
+ const tl_tree_var_type *tree_var_type = static_cast<const tl_tree_var_type *>(a.type);
+ assert(a.flags & FLAG_EXCL);
+ assert(tree_var_type->var_num >= 0);
+ if (tree_var_type->var_num == result_var_type->var_num) {
+ out.append(w.gen_var_type_fetch(a));
+ }
+ }
+ }
+ } else {
+ assert(result->get_type() == NODE_TYPE_TYPE);
+ const tl_tree_type *result_type = static_cast<const tl_tree_type *>(result);
+ out.append(w.gen_type_fetch("", result_type, vars, parser_type));
+ }
+
+ out.append(w.gen_fetch_function_result_end());
+
+ out.append(w.gen_fetch_function_result_any_begin(parser_name, class_name, false));
+ out.append(w.gen_fetch_function_result_any_end(false));
+}
+
+static void write_constructor_fetch(tl_outputer &out, const std::string &parser_name, const tl_combinator *t,
+ const std::string &class_name, const tl_tree_type *result_type, bool is_flat,
+ const std::set<std::string> &request_types,
+ const std::set<std::string> &result_types, const TL_writer &w) {
+ std::vector<var_description> vars(t->var_count);
+
+ int parser_type = w.get_parser_type(t, parser_name);
+
+ if (!is_reachable_for_parser(parser_type, t->name, request_types, result_types, w)) {
+ return;
+ }
+
+ out.append(w.gen_fetch_function_begin(parser_name, class_name, static_cast<int>(result_type->children.size()), vars,
+ parser_type));
+ out.append(w.gen_vars(t, result_type, vars));
+ out.append(w.gen_uni(result_type, vars, true));
+ int field_num = 0;
+ for (std::size_t i = 0; i < t->args.size(); i++) {
+ std::string field_fetch = w.gen_field_fetch(field_num, t->args[i], vars, is_flat, parser_type);
+ if (field_fetch.size()) {
+ out.append(field_fetch);
+ field_num++;
+ }
+ }
+
+ out.append(w.gen_fetch_function_end(field_num, vars, parser_type));
+}
+
+static void write_constructor_store(tl_outputer &out, const std::string &storer_name, const tl_combinator *t,
+ const std::string &class_name, const tl_tree_type *result_type, bool is_flat,
+ const std::set<std::string> &request_types,
+ const std::set<std::string> &result_types, const TL_writer &w) {
+ std::vector<var_description> vars(t->var_count);
+ int storer_type = w.get_storer_type(t, storer_name);
+
+ if (!is_reachable_for_storer(storer_type, t->name, request_types, result_types, w)) {
+ return;
+ }
+
+ out.append(w.gen_store_function_begin(storer_name, class_name, static_cast<int>(result_type->children.size()), vars,
+ storer_type));
+ out.append(w.gen_vars(t, result_type, vars));
+ out.append(w.gen_uni(result_type, vars, false));
+ for (std::size_t i = 0; i < t->args.size(); i++) {
+ // std::fprintf(stderr, "%s: %s\n", result_type->type->name.c_str(), t->name.c_str());
+ out.append(w.gen_field_store(t->args[i], vars, is_flat, storer_type));
+ }
+
+ out.append(w.gen_store_function_end(vars, storer_type));
+}
+
+static int gen_field_definitions(tl_outputer &out, const tl_combinator *t, const std::string &class_name,
+ const TL_writer &w) {
+ int required_args = 0;
+
+ for (std::size_t i = 0; i < t->args.size(); i++) {
+ const arg &a = t->args[i];
+
+ assert(-1 <= a.var_num && a.var_num < t->var_count);
+
+ required_args += !(a.flags & FLAG_OPT_VAR);
+
+ if (a.flags & FLAG_OPT_VAR) {
+ // continue;
+ }
+
+ std::string type_name = w.gen_field_type(a);
+ if (type_name.size()) {
+ out.append(w.gen_field_definition(class_name, type_name, w.gen_field_name(a.name)));
+ }
+ }
+
+ return required_args;
+}
+
+static void write_function(tl_outputer &out, const tl_combinator *t, const std::set<std::string> &request_types,
+ const std::set<std::string> &result_types, const TL_writer &w) {
+ assert(w.is_combinator_supported(t));
+
+ std::string class_name = w.gen_class_name(t->name);
+
+ out.append(w.gen_class_begin(class_name, w.gen_base_function_class_name(), false));
+
+ int required_args = gen_field_definitions(out, t, class_name, w);
+ out.append(w.gen_flags_definitions(t));
+
+ std::vector<var_description> vars(t->var_count);
+ out.append(w.gen_function_vars(t, vars));
+
+ write_class_constructor(out, t, class_name, true, w);
+ if (required_args) {
+ write_class_constructor(out, t, class_name, false, w);
+ }
+
+ out.append(w.gen_get_id(class_name, t->id, false));
+
+ out.append(w.gen_function_result_type(t->result));
+
+ // PARSER
+ std::vector<std::string> parsers = w.get_parsers();
+ for (std::size_t i = 0; i < parsers.size(); i++) {
+ write_function_fetch(out, parsers[i], t, class_name, request_types, result_types, w);
+ }
+
+ // STORER
+ std::vector<std::string> storers = w.get_storers();
+ for (std::size_t i = 0; i < storers.size(); i++) {
+ write_function_store(out, storers[i], t, class_name, vars, request_types, result_types, w);
+ }
+
+ // PARSE RESULT
+ for (std::size_t i = 0; i < parsers.size(); i++) {
+ if (w.get_parser_mode(-1) == TL_writer::Server) {
+ continue;
+ }
+
+ write_function_result_fetch(out, parsers[i], t, class_name, t->result, vars, w);
+ }
+
+ // ADDITIONAL FUNCTIONS
+ std::vector<std::string> additional_functions = w.get_additional_functions();
+ for (std::size_t i = 0; i < additional_functions.size(); i++) {
+ out.append(w.gen_additional_function(additional_functions[i], t, true));
+ }
+
+ out.append(w.gen_class_end());
+}
+
+static void write_constructor(tl_outputer &out, const tl_combinator *t, const std::string &base_class, bool is_proxy,
+ const std::set<std::string> &request_types, const std::set<std::string> &result_types,
+ const TL_writer &w) {
+ assert(w.is_combinator_supported(t));
+
+ std::string class_name = w.gen_class_name(t->name);
+
+ out.append(w.gen_class_begin(class_name, base_class, is_proxy));
+ int required_args = gen_field_definitions(out, t, class_name, w);
+ out.append(w.gen_flags_definitions(t));
+
+ write_class_constructor(out, t, class_name, true, w);
+ if (required_args) {
+ write_class_constructor(out, t, class_name, false, w);
+ }
+
+ out.append(w.gen_get_id(class_name, t->id, false));
+
+ // PARSER
+ assert(t->result->get_type() == NODE_TYPE_TYPE);
+ const tl_tree_type *result_type = static_cast<const tl_tree_type *>(t->result);
+
+ std::vector<std::string> parsers = w.get_parsers();
+ for (std::size_t i = 0; i < parsers.size(); i++) {
+ write_constructor_fetch(out, parsers[i], t, class_name, result_type,
+ required_args == 1 && result_type->type->simple_constructors == 1, request_types,
+ result_types, w);
+ }
+
+ // STORER
+ std::vector<std::string> storers = w.get_storers();
+ for (std::size_t i = 0; i < storers.size(); i++) {
+ write_constructor_store(out, storers[i], t, class_name, result_type,
+ required_args == 1 && result_type->type->simple_constructors == 1, request_types,
+ result_types, w);
+ }
+
+ // ADDITIONAL FUNCTIONS
+ std::vector<std::string> additional_functions = w.get_additional_functions();
+ for (std::size_t i = 0; i < additional_functions.size(); i++) {
+ out.append(w.gen_additional_function(additional_functions[i], t, false));
+ }
+
+ out.append(w.gen_class_end());
+}
+
+void write_class(tl_outputer &out, const tl_type *t, const std::set<std::string> &request_types,
+ const std::set<std::string> &result_types, const TL_writer &w) {
+ assert(t->constructors_num > 0);
+ assert(!w.is_built_in_simple_type(t->name));
+ assert(!w.is_built_in_complex_type(t->name));
+ assert(!(t->flags & FLAG_COMPLEX));
+
+ assert(t->arity >= 0);
+ assert(t->simple_constructors > 0);
+ assert(t->flags == 0);
+
+ const std::string base_class = w.gen_base_type_class_name(t->arity);
+ const std::string class_name = w.gen_class_name(t->name);
+
+ std::vector<var_description> empty_vars;
+ bool optimize_one_constructor = (t->simple_constructors == 1);
+ if (!optimize_one_constructor) {
+ out.append(w.gen_class_begin(class_name, base_class, true));
+
+ out.append(w.gen_get_id(class_name, 0, true));
+
+ std::vector<std::string> parsers = w.get_parsers();
+ for (std::size_t i = 0; i < parsers.size(); i++) {
+ if (!is_reachable_for_parser(-1, t->name, request_types, result_types, w)) {
+ continue;
+ }
+
+ out.append(w.gen_fetch_function_begin(parsers[i], class_name, t->arity, empty_vars, -1));
+ out.append(w.gen_fetch_switch_begin());
+ for (std::size_t j = 0; j < t->constructors_num; j++) {
+ if (w.is_combinator_supported(t->constructors[j])) {
+ out.append(w.gen_fetch_switch_case(t->constructors[j], t->arity));
+ }
+ }
+
+ out.append(w.gen_fetch_switch_end());
+ out.append(w.gen_fetch_function_end(-1, empty_vars, -1));
+ }
+
+ std::vector<std::string> storers = w.get_storers();
+ for (std::size_t i = 0; i < storers.size(); i++) {
+ if (!is_reachable_for_storer(-1, t->name, request_types, result_types, w)) {
+ continue;
+ }
+
+ out.append(w.gen_store_function_begin(storers[i], class_name, t->arity, empty_vars, -1));
+ out.append(w.gen_store_function_end(empty_vars, -1));
+ }
+
+ std::vector<std::string> additional_functions = w.get_additional_functions();
+ for (std::size_t i = 0; i < additional_functions.size(); i++) {
+ out.append(w.gen_additional_proxy_function_begin(additional_functions[i], t, class_name, t->arity, false));
+ for (std::size_t j = 0; j < t->constructors_num; j++) {
+ if (w.is_combinator_supported(t->constructors[j])) {
+ out.append(
+ w.gen_additional_proxy_function_case(additional_functions[i], t, t->constructors[j], t->arity, false));
+ }
+ }
+
+ out.append(w.gen_additional_proxy_function_end(additional_functions[i], t, false));
+ }
+
+ out.append(w.gen_class_end());
+ }
+
+ int written_constructors = 0;
+ for (std::size_t i = 0; i < t->constructors_num; i++) {
+ if (w.is_combinator_supported(t->constructors[i])) {
+ if (optimize_one_constructor) {
+ write_constructor(out, t->constructors[i], base_class, false, request_types, result_types, w);
+ out.append(w.gen_class_alias(w.gen_class_name(t->constructors[i]->name), class_name));
+ } else {
+ write_constructor(out, t->constructors[i], class_name, false, request_types, result_types, w);
+ }
+ written_constructors++;
+ } else {
+ std::fprintf(stderr, "Skip complex constructor %s of %s\n", t->constructors[i]->name.c_str(), t->name.c_str());
+ }
+ }
+ assert(written_constructors == t->simple_constructors);
+}
+
+static void dfs_type(const tl_type *t, std::set<std::string> &found, const TL_writer &w);
+
+static void dfs_tree(const tl_tree *t, std::set<std::string> &found, const TL_writer &w) {
+ int type = t->get_type();
+
+ if (type == NODE_TYPE_ARRAY) {
+ const tl_tree_array *arr = static_cast<const tl_tree_array *>(t);
+ for (std::size_t i = 0; i < arr->args.size(); i++) {
+ dfs_tree(arr->args[i].type, found, w);
+ }
+ } else if (type == NODE_TYPE_TYPE) {
+ const tl_tree_type *tree_type = static_cast<const tl_tree_type *>(t);
+ dfs_type(tree_type->type, found, w);
+ for (std::size_t i = 0; i < tree_type->children.size(); i++) {
+ dfs_tree(tree_type->children[i], found, w);
+ }
+ } else {
+ assert(type == NODE_TYPE_VAR_TYPE);
+ }
+}
+
+static void dfs_combinator(const tl_combinator *constructor, std::set<std::string> &found, const TL_writer &w) {
+ if (!w.is_combinator_supported(constructor)) {
+ return;
+ }
+
+ if (!found.insert(constructor->name).second) {
+ return;
+ }
+
+ for (std::size_t i = 0; i < constructor->args.size(); i++) {
+ dfs_tree(constructor->args[i].type, found, w);
+ }
+}
+
+static void dfs_type(const tl_type *t, std::set<std::string> &found, const TL_writer &w) {
+ if (!found.insert(t->name).second) {
+ return;
+ }
+
+ if (t->constructors_num == 0 || w.is_built_in_simple_type(t->name) || w.is_built_in_complex_type(t->name)) {
+ return;
+ }
+
+ assert(!(t->flags & FLAG_COMPLEX));
+
+ for (std::size_t i = 0; i < t->constructors_num; i++) {
+ dfs_combinator(t->constructors[i], found, w);
+ }
+}
+
+void write_tl(const tl_config &config, tl_outputer &out, const TL_writer &w) {
+ out.append(w.gen_output_begin());
+
+ std::size_t types_n = config.get_type_count();
+ std::size_t functions_n = config.get_function_count();
+
+ bool found_complex = false;
+ for (std::size_t type = 0; type < types_n; type++) {
+ tl_type *t = config.get_type_by_num(type);
+ assert(t->constructors_num == t->constructors.size());
+ if (t->constructors_num == 0) { // built-in dummy types
+ if (t->name == "Type") {
+ assert(t->id == ID_VAR_TYPE);
+ t->flags |= FLAG_COMPLEX;
+ found_complex = true;
+ }
+ continue;
+ }
+
+ for (std::size_t j = 0; j < t->constructors_num; j++) {
+ tl_combinator *constructor = t->constructors[j];
+ assert(constructor->type_id == t->id);
+ assert(constructor->result->get_type() == NODE_TYPE_TYPE);
+ assert(static_cast<const tl_tree_type *>(constructor->result)->type == t);
+ assert(static_cast<const tl_tree_type *>(constructor->result)->children.size() ==
+ static_cast<std::size_t>(t->arity));
+ assert(static_cast<const tl_tree_type *>(constructor->result)->flags == (t->arity > 0 ? 0 : FLAG_NOVAR));
+
+ for (std::size_t k = 0; k < constructor->args.size(); k++) {
+ const arg &a = constructor->args[k];
+
+ assert(-1 <= a.var_num && a.var_num <= constructor->var_count);
+
+ int arg_type = a.type->get_type();
+ assert(arg_type == NODE_TYPE_TYPE || arg_type == NODE_TYPE_VAR_TYPE || arg_type == NODE_TYPE_ARRAY);
+ if (a.var_num >= 0) {
+ assert(arg_type == NODE_TYPE_TYPE);
+ assert(static_cast<const tl_tree_type *>(a.type)->type->id == ID_VAR_NUM ||
+ static_cast<const tl_tree_type *>(a.type)->type->id == ID_VAR_TYPE);
+ }
+
+ if (arg_type == NODE_TYPE_ARRAY) {
+ const tl_tree_array *arr = static_cast<const tl_tree_array *>(a.type);
+ assert(arr->multiplicity->get_type() == NODE_TYPE_NAT_CONST ||
+ arr->multiplicity->get_type() == NODE_TYPE_VAR_NUM);
+ for (std::size_t l = 0; l < arr->args.size(); l++) {
+ const arg &b = arr->args[l];
+ int b_arg_type = b.type->get_type();
+ if (b_arg_type == NODE_TYPE_VAR_TYPE || b_arg_type == NODE_TYPE_ARRAY || b.var_num != -1 ||
+ b.exist_var_num != -1) {
+ if (!w.is_built_in_complex_type(t->name)) {
+ t->flags |= FLAG_COMPLEX;
+ found_complex = true;
+ }
+ } else {
+ assert(b_arg_type == NODE_TYPE_TYPE);
+ }
+ assert(b.flags == FLAG_NOVAR || b.flags == 0);
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < t->arity; i++) {
+ int main_type = static_cast<const tl_tree_type *>(t->constructors[0]->result)->children[i]->get_type();
+ for (std::size_t j = 1; j < t->constructors_num; j++) {
+ assert(static_cast<const tl_tree_type *>(t->constructors[j]->result)->children[i]->get_type() == main_type);
+ }
+ assert(main_type == NODE_TYPE_VAR_TYPE || main_type == NODE_TYPE_VAR_NUM);
+ if (main_type == NODE_TYPE_VAR_TYPE) {
+ if (!w.is_built_in_complex_type(t->name)) {
+ t->flags |= FLAG_COMPLEX;
+ found_complex = true;
+ }
+ }
+ }
+ }
+
+ while (found_complex) {
+ found_complex = false;
+ for (std::size_t type = 0; type < types_n; type++) {
+ tl_type *t = config.get_type_by_num(type);
+ if (t->constructors_num == 0 || w.is_built_in_complex_type(t->name)) { // built-in dummy or complex types
+ continue;
+ }
+ if (t->flags & FLAG_COMPLEX) { // already complex
+ continue;
+ }
+
+ t->simple_constructors = 0;
+ for (std::size_t i = 0; i < t->constructors_num; i++) {
+ t->simple_constructors += w.is_combinator_supported(t->constructors[i]);
+ }
+ if (t->simple_constructors == 0) {
+ t->flags |= FLAG_COMPLEX;
+ found_complex = true;
+ // std::fprintf(stderr, "Found complex %s\n", t->name.c_str());
+ }
+ }
+ }
+
+ std::set<std::string> request_types;
+ std::set<std::string> result_types;
+ for (std::size_t function = 0; function < functions_n; function++) {
+ const tl_combinator *t = config.get_function_by_num(function);
+ dfs_combinator(t, request_types, w);
+ dfs_tree(t->result, result_types, w);
+ }
+
+ // write forward declarations
+ for (std::size_t type = 0; type < types_n; type++) {
+ tl_type *t = config.get_type_by_num(type);
+ if (t->constructors_num == 0 || w.is_built_in_simple_type(t->name) || w.is_built_in_complex_type(t->name) ||
+ (t->flags & FLAG_COMPLEX)) { // built-in or complex types
+ continue;
+ }
+
+ assert(t->flags == 0);
+
+ if (t->simple_constructors != 1) {
+ out.append(w.gen_forward_class_declaration(w.gen_class_name(t->name), true));
+ } else {
+ for (std::size_t i = 0; i < t->constructors_num; i++) {
+ if (w.is_combinator_supported(t->constructors[i])) {
+ out.append(w.gen_forward_class_declaration(w.gen_class_name(t->constructors[i]->name), false));
+ }
+ }
+ }
+ }
+ for (int i = 0; i <= w.get_max_arity(); i++) {
+ out.append(w.gen_forward_class_declaration(w.gen_base_type_class_name(i), true));
+ }
+
+ for (std::size_t function = 0; function < functions_n; function++) {
+ tl_combinator *t = config.get_function_by_num(function);
+ if (!w.is_combinator_supported(t)) {
+ continue;
+ }
+
+ // out.append(w.gen_forward_class_declaration(w.gen_class_name(t->name), false));
+ }
+ // out.append(w.gen_forward_class_declaration(w.gen_base_function_class_name(), true));
+
+ // write base classes
+ std::vector<var_description> empty_vars;
+ for (int i = 0; i <= w.get_max_arity(); i++) {
+ out.append(w.gen_class_begin(w.gen_base_type_class_name(i), w.gen_base_tl_class_name(), true));
+
+ out.append(w.gen_get_id(w.gen_base_type_class_name(i), 0, true));
+
+ std::vector<std::string> parsers = w.get_parsers();
+ for (std::size_t j = 0; j < parsers.size(); j++) {
+ int case_count = 0;
+ for (std::size_t type = 0; type < types_n; type++) {
+ tl_type *t = config.get_type_by_num(type);
+ if (t->constructors_num == 0 || w.is_built_in_simple_type(t->name) || w.is_built_in_complex_type(t->name) ||
+ (t->flags & FLAG_COMPLEX)) { // built-in or complex types
+ continue;
+ }
+ if (t->arity != i) { // additional condition
+ continue;
+ }
+
+ for (std::size_t k = 0; k < t->constructors_num; k++) {
+ if (w.is_combinator_supported(t->constructors[k]) &&
+ is_reachable_for_parser(-1, t->constructors[k]->name, request_types, result_types, w)) {
+ case_count++;
+ }
+ }
+ }
+
+ if (case_count == 0) {
+ continue;
+ }
+
+ out.append(w.gen_fetch_function_begin(parsers[j], w.gen_base_type_class_name(i), i, empty_vars, -1));
+ out.append(w.gen_fetch_switch_begin());
+ for (std::size_t type = 0; type < types_n; type++) {
+ tl_type *t = config.get_type_by_num(type);
+ if (t->constructors_num == 0 || w.is_built_in_simple_type(t->name) || w.is_built_in_complex_type(t->name) ||
+ (t->flags & FLAG_COMPLEX)) { // built-in or complex types
+ continue;
+ }
+ if (t->arity != i) { // additional condition
+ continue;
+ }
+
+ for (std::size_t k = 0; k < t->constructors_num; k++) {
+ if (w.is_combinator_supported(t->constructors[k]) &&
+ is_reachable_for_parser(-1, t->constructors[k]->name, request_types, result_types, w)) {
+ out.append(w.gen_fetch_switch_case(t->constructors[k], i));
+ }
+ }
+ }
+ out.append(w.gen_fetch_switch_end());
+ out.append(w.gen_fetch_function_end(-1, empty_vars, -1));
+ }
+
+ std::vector<std::string> additional_functions = w.get_additional_functions();
+ for (std::size_t j = 0; j < additional_functions.size(); j++) {
+ out.append(w.gen_additional_proxy_function_begin(additional_functions[j], NULL, w.gen_base_type_class_name(i), i,
+ false));
+ for (std::size_t type = 0; type < types_n; type++) {
+ tl_type *t = config.get_type_by_num(type);
+ if (t->constructors_num == 0 || w.is_built_in_simple_type(t->name) || w.is_built_in_complex_type(t->name) ||
+ (t->flags & FLAG_COMPLEX)) { // built-in or complex types
+ continue;
+ }
+ if (t->arity != i) { // additional condition
+ continue;
+ }
+
+ int function_type = w.get_additional_function_type(additional_functions[j]);
+ if ((function_type & 1) && t->simple_constructors != 1) {
+ out.append(w.gen_additional_proxy_function_case(additional_functions[j], NULL, w.gen_class_name(t->name), i));
+ }
+ if ((function_type & 2) || ((function_type & 1) && t->simple_constructors == 1)) {
+ for (std::size_t k = 0; k < t->constructors_num; k++) {
+ if (w.is_combinator_supported(t->constructors[k])) {
+ out.append(
+ w.gen_additional_proxy_function_case(additional_functions[j], NULL, t->constructors[k], i, false));
+ }
+ }
+ }
+ }
+
+ out.append(w.gen_additional_proxy_function_end(additional_functions[j], NULL, false));
+ }
+
+ std::vector<std::string> storers = w.get_storers();
+ for (std::size_t j = 0; j < storers.size(); j++) {
+ out.append(w.gen_store_function_begin(storers[j], w.gen_base_type_class_name(i), i, empty_vars, -1));
+ out.append(w.gen_store_function_end(empty_vars, -1));
+ }
+
+ out.append(w.gen_class_end());
+ }
+
+ {
+ out.append(w.gen_class_begin(w.gen_base_function_class_name(), w.gen_base_tl_class_name(), true));
+
+ out.append(w.gen_get_id(w.gen_base_function_class_name(), 0, true));
+
+ std::vector<std::string> parsers = w.get_parsers();
+ for (std::size_t j = 0; j < parsers.size(); j++) {
+ if (w.get_parser_mode(-1) == TL_writer::Client) {
+ continue;
+ }
+
+ out.append(w.gen_fetch_function_begin(parsers[j], w.gen_base_function_class_name(), 0, empty_vars, -1));
+ out.append(w.gen_fetch_switch_begin());
+ for (std::size_t function = 0; function < functions_n; function++) {
+ tl_combinator *t = config.get_function_by_num(function);
+
+ if (w.is_combinator_supported(t)) {
+ out.append(w.gen_fetch_switch_case(t, 0));
+ }
+ }
+ out.append(w.gen_fetch_switch_end());
+ out.append(w.gen_fetch_function_end(-1, empty_vars, -1));
+ }
+
+ std::vector<std::string> storers = w.get_storers();
+ for (std::size_t j = 0; j < storers.size(); j++) {
+ if (w.get_storer_mode(-1) == TL_writer::Server) {
+ continue;
+ }
+
+ out.append(w.gen_store_function_begin(storers[j], w.gen_base_function_class_name(), 0, empty_vars, -1));
+ out.append(w.gen_store_function_end(empty_vars, -1));
+ }
+
+ for (std::size_t j = 0; j < parsers.size(); j++) {
+ if (w.get_parser_mode(-1) == TL_writer::Server) {
+ continue;
+ }
+
+ out.append(w.gen_fetch_function_result_any_begin(parsers[j], w.gen_base_function_class_name(), true));
+ out.append(w.gen_fetch_function_result_any_end(true));
+ }
+
+ std::vector<std::string> additional_functions = w.get_additional_functions();
+ for (std::size_t j = 0; j < additional_functions.size(); j++) {
+ out.append(w.gen_additional_proxy_function_begin(additional_functions[j], NULL, w.gen_base_function_class_name(),
+ 0, true));
+ for (std::size_t function = 0; function < functions_n; function++) {
+ tl_combinator *t = config.get_function_by_num(function);
+
+ if (w.is_combinator_supported(t)) {
+ out.append(w.gen_additional_proxy_function_case(additional_functions[j], NULL, t, 0, true));
+ }
+ }
+
+ out.append(w.gen_additional_proxy_function_end(additional_functions[j], NULL, true));
+ }
+
+ out.append(w.gen_class_end());
+ }
+
+ for (std::size_t type = 0; type < types_n; type++) {
+ tl_type *t = config.get_type_by_num(type);
+ if (t->constructors_num == 0 || w.is_built_in_simple_type(t->name) ||
+ w.is_built_in_complex_type(t->name)) { // built-in dummy or complex types
+ continue;
+ }
+
+ if (t->flags & FLAG_COMPLEX) {
+ std::fprintf(stderr, "Can't generate class %s\n", t->name.c_str());
+ continue;
+ }
+
+ write_class(out, t, request_types, result_types, w);
+ }
+
+ for (std::size_t function = 0; function < functions_n; function++) {
+ tl_combinator *t = config.get_function_by_num(function);
+ if (!w.is_combinator_supported(t)) {
+ std::fprintf(stderr, "Function %s is too hard to store\n", t->name.c_str());
+ continue;
+ }
+
+ write_function(out, t, request_types, result_types, w);
+ }
+ out.append(w.gen_output_end());
+
+ for (std::size_t type = 0; type < types_n; type++) {
+ tl_type *t = config.get_type_by_num(type);
+ if (t->flags & FLAG_COMPLEX) {
+ t->flags &= ~FLAG_COMPLEX; // remove temporary flag
+ }
+ }
+}
+
+tl_config read_tl_config_from_file(const std::string &file_name) {
+ std::string config = get_file_contents(file_name, "rb");
+ if (config.empty()) {
+ std::fprintf(stderr, "Config file %s is empty\n", file_name.c_str());
+ std::abort();
+ }
+ if (config.size() % sizeof(std::int32_t) != 0) {
+ std::fprintf(stderr, "Config size = %d is not multiple of %d\n", static_cast<int>(config.size()),
+ static_cast<int>(sizeof(std::int32_t)));
+ std::abort();
+ }
+
+ tl_config_parser parser(config.c_str(), config.size());
+ return parser.parse_config();
+}
+
+bool write_tl_to_file(const tl_config &config, const std::string &file_name, const TL_writer &w) {
+ tl_string_outputer out;
+ write_tl(config, out, w);
+
+ auto old_file_contents = get_file_contents(file_name, "rb");
+ if (!w.is_documentation_generated()) {
+ old_file_contents = remove_documentation(old_file_contents);
+ }
+
+ if (old_file_contents != out.get_result()) {
+ std::fprintf(stderr, "Write tl to file %s\n", file_name.c_str());
+ return put_file_contents(file_name, "wb", out.get_result());
+ }
+
+ return true;
+}
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_generate.h b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_generate.h
new file mode 100644
index 0000000000..3523d1c828
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_generate.h
@@ -0,0 +1,24 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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 "tl_config.h"
+#include "tl_outputer.h"
+#include "tl_writer.h"
+
+#include <string>
+
+namespace td {
+namespace tl {
+
+void write_tl(const tl_config &config, tl_outputer &out, const TL_writer &w);
+
+tl_config read_tl_config_from_file(const std::string &file_name);
+bool write_tl_to_file(const tl_config &config, const std::string &file_name, const TL_writer &w);
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_outputer.cpp b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_outputer.cpp
new file mode 100644
index 0000000000..fed4ceb818
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_outputer.cpp
@@ -0,0 +1,16 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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)
+//
+#include "tl_outputer.h"
+
+namespace td {
+namespace tl {
+
+tl_outputer::~tl_outputer() {
+}
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_outputer.h b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_outputer.h
new file mode 100644
index 0000000000..47c0ab4fed
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_outputer.h
@@ -0,0 +1,22 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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 <string>
+
+namespace td {
+namespace tl {
+
+class tl_outputer {
+ public:
+ virtual void append(const std::string &str) = 0;
+
+ virtual ~tl_outputer() = 0;
+};
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_simple.h b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_simple.h
new file mode 100644
index 0000000000..bf4801f1e2
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_simple.h
@@ -0,0 +1,204 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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_config.h"
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace td {
+namespace tl {
+namespace simple {
+// TL type is
+
+std::string gen_cpp_name(std::string name) {
+ for (std::size_t i = 0; i < name.size(); i++) {
+ if ((name[i] < '0' || '9' < name[i]) && (name[i] < 'a' || 'z' < name[i]) && (name[i] < 'A' || 'Z' < name[i])) {
+ name[i] = '_';
+ }
+ }
+ assert(name.size() > 0);
+ assert(name[name.size() - 1] != '_');
+ return name;
+}
+
+std::string gen_cpp_field_name(std::string name) {
+ return gen_cpp_name(name) + "_";
+}
+
+struct CustomType;
+struct Type {
+ enum { Int32, Int53, Int64, Double, String, Bytes, Vector, Bool, Custom } type;
+
+ // type == Custom
+ bool is_bare{false};
+ const CustomType *custom{nullptr};
+
+ // type == Vector
+ const Type *vector_value_type{nullptr};
+}; // namespace simple
+
+struct Arg {
+ const Type *type;
+ std::string name;
+};
+
+struct Constructor {
+ std::string name;
+ std::int32_t id;
+ std::vector<Arg> args;
+ const CustomType *type;
+};
+
+struct CustomType {
+ std::string name;
+ std::vector<const Constructor *> constructors;
+};
+
+struct Function {
+ std::string name;
+ std::int32_t id;
+ std::vector<Arg> args;
+ const Type *type;
+};
+
+class Schema {
+ public:
+ explicit Schema(const tl_config &config) {
+ config_ = &config;
+ for (std::size_t type_num = 0, type_count = config.get_type_count(); type_num < type_count; type_num++) {
+ auto *from_type = config.get_type_by_num(type_num);
+ if (from_type->name == "Vector") {
+ continue;
+ }
+ auto *type = get_type(from_type);
+ if (type->type == Type::Custom) {
+ custom_types.push_back(type->custom);
+ }
+ }
+ for (std::size_t function_num = 0, function_count = config.get_function_count(); function_num < function_count;
+ function_num++) {
+ auto *from_function = config.get_function_by_num(function_num);
+ functions.push_back(get_function(from_function));
+ }
+ }
+
+ std::vector<const CustomType *> custom_types;
+ std::vector<const Function *> functions;
+
+ private:
+ std::vector<std::unique_ptr<Function>> functions_;
+ std::vector<std::unique_ptr<Constructor>> constructors_;
+ std::vector<std::unique_ptr<CustomType>> custom_types_;
+ std::vector<std::unique_ptr<Type>> types_;
+
+ const tl_config *config_{nullptr};
+ std::map<std::int32_t, Type *> type_by_id;
+ std::map<std::int32_t, Constructor *> constructor_by_id;
+ std::map<std::int32_t, Function *> function_by_id;
+
+ const Type *get_type(const tl_type *from_type) {
+ auto &type = type_by_id[from_type->id];
+ if (!type) {
+ types_.push_back(std::make_unique<Type>());
+ type = types_.back().get();
+
+ if (from_type->name == "Int32") {
+ type->type = Type::Int32;
+ } else if (from_type->name == "Int53") {
+ type->type = Type::Int53;
+ } else if (from_type->name == "Int64") {
+ type->type = Type::Int64;
+ } else if (from_type->name == "Double") {
+ type->type = Type::Double;
+ } else if (from_type->name == "String") {
+ type->type = Type::String;
+ } else if (from_type->name == "Bytes") {
+ type->type = Type::Bytes;
+ } else if (from_type->name == "Bool") {
+ type->type = Type::Bool;
+ } else if (from_type->name == "Vector") {
+ assert(false); // unreachable
+ } else {
+ type->type = Type::Custom;
+ custom_types_.push_back(std::make_unique<CustomType>());
+ auto *custom_type = custom_types_.back().get();
+ type->custom = custom_type;
+ custom_type->name = from_type->name;
+ for (auto *constructor : from_type->constructors) {
+ custom_type->constructors.push_back(get_constructor(constructor));
+ }
+ }
+ }
+ return type;
+ }
+ const CustomType *get_custom_type(const tl_type *from_type) {
+ auto *type = get_type(from_type);
+ assert(type->type == Type::Custom);
+ return type->custom;
+ }
+
+ const Constructor *get_constructor(const tl_combinator *from) {
+ auto &constructor = constructor_by_id[from->id];
+ if (!constructor) {
+ constructors_.push_back(std::make_unique<Constructor>());
+ constructor = constructors_.back().get();
+ constructor->id = from->id;
+ constructor->name = from->name;
+ constructor->type = get_custom_type(config_->get_type(from->type_id));
+ for (auto &from_arg : from->args) {
+ Arg arg;
+ arg.name = from_arg.name;
+ arg.type = get_type(from_arg.type);
+ constructor->args.push_back(std::move(arg));
+ }
+ }
+ return constructor;
+ }
+ const Function *get_function(const tl_combinator *from) {
+ auto &function = function_by_id[from->id];
+ if (!function) {
+ functions_.push_back(std::make_unique<Function>());
+ function = functions_.back().get();
+ function->id = from->id;
+ function->name = from->name;
+ function->type = get_type(config_->get_type(from->type_id));
+ for (auto &from_arg : from->args) {
+ Arg arg;
+ arg.name = from_arg.name;
+ arg.type = get_type(from_arg.type);
+ function->args.push_back(std::move(arg));
+ }
+ }
+ return function;
+ }
+ const Type *get_type(const tl_tree *tree) {
+ assert(tree->get_type() == NODE_TYPE_TYPE);
+ auto *type_tree = static_cast<const tl_tree_type *>(tree);
+ if (type_tree->type->name == "Vector") {
+ assert(type_tree->children.size() == 1);
+ types_.push_back(std::make_unique<Type>());
+ auto *type = types_.back().get();
+ type->type = Type::Vector;
+ type->vector_value_type = get_type(type_tree->children[0]);
+ return type;
+ } else {
+ assert(type_tree->children.empty());
+ return get_type(type_tree->type);
+ }
+ }
+};
+
+} // namespace simple
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_simple_parser.h b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_simple_parser.h
new file mode 100644
index 0000000000..9e612bf799
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_simple_parser.h
@@ -0,0 +1,107 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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 <cassert>
+#include <cstdint>
+#include <cstring>
+#include <string>
+
+namespace td {
+namespace tl {
+
+class tl_simple_parser {
+ const char *data;
+ const char *data_begin;
+ std::size_t data_len;
+ const char *error;
+ std::size_t error_pos;
+
+ void set_error(const char *error_message) {
+ if (error == NULL) {
+ assert(error_message != NULL);
+ error = error_message;
+ error_pos = static_cast<std::size_t>(data - data_begin);
+ data = "\x00\x00\x00\x00\x00\x00\x00\x00";
+ data_len = 0;
+ } else {
+ data = "\x00\x00\x00\x00\x00\x00\x00\x00";
+ assert(data_len == 0);
+ }
+ }
+
+ void check_len(const std::size_t len) {
+ if (data_len < len) {
+ set_error("Not enough data to read");
+ } else {
+ data_len -= len;
+ }
+ }
+
+ tl_simple_parser(const tl_simple_parser &other);
+ tl_simple_parser &operator=(const tl_simple_parser &other);
+
+ public:
+ tl_simple_parser(const char *data, std::size_t data_len)
+ : data(data), data_begin(data), data_len(data_len), error(), error_pos() {
+ }
+
+ const char *get_error() const {
+ return error;
+ }
+
+ std::size_t get_error_pos() const {
+ return error_pos;
+ }
+
+ std::int32_t fetch_int() {
+ check_len(sizeof(std::int32_t));
+ std::int32_t result = *reinterpret_cast<const std::int32_t *>(data);
+ data += sizeof(std::int32_t);
+ return result;
+ }
+
+ std::int64_t fetch_long() {
+ check_len(sizeof(std::int64_t));
+ std::int64_t result;
+ std::memcpy(reinterpret_cast<char *>(&result), data, sizeof(std::int64_t));
+ data += sizeof(std::int64_t);
+ return result;
+ }
+
+ std::string fetch_string() {
+ check_len(4);
+ int result_len = static_cast<unsigned char>(data[0]);
+ if (result_len < 254) {
+ check_len((result_len >> 2) * 4);
+ std::string result(data + 1, result_len);
+ data += ((result_len >> 2) + 1) * 4;
+ return result;
+ }
+
+ if (result_len == 254) {
+ result_len = static_cast<unsigned char>(data[1]) + (static_cast<unsigned char>(data[2]) << 8) +
+ (static_cast<unsigned char>(data[3]) << 16);
+ check_len(((result_len + 3) >> 2) * 4);
+ std::string result(data + 4, result_len);
+ data += ((result_len + 7) >> 2) * 4;
+ return result;
+ }
+
+ set_error("Can't fetch string, 255 found");
+ return std::string();
+ }
+
+ void fetch_end() {
+ if (data_len) {
+ set_error("Too much data to fetch");
+ }
+ }
+};
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_string_outputer.cpp b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_string_outputer.cpp
new file mode 100644
index 0000000000..4a72ecdccd
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_string_outputer.cpp
@@ -0,0 +1,21 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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)
+//
+#include "tl_string_outputer.h"
+
+namespace td {
+namespace tl {
+
+void tl_string_outputer::append(const std::string &str) {
+ result += str;
+}
+
+const std::string &tl_string_outputer::get_result() const {
+ return result;
+}
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_string_outputer.h b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_string_outputer.h
new file mode 100644
index 0000000000..f0936340da
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_string_outputer.h
@@ -0,0 +1,26 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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 "tl_outputer.h"
+
+#include <string>
+
+namespace td {
+namespace tl {
+
+class tl_string_outputer : public tl_outputer {
+ std::string result;
+
+ public:
+ virtual void append(const std::string &str);
+
+ const std::string &get_result() const;
+};
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_writer.cpp b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_writer.cpp
new file mode 100644
index 0000000000..f1d8b2e18a
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_writer.cpp
@@ -0,0 +1,231 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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)
+//
+#include "tl_writer.h"
+
+#include "tl_core.h"
+
+#include <cassert>
+#include <cstdio>
+
+namespace td {
+namespace tl {
+
+std::string TL_writer::int_to_string(int x) {
+ char buf[15];
+ std::sprintf(buf, "%d", x);
+ return buf;
+}
+
+bool TL_writer::is_alnum(char c) {
+ return ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
+}
+
+char TL_writer::to_lower(char c) {
+ return 'A' <= c && c <= 'Z' ? static_cast<char>(c - 'A' + 'a') : c;
+}
+
+char TL_writer::to_upper(char c) {
+ return 'a' <= c && c <= 'z' ? static_cast<char>(c - 'a' + 'A') : c;
+}
+
+std::vector<std::string> TL_writer::get_additional_functions() const {
+ return std::vector<std::string>();
+}
+
+bool TL_writer::is_type_supported(const tl_tree_type *tree_type) const {
+ if (tree_type->type->flags & FLAG_COMPLEX) {
+ return false;
+ }
+
+ for (std::size_t i = 0; i < tree_type->children.size(); i++) {
+ const tl_tree *child = tree_type->children[i];
+ assert(child->get_type() == NODE_TYPE_TYPE || child->get_type() == NODE_TYPE_VAR_TYPE ||
+ child->get_type() == NODE_TYPE_NAT_CONST || child->get_type() == NODE_TYPE_VAR_NUM);
+
+ if (child->get_type() == NODE_TYPE_TYPE) {
+ if (!is_type_supported(static_cast<const tl_tree_type *>(child))) {
+ return false;
+ }
+ }
+ if (child->get_type() == NODE_TYPE_VAR_TYPE) {
+ return false; // TODO
+ }
+ }
+
+ return true;
+}
+
+bool TL_writer::is_combinator_supported(const tl_combinator *constructor) const {
+ std::vector<bool> is_function_result(constructor->var_count);
+ for (std::size_t i = 0; i < constructor->args.size(); i++) {
+ const arg &a = constructor->args[i];
+
+ int arg_type = a.type->get_type();
+ if (arg_type == NODE_TYPE_VAR_TYPE) {
+ const tl_tree_var_type *t = static_cast<const tl_tree_var_type *>(a.type);
+ if (a.flags & FLAG_EXCL) {
+ assert(t->var_num >= 0);
+ if (is_function_result[t->var_num]) {
+ return false; // lazy to check that result of two function calls is the same
+ }
+ is_function_result[t->var_num] = true;
+ } else {
+ return false; // do not support generic types
+ }
+ }
+ }
+
+ for (std::size_t i = 0; i < constructor->args.size(); i++) {
+ const arg &a = constructor->args[i];
+
+ int arg_type = a.type->get_type();
+ if (a.var_num >= 0) {
+ assert(arg_type == NODE_TYPE_TYPE);
+ const tl_tree_type *a_type = static_cast<const tl_tree_type *>(a.type);
+ if (a_type->type->id == ID_VAR_TYPE) {
+ assert(!(a_type->flags & FLAG_EXCL));
+ if (!is_function_result[a.var_num]) {
+ assert(false); // not possible, otherwise type is an argument of a type, but all types with type arguments
+ // are already marked complex
+ return false;
+ } else {
+ continue;
+ }
+ }
+ }
+
+ if (arg_type == NODE_TYPE_VAR_TYPE) {
+ continue;
+ } else if (arg_type == NODE_TYPE_TYPE) {
+ if (!is_type_supported(static_cast<const tl_tree_type *>(a.type))) {
+ return false;
+ }
+ } else {
+ assert(arg_type == NODE_TYPE_ARRAY);
+ const tl_tree_array *arr = static_cast<const tl_tree_array *>(a.type);
+ for (std::size_t j = 0; j < arr->args.size(); j++) {
+ const arg &b = arr->args[j];
+ assert(b.type->get_type() == NODE_TYPE_TYPE && b.var_num == -1);
+ if (!is_type_supported(static_cast<const tl_tree_type *>(b.type))) {
+ return false;
+ }
+ }
+ }
+ }
+
+ tl_tree *result = constructor->result;
+ if (result->get_type() == NODE_TYPE_TYPE) {
+ if (!is_type_supported(static_cast<const tl_tree_type *>(result))) {
+ return false;
+ }
+ } else {
+ assert(result->get_type() == NODE_TYPE_VAR_TYPE);
+ const tl_tree_var_type *t = static_cast<const tl_tree_var_type *>(result);
+ return is_function_result[t->var_num];
+ }
+
+ return true;
+}
+
+bool TL_writer::is_documentation_generated() const {
+ return false;
+}
+
+std::string TL_writer::gen_main_class_name(const tl_type *t) const {
+ if (t->simple_constructors == 1) {
+ for (std::size_t i = 0; i < t->constructors_num; i++) {
+ if (is_combinator_supported(t->constructors[i])) {
+ return gen_class_name(t->constructors[i]->name);
+ }
+ }
+ }
+
+ return gen_class_name(t->name);
+}
+
+int TL_writer::get_parser_type(const tl_combinator *t, const std::string &parser_name) const {
+ return t->var_count > 0;
+}
+
+int TL_writer::get_storer_type(const tl_combinator *t, const std::string &storer_name) const {
+ return 0;
+}
+
+int TL_writer::get_additional_function_type(const std::string &additional_function_name) const {
+ return 0;
+}
+
+TL_writer::Mode TL_writer::get_parser_mode(int type) const {
+ return All;
+}
+
+TL_writer::Mode TL_writer::get_storer_mode(int type) const {
+ return All;
+}
+
+std::string TL_writer::gen_field_type(const arg &a) const {
+ if (a.flags & FLAG_EXCL) {
+ assert(a.flags == FLAG_EXCL);
+ assert(a.type->get_type() == NODE_TYPE_VAR_TYPE);
+
+ return gen_var_type_name();
+ }
+
+ assert(a.flags == FLAG_NOVAR || a.flags == 0 || a.flags == (FLAG_OPT_VAR | FLAG_NOVAR | FLAG_BARE));
+
+ if (a.type->get_type() == NODE_TYPE_TYPE) {
+ const tl_tree_type *arg_type = static_cast<const tl_tree_type *>(a.type);
+ assert(arg_type->children.size() == static_cast<std::size_t>(arg_type->type->arity));
+
+ if (arg_type->type->id == ID_VAR_TYPE) {
+ return std::string();
+ }
+
+ return gen_type_name(arg_type);
+ } else {
+ assert(a.flags == FLAG_NOVAR || a.flags == 0);
+
+ assert(a.type->get_type() == NODE_TYPE_ARRAY);
+ const tl_tree_array *arg_array = static_cast<const tl_tree_array *>(a.type);
+ assert((arg_array->flags & ~FLAG_NOVAR) == 0);
+ return gen_array_type_name(arg_array, a.name);
+ }
+}
+
+std::string TL_writer::gen_additional_function(const std::string &function_name, const tl_combinator *t,
+ bool is_function) const {
+ assert(false);
+ return "";
+}
+
+std::string TL_writer::gen_additional_proxy_function_begin(const std::string &function_name, const tl_type *type,
+ const std::string &class_name, int arity,
+ bool is_function) const {
+ assert(false);
+ return "";
+}
+
+std::string TL_writer::gen_additional_proxy_function_case(const std::string &function_name, const tl_type *type,
+ const std::string &class_name, int arity) const {
+ assert(false);
+ return "";
+}
+
+std::string TL_writer::gen_additional_proxy_function_case(const std::string &function_name, const tl_type *type,
+ const tl_combinator *t, int arity, bool is_function) const {
+ assert(false);
+ return "";
+}
+
+std::string TL_writer::gen_additional_proxy_function_end(const std::string &function_name, const tl_type *type,
+ bool is_function) const {
+ assert(false);
+ return "";
+}
+
+} // namespace tl
+} // namespace td
diff --git a/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_writer.h b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_writer.h
new file mode 100644
index 0000000000..3c3847516b
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/tdtl/td/tl/tl_writer.h
@@ -0,0 +1,162 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// 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 "tl_core.h"
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace td {
+namespace tl {
+
+class var_description {
+ public:
+ int index;
+ bool is_stored;
+ bool is_type;
+ int parameter_num;
+ int function_arg_num;
+
+ var_description() : index(-1), is_stored(false), is_type(false), parameter_num(-1), function_arg_num(-1) {
+ }
+};
+
+class TL_writer {
+ TL_writer(const TL_writer &other);
+ TL_writer &operator=(const TL_writer &other);
+
+ protected:
+ const std::string tl_name;
+
+ public:
+ enum Mode { All, Client, Server };
+
+ explicit TL_writer(const std::string &tl_name) : tl_name(tl_name) {
+ }
+
+ virtual ~TL_writer() {
+ }
+
+ virtual int get_max_arity() const = 0;
+
+ static std::string int_to_string(int x);
+ static bool is_alnum(char c);
+ static char to_lower(char c);
+ static char to_upper(char c);
+
+ virtual bool is_built_in_simple_type(const std::string &name) const = 0;
+ virtual bool is_built_in_complex_type(const std::string &name) const = 0;
+ virtual bool is_type_supported(const tl_tree_type *tree_type) const;
+ virtual bool is_type_bare(const tl_type *t) const = 0;
+ virtual bool is_combinator_supported(const tl_combinator *constructor) const;
+ virtual bool is_documentation_generated() const;
+
+ virtual int get_parser_type(const tl_combinator *t, const std::string &parser_name) const;
+ virtual int get_storer_type(const tl_combinator *t, const std::string &storer_name) const;
+ virtual int get_additional_function_type(const std::string &additional_function_name) const;
+ virtual Mode get_parser_mode(int type) const;
+ virtual Mode get_storer_mode(int type) const;
+ virtual std::vector<std::string> get_parsers() const = 0;
+ virtual std::vector<std::string> get_storers() const = 0;
+ virtual std::vector<std::string> get_additional_functions() const;
+
+ virtual std::string gen_base_tl_class_name() const = 0;
+ virtual std::string gen_base_type_class_name(int arity) const = 0;
+ virtual std::string gen_base_function_class_name() const = 0;
+ virtual std::string gen_class_name(std::string name) const = 0;
+ virtual std::string gen_field_name(std::string name) const = 0;
+ virtual std::string gen_var_name(const var_description &desc) const = 0;
+ virtual std::string gen_parameter_name(int index) const = 0;
+ virtual std::string gen_main_class_name(const tl_type *t) const;
+ virtual std::string gen_field_type(const arg &a) const;
+ virtual std::string gen_type_name(const tl_tree_type *tree_type) const = 0;
+ virtual std::string gen_array_type_name(const tl_tree_array *arr, const std::string &field_name) const = 0;
+ virtual std::string gen_var_type_name() const = 0;
+
+ virtual std::string gen_int_const(const tl_tree *tree_c, const std::vector<var_description> &vars) const = 0;
+
+ virtual std::string gen_output_begin() const = 0;
+ virtual std::string gen_output_end() const = 0;
+
+ virtual std::string gen_forward_class_declaration(const std::string &class_name, bool is_proxy) const = 0;
+
+ virtual std::string gen_class_begin(const std::string &class_name, const std::string &base_class_name,
+ bool is_proxy) const = 0;
+ virtual std::string gen_class_end() const = 0;
+
+ virtual std::string gen_class_alias(const std::string &class_name, const std::string &alias_name) const = 0;
+
+ virtual std::string gen_field_definition(const std::string &class_name, const std::string &type_name,
+ const std::string &field_name) const = 0;
+ virtual std::string gen_flags_definitions(const tl_combinator *t) const {
+ return "";
+ }
+
+ virtual std::string gen_vars(const tl_combinator *t, const tl_tree_type *result_type,
+ std::vector<var_description> &vars) const = 0;
+ virtual std::string gen_function_vars(const tl_combinator *t, std::vector<var_description> &vars) const = 0;
+ virtual std::string gen_uni(const tl_tree_type *result_type, std::vector<var_description> &vars,
+ bool check_negative) const = 0;
+ virtual std::string gen_constructor_id_store(std::int32_t id, int storer_type) const = 0;
+ virtual std::string gen_field_fetch(int field_num, const arg &a, std::vector<var_description> &vars, bool flat,
+ int parser_type) const = 0;
+ virtual std::string gen_field_store(const arg &a, std::vector<var_description> &vars, bool flat,
+ int storer_type) const = 0;
+ virtual std::string gen_type_fetch(const std::string &field_name, const tl_tree_type *tree_type,
+ const std::vector<var_description> &vars, int parser_type) const = 0;
+ virtual std::string gen_type_store(const std::string &field_name, const tl_tree_type *tree_type,
+ const std::vector<var_description> &vars, int storer_type) const = 0;
+ virtual std::string gen_var_type_fetch(const arg &a) const = 0;
+
+ virtual std::string gen_get_id(const std::string &class_name, std::int32_t id, bool is_proxy) const = 0;
+
+ virtual std::string gen_function_result_type(const tl_tree *result) const = 0;
+
+ virtual std::string gen_fetch_function_begin(const std::string &parser_name, const std::string &class_name, int arity,
+ std::vector<var_description> &vars, int parser_type) const = 0;
+ virtual std::string gen_fetch_function_end(int field_num, const std::vector<var_description> &vars,
+ int parser_type) const = 0;
+
+ virtual std::string gen_fetch_function_result_begin(const std::string &parser_name, const std::string &class_name,
+ const tl_tree *result) const = 0;
+ virtual std::string gen_fetch_function_result_end() const = 0;
+ virtual std::string gen_fetch_function_result_any_begin(const std::string &parser_name, const std::string &class_name,
+ bool is_proxy) const = 0;
+ virtual std::string gen_fetch_function_result_any_end(bool is_proxy) const = 0;
+
+ virtual std::string gen_store_function_begin(const std::string &storer_name, const std::string &class_name, int arity,
+ std::vector<var_description> &vars, int storer_type) const = 0;
+ virtual std::string gen_store_function_end(const std::vector<var_description> &vars, int storer_type) const = 0;
+
+ virtual std::string gen_fetch_switch_begin() const = 0;
+ virtual std::string gen_fetch_switch_case(const tl_combinator *t, int arity) const = 0;
+ virtual std::string gen_fetch_switch_end() const = 0;
+
+ virtual std::string gen_constructor_begin(int fields_num, const std::string &class_name, bool is_default) const = 0;
+ virtual std::string gen_constructor_parameter(int field_num, const std::string &class_name, const arg &a,
+ bool is_default) const = 0;
+ virtual std::string gen_constructor_field_init(int field_num, const std::string &class_name, const arg &a,
+ bool is_default) const = 0;
+ virtual std::string gen_constructor_end(const tl_combinator *t, int fields_num, bool is_default) const = 0;
+
+ virtual std::string gen_additional_function(const std::string &function_name, const tl_combinator *t,
+ bool is_function) const;
+ virtual std::string gen_additional_proxy_function_begin(const std::string &function_name, const tl_type *type,
+ const std::string &class_name, int arity,
+ bool is_function) const;
+ virtual std::string gen_additional_proxy_function_case(const std::string &function_name, const tl_type *type,
+ const std::string &class_name, int arity) const;
+ virtual std::string gen_additional_proxy_function_case(const std::string &function_name, const tl_type *type,
+ const tl_combinator *t, int arity, bool is_function) const;
+ virtual std::string gen_additional_proxy_function_end(const std::string &function_name, const tl_type *type,
+ bool is_function) const;
+};
+
+} // namespace tl
+} // namespace td