diff options
Diffstat (limited to 'protocols/Telegram/tdlib/td/tdtl')
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 |