mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
initial commit
This commit is contained in:
commit
c2da007f40
1610 changed files with 398047 additions and 0 deletions
45
crypto/tl/boc.tlb
Normal file
45
crypto/tl/boc.tlb
Normal 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
60
crypto/tl/hashmap.tlb
Normal 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
262
crypto/tl/tlbc-aux.h
Normal 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
328
crypto/tl/tlbc-data.h
Normal 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
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
290
crypto/tl/tlbc-gen-cpp.h
Normal 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
3078
crypto/tl/tlbc.cpp
Normal file
File diff suppressed because it is too large
Load diff
342
crypto/tl/tlblib.cpp
Normal file
342
crypto/tl/tlblib.cpp
Normal 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
981
crypto/tl/tlblib.hpp
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue