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
 |