1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

initial commit

This commit is contained in:
initial commit 2019-09-07 14:03:22 +04:00 committed by vvaltman
commit c2da007f40
1610 changed files with 398047 additions and 0 deletions

45
crypto/tl/boc.tlb Normal file
View file

@ -0,0 +1,45 @@
//
// Bag-of-Cells (BoC) serialization formats
//
serialized_boc_idx#68ff65f3 size:(## 8) { size <= 4 }
off_bytes:(## 8) { off_bytes <= 8 }
cells:(##(size * 8))
roots:(##(size * 8)) { roots = 1 }
absent:(##(size * 8)) { roots + absent <= cells }
tot_cells_size:(##(off_bytes * 8))
index:(cells * ##(off_bytes * 8))
cell_data:(tot_cells_size * [ uint8 ])
= BagOfCells;
serialized_boc_idx_crc32c#acc3a728 size:(## 8) { size <= 4 }
off_bytes:(## 8) { off_bytes <= 8 }
cells:(##(size * 8))
roots:(##(size * 8)) { roots = 1 }
absent:(##(size * 8)) { roots + absent <= cells }
tot_cells_size:(##(off_bytes * 8))
index:(cells * ##(off_bytes * 8))
cell_data:(tot_cells_size * [ uint8 ])
crc32c:uint32 = BagOfCells;
serialized_boc#b5ee9c72 has_idx:(## 1) has_crc32c:(## 1)
has_cache_bits:(## 1) flags:(## 2) { flags = 0 }
size:(## 3) { size <= 4 }
off_bytes:(## 8) { off_bytes <= 8 }
cells:(##(size * 8))
roots:(##(size * 8)) { roots >= 1 }
absent:(##(size * 8)) { roots + absent <= cells }
tot_cells_size:(##(off_bytes * 8))
root_list:(roots * ##(size * 8))
index:(cells * ##(off_bytes * 8))
cell_data:(tot_cells_size * [ uint8 ])
= BagOfCells;
compiled_smart_contract
compiled_at:uint32 code:^Cell data:^Cell
description:(Maybe ^TinyString)
^[ source_file:(Maybe ^TinyString)
compiler_version:(Maybe ^TinyString) ]
= CompiledSmartContract;
tiny_string#_ len:(#<= 126) str:(len * [ uint8 ]) = TinyString;

60
crypto/tl/hashmap.tlb Normal file
View file

@ -0,0 +1,60 @@
bit#_ _:(## 1) = Bit;
// ordinary Hashmap / HashmapE, with fixed length keys
//
hm_edge#_ {n:#} {X:Type} {l:#} {m:#} label:(HmLabel ~l n)
{n = (~m) + l} node:(HashmapNode m X) = Hashmap n X;
hmn_leaf#_ {X:Type} value:X = HashmapNode 0 X;
hmn_fork#_ {n:#} {X:Type} left:^(Hashmap n X)
right:^(Hashmap n X) = HashmapNode (n + 1) X;
hml_short$0 {m:#} {n:#} len:(Unary ~n) s:(n * Bit) = HmLabel ~n m;
hml_long$10 {m:#} n:(#<= m) s:(n * Bit) = HmLabel ~n m;
hml_same$11 {m:#} v:Bit n:(#<= m) = HmLabel ~n m;
unary_zero$0 = Unary ~0;
unary_succ$1 {n:#} x:(Unary ~n) = Unary ~(n + 1);
hme_empty$0 {n:#} {X:Type} = HashmapE n X;
hme_root$1 {n:#} {X:Type} root:^(Hashmap n X) = HashmapE n X;
true#_ = True;
_ {n:#} _:(Hashmap n True) = BitstringSet n;
// VarHashmap / VarHashmapE, with variable-length keys
//
vhm_edge#_ {n:#} {X:Type} {l:#} {m:#} label:(HmLabel ~l n)
{n = (~m) + l} node:(VarHashmapNode m X)
= VarHashmap n X;
vhmn_leaf$00 {n:#} {X:Type} value:X = VarHashmapNode n X;
vhmn_fork$01 {n:#} {X:Type} left:^(VarHashmap n X)
right:^(VarHashmap n X) value:(Maybe X)
= VarHashmapNode (n + 1) X;
vhmn_cont$1 {n:#} {X:Type} branch:Bit child:^(VarHashmap n X)
value:X = VarHashmapNode (n + 1) X;
nothing$0 {X:Type} = Maybe X;
just$1 {X:Type} value:X = Maybe X;
vhme_empty$0 {n:#} {X:Type} = VarHashmapE n X;
vhme_root$1 {n:#} {X:Type} root:^(VarHashmap n X)
= VarHashmapE n X;
//
// PfxHashmap / PfxHashmapE, with variable-length keys
// constituting a prefix code
//
phm_edge#_ {n:#} {X:Type} {l:#} {m:#} label:(HmLabel ~l n)
{n = (~m) + l} node:(PfxHashmapNode m X)
= PfxHashmap n X;
phmn_leaf$0 {n:#} {X:Type} value:X = PfxHashmapNode n X;
phmn_fork$1 {n:#} {X:Type} left:^(PfxHashmap n X)
right:^(PfxHashmap n X) = PfxHashmapNode (n + 1) X;
phme_empty$0 {n:#} {X:Type} = PfxHashmapE n X;
phme_root$1 {n:#} {X:Type} root:^(PfxHashmap n X)
= PfxHashmapE n X;

262
crypto/tl/tlbc-aux.h Normal file
View file

@ -0,0 +1,262 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include <vector>
#include <string>
#include <memory>
#include <ostream>
namespace tlbc {
static constexpr unsigned long long All = 1ULL << 63;
struct BitPfxCollection {
std::vector<unsigned long long> pfx;
void clear() {
pfx.clear();
}
void all() {
pfx.clear();
pfx.push_back(All);
}
BitPfxCollection() = default;
BitPfxCollection(unsigned long long one_pfx) {
if (one_pfx) {
pfx.push_back(one_pfx);
}
}
bool empty() const {
return pfx.empty();
}
unsigned long long min() const {
return pfx.empty() ? 0 : pfx[0];
}
bool is_all() const {
return pfx.size() == 1 && pfx[0] == All;
}
BitPfxCollection& operator*=(unsigned long long prepend);
BitPfxCollection operator*(unsigned long long prepend) const;
BitPfxCollection operator+(const BitPfxCollection& other) const;
bool operator+=(const BitPfxCollection& other);
bool operator==(const BitPfxCollection& other) const {
return pfx == other.pfx;
}
bool operator!=(const BitPfxCollection& other) const {
return pfx != other.pfx;
}
void merge_back(unsigned long long z);
void show(std::ostream& os) const;
};
std::ostream& operator<<(std::ostream& os, const BitPfxCollection& p);
struct AdmissibilityInfo {
enum { side = 4 };
std::vector<bool> info;
int dim;
AdmissibilityInfo() : info(1, false), dim(0) {
}
void extend(int dim1);
bool operator[](std::size_t i) {
return info[i & (info.size() - 1)];
}
void operator|=(const AdmissibilityInfo& other);
void set_all(bool val = true);
void clear_all() {
set_all(false);
}
void set_by_pattern(int pdim, int pattern[]);
void show(std::ostream& os) const;
bool is_set_all() const {
return !dim && info[0];
}
bool extract1(char A[side], char tag, int p1) const;
bool extract2(char A[side][side], char tag, int p1, int p2) const;
bool extract3(char A[side][side][side], char tag, int p1, int p2, int p3) const;
int conflicts_at(const AdmissibilityInfo& other) const;
bool conflicts_with(const AdmissibilityInfo& other) const {
return conflicts_at(other) >= 0;
}
};
std::ostream& operator<<(std::ostream& os, const AdmissibilityInfo& p);
struct ConflictSet {
unsigned long long x;
explicit ConflictSet(unsigned long long _x = 0) : x(_x) {
}
bool operator[](int i) const {
return (x >> i) & 1;
}
ConflictSet& operator|=(ConflictSet other) {
x |= other.x;
return *this;
}
int size() const {
return td::count_bits64(x);
}
int min() const {
return x ? td::count_trailing_zeroes_non_zero64(x) : 0x7fffffff;
}
int max() const {
return x ? 63 - td::count_leading_zeroes_non_zero64(x) : -1;
}
void remove(int i) {
x &= ~(1ULL << i);
}
void insert(int i) {
x |= (1ULL << i);
}
};
struct ConflictGraph {
std::array<ConflictSet, 64> g;
ConflictSet& operator[](int i) {
return g[i];
}
const ConflictSet& operator[](int i) const {
return g[i];
}
void set_clique(ConflictSet set);
};
struct BinTrie {
std::unique_ptr<BinTrie> left, right;
unsigned long long tag, down_tag;
int useful_depth;
BinTrie(unsigned long long _tag = 0, std::unique_ptr<BinTrie> _left = {}, std::unique_ptr<BinTrie> _right = {})
: left(std::move(_left)), right(std::move(_right)), tag(_tag), down_tag(0), useful_depth(0) {
}
void ins_path(unsigned long long path, unsigned long long new_tag);
unsigned long long lookup_tag(unsigned long long path) const;
const BinTrie* lookup_node_const(unsigned long long path) const;
BinTrie* lookup_node(unsigned long long path);
bool is_unique() const {
return !(down_tag & (down_tag - 1));
}
int unique_value() const {
return down_tag ? td::count_trailing_zeroes_non_zero64(down_tag) : -1;
}
static std::unique_ptr<BinTrie> insert_path(std::unique_ptr<BinTrie> root, unsigned long long path,
unsigned long long tag);
static std::unique_ptr<BinTrie> insert_paths(std::unique_ptr<BinTrie> root, const BitPfxCollection& paths,
unsigned long long tag);
void set_conflict_graph(ConflictGraph& gr, unsigned long long colors = 0) const;
int compute_useful_depth(unsigned long long colors = 0);
unsigned long long find_conflict_path(unsigned long long colors = 0, unsigned long long mask = ~0ULL) const;
unsigned long long build_submap_at(int depth, unsigned long long A[], unsigned long long pfx) const;
unsigned long long build_submap(int depth, unsigned long long A[]) const;
void show(std::ostream& os, unsigned long long pfx = 1ULL << 63) const;
};
std::ostream& operator<<(std::ostream& os, const BinTrie& bt);
struct MinMaxSize {
enum : unsigned long long { Any = 0x7ff07, OneRef = 0x100000001ULL, Impossible = (0x7ff07ULL << 32) };
unsigned long long minmax_size;
unsigned min_size() const {
return (unsigned)(minmax_size >> 32);
}
unsigned max_size() const {
return (unsigned)(minmax_size & 0xffffffff);
}
unsigned long long get() const {
return minmax_size;
}
bool is_fixed() const {
return min_size() == max_size();
}
int fixed_bit_size() const {
return is_fixed() && !(min_size() & 0xff) ? (min_size() >> 8) : -1;
}
bool fits_into_cell() const {
return !((0x3ff04 - min_size()) & 0x80000080U);
}
bool is_possible() const {
return !((max_size() - min_size()) & 0x80000080U);
}
void normalize();
MinMaxSize& clear() {
minmax_size = 0;
return *this;
}
MinMaxSize& clear_min() {
minmax_size &= (1ULL << 32) - 1;
return *this;
}
MinMaxSize& infinite_max() {
minmax_size |= 0x3ff07;
return *this;
}
MinMaxSize(unsigned long long _size = Impossible, bool _normalize = false) : minmax_size(_size) {
if (_normalize) {
normalize();
}
}
static unsigned convert_size(unsigned z) {
return ((z & 0xff) << 16) | (z >> 8);
}
unsigned convert_min_size() const {
return convert_size(min_size());
}
unsigned convert_max_size() const {
return convert_size(max_size());
}
MinMaxSize operator+(MinMaxSize y) {
return MinMaxSize(get() + y.get(), true);
}
MinMaxSize& operator+=(MinMaxSize y) {
minmax_size += y.get();
normalize();
return *this;
}
MinMaxSize& operator|=(MinMaxSize y);
bool operator==(MinMaxSize y) {
return get() == y.get();
}
bool operator!=(MinMaxSize y) {
return get() != y.get();
}
MinMaxSize& repeat(int count);
MinMaxSize& repeat_at_least(int count);
static MinMaxSize fixed_size(unsigned sz) {
return MinMaxSize(sz * 0x10000000100ULL);
}
static MinMaxSize size_range(unsigned min_sz, unsigned max_sz) {
return MinMaxSize((((unsigned long long)min_sz << 32) + max_sz) << 8);
}
void show(std::ostream& os) const;
struct unpacked {
unsigned min_bits, min_refs, max_bits, max_refs;
unpacked(MinMaxSize val);
MinMaxSize pack() const;
void show(std::ostream& os) const;
};
private:
void nrm(unsigned long long a, unsigned long long b) {
if (minmax_size & a) {
minmax_size = (minmax_size | (a | b)) - a;
}
}
};
std::ostream& operator<<(std::ostream& os, MinMaxSize t);
} // namespace tlbc

328
crypto/tl/tlbc-data.h Normal file
View file

@ -0,0 +1,328 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include <string>
#include <vector>
namespace tlbc {
using src::Lexem;
using src::Lexer;
using sym::sym_idx_t;
struct Type;
struct Constructor;
struct TypeExpr {
enum { te_Unknown, te_Type, te_Param, te_Apply, te_Add, te_MulConst, te_IntConst, te_Tuple, te_Ref, te_CondType };
enum { max_const_expr = 100000, const_htable_size = 170239 };
int tp;
int value;
Type* type_applied;
bool is_nat; // we keep integer expressions in 'TypeExpr' as well
bool is_nat_subtype; // this is # or a subtype of #
bool negated; // is it linearly negative
bool tchk_only; // type to be used as RHS of <field>:<type-expr> only
int is_constexpr; // if non-zero, it is an index in `const_type_expr`, the table of all constant type expressions
src::SrcLocation where;
std::vector<TypeExpr*> args;
TypeExpr(const src::SrcLocation& loc, int _tp, int _value = 0, bool _pol = false)
: tp(_tp)
, value(_value)
, type_applied(nullptr)
, is_nat_subtype(false)
, negated(_pol)
, tchk_only(false)
, is_constexpr(0)
, where(loc) {
init_is_nat();
}
TypeExpr(const src::SrcLocation& loc, int _tp, int _value, std::initializer_list<TypeExpr*> _arglist,
bool _pol = false)
: tp(_tp)
, value(_value)
, type_applied(nullptr)
, is_nat_subtype(false)
, negated(_pol)
, tchk_only(false)
, is_constexpr(0)
, where(loc)
, args(std::move(_arglist)) {
init_is_nat();
}
TypeExpr(const src::SrcLocation& loc, int _tp, int _value, std::vector<TypeExpr*> _arglist, bool _pol = false)
: tp(_tp)
, value(_value)
, type_applied(nullptr)
, is_nat_subtype(false)
, negated(_pol)
, tchk_only(false)
, is_constexpr(0)
, where(loc)
, args(std::move(_arglist)) {
init_is_nat();
}
void check_mode(const src::SrcLocation& loc, int mode);
bool no_tchk() const;
bool close(const src::SrcLocation& loc);
bool bind_value(bool value_negated, Constructor& cs, bool checking_type = false);
int abstract_interpret_nat() const;
MinMaxSize compute_size() const;
bool compute_any_bits() const;
bool detect_constexpr();
int is_integer() const;
bool is_anon() const;
bool is_ref_to_anon() const;
bool equal(const TypeExpr& other) const;
void const_type_name(std::ostream& os) const;
static TypeExpr* mk_intconst(const src::SrcLocation& loc, std::string int_const);
static TypeExpr* mk_intconst(const src::SrcLocation& loc, unsigned int_const);
static TypeExpr* mk_apply_gen(const src::SrcLocation& loc, TypeExpr* expr1, TypeExpr* expr2);
static TypeExpr* mk_mulint(const src::SrcLocation& loc, TypeExpr* expr1, TypeExpr* expr2);
static TypeExpr* mk_cellref(const src::SrcLocation& loc, TypeExpr* expr1);
static TypeExpr* mk_apply(const src::SrcLocation& loc, int tp, TypeExpr* expr1, TypeExpr* expr2);
static TypeExpr* mk_apply_empty(const src::SrcLocation& loc, sym_idx_t name, Type* type_applied);
void show(std::ostream& os, const Constructor* cs = nullptr, int prio = 0, int mode = 0) const;
private:
void init_is_nat() {
is_nat = (tp >= te_Add && tp <= te_IntConst);
}
unsigned long long compute_hash() const;
static TypeExpr* const_htable[const_htable_size];
};
// extern TypeExpr* TypeExpr::const_htable[TypeExpr::const_htable_size];
extern TypeExpr* const_type_expr[TypeExpr::max_const_expr];
extern int const_type_expr_num;
std::ostream& operator<<(std::ostream& os, const TypeExpr* te);
struct Field {
int field_idx;
bool implicit;
bool known;
bool constraint;
bool used;
bool subrec;
sym_idx_t name;
TypeExpr* type;
const src::SrcLocation loc;
Field(const src::SrcLocation& where, bool impl, int idx, sym_idx_t fname = 0, TypeExpr* ftype = nullptr)
: field_idx(idx)
, implicit(impl)
, known(false)
, constraint(false)
, used(false)
, subrec(false)
, name(fname)
, type(ftype)
, loc(where) {
}
void register_sym() const;
std::string get_name() const;
bool isomorphic_to(const Field& f, bool allow_other_names = true) const;
};
struct Constructor {
sym_idx_t constr_name;
sym_idx_t type_name;
Type* type_defined;
src::SrcLocation where;
unsigned long long tag;
int tag_bits;
int fields_num;
int type_arity;
bool is_fwd;
bool is_enum;
bool is_simple_enum;
bool is_special;
bool has_fixed_size;
bool any_bits;
MinMaxSize size;
BitPfxCollection begins_with;
std::vector<Field> fields;
std::vector<TypeExpr*> params;
std::vector<bool> param_negated;
std::vector<int> param_const_val; // -1 -- not integer or not constant
AdmissibilityInfo admissible_params;
void set_tag(unsigned long long new_tag) {
tag = new_tag;
tag_bits = (tag ? 63 - td::count_trailing_zeroes_non_zero64(tag) : -1);
}
Constructor(const src::SrcLocation& _loc = {}, sym_idx_t cname = 0, sym_idx_t tname = 0, unsigned long long _tag = 0,
Type* type = nullptr)
: constr_name(cname)
, type_name(tname)
, type_defined(type)
, where(_loc)
, fields_num(0)
, type_arity(0)
, is_fwd(false)
, is_enum(false)
, is_simple_enum(false)
, is_special(false)
, has_fixed_size(false)
, any_bits(false) {
set_tag(_tag);
}
Field& new_field(const src::SrcLocation& where, bool implicit, sym_idx_t name);
void show(std::ostream& os, int mode = 0) const;
std::string get_name() const;
std::string get_qualified_name() const;
bool isomorphic_to(const Constructor& cs, bool allow_other_names) const;
unsigned long long compute_tag() const;
void check_assign_tag();
bool compute_is_fwd();
bool recompute_begins_with();
bool recompute_minmax_size();
bool recompute_any_bits();
bool compute_admissible_params();
int get_const_param(unsigned idx) const {
return idx < param_const_val.size() ? param_const_val[idx] : -1;
}
};
std::ostream& operator<<(std::ostream& os, const Constructor& cs);
struct Type {
enum { _IsType = 1, _IsNat = 2, _IsPos = 4, _IsNeg = 8, _NonConst = 16 };
sym_idx_t type_name;
int type_idx;
int parent_type_idx;
int constr_num;
int arity;
int used;
int last_declared;
static int last_declared_counter;
bool produces_nat;
bool is_final;
bool is_builtin;
bool is_enum;
bool is_simple_enum;
bool is_special;
bool is_pfx_determ;
bool is_param_determ;
bool is_const_param_determ;
bool is_const_param_pfx_determ;
bool is_param_pfx_determ;
bool is_determ;
bool has_fixed_size;
bool any_bits;
bool is_auto;
bool is_anon;
bool is_unit;
bool is_bool;
signed char is_integer;
int useful_depth;
int const_param_idx;
int conflict1, conflict2;
MinMaxSize size;
std::vector<Constructor*> constructors;
std::vector<int> args;
BitPfxCollection begins_with;
AdmissibilityInfo admissible_params;
std::unique_ptr<BinTrie> cs_trie;
Type(int idx, sym_idx_t _tname = 0, bool pnat = false, int _arity = -1, bool _final = false, bool _nonempty = false)
: type_name(_tname)
, type_idx(idx)
, parent_type_idx(-1)
, constr_num(0)
, arity(_arity)
, used(0)
, last_declared(0)
, produces_nat(pnat)
, is_final(_final)
, is_builtin(_final)
, is_enum(!_final)
, is_simple_enum(!_final)
, is_special(false)
, is_pfx_determ(false)
, is_param_determ(false)
, is_const_param_determ(false)
, is_const_param_pfx_determ(false)
, is_param_pfx_determ(false)
, is_determ(false)
, has_fixed_size(false)
, any_bits(false)
, is_auto(false)
, is_anon(false)
, is_unit(false)
, is_bool(false)
, is_integer(pnat)
, useful_depth(-1)
, const_param_idx(-1)
, conflict1(-1)
, conflict2(-1) {
if (arity > 0) {
args.resize(arity, 0);
}
if (_nonempty) {
begins_with.all();
}
}
void bind_constructor(const src::SrcLocation& loc, Constructor* cs);
bool unique_constructor_equals(const Constructor& cs, bool allow_other_names = false) const;
void print_name(std::ostream& os) const;
std::string get_name() const;
bool recompute_begins_with();
bool recompute_minmax_size();
bool recompute_any_bits();
bool compute_admissible_params();
void compute_constructor_trie();
int detect_const_params();
bool check_conflicts();
void show_constructor_conflict();
void detect_basic_types();
bool cons_all_exact() const;
int cons_common_len() const;
bool is_const_arg(int p) const;
std::vector<int> get_all_param_values(int p) const;
std::vector<int> get_constr_by_param_value(int p, int pv) const;
void renew_last_declared() {
last_declared = ++last_declared_counter;
}
};
extern TypeExpr type_Type;
struct SymVal : sym::SymValBase {
TypeExpr* sym_type;
SymVal(int _type, int _idx, TypeExpr* _stype = nullptr) : sym::SymValBase(_type, _idx), sym_type(_stype) {
}
TypeExpr* get_type() const {
return sym_type;
}
};
struct SymValType : SymVal {
Type* type_ref;
explicit SymValType(Type* _type = nullptr) : SymVal(sym::SymValBase::_Typename, 0, &type_Type), type_ref(_type) {
}
};
extern sym_idx_t Nat_name, Eq_name, Less_name, Leq_name;
extern Type *Nat_type, *Eq_type;
extern Type *NatWidth_type, *NatLess_type, *NatLeq_type, *Int_type, *UInt_type;
extern int types_num, builtin_types_num;
extern std::vector<Type> types;
} // namespace tlbc

3412
crypto/tl/tlbc-gen-cpp.cpp Normal file

File diff suppressed because it is too large Load diff

290
crypto/tl/tlbc-gen-cpp.h Normal file
View file

@ -0,0 +1,290 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
namespace tlbc {
extern std::set<std::string> forbidden_cpp_idents, local_forbidden_cpp_idents;
struct CppIdentSet {
std::set<std::string> cpp_idents;
const std::set<std::string>* extra_forbidden_idents;
CppIdentSet(const std::set<std::string>* forbid = nullptr) : extra_forbidden_idents(forbid) {
}
static std::string compute_cpp_ident(std::string orig_ident, int count = 0);
std::string new_ident(std::string orig_ident, int count = 0, std::string suffix = "");
bool insert(std::string ident) {
return cpp_idents.insert(ident).second;
}
bool defined(std::string ident) {
return cpp_idents.count(ident);
}
bool is_good_ident(std::string ident);
void clear() {
cpp_idents.clear();
}
};
extern CppIdentSet global_cpp_ids;
struct Action {
int fixed_size;
bool is_pure;
bool is_constraint;
std::string action;
Action(int _size) : fixed_size(_size), is_pure(false), is_constraint(false) {
}
Action(std::string _action, bool _cst = false)
: fixed_size(-1), is_pure(false), is_constraint(_cst), action(_action) {
}
Action(const std::ostringstream& ss, bool _cst = false)
: fixed_size(-1), is_pure(false), is_constraint(_cst), action(ss.str()) {
}
Action(std::ostringstream&& ss, bool _cst = false)
: fixed_size(-1), is_pure(false), is_constraint(_cst), action(std::move(ss).str()) {
}
void show(std::ostream& os) const;
bool may_combine(const Action& next) const;
bool operator+=(const Action& next);
};
enum cpp_val_type {
ct_unknown,
ct_void = 1,
ct_slice = 2,
ct_cell = 3,
ct_typeref = 4,
ct_typeptr = 5,
ct_bits = 6,
ct_bitstring = 7,
ct_integer = 8,
ct_bool = 10,
ct_enum = 11,
ct_int32 = 12,
ct_uint32 = 13,
ct_int64 = 14,
ct_uint64 = 15,
ct_subrecord = 16
};
struct CppValType {
cpp_val_type vt;
int size;
CppValType(cpp_val_type _vt = ct_unknown, int _size = -1) : vt(_vt), size(_size) {
}
cpp_val_type get() const {
return vt;
}
void show(std::ostream& os, bool pass_value = false) const;
bool needs_move() const;
};
extern std::ostream& operator<<(std::ostream& os, CppValType cvt);
class CppTypeCode {
Type& type;
bool ok;
bool builtin;
bool inline_get_tag;
bool inline_skip;
bool inline_validate_skip;
bool simple_get_size;
bool simple_cons_tags;
bool incremental_cons_tags;
public:
int params;
int tot_params;
int ret_params;
int cons_num;
int common_cons_len;
std::vector<std::string> cons_enum_name;
std::vector<int> cons_enum_value;
std::vector<int> cons_tag_map;
std::vector<bool> cons_tag_exact;
std::vector<int> cons_idx_by_enum;
std::string cpp_type_var_name;
std::string cpp_type_class_name;
std::string cpp_type_template_name;
struct ConsRecord;
struct ConsField {
const Field& field;
const ConsRecord* subrec;
std::string name;
cpp_val_type ctype;
int size;
int orig_idx;
bool implicit;
ConsField(const Field& _field, std::string _name, cpp_val_type _ctype, int _size, int _idx,
const ConsRecord* _subrec = nullptr, bool _implicit = false)
: field(_field), subrec(_subrec), name(_name), ctype(_ctype), size(_size), orig_idx(_idx), implicit(_implicit) {
assert(ctype != ct_subrecord || subrec);
}
CppValType get_cvt() const {
return {ctype, size};
}
void print_type(std::ostream& os, bool pass_value = false) const;
};
struct ConsRecord {
const CppTypeCode& cpp_type;
const Constructor& constr;
int cons_idx;
bool is_trivial;
bool is_small;
bool triv_conflict;
bool has_trivial_name;
bool inline_record;
bool declared;
cpp_val_type equiv_cpp_type;
std::vector<cpp_val_type> equiv_cpp_types;
std::string cpp_name;
std::vector<ConsField> cpp_fields;
ConsRecord(const CppTypeCode& _cpp_type, const Constructor& _constr, int idx, bool _triv = false)
: cpp_type(_cpp_type), constr(_constr), cons_idx(idx), is_trivial(_triv), declared(false) {
}
bool recover_idents(CppIdentSet& idents) const;
void declare_record(std::ostream& os, std::string nl, int options);
bool declare_record_unpack(std::ostream& os, std::string nl, int options);
bool declare_record_pack(std::ostream& os, std::string nl, int options);
void print_full_name(std::ostream& os) const;
};
std::vector<ConsRecord> records;
private:
std::vector<std::string> type_param_name;
std::vector<bool> type_param_is_nat;
std::vector<bool> type_param_is_neg;
std::string template_args;
std::string constructor_args;
std::string skip_extra_args;
std::string skip_extra_args_pass;
CppIdentSet local_cpp_ids;
bool init();
public:
CppTypeCode(Type& _type) : type(_type), local_cpp_ids(&local_forbidden_cpp_idents) {
ok = init();
}
bool is_ok() const {
return ok;
}
void generate(std::ostream& os, int options = 0);
private:
bool compute_simple_cons_tags();
bool check_incremental_cons_tags() const;
unsigned long long compute_selector_mask() const;
void assign_class_name();
void assign_cons_names();
void assign_class_field_names();
void assign_cons_values();
void assign_record_cons_names();
void generate_cons_enum(std::ostream& os);
void generate_type_constructor(std::ostream& os, int options);
void generate_type_fields(std::ostream& os, int options);
void generate_header(std::ostream& os, int options = 0);
void generate_body(std::ostream& os, int options = 0);
void generate_cons_len_array(std::ostream& os, std::string nl, int options = 0);
void generate_cons_tag_array(std::ostream& os, std::string nl, int options = 0);
void generate_cons_tag_info(std::ostream& os, std::string nl, int options = 0);
void generate_skip_method(std::ostream& os, int options = 0);
void generate_skip_cons_method(std::ostream& os, std::string nl, int cidx, int options);
void generate_cons_tag_check(std::ostream& os, std::string nl, int cidx, bool force = false);
void generate_check_tag_method(std::ostream& os);
void generate_unpack_method(std::ostream& os, ConsRecord& rec, int options);
void generate_pack_method(std::ostream& os, ConsRecord& rec, int options);
void generate_ext_fetch_to(std::ostream& os, int options);
void generate_fetch_enum_method(std::ostream& os, int options);
void generate_store_enum_method(std::ostream& os, int options);
void generate_print_type_body(std::ostream& os, std::string nl);
void generate_print_method(std::ostream& os, int options = 0);
void generate_print_cons_method(std::ostream& os, std::string nl, int cidx, int options);
void generate_get_tag_body(std::ostream& os, std::string nl);
void generate_get_tag_subcase(std::ostream& os, std::string nl, const BinTrie* trie, int depth) const;
void generate_get_tag_param(std::ostream& os, std::string nl, unsigned long long tag,
unsigned long long params = std::numeric_limits<td::uint64>::max()) const;
void generate_get_tag_param1(std::ostream& os, std::string nl, const char A[4],
const std::string param_names[1]) const;
void generate_get_tag_param2(std::ostream& os, std::string nl, const char A[4][4],
const std::string param_names[2]) const;
void generate_get_tag_param3(std::ostream& os, std::string nl, const char A[4][4][4],
const std::string param_names[3]) const;
bool match_param_pattern(std::ostream& os, std::string nl, const char A[4], int mask, std::string pattern,
std::string param_name) const;
std::string get_nat_param_name(int idx) const;
void generate_tag_pfx_selector(std::ostream& os, std::string nl, const BinTrie& trie, int d, int min_size) const;
bool generate_get_tag_pfx_distinguisher(std::ostream& os, std::string nl, const std::vector<int>& constr_list,
bool in_block) const;
private:
std::vector<Action> actions;
int incomplete;
int tmp_ints;
bool needs_tmp_cell;
std::vector<std::string> tmp_vars;
std::vector<std::string> field_vars;
std::vector<bool> field_var_set;
std::vector<bool> param_var_set;
std::vector<bool> param_constraint_used;
std::vector<std::pair<std::string, const TypeExpr*>> postponed_equate;
CppIdentSet tmp_cpp_ids;
void clear_context();
void init_cons_context(const Constructor& constr);
std::string new_tmp_var(std::string hint);
std::string new_tmp_var();
void add_action(const Action& act);
void output_actions(std::ostream& os, std::string nl, int options);
void output_cpp_expr(std::ostream& os, const TypeExpr* expr, int prio = 0, bool allow_type_neg = false) const;
void output_cpp_sizeof_expr(std::ostream& os, const TypeExpr* expr, int prio) const;
void output_negative_type_arguments(std::ostream& os, const TypeExpr* expr);
bool can_compute(const TypeExpr* expr) const;
bool can_use_to_compute(const TypeExpr* expr, int i) const;
bool can_compute_sizeof(const TypeExpr* expr) const;
bool is_self(const TypeExpr* expr, const Constructor& constr) const;
void add_compute_actions(const TypeExpr* expr, int i, std::string bind_to);
void identify_cons_params(const Constructor& constr, int options);
void identify_cons_neg_params(const Constructor& constr, int options);
void bind_record_fields(const ConsRecord& rec, int options);
void add_cons_tag_check(const Constructor& constr, int cidx, int options);
void add_cons_tag_store(const Constructor& constr, int cidx);
std::string add_fetch_nat_field(const Constructor& constr, const Field& field, int options);
void add_store_nat_field(const Constructor& constr, const Field& field, int options);
void add_remaining_param_constraints_check(const Constructor& constr, int options);
void compute_implicit_field(const Constructor& constr, const Field& field, int options);
bool add_constraint_check(const Constructor& constr, const Field& field, int options);
void add_postponed_equate_actions();
void output_fetch_field(std::ostream& os, std::string field_name, const TypeExpr* expr, cpp_val_type cvt);
void output_fetch_subrecord(std::ostream& os, std::string field_name, const ConsRecord* subrec);
void output_store_field(std::ostream& os, std::string field_name, const TypeExpr* expr, cpp_val_type cvt);
void add_store_subrecord(std::string field_name, const ConsRecord* subrec);
void generate_skip_field(const Constructor& constr, const Field& field, int options);
void generate_print_field(const Constructor& constr, const Field& field, int options);
bool output_print_simple_field(std::ostream& os, const Field& field, std::string field_name, const TypeExpr* expr);
void generate_unpack_field(const ConsField& fi, const Constructor& constr, const Field& field, int options);
void generate_pack_field(const ConsField& fi, const Constructor& constr, const Field& field, int options);
};
extern std::vector<std::unique_ptr<CppTypeCode>> cpp_type;
extern bool add_type_members;
} // namespace tlbc

3078
crypto/tl/tlbc.cpp Normal file

File diff suppressed because it is too large Load diff

342
crypto/tl/tlblib.cpp Normal file
View file

@ -0,0 +1,342 @@
/*
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-2019 Telegram Systems LLP
*/
#include <tl/tlblib.hpp>
namespace tlb {
const False t_False;
const True t_True;
const Unit t_Unit;
const Bool t_Bool;
const Int t_int8{8}, t_int16{16}, t_int24{24}, t_int32{32}, t_int64{64}, t_int128{128}, t_int256{256}, t_int257{257};
const UInt t_uint8{8}, t_uint16{16}, t_uint24{24}, t_uint32{32}, t_uint64{64}, t_uint128{128}, t_uint256{256};
const NatWidth t_Nat{32};
const Anything t_Anything;
const RefAnything t_RefCell;
bool Bool::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
int t = get_tag(cs);
return cs.advance(1) && pp.out(t ? "bool_true" : "bool_false");
}
bool NatWidth::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
long long value = (long long)cs.fetch_ulong(32);
return value >= 0 && pp.out_int(value);
}
bool NatLeq::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
long long value = (long long)as_uint(cs);
return value >= 0 && skip(cs) && pp.out_int(value);
}
bool NatLess::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
long long value = (long long)as_uint(cs);
return value >= 0 && skip(cs) && pp.out_int(value);
}
bool TupleT::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
pp.open("tuple ");
pp.os << n << " [";
pp.mode_nl();
int i = n;
for (; i > 0; --i) {
if (!X.print_skip(pp, cs)) {
return false;
}
pp.mode_nl();
}
return pp.close("]");
}
bool CondT::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
return (n > 0 ? X.print_skip(pp, cs) : (!n && pp.out("()")));
}
bool Int::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
if (n <= 64) {
long long value;
return cs.fetch_int_to(n, value) && pp.out_int(value);
} else {
return pp.out_integer(cs.fetch_int256(n, true));
}
}
bool UInt::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
if (n <= 64) {
unsigned long long value;
return cs.fetch_uint_to(n, value) && pp.out_uint(value);
} else {
return pp.out_integer(cs.fetch_int256(n, false));
}
}
bool Bits::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
if (cs.have(n)) {
pp.os << 'x' << cs.fetch_bits(n).to_hex();
return true;
} else {
return false;
}
}
bool TupleT::skip(vm::CellSlice& cs) const {
int i = n;
for (; i > 0; --i) {
if (!X.skip(cs)) {
break;
}
}
return !i;
}
bool TupleT::validate_skip(vm::CellSlice& cs, bool weak) const {
int i = n;
for (; i > 0; --i) {
if (!X.validate_skip(cs, weak)) {
break;
}
}
return !i;
}
bool TLB::validate_ref_internal(Ref<vm::Cell> cell_ref, bool weak) const {
bool is_special;
auto cs = load_cell_slice_special(std::move(cell_ref), is_special);
return always_special() ? is_special : (is_special ? weak : (validate_skip(cs) && cs.empty_ext()));
}
bool TLB::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
pp.open("raw@");
pp << *this << ' ';
vm::CellSlice cs_copy{cs};
if (!validate_skip(cs) || !cs_copy.cut_tail(cs)) {
return pp.fail("invalid value");
}
pp.raw_nl();
cs_copy.print_rec(pp.os, pp.indent);
return pp.mkindent() && pp.close();
}
bool TLB::print_special(PrettyPrinter& pp, vm::CellSlice& cs) const {
pp.open("raw@");
pp << *this << ' ';
pp.raw_nl();
cs.print_rec(pp.os, pp.indent);
return pp.mkindent() && pp.close();
}
bool TLB::print_ref(PrettyPrinter& pp, Ref<vm::Cell> cell_ref) const {
if (cell_ref.is_null()) {
return pp.fail("null cell reference");
}
bool is_special;
auto cs = load_cell_slice_special(std::move(cell_ref), is_special);
if (is_special) {
return print_special(pp, cs);
} else {
return print_skip(pp, cs) && (cs.empty_ext() || pp.fail("extra data in cell"));
}
}
bool TLB::print_skip(std::ostream& os, vm::CellSlice& cs, int indent) const {
PrettyPrinter pp{os, indent};
return pp.fail_unless(print_skip(pp, cs));
}
bool TLB::print(std::ostream& os, const vm::CellSlice& cs, int indent) const {
PrettyPrinter pp{os, indent};
return pp.fail_unless(print(pp, cs));
}
bool TLB::print_ref(std::ostream& os, Ref<vm::Cell> cell_ref, int indent) const {
PrettyPrinter pp{os, indent};
return pp.fail_unless(print_ref(pp, std::move(cell_ref)));
}
std::string TLB::as_string_skip(vm::CellSlice& cs, int indent) const {
std::ostringstream os;
print_skip(os, cs, indent);
return os.str();
}
std::string TLB::as_string(const vm::CellSlice& cs, int indent) const {
std::ostringstream os;
print(os, cs, indent);
return os.str();
}
std::string TLB::as_string_ref(Ref<vm::Cell> cell_ref, int indent) const {
std::ostringstream os;
print_ref(os, std::move(cell_ref), indent);
return os.str();
}
PrettyPrinter::~PrettyPrinter() {
if (failed || level) {
if (nl_used) {
nl(-2 * level);
}
os << "PRINTING FAILED";
while (level > 0) {
os << ')';
--level;
}
}
if (nl_used) {
os << std::endl;
}
}
bool PrettyPrinter::fail(std::string msg) {
os << "<FATAL: " << msg << ">";
failed = true;
return false;
}
bool PrettyPrinter::mkindent(int delta) {
indent += delta;
for (int i = 0; i < indent; i++) {
os << ' ';
}
nl_used = true;
return true;
}
bool PrettyPrinter::nl(int delta) {
os << std::endl;
return mkindent(delta);
}
bool PrettyPrinter::raw_nl(int delta) {
os << std::endl;
indent += delta;
nl_used = true;
return true;
}
bool PrettyPrinter::open(std::string msg) {
os << "(" << msg;
indent += 2;
level++;
return true;
}
bool PrettyPrinter::close() {
return close("");
}
bool PrettyPrinter::close(std::string msg) {
if (level <= 0) {
return fail("cannot close scope");
}
indent -= 2;
--level;
os << msg << ")";
return true;
}
bool PrettyPrinter::mode_nl() {
if (mode & 1) {
return nl();
} else {
os << ' ';
return true;
}
}
bool PrettyPrinter::field(std::string name) {
mode_nl();
os << name << ':';
return true;
}
bool PrettyPrinter::field() {
mode_nl();
return true;
}
bool PrettyPrinter::field_int(long long x, std::string name) {
os << ' ' << name << ':' << x;
return true;
}
bool PrettyPrinter::field_int(long long x) {
os << ' ' << x;
return true;
}
bool PrettyPrinter::field_uint(unsigned long long x, std::string name) {
os << ' ' << name << ':' << x;
return true;
}
bool PrettyPrinter::field_uint(unsigned long long x) {
os << ' ' << x;
return true;
}
bool PrettyPrinter::fetch_bits_field(vm::CellSlice& cs, int n) {
os << " x";
return cs.have(n) && out(cs.fetch_bits(n).to_hex());
}
bool PrettyPrinter::fetch_bits_field(vm::CellSlice& cs, int n, std::string name) {
os << ' ' << name << ":x";
return cs.have(n) && out(cs.fetch_bits(n).to_hex());
}
bool PrettyPrinter::fetch_int_field(vm::CellSlice& cs, int n) {
return cs.have(n) && field_int(cs.fetch_long(n));
}
bool PrettyPrinter::fetch_int_field(vm::CellSlice& cs, int n, std::string name) {
return cs.have(n) && field_int(cs.fetch_long(n), name);
}
bool PrettyPrinter::fetch_uint_field(vm::CellSlice& cs, int n) {
return cs.have(n) && field_uint(cs.fetch_ulong(n));
}
bool PrettyPrinter::fetch_uint_field(vm::CellSlice& cs, int n, std::string name) {
return cs.have(n) && field_uint(cs.fetch_ulong(n), name);
}
bool PrettyPrinter::fetch_int256_field(vm::CellSlice& cs, int n) {
os << ' ';
return out_integer(cs.fetch_int256(n, true));
}
bool PrettyPrinter::fetch_int256_field(vm::CellSlice& cs, int n, std::string name) {
os << ' ' << name << ':';
return out_integer(cs.fetch_int256(n, true));
}
bool PrettyPrinter::fetch_uint256_field(vm::CellSlice& cs, int n) {
os << ' ';
return out_integer(cs.fetch_int256(n, false));
}
bool PrettyPrinter::fetch_uint256_field(vm::CellSlice& cs, int n, std::string name) {
os << ' ' << name << ':';
return out_integer(cs.fetch_int256(n, false));
}
} // namespace tlb

981
crypto/tl/tlblib.hpp Normal file
View file

@ -0,0 +1,981 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include <iostream>
#include "vm/cellslice.h"
namespace tlb {
using td::Ref;
using vm::CellSlice;
struct PrettyPrinter;
class TLB {
public:
virtual ~TLB() = default;
virtual int get_size(const vm::CellSlice& cs) const {
return -1;
}
virtual bool skip(vm::CellSlice& cs) const {
return cs.skip_ext(get_size(cs));
}
virtual bool validate(const vm::CellSlice& cs, bool weak = false) const {
return cs.have_ext(get_size(cs));
}
virtual bool validate_exact(const vm::CellSlice& cs, bool weak = false) const {
return (int)cs.size_ext() == get_size(cs);
}
bool validate_csr(Ref<vm::CellSlice> cs_ref, bool weak = false) const {
return cs_ref.not_null() && validate_skip_exact(cs_ref.write(), weak);
}
Ref<vm::CellSlice> fetch(vm::CellSlice& cs) const {
return cs.fetch_subslice_ext(get_size(cs));
}
Ref<vm::CellSlice> prefetch(const vm::CellSlice& cs) const {
return cs.prefetch_subslice_ext(get_size(cs));
}
virtual Ref<vm::CellSlice> validate_fetch(vm::CellSlice& cs, bool weak = false) const {
return validate(cs, weak) ? cs.fetch_subslice_ext(get_size(cs)) : Ref<vm::CellSlice>{};
}
virtual Ref<vm::CellSlice> validate_prefetch(const vm::CellSlice& cs, bool weak = false) const {
return validate(cs, weak) ? cs.prefetch_subslice_ext(get_size(cs)) : Ref<vm::CellSlice>{};
}
bool fetch_to(vm::CellSlice& cs, Ref<vm::CellSlice>& res) const {
return (res = fetch(cs)).not_null();
}
bool validate_fetch_to(vm::CellSlice& cs, Ref<vm::CellSlice>& res, bool weak = false) const {
return (res = validate_fetch(cs, weak)).not_null();
}
bool store_from(vm::CellBuilder& cb, Ref<vm::CellSlice> field) const {
return field.not_null() && get_size(*field) == (int)field->size_ext() && cb.append_cellslice_bool(std::move(field));
}
bool validate_store_from(vm::CellBuilder& cb, Ref<vm::CellSlice> field, bool weak = false) const {
if (field.is_null()) {
return false;
}
vm::CellSlice cs{*field};
return validate_skip(cs, weak) && cs.empty_ext() && cb.append_cellslice_bool(std::move(field));
}
virtual bool extract(vm::CellSlice& cs) const {
return cs.only_ext(get_size(cs));
}
virtual bool validate_extract(vm::CellSlice& cs, bool weak = false) const {
return validate(cs, weak) && extract(cs);
}
int get_size_by_skip(const vm::CellSlice& cs) const {
vm::CellSlice copy{cs};
return skip(copy) ? copy.subtract_base_ext(cs) : -1;
}
virtual bool validate_skip(vm::CellSlice& cs, bool weak = false) const {
return validate(cs, weak) && skip(cs);
}
bool validate_skip_exact(vm::CellSlice& cs, bool weak = false) const {
return validate_skip(cs, weak) && cs.empty_ext();
}
bool validate_by_skip(const vm::CellSlice& cs, bool weak = false) const {
vm::CellSlice copy{cs};
return validate_skip(copy, weak);
}
bool validate_by_skip_exact(const vm::CellSlice& cs, bool weak = false) const {
vm::CellSlice copy{cs};
return validate_skip_exact(copy, weak);
}
bool extract_by_skip(vm::CellSlice& cs) const {
vm::CellSlice copy{cs};
return skip(copy) && cs.cut_tail(copy);
}
bool validate_extract_by_skip(vm::CellSlice& cs, bool weak = false) const {
vm::CellSlice copy{cs};
return validate_skip(copy, weak) && cs.cut_tail(copy);
}
Ref<vm::CellSlice> validate_fetch_by_skip(vm::CellSlice& cs, bool weak = false) const {
Ref<vm::CellSlice> copy{true, cs};
return validate_skip(cs, weak) && copy.unique_write().cut_tail(cs) ? copy : Ref<vm::CellSlice>{};
}
Ref<vm::CellSlice> validate_prefetch_by_skip(const vm::CellSlice& cs, bool weak = false) const {
vm::CellSlice copy{cs};
return validate_skip(copy, false) ? cs.prefetch_subslice_ext(copy.subtract_base_ext(cs)) : Ref<vm::CellSlice>{};
}
virtual bool skip_copy(vm::CellBuilder& cb, vm::CellSlice& cs) const {
return cb.append_cellslice_bool(fetch(cs));
}
virtual bool copy(vm::CellBuilder& cb, const vm::CellSlice& cs) const {
return cb.append_cellslice_bool(prefetch(cs));
}
virtual bool always_special() const {
return false;
}
virtual int get_tag(const vm::CellSlice& cs) const {
return -1;
}
virtual int check_tag(const vm::CellSlice& cs) const {
return get_tag(cs);
}
bool has_valid_tag(const vm::CellSlice& cs) const {
return check_tag(cs) >= 0;
}
virtual long long as_int(const vm::CellSlice& cs) const {
return -1;
}
virtual unsigned long long as_uint(const vm::CellSlice& cs) const {
return static_cast<unsigned long long>(-1);
}
virtual td::RefInt256 as_integer(const vm::CellSlice& cs) const {
return {};
}
virtual td::RefInt256 as_integer_skip(vm::CellSlice& cs) const {
return {};
}
virtual td::RefInt256 as_integer(Ref<vm::CellSlice> cs) const {
return as_integer(*cs);
}
bool as_integer_skip_to(vm::CellSlice& cs, td::RefInt256& res) const {
return (res = as_integer_skip(cs)).not_null();
}
bool as_integer_to(const vm::CellSlice& cs, td::RefInt256& res) const {
return (res = as_integer(cs)).not_null();
}
bool as_integer_to(Ref<vm::CellSlice> cs_ref, td::RefInt256& res) const {
return (res = as_integer(std::move(cs_ref))).not_null();
}
bool validate_ref(Ref<vm::Cell> cell_ref, bool weak = false) const {
return cell_ref.not_null() && validate_ref_internal(std::move(cell_ref), weak);
}
bool force_validate_ref(Ref<vm::Cell> cell_ref) const {
return cell_ref.not_null() && validate_ref_internal(std::move(cell_ref), false);
}
bool validate_skip_ref(vm::CellSlice& cs, bool weak = false) const {
return validate_ref(cs.fetch_ref(), weak);
}
virtual bool null_value(vm::CellBuilder& cb) const {
return false;
}
virtual bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const {
return false;
}
virtual bool store_long(vm::CellBuilder& cb, long long value) const {
return store_integer_value(cb, td::BigInt256{value});
}
virtual bool store_integer_ref(vm::CellBuilder& cb, td::RefInt256 value) const {
return value.not_null() && store_integer_value(cb, *value);
}
virtual bool add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const {
td::RefInt256 x = as_integer_skip(cs1), y = as_integer_skip(cs2);
return x.not_null() && y.not_null() && store_integer_ref(cb, x += std::move(y));
}
// result: -1 = error, 0 = ok (zero), 1 = ok
virtual int sub_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const {
td::RefInt256 x = as_integer_skip(cs1), y = as_integer_skip(cs2);
return x.not_null() && y.not_null() && store_integer_ref(cb, x -= std::move(y)) ? (td::sgn(x) ? 1 : 0) : -1;
}
template <typename... Args>
bool unpack(Ref<vm::CellSlice> cs_ref, Args&... args) const {
return cs_ref.not_null() && unpack(cs_ref.write(), args...) && cs_ref->empty_ext();
}
virtual std::ostream& print_type(std::ostream& os) const {
return os << "<unknown-TLB-type>";
}
virtual bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const;
virtual bool print(PrettyPrinter& pp, const vm::CellSlice& cs) const {
vm::CellSlice cs_copy{cs};
return print_skip(pp, cs_copy);
}
bool print_special(PrettyPrinter& pp, vm::CellSlice& cs) const;
bool print_ref(PrettyPrinter& pp, Ref<vm::Cell> cell_ref) const;
bool print(PrettyPrinter& pp, Ref<vm::CellSlice> cs_ref) const {
return print(pp, *cs_ref);
}
bool print_skip(std::ostream& os, vm::CellSlice& cs, int indent = 0) const;
bool print(std::ostream& os, const vm::CellSlice& cs, int indent = 0) const;
bool print(std::ostream& os, Ref<vm::CellSlice> cs_ref, int indent = 0) const {
return print(os, *cs_ref, indent);
}
bool print_ref(std::ostream& os, Ref<vm::Cell> cell_ref, int indent = 0) const;
std::string as_string_skip(vm::CellSlice& cs, int indent = 0) const;
std::string as_string(const vm::CellSlice& cs, int indent = 0) const;
std::string as_string(Ref<vm::CellSlice> cs_ref, int indent = 0) const {
return cs_ref.not_null() ? as_string(*cs_ref, indent) : "<null>";
}
std::string as_string_ref(Ref<vm::Cell> cell_ref, int indent = 0) const;
protected:
bool validate_ref_internal(Ref<vm::Cell> cell_ref, bool weak = false) const;
};
static inline std::ostream& operator<<(std::ostream& os, const TLB& type) {
return type.print_type(os);
}
struct TLB_Complex : TLB {
bool skip(vm::CellSlice& cs) const override {
return validate_skip(cs);
}
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override = 0;
int get_size(const vm::CellSlice& cs) const override {
return get_size_by_skip(cs);
}
bool validate(const vm::CellSlice& cs, bool weak = false) const override {
return validate_by_skip(cs, weak);
}
bool validate_exact(const vm::CellSlice& cs, bool weak = false) const override {
return validate_by_skip_exact(cs, weak);
}
bool extract(vm::CellSlice& cs) const override {
return extract_by_skip(cs);
}
bool validate_extract(vm::CellSlice& cs, bool weak = false) const override {
return validate_extract_by_skip(cs, weak);
}
Ref<vm::CellSlice> validate_fetch(vm::CellSlice& cs, bool weak = false) const override {
return validate_fetch_by_skip(cs, weak);
}
Ref<vm::CellSlice> validate_prefetch(const vm::CellSlice& cs, bool weak = false) const override {
return validate_prefetch_by_skip(cs, weak);
}
td::RefInt256 as_integer(const vm::CellSlice& cs) const override {
vm::CellSlice copy{cs};
auto res = as_integer_skip(copy);
return res.not_null() && copy.empty_ext() ? std::move(res) : td::RefInt256{};
}
td::RefInt256 as_integer(Ref<vm::CellSlice> cs) const override {
auto res = as_integer_skip(cs.write());
return res.not_null() && cs->empty_ext() ? std::move(res) : td::RefInt256{};
}
};
static inline bool add_chk(int x, int y, int z) {
return x + y == z && z >= 0;
}
static inline bool add_r1(int& x, int y, int z) {
return z >= y && (x = z - y) >= 0;
}
static inline bool add_r3(int& x, int y, int& z) {
return (z = (x + y)) >= 0;
}
static inline bool mul_chk(int x, int y, int z) {
return (long long)x * y == z;
}
static inline bool mul_r1(int& x, int y, int z) {
return y && !(z % y) && (x = z / y) >= 0;
}
static inline bool mul_r3(int x, int y, int& z) {
unsigned long long t = (unsigned long long)x * y;
if (t <= 0x7fffffff) {
z = (int)t;
return true;
} else {
return false;
}
}
static inline int mul_bound(int x, int y) {
unsigned long long t = (unsigned long long)x * y;
return t <= 0x7fffffff ? (int)t : 0x7fffffff;
}
// templatized unpack functions
template <typename R, typename... Args>
bool unpack(vm::CellSlice& cs, R& rec, Args&... args) {
return (typename R::type_class{}).unpack(cs, rec, args...);
}
template <typename R, typename... Args>
bool unpack_exact(vm::CellSlice& cs, R& rec, Args&... args) {
return (typename R::type_class{}).unpack(cs, rec, args...) && cs.empty_ext();
}
template <typename T, typename R, typename... Args>
bool type_unpack(vm::CellSlice& cs, const T& type, R& rec, Args&... args) {
return type.unpack(cs, rec, args...);
}
template <typename T, typename R, typename... Args>
bool type_unpack_exact(vm::CellSlice& cs, const T& type, R& rec, Args&... args) {
return type.unpack(cs, rec, args...) && cs.empty_ext();
}
template <typename R, typename... Args>
bool csr_unpack(Ref<vm::CellSlice> csr, R& rec, Args&... args) {
return (typename R::type_class{}).unpack(csr.write(), rec, args...) && csr->empty_ext();
}
template <typename R, typename... Args>
bool csr_unpack_safe(Ref<vm::CellSlice> csr, R& rec, Args&... args) {
return csr.not_null() && (typename R::type_class{}).unpack(csr.write(), rec, args...) && csr->empty_ext();
}
template <typename R, typename... Args>
bool unpack_cell(Ref<vm::Cell> cell, R& rec, Args&... args) {
vm::CellSlice cs = vm::load_cell_slice(std::move(cell));
return cs.is_valid() && (typename R::type_class{}).unpack(cs, rec, args...) && cs.empty_ext();
}
template <typename R, typename... Args>
bool unpack_cell_inexact(Ref<vm::Cell> cell, R& rec, Args&... args) {
vm::CellSlice cs = vm::load_cell_slice(std::move(cell));
return cs.is_valid() && (typename R::type_class{}).unpack(cs, rec, args...);
}
template <typename T, typename R, typename... Args>
bool type_unpack_cell(Ref<vm::Cell> cell, const T& type, R& rec, Args&... args) {
vm::CellSlice cs = vm::load_cell_slice(std::move(cell));
return cs.is_valid() && type.unpack(cs, rec, args...) && cs.empty_ext();
}
template <typename T, typename R, typename... Args>
bool csr_type_unpack(Ref<vm::CellSlice> csr, const T& type, R& rec, Args&... args) {
return type.unpack(csr.write(), rec, args...) && csr->empty_ext();
}
template <typename R, typename... Args>
bool csr_unpack_inexact(Ref<vm::CellSlice> csr, R& rec, Args&... args) {
return (typename R::type_class{}).unpack(csr.write(), rec, args...);
}
template <typename T, typename R, typename... Args>
bool csr_type_unpack_inexact(Ref<vm::CellSlice> csr, const T& type, R& rec, Args&... args) {
return type.unpack(csr.write(), rec, args...);
}
template <typename R, typename... Args>
bool csr_unpack_skip(Ref<vm::CellSlice>& csr, R& rec, Args&... args) {
return (typename R::type_class{}).unpack(csr.write(), rec, args...);
}
template <typename T, typename R, typename... Args>
bool csr_type_unpack_skip(Ref<vm::CellSlice>& csr, const T& type, R& rec, Args&... args) {
return type.unpack(csr.write(), rec, args...);
}
// templatized pack functions
template <typename R, typename... Args>
bool pack(vm::CellBuilder& cb, const R& rec, Args&... args) {
return (typename R::type_class{}).pack(cb, rec, args...);
}
template <typename T, typename R, typename... Args>
bool type_pack(vm::CellBuilder& cb, const T& type, const R& rec, Args&... args) {
return type.pack(cb, rec, args...);
}
template <typename R, typename... Args>
bool pack_cell(Ref<vm::Cell>& cell, const R& rec, Args&... args) {
vm::CellBuilder cb;
return pack(cb, rec, args...) && cb.finalize_to(cell);
}
template <typename T, typename R, typename... Args>
bool type_pack_cell(Ref<vm::Cell>& cell, const T& type, const R& rec, Args&... args) {
vm::CellBuilder cb;
return type.pack(cb, rec, args...) && cb.finalize_to(cell);
}
template <typename R, typename... Args>
bool csr_pack(Ref<vm::CellSlice>& csr, const R& rec, Args&... args) {
vm::CellBuilder cb;
Ref<vm::Cell> cell;
return pack(cb, rec, args...) && cb.finalize_to(cell) && (csr = vm::load_cell_slice_ref(std::move(cell))).not_null();
}
template <typename T, typename R, typename... Args>
bool csr_type_pack(Ref<vm::CellSlice>& csr, const T& type, const R& rec, Args&... args) {
vm::CellBuilder cb;
Ref<vm::Cell> cell;
return type.pack(cb, rec, args...) && cb.finalize_to(cell) &&
(csr = vm::load_cell_slice_ref(std::move(cell))).not_null();
}
// templatized store_from function
template <typename T, typename... Args>
bool store_from(vm::CellBuilder& cb, const T& tlb_type, Ref<vm::CellSlice> field, Args&... args) {
if (field.is_null()) {
return false;
}
vm::CellSlice cs{*field};
return tlb_type.skip(cs, args...) && cs.empty_ext() && cb.append_cellslice_bool(std::move(field));
}
} // namespace tlb
namespace tlb {
struct PrettyPrinter {
std::ostream& os;
int indent;
int level;
bool failed;
bool nl_used;
int mode;
PrettyPrinter(std::ostream& _os, int _indent = 0, int _mode = 1)
: os(_os), indent(_indent), level(0), failed(false), nl_used(false), mode(_mode) {
}
~PrettyPrinter();
bool ok() const {
return !failed && !level;
}
bool fail_unless(bool res) {
if (!res) {
failed = true;
}
return res;
}
bool fail(std::string msg);
bool nl(int delta = 0);
bool raw_nl(int delta = 0);
bool mkindent(int delta = 0);
bool mode_nl();
bool open(std::string msg = "");
bool close();
bool close(std::string msg);
bool field(std::string name);
bool field();
bool field_int(long long value);
bool field_int(long long value, std::string name);
bool field_uint(unsigned long long value);
bool field_uint(unsigned long long value, std::string name);
bool out(std::string str) {
os << str;
return true;
}
bool out_int(long long value) {
os << value;
return true;
}
bool out_uint(unsigned long long value) {
os << value;
return true;
}
bool out_integer(td::RefInt256 value) {
if (value.not_null()) {
os << std::move(value);
return true;
} else {
return false;
}
}
bool cons(std::string str) {
return out(str);
}
bool fetch_bits_field(vm::CellSlice& cs, int n);
bool fetch_bits_field(vm::CellSlice& cs, int n, std::string name);
bool fetch_int_field(vm::CellSlice& cs, int n);
bool fetch_int_field(vm::CellSlice& cs, int n, std::string name);
bool fetch_uint_field(vm::CellSlice& cs, int n);
bool fetch_uint_field(vm::CellSlice& cs, int n, std::string name);
bool fetch_int256_field(vm::CellSlice& cs, int n);
bool fetch_int256_field(vm::CellSlice& cs, int n, std::string name);
bool fetch_uint256_field(vm::CellSlice& cs, int n);
bool fetch_uint256_field(vm::CellSlice& cs, int n, std::string name);
template <typename T>
PrettyPrinter& operator<<(const T& value) {
os << value;
return *this;
}
};
} // namespace tlb
namespace tlb {
struct False final : TLB {
int get_size(const vm::CellSlice& cs) const override {
return -1;
}
std::ostream& print_type(std::ostream& os) const override {
return os << "False";
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override {
return false;
}
};
extern const False t_False;
struct True final : TLB {
int get_size(const vm::CellSlice& cs) const override {
return 0;
}
std::ostream& print_type(std::ostream& os) const override {
return os << "True";
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override {
return pp.out("true");
}
};
extern const True t_True;
struct Unit final : TLB {
int get_size(const vm::CellSlice& cs) const override {
return 0;
}
std::ostream& print_type(std::ostream& os) const override {
return os << "Unit";
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override {
return pp.out("()");
}
};
struct FwdT final : TLB {
const TLB& X;
FwdT(const TLB& _X) : X(_X) {
}
int get_size(const vm::CellSlice& cs) const override {
return X.get_size(cs);
}
bool skip(vm::CellSlice& cs) const override {
return X.skip(cs);
}
bool validate(const vm::CellSlice& cs, bool weak = false) const override {
return X.validate(cs, weak);
}
Ref<vm::CellSlice> validate_fetch(vm::CellSlice& cs, bool weak = false) const override {
return X.validate_fetch(cs, weak);
}
Ref<vm::CellSlice> validate_prefetch(const vm::CellSlice& cs, bool weak = false) const override {
return X.validate_prefetch(cs, weak);
}
bool extract(vm::CellSlice& cs) const override {
return X.extract(cs);
}
bool validate_extract(vm::CellSlice& cs, bool weak = false) const override {
return X.validate_extract(cs, weak);
}
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
return X.validate_skip(cs, weak);
}
bool skip_copy(vm::CellBuilder& cb, vm::CellSlice& cs) const override {
return X.skip_copy(cb, cs);
}
bool copy(vm::CellBuilder& cb, const vm::CellSlice& cs) const override {
return X.copy(cb, cs);
}
int get_tag(const vm::CellSlice& cs) const override {
return X.get_tag(cs);
}
long long as_int(const vm::CellSlice& cs) const override {
return X.as_int(cs);
}
unsigned long long as_uint(const vm::CellSlice& cs) const override {
return X.as_uint(cs);
}
td::RefInt256 as_integer(const vm::CellSlice& cs) const override {
return X.as_integer(cs);
}
td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override {
return X.as_integer_skip(cs);
}
td::RefInt256 as_integer(Ref<vm::CellSlice> cs) const override {
return X.as_integer(std::move(cs));
}
bool null_value(vm::CellBuilder& cb) const override {
return X.null_value(cb);
}
bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override {
return X.store_integer_value(cb, value);
}
bool store_integer_ref(vm::CellBuilder& cb, td::RefInt256 value) const override {
return X.store_integer_ref(cb, std::move(value));
}
bool add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const override {
return X.add_values(cb, cs1, cs2);
}
std::ostream& print_type(std::ostream& os) const override {
return X.print_type(os);
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override {
return X.print_skip(pp, cs);
}
};
extern const Unit t_Unit;
struct Bool final : TLB {
enum { bool_false = 0, bool_true = 1 };
int get_size(const vm::CellSlice& cs) const override {
return 1;
}
int get_tag(const vm::CellSlice& cs) const override {
return (int)cs.prefetch_ulong(1);
}
std::ostream& print_type(std::ostream& os) const override {
return os << "Bool";
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
};
extern const Bool t_Bool;
struct NatWidth final : TLB {
int n;
NatWidth(int _n) : n(_n) {
}
int get_size(const vm::CellSlice& cs) const override {
return n <= 32 ? n : -1;
}
td::RefInt256 as_integer(const vm::CellSlice& cs) const override {
return cs.prefetch_int256(n, false);
}
td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override {
return cs.fetch_int256(n, false);
}
unsigned long long as_uint(const vm::CellSlice& cs) const override {
return n <= 32 ? cs.prefetch_ulong(n) : -1;
}
std::ostream& print_type(std::ostream& os) const override {
return os << "(## " << n << ')';
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
};
extern const NatWidth t_Nat;
struct NatLess final : TLB {
int n, w;
NatLess(int _n) : n(_n - 1), w(32 - td::count_leading_zeroes32(_n - 1)) {
}
int get_size(const vm::CellSlice& cs) const override {
return n >= 0 ? w : -1;
}
bool validate(const vm::CellSlice& cs, bool weak = false) const override {
return n >= 0 && (unsigned)cs.prefetch_ulong(w) <= (unsigned)n;
}
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
return n >= 0 && (unsigned)cs.fetch_ulong(w) <= (unsigned)n;
}
unsigned long long as_uint(const vm::CellSlice& cs) const override {
unsigned long long r = cs.prefetch_ulong(w);
return n >= 0 && (unsigned)r <= (unsigned)n ? r : std::numeric_limits<td::uint64>::max();
}
std::ostream& print_type(std::ostream& os) const override {
return os << "(#< " << n << ')';
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
};
struct NatLeq final : TLB {
int n, w;
NatLeq(int _n) : n(_n), w(32 - td::count_leading_zeroes32(_n)) {
}
int get_size(const vm::CellSlice& cs) const override {
return n >= 0 ? w : -1;
}
bool validate(const vm::CellSlice& cs, bool weak = false) const override {
return n >= 0 && (unsigned)cs.prefetch_ulong(w) <= (unsigned)n;
}
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
return n >= 0 && (unsigned)cs.fetch_ulong(w) <= (unsigned)n;
}
unsigned long long as_uint(const vm::CellSlice& cs) const override {
unsigned long long r = cs.prefetch_ulong(w);
return n >= 0 && (unsigned)r <= (unsigned)n ? r : std::numeric_limits<td::uint64>::max();
}
std::ostream& print_type(std::ostream& os) const override {
return os << "(#<= " << n << ')';
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
};
struct TupleT final : TLB_Complex {
int n;
const TLB& X;
TupleT(int _n, const TLB& _X) : n(_n), X(_X) {
}
bool skip(vm::CellSlice& cs) const override;
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
int get_tag(const vm::CellSlice& cs) const override {
return 0;
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
};
struct CondT final : TLB_Complex {
int n;
const TLB& X;
CondT(int _n, const TLB& _X) : n(_n), X(_X) {
}
bool skip(vm::CellSlice& cs) const override {
return !n || X.skip(cs);
}
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
return !n || (n > 0 && X.validate_skip(cs, weak));
}
int get_tag(const vm::CellSlice& cs) const override {
return 0;
}
std::ostream& print_type(std::ostream& os) const override {
return os << "(CondT " << n << ' ' << X << ')';
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
};
template <typename T>
struct Cond final : TLB_Complex {
int n;
T field_type;
template <typename... Args>
Cond(int _n, Args... args) : n(_n), field_type(args...) {
}
bool skip(vm::CellSlice& cs) const override {
return !n || field_type.skip(cs);
}
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
return !n || (n > 0 && field_type.validate_skip(cs, weak));
}
int get_tag(const vm::CellSlice& cs) const override {
return 0;
}
std::ostream& print_type(std::ostream& os) const override {
return os << "(Cond " << n << ' ' << field_type << ')';
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override {
return (n > 0 ? field_type.print_skip(pp, cs) : (!n && pp.out("()")));
}
};
struct Int final : TLB {
int n;
Int(int _n) : n(_n) {
}
int get_size(const vm::CellSlice& cs) const override {
return n;
}
td::RefInt256 as_integer(const vm::CellSlice& cs) const override {
return cs.prefetch_int256(n, true);
}
td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override {
return cs.fetch_int256(n, true);
}
long long as_int(const vm::CellSlice& cs) const override {
return n <= 64 ? cs.prefetch_long(n) : (1ULL << 63);
}
bool null_value(vm::CellBuilder& cb) const override {
return cb.store_zeroes_bool(n);
}
bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override {
return cb.store_int256_bool(value, n, true);
}
std::ostream& print_type(std::ostream& os) const override {
return os << "int" << n;
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
};
extern const Int t_int8, t_int16, t_int24, t_int32, t_int64, t_int128, t_int256, t_int257;
struct UInt final : TLB {
int n;
UInt(int _n) : n(_n) {
}
int get_size(const vm::CellSlice& cs) const override {
return n;
}
td::RefInt256 as_integer(const vm::CellSlice& cs) const override {
return cs.prefetch_int256(n, false);
}
td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override {
return cs.fetch_int256(n, false);
}
unsigned long long as_uint(const vm::CellSlice& cs) const override {
return n <= 64 ? cs.prefetch_ulong(n) : -1;
}
bool null_value(vm::CellBuilder& cb) const override {
return cb.store_zeroes_bool(n);
}
bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override {
return cb.store_int256_bool(value, n, false);
}
std::ostream& print_type(std::ostream& os) const override {
return os << "uint" << n;
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
};
extern const UInt t_uint8, t_uint16, t_uint24, t_uint32, t_uint64, t_uint128, t_uint256;
struct Bits final : TLB {
int n;
Bits(int _n) : n(_n) {
}
int get_size(const vm::CellSlice& cs) const override {
return n;
}
bool null_value(vm::CellBuilder& cb) const override {
return cb.store_zeroes_bool(n);
}
std::ostream& print_type(std::ostream& os) const override {
return os << "bits" << n;
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
};
template <class T>
struct Maybe : TLB_Complex {
T field_type;
template <typename... Args>
Maybe(Args... args) : field_type(args...) {
}
bool skip(vm::CellSlice& cs) const override;
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
int get_tag(const vm::CellSlice& cs) const override {
return cs.have(1) ? (int)cs.prefetch_ulong(1) : -1;
}
std::ostream& print_type(std::ostream& os) const override {
return os << "(Maybe " << field_type << ')';
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
};
template <class T>
bool Maybe<T>::skip(vm::CellSlice& cs) const {
int t = get_tag(cs);
if (t > 0) {
return cs.advance(1) && field_type.skip(cs);
} else if (!t) {
return cs.advance(1);
} else {
return false;
}
}
template <class T>
bool Maybe<T>::validate_skip(vm::CellSlice& cs, bool weak) const {
int t = get_tag(cs);
if (t > 0) {
return cs.advance(1) && field_type.validate_skip(cs, weak);
} else if (!t) {
return cs.advance(1);
} else {
return false;
}
}
template <class T>
bool Maybe<T>::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
if (!get_tag(cs)) {
return cs.advance(1) && pp.out("nothing");
} else {
return cs.advance(1) && pp.open("just ") && field_type.print_skip(pp, cs) && pp.close();
}
}
struct RefAnything final : TLB {
int get_size(const vm::CellSlice& cs) const override {
return 0x10000;
}
std::ostream& print_type(std::ostream& os) const override {
return os << "^Cell";
}
};
extern const RefAnything t_RefCell;
struct Anything final : TLB {
int get_size(const vm::CellSlice& cs) const override {
return cs.size_ext();
}
std::ostream& print_type(std::ostream& os) const override {
return os << "Any";
}
};
extern const Anything t_Anything;
template <class T>
struct RefTo final : TLB {
T ref_type;
template <typename... Args>
RefTo(Args... args) : ref_type(args...) {
}
int get_size(const vm::CellSlice& cs) const override {
return 0x10000;
}
bool validate(const vm::CellSlice& cs, bool weak = false) const override {
return cs.size_refs() ? ref_type.validate_ref(cs.prefetch_ref(), weak) : false;
}
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
return ref_type.validate_skip_ref(cs, weak);
}
std::ostream& print_type(std::ostream& os) const override {
return os << '^' << ref_type;
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override {
return pp.out("^") && ref_type.print_ref(pp, cs.fetch_ref());
}
};
struct RefT final : TLB {
const TLB& X;
RefT(const TLB& _X) : X(_X) {
}
int get_size(const vm::CellSlice& cs) const override {
return 0x10000;
}
bool validate(const vm::CellSlice& cs, bool weak = false) const override {
return X.validate_ref(cs.prefetch_ref(), weak);
}
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
return X.validate_skip_ref(cs, weak);
}
std::ostream& print_type(std::ostream& os) const override {
return os << '^' << X;
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override {
return pp.out("^") && X.print_ref(pp, cs.fetch_ref());
}
};
template <class T1, class T2>
struct Either final : TLB_Complex {
T1 left_type;
T2 right_type;
bool skip(vm::CellSlice& cs) const override {
return cs.have(1) ? (cs.fetch_ulong(1) ? right_type.skip(cs) : left_type.skip(cs)) : false;
}
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
return cs.have(1) ? (cs.fetch_ulong(1) ? right_type.validate_skip(cs, weak) : left_type.validate_skip(cs, weak))
: false;
}
int get_tag(const vm::CellSlice& cs) const override {
return (int)cs.prefetch_ulong(1);
}
std::ostream& print_type(std::ostream& os) const override {
return os << "(Either " << left_type << ' ' << right_type << ')';
}
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
};
template <class T1, class T2>
bool Either<T1, T2>::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
if (!get_tag(cs)) {
return cs.advance(1) && pp.open("left ") && left_type.print_skip(pp, cs) && pp.close();
} else {
return cs.advance(1) && pp.open("right ") && right_type.print_skip(pp, cs) && pp.close();
}
}
} // namespace tlb