// // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 // // 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> #include <iostream> namespace td { namespace tl { namespace simple { inline std::string gen_cpp_name(std::string name) { for (auto &c : name) { if ((c < '0' || '9' < c) && (c < 'a' || 'z' < c) && (c < 'A' || 'Z' < c)) { c = '_'; } } assert(!name.empty()); assert(name[name.size() - 1] != '_'); return name; } inline 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}; }; 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; mutable bool is_result_{false}; mutable bool is_query_{false}; }; 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)); } for (auto &function : functions_) { mark_result(function->type); for (auto &arg : function->args) { mark_query(arg.type); } } //for (auto custom_type : custom_types) { //std::cerr << custom_type->name; //if (custom_type->is_result_) { //std::cerr << " result"; //} //if (custom_type->is_query_) { //std::cerr << " query"; //} //std::cerr << std::endl; //} } 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; void mark_result(const Type *type) { do_mark(type, true); } void mark_query(const Type *type) { do_mark(type, false); } void do_mark(const Type *type, bool is_result) { if (type->type == Type::Vector) { return do_mark(type->vector_value_type, is_result); } if (type->type != Type::Custom) { return; } auto *custom = type->custom; auto &was = is_result ? custom->is_result_ : custom->is_query_; if (was) { return; } was = true; for (auto constructor : custom->constructors) { for (auto &arg : constructor->args) { do_mark(arg.type, is_result); } } } 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