mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			384 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			384 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|     This file is part of TON Blockchain Library.
 | |
| 
 | |
|     TON Blockchain Library is free software: you can redistribute it and/or modify
 | |
|     it under the terms of the GNU Lesser General Public License as published by
 | |
|     the Free Software Foundation, either version 2 of the License, or
 | |
|     (at your option) any later version.
 | |
| 
 | |
|     TON Blockchain Library is distributed in the hope that it will be useful,
 | |
|     but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|     GNU Lesser General Public License for more details.
 | |
| 
 | |
|     You should have received a copy of the GNU Lesser General Public License
 | |
|     along with TON Blockchain Library.  If not, see <http://www.gnu.org/licenses/>.
 | |
| 
 | |
|     Copyright 2017-2020 Telegram Systems LLP
 | |
| */
 | |
| #include "tl_config.h"
 | |
| 
 | |
| #include <cassert>
 | |
| #include <cstdio>
 | |
| #include <cstdlib>
 | |
| #include <memory>
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| template <class T>
 | |
| T *store(std::unique_ptr<T> ptr) {
 | |
|   static std::vector<std::unique_ptr<T>> storage;
 | |
|   auto res = ptr.get();
 | |
|   storage.push_back(std::move(ptr));
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| tl_tree *tl_config_parser::read_num_const() {
 | |
|   int num = static_cast<int>(try_parse_int());
 | |
| 
 | |
|   return store(std::make_unique<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 store(std::make_unique<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 store(std::make_unique<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 = store(std::make_unique<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 = store(std::make_unique<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 = store(std::make_unique<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 = store(std::make_unique<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 version %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
 |