1
0
mirror of https://github.com/danog/ton.git synced 2024-11-30 04:29:19 +01:00

func/fift: bugfixes

This commit is contained in:
ton 2019-10-09 20:00:54 +04:00
parent f67f5d879b
commit 38c3e39066
41 changed files with 248 additions and 99 deletions

View File

@ -268,8 +268,8 @@ HttpAnswer& HttpAnswer::operator<<(TransactionCell trans_c) {
}
*this << "<div class=\"table-responsive my-3\">\n"
<< "<table class=\"table-sm table-striped\">\n"
<< "<tr><th>block</th><td><a href=\"" << BlockLink{trans_c.block_id} << "\">"
<< trans_c.block_id.id.to_str() << "</a></td></tr>"
<< "<tr><th>block</th><td><a href=\"" << BlockLink{trans_c.block_id} << "\">" << trans_c.block_id.id.to_str()
<< "</a></td></tr>"
<< "<tr><th>workchain</th><td>" << trans_c.addr.workchain << "</td></tr>"
<< "<tr><th>account hex</th><td>" << trans_c.addr.addr.to_hex() << "</td></tr>"
<< "<tr><th>account</th><td>" << trans_c.addr.rserialize(true) << "</td></tr>"
@ -381,8 +381,8 @@ HttpAnswer& HttpAnswer::operator<<(AccountCell acc_c) {
*this << "<div class=\"table-responsive my-3\">\n"
<< "<table class=\"table-sm table-striped\">\n";
*this << "<tr><th>block</th><td><a href=\"" << BlockLink{acc_c.block_id} << "\">"
<< block_id.id.to_str() << "</a></td></tr>";
*this << "<tr><th>block</th><td><a href=\"" << BlockLink{acc_c.block_id} << "\">" << block_id.id.to_str()
<< "</a></td></tr>";
*this << "<tr><th>workchain</th><td>" << acc_c.addr.workchain << "</td></tr>";
*this << "<tr><th>account hex</th><td>" << acc_c.addr.addr.to_hex() << "</td></tr>";
*this << "<tr><th>account</th><td>" << acc_c.addr.rserialize(true) << "</td></tr>";
@ -438,21 +438,24 @@ HttpAnswer& HttpAnswer::operator<<(BlockHeaderCell head_c) {
<< "<tr><th>roothash</th><td>" << block_id.root_hash.to_hex() << "</td></tr>\n"
<< "<tr><th>filehash</th><td>" << block_id.file_hash.to_hex() << "</td></tr>\n"
<< "<tr><th>time</th><td>" << info.gen_utime << "</td></tr>\n"
<< "<tr><th>lt</th><td>" << info.start_lt << " .. " << info.end_lt
<< "</td></tr>\n"
<< "<tr><th>lt</th><td>" << info.start_lt << " .. " << info.end_lt << "</td></tr>\n"
<< "<tr><th>global_id</th><td>" << blk.global_id << "</td></tr>\n"
<< "<tr><th>version</th><td>" << info.version << "</td></tr>\n"
<< "<tr><th>flags</th><td>" << info.flags << "</td></tr>\n"
<< "<tr><th>key_block</th><td>" << info.key_block << "</td></tr>\n"
<< "<tr><th>not_master</th><td>" << info.not_master << "</td></tr>\n"
<< "<tr><th>after_merge</th><td>" << info.after_merge << "</td></tr>\n"
<< "<tr><th>after_split</th><td>" << info.after_split << "</td></tr>\n"
<< "<tr><th>before_split</th><td>" << info.before_split << "</td></tr>\n"
<< "<tr><th>want_merge</th><td>" << info.want_merge << "</td></tr>\n"
<< "<tr><th>want_split</th><td>" << info.want_split << "</td></tr>\n"
<< "<tr><th>validator_list_hash_short</th><td>"
<< info.gen_validator_list_hash_short << "</td></tr>\n"
<< "<tr><th>validator_list_hash_short</th><td>" << info.gen_validator_list_hash_short << "</td></tr>\n"
<< "<tr><th>catchain_seqno</th><td>" << info.gen_catchain_seqno << "</td></tr>\n"
<< "<tr><th>min_ref_mc_seqno</th><td>" << info.min_ref_mc_seqno
<< "</td></tr>\n";
<< "<tr><th>min_ref_mc_seqno</th><td>" << info.min_ref_mc_seqno << "</td></tr>\n"
<< "<tr><th>vert_seqno</th><td>" << info.vert_seq_no << "</td></tr>\n"
<< "<tr><th>vert_seqno_incr</th><td>" << info.vert_seqno_incr << "</td></tr>\n"
<< "<tr><th>prev_key_block_seqno</th><td>"
<< ton::BlockId{ton::masterchainId, ton::shardIdAll, info.prev_key_block_seqno} << "</td></tr>\n";
for (auto id : prev) {
*this << "<tr><th>prev block</th><td>" << id << "</td></tr>\n";
}
@ -627,7 +630,8 @@ std::string HttpAnswer::header() {
sb_->clear();
*this << "<!DOCTYPE html>\n"
<< "<html lang=\"en\"><head><meta charset=\"utf-8\"><title>" << title_ << "</title>\n"
<< "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\" />\n"
<< "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0, "
"maximum-scale=1.0, user-scalable=no\" />\n"
<< "<meta name=\"format-detection\" content=\"telephone=no\" />\n"
<< "<!-- Latest compiled and minified CSS -->\n"
<< "<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">\n"
@ -648,7 +652,8 @@ std::string HttpAnswer::header() {
<< "<div class=\"input-group ml-auto\" style=\"max-width:540px;\">"
<< "<input class=\"form-control mr-2 rounded\" type=\"search\" placeholder=\"account\" aria-label=\"account\" "
<< "name=\"account\">";
*this << "<div class=\"input-group-append\"><button class=\"btn btn-outline-primary rounded\" type=\"submit\">view</button></div>"
*this << "<div class=\"input-group-append\"><button class=\"btn btn-outline-primary rounded\" "
"type=\"submit\">view</button></div>"
<< "</div></form>"
<< "</nav>\n";

View File

@ -756,6 +756,12 @@ x{EDF9} @Defop BOOLEVAL
{ PUSHINT c3 PREPAREVAR } cond
} dup : PREPARE : PREPAREDICT
//
// inline support
{ dup sbits { @addop } {
dup srefs 1- abort"exactly one reference expected in inline"
ref@ CALLREF } cond
} : INLINE
//
// throwing and handling exceptions
{ dup 6 ufits
{ <b x{F22_} s, swap 6 u, }
@ -1047,6 +1053,7 @@ x{FFF0} @Defop SETCPX
//
variable @proccnt
variable @proclist
variable @procdict
19 constant @procdictkeylen
{ @proclist @ cons @proclist ! } : @proclistadd
{ dup @procdictkeylen fits not abort"procedure index out of range"
@ -1061,26 +1068,39 @@ variable @proclist
{ swap @declproc }
cond } : DECLMETHOD
"main" @proclistadd
dictnew
dictnew @procdict !
} : PROGRAM{
{ dup sbits 1000 > { s>c <b swap ref, b> <s } if } : @adj-long-proc
{ // d i s
@adj-long-proc swap rot @procdictkeylen idict!+ not abort"cannot define procedure, redefined?"
} : PROC
{ 2dup swap @procdictkeylen idict@ abort"procedure already defined"
1 { -rot @normal? b> <s PROC } does @doafter<{
} : PROC:<{
{ 0 swap @procdictkeylen idict@ not abort"`main` procedure not defined" drop
{ over sbits < { s>c <b swap ref, b> <s } if } : @adj-long-proc
{ // i s l
@adj-long-proc swap @procdict @ @procdictkeylen
idict!+ not abort"cannot define procedure, redefined?"
@procdict !
} : @def-proc
{ 1000 @def-proc } : PROC
{ 0 @def-proc } : PROCREF
{ @procdict @ @procdictkeylen idict@ abort"procedure already defined"
} : @fail-ifdef
{ over @fail-ifdef
2 { rot @normal? rot b> <s swap @def-proc drop } does
null swap @doafter<{
} : @PROC:<{
{ 1000 @PROC:<{ } : PROC:<{
{ 0 @PROC:<{ } : PROCREF:<{
{ dup @procdict @ @procdictkeylen idict@
{ nip INLINE } { CALLDICT } cond
} dup : INLINECALL : INLINECALLDICT
{ 0 @procdict @ @procdictkeylen idict@ not abort"`main` procedure not defined" drop
} : @chkmaindef
{ dup @chkmaindef
{ @chkmaindef
@proclist @ { dup null? not } {
uncons swap dup find not
{ +": undefined procedure name in list" abort } if
execute 3 pick @procdictkeylen idict@ not
execute @procdict @ @procdictkeylen idict@ not
{ +": procedure declared but left undefined" abort } if
drop (forget)
} while
drop @proclist null! @proccnt 0!
@procdict dup @ swap null!
} : }END
forget @proclist forget @proccnt
{ }END <{ SETCP0 swap @procdictkeylen DICTPUSHCONST DICTIGETJMP 11 THROWARG }> } : }END>

View File

@ -43,6 +43,9 @@ td::Result<std::string> load_TonUtil_fif(std::string dir = "") {
td::Result<std::string> load_Lists_fif(std::string dir = "") {
return load_source("Lists.fif", dir);
}
td::Result<std::string> load_Lisp_fif(std::string dir = "") {
return load_source("Lisp.fif", dir);
}
class MemoryFileLoader : public fift::FileLoader {
public:
@ -91,7 +94,8 @@ class MemoryFileLoader : public fift::FileLoader {
};
td::Result<fift::SourceLookup> create_source_lookup(std::string main, bool need_preamble = true, bool need_asm = true,
bool need_ton_util = true, std::string dir = "") {
bool need_ton_util = true, bool need_lisp = true,
std::string dir = "") {
auto loader = std::make_unique<MemoryFileLoader>();
loader->add_file("/main.fif", std::move(main));
if (need_preamble) {
@ -112,6 +116,10 @@ td::Result<fift::SourceLookup> create_source_lookup(std::string main, bool need_
loader->add_file("/TonUtil.fif", std::move(f));
}
}
if (need_lisp) {
TRY_RESULT(f, load_Lisp_fif(dir));
loader->add_file("/Lisp.fif", std::move(f));
}
auto res = fift::SourceLookup(std::move(loader));
res.add_include_path("/");
return std::move(res);
@ -143,7 +151,7 @@ td::Result<fift::SourceLookup> run_fift(fift::SourceLookup source_lookup, std::o
} // namespace
td::Result<FiftOutput> mem_run_fift(std::string source, std::vector<std::string> args, std::string fift_dir) {
std::stringstream ss;
TRY_RESULT(source_lookup, create_source_lookup(source, true, true, true, fift_dir));
TRY_RESULT(source_lookup, create_source_lookup(source, true, true, true, true, fift_dir));
TRY_RESULT_ASSIGN(source_lookup, run_fift(std::move(source_lookup), &ss, true, std::move(args)));
FiftOutput res;
res.source_lookup = std::move(source_lookup);
@ -159,8 +167,8 @@ td::Result<FiftOutput> mem_run_fift(SourceLookup source_lookup, std::vector<std:
return std::move(res);
}
td::Result<fift::SourceLookup> create_mem_source_lookup(std::string main, std::string fift_dir, bool need_preamble,
bool need_asm, bool need_ton_util) {
return create_source_lookup(main, need_preamble, need_asm, need_ton_util, fift_dir);
bool need_asm, bool need_ton_util, bool need_lisp) {
return create_source_lookup(main, need_preamble, need_asm, need_ton_util, need_lisp, fift_dir);
}
td::Result<td::Ref<vm::Cell>> compile_asm(td::Slice asm_code, std::string fift_dir, bool is_raw) {
@ -168,7 +176,7 @@ td::Result<td::Ref<vm::Cell>> compile_asm(td::Slice asm_code, std::string fift_d
TRY_RESULT(source_lookup,
create_source_lookup(PSTRING() << "\"Asm.fif\" include\n " << (is_raw ? "<{" : "") << asm_code << "\n"
<< (is_raw ? "}>c" : "") << " boc>B \"res\" B>file",
true, true, true, fift_dir));
true, true, true, false, fift_dir));
TRY_RESULT(res, run_fift(std::move(source_lookup), &ss));
TRY_RESULT(boc, res.read_file("res"));
return vm::std_boc_deserialize(std::move(boc.data));

View File

@ -28,7 +28,7 @@ struct FiftOutput {
};
td::Result<fift::SourceLookup> create_mem_source_lookup(std::string main, std::string fift_dir = "",
bool need_preamble = true, bool need_asm = true,
bool need_ton_util = true);
bool need_ton_util = true, bool need_lisp = true);
td::Result<FiftOutput> mem_run_fift(std::string source, std::vector<std::string> args = {}, std::string fift_dir = "");
td::Result<FiftOutput> mem_run_fift(SourceLookup source_lookup, std::vector<std::string> args);
td::Result<td::Ref<vm::Cell>> compile_asm(td::Slice asm_code, std::string fift_dir = "", bool is_raw = true);

View File

@ -2346,7 +2346,7 @@ void compile_one_literal(WordList& wlist, vm::StackEntry val) {
auto x = std::move(val).as_int();
if (!x->signed_fits_bits(257)) {
throw IntError{"invalid numeric literal"};
} else if (x->signed_fits_bits(64)) {
} else if (x->signed_fits_bits(td::BigIntInfo::word_shift)) {
wlist.push_back(Ref<StackWord>{true, std::bind(interpret_const, _1, x->to_long())});
} else {
wlist.push_back(Ref<StackWord>{true, std::bind(interpret_big_const, _1, std::move(x))});

View File

@ -193,21 +193,21 @@ void AsmOp::out(std::ostream& os) const {
os << (b ? "SWAP" : "NOP");
break;
}
os << "s" << a << " s" << b << " XCHG";
os << SReg(a) << ' ' << SReg(b) << " XCHG";
break;
case a_push:
if (!(a & -2)) {
os << (a ? "OVER" : "DUP");
break;
}
os << "s" << a << " PUSH";
os << SReg(a) << " PUSH";
break;
case a_pop:
if (!(a & -2)) {
os << (a ? "NIP" : "DROP");
break;
}
os << "s" << a << " POP";
os << SReg(a) << " POP";
break;
default:
throw src::Fatal{"unknown assembler operation"};

View File

@ -406,8 +406,11 @@ bool Op::generate_code_step(Stack& stack) {
}
func->compile(stack.o, res, args); // compile res := f (args)
} else {
auto fv = dynamic_cast<const SymValCodeFunc*>(fun_ref->value);
std::string name = sym::symbols.get_name(fun_ref->sym_idx);
stack.o << AsmOp::Custom(name + " CALLDICT", (int)right.size(), (int)left.size());
bool is_inline = (fv && (fv->flags & 3));
stack.o << AsmOp::Custom(name + (is_inline ? " INLINECALLDICT" : " CALLDICT"), (int)right.size(),
(int)left.size());
}
}
stack.s.resize(k);
@ -553,7 +556,7 @@ bool Op::generate_code_step(Stack& stack) {
stack.opt_show();
stack.s.pop_back();
stack.modified();
if (!next->is_empty()) {
if (true || !next->is_empty()) {
stack.o << "REPEAT:<{";
stack.o.indent();
stack.forget_const();
@ -601,7 +604,7 @@ bool Op::generate_code_step(Stack& stack) {
case _Until: {
// stack.drop_vars_except(block0->var_info);
// stack.opt_show();
if (!next->is_empty()) {
if (true || !next->is_empty()) {
stack.o << "UNTIL:<{";
stack.o.indent();
stack.forget_const();
@ -632,7 +635,7 @@ bool Op::generate_code_step(Stack& stack) {
stack.drop_vars_except(block0->var_info);
stack.opt_show();
StackLayout layout1 = stack.vars();
bool next_empty = next->is_empty();
bool next_empty = false && next->is_empty();
stack.o << "WHILE:<{";
stack.o.indent();
stack.forget_const();

View File

@ -83,7 +83,8 @@ void generate_output_func(SymDef* func_sym) {
if (verbosity >= 2) {
std::cerr << "\n---------- resulting code for " << name << " -------------\n";
}
*outs << std::string(indent * 2, ' ') << name << " PROC:<{\n";
bool inline_ref = (func_val->flags & 2);
*outs << std::string(indent * 2, ' ') << name << " PROC" << (inline_ref ? "REF" : "") << ":<{\n";
code.generate_code(
*outs,
(stack_layout_comments ? Stack::_StkCmt | Stack::_CptStkCmt : 0) | (opt_level < 2 ? Stack::_DisableOpt : 0),

View File

@ -79,6 +79,9 @@ enum Keyword {
_RshiftLet,
_RshiftRLet,
_RshiftCLet,
_AndLet,
_OrLet,
_XorLet,
_Int,
_Cell,
_Slice,
@ -90,6 +93,8 @@ enum Keyword {
_Asm,
_Impure,
_Extern,
_Inline,
_InlineRef,
_MethodId,
_Operator,
_Infix,
@ -632,6 +637,9 @@ struct CodeBlob {
}
bool import_params(FormalArgList arg_list);
var_idx_t create_var(int cls, TypeExpr* var_type = 0, SymDef* sym = 0, const SrcLocation* loc = 0);
var_idx_t create_tmp_var(TypeExpr* var_type = 0, const SrcLocation* loc = 0) {
return create_var(TmpVar::_Tmp, var_type, nullptr, loc);
}
int split_vars(bool strict = false);
bool compute_used_code_vars();
bool compute_used_code_vars(std::unique_ptr<Op>& ops, const VarDescrList& var_info, bool edit) const;
@ -670,8 +678,9 @@ struct SymVal : sym::SymValBase {
TypeExpr* sym_type;
td::RefInt256 method_id;
bool impure;
short flags; // +1 = inline, +2 = inline_ref
SymVal(int _type, int _idx, TypeExpr* _stype = nullptr, bool _impure = false)
: sym::SymValBase(_type, _idx), sym_type(_stype), impure(_impure) {
: sym::SymValBase(_type, _idx), sym_type(_stype), impure(_impure), flags(0) {
}
~SymVal() override = default;
TypeExpr* get_type() const {
@ -802,6 +811,10 @@ struct Expr {
int define_new_vars(CodeBlob& code);
int predefine_vars();
std::vector<var_idx_t> pre_compile(CodeBlob& code) const;
var_idx_t new_tmp(CodeBlob& code) const;
std::vector<var_idx_t> new_tmp_vect(CodeBlob& code) const {
return {new_tmp(code)};
}
};
/*

View File

@ -212,6 +212,10 @@ int Expr::predefine_vars() {
return 0;
}
var_idx_t Expr::new_tmp(CodeBlob& code) const {
return code.create_tmp_var(e_type, &here);
}
std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code) const {
switch (cls) {
case _Tuple: {
@ -241,8 +245,7 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code) const {
res.insert(res.end(), add.cbegin(), add.cend());
}
}
var_idx_t rv = code.create_var(TmpVar::_Tmp, e_type, nullptr, &here);
std::vector<var_idx_t> rvect{rv};
auto rvect = new_tmp_vect(code);
auto& op = code.emplace_back(here, Op::_Call, rvect, std::move(res), sym);
if (flags & _IsImpure) {
op.flags |= Op::_Impure;
@ -256,57 +259,52 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code) const {
return {val};
case _VarApply:
if (args[0]->cls == _Glob) {
std::vector<var_idx_t> res = args[1]->pre_compile(code);
var_idx_t rv = code.create_var(TmpVar::_Tmp, e_type, nullptr, &here);
std::vector<var_idx_t> rvect{rv};
auto res = args[1]->pre_compile(code);
auto rvect = new_tmp_vect(code);
auto& op = code.emplace_back(here, Op::_Call, rvect, std::move(res), args[0]->sym);
if (args[0]->flags & _IsImpure) {
op.flags |= Op::_Impure;
}
return rvect;
} else {
std::vector<var_idx_t> res = args[1]->pre_compile(code);
std::vector<var_idx_t> tfunc = args[0]->pre_compile(code);
auto res = args[1]->pre_compile(code);
auto tfunc = args[0]->pre_compile(code);
if (tfunc.size() != 1) {
throw src::Fatal{"stack tuple used as a function"};
}
res.push_back(tfunc[0]);
var_idx_t rv = code.create_var(TmpVar::_Tmp, e_type, nullptr, &here);
std::vector<var_idx_t> rvect{rv};
auto rvect = new_tmp_vect(code);
code.emplace_back(here, Op::_CallInd, rvect, std::move(res));
return rvect;
}
case _Const: {
var_idx_t rv = code.create_var(TmpVar::_Tmp, e_type, nullptr, &here);
std::vector<var_idx_t> rvect{rv};
auto rvect = new_tmp_vect(code);
code.emplace_back(here, Op::_IntConst, rvect, intval);
return rvect;
}
case _Glob: {
var_idx_t rv = code.create_var(TmpVar::_Tmp, e_type, nullptr, &here);
std::vector<var_idx_t> rvect{rv};
auto rvect = new_tmp_vect(code);
code.emplace_back(here, Op::_GlobVar, rvect, std::vector<var_idx_t>{}, sym);
return rvect;
}
case _Letop: {
std::vector<var_idx_t> right = args[1]->pre_compile(code);
std::vector<var_idx_t> left = args[0]->pre_compile(code);
code.emplace_back(here, Op::_Let, left, std::move(right));
return left;
auto right = args[1]->pre_compile(code);
auto left = args[0]->pre_compile(code);
code.emplace_back(here, Op::_Let, std::move(left), right);
return right;
}
case _LetFirst: {
var_idx_t rv = code.create_var(TmpVar::_Tmp, e_type, nullptr, &here);
std::vector<var_idx_t> right = args[1]->pre_compile(code);
std::vector<var_idx_t> left = args[0]->pre_compile(code);
left.push_back(rv);
auto rvect = new_tmp_vect(code);
auto right = args[1]->pre_compile(code);
auto left = args[0]->pre_compile(code);
left.push_back(rvect[0]);
code.emplace_back(here, Op::_Let, std::move(left), std::move(right));
return std::vector<var_idx_t>{rv};
return rvect;
}
case _CondExpr: {
auto cond = args[0]->pre_compile(code);
assert(cond.size() == 1);
var_idx_t rv = code.create_var(TmpVar::_Tmp, e_type, nullptr, &here);
std::vector<var_idx_t> rvect{rv};
auto rvect = new_tmp_vect(code);
Op& if_op = code.emplace_back(here, Op::_If, cond);
code.push_set_cur(if_op.block0);
code.emplace_back(here, Op::_Let, rvect, args[1]->pre_compile(code));

View File

@ -79,7 +79,10 @@ void define_keywords() {
.add_keyword("<<=", Kw::_LshiftLet)
.add_keyword(">>=", Kw::_RshiftLet)
.add_keyword(">>~=", Kw::_RshiftRLet)
.add_keyword(">>^=", Kw::_RshiftCLet);
.add_keyword(">>^=", Kw::_RshiftCLet)
.add_keyword("&=", Kw::_AndLet)
.add_keyword("|=", Kw::_OrLet)
.add_keyword("^=", Kw::_XorLet);
sym::symbols.add_keyword("return", Kw::_Return)
.add_keyword("var", Kw::_Var)
@ -105,6 +108,8 @@ void define_keywords() {
sym::symbols.add_keyword("extern", Kw::_Extern)
.add_keyword("asm", Kw::_Asm)
.add_keyword("impure", Kw::_Impure)
.add_keyword("inline", Kw::_Inline)
.add_keyword("inline_ref", Kw::_InlineRef)
.add_keyword("method_id", Kw::_MethodId)
.add_keyword("operator", Kw::_Operator)
.add_keyword("infix", Kw::_Infix)

View File

@ -428,7 +428,6 @@ Expr* parse_expr80(Lexer& lex, CodeBlob& code, bool nv) {
res->flags = Expr::_IsRvalue | (val->impure ? Expr::_IsImpure : 0);
res->deduce_type(lex.cur());
if (modify) {
// FIXME (use _LetFirst instead of _Letop)
auto tmp = res;
res = new Expr{Expr::_LetFirst, {obj->copy(), tmp}};
res->here = loc;
@ -587,7 +586,8 @@ Expr* parse_expr10(Lexer& lex, CodeBlob& code, bool nv) {
auto x = parse_expr13(lex, code, nv);
int t = lex.tp();
if (t == _PlusLet || t == _MinusLet || t == _TimesLet || t == _DivLet || t == _DivRLet || t == _DivCLet ||
t == _ModLet || t == _LshiftLet || t == _RshiftLet || t == _RshiftCLet || t == _RshiftRLet) {
t == _ModLet || t == _LshiftLet || t == _RshiftLet || t == _RshiftCLet || t == _RshiftRLet || t == _AndLet ||
t == _OrLet || t == _XorLet) {
x->chk_lvalue(lex.cur());
x->chk_rvalue(lex.cur());
sym_idx_t name = symbols.lookup_add(std::string{"^_"} + lex.cur().str + "_");
@ -974,6 +974,11 @@ void parse_func_def(Lexer& lex) {
if (impure) {
lex.next();
}
int f = 0;
if (lex.tp() == _Inline || lex.tp() == _InlineRef) {
f = (lex.tp() == _Inline) ? 1 : 2;
lex.next();
}
td::RefInt256 method_id;
std::string method_name;
if (lex.tp() == _MethodId) {
@ -1071,6 +1076,17 @@ void parse_func_def(Lexer& lex) {
lex.cur().error("integer method identifier for `"s + func_name.str + "` changed to a different value");
}
}
if (f) {
auto val = dynamic_cast<SymVal*>(func_sym->value);
if (!val) {
lex.cur().error("cannot set unknown function `"s + func_name.str + "` as an inline");
}
if (!(val->flags & 3)) {
val->flags = (short)(val->flags | f);
} else if ((val->flags & 3) != f) {
lex.cur().error("inline mode for `"s + func_name.str + "` changed with respect to a previous declaration");
}
}
if (verbosity >= 1) {
std::cerr << "new type of function " << func_name.str << " : " << func_type << std::endl;
}

20
crypto/func/test/b3.fc Normal file
View File

@ -0,0 +1,20 @@
;; inline test
_ unpack() inline {
var ds = get_data().begin_parse();
var res = (ds~load_uint(8), ds~load_int(32), ds~load_int(32));
return res;
}
() pack(a, x, y) impure inline_ref {
set_data(begin_cell()
.store_uint(a, 8)
.store_int(x, 32)
.store_int(y, 32)
.end_cell());
}
() main() impure {
var (a, x, y) = unpack();
x += y;
pack(a, x, y);
}

9
crypto/func/test/w1.fc Normal file
View File

@ -0,0 +1,9 @@
(int, int) nested_if(int id) method_id {
dump_stack();
if (id > 0) {
if (id > 10) {
return (2 * id, 3 * id);
}
}
return (5, 6);
}

14
crypto/func/test/w2.fc Normal file
View File

@ -0,0 +1,14 @@
_ f(cs) {
return (cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8),
cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8),
cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8),
cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8),
cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8));
}
_ main(cs) {
var (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10,
x11, x12, x13, x14, x15, x16, x17, x18, x19) = f(cs);
return x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9
+ x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19;
}

2
crypto/smartcont/highload-wallet-v2.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
{ ."usage: " @' $0 type ." <filename-base> <subwallet-id> <order-file> [<savefile>]" cr

2
crypto/smartcont/highload-wallet.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
{ ."usage: " @' $0 type ." <filename-base> <subwallet-id> <seqno> <order-file> [<savefile>]" cr

2
crypto/smartcont/new-highload-wallet-v2.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
"Asm.fif" include

2
crypto/smartcont/new-highload-wallet.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
"Asm.fif" include

2
crypto/smartcont/new-pinger.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
"Asm.fif" include

2
crypto/smartcont/new-testgiver.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
"Asm.fif" include

2
crypto/smartcont/new-wallet-v2.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
"Asm.fif" include

2
crypto/smartcont/new-wallet.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
"Asm.fif" include

2
crypto/smartcont/recover-stake.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
{ ."usage: " @' $0 type ." [<savefile>]" cr

2
crypto/smartcont/show-addr.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
{ ."usage: " @' $0 type ." <filename-base>" cr

2
crypto/smartcont/testgiver.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
{ ."usage: " @' $0 type ." <dest-addr> <seqno> <amount> [<savefile>]" cr

2
crypto/smartcont/update-config-smc.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
{ ."usage: " @' $0 type ." <filename-base> <seqno> [<savefile>]" cr

2
crypto/smartcont/update-config.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
{ ."usage: " @' $0 type ." <filename-base> <seqno> <index> <new-value-boc> [<savefile>]" cr

2
crypto/smartcont/update-elector-smc.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
{ ."usage: " @' $0 type ." <filename-base> <seqno> [<savefile>]" cr

2
crypto/smartcont/validator-elect-req.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
{ ."usage: " @' $0 type ." <wallet-addr> <elect-utime> <max-factor> <adnl-addr> [<savefile>]" cr

2
crypto/smartcont/validator-elect-signed.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
{ ."usage: " @' $0 type ." <wallet-addr> <elect-utime> <max-factor> <adnl-addr> <validator-pubkey> <validator-signature> [<savefile>]" cr

2
crypto/smartcont/wallet-v2.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
{ ."usage: " @' $0 type ." <filename-base> <dest-addr> <seqno> <amount> [-B <body-boc>] [<savefile>]" cr

2
crypto/smartcont/wallet.fif Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env fift -s
#!/usr/bin/fift -s
"TonUtil.fif" include
{ ."usage: " @' $0 type ." <filename-base> <dest-addr> <seqno> <amount> [-B <body-boc>] [-C <transfer-comment>] [<savefile>]" cr

View File

@ -90,3 +90,23 @@ TEST(Fift, test) {
TEST(Fift, bug_div) {
run_fift("bug_div.fif");
}
TEST(Fift, bug_ufits) {
run_fift("bug_ufits.fif");
}
TEST(Fift, test_dict) {
run_fift("testdict.fif");
}
TEST(Fift, test_fixed) {
run_fift("fixed.fif");
}
TEST(Fift, test_sort) {
run_fift("sort.fif");
}
TEST(Fift, test_sort2) {
run_fift("sort2.fif");
}

View File

@ -0,0 +1 @@
100000000000000000 dup =: amount 56 ufits . amount 56 ufits .

View File

@ -4,8 +4,13 @@ Test_Bitstrings_main_default a8b08af3116923c4c2a14e138d168375abd0c059f2f780d3267
Test_Cells_simple_default 832502642fe4fe5db70de82681aedb7d54d7f3530e0069861fff405fe6f6cf23
Test_Fift_bug_div_default 1ac42861ce96b2896001c587f65e9afe1617db48859f19c2f4e3063a20ea60b0
Test_Fift_bug_newlize_default e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Test_Fift_bug_ufits_default 51bf5a9f1ed7633a193f6fdd17a7a3af8e032dfe72a9669c85e8639aa8a7c195
Test_Fift_contfrac_default 09ebce5c91bcb70696c6fb6981d82dc3b9e3444dab608a7a1b044c0ddd778a96
Test_Fift_test_default 4e44b3382963ec89f7b5c8f2ebd85da3bc8aebad5b49f5b11b14075061477b4d
Test_Fift_test_dict_default 480d22a6ec25a232febf4eec8ff64747573f79721327e7ff3b1aa7ea4921bbb4
Test_Fift_test_fixed_default 278a19d56b773102caf5c1fe2997ea6c8d0d9e720eff8503feede6398a197eec
Test_Fift_test_sort2_default 9b57d47e6a10e7d1bbb565db35400debf2f963031f434742a702ec76555a5d3a
Test_Fift_test_sort_default 9b57d47e6a10e7d1bbb565db35400debf2f963031f434742a702ec76555a5d3a
Test_Fift_testvm2_default 8a6e35fc0224398be9d2de39d31c86ea96965ef1eca2aa9e0af2303150ed4a7b
Test_Fift_testvm3_default 3c1b77471c5fd914ed8b5f528b9faed618e278693f5030b953ff150e543864ae
Test_Fift_testvm4_default 8a6e35fc0224398be9d2de39d31c86ea96965ef1eca2aa9e0af2303150ed4a7b

View File

@ -2,6 +2,7 @@
#include "td/utils/filesystem.h"
#include "td/utils/port/path.h"
#include "td/utils/PathView.h"
#include <map>
#include <utility>
@ -51,7 +52,7 @@ class KeyValueDir : public KeyValue {
return td::WalkPath::Action::SkipDir;
}
} else if (type == td::WalkPath::Type::NotDir) {
f(path);
f(td::PathView::relative(path, directory_));
}
return td::WalkPath::Action::Continue;

View File

@ -29,6 +29,7 @@
#include "ton/ton-types.h"
#include "ton/ton-tl.hpp"
#include "ton/ton-io.hpp"
#include "common/errorlog.h"
@ -1004,9 +1005,11 @@ td::Status ValidatorEngine::load_global_config() {
ton::BlockIdExt init_block;
if (!conf.validator_->init_block_) {
LOG(INFO) << "no init block in config. using zero state";
init_block = zero_state;
} else {
init_block = ton::create_block_id(conf.validator_->init_block_);
LOG(INFO) << "found init block " << init_block;
if (init_block.id.workchain != ton::masterchainId || init_block.id.shard != ton::shardIdAll) {
return td::Status::Error(ton::ErrorCode::error, "[validator] section contains invalid [init_block]");
}

View File

@ -596,17 +596,17 @@ void FullNodeShardImpl::download_block(BlockIdExt id, td::uint32 priority, td::T
void FullNodeShardImpl::download_zero_state(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) {
td::actor::create_actor<DownloadState>("downloadstatereq", id, BlockIdExt{}, adnl_id_, overlay_id_,
adnl::AdnlNodeIdShort::zero(), priority, timeout, validator_manager_, rldp_,
overlays_, adnl_, client_, std::move(promise))
td::actor::create_actor<DownloadState>(PSTRING() << "downloadstatereq" << id.id.to_str(), id, BlockIdExt{}, adnl_id_,
overlay_id_, adnl::AdnlNodeIdShort::zero(), priority, timeout,
validator_manager_, rldp_, overlays_, adnl_, client_, std::move(promise))
.release();
}
void FullNodeShardImpl::download_persistent_state(BlockIdExt id, BlockIdExt masterchain_block_id, td::uint32 priority,
td::Timestamp timeout, td::Promise<td::BufferSlice> promise) {
td::actor::create_actor<DownloadState>("downloadstatereq", id, masterchain_block_id, adnl_id_, overlay_id_,
adnl::AdnlNodeIdShort::zero(), priority, timeout, validator_manager_, rldp_,
overlays_, adnl_, client_, std::move(promise))
td::actor::create_actor<DownloadState>(PSTRING() << "downloadstatereq" << id.id.to_str(), id, masterchain_block_id,
adnl_id_, overlay_id_, adnl::AdnlNodeIdShort::zero(), priority, timeout,
validator_manager_, rldp_, overlays_, adnl_, client_, std::move(promise))
.release();
}

View File

@ -32,6 +32,7 @@ namespace ton {
namespace validator {
void ValidatorManagerMasterchainReiniter::start_up() {
LOG(INFO) << "init_block_id=" << block_id_;
CHECK(block_id_.is_masterchain());
CHECK(block_id_.id.shard == shardIdAll);
CHECK(block_id_.seqno() >= opts_->get_last_fork_masterchain_seqno());
@ -83,7 +84,9 @@ void ValidatorManagerMasterchainReiniter::download_proof_link() {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
if (R.is_error()) {
LOG(WARNING) << "failed to download proof link: " << R.move_as_error();
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainReiniter::download_proof_link);
delay_action(
[SelfId]() { td::actor::send_closure(SelfId, &ValidatorManagerMasterchainReiniter::download_proof_link); },
td::Timestamp::in(1.0));
} else {
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainReiniter::downloaded_proof_link, R.move_as_ok());
}
@ -208,6 +211,10 @@ void ValidatorManagerMasterchainReiniter::choose_masterchain_state() {
p = key_blocks_[key_blocks_.size() - 2 - i];
}
LOG(INFO) << "key block candidate: seqno=" << h->id().seqno()
<< " is_persistent=" << (!p || ValidatorManager::is_persistent_state(h->unix_time(), p->unix_time()))
<< " ttl=" << ValidatorManager::persistent_state_ttl(h->unix_time())
<< " syncbefore=" << opts_->sync_blocks_before();
if (!p || ValidatorManager::is_persistent_state(h->unix_time(), p->unix_time())) {
auto ttl = ValidatorManager::persistent_state_ttl(h->unix_time());
if (ttl > td::Clocks::system() + opts_->sync_blocks_before()) {

View File

@ -172,12 +172,12 @@ void DownloadState::got_block_state_description(td::BufferSlice data) {
create_serialize_tl_object<ton_api::tonNode_downloadZeroState>(create_tl_block_id(block_id_));
if (client_.empty()) {
td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_,
overlay_id_, "download state", std::move(P), timeout_, std::move(query),
FullNode::max_state_size(), rldp_);
overlay_id_, "download state", std::move(P), td::Timestamp::in(3.0),
std::move(query), FullNode::max_state_size(), rldp_);
} else {
td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "download state",
create_serialize_tl_object_suffix<ton_api::tonNode_query>(std::move(query)),
timeout_, std::move(P));
td::Timestamp::in(3.0), std::move(P));
}
}));
}
@ -213,12 +213,12 @@ void DownloadState::got_block_state_part(td::BufferSlice data, td::uint32 reques
create_tl_block_id(block_id_), create_tl_block_id(masterchain_block_id_), sum_, part_size);
if (client_.empty()) {
td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, overlay_id_,
"download state", std::move(P), timeout_, std::move(query), FullNode::max_state_size(),
rldp_);
"download state", std::move(P), td::Timestamp::in(10.0), std::move(query),
FullNode::max_state_size(), rldp_);
} else {
td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "download state",
create_serialize_tl_object_suffix<ton_api::tonNode_query>(std::move(query)), timeout_,
std::move(P));
create_serialize_tl_object_suffix<ton_api::tonNode_query>(std::move(query)),
td::Timestamp::in(10.0), std::move(P));
}
}