From 0bc6305f96cf17d4c1a5bd86cdb3df85a99ccc92 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Tue, 16 Apr 2024 21:52:11 +0300 Subject: [PATCH 01/30] [FunC] Change some fields to enums instead of integers It makes it easier to understand/debug Also, drop some unused enum values from that cases --- .gitignore | 2 + crypto/func/func.h | 76 +++++++++++++++++-------------------- crypto/func/gen-abscode.cpp | 6 +-- crypto/func/parse-func.cpp | 4 +- crypto/func/unify-types.cpp | 2 +- 5 files changed, 42 insertions(+), 48 deletions(-) diff --git a/.gitignore b/.gitignore index 536918ab3..5ac24ec1b 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,8 @@ test/regression-tests.cache/ **/*build*/ .idea .vscode +dev/ +.DS_Store zlib/ libsodium/ libmicrohttpd-0.9.77-w32-bin/ diff --git a/crypto/func/func.h b/crypto/func/func.h index 2b95bcbc5..7da3f0ad8 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -149,8 +149,8 @@ class IdSc { */ struct TypeExpr { - enum te_type { te_Unknown, te_Var, te_Indirect, te_Atomic, te_Tensor, te_Tuple, te_Map, te_Type, te_ForAll } constr; - enum { + enum te_type { te_Unknown, te_Var, te_Indirect, te_Atomic, te_Tensor, te_Tuple, te_Map, te_ForAll } constr; + enum AtomicType { _Int = Keyword::_Int, _Cell = Keyword::_Cell, _Slice = Keyword::_Slice, @@ -216,7 +216,7 @@ struct TypeExpr { void compute_width(); bool recompute_width(); void show_width(std::ostream& os); - std::ostream& print(std::ostream& os, int prio = 0); + std::ostream& print(std::ostream& os, int prio = 0) const; void replace_with(TypeExpr* te2); int extract_components(std::vector& comp_list); static int holes, type_vars; @@ -535,7 +535,7 @@ class ListIterator { struct Stack; struct Op { - enum { + enum OpKind { _Undef, _Nop, _Call, @@ -554,10 +554,10 @@ struct Op { _Repeat, _Again, _TryCatch, - _SliceConst + _SliceConst, }; - int cl; - enum { _Disabled = 1, _Reachable = 2, _NoReturn = 4, _ImpureR = 8, _ImpureW = 16, _Impure = 24 }; + OpKind cl; + enum { _Disabled = 1, _NoReturn = 4, _Impure = 24 }; int flags; std::unique_ptr next; SymDef* fun_ref; @@ -568,25 +568,25 @@ struct Op { std::unique_ptr block0, block1; td::RefInt256 int_const; std::string str_const; - Op(const SrcLocation& _where = {}, int _cl = _Undef) : cl(_cl), flags(0), fun_ref(nullptr), where(_where) { + Op(const SrcLocation& _where = {}, OpKind _cl = _Undef) : cl(_cl), flags(0), fun_ref(nullptr), where(_where) { } - Op(const SrcLocation& _where, int _cl, const std::vector& _left) + Op(const SrcLocation& _where, OpKind _cl, const std::vector& _left) : cl(_cl), flags(0), fun_ref(nullptr), where(_where), left(_left) { } - Op(const SrcLocation& _where, int _cl, std::vector&& _left) + Op(const SrcLocation& _where, OpKind _cl, std::vector&& _left) : cl(_cl), flags(0), fun_ref(nullptr), where(_where), left(std::move(_left)) { } - Op(const SrcLocation& _where, int _cl, const std::vector& _left, td::RefInt256 _const) + Op(const SrcLocation& _where, OpKind _cl, const std::vector& _left, td::RefInt256 _const) : cl(_cl), flags(0), fun_ref(nullptr), where(_where), left(_left), int_const(_const) { } - Op(const SrcLocation& _where, int _cl, const std::vector& _left, std::string _const) + Op(const SrcLocation& _where, OpKind _cl, const std::vector& _left, std::string _const) : cl(_cl), flags(0), fun_ref(nullptr), where(_where), left(_left), str_const(_const) { } - Op(const SrcLocation& _where, int _cl, const std::vector& _left, const std::vector& _right, + Op(const SrcLocation& _where, OpKind _cl, const std::vector& _left, const std::vector& _right, SymDef* _fun = nullptr) : cl(_cl), flags(0), fun_ref(_fun), where(_where), left(_left), right(_right) { } - Op(const SrcLocation& _where, int _cl, std::vector&& _left, std::vector&& _right, + Op(const SrcLocation& _where, OpKind _cl, std::vector&& _left, std::vector&& _right, SymDef* _fun = nullptr) : cl(_cl), flags(0), fun_ref(_fun), where(_where), left(std::move(_left)), right(std::move(_right)) { } @@ -599,9 +599,6 @@ struct Op { void disable() { flags |= _Disabled; } - bool unreachable() { - return !(flags & _Reachable); - } void flags_set_clear(int set, int clear); void show(std::ostream& os, const std::vector& vars, std::string pfx = "", int mode = 0) const; void show_var_list(std::ostream& os, const std::vector& idx_list, const std::vector& vars) const; @@ -898,7 +895,7 @@ extern std::stack inclusion_locations; */ struct Expr { - enum { + enum ExprCls { _None, _Apply, _VarApply, @@ -914,11 +911,11 @@ struct Expr { _Hole, _Type, _CondExpr, - _SliceConst + _SliceConst, }; - int cls; + ExprCls cls; int val{0}; - enum { _IsType = 1, _IsRvalue = 2, _IsLvalue = 4, _IsHole = 8, _IsNewVar = 16, _IsImpure = 32 }; + enum { _IsType = 1, _IsRvalue = 2, _IsLvalue = 4, _IsImpure = 32 }; int flags{0}; SrcLocation here; td::RefInt256 intval; @@ -926,19 +923,19 @@ struct Expr { SymDef* sym{nullptr}; TypeExpr* e_type{nullptr}; std::vector args; - Expr(int c = _None) : cls(c) { + explicit Expr(ExprCls c = _None) : cls(c) { } - Expr(int c, const SrcLocation& loc) : cls(c), here(loc) { + Expr(ExprCls c, const SrcLocation& loc) : cls(c), here(loc) { } - Expr(int c, std::vector _args) : cls(c), args(std::move(_args)) { + Expr(ExprCls c, std::vector _args) : cls(c), args(std::move(_args)) { } - Expr(int c, std::initializer_list _arglist) : cls(c), args(std::move(_arglist)) { + Expr(ExprCls c, std::initializer_list _arglist) : cls(c), args(std::move(_arglist)) { } - Expr(int c, SymDef* _sym, std::initializer_list _arglist) : cls(c), sym(_sym), args(std::move(_arglist)) { + Expr(ExprCls c, SymDef* _sym, std::initializer_list _arglist) : cls(c), sym(_sym), args(std::move(_arglist)) { } - Expr(int c, SymDef* _sym, std::vector _arglist) : cls(c), sym(_sym), args(std::move(_arglist)) { + Expr(ExprCls c, SymDef* _sym, std::vector _arglist) : cls(c), sym(_sym), args(std::move(_arglist)) { } - Expr(int c, sym_idx_t name_idx, std::initializer_list _arglist); + Expr(ExprCls c, sym_idx_t name_idx, std::initializer_list _arglist); ~Expr() { for (auto& arg_ptr : args) { delete arg_ptr; @@ -979,7 +976,6 @@ struct Expr { int define_new_vars(CodeBlob& code); int predefine_vars(); std::vector pre_compile(CodeBlob& code, std::vector>* lval_globs = nullptr) const; - static std::vector pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here); var_idx_t new_tmp(CodeBlob& code) const; std::vector new_tmp_vect(CodeBlob& code) const { return {new_tmp(code)}; @@ -1000,9 +996,9 @@ using Const = td::RefInt256; struct AsmOp { enum Type { a_none, a_xchg, a_push, a_pop, a_const, a_custom, a_magic }; - int t{a_none}; + Type t{a_none}; int indent{0}; - int a, b, c; + int a, b; bool gconst{false}; std::string op; td::RefInt256 origin; @@ -1012,26 +1008,22 @@ struct AsmOp { } }; AsmOp() = default; - AsmOp(int _t) : t(_t) { + AsmOp(Type _t) : t(_t) { } - AsmOp(int _t, std::string _op) : t(_t), op(std::move(_op)) { + AsmOp(Type _t, std::string _op) : t(_t), op(std::move(_op)) { } - AsmOp(int _t, int _a) : t(_t), a(_a) { + AsmOp(Type _t, int _a) : t(_t), a(_a) { } - AsmOp(int _t, int _a, std::string _op) : t(_t), a(_a), op(std::move(_op)) { + AsmOp(Type _t, int _a, std::string _op) : t(_t), a(_a), op(std::move(_op)) { } - AsmOp(int _t, int _a, int _b) : t(_t), a(_a), b(_b) { + AsmOp(Type _t, int _a, int _b) : t(_t), a(_a), b(_b) { } - AsmOp(int _t, int _a, int _b, std::string _op) : t(_t), a(_a), b(_b), op(std::move(_op)) { + AsmOp(Type _t, int _a, int _b, std::string _op) : t(_t), a(_a), b(_b), op(std::move(_op)) { compute_gconst(); } - AsmOp(int _t, int _a, int _b, std::string _op, td::RefInt256 x) : t(_t), a(_a), b(_b), op(std::move(_op)), origin(x) { + AsmOp(Type _t, int _a, int _b, std::string _op, td::RefInt256 x) : t(_t), a(_a), b(_b), op(std::move(_op)), origin(x) { compute_gconst(); } - AsmOp(int _t, int _a, int _b, int _c) : t(_t), a(_a), b(_b), c(_c) { - } - AsmOp(int _t, int _a, int _b, int _c, std::string _op) : t(_t), a(_a), b(_b), c(_c), op(std::move(_op)) { - } void out(std::ostream& os) const; void out_indent_nl(std::ostream& os, bool no_nl = false) const; std::string to_string() const; diff --git a/crypto/func/gen-abscode.cpp b/crypto/func/gen-abscode.cpp index 9989d10c4..fe2d1850d 100644 --- a/crypto/func/gen-abscode.cpp +++ b/crypto/func/gen-abscode.cpp @@ -37,7 +37,7 @@ Expr* Expr::copy() const { return res; } -Expr::Expr(int c, sym_idx_t name_idx, std::initializer_list _arglist) : cls(c), args(std::move(_arglist)) { +Expr::Expr(ExprCls c, sym_idx_t name_idx, std::initializer_list _arglist) : cls(c), args(std::move(_arglist)) { sym = sym::lookup_symbol(name_idx); if (!sym) { } @@ -233,7 +233,7 @@ void add_set_globs(CodeBlob& code, std::vector>& g } } -std::vector Expr::pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here) { +std::vector pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here) { while (lhs->is_type_apply()) { lhs = lhs->args.at(0); } @@ -249,7 +249,7 @@ std::vector Expr::pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rh auto unpacked_type = rhs->e_type->args.at(0); std::vector tmp{code.create_tmp_var(unpacked_type, &rhs->here)}; code.emplace_back(lhs->here, Op::_UnTuple, tmp, std::move(right)); - auto tvar = new Expr{_Var}; + auto tvar = new Expr{Expr::_Var}; tvar->set_val(tmp[0]); tvar->set_location(rhs->here); tvar->e_type = unpacked_type; diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index 15794c425..fa2bac023 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -580,7 +580,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { if (t == '_') { Expr* res = new Expr{Expr::_Hole, lex.cur().loc}; res->val = -1; - res->flags = (Expr::_IsLvalue | Expr::_IsHole | Expr::_IsNewVar); + res->flags = Expr::_IsLvalue; res->e_type = TypeExpr::new_hole(); lex.next(); return res; @@ -642,7 +642,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { if (nv) { res->val = ~lex.cur().val; res->e_type = TypeExpr::new_hole(); - res->flags = Expr::_IsLvalue | Expr::_IsNewVar; + res->flags = Expr::_IsLvalue; // std::cerr << "defined new variable " << lex.cur().str << " : " << res->e_type << std::endl; } else { if (!sym) { diff --git a/crypto/func/unify-types.cpp b/crypto/func/unify-types.cpp index f9b639c0e..22b33281a 100644 --- a/crypto/func/unify-types.cpp +++ b/crypto/func/unify-types.cpp @@ -209,7 +209,7 @@ std::ostream& operator<<(std::ostream& os, TypeExpr* type_expr) { return type_expr->print(os); } -std::ostream& TypeExpr::print(std::ostream& os, int lex_level) { +std::ostream& TypeExpr::print(std::ostream& os, int lex_level) const { switch (constr) { case te_Unknown: return os << "??" << value; From a5d2a1003fb92111a38b7c25484055950bc054d1 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Sat, 20 Apr 2024 01:10:50 +0300 Subject: [PATCH 02/30] [FunC] Enrich and refactor testing framework, add negative tests * fully refactor run_tests.py, make it extensible for the future * an ability to write @compilation_should_fail tests * an ability to launch run_tests.py for a single .fc file * keep run_tests.js in sync with run_tests.py * extract legacy_tests names/hashes to a separate file shared between legacy_tester.py and legacy_tester.js --- crypto/func/auto-tests/legacy_tester.js | 63 +++- crypto/func/auto-tests/legacy_tester.py | 69 ++--- crypto/func/auto-tests/legacy_tests.json | 1 - crypto/func/auto-tests/legacy_tests.jsonl | 37 +++ crypto/func/auto-tests/run_tests.js | 292 ++++++++++++++++--- crypto/func/auto-tests/run_tests.py | 302 ++++++++++++++------ crypto/func/auto-tests/tests/invalid.fc | 8 + crypto/func/auto-tests/tests/test-math.fc | 2 +- crypto/func/auto-tests/wasm_tests_common.js | 16 +- 9 files changed, 601 insertions(+), 189 deletions(-) delete mode 100644 crypto/func/auto-tests/legacy_tests.json create mode 100644 crypto/func/auto-tests/legacy_tests.jsonl create mode 100644 crypto/func/auto-tests/tests/invalid.fc diff --git a/crypto/func/auto-tests/legacy_tester.js b/crypto/func/auto-tests/legacy_tester.js index 57092d683..53be1d29d 100644 --- a/crypto/func/auto-tests/legacy_tester.js +++ b/crypto/func/auto-tests/legacy_tester.js @@ -1,27 +1,68 @@ -const fs = require('fs/promises'); +// Usage: `node legacy_tests.js` from current dir, providing some env (see getenv() calls). +// This is a JS version of legacy_tester.py to test FunC compiled to WASM. + +const fs = require('fs'); +const path = require('path') +const process = require('process'); const { compileWasm, compileFile } = require('./wasm_tests_common'); + +/** @return {string} */ +function getenv(name, def = null) { + if (name in process.env) + return process.env[name] + if (def === null) { + console.log(`Environment variable ${name} is not set`) + process.exit(1) + } + return def +} + +const FUNCFIFTLIB_MODULE = getenv('FUNCFIFTLIB_MODULE') +const FUNCFIFTLIB_WASM = getenv('FUNCFIFTLIB_WASM') +const TESTS_DIR = "legacy_tests" + +/** + * @return {{filename: string, code_hash: BigInt}[]} + */ +function load_legacy_tests_list(jsonl_filename) { + let contents = fs.readFileSync(jsonl_filename) + let results = [...contents.toString().matchAll(/^\[\s*"(.*?)"\s*,\s*(.*?)\s*]/gms)] + return results.map((line) => ({ + filename: line[1].trim(), + code_hash: BigInt(line[2]), + })) +} + async function main() { - const tests = JSON.parse((await fs.readFile('../legacy_tests.json')).toString('utf-8')) + const tests = load_legacy_tests_list('legacy_tests.jsonl') - for (const [filename, hashstr] of tests) { - if (filename.includes('storage-provider')) continue; + for (let ti = 0; ti < tests.length; ++ti) { + const {filename: filename_rel, code_hash} = tests[ti] + const filename = path.join(TESTS_DIR, filename_rel) + console.log(`Running test ${ti + 1}/${tests.length}: ${filename_rel}`) - const mod = await compileWasm() + if (filename.includes('storage-provider')) { + console.log(" Skip"); + continue; + } - const response = await compileFile(mod, filename); + const wasmModule = await compileWasm(FUNCFIFTLIB_MODULE, FUNCFIFTLIB_WASM) + const response = compileFile(wasmModule, filename); if (response.status !== 'ok') { console.error(response); - throw new Error('Could not compile ' + filename); + throw new Error(`Could not compile ${filename}`); } - if (BigInt('0x' + response.codeHashHex) !== BigInt(hashstr)) { - throw new Error('Compilation result is different for ' + filename); + if (BigInt('0x' + response.codeHashHex) !== code_hash) { + throw new Error(`Code hash is different for ${filename}`); } - console.log(filename, 'ok'); + console.log(' OK '); } + + console.log(`Done ${tests.length}`) } -main() \ No newline at end of file +main().catch(console.error) diff --git a/crypto/func/auto-tests/legacy_tester.py b/crypto/func/auto-tests/legacy_tester.py index 9a9905012..b36614298 100644 --- a/crypto/func/auto-tests/legacy_tester.py +++ b/crypto/func/auto-tests/legacy_tester.py @@ -1,5 +1,13 @@ +# Usage: `legacy_tests.py` from current dir, providing some env (see getenv() calls). +# Unlike run_tests.py, it launches tests from legacy_tests/ folder (which are real-world contracts) +# and checks that code hashes are expected (that contracts are compiled exactly the same way). +# In other words, it doesn't execute TVM, it just compiles fift to acquire a contract hash. +# In the future, we may merge these tests with regular ones (when the testing framework becomes richer). +# Note, that there is also legacy_tester.js to test FunC compiled to WASM. + import os import os.path +import re import subprocess import sys import tempfile @@ -7,39 +15,6 @@ add_pragmas = [] #["allow-post-modification", "compute-asm-ltr"]; -tests = [ - # note, that deployed version of elector,config and multisig differ since it is compilled with func-0.1.0. - # Newer compillators optimize arithmetic and logic expression that can be calculated at the compile time - ["elector/elector-code.fc", 115226404411715505328583639896096915745686314074575650766750648324043316883483], - ["config/config-code.fc", 10913070768607625342121305745084703121685937915388357634624451844356456145601], - ["eth-bridge-multisig/multisig-code.fc", 101509909129354488841890823627011033360100627957439967918234053299675481277954], - - ["bsc-bridge-collector/votes-collector.fc", 62190447221288642706570413295807615918589884489514159926097051017036969900417], - ["uni-lock-wallet/uni-lockup-wallet.fc", 61959738324779104851267145467044677651344601417998258530238254441977103654381], - ["nft-collection/nft-collection-editable.fc", 45561997735512210616567774035540357815786262097548276229169737015839077731274], - ["dns-collection/nft-collection.fc", 107999822699841936063083742021519765435859194241091312445235370766165379261859], - - - # note, that deployed version of tele-nft-item differs since it is compilled with func-0.3.0. - # After introducing of try/catch construction, c2 register is not always the default one. - # Thus it is necessary to save it upon jumps, differences of deployed and below compilled is that - # "c2 SAVE" is added to the beginning of recv_internal. It does not change behavior. - ["tele-nft-item/nft-item.fc", 69777543125381987786450436977742010705076866061362104025338034583422166453344], - - ["storage/storage-contract.fc", 91377830060355733016937375216020277778264560226873154627574229667513068328151], - ["storage/storage-provider.fc", 13618336676213331164384407184540461509022654507176709588621016553953760588122], - ["nominator-pool/pool.fc", 69767057279163099864792356875696330339149706521019810113334238732928422055375], - ["jetton-minter/jetton-minter.fc", 9028309926287301331466371999814928201427184114165428257502393474125007156494], - ["gg-marketplace/nft-marketplace-v2.fc", 92199806964112524639740773542356508485601908152150843819273107618799016205930], - ["jetton-wallet/jetton-wallet.fc", 86251125787443633057458168028617933212663498001665054651523310772884328206542], - ["whales-nominators/nominators.fc", 8941364499854379927692172316865293429893094891593442801401542636695127885153], - - - ["tact-examples/treasure_Treasure.code.fc", 13962538639825790677138656603323869918938565499584297120566680287245364723897], - ["tact-examples/jetton_SampleJetton.code.fc", 94076762218493729104783735200107713211245710256802265203823917715299139499110], - ["tact-examples/jetton_JettonDefaultWallet.code.fc", 29421313492520031238091587108198906058157443241743283101866538036369069620563], - ["tact-examples/maps_MapTestContract.code.fc", 22556550222249123835909180266811414538971143565993192846012583552876721649744], -] def getenv(name, default=None): if name in os.environ: @@ -49,8 +24,10 @@ def getenv(name, default=None): exit(1) return default + FUNC_EXECUTABLE = getenv("FUNC_EXECUTABLE", "func") FIFT_EXECUTABLE = getenv("FIFT_EXECUTABLE", "fift") +FIFT_LIBS_FOLDER = getenv("FIFTPATH") # this env is needed for fift to work properly TMP_DIR = tempfile.mkdtemp() COMPILED_FIF = os.path.join(TMP_DIR, "compiled.fif") @@ -58,6 +35,17 @@ def getenv(name, default=None): TESTS_DIR = "legacy_tests" + +def load_legacy_tests_list(jsonl_filename: str) -> list[tuple[str, int]]: + with open(jsonl_filename) as fd: + contents = fd.read() + results = re.findall('^\[\s*"(.*?)"\s*,\s*(.*?)\s*]', contents, re.MULTILINE) + return list(map(lambda line: (line[0], int(line[1])), results)) + + +tests = load_legacy_tests_list('legacy_tests.jsonl') + + class ExecutionError(Exception): pass @@ -119,12 +107,11 @@ def get_version(): return s.strip() success = 0 -for ti, t in enumerate(tests): - tf, th = t - print(" Running test %d/%d: %s" % (ti + 1, len(tests), tf), file=sys.stderr) - tf = os.path.join(TESTS_DIR, tf) +for ti, (filename_rel, code_hash) in enumerate(tests): + print("Running test %d/%d: %s" % (ti + 1, len(tests), filename_rel), file=sys.stderr) try: - compile_func(tf) + filename = os.path.join(TESTS_DIR, filename_rel) + compile_func(filename) except ExecutionError as e: print(file=sys.stderr) print("Compilation error", file=sys.stderr) @@ -136,8 +123,8 @@ def get_version(): try: func_out = run_runner() - if func_out != th: - raise ExecutionError("Error : expected '%d', found '%d'" % (th, func_out)) + if func_out != code_hash: + raise ExecutionError("Error : expected '%d', found '%d'" % (code_hash, func_out)) success += 1 except ExecutionError as e: print(e, file=sys.stderr) @@ -148,4 +135,4 @@ def get_version(): print(" OK ", file=sys.stderr) print(get_version()) -print("Done: Success %d, Error: %d"%(success, len(tests)-success), file=sys.stderr) \ No newline at end of file +print("Done: Success %d, Error: %d"%(success, len(tests)-success), file=sys.stderr) diff --git a/crypto/func/auto-tests/legacy_tests.json b/crypto/func/auto-tests/legacy_tests.json deleted file mode 100644 index 61a433bb7..000000000 --- a/crypto/func/auto-tests/legacy_tests.json +++ /dev/null @@ -1 +0,0 @@ -[["elector/elector-code.fc", "115226404411715505328583639896096915745686314074575650766750648324043316883483"], ["config/config-code.fc", "10913070768607625342121305745084703121685937915388357634624451844356456145601"], ["eth-bridge-multisig/multisig-code.fc", "101509909129354488841890823627011033360100627957439967918234053299675481277954"], ["bsc-bridge-collector/votes-collector.fc", "62190447221288642706570413295807615918589884489514159926097051017036969900417"], ["uni-lock-wallet/uni-lockup-wallet.fc", "61959738324779104851267145467044677651344601417998258530238254441977103654381"], ["nft-collection/nft-collection-editable.fc", "45561997735512210616567774035540357815786262097548276229169737015839077731274"], ["dns-collection/nft-collection.fc", "107999822699841936063083742021519765435859194241091312445235370766165379261859"], ["tele-nft-item/nft-item.fc", "69777543125381987786450436977742010705076866061362104025338034583422166453344"], ["storage/storage-contract.fc", "91377830060355733016937375216020277778264560226873154627574229667513068328151"], ["storage/storage-provider.fc", "13618336676213331164384407184540461509022654507176709588621016553953760588122"], ["nominator-pool/pool.fc", "69767057279163099864792356875696330339149706521019810113334238732928422055375"], ["jetton-minter/jetton-minter.fc", "9028309926287301331466371999814928201427184114165428257502393474125007156494"], ["gg-marketplace/nft-marketplace-v2.fc", "92199806964112524639740773542356508485601908152150843819273107618799016205930"], ["jetton-wallet/jetton-wallet.fc", "86251125787443633057458168028617933212663498001665054651523310772884328206542"], ["whales-nominators/nominators.fc", "8941364499854379927692172316865293429893094891593442801401542636695127885153"], ["tact-examples/treasure_Treasure.code.fc", "13962538639825790677138656603323869918938565499584297120566680287245364723897"], ["tact-examples/jetton_SampleJetton.code.fc", "94076762218493729104783735200107713211245710256802265203823917715299139499110"], ["tact-examples/jetton_JettonDefaultWallet.code.fc", "29421313492520031238091587108198906058157443241743283101866538036369069620563"], ["tact-examples/maps_MapTestContract.code.fc", "22556550222249123835909180266811414538971143565993192846012583552876721649744"]] \ No newline at end of file diff --git a/crypto/func/auto-tests/legacy_tests.jsonl b/crypto/func/auto-tests/legacy_tests.jsonl new file mode 100644 index 000000000..15cd72754 --- /dev/null +++ b/crypto/func/auto-tests/legacy_tests.jsonl @@ -0,0 +1,37 @@ +// This file is used by both legacy_tester.py and legacy_tester.js. +// Its extension is .jsonl (not just .json) in order to use comments. +// It contains a simple format ["filename_rel",bigint_hash] +// and is parsed just using regexp ^\[\s*"(.*?)"\s*,\s*(.*?)\s*] +// Some tests can be commented out, or they can be multiline, it works. + +// note, that deployed version of elector,config and multisig differ since it is compiled with func-0.1.0. +// Newer compilers optimize arithmetic and logic expression that can be calculated at the compile time +["elector/elector-code.fc", 115226404411715505328583639896096915745686314074575650766750648324043316883483] +["config/config-code.fc", 10913070768607625342121305745084703121685937915388357634624451844356456145601] +["eth-bridge-multisig/multisig-code.fc", 101509909129354488841890823627011033360100627957439967918234053299675481277954] + +["bsc-bridge-collector/votes-collector.fc", 62190447221288642706570413295807615918589884489514159926097051017036969900417] +["uni-lock-wallet/uni-lockup-wallet.fc", 61959738324779104851267145467044677651344601417998258530238254441977103654381] +["nft-collection/nft-collection-editable.fc", 45561997735512210616567774035540357815786262097548276229169737015839077731274] +["dns-collection/nft-collection.fc", 107999822699841936063083742021519765435859194241091312445235370766165379261859] + + +// note, that deployed version of tele-nft-item differs since it is compiled with func-0.3.0. +// After introducing of try/catch construction, c2 register is not always the default one. +// Thus it is necessary to save it upon jumps, differences of deployed and below compiled is that +// "c2 SAVE" is added to the beginning of recv_internal. It does not change behavior. +["tele-nft-item/nft-item.fc", 69777543125381987786450436977742010705076866061362104025338034583422166453344] + +["storage/storage-contract.fc", 91377830060355733016937375216020277778264560226873154627574229667513068328151] +["storage/storage-provider.fc", 13618336676213331164384407184540461509022654507176709588621016553953760588122] +["nominator-pool/pool.fc", 69767057279163099864792356875696330339149706521019810113334238732928422055375] +["jetton-minter/jetton-minter.fc", 9028309926287301331466371999814928201427184114165428257502393474125007156494] +["gg-marketplace/nft-marketplace-v2.fc", 92199806964112524639740773542356508485601908152150843819273107618799016205930] +["jetton-wallet/jetton-wallet.fc", 86251125787443633057458168028617933212663498001665054651523310772884328206542] +["whales-nominators/nominators.fc", 8941364499854379927692172316865293429893094891593442801401542636695127885153] + + +["tact-examples/treasure_Treasure.code.fc", 13962538639825790677138656603323869918938565499584297120566680287245364723897] +["tact-examples/jetton_SampleJetton.code.fc", 94076762218493729104783735200107713211245710256802265203823917715299139499110] +["tact-examples/jetton_JettonDefaultWallet.code.fc", 29421313492520031238091587108198906058157443241743283101866538036369069620563] +["tact-examples/maps_MapTestContract.code.fc", 22556550222249123835909180266811414538971143565993192846012583552876721649744] diff --git a/crypto/func/auto-tests/run_tests.js b/crypto/func/auto-tests/run_tests.js index f8e6c6a78..19db5ffe7 100644 --- a/crypto/func/auto-tests/run_tests.js +++ b/crypto/func/auto-tests/run_tests.js @@ -1,77 +1,277 @@ -const fs = require('fs/promises'); +// Usage: `node run_tests.js tests_dir` OR `node run_tests.js test_file.fc` +// from current dir, providing some env (see getenv() calls). +// This is a JS version of run_tests.py to test FunC compiled to WASM. +// Don't forget to keep it identical to Python version! + +const fs = require('fs'); const os = require('os'); const path = require('path'); const { compileWasm, compileFile } = require('./wasm_tests_common'); -const { execSync } = require('child_process'); - -async function main() { - const compiledPath = path.join(os.tmpdir(), 'compiled.fif'); - const runnerPath = path.join(os.tmpdir(), 'runner.fif'); +const child_process = require('child_process'); - const tests = (await fs.readdir('.')).filter(f => f.endsWith('.fc')).sort(); +function print(...args) { + console.log(...args) +} - const mathChars = '0x123456789()+-*/<>'.split('') +/** @return {string} */ +function getenv(name, def = null) { + if (name in process.env) + return process.env[name] + if (def === null) { + print(`Environment variable ${name} is not set`) + process.exit(1) + } + return def +} - for (const testFile of tests) { - const mod = await compileWasm() +const FUNCFIFTLIB_MODULE = getenv('FUNCFIFTLIB_MODULE') +const FUNCFIFTLIB_WASM = getenv('FUNCFIFTLIB_WASM') +const FIFT_EXECUTABLE = getenv('FIFT_EXECUTABLE') +const FIFT_LIBS_FOLDER = getenv('FIFTPATH') // this env is needed for fift to work properly +const TMP_DIR = os.tmpdir() - const result = await compileFile(mod, testFile) +class CmdLineOptions { + constructor(/**string[]*/ argv) { + if (argv.length !== 3) { + print("Usage: node run_tests.js tests_dir OR node run_tests.js test_file.fc") + process.exit(1) + } + if (!fs.existsSync(argv[2])) { + print(`Input '${argv[2]}' doesn't exist`) + process.exit(1) + } - if (result.status !== 'ok') { - console.error(result); - throw new Error('Could not compile ' + filename); + if (fs.lstatSync(argv[2]).isDirectory()) { + this.tests_dir = argv[2] + this.test_file = null + } else { + this.tests_dir = path.dirname(argv[2]) + this.test_file = argv[2] } + } - const fileLines = (await fs.readFile(testFile)).toString('utf-8').split('\n'); + /** @return {string[]} */ + find_tests() { + if (this.test_file) // an option to run (debug) a single test + return [this.test_file] - const testCases = []; + let tests = fs.readdirSync(this.tests_dir).filter(f => f.endsWith('.fc') || f.endsWith(".func")) + tests.sort() + return tests.map(f => path.join(this.tests_dir, f)) + } +} - for (const line of fileLines) { - const parts = line.split('|').map(c => c.trim()); - if (parts.length !== 4 || parts[0] !== 'TESTCASE') continue; +class ParseInputError extends Error { +} - const processedInputs = []; +class FuncCompilationFailedError extends Error { + constructor(/**string*/ message, /**string*/ stderr) { + super(message); + this.stderr = stderr + } +} - for (const input of parts[2].split(' ')) { - if (input.includes('x{')) { - processedInputs.push(input); - continue; - } +class FuncCompilationSucceededError extends Error { +} - if (input.length === 0) { - continue - } +class FiftExecutionFailedError extends Error { + constructor(/**string*/ message, /**string*/ stderr) { + super(message); + this.stderr = stderr + } +} - const replacedInput = input.split('').filter(c => mathChars.includes(c)).join('').replace('//', '/').replace(/([0-9a-f])($|[^0-9a-fx])/gmi, '$1n$2') +class CompareOutputError extends Error { + constructor(/**string*/ message, /**string*/ output) { + super(message); + this.output = output + } +} - processedInputs.push(eval(replacedInput).toString()); - } - testCases.push([parts[1], processedInputs.join(' '), parts[3]]); +/* + * In positive tests, there are several testcases "input X should produce output Y". + */ +class FuncTestCaseInputOutput { + static reJustNumber = /^[-+]?\d+$/ + static reMathExpr = /^[0x123456789()+\-*/<>]*$/ + + constructor(/**string*/ method_id_str, /**string*/ input_str, /**string*/ output_str) { + let processed_inputs = [] + for (let in_arg of input_str.split(' ')) { + if (in_arg.length === 0) + continue + else if (in_arg.startsWith("x{") || FuncTestCaseInputOutput.reJustNumber.test(in_arg)) + processed_inputs.push(in_arg) + else if (FuncTestCaseInputOutput.reMathExpr.test(in_arg)) + // replace "3<<254" with "3n<<254n" (big number) before eval (in Python we don't need this) + processed_inputs.push(eval(in_arg.replace('//', '/').replace(/(\d)($|\D)/gmi, '$1n$2')).toString()) + else + throw new ParseInputError(`'${in_arg}' can't be evaluated`) } - await fs.writeFile(compiledPath, '"Asm.fif" include\n' + JSON.parse('"' + result.fiftCode + '"')); - await fs.writeFile(runnerPath, `"${compiledPath}" include `${t[1]} ${t[0]} code 1 runvmx abort"exitcode is not 0" .s cr { drop } depth 1- times`).join('\n')}`) + this.method_id = +method_id_str + this.input = processed_inputs.join(' ') + this.expected_output = output_str + } - const fiftResult = execSync(`${process.env.FIFT_EXECUTABLE || 'fift'} -I ${process.env.FIFT_LIBS} /tmp/runner.fif`, { - stdio: ['pipe', 'pipe', 'ignore'] - }).toString('utf-8') + check(/**string[]*/ stdout_lines, /**number*/ line_idx) { + if (stdout_lines[line_idx] !== this.expected_output) + throw new CompareOutputError(`error on case ${line_idx + 1}: expected '${this.expected_output}', found '${stdout_lines[line_idx]}'`, stdout_lines.join("\n")) + } +} - const testResults = fiftResult.split('\n').map(s => s.trim()).filter(s => s.length > 0) +/* + * @stderr checks, when compilation fails, that stderr (compilation error) is expected. + */ +class FuncTestCaseStderrIncludes { + constructor(/**string*/ expected_substr) { + this.expected_substr = expected_substr + } - if (testResults.length !== testCases.length) { - throw new Error(`Got ${testResults.length} results but there are ${testCases.length} cases`) - } + check(/**string*/ stderr) { + if (!stderr.includes(this.expected_substr)) + throw new CompareOutputError(`pattern '${this.expected_substr}' not found in stderr`, stderr) + } +} - for (let i = 0; i < testResults.length; i++) { - if (testResults[i] !== testCases[i][2]) { - throw new Error(`Unequal result ${testResults[i]} and case ${testCases[i][2]}`) +class FuncTestFile { + constructor(/**string*/ func_filename, /**string*/ artifacts_folder) { + this.func_filename = func_filename + this.artifacts_folder = artifacts_folder + this.compilation_should_fail = false + /** @type {FuncTestCaseStderrIncludes[]} */ + this.stderr_includes = [] + /** @type {FuncTestCaseInputOutput[]} */ + this.input_output = [] + } + + parse_input_from_func_file() { + const lines = fs.readFileSync(this.func_filename, 'utf-8').split(/\r?\n/) + let i = 0 + while (i < lines.length) { + const line = lines[i] + if (line.startsWith('TESTCASE')) { + let s = line.split("|").map(p => p.trim()) + if (s.length !== 4) + throw new ParseInputError(`incorrect format of TESTCASE: ${line}`) + this.input_output.push(new FuncTestCaseInputOutput(s[1], s[2], s[3])) + } else if (line.startsWith('@compilation_should_fail')) { + this.compilation_should_fail = true + } else if (line.startsWith('@stderr')) { + this.stderr_includes.push(new FuncTestCaseStderrIncludes(line.substring(7).trim())) } + i++ + } + + if (this.input_output.length === 0 && !this.compilation_should_fail) + throw new ParseInputError("no TESTCASE present") + if (this.input_output.length !== 0 && this.compilation_should_fail) + throw new ParseInputError("TESTCASE present, but compilation_should_fail") + } + + get_compiled_fif_filename() { + return this.artifacts_folder + "/compiled.fif" + } + + get_runner_fif_filename() { + return this.artifacts_folder + "/runner.fif" + } + + async run_and_check() { + const wasmModule = await compileWasm(FUNCFIFTLIB_MODULE, FUNCFIFTLIB_WASM) + let res = compileFile(wasmModule, this.func_filename) + let exit_code = res.status === 'ok' ? 0 : 1 + let stderr = res.message + let stdout = '' + + if (exit_code === 0 && this.compilation_should_fail) + throw new FuncCompilationSucceededError("compilation succeeded, but it should have failed") + + if (exit_code !== 0 && this.compilation_should_fail) { + for (let should_include of this.stderr_includes) + should_include.check(stderr) + return + } + + if (exit_code !== 0 && !this.compilation_should_fail) + throw new FuncCompilationFailedError(`func exit_code = ${exit_code}`, stderr) + + fs.writeFileSync(this.get_compiled_fif_filename(), `"Asm.fif" include\n${res.fiftCode}`) + { + let runner = `"${this.get_compiled_fif_filename()}" include x.trim()).filter(s => s.length > 0) + + if (exit_code) + throw new FiftExecutionFailedError(`fift exit_code = ${exit_code}`, stderr) + + if (stdout_lines.length !== this.input_output.length) + throw new CompareOutputError(`unexpected number of fift output: ${stdout_lines.length} lines, but ${this.input_output.length} testcases`, stdout) + + for (let i = 0; i < stdout_lines.length; ++i) + this.input_output[i].check(stdout_lines, i) + } +} + +async function run_all_tests(/**string[]*/ tests) { + for (let ti = 0; ti < tests.length; ++ti) { + let func_filename = tests[ti] + print(`Running test ${ti + 1}/${tests.length}: ${func_filename}`) + + let artifacts_folder = path.join(TMP_DIR, func_filename) + let testcase = new FuncTestFile(func_filename, artifacts_folder) + + try { + if (!fs.existsSync(artifacts_folder)) + fs.mkdirSync(artifacts_folder, {recursive: true}) + testcase.parse_input_from_func_file() + await testcase.run_and_check() + fs.rmSync(artifacts_folder, {recursive: true}) + + if (testcase.compilation_should_fail) + print(" OK, compilation failed as it should") + else + print(` OK, ${testcase.input_output.length} cases`) + } catch (e) { + if (e instanceof ParseInputError) { + print(" Error parsing input:", e.message) + process.exit(2) + } else if (e instanceof FuncCompilationFailedError) { + print(" Error compiling func:", e.message) + print(" stderr:") + print(e.stderr.trimEnd()) + process.exit(2) + } else if (e instanceof FiftExecutionFailedError) { + print(" Error executing fift:", e.message) + print(" stderr:") + print(e.stderr.trimEnd()) + print(" compiled.fif at:", testcase.get_compiled_fif_filename()) + process.exit(2) + } else if (e instanceof CompareOutputError) { + print(" Mismatch in output:", e.message) + print(" Full output:") + print(e.output.trimEnd()) + print(" Was compiled to:", testcase.get_compiled_fif_filename()) + process.exit(2) + } + throw e + } } } -main() \ No newline at end of file +const tests = new CmdLineOptions(process.argv).find_tests() +print(`Found ${tests.length} tests`) +run_all_tests(tests).then( + () => print(`Done, ${tests.length} tests`), + console.error +) diff --git a/crypto/func/auto-tests/run_tests.py b/crypto/func/auto-tests/run_tests.py index 158e871b8..990e50461 100644 --- a/crypto/func/auto-tests/run_tests.py +++ b/crypto/func/auto-tests/run_tests.py @@ -1,5 +1,18 @@ +# Usage: `run_tests.py tests_dir` OR `run_tests.py test_file.fc` +# from current dir, providing some env (see getenv() calls). +# Every .fc file should provide {- testcase description in a comment -}, consider tests/ folder. +# +# Tests for FunC can be +# * positive (compiled to .fif, run with fift, compared output with the one expected) +# * negative (compilation fails, and it's expected; patterns in stderr can be specified) +# +# Note, that there is also run_tests.js to test FunC compiled to WASM. +# Don't forget to keep it identical to Python version! + import os import os.path +import re +import shutil import subprocess import sys import tempfile @@ -16,95 +29,224 @@ def getenv(name, default=None): FUNC_EXECUTABLE = getenv("FUNC_EXECUTABLE", "func") FIFT_EXECUTABLE = getenv("FIFT_EXECUTABLE", "fift") +FIFT_LIBS_FOLDER = getenv("FIFTPATH") # this env is needed for fift to work properly TMP_DIR = tempfile.mkdtemp() -COMPILED_FIF = os.path.join(TMP_DIR, "compiled.fif") -RUNNER_FIF = os.path.join(TMP_DIR, "runner.fif") -if len(sys.argv) != 2: - print("Usage : run_tests.py tests_dir", file=sys.stderr) - exit(1) -TESTS_DIR = sys.argv[1] +class CmdLineOptions: + def __init__(self, argv: list[str]): + if len(argv) != 2: + print("Usage: run_tests.py tests_dir OR run_tests.py test_file.fc", file=sys.stderr) + exit(1) + if not os.path.exists(argv[1]): + print("Input '%s' doesn't exist" % argv[1], file=sys.stderr) + exit(1) + + if os.path.isdir(argv[1]): + self.tests_dir = argv[1] + self.test_file = None + else: + self.tests_dir = os.path.dirname(argv[1]) + self.test_file = argv[1] + + def find_tests(self) -> list[str]: + if self.test_file is not None: # an option to run (debug) a single test + return [self.test_file] + + tests = [f for f in os.listdir(self.tests_dir) if f.endswith(".fc") or f.endswith(".func")] + tests.sort() + return [os.path.join(self.tests_dir, f) for f in tests] -class ExecutionError(Exception): + +class ParseInputError(Exception): pass -def compile_func(f): - res = subprocess.run([FUNC_EXECUTABLE, "-o", COMPILED_FIF, "-SPA", f], capture_output=True, timeout=10) - if res.returncode != 0: - raise ExecutionError(str(res.stderr, "utf-8")) +class FuncCompilationFailedError(Exception): + def __init__(self, message: str, stderr: str): + super().__init__(message) + self.stderr = stderr -def run_runner(): - res = subprocess.run([FIFT_EXECUTABLE, RUNNER_FIF], capture_output=True, timeout=10) - if res.returncode != 0: - raise ExecutionError(str(res.stderr, "utf-8")) - s = str(res.stdout, "utf-8") - s = [x.strip() for x in s.split("\n")] - return [x for x in s if x != ""] +class FuncCompilationSucceededError(Exception): + pass -tests = [s for s in os.listdir(TESTS_DIR) if s.endswith(".fc")] -tests.sort() -print("Found", len(tests), "tests", file=sys.stderr) -for ti, tf in enumerate(tests): - print("Running test %d/%d: %s" % (ti + 1, len(tests), tf), file=sys.stderr) - tf = os.path.join(TESTS_DIR, tf) - try: - compile_func(tf) - except ExecutionError as e: - print(file=sys.stderr) - print("Compilation error", file=sys.stderr) - print(e, file=sys.stderr) - exit(2) - with open(tf, "r") as fd: - lines = fd.readlines() - cases = [] - for s in lines: - s = [x.strip() for x in s.split("|")] - if len(s) == 4 and s[0].strip() == "TESTCASE": - cases.append(s[1:]) - if len(cases) == 0: - print(file=sys.stderr) - print("Error: no test cases", file=sys.stderr) - exit(2) - - # preprocess arithmetics in input - for i in range(len(cases)): - inputs = cases[i][1].split(" ") - processed_inputs = "" - for in_arg in inputs: - if "x{" in in_arg: - processed_inputs += in_arg +class FiftExecutionFailedError(Exception): + def __init__(self, message: str, stderr: str): + super().__init__(message) + self.stderr = stderr + + +class CompareOutputError(Exception): + def __init__(self, message: str, output: str): + super().__init__(message) + self.output = output + + +class FuncTestCaseInputOutput: + """ + In positive tests, there are several testcases "input X should produce output Y". + They are written as a table: + TESTCASE | method_id | input (one or several) | output + """ + reJustNumber = re.compile("[-+]?\d+") + reMathExpr = re.compile("[0x123456789()+\-*/<>]+") + + def __init__(self, method_id_str: str, input_str: str, output_str: str): + processed_inputs = [] + for in_arg in input_str.split(" "): + if len(in_arg) == 0: continue - # filter and execute - # is it safe enough? - filtered_in = "".join(filter(lambda x: x in "0x123456789()+-*/<>", in_arg)) - if filtered_in: - processed_inputs += str(eval(filtered_in)) + " " - cases[i][1] = processed_inputs.strip() - - with open(RUNNER_FIF, "w") as f: - print("\"%s\" include { return mod.UTF8ToString(ptr); }; -async function compileFile(mod, filename) { +/** @return {{status: string, message: string, fiftCode: string, codeBoc: string, codeHashHex: string}} */ +function compileFile(mod, filename) { const callbackPtr = mod.addFunction((_kind, _data, contents, error) => { const kind = copyFromCString(mod, _kind); const data = copyFromCString(mod, _data); @@ -28,7 +29,7 @@ async function compileFile(mod, filename) { try { copyToCStringPtr(mod, fsSync.readFileSync(path).toString('utf-8'), contents); } catch (err) { - copyToCStringPtr(mod, e.message, error); + copyToCStringPtr(mod, err.message, error); } } else { copyToCStringPtr(mod, 'Unknown callback kind ' + kind, error); @@ -47,14 +48,11 @@ async function compileFile(mod, filename) { return JSON.parse(copyFromCString(mod, responsePtr)); } -const wasmModule = require(process.env.FUNCFIFTLIB_MODULE) +async function compileWasm(fiftFuncLibJsFileName, fiftFuncLibWasmFileName) { + const wasmModule = require(fiftFuncLibJsFileName) + const wasmBinary = new Uint8Array(fsSync.readFileSync(fiftFuncLibWasmFileName)) -const wasmBinary = new Uint8Array(fsSync.readFileSync(process.env.FUNCFIFTLIB_WASM)) - -async function compileWasm() { - const mod = await wasmModule({ wasmBinary }) - - return mod + return await wasmModule({ wasmBinary }) } module.exports = { From cbd78964c561083e5a31a12a2ec1e1eea1f14e88 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Sat, 20 Apr 2024 23:13:10 +0300 Subject: [PATCH 03/30] [FunC] CMake option -DFUNC_DEBUG for development purposes Seeing function name in debugger makes it much easier to delve into FunC sources --- crypto/CMakeLists.txt | 4 ++++ crypto/func/builtins.cpp | 9 +++++++++ crypto/func/func.h | 6 ++++++ crypto/func/parse-func.cpp | 9 +++++++++ 4 files changed, 28 insertions(+) diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index 306194408..50cf8f3bf 100644 --- a/crypto/CMakeLists.txt +++ b/crypto/CMakeLists.txt @@ -390,6 +390,10 @@ target_link_libraries(func PUBLIC ton_crypto src_parser git ton_block) if (WINGETOPT_FOUND) target_link_libraries_system(func wingetopt) endif() +if (${FUNC_DEBUG}) # -DFUNC_DEBUG=1 in CMake options => #define FUNC_DEBUG (for development purposes) + message(STATUS "FUNC_DEBUG is ON") + target_compile_definitions(func PRIVATE FUNC_DEBUG=1) +endif() if (USE_EMSCRIPTEN) add_executable(funcfiftlib funcfiftlib/funcfiftlib.cpp ${FUNC_LIB_SOURCE}) diff --git a/crypto/func/builtins.cpp b/crypto/func/builtins.cpp index 9de673fd7..d86ab7ecd 100644 --- a/crypto/func/builtins.cpp +++ b/crypto/func/builtins.cpp @@ -51,6 +51,9 @@ template SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const T& func, bool impure = false) { SymDef* def = predefine_builtin_func(name, func_type); def->value = new SymValAsmFunc{func_type, func, impure}; +#ifdef FUNC_DEBUG + dynamic_cast(def->value)->name = name; +#endif return def; } @@ -59,6 +62,9 @@ SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const T& func std::initializer_list ret_order = {}, bool impure = false) { SymDef* def = predefine_builtin_func(name, func_type); def->value = new SymValAsmFunc{func_type, func, arg_order, ret_order, impure}; +#ifdef FUNC_DEBUG + dynamic_cast(def->value)->name = name; +#endif return def; } @@ -67,6 +73,9 @@ SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const AsmOp& bool impure = false) { SymDef* def = predefine_builtin_func(name, func_type); def->value = new SymValAsmFunc{func_type, make_simple_compile(macro), arg_order, ret_order, impure}; +#ifdef FUNC_DEBUG + dynamic_cast(def->value)->name = name; +#endif return def; } diff --git a/crypto/func/func.h b/crypto/func/func.h index 7da3f0ad8..f4756edd6 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -773,6 +773,9 @@ struct SymVal : sym::SymValBase { struct SymValFunc : SymVal { std::vector arg_order, ret_order; +#ifdef FUNC_DEBUG + std::string name; // seeing function name in debugger makes it much easier to delve into FunC sources +#endif ~SymValFunc() override = default; SymValFunc(int val, TypeExpr* _ft, bool _impure = false) : SymVal(_Func, val, _ft, _impure) { } @@ -809,6 +812,9 @@ struct SymValType : sym::SymValBase { struct SymValGlobVar : sym::SymValBase { TypeExpr* sym_type; int out_idx{0}; +#ifdef FUNC_DEBUG + std::string name; // seeing variable name in debugger makes it much easier to delve into FunC sources +#endif SymValGlobVar(int val, TypeExpr* gvtype, int oidx = 0) : sym::SymValBase(_GlobVar, val), sym_type(gvtype), out_idx(oidx) { } diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index fa2bac023..0e0378218 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -230,6 +230,9 @@ void parse_global_var_decl(Lexer& lex) { } } else { sym_def->value = new SymValGlobVar{glob_var_cnt++, var_type}; +#ifdef FUNC_DEBUG + dynamic_cast(sym_def->value)->name = lex.cur().str; +#endif glob_vars.push_back(sym_def); } lex.next(); @@ -384,6 +387,9 @@ void parse_global_var_decls(Lexer& lex) { SymValCodeFunc* make_new_glob_func(SymDef* func_sym, TypeExpr* func_type, bool impure = false) { SymValCodeFunc* res = new SymValCodeFunc{glob_func_cnt, func_type, impure}; +#ifdef FUNC_DEBUG + res->name = func_sym->name(); +#endif func_sym->value = res; glob_func.push_back(func_sym); glob_func_cnt++; @@ -1530,6 +1536,9 @@ void parse_func_def(Lexer& lex) { } else { Lexem asm_lexem = lex.cur(); SymValAsmFunc* asm_func = parse_asm_func_body(lex, func_type, arg_list, ret_type, impure); +#ifdef FUNC_DEBUG + asm_func->name = func_name.str; +#endif if (func_sym_val) { if (dynamic_cast(func_sym_val)) { asm_lexem.error("function `"s + func_name.str + "` was already declared as an ordinary function"); From bac4e3df9780e6f000884c6e5e0a1b68fcadb12e Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Sun, 21 Apr 2024 23:21:07 +0300 Subject: [PATCH 04/30] [FunC] Enrich testing framework, add fif output patterns * @fif_codegen to match compiled.fif against an expected pattern * @fif_codegen_avoid to ensure compiled.fif doesn't contain a substring * both in Python and JS run_tests * consider tests/codegen_check_demo.fc for examples --- crypto/func/auto-tests/run_tests.js | 169 ++++++++++++++++-- crypto/func/auto-tests/run_tests.py | 168 +++++++++++++++-- .../auto-tests/tests/codegen_check_demo.fc | 95 ++++++++++ 3 files changed, 405 insertions(+), 27 deletions(-) create mode 100644 crypto/func/auto-tests/tests/codegen_check_demo.fc diff --git a/crypto/func/auto-tests/run_tests.js b/crypto/func/auto-tests/run_tests.js index 19db5ffe7..28a0d5368 100644 --- a/crypto/func/auto-tests/run_tests.js +++ b/crypto/func/auto-tests/run_tests.js @@ -89,6 +89,9 @@ class CompareOutputError extends Error { } } +class CompareFifCodegenError extends Error { +} + /* * In positive tests, there are several testcases "input X should produce output Y". @@ -124,34 +127,136 @@ class FuncTestCaseInputOutput { /* * @stderr checks, when compilation fails, that stderr (compilation error) is expected. + * If it's multiline, all lines must be present in specified order. */ -class FuncTestCaseStderrIncludes { - constructor(/**string*/ expected_substr) { - this.expected_substr = expected_substr +class FuncTestCaseStderr { + constructor(/**string[]*/ stderr_pattern, /**boolean*/ avoid) { + this.stderr_pattern = stderr_pattern + this.avoid = avoid } check(/**string*/ stderr) { - if (!stderr.includes(this.expected_substr)) - throw new CompareOutputError(`pattern '${this.expected_substr}' not found in stderr`, stderr) + const line_match = this.find_pattern_in_stderr(stderr.split(/\n/)) + if (line_match === -1 && !this.avoid) + throw new CompareOutputError("pattern not found in stderr:\n" + + this.stderr_pattern.map(x => " " + x).join("\n"), stderr) + else if (line_match !== -1 && this.avoid) + throw new CompareOutputError(`pattern found (line ${line_match + 1}), but not expected to be:\n` + + this.stderr_pattern.map(x => " " + x).join("\n"), stderr) + } + + find_pattern_in_stderr(/**string[]*/ stderr) { + for (let line_start = 0; line_start < stderr.length; ++line_start) + if (this.try_match_pattern(0, stderr, line_start)) + return line_start + return -1 + } + + try_match_pattern(/**number*/ pattern_offset, /**string[]*/ stderr, /**number*/ offset) { + if (pattern_offset >= this.stderr_pattern.length) + return true + if (offset >= stderr.length) + return false + + const line_pattern = this.stderr_pattern[pattern_offset] + const line_output = stderr[offset] + return line_output.includes(line_pattern) && this.try_match_pattern(pattern_offset + 1, stderr, offset + 1) + } +} + +/* + * @fif_codegen checks that contents of compiled.fif matches the expected pattern. + * @fif_codegen_avoid checks that is does not match the pattern. + * See comments in run_tests.py. + */ +class FuncTestCaseFifCodegen { + constructor(/**string[]*/ fif_pattern, /**boolean*/ avoid) { + /** @type {string[]} */ + this.fif_pattern = fif_pattern.map(s => s.trim()) + this.avoid = avoid + } + + check(/**string[]*/ fif_output) { + // in case there are no comments at all (typically for wasm), drop them from fif_pattern + const has_comments = fif_output.some(line => line.includes("//") && !line.includes("generated from")) + if (!has_comments) { + this.fif_pattern = this.fif_pattern.map(s => FuncTestCaseFifCodegen.split_line_to_cmd_and_comment(s)[0]) + this.fif_pattern = this.fif_pattern.filter(s => s !== '') + } + + const line_match = this.find_pattern_in_fif_output(fif_output) + if (line_match === -1 && !this.avoid) + throw new CompareFifCodegenError("pattern not found:\n" + + this.fif_pattern.map(x => " " + x).join("\n")) + else if (line_match !== -1 && this.avoid) + throw new CompareFifCodegenError(`pattern found (line ${line_match + 1}), but not expected to be:\n` + + this.fif_pattern.map(x => " " + x).join("\n")) + } + + find_pattern_in_fif_output(/**string[]*/ fif_output) { + for (let line_start = 0; line_start < fif_output.length; ++line_start) + if (this.try_match_pattern(0, fif_output, line_start)) + return line_start + return -1 + } + + try_match_pattern(/**number*/ pattern_offset, /**string[]*/ fif_output, /**number*/ offset) { + if (pattern_offset >= this.fif_pattern.length) + return true + if (offset >= fif_output.length) + return false + const line_pattern = this.fif_pattern[pattern_offset] + const line_output = fif_output[offset] + + if (line_pattern !== "...") { + if (!FuncTestCaseFifCodegen.does_line_match(line_pattern, line_output)) + return false + return this.try_match_pattern(pattern_offset + 1, fif_output, offset + 1) + } + while (offset < fif_output.length) { + if (this.try_match_pattern(pattern_offset + 1, fif_output, offset)) + return true + offset = offset + 1 + } + return false + } + + static split_line_to_cmd_and_comment(/**string*/ trimmed_line) { + const pos = trimmed_line.indexOf("//") + if (pos === -1) + return [trimmed_line, null] + else + return [trimmed_line.substring(0, pos).trimEnd(), trimmed_line.substring(pos + 2).trimStart()] + } + + static does_line_match(/**string*/ line_pattern, /**string*/ line_output) { + const [cmd_pattern, comment_pattern] = FuncTestCaseFifCodegen.split_line_to_cmd_and_comment(line_pattern) + const [cmd_output, comment_output] = FuncTestCaseFifCodegen.split_line_to_cmd_and_comment(line_output.trim()) + return cmd_pattern === cmd_output && (comment_pattern === null || comment_pattern === comment_output) } } + class FuncTestFile { constructor(/**string*/ func_filename, /**string*/ artifacts_folder) { + this.line_idx = 0 this.func_filename = func_filename this.artifacts_folder = artifacts_folder this.compilation_should_fail = false - /** @type {FuncTestCaseStderrIncludes[]} */ + /** @type {FuncTestCaseStderr[]} */ this.stderr_includes = [] /** @type {FuncTestCaseInputOutput[]} */ this.input_output = [] + /** @type {FuncTestCaseFifCodegen[]} */ + this.fif_codegen = [] } parse_input_from_func_file() { const lines = fs.readFileSync(this.func_filename, 'utf-8').split(/\r?\n/) - let i = 0 - while (i < lines.length) { - const line = lines[i] + this.line_idx = 0 + + while (this.line_idx < lines.length) { + const line = lines[this.line_idx] if (line.startsWith('TESTCASE')) { let s = line.split("|").map(p => p.trim()) if (s.length !== 4) @@ -160,9 +265,13 @@ class FuncTestFile { } else if (line.startsWith('@compilation_should_fail')) { this.compilation_should_fail = true } else if (line.startsWith('@stderr')) { - this.stderr_includes.push(new FuncTestCaseStderrIncludes(line.substring(7).trim())) + this.stderr_includes.push(new FuncTestCaseStderr(this.parse_string_value(lines), false)) + } else if (line.startsWith("@fif_codegen_avoid")) { + this.fif_codegen.push(new FuncTestCaseFifCodegen(this.parse_string_value(lines), true)) + } else if (line.startsWith("@fif_codegen")) { + this.fif_codegen.push(new FuncTestCaseFifCodegen(this.parse_string_value(lines), false)) } - i++ + this.line_idx++ } if (this.input_output.length === 0 && !this.compilation_should_fail) @@ -171,6 +280,31 @@ class FuncTestFile { throw new ParseInputError("TESTCASE present, but compilation_should_fail") } + /** @return {string[]} */ + parse_string_value(/**string[]*/ lines) { + // a tag must be followed by a space (single-line), e.g. '@stderr some text' + // or be a multi-line value, surrounded by """ + const line = lines[this.line_idx] + const pos_sp = line.indexOf(' ') + const is_multi_line = lines[this.line_idx + 1] === '"""' + const is_single_line = pos_sp !== -1 + if (!is_single_line && !is_multi_line) + throw new ParseInputError(`${line} value is empty (not followed by a string or a multiline """)`) + if (is_single_line && is_multi_line) + throw new ParseInputError(`${line.substring(0, pos_sp)} value is both single-line and followed by """`) + + if (is_single_line) + return [line.substring(pos_sp + 1).trim()] + + this.line_idx += 2 + let s_multiline = [] + while (this.line_idx < lines.length && lines[this.line_idx] !== '"""') { + s_multiline.push(lines[this.line_idx]) + this.line_idx = this.line_idx + 1 + } + return s_multiline + } + get_compiled_fif_filename() { return this.artifacts_folder + "/compiled.fif" } @@ -220,6 +354,12 @@ class FuncTestFile { for (let i = 0; i < stdout_lines.length; ++i) this.input_output[i].check(stdout_lines, i) + + if (this.fif_codegen.length) { + const fif_output = fs.readFileSync(this.get_compiled_fif_filename(), 'utf-8').split(/\r?\n/) + for (let fif_codegen of this.fif_codegen) + fif_codegen.check(fif_output) + } } } @@ -244,7 +384,7 @@ async function run_all_tests(/**string[]*/ tests) { print(` OK, ${testcase.input_output.length} cases`) } catch (e) { if (e instanceof ParseInputError) { - print(" Error parsing input:", e.message) + print(` Error parsing input (cur line #${testcase.line_idx + 1}):`, e.message) process.exit(2) } else if (e instanceof FuncCompilationFailedError) { print(" Error compiling func:", e.message) @@ -263,6 +403,11 @@ async function run_all_tests(/**string[]*/ tests) { print(e.output.trimEnd()) print(" Was compiled to:", testcase.get_compiled_fif_filename()) process.exit(2) + } else if (e instanceof CompareFifCodegenError) { + print(" Mismatch in fif codegen:", e.message) + print(" Was compiled to:", testcase.get_compiled_fif_filename()) + print(fs.readFileSync(testcase.get_compiled_fif_filename(), 'utf-8')) + process.exit(2) } throw e } diff --git a/crypto/func/auto-tests/run_tests.py b/crypto/func/auto-tests/run_tests.py index 990e50461..3e2cb8a67 100644 --- a/crypto/func/auto-tests/run_tests.py +++ b/crypto/func/auto-tests/run_tests.py @@ -84,6 +84,10 @@ def __init__(self, message: str, output: str): self.output = output +class CompareFifCodegenError(Exception): + pass + + class FuncTestCaseInputOutput: """ In positive tests, there are several testcases "input X should produce output Y". @@ -114,33 +118,131 @@ def check(self, stdout_lines: list[str], line_idx: int): raise CompareOutputError("error on case %d: expected '%s', found '%s'" % (line_idx + 1, self.expected_output, stdout_lines[line_idx]), "\n".join(stdout_lines)) -class FuncTestCaseStderrIncludes: +class FuncTestCaseStderr: """ @stderr checks, when compilation fails, that stderr (compilation error) is expected. + If it's multiline, all lines must be present in specified order. """ - def __init__(self, expected_substr: str): - self.expected_substr = expected_substr + def __init__(self, stderr_pattern: list[str], avoid: bool): + self.stderr_pattern = stderr_pattern + self.avoid = avoid def check(self, stderr: str): - if self.expected_substr not in stderr: - raise CompareOutputError("pattern '%s' not found in stderr" % self.expected_substr, stderr) + line_match = self.find_pattern_in_stderr(stderr.splitlines()) + if line_match == -1 and not self.avoid: + raise CompareOutputError("pattern not found in stderr:\n%s" % + "\n".join(map(lambda x: " " + x, self.stderr_pattern)), stderr) + elif line_match != -1 and self.avoid: + raise CompareOutputError("pattern found (line %d), but not expected to be:\n%s" % + (line_match + 1, "\n".join(map(lambda x: " " + x, self.stderr_pattern))), stderr) + + def find_pattern_in_stderr(self, stderr: list[str]) -> int: + for line_start in range(len(stderr)): + if self.try_match_pattern(0, stderr, line_start): + return line_start + return -1 + + def try_match_pattern(self, pattern_offset: int, stderr: list[str], offset: int) -> bool: + if pattern_offset >= len(self.stderr_pattern): + return True + if offset >= len(stderr): + return False + + line_pattern = self.stderr_pattern[pattern_offset] + line_output = stderr[offset] + return line_output.find(line_pattern) != -1 and self.try_match_pattern(pattern_offset + 1, stderr, offset + 1) + + +class FuncTestCaseFifCodegen: + """ + @fif_codegen checks that contents of compiled.fif matches the expected pattern. + @fif_codegen_avoid checks that is does not match the pattern. + The pattern is a multiline piece of fift code, optionally with "..." meaning "any lines here". + See tests/codegen_check_demo.fc of how it looks. + A notable thing about indentations (spaces at line starts): + Taking them into account will complicate the code without reasonable profit, + that's why we just trim every string. + And one more word about //comments. FunC inserts them into fift output. + If a line in the pattern contains a //comment, it's expected to be equal. + If a line does not, we just compare a command. + """ + + def __init__(self, fif_pattern: list[str], avoid: bool): + self.fif_pattern = [s.strip() for s in fif_pattern] + self.avoid = avoid + + def check(self, fif_output: list[str]): + # in case there are no comments at all (-S not set, or from wasm), drop them from fif_pattern + has_comments = any("//" in line and "generated from" not in line for line in fif_output) + if not has_comments: + self.fif_pattern = [FuncTestCaseFifCodegen.split_line_to_cmd_and_comment(s)[0] for s in self.fif_pattern] + self.fif_pattern = [s for s in self.fif_pattern if s != ""] + + line_match = self.find_pattern_in_fif_output(fif_output) + if line_match == -1 and not self.avoid: + raise CompareFifCodegenError("pattern not found:\n%s" % + "\n".join(map(lambda x: " " + x, self.fif_pattern))) + elif line_match != -1 and self.avoid: + raise CompareFifCodegenError("pattern found (line %d), but not expected to be:\n%s" % + (line_match + 1, "\n".join(map(lambda x: " " + x, self.fif_pattern)))) + + def find_pattern_in_fif_output(self, fif_output: list[str]) -> int: + for line_start in range(len(fif_output)): + if self.try_match_pattern(0, fif_output, line_start): + return line_start + return -1 + + def try_match_pattern(self, pattern_offset: int, fif_output: list[str], offset: int) -> bool: + if pattern_offset >= len(self.fif_pattern): + return True + if offset >= len(fif_output): + return False + line_pattern = self.fif_pattern[pattern_offset] + line_output = fif_output[offset] + + if line_pattern != "...": + if not FuncTestCaseFifCodegen.does_line_match(line_pattern, line_output): + return False + return self.try_match_pattern(pattern_offset + 1, fif_output, offset + 1) + while offset < len(fif_output): + if self.try_match_pattern(pattern_offset + 1, fif_output, offset): + return True + offset = offset + 1 + return False + + @staticmethod + def split_line_to_cmd_and_comment(trimmed_line: str) -> tuple[str, str | None]: + pos = trimmed_line.find("//") + if pos == -1: + return trimmed_line, None + else: + return trimmed_line[:pos].rstrip(), trimmed_line[pos + 2:].lstrip() + + @staticmethod + def does_line_match(line_pattern: str, line_output: str) -> bool: + cmd_pattern, comment_pattern = FuncTestCaseFifCodegen.split_line_to_cmd_and_comment(line_pattern) + cmd_output, comment_output = FuncTestCaseFifCodegen.split_line_to_cmd_and_comment(line_output.strip()) + return cmd_pattern == cmd_output and (comment_pattern is None or comment_pattern == comment_output) class FuncTestFile: def __init__(self, func_filename: str, artifacts_folder: str): + self.line_idx = 0 self.func_filename = func_filename self.artifacts_folder = artifacts_folder self.compilation_should_fail = False - self.stderr_includes: list[FuncTestCaseStderrIncludes] = [] + self.stderr_includes: list[FuncTestCaseStderr] = [] self.input_output: list[FuncTestCaseInputOutput] = [] + self.fif_codegen: list[FuncTestCaseFifCodegen] = [] def parse_input_from_func_file(self): with open(self.func_filename, "r") as fd: lines = fd.read().splitlines() - i = 0 - while i < len(lines): - line = lines[i] + self.line_idx = 0 + + while self.line_idx < len(lines): + line = lines[self.line_idx] if line.startswith("TESTCASE"): s = [x.strip() for x in line.split("|")] if len(s) != 4: @@ -149,18 +251,43 @@ def parse_input_from_func_file(self): elif line.startswith("@compilation_should_fail"): self.compilation_should_fail = True elif line.startswith("@stderr"): - self.stderr_includes.append(FuncTestCaseStderrIncludes(line[7:].strip())) - i = i + 1 + self.stderr_includes.append(FuncTestCaseStderr(self.parse_string_value(lines), False)) + elif line.startswith("@fif_codegen_avoid"): + self.fif_codegen.append(FuncTestCaseFifCodegen(self.parse_string_value(lines), True)) + elif line.startswith("@fif_codegen"): + self.fif_codegen.append(FuncTestCaseFifCodegen(self.parse_string_value(lines), False)) + self.line_idx = self.line_idx + 1 if len(self.input_output) == 0 and not self.compilation_should_fail: raise ParseInputError("no TESTCASE present") if len(self.input_output) != 0 and self.compilation_should_fail: raise ParseInputError("TESTCASE present, but compilation_should_fail") + def parse_string_value(self, lines: list[str]) -> list[str]: + # a tag must be followed by a space (single-line), e.g. '@stderr some text' + # or be a multi-line value, surrounded by """ + line = lines[self.line_idx] + pos_sp = line.find(' ') + is_multi_line = lines[self.line_idx + 1] == '"""' + is_single_line = pos_sp != -1 + if not is_single_line and not is_multi_line: + raise ParseInputError('%s value is empty (not followed by a string or a multiline """)' % line) + if is_single_line and is_multi_line: + raise ParseInputError('%s value is both single-line and followed by """' % line[:pos_sp]) + + if is_single_line: + return [line[pos_sp + 1:].strip()] + + self.line_idx += 2 + s_multiline = [] + while self.line_idx < len(lines) and lines[self.line_idx] != '"""': + s_multiline.append(lines[self.line_idx]) + self.line_idx = self.line_idx + 1 + return s_multiline + def get_compiled_fif_filename(self): return self.artifacts_folder + "/compiled.fif" - @property def get_runner_fif_filename(self): return self.artifacts_folder + "/runner.fif" @@ -181,12 +308,12 @@ def run_and_check(self): if exit_code != 0 and not self.compilation_should_fail: raise FuncCompilationFailedError("func exit_code = %d" % exit_code, stderr) - with open(self.get_runner_fif_filename, "w") as f: + with open(self.get_runner_fif_filename(), "w") as f: f.write("\"%s\" include 0) { + t = s; + z -= 1; + } + return ~ t; +} + +{- + method_id | in | out +TESTCASE | 0 | 1 | -2 +TESTCASE | 0 | 5 | -6 +TESTCASE | 101 | | 0 + +Below, I just give examples of @fif_codegen tag: +* a pattern can be single-line (after the tag), or multi-line, surrounded with """ +* there may be multiple @fif_codegen, they all will be checked +* identation (spaces) is not checked intentionally +* "..." means any number of any lines +* lines not divided with "..." are expected to be consecutive in fif output +* //comments can be omitted, but if present, they are also expected to be equal +* there is also a tag @fif_codegen_avoid to check a pattern does not occur + +@fif_codegen +""" +main PROC:<{ + // s + 17 PUSHINT // s _3=17 + OVER // s z=17 t + WHILE:<{ + ... + }>DO<{ // s z t + ... + s1 s(-1) PUXC // s t z + ... + 2 1 BLKDROP2 + ... +}> +""" + +@fif_codegen +""" +main PROC:<{ + ... + WHILE:<{ + ... + }>DO<{ + ... + }> + }END>c +""" + +@fif_codegen +""" + OVER + 0 GTINT // s z t _5 +""" + +@fif_codegen +""" + "Asm.fif" include + ... + PROGRAM{ + ... + }END>c +""" + +@fif_codegen +""" +test1 PROC:<{ +// +FALSE +}> +""" + +@fif_codegen NOT // _8 +@fif_codegen main PROC:<{ + +@fif_codegen_avoid PROCINLINE +@fif_codegen_avoid END c +@fif_codegen_avoid +""" +multiline +can also be +""" +-} From 18050a7591cb03786d5df8533e9578871a876b8b Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Fri, 26 Apr 2024 14:27:16 +0300 Subject: [PATCH 05/30] [FunC] Auto-inline functions-wrappers `T f(...args) { return anotherF(...args); }` This will allow to easily implement camelCase wrappers aside stdlib, even without changing hashes of existing contracts. Also, stdlib renamings could be easily performed in the same manner, even with arguments reordered. --- crypto/func/asmops.cpp | 3 + crypto/func/auto-tests/legacy_tests.jsonl | 7 +- crypto/func/auto-tests/tests/camel1.fc | 239 ++++++++++++++++++++++ crypto/func/auto-tests/tests/camel2.fc | 208 +++++++++++++++++++ crypto/func/auto-tests/tests/camel3.fc | 104 ++++++++++ crypto/func/auto-tests/tests/camel4.fc | 130 ++++++++++++ crypto/func/codegen.cpp | 36 ++-- crypto/func/func.cpp | 54 ++++- crypto/func/func.h | 39 ++-- crypto/func/gen-abscode.cpp | 36 +++- crypto/func/parse-func.cpp | 100 +++++++-- crypto/func/unify-types.cpp | 33 +++ 12 files changed, 929 insertions(+), 60 deletions(-) create mode 100644 crypto/func/auto-tests/tests/camel1.fc create mode 100644 crypto/func/auto-tests/tests/camel2.fc create mode 100644 crypto/func/auto-tests/tests/camel3.fc create mode 100644 crypto/func/auto-tests/tests/camel4.fc diff --git a/crypto/func/asmops.cpp b/crypto/func/asmops.cpp index 71ee58f68..960cacdeb 100644 --- a/crypto/func/asmops.cpp +++ b/crypto/func/asmops.cpp @@ -320,6 +320,9 @@ void AsmOpList::show_var_ext(std::ostream& os, std::pair os << '_' << i; } else { var_names_->at(i).show(os, 2); + // if (!var_names_->at(i).v_type->is_int()) { + // os << '<'; var_names_->at(i).v_type->print(os); os << '>'; + // } } if ((unsigned)j < constants_.size() && constants_[j].not_null()) { os << '=' << constants_[j]; diff --git a/crypto/func/auto-tests/legacy_tests.jsonl b/crypto/func/auto-tests/legacy_tests.jsonl index 15cd72754..0075bf830 100644 --- a/crypto/func/auto-tests/legacy_tests.jsonl +++ b/crypto/func/auto-tests/legacy_tests.jsonl @@ -31,7 +31,8 @@ ["whales-nominators/nominators.fc", 8941364499854379927692172316865293429893094891593442801401542636695127885153] -["tact-examples/treasure_Treasure.code.fc", 13962538639825790677138656603323869918938565499584297120566680287245364723897] -["tact-examples/jetton_SampleJetton.code.fc", 94076762218493729104783735200107713211245710256802265203823917715299139499110] -["tact-examples/jetton_JettonDefaultWallet.code.fc", 29421313492520031238091587108198906058157443241743283101866538036369069620563] +// (April 2024) tact hashes changed, because '__tact_address_eq()' is now inlined as a wrapper +["tact-examples/treasure_Treasure.code.fc", 74579212939836529446778705921340099196942507859825095056546203678047252921894] +["tact-examples/jetton_SampleJetton.code.fc", 90109697379313597998231209537203822165325184678797680193687781490465875320451] +["tact-examples/jetton_JettonDefaultWallet.code.fc", 40972091374757565863193840427121230466303309310521439431197914284004190565629] ["tact-examples/maps_MapTestContract.code.fc", 22556550222249123835909180266811414538971143565993192846012583552876721649744] diff --git a/crypto/func/auto-tests/tests/camel1.fc b/crypto/func/auto-tests/tests/camel1.fc new file mode 100644 index 000000000..1146f6977 --- /dev/null +++ b/crypto/func/auto-tests/tests/camel1.fc @@ -0,0 +1,239 @@ +;; Here we test "functions that just wrap other functions" (camelCase in particular): +;; > builder beginCell() { return begin_cell(); } +;; Such functions, when called, are explicitly inlined during code generation (even without `inline` modifier). +;; It means, that `beginCell()` is replaced to `begin_cell()` (and effectively to `NEWC`). +;; Moreover, body of `beginCell` is NOT codegenerated at all. +;; Hence, we can write camelCase wrappers (as well as more intelligible namings around stdlib functions) +;; without affecting performance and even bytecode hashes. +;; This works with ~functions also. And even works with wrappers of wrappers. +;; Moreover, such wrappers can reorder input parameters, see a separate test camel2.fc. + +builder begin_cell() asm "NEWC"; +cell end_cell(builder b) asm "ENDC"; +builder store_ref(builder b, cell c) asm(c b) "STREF"; +slice begin_parse(cell c) asm "CTOS"; +slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; + +builder beginCell() { return begin_cell(); } +cell endCell(builder b) { return end_cell(b); } +builder storeRef(builder b, cell c) { return store_ref(b, c); } +builder storeUint(builder b, int i, int bw) { return store_uint(b, i, bw); } + +;; 'inline' is not needed actually, but if it exists, it's just ignored +slice beginParse(cell c) inline { return begin_parse(c); } +slice skipBits(slice s, int len) inline { return skip_bits(s, len); } +(slice, ()) ~skipBits(slice s, int len) inline { return ~skip_bits(s, len); } +(slice, int) ~loadUint(slice s, int len) inline { return load_uint(s, len); } + +(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; +(int, int, int) computeDataSize(cell c, int maxCells) impure { return compute_data_size(c, maxCells); } + +cell new_dict() asm "NEWDICT"; +cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; +(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; + +cell dict::new() { return new_dict(); } +cell dict::iset(cell dict, int keyLen, int index, slice value) { return idict_set(dict, keyLen, index, value); } +(cell, ()) ~dict::iset(cell dict, int keyLen, int index, slice value) { return ~idict_set(dict, keyLen, index, value); } +(slice, int) dict::tryIGet(cell dict, int keyLen, int index) { return idict_get?(dict, keyLen, index); } +(int, slice, int) dict::tryIGetMin(cell dict, int keyLen) { return idict_get_min?(dict, keyLen); } + +tuple empty_tuple() asm "NIL"; +forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; +forall X -> X null() asm "PUSHNULL"; + +tuple emptyTuple() { return empty_tuple(); } +tuple emptyTuple1() { return emptyTuple(); } +tuple emptyTuple11() { return emptyTuple1(); } +forall X -> tuple tuplePush(tuple t, X value) { return tpush(t, value); } +forall X -> (tuple, ()) ~tuplePush(tuple t, X value) { return ~tpush(t, value); } +forall X -> X tupleAt(tuple t, int index) { return at(t, index); } +forall X1, Y2, Z3 -> Y2 tripleSecond([X1, Y2, Z3] p) { return triple_second(p); } +forall X -> X nullValue() asm "PUSHNULL"; + +() throwIf(int excNo, int condition) impure { return throw_if(excNo, condition); } + +tuple initial1(tuple x) { return x; } +_ initial2(x) { return initial1(x); } + +int add(int x, int y) { return x + y; } ;; this is also a wrapper, as its body is _+_(x,y) + +() fake1(int a, int b, int c) impure asm(a b c) "DROP DROP DROP"; +() fake2(int a, int b, int c) impure asm(b c a) "DROP DROP DROP"; +() fake3(int a, int b, int c) impure asm(c a b) "DROP DROP DROP"; +() fake4(int a, int b, int c) impure asm(c b a) "DROP DROP DROP"; + +() fake1Wrapper(int a, int b, int c) { return fake1(a, b, c); } +() fake2Wrapper(int a, int b, int c) { return fake2(a, b, c); } +() fake3Wrapper(int a, int b, int c) { return fake3(a, b, c); } +() fake4Wrapper(int a, int b, int c) { return fake4(a, b, c); } + +[int, int, int] test1() method_id(101) { + int x = 1; + int y = 1; + cell to_be_ref = beginCell().endCell(); + builder in_c = beginCell().storeUint(123, 8); + in_c = storeRef(in_c, to_be_ref); + var (a, b, c) = computeDataSize(in_c.endCell(), 10); + throwIf(101, b != 8); + throwIf(101, c != 1); + return [a, add(b, x), add(c, y)]; +} + +[[int, int, int], int, int, int] test2() method_id(102) { + cell dict = dict::new(); + dict = dict::iset(dict, 32, 456, beginCell().storeUint(4560, 32).endCell().beginParse()); + dict.dict::iset(32, 789, beginCell().storeUint(7890, 32).endCell().beginParse()); + dict~dict::iset(32, 123, beginCell().storeUint(0, 64).storeUint(1230, 32).storeUint(1231, 32).storeUint(1232, 32).endCell().beginParse()); + + var (mink, minv, _) = dict::tryIGetMin(dict, 32); + ;; skip 64 bits + minv~skipBits(16); + minv = minv.skipBits(16); + minv.skipBits(16000); ;; does nothing + (minv, _) = ~skipBits(minv, 16); + skipBits(minv, 16000); ;; does nothing + minv~skipBits(16); + ;; load 3*32 + var minv1 = minv~loadUint(32); + var minv2 = minv~loadUint(32); + var minv3 = minv~loadUint(32); + + var (_, found123) = dict::tryIGet(dict, 32, 123); + var (_, found456) = dict::tryIGet(dict, 32, 456); + var (_, found789) = dict::tryIGet(dict, 32, 789); + return [[minv1, minv2, minv3], found123, found456, found789]; +} + +tuple test3() method_id(103) { + tuple with34 = initial2(emptyTuple1()); + with34~tuplePush(34); + + tuple t = emptyTuple11(); + t = tuplePush(t, 12); + tuplePush(t, emptyTuple11()); ;; does nothing + t~tuplePush(emptyTuple1()); + t~tuplePush(with34.tupleAt(0)); + t.tuplePush("123"s); ;; does nothing + + [cell, int, cell] tri = [nullValue(), 90 + 1, null()]; + int f = tripleSecond(tri); + (t, _) = ~tuplePush(t, f); + + return t; +} + +(int) test4(int a, int b, int c) method_id(104) { + fake1Wrapper(a, b, c); + fake2Wrapper(a, b, c); + fake3Wrapper(a, b, c); + fake4Wrapper(a, b, c); + return 10; +} + +int main() { + return 0; +} + +{- + method_id | in | out +TESTCASE | 101 | | [ 2 9 2 ] +TESTCASE | 102 | | [ [ 1230 1231 1232 ] -1 -1 0 ] +TESTCASE | 103 | | [ 12 [] 34 91 ] + +@fif_codegen +""" + test1 PROC:<{ + // + NEWC // _5 + ENDC // to_be_ref + 123 PUSHINT // to_be_ref _8=123 + NEWC // to_be_ref _8=123 _9 + 8 STU // to_be_ref in_c + STREF // in_c + ENDC // _16 + 10 PUSHINT // _16 _17=10 + CDATASIZE // a b c + OVER // a b c b + 8 NEQINT // a b c _21 + 101 THROWIF + DUP // a b c c + 1 NEQINT // a b c _25 + 101 THROWIF + SWAP // a c b + INC // a c _28 + SWAP // a _28 c + INC // a _28 _29 + TRIPLE // _27 + }> +""" + +@fif_codegen +""" + test2 PROC:<{ + ... + 16 PUSHINT // dict minv _45=16 + SDSKIPFIRST // dict minv + 16 PUSHINT // dict minv _47=16 + SDSKIPFIRST // dict minv + 16 PUSHINT // dict minv _52=16 + SDSKIPFIRST // dict minv + 16 PUSHINT // dict minv _57=16 + SDSKIPFIRST // dict minv + ... + 32 PUSHINT // dict minv1 minv2 minv3 found123 _78=456 dict _79=32 + DICTIGET + NULLSWAPIFNOT // dict minv1 minv2 minv3 found123 _99 _100 + 789 PUSHINT + s2 POP + s0 s6 XCHG + 32 PUSHINT // found456 minv1 minv2 minv3 found123 _83=789 dict _84=32 + ... + 4 TUPLE // _86 + }> +""" + +@fif_codegen +""" + test3 PROC:<{ + // + NIL // _1 + initial1 CALLDICT // with34 + ... + TRIPLE // t tri + SECOND // t f + TPUSH // t + }> +""" + +@fif_codegen +""" + test4 PROC:<{ + // a b c + s2 s1 s0 PUSH3 // a b c a b c + DROP DROP DROP + s1 s0 s2 PUSH3 // a b c b c a + DROP DROP DROP + s0 s2 s1 PUSH3 // a b c c a b + DROP DROP DROP + s0 s2 XCHG // c b a + DROP DROP DROP + 10 PUSHINT // _7=10 + }> +""" + +@fif_codegen_avoid DECLPROC beginCell +@fif_codegen_avoid DECLPROC storeUint +@fif_codegen_avoid DECLPROC storeRef +@fif_codegen_avoid DECLPROC computeDataSize +@fif_codegen_avoid DECLPROC tryIdictGet +@fif_codegen_avoid DECLPROC emptyTuple +@fif_codegen_avoid DECLPROC storeUint1 +@fif_codegen_avoid DECLPROC initial2 +@fif_codegen_avoid DECLPROC add +-} diff --git a/crypto/func/auto-tests/tests/camel2.fc b/crypto/func/auto-tests/tests/camel2.fc new file mode 100644 index 000000000..32c32e088 --- /dev/null +++ b/crypto/func/auto-tests/tests/camel2.fc @@ -0,0 +1,208 @@ +;; Here we also test "functions that just wrap other functions" like in camel1.fc, +;; but when they reorder arguments, e.g. +;; > T f(x,y) { return anotherF(y,x); } +;; This also works, even for wrappers of wrappers, even if anotherF is asm(with reorder). +;; But swapping arguments may sometimes lead to bytecode changes (see test2), +;; both with compute-asm-ltr and without it. + +#pragma compute-asm-ltr; + +builder begin_cell() asm "NEWC"; +cell end_cell(builder b) asm "ENDC"; +slice begin_parse(cell c) asm "CTOS"; +builder store_ref(builder b, cell c) asm(c b) "STREF"; + +builder beginCell() { return begin_cell(); } +cell endCell(builder b) { return end_cell(b); } +builder storeRef1(builder b, cell c) { return store_ref(b, c); } +builder storeRef2(cell c, builder b) { return store_ref(b, c); } +builder storeUint1(builder b, int x, int bw) { return store_uint(b, x, bw); } +builder storeUint2(builder b, int bw, int x) { return store_uint(b, x, bw); } + +(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; +(int, int, int) computeDataSize1(cell c, int maxCells) impure { return compute_data_size(c, maxCells); } +(int, int, int) computeDataSize2(int maxCells, cell c) impure { return compute_data_size(c, maxCells); } + +() throwIf(int condition, int excNo) impure { return throw_if(excNo, condition); } + +() fake(int a, int b, int c) impure asm "DROP DROP DROP"; +() fake2(int b, int c, int a) { return fake(a,b,c); } +() fake3(int c, int a, int b) { return fake(a,b,c); } +() fake4(int c, int b, int a) { return fake(a,b,c); } + +(int, int, int) test1() method_id(101) { + int x = 1; + int y = 1; + cell to_be_ref = beginCell().endCell(); + builder in_c = beginCell().storeUint1(123, 8); + in_c = storeRef1(in_c, to_be_ref); + var (a, b, c) = computeDataSize1(in_c.endCell(), 10); + throwIf(0, 101); + return (a, b + x, c + y); +} + +(int, int, int) test2() method_id(102) { + int x = 1; + int y = 1; + cell to_be_ref = beginCell().endCell(); + builder in_c = beginCell().storeUint2(8, 123); + in_c = storeRef2(to_be_ref, in_c); + var (a, b, c) = computeDataSize2(10, in_c.endCell()); + return (a, b + x, c + y); +} + +(int, int, int) test3() method_id(103) { + int x = 1; + int y = 1; + cell to_be_ref = begin_cell().end_cell(); + builder in_c = begin_cell().store_uint(123, 8); + in_c = store_ref(in_c, to_be_ref); + var (a, b, c) = compute_data_size(in_c.end_cell(), 10); + return (a, b + x, c + y); +} + +builder beginCell1() { return begin_cell(); } +builder beginCell11() { return beginCell1(); } +builder beginCell111() { return beginCell11(); } + +cell endCell1(builder b) { return end_cell(b); } +cell endCell11(builder b) { return endCell1(b); } + +slice beginParse1(cell c) { return begin_parse(c); } +slice beginParse11(cell c) { return beginParse1(c); } + +builder storeInt1(builder b, int bw, int x) { return store_int(b, x, bw); } +builder storeInt11(int bw, int x, builder b) { return storeInt1(b, bw, x); } +builder storeInt111(builder b, int x, int bw) { return storeInt11(bw, x, b); } + +slice test4() method_id(104) { + builder b = beginCell111(); + b = storeInt11(32, 1, b); + b = storeInt111(b, 2, 32).storeInt111(3, 32); + return b.endCell11().beginParse11(); +} + +(int) test5(int a, int b, int c) method_id(105) { + fake(a, b, c); + fake2(b, c, a); + fake3(c, a, b); + fake4(c, b, a); + return a; +} + +() main() { + throw(0); +} + +{- + method_id | in | out +TESTCASE | 101 | | 2 9 2 +TESTCASE | 102 | | 2 9 2 +TESTCASE | 103 | | 2 9 2 +TESTCASE | 104 | | CS{Cell{0018000000010000000200000003} bits: 0..96; refs: 0..0} + +test1 and test3 fif code is absolutely identical, test2 (due to reorder) is a bit different: + +@fif_codegen +""" + test1 PROC:<{ + // + NEWC // _5 + ENDC // to_be_ref + NEWC // to_be_ref _8 + 123 PUSHINT // to_be_ref _8 _9=123 + SWAP // to_be_ref _9=123 _8 + 8 STU // to_be_ref in_c + STREF // in_c + ENDC // _16 + 10 PUSHINT // _16 _17=10 + CDATASIZE // a b c + SWAP // a c b + INC // a c _22 + SWAP // a _22 c + INC // a _22 _23 + }> +""" + +@fif_codegen +""" + test2 PROC:<{ + // + NEWC // _5 + ENDC // to_be_ref + NEWC // to_be_ref _8 + 123 PUSHINT // to_be_ref _8 _10=123 + SWAP // to_be_ref _10=123 _8 + 8 STU // to_be_ref in_c + STREF // in_c + 10 PUSHINT + SWAP + ENDC + SWAP + CDATASIZE // a b c + SWAP // a c b + INC // a c _19 + SWAP // a _19 c + INC // a _19 _20 + }> +""" + +@fif_codegen +""" + test3 PROC:<{ + // + NEWC // _5 + ENDC // to_be_ref + NEWC // to_be_ref _8 + 123 PUSHINT // to_be_ref _8 _9=123 + SWAP // to_be_ref _9=123 _8 + 8 STU // to_be_ref in_c + STREF // in_c + ENDC // _16 + 10 PUSHINT // _16 _17=10 + CDATASIZE // a b c + SWAP // a c b + INC // a c _19 + SWAP // a _19 c + INC // a _19 _20 + }> +""" + +@fif_codegen +""" + test4 PROC:<{ + // + NEWC // b + 1 PUSHINT // b _3=1 + SWAP // _3=1 b + 32 STI // b + 2 PUSHINT + SWAP // _5=2 b + 32 STI + 3 PUSHINT + SWAP + 32 STI // b + ENDC // _11 + CTOS // _12 + }> +""" + +@fif_codegen +""" + test5 PROC:<{ + // a b c + s2 s1 s0 PUSH3 // a b c a b c + DROP DROP DROP + s2 s1 s0 PUSH3 // a b c a b c + DROP DROP DROP + s2 s1 s0 PUSH3 // a b c a b c + DROP DROP DROP + s2 PUSH + -ROT // a a b c + DROP DROP DROP + }> +""" + +@fif_codegen_avoid storeUint1 +@fif_codegen_avoid storeUint2 +-} diff --git a/crypto/func/auto-tests/tests/camel3.fc b/crypto/func/auto-tests/tests/camel3.fc new file mode 100644 index 000000000..4ae2fc413 --- /dev/null +++ b/crypto/func/auto-tests/tests/camel3.fc @@ -0,0 +1,104 @@ +;; Here we test that if you declare a wrapper like +;; > builder beginCell() { return begin_cell(); } +;; but use it NOT only as a direct call, BUT as a 1-st class function +;; (save to a variable, return from a function, etc.) +;; it also works, since a function becomes codegenerated (though direct calls are expectedly inlined). + +builder begin_cell() asm "NEWC"; +cell end_cell(builder b) asm "ENDC"; +builder store_ref(builder b, cell c) asm(c b) "STREF"; + +builder beginCell() { return begin_cell(); } +cell endCell(builder b) { return end_cell(b); } +builder storeRef(builder b, cell c) { return store_ref(b, c); } +builder storeUint3(int i, int bw, builder b) { return store_uint(b, i, bw); } + +(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; +(int, int, int) computeDataSize2(int maxCells, cell c) impure { return compute_data_size(c, maxCells); } + +tuple empty_tuple() asm "NIL"; +forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; +forall X -> X first(tuple t) asm "FIRST"; + +tuple emptyTuple() { return empty_tuple(); } +forall X -> tuple tuplePush(tuple t, X value) { return tpush(t, value); } +forall X -> (tuple, ()) ~tuplePush(tuple t, X value) { return ~tpush(t, value); } +forall X -> X tupleGetFirst(tuple t) { return first(t); } + + +(var, var) getBeginEnd() inline { + return (beginCell, endCell); +} + +(builder) begAndStore(beg, store, int x) { + return store(x, 8, beg()); +} + +(int, int, int) test1() { + var (_, computer) = (0, computeDataSize2); + var (beg, end) = getBeginEnd(); + + tuple t = emptyTuple(); + t~tuplePush(storeRef); + var refStorer = tupleGetFirst(t); + + int x = 1; + int y = 1; + cell to_be_ref = beginCell().endCell(); + builder in_c = begAndStore(beg, storeUint3, 123); + in_c = refStorer(in_c, to_be_ref); + var (a, b, c) = computer(10, end(in_c)); + return (a, b + x, c + y); +} + +(int, int, int) main() { + return test1(); +} + +{- + method_id | in | out +TESTCASE | 0 | | 2 9 2 + +@fif_codegen DECLPROC beginCell +@fif_codegen DECLPROC computeDataSize2 + +@fif_codegen +""" + storeUint3 PROC:<{ + // i bw b + SWAP // i b bw + STUX // _3 + }> +""" + +@fif_codegen +""" + storeRef PROC:<{ + // b c + SWAP // c b + STREF // _2 + }> +""" + +@fif_codegen +""" + CONT:<{ + computeDataSize2 CALLDICT + }> // computer + getBeginEnd INLINECALLDICT // computer beg end + NIL // computer beg end t + ... + NEWC // computer beg end refStorer _19 + ENDC // computer beg end refStorer to_be_ref + ... + CONT:<{ + storeUint3 CALLDICT + }> + ... + begAndStore CALLDICT // computer to_be_ref end refStorer in_c +""" + +@fif_codegen_avoid emptyTuple +@fif_codegen_avoid tuplePush +-} diff --git a/crypto/func/auto-tests/tests/camel4.fc b/crypto/func/auto-tests/tests/camel4.fc new file mode 100644 index 000000000..1f014dc01 --- /dev/null +++ b/crypto/func/auto-tests/tests/camel4.fc @@ -0,0 +1,130 @@ +;; Here we test that a just-return function is not a valid wrapper, it will not be inlined. +;; (doesn't use all arguments, has different pureness, has method_id, etc.) + +builder begin_cell() asm "NEWC"; +cell end_cell(builder b) asm "ENDC"; +slice begin_parse(cell c) asm "CTOS"; +() set_data(cell c) impure asm "c4 POP"; +cell get_data() asm "c4 PUSH"; +tuple empty_tuple() asm "NIL"; +forall X -> (tuple, ()) tpush(tuple t, X x) asm "TPUSH"; + +builder storeUint(builder b, int x, int unused) { return store_uint(b, x, x); } +() throwIf(int excNo, int cond) impure { throw_if(excNo, cond); } +() throwIf2(int excNo, int cond) { return throw_if(excNo, cond); } + +_ initial1(x) { return x; } +_ initial2(x) { return initial1(x); } + +tuple asm_func_4(int a, (int, (int, int)) b, int c) asm (b a c -> 0) "5 TUPLE"; +_ asmFunc4(int a, (int, (int, int)) b, int c) { return asm_func_4(a, b, c); } + +int postpone_elections() { + return false; +} + +(int) setAndGetData(int ret) { + cell c = begin_cell().store_uint(ret, 8).end_cell(); + set_data(c); + slice s = get_data().begin_parse(); + throwIf(101, 0); + var unused = throwIf2(101, 0); + return s~load_uint(8); +} + +int setAndGetDataWrapper(int ret) { + return setAndGetData(ret); +} + +int test1() method_id(101) { + cell c = begin_cell().storeUint(32, 10000000).end_cell(); + slice s = c.begin_parse(); + return s~load_uint(32); +} + +int test2(int ret) method_id { + return setAndGetDataWrapper(ret); +} + +int test3() method_id(103) { + return initial2(10); +} + +global tuple t; + +int foo(int x) { + t~tpush(x); + return x * 10; +} + +(tuple, tuple) test4() method_id(104) { + t = empty_tuple(); + tuple t2 = asmFunc4(foo(11), (foo(22), (foo(33), foo(44))), foo(55)); + return (t, t2); +} + +int test5() method_id(105) { + if (1) { + return postpone_elections(); + } + return 123; +} + +int main(int ret) { + return setAndGetDataWrapper(ret); +} + +int recv_external(int ret) { + return setAndGetData(ret); +} + +{- + method_id | in | out +TESTCASE | 101 | | 32 +TESTCASE | 103 | | 10 +TESTCASE | 104 | | [ 11 22 33 44 55 ] [ 220 330 440 110 550 ] +TESTCASE | 105 | | 0 +TESTCASE | 74435 | 99 | 99 +TESTCASE | 0 | 98 | 98 +TESTCASE | -1 | 97 | 97 + +@fif_codegen DECLPROC storeUint +@fif_codegen DECLPROC throwIf +@fif_codegen DECLPROC throwIf2 +@fif_codegen DECLPROC postpone_elections +@fif_codegen 74435 DECLMETHOD test2 + +@fif_codegen +""" + test3 PROC:<{ + // + 10 PUSHINT // _0=10 + initial2 CALLDICT // _1 + }> +""" + +@fif_codegen +""" + test2 PROC:<{ + // ret + setAndGetData CALLDICT // _1 + }> +""" + +@fif_codegen +""" + 11 PUSHINT + foo CALLDICT + 22 PUSHINT + foo CALLDICT + 33 PUSHINT + foo CALLDICT + 44 PUSHINT + foo CALLDICT + 55 PUSHINT + foo CALLDICT + asmFunc4 CALLDICT // t2 +""" + +@fif_codegen_avoid setAndGetDataWrapper +-} diff --git a/crypto/func/codegen.cpp b/crypto/func/codegen.cpp index de45c8418..610bd2a95 100644 --- a/crypto/func/codegen.cpp +++ b/crypto/func/codegen.cpp @@ -439,6 +439,7 @@ bool Op::generate_code_step(Stack& stack) { if (disabled()) { return true; } + // fun_ref can be nullptr for Op::_CallInd (invoke a variable, not a function) SymValFunc* func = (fun_ref ? dynamic_cast(fun_ref->value) : nullptr); auto arg_order = (func ? func->get_arg_order() : nullptr); auto ret_order = (func ? func->get_ret_order() : nullptr); @@ -488,27 +489,24 @@ bool Op::generate_code_step(Stack& stack) { }; if (cl == _CallInd) { exec_callxargs((int)right.size() - 1, (int)left.size()); + } else if (auto asm_fv = dynamic_cast(fun_ref->value)) { + std::vector res; + res.reserve(left.size()); + for (var_idx_t i : left) { + res.emplace_back(i); + } + asm_fv->compile(stack.o, res, args, where); // compile res := f (args) } else { - auto func = dynamic_cast(fun_ref->value); - if (func) { - std::vector res; - res.reserve(left.size()); - for (var_idx_t i : left) { - res.emplace_back(i); - } - func->compile(stack.o, res, args, where); // compile res := f (args) + auto fv = dynamic_cast(fun_ref->value); + // todo can be fv == nullptr? + std::string name = sym::symbols.get_name(fun_ref->sym_idx); + if (fv && (fv->is_inline() || fv->is_inline_ref())) { + stack.o << AsmOp::Custom(name + " INLINECALLDICT", (int)right.size(), (int)left.size()); + } else if (fv && fv->code && fv->code->require_callxargs) { + stack.o << AsmOp::Custom(name + (" PREPAREDICT"), 0, 2); + exec_callxargs((int)right.size() + 1, (int)left.size()); } else { - auto fv = dynamic_cast(fun_ref->value); - std::string name = sym::symbols.get_name(fun_ref->sym_idx); - bool is_inline = (fv && (fv->flags & 3)); - if (is_inline) { - stack.o << AsmOp::Custom(name + " INLINECALLDICT", (int)right.size(), (int)left.size()); - } else if (fv && fv->code && fv->code->require_callxargs) { - stack.o << AsmOp::Custom(name + (" PREPAREDICT"), 0, 2); - exec_callxargs((int)right.size() + 1, (int)left.size()); - } else { - stack.o << AsmOp::Custom(name + " CALLDICT", (int)right.size(), (int)left.size()); - } + stack.o << AsmOp::Custom(name + " CALLDICT", (int)right.size(), (int)left.size()); } } stack.s.resize(k); diff --git a/crypto/func/func.cpp b/crypto/func/func.cpp index 39648c05a..42cea2519 100644 --- a/crypto/func/func.cpp +++ b/crypto/func/func.cpp @@ -43,6 +43,35 @@ GlobalPragma pragma_compute_asm_ltr{"compute-asm-ltr"}; std::string generated_from, boc_output_filename; ReadCallback::Callback read_callback; +// returns argument type of a function +// note, that when a function has multiple arguments, its arg type is a tensor (no arguments — an empty tensor) +// in other words, `f(int a, int b)` and `f((int,int) ab)` is the same when we speak about types +const TypeExpr *SymValFunc::get_arg_type() const { + if (!sym_type) + return nullptr; + + func_assert(sym_type->constr == TypeExpr::te_Map || sym_type->constr == TypeExpr::te_ForAll); + const TypeExpr *te_map = sym_type->constr == TypeExpr::te_ForAll ? sym_type->args[0] : sym_type; + const TypeExpr *arg_type = te_map->args[0]; + + while (arg_type->constr == TypeExpr::te_Indirect) { + arg_type = arg_type->args[0]; + } + return arg_type; +} + + +bool SymValCodeFunc::does_need_codegen() const { + if (flags & flagUsedAsNonCall) { + return true; + } + // when a function f() is just `return anotherF(...args)`, it doesn't need to be codegenerated at all, + // since all its usages are inlined + return !is_just_wrapper_for_another_f(); + // in the future, we may want to implement a true AST inlining for `inline` functions also + // in the future, unused functions may also be excluded from codegen +} + td::Result fs_read_callback(ReadCallback::Kind kind, const char* query) { switch (kind) { case ReadCallback::Kind::ReadFile: { @@ -124,12 +153,10 @@ void generate_output_func(SymDef* func_sym, std::ostream &outs, std::ostream &er if (verbosity >= 2) { errs << "\n---------- resulting code for " << name << " -------------\n"; } - bool inline_func = (func_val->flags & 1); - bool inline_ref = (func_val->flags & 2); const char* modifier = ""; - if (inline_func) { + if (func_val->is_inline()) { modifier = "INLINE"; - } else if (inline_ref) { + } else if (func_val->is_inline_ref()) { modifier = "REF"; } outs << std::string(indent * 2, ' ') << name << " PROC" << modifier << ":<{\n"; @@ -140,12 +167,10 @@ void generate_output_func(SymDef* func_sym, std::ostream &outs, std::ostream &er if (opt_level < 2) { mode |= Stack::_DisableOpt; } - auto fv = dynamic_cast(func_sym->value); - // Flags: 1 - inline, 2 - inline_ref - if (fv && (fv->flags & 1) && code.ops->noreturn()) { + if (func_val->is_inline() && code.ops->noreturn()) { mode |= Stack::_InlineFunc; } - if (fv && (fv->flags & 3)) { + if (func_val->is_inline() || func_val->is_inline_ref()) { mode |= Stack::_InlineAny; } code.generate_code(outs, mode, indent + 1); @@ -167,6 +192,13 @@ int generate_output(std::ostream &outs, std::ostream &errs) { for (SymDef* func_sym : glob_func) { SymValCodeFunc* func_val = dynamic_cast(func_sym->value); func_assert(func_val); + if (!func_val->does_need_codegen()) { + if (verbosity >= 2) { + errs << func_sym->name() << ": code not generated, function does not need codegen\n"; + } + continue; + } + std::string name = sym::symbols.get_name(func_sym->sym_idx); outs << std::string(indent * 2, ' '); if (func_val->method_id.is_null()) { @@ -182,6 +214,10 @@ int generate_output(std::ostream &outs, std::ostream &errs) { } int errors = 0; for (SymDef* func_sym : glob_func) { + SymValCodeFunc* func_val = dynamic_cast(func_sym->value); + if (!func_val->does_need_codegen()) { + continue; + } try { generate_output_func(func_sym, outs, errs); } catch (src::Error& err) { @@ -259,4 +295,4 @@ int func_proceed(const std::vector &sources, std::ostream &outs, st return 0; } -} // namespace funC \ No newline at end of file +} // namespace funC diff --git a/crypto/func/func.h b/crypto/func/func.h index f4756edd6..e968978c2 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -219,6 +219,8 @@ struct TypeExpr { std::ostream& print(std::ostream& os, int prio = 0) const; void replace_with(TypeExpr* te2); int extract_components(std::vector& comp_list); + bool equals_to(const TypeExpr* rhs) const; + bool has_unknown_inside() const; static int holes, type_vars; static TypeExpr* new_hole() { return new TypeExpr{te_Unknown, ++holes}; @@ -752,26 +754,27 @@ struct CodeBlob { struct SymVal : sym::SymValBase { TypeExpr* sym_type; - td::RefInt256 method_id; bool impure; bool auto_apply{false}; - 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), flags(0) { + : sym::SymValBase(_type, _idx), sym_type(_stype), impure(_impure) { } ~SymVal() override = default; TypeExpr* get_type() const { return sym_type; } - virtual const std::vector* get_arg_order() const { - return nullptr; - } - virtual const std::vector* get_ret_order() const { - return nullptr; - } }; struct SymValFunc : SymVal { + enum SymValFlag { + flagInline = 1, // function marked `inline` + flagInlineRef = 2, // function marked `inline_ref` + flagWrapsAnotherF = 4, // (T) thisF(...args) { return anotherF(...args); } (calls to thisF will be replaced) + flagUsedAsNonCall = 8, // used not only as `f()`, but as a 1-st class function (assigned to var, pushed to tuple, etc.) + }; + + td::RefInt256 method_id; // todo why int256? it's small + int flags{0}; std::vector arg_order, ret_order; #ifdef FUNC_DEBUG std::string name; // seeing function name in debugger makes it much easier to delve into FunC sources @@ -784,12 +787,23 @@ struct SymValFunc : SymVal { : SymVal(_Func, val, _ft, _impure), arg_order(_arg_order), ret_order(_ret_order) { } - const std::vector* get_arg_order() const override { + const std::vector* get_arg_order() const { return arg_order.empty() ? nullptr : &arg_order; } - const std::vector* get_ret_order() const override { + const std::vector* get_ret_order() const { return ret_order.empty() ? nullptr : &ret_order; } + const TypeExpr* get_arg_type() const; + + bool is_inline() const { + return flags & flagInline; + } + bool is_inline_ref() const { + return flags & flagInlineRef; + } + bool is_just_wrapper_for_another_f() const { + return flags & flagWrapsAnotherF; + } }; struct SymValCodeFunc : SymValFunc { @@ -797,6 +811,7 @@ struct SymValCodeFunc : SymValFunc { ~SymValCodeFunc() override = default; SymValCodeFunc(int val, TypeExpr* _ft, bool _impure = false) : SymValFunc(val, _ft, _impure), code(nullptr) { } + bool does_need_codegen() const; }; struct SymValType : sym::SymValBase { @@ -910,7 +925,7 @@ struct Expr { _Tensor, _Const, _Var, - _Glob, + _GlobFunc, _GlobVar, _Letop, _LetFirst, diff --git a/crypto/func/gen-abscode.cpp b/crypto/func/gen-abscode.cpp index fe2d1850d..60e8c8e72 100644 --- a/crypto/func/gen-abscode.cpp +++ b/crypto/func/gen-abscode.cpp @@ -340,16 +340,36 @@ std::vector Expr::pre_compile(CodeBlob& code, std::vector(sym->value); std::vector res; - if (func && func->arg_order.size() == args.size() && !(code.flags & CodeBlob::_ComputeAsmLtr)) { + SymDef* applied_sym = sym; + auto func = dynamic_cast(applied_sym->value); + // replace `beginCell()` with `begin_cell()` + if (func && func->is_just_wrapper_for_another_f()) { + // body is { Op::_Import; Op::_Call; Op::_Return; } + const Op *op_call = dynamic_cast(func)->code->ops.get(); + while (op_call->cl != Op::_Call) { + op_call = op_call->next.get(); + } + applied_sym = op_call->fun_ref; + func = dynamic_cast(applied_sym->value); + // soon we'll get rid of this pragma: it will be always on, we'll pass just {} here and below + bool compute_asm_ltr = code.flags & CodeBlob::_ComputeAsmLtr; + // a function may call anotherF with shuffled arguments: f(x,y) { return anotherF(y,x) } + // then op_call looks like (_1,_0), so use op_call->right for correct positions in Op::_Call below + // it's correct, since every argument has width 1 + std::vector res_inner = pre_compile_tensor(args, code, lval_globs, compute_asm_ltr ? std::vector{} : func->arg_order); + res.reserve(res_inner.size()); + for (var_idx_t right_idx : op_call->right) { + res.emplace_back(res_inner[right_idx]); + } + } else if (func && func->arg_order.size() == args.size() && !(code.flags & CodeBlob::_ComputeAsmLtr)) { //std::cerr << "!!! reordering " << args.size() << " arguments of " << sym->name() << std::endl; res = pre_compile_tensor(args, code, lval_globs, func->arg_order); } else { res = pre_compile_tensor(args, code, lval_globs, {}); } auto rvect = new_tmp_vect(code); - auto& op = code.emplace_back(here, Op::_Call, rvect, std::move(res), sym); + auto& op = code.emplace_back(here, Op::_Call, rvect, res, applied_sym); if (flags & _IsImpure) { op.flags |= Op::_Impure; } @@ -364,7 +384,7 @@ std::vector Expr::pre_compile(CodeBlob& code, std::vectorcls == _Glob) { + if (args[0]->cls == _GlobFunc) { 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); @@ -388,8 +408,14 @@ std::vector Expr::pre_compile(CodeBlob& code, std::vector(sym->value)) { + fun_ref->flags |= SymValFunc::flagUsedAsNonCall; + if (!fun_ref->arg_order.empty() || !fun_ref->ret_order.empty()) { + throw src::ParseError(here, "Saving " + sym->name() + " into a variable will most likely lead to invalid usage, since it changes the order of variables on the stack"); + } + } auto rvect = new_tmp_vect(code); if (lval_globs) { lval_globs->push_back({ sym, rvect[0] }); diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index 0e0378218..80cd35684 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -423,8 +423,8 @@ bool check_global_func(const Lexem& cur, sym_idx_t func_name = 0) { } Expr* make_func_apply(Expr* fun, Expr* x) { - Expr* res; - if (fun->cls == Expr::_Glob) { + Expr* res{nullptr}; + if (fun->cls == Expr::_GlobFunc) { if (x->cls == Expr::_Tensor) { res = new Expr{Expr::_Apply, fun->sym, x->args}; } else { @@ -664,7 +664,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { lex.cur().error_at("undefined identifier `", "`"); } else if (val->type == SymVal::_Func) { res->e_type = val->get_type(); - res->cls = Expr::_Glob; + res->cls = Expr::_GlobFunc; auto_apply = val->auto_apply; } else if (val->idx < 0) { lex.cur().error_at("accessing variable `", "` being defined"); @@ -1435,6 +1435,78 @@ TypeExpr* compute_type_closure(TypeExpr* expr, const std::vector& typ return expr; } +// if a function looks like `T f(...args) { return anotherF(...args); }`, +// set a bit to flags +// then, all calls to `f(...)` will be effectively replaced with `anotherF(...)` +void detect_if_function_just_wraps_another(SymValCodeFunc* v_current, const td::RefInt256 &method_id) { + const std::string& function_name = v_current->code->name; + + // in "AST" representation, the first is Op::_Import (input arguments, even if none) + const auto& op_import = v_current->code->ops; + func_assert(op_import && op_import->cl == Op::_Import); + + // then Op::_Call (anotherF) + // when pragma allow-post-modification, it might be prepended with empty Op::_Let todo I don't like this + const Op* op_call = op_import->next.get(); + while (op_call && op_call->cl == Op::_Let && op_call->disabled()) + op_call = op_call->next.get(); + if (!op_call || op_call->cl != Op::_Call) + return; + func_assert(op_call->left.size() == 1); + + const auto& op_return = op_call->next; + if (!op_return || op_return->cl != Op::_Return || op_return->left.size() != 1) + return; + + bool indices_expected = op_import->left.size() == op_call->left[0] && op_call->left[0] == op_return->left[0]; + if (!indices_expected) + return; + + const SymDef* f_called = op_call->fun_ref; + const SymValFunc* v_called = dynamic_cast(f_called->value); + if (!v_called) + return; + + // `return` must use all arguments, e.g. `return (_0,_2,_1)`, not `return (_0,_1,_1)` + int args_used_mask = 0; + for (var_idx_t arg_idx : op_call->right) { + args_used_mask |= 1 << arg_idx; + } + if (args_used_mask != (1 << op_call->right.size()) - 1) + return; + + // detect getters (having method_id), they should not be treated as wrappers + // v_current->method_id will be assigned later; todo refactor function parsing completely, it's weird + // moreover, `recv_external()` and others are also exported, but FunC is unaware of method_id + // (it's assigned by Fift later) + // so, for now, just handle "special" function names, the same as in Asm.fif + if (!method_id.is_null()) + return; + if (function_name == "main" || function_name == "recv_internal" || function_name == "recv_external" || + function_name == "run_ticktock" || function_name == "split_prepare" || function_name == "split_install") + return; + + // all types must be strictly defined (on mismatch, a compilation error will be triggered anyway) + if (v_called->sym_type->has_unknown_inside() || v_current->sym_type->has_unknown_inside()) + return; + // avoid situations like `f(int a, (int,int) b)`, inlining will be cumbersome + if (v_current->get_arg_type()->get_width() != op_call->right.size()) + return; + // 'return true;' (false, nil) are (surprisingly) also function calls, with auto_apply=true + if (v_called->auto_apply) + return; + + // they must have the same pureness + if (v_called->impure != v_current->impure || v_current->is_inline_ref()) + return; + + // ok, f_current is a wrapper + v_current->flags |= SymValFunc::flagWrapsAnotherF; + if (verbosity >= 2) { + std::cerr << function_name << " -> " << f_called->name() << std::endl; + } +} + void parse_func_def(Lexer& lex) { SrcLocation loc{lex.cur().loc}; sym::open_scope(lex); @@ -1453,9 +1525,12 @@ 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; + int flags_inline = 0; + if (lex.tp() == _Inline) { + flags_inline = SymValFunc::flagInline; + lex.next(); + } else if (lex.tp() == _InlineRef) { + flags_inline = SymValFunc::flagInlineRef; lex.next(); } td::RefInt256 method_id; @@ -1533,6 +1608,7 @@ void parse_func_def(Lexer& lex) { code->loc = loc; // code->print(std::cerr); // !!!DEBUG!!! func_sym_code->code = code; + detect_if_function_just_wraps_another(func_sym_code, method_id); } else { Lexem asm_lexem = lex.cur(); SymValAsmFunc* asm_func = parse_asm_func_body(lex, func_type, arg_list, ret_type, impure); @@ -1555,7 +1631,7 @@ void parse_func_def(Lexer& lex) { func_sym->value = asm_func; } if (method_id.not_null()) { - auto val = dynamic_cast(func_sym->value); + auto val = dynamic_cast(func_sym->value); if (!val) { lex.cur().error("cannot set method id for unknown function `"s + func_name.str + "`"); } @@ -1566,14 +1642,14 @@ void parse_func_def(Lexer& lex) { val->method_id->to_dec_string() + " to a different value " + method_id->to_dec_string()); } } - if (f) { - auto val = dynamic_cast(func_sym->value); + if (flags_inline) { + auto val = dynamic_cast(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) { + if (!val->is_inline() && !val->is_inline_ref()) { + val->flags |= flags_inline; + } else if ((val->flags & (SymValFunc::flagInline | SymValFunc::flagInlineRef)) != flags_inline) { lex.cur().error("inline mode for `"s + func_name.str + "` changed with respect to a previous declaration"); } } diff --git a/crypto/func/unify-types.cpp b/crypto/func/unify-types.cpp index 22b33281a..e8a9d0781 100644 --- a/crypto/func/unify-types.cpp +++ b/crypto/func/unify-types.cpp @@ -115,6 +115,39 @@ int TypeExpr::extract_components(std::vector& comp_list) { return res; } +bool TypeExpr::equals_to(const TypeExpr *rhs) const { + const TypeExpr *l = this; + const TypeExpr *r = rhs; + while (l->constr == te_Indirect) + l = l->args[0]; + while (r->constr == te_Indirect) + r = r->args[0]; + + bool eq = l->constr == r->constr && l->value == r->value && + l->minw == r->minw && l->maxw == r->maxw && + l->was_forall_var == r->was_forall_var && + l->args.size() == r->args.size(); + if (!eq) + return false; + + for (int i = 0; i < l->args.size(); ++i) { + if (!l->args[i]->equals_to(r->args[i])) + return false; + } + return true; +} + +bool TypeExpr::has_unknown_inside() const { + if (constr == te_Unknown) + return true; + + for (const TypeExpr* inner : args) { + if (inner->has_unknown_inside()) + return true; + } + return false; +} + TypeExpr* TypeExpr::new_map(TypeExpr* from, TypeExpr* to) { return new TypeExpr{te_Map, std::vector{from, to}}; } From c74e49d467cd9084abaff1b67d99aa40eb480a6a Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Sat, 27 Apr 2024 14:32:16 +0500 Subject: [PATCH 06/30] [FunC] Enrich testing framework, add code hash checking @code_hash to match (boc) hash of compiled.fif against expected. While being much less flexible than @fif_codegen, it nevertheless gives a guarantee of bytecode stability on compiler modifications. --- crypto/func/auto-tests/run_tests.js | 41 ++++++++++++++++++- crypto/func/auto-tests/run_tests.py | 39 +++++++++++++++++- crypto/func/auto-tests/tests/a6.fc | 2 + .../tests/allow_post_modification.fc | 13 ++++++ crypto/func/auto-tests/tests/asm_arg_order.fc | 2 + crypto/func/auto-tests/tests/co1.fc | 2 + crypto/func/auto-tests/tests/s1.fc | 2 + crypto/func/auto-tests/tests/try-func.fc | 2 + .../auto-tests/tests/unbalanced_ret_nested.fc | 2 + crypto/func/auto-tests/tests/w6.fc | 2 + 10 files changed, 105 insertions(+), 2 deletions(-) diff --git a/crypto/func/auto-tests/run_tests.js b/crypto/func/auto-tests/run_tests.js index 28a0d5368..bef2ed42b 100644 --- a/crypto/func/auto-tests/run_tests.js +++ b/crypto/func/auto-tests/run_tests.js @@ -92,6 +92,9 @@ class CompareOutputError extends Error { class CompareFifCodegenError extends Error { } +class CompareCodeHashError extends Error { +} + /* * In positive tests, there are several testcases "input X should produce output Y". @@ -236,6 +239,22 @@ class FuncTestCaseFifCodegen { } } +/* + * @code_hash checks that hash of compiled output.fif matches the provided value. + * It's used to "record" code boc hash and to check that it remains the same on compiler modifications. + * Being much less flexible than @fif_codegen, it nevertheless gives a guarantee of bytecode stability. + */ +class FuncTestCaseExpectedHash { + constructor(/**string*/ expected_hash) { + this.code_hash = expected_hash + } + + check(fif_code_hash) { + if (this.code_hash !== fif_code_hash) + throw new CompareCodeHashError(`expected ${this.code_hash}, actual ${fif_code_hash}`) + } +} + class FuncTestFile { constructor(/**string*/ func_filename, /**string*/ artifacts_folder) { @@ -249,6 +268,8 @@ class FuncTestFile { this.input_output = [] /** @type {FuncTestCaseFifCodegen[]} */ this.fif_codegen = [] + /** @type {FuncTestCaseExpectedHash | null} */ + this.expected_hash = null } parse_input_from_func_file() { @@ -270,6 +291,8 @@ class FuncTestFile { this.fif_codegen.push(new FuncTestCaseFifCodegen(this.parse_string_value(lines), true)) } else if (line.startsWith("@fif_codegen")) { this.fif_codegen.push(new FuncTestCaseFifCodegen(this.parse_string_value(lines), false)) + } else if (line.startsWith("@code_hash")) { + this.expected_hash = new FuncTestCaseExpectedHash(this.parse_string_value(lines, false)[0]) } this.line_idx++ } @@ -281,7 +304,7 @@ class FuncTestFile { } /** @return {string[]} */ - parse_string_value(/**string[]*/ lines) { + parse_string_value(/**string[]*/ lines, allow_multiline = true) { // a tag must be followed by a space (single-line), e.g. '@stderr some text' // or be a multi-line value, surrounded by """ const line = lines[this.line_idx] @@ -292,6 +315,8 @@ class FuncTestFile { throw new ParseInputError(`${line} value is empty (not followed by a string or a multiline """)`) if (is_single_line && is_multi_line) throw new ParseInputError(`${line.substring(0, pos_sp)} value is both single-line and followed by """`) + if (is_multi_line && !allow_multiline) + throw new ParseInputError(`${line} value should be single-line`); if (is_single_line) return [line.substring(pos_sp + 1).trim()] @@ -337,6 +362,8 @@ class FuncTestFile { let runner = `"${this.get_compiled_fif_filename()}" include x.trim()).filter(s => s.length > 0) + let fif_code_hash = null + if (this.expected_hash !== null) { // then the last stdout line is a hash + fif_code_hash = stdout_lines[stdout_lines.length - 1] + stdout_lines = stdout_lines.slice(0, stdout_lines.length - 1) + } if (exit_code) throw new FiftExecutionFailedError(`fift exit_code = ${exit_code}`, stderr) @@ -360,6 +392,9 @@ class FuncTestFile { for (let fif_codegen of this.fif_codegen) fif_codegen.check(fif_output) } + + if (this.expected_hash !== null) + this.expected_hash.check(fif_code_hash) } } @@ -408,6 +443,10 @@ async function run_all_tests(/**string[]*/ tests) { print(" Was compiled to:", testcase.get_compiled_fif_filename()) print(fs.readFileSync(testcase.get_compiled_fif_filename(), 'utf-8')) process.exit(2) + } else if (e instanceof CompareCodeHashError) { + print(" Mismatch in code hash:", e.message) + print(" Was compiled to:", testcase.get_compiled_fif_filename()) + process.exit(2) } throw e } diff --git a/crypto/func/auto-tests/run_tests.py b/crypto/func/auto-tests/run_tests.py index 3e2cb8a67..e9e393e23 100644 --- a/crypto/func/auto-tests/run_tests.py +++ b/crypto/func/auto-tests/run_tests.py @@ -88,6 +88,10 @@ class CompareFifCodegenError(Exception): pass +class CompareCodeHashError(Exception): + pass + + class FuncTestCaseInputOutput: """ In positive tests, there are several testcases "input X should produce output Y". @@ -226,6 +230,21 @@ def does_line_match(line_pattern: str, line_output: str) -> bool: return cmd_pattern == cmd_output and (comment_pattern is None or comment_pattern == comment_output) +class FuncTestCaseExpectedHash: + """ + @code_hash checks that hash of compiled output.fif matches the provided value. + It's used to "record" code boc hash and to check that it remains the same on compiler modifications. + Being much less flexible than @fif_codegen, it nevertheless gives a guarantee of bytecode stability. + """ + + def __init__(self, expected_hash: str): + self.code_hash = expected_hash + + def check(self, fif_code_hash: str): + if self.code_hash != fif_code_hash: + raise CompareCodeHashError("expected %s, actual %s" % (self.code_hash, fif_code_hash)) + + class FuncTestFile: def __init__(self, func_filename: str, artifacts_folder: str): self.line_idx = 0 @@ -235,6 +254,7 @@ def __init__(self, func_filename: str, artifacts_folder: str): self.stderr_includes: list[FuncTestCaseStderr] = [] self.input_output: list[FuncTestCaseInputOutput] = [] self.fif_codegen: list[FuncTestCaseFifCodegen] = [] + self.expected_hash: FuncTestCaseExpectedHash | None = None def parse_input_from_func_file(self): with open(self.func_filename, "r") as fd: @@ -256,6 +276,8 @@ def parse_input_from_func_file(self): self.fif_codegen.append(FuncTestCaseFifCodegen(self.parse_string_value(lines), True)) elif line.startswith("@fif_codegen"): self.fif_codegen.append(FuncTestCaseFifCodegen(self.parse_string_value(lines), False)) + elif line.startswith("@code_hash"): + self.expected_hash = FuncTestCaseExpectedHash(self.parse_string_value(lines, False)[0]) self.line_idx = self.line_idx + 1 if len(self.input_output) == 0 and not self.compilation_should_fail: @@ -263,7 +285,7 @@ def parse_input_from_func_file(self): if len(self.input_output) != 0 and self.compilation_should_fail: raise ParseInputError("TESTCASE present, but compilation_should_fail") - def parse_string_value(self, lines: list[str]) -> list[str]: + def parse_string_value(self, lines: list[str], allow_multiline = True) -> list[str]: # a tag must be followed by a space (single-line), e.g. '@stderr some text' # or be a multi-line value, surrounded by """ line = lines[self.line_idx] @@ -274,6 +296,8 @@ def parse_string_value(self, lines: list[str]) -> list[str]: raise ParseInputError('%s value is empty (not followed by a string or a multiline """)' % line) if is_single_line and is_multi_line: raise ParseInputError('%s value is both single-line and followed by """' % line[:pos_sp]) + if is_multi_line and not allow_multiline: + raise ParseInputError("%s value should be single-line" % line) if is_single_line: return [line[pos_sp + 1:].strip()] @@ -312,6 +336,8 @@ def run_and_check(self): f.write("\"%s\" include 10) { + return (x~inc(8), x + 1, x = 1, x <<= 3, x); + } else { + xx = 9; + return (x, x~inc(-4), x~inc(-1), x >= 1, x = x + xx); + } +} + () main() { } @@ -75,4 +84,8 @@ TESTCASE | 16 | 100 | 100 50 105 210 210 211 211 TESTCASE | 17 | 100 | 100 50 105 210 210 211 211 TESTCASE | 18 | 100 | 210 210 211 211 100 50 105 TESTCASE | 19 | 100 | 100 50 105 210 210 211 211 +TESTCASE | 20 | 80 | 80 89 1 8 8 +TESTCASE | 20 | 9 | 9 -40 -10 -1 13 + +@code_hash 67078680159561921827850021610104736412668316252257881932102553152922274405210 -} diff --git a/crypto/func/auto-tests/tests/asm_arg_order.fc b/crypto/func/auto-tests/tests/asm_arg_order.fc index b53419e30..84a8a926c 100644 --- a/crypto/func/auto-tests/tests/asm_arg_order.fc +++ b/crypto/func/auto-tests/tests/asm_arg_order.fc @@ -110,4 +110,6 @@ TESTCASE | 23 | | [ 11 22 33 ] [ 220 330 110 ] TESTCASE | 24 | | [ 11 22 33 44 55 ] [ 220 330 440 110 550 ] TESTCASE | 25 | | [ 22 33 ] [ 220 330 ] TESTCASE | 26 | | [ 11 22 33 ] [ 220 330 110 ] + +@code_hash 53895312198338603934600244087571743055624960603383611438828666636202841531600 -} diff --git a/crypto/func/auto-tests/tests/co1.fc b/crypto/func/auto-tests/tests/co1.fc index 440672434..515c6bc6a 100644 --- a/crypto/func/auto-tests/tests/co1.fc +++ b/crypto/func/auto-tests/tests/co1.fc @@ -57,4 +57,6 @@ _ main() { {- TESTCASE | 0 | | 0 + +@code_hash 98157584761932576648981760908342408003231747902562138202913714302941716912743 -} diff --git a/crypto/func/auto-tests/tests/s1.fc b/crypto/func/auto-tests/tests/s1.fc index 1541943d1..97b19f166 100644 --- a/crypto/func/auto-tests/tests/s1.fc +++ b/crypto/func/auto-tests/tests/s1.fc @@ -51,4 +51,6 @@ _ main() { {- TESTCASE | 0 | | 0 + +@code_hash 35542701048549611407499491204004197688673151742407097578098250360682143458214 -} diff --git a/crypto/func/auto-tests/tests/try-func.fc b/crypto/func/auto-tests/tests/try-func.fc index 5678965ef..fb2a968a4 100644 --- a/crypto/func/auto-tests/tests/try-func.fc +++ b/crypto/func/auto-tests/tests/try-func.fc @@ -106,4 +106,6 @@ TESTCASE | 4 | 4 8 9 | 4350009 TESTCASE | 4 | 4 7 9 | 4001009 TESTCASE | 5 | 4 8 9 | 4350009 TESTCASE | 5 | 4 7 9 | 4001009 + +@code_hash 30648920105446086409127767431349650306796188362733360847851465122919640638913 -} diff --git a/crypto/func/auto-tests/tests/unbalanced_ret_nested.fc b/crypto/func/auto-tests/tests/unbalanced_ret_nested.fc index 7ab4bdf0d..a54a0dd12 100644 --- a/crypto/func/auto-tests/tests/unbalanced_ret_nested.fc +++ b/crypto/func/auto-tests/tests/unbalanced_ret_nested.fc @@ -32,4 +32,6 @@ TESTCASE | 0 | -5 -4 | 111 -70 TESTCASE | 0 | -4 3 | -7 40 TESTCASE | 0 | -4 -5 | -7 1110 TESTCASE | 0 | -4 -4 | -7 -70 + +@code_hash 68625253347714662162648433047986779710161195298061582217368558479961252943991 -} diff --git a/crypto/func/auto-tests/tests/w6.fc b/crypto/func/auto-tests/tests/w6.fc index 9b91cdf75..44337c125 100644 --- a/crypto/func/auto-tests/tests/w6.fc +++ b/crypto/func/auto-tests/tests/w6.fc @@ -14,4 +14,6 @@ int main(int x) { {- method_id | in | out TESTCASE | 0 | 0 | 1 + +@code_hash 36599880583276393028571473830850694081778552118303309411432666239740650614479 -} From a174f858be57c35b8bb199249c7ea438aa849ef8 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Sat, 27 Apr 2024 19:50:51 +0500 Subject: [PATCH 07/30] [FunC] Apply camelCase to some tests to ensure code_hash remains unchanged In auto-tests, @code_hash controls bytecode stability. In legacy tests, expected hashes are specified in a separate file. --- .../bsc-bridge-collector/votes-collector.fc | 18 +++++++--- .../legacy_tests/elector/elector-code.fc | 34 +++++++++++++------ .../legacy_tests/wallet-v4/wallet-v4-code.fc | 10 ++++-- crypto/func/auto-tests/tests/a6.fc | 14 +++++--- .../tests/allow_post_modification.fc | 14 +++++--- crypto/func/auto-tests/tests/asm_arg_order.fc | 20 +++++++---- crypto/func/auto-tests/tests/co1.fc | 8 +++-- .../auto-tests/tests/unbalanced_ret_nested.fc | 5 ++- 8 files changed, 85 insertions(+), 38 deletions(-) diff --git a/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/votes-collector.fc b/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/votes-collector.fc index cec4ed211..2a74e3644 100644 --- a/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/votes-collector.fc +++ b/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/votes-collector.fc @@ -12,8 +12,16 @@ cell load_data() inline_ref { set_data(st); } +cell loadData() { + return load_data(); +} + +() saveData(cell c) impure { + return save_data(c); +} + () vote_on_external_chain(slice s_addr, int query_id, int voting_id, slice signature) impure { - cell external_votings = load_data(); + cell external_votings = loadData(); (_, int oracles_address, cell oracles) = get_bridge_config(); (int wc, int addr) = parse_std_addr(s_addr); throw_if(301, wc + 1); @@ -39,12 +47,12 @@ cell load_data() inline_ref { .store_dict(signatures); external_votings~udict_set_builder(256, voting_id, new_voting_data); - save_data(external_votings); + saveData(external_votings); return send_receipt_message(s_addr, 0x10000 + 5, query_id, voting_id, 0, 64); } () remove_outdated_votings(slice s_addr, int query_id, slice external_ids) impure { - cell external_votings = load_data(); + cell external_votings = loadData(); int bound = now() - 60 * 60 * 24 * 7; while (~ external_ids.slice_empty?()) { @@ -62,7 +70,7 @@ cell load_data() inline_ref { } } - save_data(external_votings); + saveData(external_votings); return send_receipt_message(s_addr, 0x10000 + 6, query_id, 0, 0, 64); ;; thanks } @@ -96,7 +104,7 @@ cell load_data() inline_ref { } (tuple) get_external_voting_data(int voting_id) method_id { - cell external_votings = load_data(); + cell external_votings = loadData(); (slice voting_data, int found?) = external_votings.udict_get?(256, voting_id); throw_unless(309, found?); (int time, int old_oracles_address, cell signatures) = (voting_data~load_uint(32), diff --git a/crypto/func/auto-tests/legacy_tests/elector/elector-code.fc b/crypto/func/auto-tests/legacy_tests/elector/elector-code.fc index a06524423..f32858666 100644 --- a/crypto/func/auto-tests/legacy_tests/elector/elector-code.fc +++ b/crypto/func/auto-tests/legacy_tests/elector/elector-code.fc @@ -2,23 +2,35 @@ #include "stdlib.fc"; +(slice, cell) loadDict(slice s) { return load_dict(s); } +(slice, int) loadGrams(slice s) { return load_grams(s); } +(slice, int) loadUint(slice s, int len) { return load_uint(s, len); } +() endParse(slice s) impure { return end_parse(s); } +builder storeDict(builder b, cell c) { return store_dict(b, c); } +builder storeUint(builder b, int x, int len) { return store_uint(b, x, len); } +() throwUnless(int excno, int cond) impure { return throw_unless(excno, cond); } +cell configParam(int paramNo) { return config_param(paramNo); } +forall X -> int isNull(X x) { return null?(x); } +(slice, int) tryUDictGet(cell dict, int keyLen, int index) { return udict_get?(dict, keyLen, index); } + + ;; cur_elect credits past_elections grams active_id active_hash (cell, cell, cell, int, int, int) load_data() inline_ref { var cs = get_data().begin_parse(); - var res = (cs~load_dict(), cs~load_dict(), cs~load_dict(), cs~load_grams(), cs~load_uint(32), cs~load_uint(256)); - cs.end_parse(); + var res = (cs~loadDict(), cs~loadDict(), cs~load_dict(), cs~loadGrams(), cs~loadUint(32), cs~load_uint(256)); + cs.endParse(); return res; } ;; cur_elect credits past_elections grams active_id active_hash () store_data(elect, credits, past_elections, grams, active_id, active_hash) impure inline_ref { set_data(begin_cell() - .store_dict(elect) + .storeDict(elect) .store_dict(credits) - .store_dict(past_elections) + .storeDict(past_elections) .store_grams(grams) .store_uint(active_id, 32) - .store_uint(active_hash, 256) + .storeUint(active_hash, 256) .end_cell()); } @@ -63,7 +75,7 @@ builder pack_past_election(int unfreeze_at, int stake_held, int vset_hash, cell ;; complaint_status#2d complaint:^ValidatorComplaint voters:(HashmapE 16 True) ;; vset_id:uint256 weight_remaining:int64 = ValidatorComplaintStatus; _ unpack_complaint_status(slice cs) inline_ref { - throw_unless(9, cs~load_uint(8) == 0x2d); + throwUnless(9, cs~load_uint(8) == 0x2d); var res = (cs~load_ref(), cs~load_dict(), cs~load_uint(256), cs~load_int(64)); cs.end_parse(); return res; @@ -71,7 +83,7 @@ _ unpack_complaint_status(slice cs) inline_ref { builder pack_complaint_status(cell complaint, cell voters, int vset_id, int weight_remaining) inline_ref { return begin_cell() - .store_uint(0x2d, 8) + .storeUint(0x2d, 8) .store_ref(complaint) .store_dict(voters) .store_uint(vset_id, 256) @@ -112,8 +124,8 @@ builder pack_complaint(int validator_pubkey, cell description, int created_at, i ;; deposit bit_price cell_price (int, int, int) get_complaint_prices() inline_ref { - var info = config_param(13); - return info.null?() ? (1 << 36, 1, 512) : info.parse_complaint_prices(); + var info = configParam(13); + return info.isNull() ? (1 << 36, 1, 512) : info.parse_complaint_prices(); } ;; elected_for elections_begin_before elections_end_before stake_held_for @@ -189,7 +201,7 @@ builder pack_complaint(int validator_pubkey, cell description, int created_at, i ;; credits 'amount' to 'addr' inside credit dictionary 'credits' _ ~credit_to(credits, addr, amount) inline_ref { - var (val, f) = credits.udict_get?(256, addr); + var (val, f) = credits.tryUDictGet(256, addr); if (f) { amount += val~load_grams(); } @@ -352,7 +364,7 @@ _ unfreeze_all(credits, past_elections, elect_id) inline_ref { var config_addr = config_param(0).begin_parse().preload_uint(256); var ds = get_data().begin_parse(); var elect = ds~load_dict(); - if ((src_wc + 1) | (src_addr != config_addr) | elect.null?()) { + if ((src_wc + 1) | (src_addr != config_addr) | elect.isNull()) { ;; not from config smc, somebody's joke? ;; or no elections active (or just completed) return (); diff --git a/crypto/func/auto-tests/legacy_tests/wallet-v4/wallet-v4-code.fc b/crypto/func/auto-tests/legacy_tests/wallet-v4/wallet-v4-code.fc index 21245a676..2b6b279fa 100644 --- a/crypto/func/auto-tests/legacy_tests/wallet-v4/wallet-v4-code.fc +++ b/crypto/func/auto-tests/legacy_tests/wallet-v4/wallet-v4-code.fc @@ -2,10 +2,14 @@ #include "stdlib.fc"; +_ skipBits(slice s, int len) { return skip_bits(s, len); } + (slice, int) dict_get?(cell dict, int key_len, slice index) asm(index dict key_len) "DICTGET" "NULLSWAPIFNOT"; (cell, int) dict_add_builder?(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTADDB"; (cell, int) dict_delete?(cell dict, int key_len, slice index) asm(index dict key_len) "DICTDEL"; +(cell, int) tryDictDelete(cell dict, int keyLen, slice index) { return dict_delete?(dict, keyLen, index); } + () recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure { var cs = in_msg_cell.begin_parse(); var flags = cs~load_uint(4); ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool @@ -25,7 +29,7 @@ slice s_addr = cs~load_msg_addr(); (int wc, int addr_hash) = parse_std_addr(s_addr); slice wc_n_address = begin_cell().store_int(wc, 8).store_uint(addr_hash, 256).end_cell().begin_parse(); - var ds = get_data().begin_parse().skip_bits(32 + 32 + 256); + var ds = get_data().begin_parse().skipBits(32 + 32 + 256); var plugins = ds~load_dict(); var (_, success?) = plugins.dict_get?(8 + 256, wc_n_address); if ~(success?) { @@ -54,7 +58,7 @@ if (op == 0x64737472) { ;; remove plugin by its request - plugins~dict_delete?(8 + 256, wc_n_address); + plugins~tryDictDelete(8 + 256, wc_n_address); var ds = get_data().begin_parse().first_bits(32 + 32 + 256); set_data(begin_cell().store_slice(ds).store_dict(plugins).end_cell()); ;; return coins only if bounce expected @@ -178,7 +182,7 @@ int get_public_key() method_id { } int is_plugin_installed(int wc, int addr_hash) method_id { - var ds = get_data().begin_parse().skip_bits(32 + 32 + 256); + var ds = get_data().begin_parse().skipBits(32 + 32 + 256); var plugins = ds~load_dict(); var (_, success?) = plugins.dict_get?(8 + 256, begin_cell().store_int(wc, 8).store_uint(addr_hash, 256).end_cell().begin_parse()); return success?; diff --git a/crypto/func/auto-tests/tests/a6.fc b/crypto/func/auto-tests/tests/a6.fc index bf36d1880..61c37d204 100644 --- a/crypto/func/auto-tests/tests/a6.fc +++ b/crypto/func/auto-tests/tests/a6.fc @@ -6,6 +6,8 @@ return (Dx / D, Dy / D); } +int mulDivR(int x, int y, int z) { return muldivr(x, y, z); } + int calc_phi() { var n = 1; repeat (70) { n *= 10; } @@ -13,7 +15,7 @@ int calc_phi() { do { (p, q) = (q, p + q); } until (q > n); - return muldivr(p, n, q); + return mulDivR(p, n, q); } int calc_sqrt2() { @@ -24,7 +26,7 @@ int calc_sqrt2() { var t = p + q; (p, q) = (q, t + q); } until (q > n); - return muldivr(p, n, q); + return mulDivR(p, n, q); } var calc_root(m) { @@ -73,14 +75,18 @@ int ataninv(int base, int q) { ;; computes base*atan(1/q) return sum; } +int arctanInv(int base, int q) { return ataninv(base, q); } + int calc_pi() { int base = 64; repeat (70) { base *= 10; } - return (ataninv(base << 2, 5) - ataninv(base, 239)) ~>> 4; + return (arctanInv(base << 2, 5) - arctanInv(base, 239)) ~>> 4; } +int calcPi() { return calc_pi(); } + int main() { - return calc_pi(); + return calcPi(); } {- diff --git a/crypto/func/auto-tests/tests/allow_post_modification.fc b/crypto/func/auto-tests/tests/allow_post_modification.fc index bab22fc38..36a310316 100644 --- a/crypto/func/auto-tests/tests/allow_post_modification.fc +++ b/crypto/func/auto-tests/tests/allow_post_modification.fc @@ -6,8 +6,12 @@ forall X -> tuple unsafe_tuple(X x) asm "NOP"; return (x + y, y * 10); } +(int, int) incWrap(int x, int y) { + return inc(x, y); +} + (int, int, int, int, int, int, int) test_return(int x) method_id(11) { - return (x, x~inc(x / 20), x, x = x * 2, x, x += 1, x); + return (x, x~incWrap(x / 20), x, x = x * 2, x, x += 1, x); } (int, int, int, int, int, int, int) test_assign(int x) method_id(12) { @@ -16,7 +20,7 @@ forall X -> tuple unsafe_tuple(X x) asm "NOP"; } tuple test_tuple(int x) method_id(13) { - tuple t = unsafe_tuple([x, x~inc(x / 20), x, x = x * 2, x, x += 1, x]); + tuple t = unsafe_tuple([x, x~incWrap(x / 20), x, x = x * 2, x, x += 1, x]); return t; } @@ -39,7 +43,7 @@ tuple test_tuple(int x) method_id(13) { } (int, int, int, int, int, int, int) test_call_2(int x) method_id(16) { - return foo2(x, x~inc(x / 20), (x, x = x * 2, x, x += 1), x); + return foo2(x, x~incWrap(x / 20), (x, x = x * 2, x, x += 1), x); } (int, int, int, int, int, int, int) asm_func(int x1, int x2, int x3, int x4, int x5, int x6, int x7) asm @@ -52,13 +56,13 @@ tuple test_tuple(int x) method_id(13) { #pragma compute-asm-ltr; (int, int, int, int, int, int, int) test_call_asm_new(int x) method_id(18) { - return asm_func(x, x~inc(x / 20), x, x = x * 2, x, x += 1, x); + return asm_func(x, x~incWrap(x / 20), x, x = x * 2, x, x += 1, x); } global int xx; (int, int, int, int, int, int, int) test_global(int x) method_id(19) { xx = x; - return (xx, xx~inc(xx / 20), xx, xx = xx * 2, xx, xx += 1, xx); + return (xx, xx~incWrap(xx / 20), xx, xx = xx * 2, xx, xx += 1, xx); } (int, int, int, int, int) test_if_else(int x) method_id(20) { diff --git a/crypto/func/auto-tests/tests/asm_arg_order.fc b/crypto/func/auto-tests/tests/asm_arg_order.fc index 84a8a926c..1824b84ad 100644 --- a/crypto/func/auto-tests/tests/asm_arg_order.fc +++ b/crypto/func/auto-tests/tests/asm_arg_order.fc @@ -1,28 +1,34 @@ tuple empty_tuple() asm "NIL"; forall X -> (tuple, ()) tpush(tuple t, X x) asm "TPUSH"; +tuple emptyTuple() { return empty_tuple(); } +forall X -> (tuple, ()) tuplePush(tuple t, X value) { return tpush(t, value); } tuple asm_func_1(int x, int y, int z) asm "3 TUPLE"; tuple asm_func_2(int x, int y, int z) asm (z y x -> 0) "3 TUPLE"; tuple asm_func_3(int x, int y, int z) asm (y z x -> 0) "3 TUPLE"; tuple asm_func_4(int a, (int, (int, int)) b, int c) asm (b a c -> 0) "5 TUPLE"; +_ asmFunc1(int x, int y, int z) { return asm_func_1(x, y, z); } +_ asmFunc3(int x, int y, int z) { return asm_func_3(x, y, z); } + (tuple, ()) asm_func_modify(tuple a, int b, int c) asm (c b a -> 0) "SWAP TPUSH SWAP TPUSH"; +(tuple, ()) asmFuncModify(tuple a, int b, int c) { return asm_func_modify(a, b, c); } global tuple t; int foo(int x) { - t~tpush(x); + t~tuplePush(x); return x * 10; } (tuple, tuple) test_old_1() method_id(11) { t = empty_tuple(); - tuple t2 = asm_func_1(foo(11), foo(22), foo(33)); + tuple t2 = asmFunc1(foo(11), foo(22), foo(33)); return (t, t2); } (tuple, tuple) test_old_2() method_id(12) { - t = empty_tuple(); + t = emptyTuple(); tuple t2 = asm_func_2(foo(11), foo(22), foo(33)); return (t, t2); } @@ -34,7 +40,7 @@ int foo(int x) { } (tuple, tuple) test_old_4() method_id(14) { - t = empty_tuple(); + t = emptyTuple(); tuple t2 = empty_tuple(); ;; This actually computes left-to-right even without compute-asm-ltr tuple t2 = asm_func_4(foo(11), (foo(22), (foo(33), foo(44))), foo(55)); @@ -44,13 +50,13 @@ int foo(int x) { (tuple, tuple) test_old_modify() method_id(15) { t = empty_tuple(); tuple t2 = empty_tuple(); - t2~asm_func_modify(foo(22), foo(33)); + t2~asmFuncModify(foo(22), foo(33)); return (t, t2); } (tuple, tuple) test_old_dot() method_id(16) { t = empty_tuple(); - tuple t2 = foo(11).asm_func_3(foo(22), foo(33)); + tuple t2 = foo(11).asmFunc3(foo(22), foo(33)); return (t, t2); } @@ -58,7 +64,7 @@ int foo(int x) { (tuple, tuple) test_new_1() method_id(21) { t = empty_tuple(); - tuple t2 = asm_func_1(foo(11), foo(22), foo(33)); + tuple t2 = asmFunc1(foo(11), foo(22), foo(33)); return (t, t2); } diff --git a/crypto/func/auto-tests/tests/co1.fc b/crypto/func/auto-tests/tests/co1.fc index 515c6bc6a..a89d5922f 100644 --- a/crypto/func/auto-tests/tests/co1.fc +++ b/crypto/func/auto-tests/tests/co1.fc @@ -33,6 +33,10 @@ slice endcs(builder b) asm "ENDC" "CTOS"; int sdeq (slice s1, slice s2) asm "SDEQ"; builder stslicer(builder b, slice s) asm "STSLICER"; +builder storeUint(builder b, int x, int len) { return store_uint(b, x, len); } +_ endSlice(builder b) { return endcs(b); } +() throwUnless(int excno, int cond) impure { return throw_unless(excno, cond); } + _ main() { int i1 = iget1(); int i2 = iget2(); @@ -46,8 +50,8 @@ _ main() { slice s2 = sget2(); slice s3 = newc().stslicer(str1).stslicer(str2r).endcs(); - throw_unless(int111, sdeq(s1, newc().store_uint(str1int, 12 * nibbles).endcs())); - throw_unless(112, sdeq(s2, newc().store_uint(str2int, 6 * nibbles).endcs())); + throw_unless(int111, sdeq(s1, newc().storeUint(str1int, 12 * nibbles).endcs())); + throwUnless(112, sdeq(s2, newc().store_uint(str2int, 6 * nibbles).endSlice())); throw_unless(113, sdeq(s3, newc().store_uint(0x636f6e737431AABBCC, 18 * nibbles).endcs())); int i4 = iget240(); diff --git a/crypto/func/auto-tests/tests/unbalanced_ret_nested.fc b/crypto/func/auto-tests/tests/unbalanced_ret_nested.fc index a54a0dd12..02847c63c 100644 --- a/crypto/func/auto-tests/tests/unbalanced_ret_nested.fc +++ b/crypto/func/auto-tests/tests/unbalanced_ret_nested.fc @@ -17,8 +17,11 @@ int foo(int y) { } return (x + 1, y); } +(int,int) bar2(int x, int y) { + return bar(x, y); +} (int, int) main(int x, int y) { - (x, y) = bar(x, y); + (x, y) = bar2(x, y); return (x, y * 10); } {- From 30572c77d62c2573d0bb556800c79fe4532503b5 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Tue, 30 Apr 2024 20:32:07 +0300 Subject: [PATCH 08/30] [FunC] Support traditional // and /**/ comments They work alongside Lisp-style ;; and {--}, without any #pragma. Conceptually, a new syntax should be disabled by default and activated using a special compiler option. But now, we don't have an easy way to provide compiler options in func-js, blueprint, etc. Note, that introducing per-file #pragma is a wrong approach here, since if we want to fire human-readable error on using '//' without pragma, lexer should nevertheless work differently. (this could be controlled by a launch option, but see above) --- crypto/func/auto-tests/tests/comments.fc | 39 ++++++++++++++ .../func/auto-tests/tests/invalid-cmt-eof.fc | 11 ++++ crypto/func/parse-func.cpp | 9 +++- crypto/parser/lexer.cpp | 53 +++++++++++-------- crypto/parser/lexer.h | 16 ++++-- crypto/tl/tlbc.cpp | 4 +- 6 files changed, 105 insertions(+), 27 deletions(-) create mode 100644 crypto/func/auto-tests/tests/comments.fc create mode 100644 crypto/func/auto-tests/tests/invalid-cmt-eof.fc diff --git a/crypto/func/auto-tests/tests/comments.fc b/crypto/func/auto-tests/tests/comments.fc new file mode 100644 index 000000000..24ff0102f --- /dev/null +++ b/crypto/func/auto-tests/tests/comments.fc @@ -0,0 +1,39 @@ + +_ get10(); + +int {- + block comment + /* + nested + */ +;;;; -} main() + +// inside a comment, {- doesn't start a new one +{- but if ;; is inside, a comment may end at this line-} { + var cc = "a string may contain {- or // or /*, not parsed"; + // return 1; + return get10() + /* + traditional comment /* may be also nested */ + // line comment + // ends */1 + + 1; + {- moreover, different comment styles + may be used for opening and closing + */ +} + +/* + first line +//* nested + //two-lined*/ +*/ + +int get10() method_id(10) { + return 10; +} + + +/* +TESTCASE | 0 | | 12 +TESTCASE | 10 | | 10 +*/ diff --git a/crypto/func/auto-tests/tests/invalid-cmt-eof.fc b/crypto/func/auto-tests/tests/invalid-cmt-eof.fc new file mode 100644 index 000000000..f9e790219 --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-cmt-eof.fc @@ -0,0 +1,11 @@ +int main() { + return 0; +} + +{- +int ... + +/* +@compilation_should_fail +@stderr comment extends past end of file +*/ diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index 80cd35684..abba60685 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -1822,7 +1822,14 @@ void parse_include(Lexer& lex, const src::FileDescr* fdescr) { bool parse_source(std::istream* is, src::FileDescr* fdescr) { src::SourceReader reader{is, fdescr}; - Lexer lex{reader, true, ";,()[] ~."}; + Lexer lex{reader, ";,()[] ~."}; + // previously, FunC had lisp-style comments, + // but starting from v0.5.0, it supports traditional (slash) comments alongside + // (in IDE, the user has a setting, what comment style he prefers) + // maybe, in some far future, we'll stop supporting lisp-style comments + lex.set_comment_tokens(";;", "{-", "-}"); + lex.set_comment2_tokens("//", "/*", "*/"); + lex.start_parsing(); while (lex.tp() != _Eof) { if (lex.tp() == _PragmaHashtag) { parse_pragma(lex); diff --git a/crypto/parser/lexer.cpp b/crypto/parser/lexer.cpp index 117f1df5a..418860ebe 100644 --- a/crypto/parser/lexer.cpp +++ b/crypto/parser/lexer.cpp @@ -124,8 +124,7 @@ int Lexem::set(std::string _str, const SrcLocation& _loc, int _tp, int _val) { return classify(); } -Lexer::Lexer(SourceReader& _src, bool init, std::string active_chars, std::string eol_cmts, std::string open_cmts, - std::string close_cmts, std::string quote_chars, std::string multiline_quote) +Lexer::Lexer(SourceReader& _src, std::string active_chars, std::string quote_chars, std::string multiline_quote) : src(_src), eof(false), lexem("", src.here(), Lexem::Undefined), peek_lexem("", {}, Lexem::Undefined), multiline_quote(std::move(multiline_quote)) { std::memset(char_class, 0, sizeof(char_class)); @@ -139,17 +138,27 @@ Lexer::Lexer(SourceReader& _src, bool init, std::string active_chars, std::strin char_class[(unsigned)c] |= activity; } } - set_spec(eol_cmt, eol_cmts); - set_spec(cmt_op, open_cmts); - set_spec(cmt_cl, close_cmts); for (int c : quote_chars) { if (c > ' ' && c <= 0x7f) { char_class[(unsigned)c] |= cc::quote_char; } } - if (init) { - next(); - } +} + +void Lexer::set_comment_tokens(const std::string &eol_cmts, const std::string &open_cmts, const std::string &close_cmts) { + set_spec(eol_cmt, eol_cmts); + set_spec(cmt_op, open_cmts); + set_spec(cmt_cl, close_cmts); +} + +void Lexer::set_comment2_tokens(const std::string &eol_cmts2, const std::string &open_cmts2, const std::string &close_cmts2) { + set_spec(eol_cmt2, eol_cmts2); + set_spec(cmt_op2, open_cmts2); + set_spec(cmt_cl2, close_cmts2); +} + +void Lexer::start_parsing() { + next(); } void Lexer::set_spec(std::array& arr, std::string setup) { @@ -206,24 +215,30 @@ const Lexem& Lexer::next() { long long comm = 1; while (!src.seek_eof()) { int cc = src.cur_char(), nc = src.next_char(); - if (cc == eol_cmt[0] || (cc == eol_cmt[1] && nc == eol_cmt[2])) { - src.load_line(); - } else if (cc == cmt_op[1] && nc == cmt_op[2]) { + // note, that in practice (both in FunC and tlbc), [0]-th element is -256, condition for [0]-th is always false + if (cc == eol_cmt[0] || (cc == eol_cmt[1] && nc == eol_cmt[2]) || cc == eol_cmt2[0] || (cc == eol_cmt2[1] && nc == eol_cmt2[2])) { + if (comm == 1) { // just "//" — skip a whole line + src.load_line(); + } else { // if "//" is nested into "/*", continue reading, since "*/" may be met + src.advance(1); + } + } else if (cc == cmt_op[1] && nc == cmt_op[2] || cc == cmt_op2[1] && nc == cmt_op2[2]) { src.advance(2); comm = comm * 2 + 1; - } else if (cc == cmt_op[0]) { + } else if (cc == cmt_op[0] || cc == cmt_op2[0]) { // always false src.advance(1); comm *= 2; } else if (comm == 1) { - break; - } else if (cc == cmt_cl[1] && nc == cmt_cl[2]) { - if (!(comm & 1)) { + break; // means that we are not inside a comment + } else if (cc == cmt_cl[1] && nc == cmt_cl[2] || cc == cmt_cl2[1] && nc == cmt_cl2[2]) { + if (!(comm & 1)) { // always false src.error(std::string{"a `"} + (char)cmt_op[0] + "` comment closed by `" + (char)cmt_cl[1] + (char)cmt_cl[2] + "`"); } + // note that in FunC, {- may be closed with */, but assume it's ok (we'll get rid of {- in the future) comm >>= 1; src.advance(2); - } else if (cc == cmt_cl[0]) { + } else if (cc == cmt_cl[0] || cc == cmt_cl2[0]) { // always false if (!(comm & 1)) { src.error(std::string{"a `"} + (char)cmt_op[1] + (char)cmt_op[2] + "` comment closed by `" + (char)cmt_cl[0] + "`"); @@ -240,11 +255,7 @@ const Lexem& Lexer::next() { if (src.seek_eof()) { eof = true; if (comm > 1) { - if (comm & 1) { - src.error(std::string{"`"} + (char)cmt_op[1] + (char)cmt_op[2] + "` comment extends past end of file"); - } else { - src.error(std::string{"`"} + (char)cmt_op[0] + "` comment extends past end of file"); - } + src.error("comment extends past end of file"); } return lexem.clear(src.here(), Lexem::Eof); } diff --git a/crypto/parser/lexer.h b/crypto/parser/lexer.h index 686d8eacd..904d8b31d 100644 --- a/crypto/parser/lexer.h +++ b/crypto/parser/lexer.h @@ -65,12 +65,16 @@ struct Lexem { static std::string lexem_name_str(int idx); }; +// todo this class (like all sources in /ton/crypto/parser) is shared between FunC and tlbc +// this "shareness" and "generalization" is weird and annoying rather than solves any problems +// later on, I'll get rid of this (parser/) folder, copying and adapting its sources to FunC and tlbc class Lexer { SourceReader& src; bool eof; Lexem lexem, peek_lexem; unsigned char char_class[128]; - std::array eol_cmt, cmt_op, cmt_cl; + std::array eol_cmt, cmt_op, cmt_cl; // for FunC < 0.5.0: ;; {- -} + std::array eol_cmt2, cmt_op2, cmt_cl2; // for FunC >= 0.5.0: // /* */ std::string multiline_quote; enum cc { left_active = 2, right_active = 1, active = 3, allow_repeat = 4, quote_char = 8 }; @@ -78,9 +82,13 @@ class Lexer { bool eof_found() const { return eof; } - Lexer(SourceReader& _src, bool init = false, std::string active_chars = ";,() ~.", std::string eol_cmts = ";;", - std::string open_cmts = "{-", std::string close_cmts = "-}", std::string quote_chars = "\"", - std::string multiline_quote = "\"\"\""); + explicit Lexer(SourceReader& _src, std::string active_chars = ";,() ~.", + std::string quote_chars = "\"", std::string multiline_quote = "\"\"\""); + + void set_comment_tokens(const std::string &eol_cmts, const std::string &open_cmts, const std::string &close_cmts); + void set_comment2_tokens(const std::string &eol_cmts2, const std::string &open_cmts2, const std::string &close_cmts2); + void start_parsing(); + const Lexem& next(); const Lexem& cur() const { return lexem; diff --git a/crypto/tl/tlbc.cpp b/crypto/tl/tlbc.cpp index b48bc472e..9f8fdb0fa 100644 --- a/crypto/tl/tlbc.cpp +++ b/crypto/tl/tlbc.cpp @@ -2421,7 +2421,9 @@ std::vector source_fdescr; bool parse_source(std::istream* is, src::FileDescr* fdescr) { src::SourceReader reader{is, fdescr}; - src::Lexer lex{reader, true, "(){}:;? #$. ^~ #", "//", "/*", "*/", ""}; + src::Lexer lex{reader, "(){}:;? #$. ^~ #", ""}; + lex.set_comment_tokens("//", "/*", "*/"); + lex.start_parsing(); while (lex.tp() != src::_Eof) { parse_constructor_def(lex); // std::cerr << lex.cur().str << '\t' << lex.cur().name_str() << std::endl; From 4994ae8edd4ed372901db3f1cda0d7fa9d5a5259 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Tue, 30 Apr 2024 20:50:45 +0300 Subject: [PATCH 09/30] [FunC] Convert stdlib.fc to traditional-style //comments --- .../bsc-bridge-collector/stdlib.fc | 22 +- .../auto-tests/legacy_tests/elector/stdlib.fc | 22 +- .../auto-tests/legacy_tests/storage/stdlib.fc | 482 ++++++++--------- crypto/func/auto-tests/tests/comments.fc | 2 +- crypto/smartcont/stdlib.fc | 486 +++++++++--------- 5 files changed, 507 insertions(+), 507 deletions(-) diff --git a/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc b/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc index 1d144040f..d5d5c8b86 100644 --- a/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc @@ -1,5 +1,5 @@ -;; Standard library for funC -;; +// Standard library for funC +// forall X -> tuple cons(X head, tuple tail) asm "CONS"; forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; @@ -47,7 +47,7 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI (int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; (int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; +// () throw_if(int excno, int cond) impure asm "THROWARGIF"; () dump_stack() impure asm "DUMPSTK"; @@ -71,12 +71,12 @@ slice begin_parse(cell c) asm "CTOS"; () end_parse(slice s) impure asm "ENDS"; (slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; cell preload_ref(slice s) asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; +// (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; +// (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; +// int preload_int(slice s, int len) asm "PLDIX"; +// int preload_uint(slice s, int len) asm "PLDUX"; +// (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; +// slice preload_bits(slice s, int len) asm "PLDSLICEX"; (slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; (slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; @@ -109,8 +109,8 @@ int builder_depth(builder b) asm "BDEPTH"; builder begin_cell() asm "NEWC"; cell end_cell(builder b) asm "ENDC"; builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; +// builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; +// builder store_int(builder b, int x, int len) asm(x b len) "STIX"; builder store_slice(builder b, slice s) asm "STSLICER"; builder store_grams(builder b, int x) asm "STGRAMS"; builder store_dict(builder b, cell c) asm(c b) "STDICT"; diff --git a/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc b/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc index 0b98eeb44..b862b5ef8 100644 --- a/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc @@ -1,5 +1,5 @@ -;; Standard library for funC -;; +// Standard library for funC +// forall X -> tuple cons(X head, tuple tail) asm "CONS"; forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; @@ -47,7 +47,7 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI (int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; (int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; +// () throw_if(int excno, int cond) impure asm "THROWARGIF"; () dump_stack() impure asm "DUMPSTK"; @@ -71,12 +71,12 @@ slice begin_parse(cell c) asm "CTOS"; () end_parse(slice s) impure asm "ENDS"; (slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; cell preload_ref(slice s) asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; +// (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; +// (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; +// int preload_int(slice s, int len) asm "PLDIX"; +// int preload_uint(slice s, int len) asm "PLDUX"; +// (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; +// slice preload_bits(slice s, int len) asm "PLDSLICEX"; (slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; (slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; @@ -109,8 +109,8 @@ int builder_depth(builder b) asm "BDEPTH"; builder begin_cell() asm "NEWC"; cell end_cell(builder b) asm "ENDC"; builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; +// builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; +// builder store_int(builder b, int x, int len) asm(x b len) "STIX"; builder store_slice(builder b, slice s) asm "STSLICER"; builder store_grams(builder b, int x) asm "STGRAMS"; builder store_dict(builder b, cell c) asm(c b) "STDICT"; diff --git a/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc b/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc index 781fdcbcc..a33d39425 100644 --- a/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc @@ -1,7 +1,7 @@ -;; Standard library for funC -;; +// Standard library for funC +// -{- +/* # Tuple manipulation primitives The names and the types are mostly self-explaining. See [polymorhism with forall](https://ton.org/docs/#/func/functions?id=polymorphism-with-forall) @@ -9,260 +9,260 @@ Note that currently values of atomic type `tuple` can't be cast to composite tuple type (e.g. `[int, cell]`) and vise versa. --} +*/ -{- +/* # Lisp-style lists Lists can be represented as nested 2-elements tuples. Empty list is conventionally represented as TVM `null` value (it can be obtained by calling [null()]). For example, tuple `(1, (2, (3, null)))` represents list `[1, 2, 3]`. Elements of a list can be of different types. --} +*/ -;;; Adds an element to the beginning of lisp-style list. +/// Adds an element to the beginning of lisp-style list. forall X -> tuple cons(X head, tuple tail) asm "CONS"; -;;; Extracts the head and the tail of lisp-style list. +/// Extracts the head and the tail of lisp-style list. forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -;;; Extracts the tail and the head of lisp-style list. +/// Extracts the tail and the head of lisp-style list. forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -;;; Returns the head of lisp-style list. +/// Returns the head of lisp-style list. forall X -> X car(tuple list) asm "CAR"; -;;; Returns the tail of lisp-style list. +/// Returns the tail of lisp-style list. tuple cdr(tuple list) asm "CDR"; -;;; Creates tuple with zero elements. +/// Creates tuple with zero elements. tuple empty_tuple() asm "NIL"; -;;; Appends a value `x` to a `Tuple t = (x1, ..., xn)`, but only if the resulting `Tuple t' = (x1, ..., xn, x)` -;;; is of length at most 255. Otherwise throws a type check exception. +/// Appends a value `x` to a `Tuple t = (x1, ..., xn)`, but only if the resulting `Tuple t' = (x1, ..., xn, x)` +/// is of length at most 255. Otherwise throws a type check exception. forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -;;; Creates a tuple of length one with given argument as element. +/// Creates a tuple of length one with given argument as element. forall X -> [X] single(X x) asm "SINGLE"; -;;; Unpacks a tuple of length one +/// Unpacks a tuple of length one forall X -> X unsingle([X] t) asm "UNSINGLE"; -;;; Creates a tuple of length two with given arguments as elements. +/// Creates a tuple of length two with given arguments as elements. forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -;;; Unpacks a tuple of length two +/// Unpacks a tuple of length two forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -;;; Creates a tuple of length three with given arguments as elements. +/// Creates a tuple of length three with given arguments as elements. forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -;;; Unpacks a tuple of length three +/// Unpacks a tuple of length three forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -;;; Creates a tuple of length four with given arguments as elements. +/// Creates a tuple of length four with given arguments as elements. forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -;;; Unpacks a tuple of length four +/// Unpacks a tuple of length four forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -;;; Returns the first element of a tuple (with unknown element types). +/// Returns the first element of a tuple (with unknown element types). forall X -> X first(tuple t) asm "FIRST"; -;;; Returns the second element of a tuple (with unknown element types). +/// Returns the second element of a tuple (with unknown element types). forall X -> X second(tuple t) asm "SECOND"; -;;; Returns the third element of a tuple (with unknown element types). +/// Returns the third element of a tuple (with unknown element types). forall X -> X third(tuple t) asm "THIRD"; -;;; Returns the fourth element of a tuple (with unknown element types). +/// Returns the fourth element of a tuple (with unknown element types). forall X -> X fourth(tuple t) asm "3 INDEX"; -;;; Returns the first element of a pair tuple. +/// Returns the first element of a pair tuple. forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -;;; Returns the second element of a pair tuple. +/// Returns the second element of a pair tuple. forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -;;; Returns the first element of a triple tuple. +/// Returns the first element of a triple tuple. forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -;;; Returns the second element of a triple tuple. +/// Returns the second element of a triple tuple. forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -;;; Returns the third element of a triple tuple. +/// Returns the third element of a triple tuple. forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -;;; Push null element (casted to given type) -;;; By the TVM type `Null` FunC represents absence of a value of some atomic type. -;;; So `null` can actually have any atomic type. +/// Push null element (casted to given type) +/// By the TVM type `Null` FunC represents absence of a value of some atomic type. +/// So `null` can actually have any atomic type. forall X -> X null() asm "PUSHNULL"; -;;; Moves a variable [x] to the top of the stack +/// Moves a variable [x] to the top of the stack forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; -;;; Returns the current Unix time as an Integer +/// Returns the current Unix time as an Integer int now() asm "NOW"; -;;; Returns the internal address of the current smart contract as a Slice with a `MsgAddressInt`. -;;; If necessary, it can be parsed further using primitives such as [parse_std_addr]. +/// Returns the internal address of the current smart contract as a Slice with a `MsgAddressInt`. +/// If necessary, it can be parsed further using primitives such as [parse_std_addr]. slice my_address() asm "MYADDR"; -;;; Returns the balance of the smart contract as a tuple consisting of an int -;;; (balance in nanotoncoins) and a `cell` -;;; (a dictionary with 32-bit keys representing the balance of "extra currencies") -;;; at the start of Computation Phase. -;;; Note that RAW primitives such as [send_raw_message] do not update this field. +/// Returns the balance of the smart contract as a tuple consisting of an int +/// (balance in nanotoncoins) and a `cell` +/// (a dictionary with 32-bit keys representing the balance of "extra currencies") +/// at the start of Computation Phase. +/// Note that RAW primitives such as [send_raw_message] do not update this field. [int, cell] get_balance() asm "BALANCE"; -;;; Returns the logical time of the current transaction. +/// Returns the logical time of the current transaction. int cur_lt() asm "LTIME"; -;;; Returns the starting logical time of the current block. +/// Returns the starting logical time of the current block. int block_lt() asm "BLOCKLT"; -;;; Computes the representation hash of a `cell` [c] and returns it as a 256-bit unsigned integer `x`. -;;; Useful for signing and checking signatures of arbitrary entities represented by a tree of cells. +/// Computes the representation hash of a `cell` [c] and returns it as a 256-bit unsigned integer `x`. +/// Useful for signing and checking signatures of arbitrary entities represented by a tree of cells. int cell_hash(cell c) asm "HASHCU"; -;;; Computes the hash of a `slice s` and returns it as a 256-bit unsigned integer `x`. -;;; The result is the same as if an ordinary cell containing only data and references from `s` had been created -;;; and its hash computed by [cell_hash]. +/// Computes the hash of a `slice s` and returns it as a 256-bit unsigned integer `x`. +/// The result is the same as if an ordinary cell containing only data and references from `s` had been created +/// and its hash computed by [cell_hash]. int slice_hash(slice s) asm "HASHSU"; -;;; Computes sha256 of the data bits of `slice` [s]. If the bit length of `s` is not divisible by eight, -;;; throws a cell underflow exception. The hash value is returned as a 256-bit unsigned integer `x`. +/// Computes sha256 of the data bits of `slice` [s]. If the bit length of `s` is not divisible by eight, +/// throws a cell underflow exception. The hash value is returned as a 256-bit unsigned integer `x`. int string_hash(slice s) asm "SHA256U"; -{- +/* # Signature checks --} - -;;; Checks the Ed25519-`signature` of a `hash` (a 256-bit unsigned integer, usually computed as the hash of some data) -;;; using [public_key] (also represented by a 256-bit unsigned integer). -;;; The signature must contain at least 512 data bits; only the first 512 bits are used. -;;; The result is `−1` if the signature is valid, `0` otherwise. -;;; Note that `CHKSIGNU` creates a 256-bit slice with the hash and calls `CHKSIGNS`. -;;; That is, if [hash] is computed as the hash of some data, these data are hashed twice, -;;; the second hashing occurring inside `CHKSIGNS`. +*/ + +/// Checks the Ed25519-`signature` of a `hash` (a 256-bit unsigned integer, usually computed as the hash of some data) +/// using [public_key] (also represented by a 256-bit unsigned integer). +/// The signature must contain at least 512 data bits; only the first 512 bits are used. +/// The result is `−1` if the signature is valid, `0` otherwise. +/// Note that `CHKSIGNU` creates a 256-bit slice with the hash and calls `CHKSIGNS`. +/// That is, if [hash] is computed as the hash of some data, these data are hashed twice, +/// the second hashing occurring inside `CHKSIGNS`. int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -;;; Checks whether [signature] is a valid Ed25519-signature of the data portion of `slice data` using `public_key`, -;;; similarly to [check_signature]. -;;; If the bit length of [data] is not divisible by eight, throws a cell underflow exception. -;;; The verification of Ed25519 signatures is the standard one, -;;; with sha256 used to reduce [data] to the 256-bit number that is actually signed. +/// Checks whether [signature] is a valid Ed25519-signature of the data portion of `slice data` using `public_key`, +/// similarly to [check_signature]. +/// If the bit length of [data] is not divisible by eight, throws a cell underflow exception. +/// The verification of Ed25519 signatures is the standard one, +/// with sha256 used to reduce [data] to the 256-bit number that is actually signed. int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; -{--- +/*-- # Computation of boc size The primitives below may be useful for computing storage fees of user-provided data. --} - -;;; Returns `(x, y, z, -1)` or `(null, null, null, 0)`. -;;; Recursively computes the count of distinct cells `x`, data bits `y`, and cell references `z` -;;; in the DAG rooted at `cell` [c], effectively returning the total storage used by this DAG taking into account -;;; the identification of equal cells. -;;; The values of `x`, `y`, and `z` are computed by a depth-first traversal of this DAG, -;;; with a hash table of visited cell hashes used to prevent visits of already-visited cells. -;;; The total count of visited cells `x` cannot exceed non-negative [max_cells]; -;;; otherwise the computation is aborted before visiting the `(max_cells + 1)`-st cell and -;;; a zero flag is returned to indicate failure. If [c] is `null`, returns `x = y = z = 0`. +*/ + +/// Returns `(x, y, z, -1)` or `(null, null, null, 0)`. +/// Recursively computes the count of distinct cells `x`, data bits `y`, and cell references `z` +/// in the DAG rooted at `cell` [c], effectively returning the total storage used by this DAG taking into account +/// the identification of equal cells. +/// The values of `x`, `y`, and `z` are computed by a depth-first traversal of this DAG, +/// with a hash table of visited cell hashes used to prevent visits of already-visited cells. +/// The total count of visited cells `x` cannot exceed non-negative [max_cells]; +/// otherwise the computation is aborted before visiting the `(max_cells + 1)`-st cell and +/// a zero flag is returned to indicate failure. If [c] is `null`, returns `x = y = z = 0`. (int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -;;; Similar to [compute_data_size?], but accepting a `slice` [s] instead of a `cell`. -;;; The returned value of `x` does not take into account the cell that contains the `slice` [s] itself; -;;; however, the data bits and the cell references of [s] are accounted for in `y` and `z`. +/// Similar to [compute_data_size?], but accepting a `slice` [s] instead of a `cell`. +/// The returned value of `x` does not take into account the cell that contains the `slice` [s] itself; +/// however, the data bits and the cell references of [s] are accounted for in `y` and `z`. (int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -;;; A non-quiet version of [compute_data_size?] that throws a cell overflow exception (`8`) on failure. +/// A non-quiet version of [compute_data_size?] that throws a cell overflow exception (`8`) on failure. (int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -;;; A non-quiet version of [slice_compute_data_size?] that throws a cell overflow exception (8) on failure. +/// A non-quiet version of [slice_compute_data_size?] that throws a cell overflow exception (8) on failure. (int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -;;; Throws an exception with exit_code excno if cond is not 0 (commented since implemented in compilator) -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; +/// Throws an exception with exit_code excno if cond is not 0 (commented since implemented in compilator) +// () throw_if(int excno, int cond) impure asm "THROWARGIF"; -{-- +/*- # Debug primitives Only works for local TVM execution with debug level verbosity --} -;;; Dumps the stack (at most the top 255 values) and shows the total stack depth. +*/ +/// Dumps the stack (at most the top 255 values) and shows the total stack depth. () dump_stack() impure asm "DUMPSTK"; -{- +/* # Persistent storage save and load --} +*/ -;;; Returns the persistent contract storage cell. It can be parsed or modified with slice and builder primitives later. +/// Returns the persistent contract storage cell. It can be parsed or modified with slice and builder primitives later. cell get_data() asm "c4 PUSH"; -;;; Sets `cell` [c] as persistent contract data. You can update persistent contract storage with this primitive. +/// Sets `cell` [c] as persistent contract data. You can update persistent contract storage with this primitive. () set_data(cell c) impure asm "c4 POP"; -{- +/* # Continuation primitives --} -;;; Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls. -;;; The primitive returns the current value of `c3`. +*/ +/// Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls. +/// The primitive returns the current value of `c3`. cont get_c3() impure asm "c3 PUSH"; -;;; Updates the current value of `c3`. Usually, it is used for updating smart contract code in run-time. -;;; Note that after execution of this primitive the current code -;;; (and the stack of recursive function calls) won't change, -;;; but any other function call will use a function from the new code. +/// Updates the current value of `c3`. Usually, it is used for updating smart contract code in run-time. +/// Note that after execution of this primitive the current code +/// (and the stack of recursive function calls) won't change, +/// but any other function call will use a function from the new code. () set_c3(cont c) impure asm "c3 POP"; -;;; Transforms a `slice` [s] into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist. +/// Transforms a `slice` [s] into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist. cont bless(slice s) impure asm "BLESS"; -{--- +/*-- # Gas related primitives --} - -;;; Sets current gas limit `gl` to its maximal allowed value `gm`, and resets the gas credit `gc` to zero, -;;; decreasing the value of `gr` by `gc` in the process. -;;; In other words, the current smart contract agrees to buy some gas to finish the current transaction. -;;; This action is required to process external messages, which bring no value (hence no gas) with themselves. -;;; -;;; For more details check [accept_message effects](https://ton.org/docs/#/smart-contracts/accept). +*/ + +/// Sets current gas limit `gl` to its maximal allowed value `gm`, and resets the gas credit `gc` to zero, +/// decreasing the value of `gr` by `gc` in the process. +/// In other words, the current smart contract agrees to buy some gas to finish the current transaction. +/// This action is required to process external messages, which bring no value (hence no gas) with themselves. +/// +/// For more details check [accept_message effects](https://ton.org/docs/#/smart-contracts/accept). () accept_message() impure asm "ACCEPT"; -;;; Sets current gas limit `gl` to the minimum of limit and `gm`, and resets the gas credit `gc` to zero. -;;; If the gas consumed so far (including the present instruction) exceeds the resulting value of `gl`, -;;; an (unhandled) out of gas exception is thrown before setting new gas limits. -;;; Notice that [set_gas_limit] with an argument `limit ≥ 2^63 − 1` is equivalent to [accept_message]. +/// Sets current gas limit `gl` to the minimum of limit and `gm`, and resets the gas credit `gc` to zero. +/// If the gas consumed so far (including the present instruction) exceeds the resulting value of `gl`, +/// an (unhandled) out of gas exception is thrown before setting new gas limits. +/// Notice that [set_gas_limit] with an argument `limit ≥ 2^63 − 1` is equivalent to [accept_message]. () set_gas_limit(int limit) impure asm "SETGASLIMIT"; -;;; Commits the current state of registers `c4` (“persistent data”) and `c5` (“actions”) -;;; so that the current execution is considered “successful” with the saved values even if an exception -;;; in Computation Phase is thrown later. +/// Commits the current state of registers `c4` (“persistent data”) and `c5` (“actions”) +/// so that the current execution is considered “successful” with the saved values even if an exception +/// in Computation Phase is thrown later. () commit() impure asm "COMMIT"; -;;; Not implemented -;;() buy_gas(int gram) impure asm "BUYGAS"; +/// Not implemented +//() buy_gas(int gram) impure asm "BUYGAS"; -;;; Computes the amount of gas that can be bought for `amount` nanoTONs, -;;; and sets `gl` accordingly in the same way as [set_gas_limit]. +/// Computes the amount of gas that can be bought for `amount` nanoTONs, +/// and sets `gl` accordingly in the same way as [set_gas_limit]. () buy_gas(int amount) impure asm "BUYGAS"; -;;; Computes the minimum of two integers [x] and [y]. +/// Computes the minimum of two integers [x] and [y]. int min(int x, int y) asm "MIN"; -;;; Computes the maximum of two integers [x] and [y]. +/// Computes the maximum of two integers [x] and [y]. int max(int x, int y) asm "MAX"; -;;; Sorts two integers. +/// Sorts two integers. (int, int) minmax(int x, int y) asm "MINMAX"; -;;; Computes the absolute value of an integer [x]. +/// Computes the absolute value of an integer [x]. int abs(int x) asm "ABS"; -{- +/* # Slice primitives It is said that a primitive _loads_ some data, @@ -273,131 +273,131 @@ int abs(int x) asm "ABS"; (it can be used as [non-modifying method](https://ton.org/docs/#/func/statements?id=non-modifying-methods)). Unless otherwise stated, loading and preloading primitives read the data from a prefix of the slice. --} +*/ -;;; Converts a `cell` [c] into a `slice`. Notice that [c] must be either an ordinary cell, -;;; or an exotic cell (see [TVM.pdf](https://ton-blockchain.github.io/docs/tvm.pdf), 3.1.2) -;;; which is automatically loaded to yield an ordinary cell `c'`, converted into a `slice` afterwards. +/// Converts a `cell` [c] into a `slice`. Notice that [c] must be either an ordinary cell, +/// or an exotic cell (see [TVM.pdf](https://ton-blockchain.github.io/docs/tvm.pdf), 3.1.2) +/// which is automatically loaded to yield an ordinary cell `c'`, converted into a `slice` afterwards. slice begin_parse(cell c) asm "CTOS"; -;;; Checks if [s] is empty. If not, throws an exception. +/// Checks if [s] is empty. If not, throws an exception. () end_parse(slice s) impure asm "ENDS"; -;;; Loads the first reference from the slice. +/// Loads the first reference from the slice. (slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -;;; Preloads the first reference from the slice. +/// Preloads the first reference from the slice. cell preload_ref(slice s) asm "PLDREF"; - {- Functions below are commented because are implemented on compilator level for optimisation -} + /* Functions below are commented because are implemented on compilator level for optimisation */ -;;; Loads a signed [len]-bit integer from a slice [s]. -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; +/// Loads a signed [len]-bit integer from a slice [s]. +// (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;;; Loads an unsigned [len]-bit integer from a slice [s]. -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; +/// Loads an unsigned [len]-bit integer from a slice [s]. +// (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;;; Preloads a signed [len]-bit integer from a slice [s]. -;; int preload_int(slice s, int len) asm "PLDIX"; +/// Preloads a signed [len]-bit integer from a slice [s]. +// int preload_int(slice s, int len) asm "PLDIX"; -;;; Preloads an unsigned [len]-bit integer from a slice [s]. -;; int preload_uint(slice s, int len) asm "PLDUX"; +/// Preloads an unsigned [len]-bit integer from a slice [s]. +// int preload_uint(slice s, int len) asm "PLDUX"; -;;; Loads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; +/// Loads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. +// (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;;; Preloads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; +/// Preloads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. +// slice preload_bits(slice s, int len) asm "PLDSLICEX"; -;;; Loads serialized amount of TonCoins (any unsigned integer up to `2^128 - 1`). +/// Loads serialized amount of TonCoins (any unsigned integer up to `2^128 - 1`). (slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; (slice, int) load_coins(slice s) asm( -> 1 0) "LDGRAMS"; -;;; Returns all but the first `0 ≤ len ≤ 1023` bits of `slice` [s]. +/// Returns all but the first `0 ≤ len ≤ 1023` bits of `slice` [s]. slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; (slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -;;; Returns the first `0 ≤ len ≤ 1023` bits of `slice` [s]. +/// Returns the first `0 ≤ len ≤ 1023` bits of `slice` [s]. slice first_bits(slice s, int len) asm "SDCUTFIRST"; -;;; Returns all but the last `0 ≤ len ≤ 1023` bits of `slice` [s]. +/// Returns all but the last `0 ≤ len ≤ 1023` bits of `slice` [s]. slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; (slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -;;; Returns the last `0 ≤ len ≤ 1023` bits of `slice` [s]. +/// Returns the last `0 ≤ len ≤ 1023` bits of `slice` [s]. slice slice_last(slice s, int len) asm "SDCUTLAST"; -;;; Loads a dictionary `D` (HashMapE) from `slice` [s]. -;;; (returns `null` if `nothing` constructor is used). +/// Loads a dictionary `D` (HashMapE) from `slice` [s]. +/// (returns `null` if `nothing` constructor is used). (slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -;;; Preloads a dictionary `D` from `slice` [s]. +/// Preloads a dictionary `D` from `slice` [s]. cell preload_dict(slice s) asm "PLDDICT"; -;;; Loads a dictionary as [load_dict], but returns only the remainder of the slice. +/// Loads a dictionary as [load_dict], but returns only the remainder of the slice. slice skip_dict(slice s) asm "SKIPDICT"; -;;; Loads (Maybe ^Cell) from `slice` [s]. -;;; In other words loads 1 bit and if it is true -;;; loads first ref and return it with slice remainder -;;; otherwise returns `null` and slice remainder +/// Loads (Maybe ^Cell) from `slice` [s]. +/// In other words loads 1 bit and if it is true +/// loads first ref and return it with slice remainder +/// otherwise returns `null` and slice remainder (slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -;;; Preloads (Maybe ^Cell) from `slice` [s]. +/// Preloads (Maybe ^Cell) from `slice` [s]. cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -;;; Returns the depth of `cell` [c]. -;;; If [c] has no references, then return `0`; -;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [c]. -;;; If [c] is a `null` instead of a cell, returns zero. +/// Returns the depth of `cell` [c]. +/// If [c] has no references, then return `0`; +/// otherwise the returned value is one plus the maximum of depths of cells referred to from [c]. +/// If [c] is a `null` instead of a cell, returns zero. int cell_depth(cell c) asm "CDEPTH"; -{- +/* # Slice size primitives --} +*/ -;;; Returns the number of references in `slice` [s]. +/// Returns the number of references in `slice` [s]. int slice_refs(slice s) asm "SREFS"; -;;; Returns the number of data bits in `slice` [s]. +/// Returns the number of data bits in `slice` [s]. int slice_bits(slice s) asm "SBITS"; -;;; Returns both the number of data bits and the number of references in `slice` [s]. +/// Returns both the number of data bits and the number of references in `slice` [s]. (int, int) slice_bits_refs(slice s) asm "SBITREFS"; -;;; Checks whether a `slice` [s] is empty (i.e., contains no bits of data and no cell references). +/// Checks whether a `slice` [s] is empty (i.e., contains no bits of data and no cell references). int slice_empty?(slice s) asm "SEMPTY"; -;;; Checks whether `slice` [s] has no bits of data. +/// Checks whether `slice` [s] has no bits of data. int slice_data_empty?(slice s) asm "SDEMPTY"; -;;; Checks whether `slice` [s] has no references. +/// Checks whether `slice` [s] has no references. int slice_refs_empty?(slice s) asm "SREMPTY"; -;;; Returns the depth of `slice` [s]. -;;; If [s] has no references, then returns `0`; -;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [s]. +/// Returns the depth of `slice` [s]. +/// If [s] has no references, then returns `0`; +/// otherwise the returned value is one plus the maximum of depths of cells referred to from [s]. int slice_depth(slice s) asm "SDEPTH"; -{- +/* # Builder size primitives --} +*/ -;;; Returns the number of cell references already stored in `builder` [b] +/// Returns the number of cell references already stored in `builder` [b] int builder_refs(builder b) asm "BREFS"; -;;; Returns the number of data bits already stored in `builder` [b]. +/// Returns the number of data bits already stored in `builder` [b]. int builder_bits(builder b) asm "BBITS"; -;;; Returns the depth of `builder` [b]. -;;; If no cell references are stored in [b], then returns 0; -;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [b]. +/// Returns the depth of `builder` [b]. +/// If no cell references are stored in [b], then returns 0; +/// otherwise the returned value is one plus the maximum of depths of cells referred to from [b]. int builder_depth(builder b) asm "BDEPTH"; -{- +/* # Builder primitives It is said that a primitive _stores_ a value `x` into a builder `b` if it returns a modified version of the builder `b'` with the value `x` stored at the end of it. @@ -405,48 +405,48 @@ int builder_depth(builder b) asm "BDEPTH"; All the primitives below first check whether there is enough space in the `builder`, and only then check the range of the value being serialized. --} +*/ -;;; Creates a new empty `builder`. +/// Creates a new empty `builder`. builder begin_cell() asm "NEWC"; -;;; Converts a `builder` into an ordinary `cell`. +/// Converts a `builder` into an ordinary `cell`. cell end_cell(builder b) asm "ENDC"; -;;; Stores a reference to `cell` [c] into `builder` [b]. +/// Stores a reference to `cell` [c] into `builder` [b]. builder store_ref(builder b, cell c) asm(c b) "STREF"; -;;; Stores an unsigned [len]-bit integer `x` into `b` for `0 ≤ len ≤ 256`. -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; +/// Stores an unsigned [len]-bit integer `x` into `b` for `0 ≤ len ≤ 256`. +// builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;;; Stores a signed [len]-bit integer `x` into `b` for` 0 ≤ len ≤ 257`. -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; +/// Stores a signed [len]-bit integer `x` into `b` for` 0 ≤ len ≤ 257`. +// builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -;;; Stores `slice` [s] into `builder` [b] +/// Stores `slice` [s] into `builder` [b] builder store_slice(builder b, slice s) asm "STSLICER"; -;;; Stores (serializes) an integer [x] in the range `0..2^128 − 1` into `builder` [b]. -;;; The serialization of [x] consists of a 4-bit unsigned big-endian integer `l`, -;;; which is the smallest integer `l ≥ 0`, such that `x < 2^8l`, -;;; followed by an `8l`-bit unsigned big-endian representation of [x]. -;;; If [x] does not belong to the supported range, a range check exception is thrown. -;;; -;;; Store amounts of TonCoins to the builder as VarUInteger 16 +/// Stores (serializes) an integer [x] in the range `0..2^128 − 1` into `builder` [b]. +/// The serialization of [x] consists of a 4-bit unsigned big-endian integer `l`, +/// which is the smallest integer `l ≥ 0`, such that `x < 2^8l`, +/// followed by an `8l`-bit unsigned big-endian representation of [x]. +/// If [x] does not belong to the supported range, a range check exception is thrown. +/// +/// Store amounts of TonCoins to the builder as VarUInteger 16 builder store_grams(builder b, int x) asm "STGRAMS"; builder store_coins(builder b, int x) asm "STGRAMS"; -;;; Stores dictionary `D` represented by `cell` [c] or `null` into `builder` [b]. -;;; In other words, stores a `1`-bit and a reference to [c] if [c] is not `null` and `0`-bit otherwise. +/// Stores dictionary `D` represented by `cell` [c] or `null` into `builder` [b]. +/// In other words, stores a `1`-bit and a reference to [c] if [c] is not `null` and `0`-bit otherwise. builder store_dict(builder b, cell c) asm(c b) "STDICT"; -;;; Stores (Maybe ^Cell) to builder: -;;; if cell is null store 1 zero bit -;;; otherwise store 1 true bit and ref to cell +/// Stores (Maybe ^Cell) to builder: +/// if cell is null store 1 zero bit +/// otherwise store 1 true bit and ref to cell builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; -{- +/* # Address manipulation primitives The address manipulation primitives listed below serialize and deserialize values according to the following TL-B scheme: ```TL-B @@ -481,39 +481,39 @@ builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; Next, integer `x` is the `workchain_id`, and slice `s` contains the address. - `addr_var` is represented by `t = (3, u, x, s)`, where `u`, `x`, and `s` have the same meaning as for `addr_std`. --} +*/ -;;; Loads from slice [s] the only prefix that is a valid `MsgAddress`, -;;; and returns both this prefix `s'` and the remainder `s''` of [s] as slices. +/// Loads from slice [s] the only prefix that is a valid `MsgAddress`, +/// and returns both this prefix `s'` and the remainder `s''` of [s] as slices. (slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -;;; Decomposes slice [s] containing a valid `MsgAddress` into a `tuple t` with separate fields of this `MsgAddress`. -;;; If [s] is not a valid `MsgAddress`, a cell deserialization exception is thrown. +/// Decomposes slice [s] containing a valid `MsgAddress` into a `tuple t` with separate fields of this `MsgAddress`. +/// If [s] is not a valid `MsgAddress`, a cell deserialization exception is thrown. tuple parse_addr(slice s) asm "PARSEMSGADDR"; -;;; Parses slice [s] containing a valid `MsgAddressInt` (usually a `msg_addr_std`), -;;; applies rewriting from the anycast (if present) to the same-length prefix of the address, -;;; and returns both the workchain and the 256-bit address as integers. -;;; If the address is not 256-bit, or if [s] is not a valid serialization of `MsgAddressInt`, -;;; throws a cell deserialization exception. +/// Parses slice [s] containing a valid `MsgAddressInt` (usually a `msg_addr_std`), +/// applies rewriting from the anycast (if present) to the same-length prefix of the address, +/// and returns both the workchain and the 256-bit address as integers. +/// If the address is not 256-bit, or if [s] is not a valid serialization of `MsgAddressInt`, +/// throws a cell deserialization exception. (int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -;;; A variant of [parse_std_addr] that returns the (rewritten) address as a slice [s], -;;; even if it is not exactly 256 bit long (represented by a `msg_addr_var`). +/// A variant of [parse_std_addr] that returns the (rewritten) address as a slice [s], +/// even if it is not exactly 256 bit long (represented by a `msg_addr_var`). (int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; -{- +/* # Dictionary primitives --} +*/ -;;; Sets the value associated with [key_len]-bit key signed index in dictionary [dict] to [value] (cell), -;;; and returns the resulting dictionary. +/// Sets the value associated with [key_len]-bit key signed index in dictionary [dict] to [value] (cell), +/// and returns the resulting dictionary. cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; (cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -;;; Sets the value associated with [key_len]-bit key unsigned index in dictionary [dict] to [value] (cell), -;;; and returns the resulting dictionary. +/// Sets the value associated with [key_len]-bit key unsigned index in dictionary [dict] to [value] (cell), +/// and returns the resulting dictionary. cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; (cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; @@ -579,47 +579,47 @@ cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(va (int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; (int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -;;; Creates an empty dictionary, which is actually a null value. Equivalent to PUSHNULL +/// Creates an empty dictionary, which is actually a null value. Equivalent to PUSHNULL cell new_dict() asm "NEWDICT"; -;;; Checks whether a dictionary is empty. Equivalent to cell_null?. +/// Checks whether a dictionary is empty. Equivalent to cell_null?. int dict_empty?(cell c) asm "DICTEMPTY"; -{- Prefix dictionary primitives -} +/* Prefix dictionary primitives */ (slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; (cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; (cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; -;;; Returns the value of the global configuration parameter with integer index `i` as a `cell` or `null` value. +/// Returns the value of the global configuration parameter with integer index `i` as a `cell` or `null` value. cell config_param(int x) asm "CONFIGOPTPARAM"; -;;; Checks whether c is a null. Note, that FunC also has polymorphic null? built-in. +/// Checks whether c is a null. Note, that FunC also has polymorphic null? built-in. int cell_null?(cell c) asm "ISNULL"; -;;; Creates an output action which would reserve exactly amount nanotoncoins (if mode = 0), at most amount nanotoncoins (if mode = 2), or all but amount nanotoncoins (if mode = 1 or mode = 3), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carrying amount nanotoncoins (or b − amount nanotoncoins, where b is the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit +2 in mode means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit +8 in mode means `amount <- -amount` before performing any further actions. Bit +4 in mode means that amount is increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currently, amount must be a non-negative integer, and mode must be in the range 0..15. +/// Creates an output action which would reserve exactly amount nanotoncoins (if mode = 0), at most amount nanotoncoins (if mode = 2), or all but amount nanotoncoins (if mode = 1 or mode = 3), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carrying amount nanotoncoins (or b − amount nanotoncoins, where b is the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit +2 in mode means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit +8 in mode means `amount <- -amount` before performing any further actions. Bit +4 in mode means that amount is increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currently, amount must be a non-negative integer, and mode must be in the range 0..15. () raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -;;; Similar to raw_reserve, but also accepts a dictionary extra_amount (represented by a cell or null) with extra currencies. In this way currencies other than TonCoin can be reserved. +/// Similar to raw_reserve, but also accepts a dictionary extra_amount (represented by a cell or null) with extra currencies. In this way currencies other than TonCoin can be reserved. () raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -;;; Sends a raw message contained in msg, which should contain a correctly serialized object Message X, with the only exception that the source address is allowed to have dummy value addr_none (to be automatically replaced with the current smart contract address), and ihr_fee, fwd_fee, created_lt and created_at fields can have arbitrary values (to be rewritten with correct values during the action phase of the current transaction). Integer parameter mode contains the flags. Currently mode = 0 is used for ordinary messages; mode = 128 is used for messages that are to carry all the remaining balance of the current smart contract (instead of the value originally indicated in the message); mode = 64 is used for messages that carry all the remaining value of the inbound message in addition to the value initially indicated in the new message (if bit 0 is not set, the gas fees are deducted from this amount); mode' = mode + 1 means that the sender wants to pay transfer fees separately; mode' = mode + 2 means that any errors arising while processing this message during the action phase should be ignored. Finally, mode' = mode + 32 means that the current account must be destroyed if its resulting balance is zero. This flag is usually employed together with +128. +/// Sends a raw message contained in msg, which should contain a correctly serialized object Message X, with the only exception that the source address is allowed to have dummy value addr_none (to be automatically replaced with the current smart contract address), and ihr_fee, fwd_fee, created_lt and created_at fields can have arbitrary values (to be rewritten with correct values during the action phase of the current transaction). Integer parameter mode contains the flags. Currently mode = 0 is used for ordinary messages; mode = 128 is used for messages that are to carry all the remaining balance of the current smart contract (instead of the value originally indicated in the message); mode = 64 is used for messages that carry all the remaining value of the inbound message in addition to the value initially indicated in the new message (if bit 0 is not set, the gas fees are deducted from this amount); mode' = mode + 1 means that the sender wants to pay transfer fees separately; mode' = mode + 2 means that any errors arising while processing this message during the action phase should be ignored. Finally, mode' = mode + 32 means that the current account must be destroyed if its resulting balance is zero. This flag is usually employed together with +128. () send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -;;; Creates an output action that would change this smart contract code to that given by cell new_code. Notice that this change will take effect only after the successful termination of the current run of the smart contract +/// Creates an output action that would change this smart contract code to that given by cell new_code. Notice that this change will take effect only after the successful termination of the current run of the smart contract () set_code(cell new_code) impure asm "SETCODE"; -;;; Generates a new pseudo-random unsigned 256-bit integer x. The algorithm is as follows: if r is the old value of the random seed, considered as a 32-byte array (by constructing the big-endian representation of an unsigned 256-bit integer), then its sha512(r) is computed; the first 32 bytes of this hash are stored as the new value r' of the random seed, and the remaining 32 bytes are returned as the next random value x. +/// Generates a new pseudo-random unsigned 256-bit integer x. The algorithm is as follows: if r is the old value of the random seed, considered as a 32-byte array (by constructing the big-endian representation of an unsigned 256-bit integer), then its sha512(r) is computed; the first 32 bytes of this hash are stored as the new value r' of the random seed, and the remaining 32 bytes are returned as the next random value x. int random() impure asm "RANDU256"; -;;; Generates a new pseudo-random integer z in the range 0..range−1 (or range..−1, if range < 0). More precisely, an unsigned random value x is generated as in random; then z := x * range / 2^256 is computed. +/// Generates a new pseudo-random integer z in the range 0..range−1 (or range..−1, if range < 0). More precisely, an unsigned random value x is generated as in random; then z := x * range / 2^256 is computed. int rand(int range) impure asm "RAND"; -;;; Returns the current random seed as an unsigned 256-bit Integer. +/// Returns the current random seed as an unsigned 256-bit Integer. int get_seed() impure asm "RANDSEED"; -;;; Sets the random seed to unsigned 256-bit seed. +/// Sets the random seed to unsigned 256-bit seed. () set_seed(int) impure asm "SETRAND"; -;;; Mixes unsigned 256-bit integer x into the random seed r by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed r, and the second with the big-endian representation of x. +/// Mixes unsigned 256-bit integer x into the random seed r by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed r, and the second with the big-endian representation of x. () randomize(int x) impure asm "ADDRAND"; -;;; Equivalent to randomize(cur_lt());. +/// Equivalent to randomize(cur_lt());. () randomize_lt() impure asm "LTIME" "ADDRAND"; -;;; Checks whether the data parts of two slices coinside +/// Checks whether the data parts of two slices coinside int equal_slice_bits (slice a, slice b) asm "SDEQ"; -;;; Concatenates two builders +/// Concatenates two builders builder store_builder(builder to, builder from) asm "STBR"; diff --git a/crypto/func/auto-tests/tests/comments.fc b/crypto/func/auto-tests/tests/comments.fc index 24ff0102f..5c95f6c2b 100644 --- a/crypto/func/auto-tests/tests/comments.fc +++ b/crypto/func/auto-tests/tests/comments.fc @@ -22,7 +22,7 @@ int {- */ } -/* +/*** first line //* nested //two-lined*/ diff --git a/crypto/smartcont/stdlib.fc b/crypto/smartcont/stdlib.fc index 978b94738..7049c6fb1 100644 --- a/crypto/smartcont/stdlib.fc +++ b/crypto/smartcont/stdlib.fc @@ -1,7 +1,7 @@ -;; Standard library for funC -;; +// Standard library for funC +// -{- +/* This file is part of TON FunC Standard Library. FunC Standard Library is free software: you can redistribute it and/or modify @@ -14,9 +14,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. --} +*/ -{- +/* # Tuple manipulation primitives The names and the types are mostly self-explaining. See [polymorhism with forall](https://ton.org/docs/#/func/functions?id=polymorphism-with-forall) @@ -24,260 +24,260 @@ Note that currently values of atomic type `tuple` can't be cast to composite tuple type (e.g. `[int, cell]`) and vise versa. --} +*/ -{- +/* # Lisp-style lists Lists can be represented as nested 2-elements tuples. Empty list is conventionally represented as TVM `null` value (it can be obtained by calling [null()]). For example, tuple `(1, (2, (3, null)))` represents list `[1, 2, 3]`. Elements of a list can be of different types. --} +*/ -;;; Adds an element to the beginning of lisp-style list. +/// Adds an element to the beginning of lisp-style list. forall X -> tuple cons(X head, tuple tail) asm "CONS"; -;;; Extracts the head and the tail of lisp-style list. +/// Extracts the head and the tail of lisp-style list. forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -;;; Extracts the tail and the head of lisp-style list. +/// Extracts the tail and the head of lisp-style list. forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -;;; Returns the head of lisp-style list. +/// Returns the head of lisp-style list. forall X -> X car(tuple list) asm "CAR"; -;;; Returns the tail of lisp-style list. +/// Returns the tail of lisp-style list. tuple cdr(tuple list) asm "CDR"; -;;; Creates tuple with zero elements. +/// Creates tuple with zero elements. tuple empty_tuple() asm "NIL"; -;;; Appends a value `x` to a `Tuple t = (x1, ..., xn)`, but only if the resulting `Tuple t' = (x1, ..., xn, x)` -;;; is of length at most 255. Otherwise throws a type check exception. +/// Appends a value `x` to a `Tuple t = (x1, ..., xn)`, but only if the resulting `Tuple t' = (x1, ..., xn, x)` +/// is of length at most 255. Otherwise throws a type check exception. forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -;;; Creates a tuple of length one with given argument as element. +/// Creates a tuple of length one with given argument as element. forall X -> [X] single(X x) asm "SINGLE"; -;;; Unpacks a tuple of length one +/// Unpacks a tuple of length one forall X -> X unsingle([X] t) asm "UNSINGLE"; -;;; Creates a tuple of length two with given arguments as elements. +/// Creates a tuple of length two with given arguments as elements. forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -;;; Unpacks a tuple of length two +/// Unpacks a tuple of length two forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -;;; Creates a tuple of length three with given arguments as elements. +/// Creates a tuple of length three with given arguments as elements. forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -;;; Unpacks a tuple of length three +/// Unpacks a tuple of length three forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -;;; Creates a tuple of length four with given arguments as elements. +/// Creates a tuple of length four with given arguments as elements. forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -;;; Unpacks a tuple of length four +/// Unpacks a tuple of length four forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -;;; Returns the first element of a tuple (with unknown element types). +/// Returns the first element of a tuple (with unknown element types). forall X -> X first(tuple t) asm "FIRST"; -;;; Returns the second element of a tuple (with unknown element types). +/// Returns the second element of a tuple (with unknown element types). forall X -> X second(tuple t) asm "SECOND"; -;;; Returns the third element of a tuple (with unknown element types). +/// Returns the third element of a tuple (with unknown element types). forall X -> X third(tuple t) asm "THIRD"; -;;; Returns the fourth element of a tuple (with unknown element types). +/// Returns the fourth element of a tuple (with unknown element types). forall X -> X fourth(tuple t) asm "3 INDEX"; -;;; Returns the first element of a pair tuple. +/// Returns the first element of a pair tuple. forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -;;; Returns the second element of a pair tuple. +/// Returns the second element of a pair tuple. forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -;;; Returns the first element of a triple tuple. +/// Returns the first element of a triple tuple. forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -;;; Returns the second element of a triple tuple. +/// Returns the second element of a triple tuple. forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -;;; Returns the third element of a triple tuple. +/// Returns the third element of a triple tuple. forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -;;; Push null element (casted to given type) -;;; By the TVM type `Null` FunC represents absence of a value of some atomic type. -;;; So `null` can actually have any atomic type. +/// Push null element (casted to given type) +/// By the TVM type `Null` FunC represents absence of a value of some atomic type. +/// So `null` can actually have any atomic type. forall X -> X null() asm "PUSHNULL"; -;;; Moves a variable [x] to the top of the stack +/// Moves a variable [x] to the top of the stack forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; -;;; Returns the current Unix time as an Integer +/// Returns the current Unix time as an Integer int now() asm "NOW"; -;;; Returns the internal address of the current smart contract as a Slice with a `MsgAddressInt`. -;;; If necessary, it can be parsed further using primitives such as [parse_std_addr]. +/// Returns the internal address of the current smart contract as a Slice with a `MsgAddressInt`. +/// If necessary, it can be parsed further using primitives such as [parse_std_addr]. slice my_address() asm "MYADDR"; -;;; Returns the balance of the smart contract as a tuple consisting of an int -;;; (balance in nanotoncoins) and a `cell` -;;; (a dictionary with 32-bit keys representing the balance of "extra currencies") -;;; at the start of Computation Phase. -;;; Note that RAW primitives such as [send_raw_message] do not update this field. +/// Returns the balance of the smart contract as a tuple consisting of an int +/// (balance in nanotoncoins) and a `cell` +/// (a dictionary with 32-bit keys representing the balance of "extra currencies") +/// at the start of Computation Phase. +/// Note that RAW primitives such as [send_raw_message] do not update this field. [int, cell] get_balance() asm "BALANCE"; -;;; Returns the logical time of the current transaction. +/// Returns the logical time of the current transaction. int cur_lt() asm "LTIME"; -;;; Returns the starting logical time of the current block. +/// Returns the starting logical time of the current block. int block_lt() asm "BLOCKLT"; -;;; Computes the representation hash of a `cell` [c] and returns it as a 256-bit unsigned integer `x`. -;;; Useful for signing and checking signatures of arbitrary entities represented by a tree of cells. +/// Computes the representation hash of a `cell` [c] and returns it as a 256-bit unsigned integer `x`. +/// Useful for signing and checking signatures of arbitrary entities represented by a tree of cells. int cell_hash(cell c) asm "HASHCU"; -;;; Computes the hash of a `slice s` and returns it as a 256-bit unsigned integer `x`. -;;; The result is the same as if an ordinary cell containing only data and references from `s` had been created -;;; and its hash computed by [cell_hash]. +/// Computes the hash of a `slice s` and returns it as a 256-bit unsigned integer `x`. +/// The result is the same as if an ordinary cell containing only data and references from `s` had been created +/// and its hash computed by [cell_hash]. int slice_hash(slice s) asm "HASHSU"; -;;; Computes sha256 of the data bits of `slice` [s]. If the bit length of `s` is not divisible by eight, -;;; throws a cell underflow exception. The hash value is returned as a 256-bit unsigned integer `x`. +/// Computes sha256 of the data bits of `slice` [s]. If the bit length of `s` is not divisible by eight, +/// throws a cell underflow exception. The hash value is returned as a 256-bit unsigned integer `x`. int string_hash(slice s) asm "SHA256U"; -{- +/* # Signature checks --} - -;;; Checks the Ed25519-`signature` of a `hash` (a 256-bit unsigned integer, usually computed as the hash of some data) -;;; using [public_key] (also represented by a 256-bit unsigned integer). -;;; The signature must contain at least 512 data bits; only the first 512 bits are used. -;;; The result is `−1` if the signature is valid, `0` otherwise. -;;; Note that `CHKSIGNU` creates a 256-bit slice with the hash and calls `CHKSIGNS`. -;;; That is, if [hash] is computed as the hash of some data, these data are hashed twice, -;;; the second hashing occurring inside `CHKSIGNS`. +*/ + +/// Checks the Ed25519-`signature` of a `hash` (a 256-bit unsigned integer, usually computed as the hash of some data) +/// using [public_key] (also represented by a 256-bit unsigned integer). +/// The signature must contain at least 512 data bits; only the first 512 bits are used. +/// The result is `−1` if the signature is valid, `0` otherwise. +/// Note that `CHKSIGNU` creates a 256-bit slice with the hash and calls `CHKSIGNS`. +/// That is, if [hash] is computed as the hash of some data, these data are hashed twice, +/// the second hashing occurring inside `CHKSIGNS`. int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -;;; Checks whether [signature] is a valid Ed25519-signature of the data portion of `slice data` using `public_key`, -;;; similarly to [check_signature]. -;;; If the bit length of [data] is not divisible by eight, throws a cell underflow exception. -;;; The verification of Ed25519 signatures is the standard one, -;;; with sha256 used to reduce [data] to the 256-bit number that is actually signed. +/// Checks whether [signature] is a valid Ed25519-signature of the data portion of `slice data` using `public_key`, +/// similarly to [check_signature]. +/// If the bit length of [data] is not divisible by eight, throws a cell underflow exception. +/// The verification of Ed25519 signatures is the standard one, +/// with sha256 used to reduce [data] to the 256-bit number that is actually signed. int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; -{--- +/*** # Computation of boc size The primitives below may be useful for computing storage fees of user-provided data. --} - -;;; Returns `(x, y, z, -1)` or `(null, null, null, 0)`. -;;; Recursively computes the count of distinct cells `x`, data bits `y`, and cell references `z` -;;; in the DAG rooted at `cell` [c], effectively returning the total storage used by this DAG taking into account -;;; the identification of equal cells. -;;; The values of `x`, `y`, and `z` are computed by a depth-first traversal of this DAG, -;;; with a hash table of visited cell hashes used to prevent visits of already-visited cells. -;;; The total count of visited cells `x` cannot exceed non-negative [max_cells]; -;;; otherwise the computation is aborted before visiting the `(max_cells + 1)`-st cell and -;;; a zero flag is returned to indicate failure. If [c] is `null`, returns `x = y = z = 0`. +*/ + +/// Returns `(x, y, z, -1)` or `(null, null, null, 0)`. +/// Recursively computes the count of distinct cells `x`, data bits `y`, and cell references `z` +/// in the DAG rooted at `cell` [c], effectively returning the total storage used by this DAG taking into account +/// the identification of equal cells. +/// The values of `x`, `y`, and `z` are computed by a depth-first traversal of this DAG, +/// with a hash table of visited cell hashes used to prevent visits of already-visited cells. +/// The total count of visited cells `x` cannot exceed non-negative [max_cells]; +/// otherwise the computation is aborted before visiting the `(max_cells + 1)`-st cell and +/// a zero flag is returned to indicate failure. If [c] is `null`, returns `x = y = z = 0`. (int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -;;; Similar to [compute_data_size?], but accepting a `slice` [s] instead of a `cell`. -;;; The returned value of `x` does not take into account the cell that contains the `slice` [s] itself; -;;; however, the data bits and the cell references of [s] are accounted for in `y` and `z`. +/// Similar to [compute_data_size?], but accepting a `slice` [s] instead of a `cell`. +/// The returned value of `x` does not take into account the cell that contains the `slice` [s] itself; +/// however, the data bits and the cell references of [s] are accounted for in `y` and `z`. (int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -;;; A non-quiet version of [compute_data_size?] that throws a cell overflow exception (`8`) on failure. +/// A non-quiet version of [compute_data_size?] that throws a cell overflow exception (`8`) on failure. (int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -;;; A non-quiet version of [slice_compute_data_size?] that throws a cell overflow exception (8) on failure. +/// A non-quiet version of [slice_compute_data_size?] that throws a cell overflow exception (8) on failure. (int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -;;; Throws an exception with exit_code excno if cond is not 0 (commented since implemented in compilator) -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; +/// Throws an exception with exit_code excno if cond is not 0 (commented since implemented in compilator) +// () throw_if(int excno, int cond) impure asm "THROWARGIF"; -{-- +/*** # Debug primitives Only works for local TVM execution with debug level verbosity --} -;;; Dumps the stack (at most the top 255 values) and shows the total stack depth. +*/ +/// Dumps the stack (at most the top 255 values) and shows the total stack depth. () dump_stack() impure asm "DUMPSTK"; -{- +/* # Persistent storage save and load --} +*/ -;;; Returns the persistent contract storage cell. It can be parsed or modified with slice and builder primitives later. +/// Returns the persistent contract storage cell. It can be parsed or modified with slice and builder primitives later. cell get_data() asm "c4 PUSH"; -;;; Sets `cell` [c] as persistent contract data. You can update persistent contract storage with this primitive. +/// Sets `cell` [c] as persistent contract data. You can update persistent contract storage with this primitive. () set_data(cell c) impure asm "c4 POP"; -{- +/* # Continuation primitives --} -;;; Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls. -;;; The primitive returns the current value of `c3`. +*/ +/// Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls. +/// The primitive returns the current value of `c3`. cont get_c3() impure asm "c3 PUSH"; -;;; Updates the current value of `c3`. Usually, it is used for updating smart contract code in run-time. -;;; Note that after execution of this primitive the current code -;;; (and the stack of recursive function calls) won't change, -;;; but any other function call will use a function from the new code. +/// Updates the current value of `c3`. Usually, it is used for updating smart contract code in run-time. +/// Note that after execution of this primitive the current code +/// (and the stack of recursive function calls) won't change, +/// but any other function call will use a function from the new code. () set_c3(cont c) impure asm "c3 POP"; -;;; Transforms a `slice` [s] into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist. +/// Transforms a `slice` [s] into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist. cont bless(slice s) impure asm "BLESS"; -{--- +/*** # Gas related primitives --} - -;;; Sets current gas limit `gl` to its maximal allowed value `gm`, and resets the gas credit `gc` to zero, -;;; decreasing the value of `gr` by `gc` in the process. -;;; In other words, the current smart contract agrees to buy some gas to finish the current transaction. -;;; This action is required to process external messages, which bring no value (hence no gas) with themselves. -;;; -;;; For more details check [accept_message effects](https://ton.org/docs/#/smart-contracts/accept). +*/ + +/// Sets current gas limit `gl` to its maximal allowed value `gm`, and resets the gas credit `gc` to zero, +/// decreasing the value of `gr` by `gc` in the process. +/// In other words, the current smart contract agrees to buy some gas to finish the current transaction. +/// This action is required to process external messages, which bring no value (hence no gas) with themselves. +/// +/// For more details check [accept_message effects](https://ton.org/docs/#/smart-contracts/accept). () accept_message() impure asm "ACCEPT"; -;;; Sets current gas limit `gl` to the minimum of limit and `gm`, and resets the gas credit `gc` to zero. -;;; If the gas consumed so far (including the present instruction) exceeds the resulting value of `gl`, -;;; an (unhandled) out of gas exception is thrown before setting new gas limits. -;;; Notice that [set_gas_limit] with an argument `limit ≥ 2^63 − 1` is equivalent to [accept_message]. +/// Sets current gas limit `gl` to the minimum of limit and `gm`, and resets the gas credit `gc` to zero. +/// If the gas consumed so far (including the present instruction) exceeds the resulting value of `gl`, +/// an (unhandled) out of gas exception is thrown before setting new gas limits. +/// Notice that [set_gas_limit] with an argument `limit ≥ 2^63 − 1` is equivalent to [accept_message]. () set_gas_limit(int limit) impure asm "SETGASLIMIT"; -;;; Commits the current state of registers `c4` (“persistent data”) and `c5` (“actions”) -;;; so that the current execution is considered “successful” with the saved values even if an exception -;;; in Computation Phase is thrown later. +/// Commits the current state of registers `c4` (“persistent data”) and `c5` (“actions”) +/// so that the current execution is considered “successful” with the saved values even if an exception +/// in Computation Phase is thrown later. () commit() impure asm "COMMIT"; -;;; Not implemented -;;() buy_gas(int gram) impure asm "BUYGAS"; +/// Not implemented +//() buy_gas(int gram) impure asm "BUYGAS"; -;;; Computes the amount of gas that can be bought for `amount` nanoTONs, -;;; and sets `gl` accordingly in the same way as [set_gas_limit]. +/// Computes the amount of gas that can be bought for `amount` nanoTONs, +/// and sets `gl` accordingly in the same way as [set_gas_limit]. () buy_gas(int amount) impure asm "BUYGAS"; -;;; Computes the minimum of two integers [x] and [y]. +/// Computes the minimum of two integers [x] and [y]. int min(int x, int y) asm "MIN"; -;;; Computes the maximum of two integers [x] and [y]. +/// Computes the maximum of two integers [x] and [y]. int max(int x, int y) asm "MAX"; -;;; Sorts two integers. +/// Sorts two integers. (int, int) minmax(int x, int y) asm "MINMAX"; -;;; Computes the absolute value of an integer [x]. +/// Computes the absolute value of an integer [x]. int abs(int x) asm "ABS"; -{- +/* # Slice primitives It is said that a primitive _loads_ some data, @@ -288,131 +288,131 @@ int abs(int x) asm "ABS"; (it can be used as [non-modifying method](https://ton.org/docs/#/func/statements?id=non-modifying-methods)). Unless otherwise stated, loading and preloading primitives read the data from a prefix of the slice. --} +*/ -;;; Converts a `cell` [c] into a `slice`. Notice that [c] must be either an ordinary cell, -;;; or an exotic cell (see [TVM.pdf](https://ton-blockchain.github.io/docs/tvm.pdf), 3.1.2) -;;; which is automatically loaded to yield an ordinary cell `c'`, converted into a `slice` afterwards. +/// Converts a `cell` [c] into a `slice`. Notice that [c] must be either an ordinary cell, +/// or an exotic cell (see [TVM.pdf](https://ton-blockchain.github.io/docs/tvm.pdf), 3.1.2) +/// which is automatically loaded to yield an ordinary cell `c'`, converted into a `slice` afterwards. slice begin_parse(cell c) asm "CTOS"; -;;; Checks if [s] is empty. If not, throws an exception. +/// Checks if [s] is empty. If not, throws an exception. () end_parse(slice s) impure asm "ENDS"; -;;; Loads the first reference from the slice. +/// Loads the first reference from the slice. (slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -;;; Preloads the first reference from the slice. +/// Preloads the first reference from the slice. cell preload_ref(slice s) asm "PLDREF"; - {- Functions below are commented because are implemented on compilator level for optimisation -} + /* Functions below are commented because are implemented on compilator level for optimisation */ -;;; Loads a signed [len]-bit integer from a slice [s]. -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; +/// Loads a signed [len]-bit integer from a slice [s]. +// (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;;; Loads an unsigned [len]-bit integer from a slice [s]. -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; +/// Loads an unsigned [len]-bit integer from a slice [s]. +// (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;;; Preloads a signed [len]-bit integer from a slice [s]. -;; int preload_int(slice s, int len) asm "PLDIX"; +/// Preloads a signed [len]-bit integer from a slice [s]. +// int preload_int(slice s, int len) asm "PLDIX"; -;;; Preloads an unsigned [len]-bit integer from a slice [s]. -;; int preload_uint(slice s, int len) asm "PLDUX"; +/// Preloads an unsigned [len]-bit integer from a slice [s]. +// int preload_uint(slice s, int len) asm "PLDUX"; -;;; Loads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; +/// Loads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. +// (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;;; Preloads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; +/// Preloads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. +// slice preload_bits(slice s, int len) asm "PLDSLICEX"; -;;; Loads serialized amount of TonCoins (any unsigned integer up to `2^120 - 1`). +/// Loads serialized amount of TonCoins (any unsigned integer up to `2^120 - 1`). (slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; (slice, int) load_coins(slice s) asm( -> 1 0) "LDGRAMS"; -;;; Returns all but the first `0 ≤ len ≤ 1023` bits of `slice` [s]. +/// Returns all but the first `0 ≤ len ≤ 1023` bits of `slice` [s]. slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; (slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -;;; Returns the first `0 ≤ len ≤ 1023` bits of `slice` [s]. +/// Returns the first `0 ≤ len ≤ 1023` bits of `slice` [s]. slice first_bits(slice s, int len) asm "SDCUTFIRST"; -;;; Returns all but the last `0 ≤ len ≤ 1023` bits of `slice` [s]. +/// Returns all but the last `0 ≤ len ≤ 1023` bits of `slice` [s]. slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; (slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -;;; Returns the last `0 ≤ len ≤ 1023` bits of `slice` [s]. +/// Returns the last `0 ≤ len ≤ 1023` bits of `slice` [s]. slice slice_last(slice s, int len) asm "SDCUTLAST"; -;;; Loads a dictionary `D` (HashMapE) from `slice` [s]. -;;; (returns `null` if `nothing` constructor is used). +/// Loads a dictionary `D` (HashMapE) from `slice` [s]. +/// (returns `null` if `nothing` constructor is used). (slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -;;; Preloads a dictionary `D` from `slice` [s]. +/// Preloads a dictionary `D` from `slice` [s]. cell preload_dict(slice s) asm "PLDDICT"; -;;; Loads a dictionary as [load_dict], but returns only the remainder of the slice. +/// Loads a dictionary as [load_dict], but returns only the remainder of the slice. slice skip_dict(slice s) asm "SKIPDICT"; -;;; Loads (Maybe ^Cell) from `slice` [s]. -;;; In other words loads 1 bit and if it is true -;;; loads first ref and return it with slice remainder -;;; otherwise returns `null` and slice remainder +/// Loads (Maybe ^Cell) from `slice` [s]. +/// In other words loads 1 bit and if it is true +/// loads first ref and return it with slice remainder +/// otherwise returns `null` and slice remainder (slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -;;; Preloads (Maybe ^Cell) from `slice` [s]. +/// Preloads (Maybe ^Cell) from `slice` [s]. cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -;;; Returns the depth of `cell` [c]. -;;; If [c] has no references, then return `0`; -;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [c]. -;;; If [c] is a `null` instead of a cell, returns zero. +/// Returns the depth of `cell` [c]. +/// If [c] has no references, then return `0`; +/// otherwise the returned value is one plus the maximum of depths of cells referred to from [c]. +/// If [c] is a `null` instead of a cell, returns zero. int cell_depth(cell c) asm "CDEPTH"; -{- +/* # Slice size primitives --} +*/ -;;; Returns the number of references in `slice` [s]. +/// Returns the number of references in `slice` [s]. int slice_refs(slice s) asm "SREFS"; -;;; Returns the number of data bits in `slice` [s]. +/// Returns the number of data bits in `slice` [s]. int slice_bits(slice s) asm "SBITS"; -;;; Returns both the number of data bits and the number of references in `slice` [s]. +/// Returns both the number of data bits and the number of references in `slice` [s]. (int, int) slice_bits_refs(slice s) asm "SBITREFS"; -;;; Checks whether a `slice` [s] is empty (i.e., contains no bits of data and no cell references). +/// Checks whether a `slice` [s] is empty (i.e., contains no bits of data and no cell references). int slice_empty?(slice s) asm "SEMPTY"; -;;; Checks whether `slice` [s] has no bits of data. +/// Checks whether `slice` [s] has no bits of data. int slice_data_empty?(slice s) asm "SDEMPTY"; -;;; Checks whether `slice` [s] has no references. +/// Checks whether `slice` [s] has no references. int slice_refs_empty?(slice s) asm "SREMPTY"; -;;; Returns the depth of `slice` [s]. -;;; If [s] has no references, then returns `0`; -;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [s]. +/// Returns the depth of `slice` [s]. +/// If [s] has no references, then returns `0`; +/// otherwise the returned value is one plus the maximum of depths of cells referred to from [s]. int slice_depth(slice s) asm "SDEPTH"; -{- +/* # Builder size primitives --} +*/ -;;; Returns the number of cell references already stored in `builder` [b] +/// Returns the number of cell references already stored in `builder` [b] int builder_refs(builder b) asm "BREFS"; -;;; Returns the number of data bits already stored in `builder` [b]. +/// Returns the number of data bits already stored in `builder` [b]. int builder_bits(builder b) asm "BBITS"; -;;; Returns the depth of `builder` [b]. -;;; If no cell references are stored in [b], then returns 0; -;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [b]. +/// Returns the depth of `builder` [b]. +/// If no cell references are stored in [b], then returns 0; +/// otherwise the returned value is one plus the maximum of depths of cells referred to from [b]. int builder_depth(builder b) asm "BDEPTH"; -{- +/* # Builder primitives It is said that a primitive _stores_ a value `x` into a builder `b` if it returns a modified version of the builder `b'` with the value `x` stored at the end of it. @@ -420,48 +420,48 @@ int builder_depth(builder b) asm "BDEPTH"; All the primitives below first check whether there is enough space in the `builder`, and only then check the range of the value being serialized. --} +*/ -;;; Creates a new empty `builder`. +/// Creates a new empty `builder`. builder begin_cell() asm "NEWC"; -;;; Converts a `builder` into an ordinary `cell`. +/// Converts a `builder` into an ordinary `cell`. cell end_cell(builder b) asm "ENDC"; -;;; Stores a reference to `cell` [c] into `builder` [b]. +/// Stores a reference to `cell` [c] into `builder` [b]. builder store_ref(builder b, cell c) asm(c b) "STREF"; -;;; Stores an unsigned [len]-bit integer `x` into `b` for `0 ≤ len ≤ 256`. -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; +/// Stores an unsigned [len]-bit integer `x` into `b` for `0 ≤ len ≤ 256`. +// builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;;; Stores a signed [len]-bit integer `x` into `b` for` 0 ≤ len ≤ 257`. -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; +/// Stores a signed [len]-bit integer `x` into `b` for` 0 ≤ len ≤ 257`. +// builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -;;; Stores `slice` [s] into `builder` [b] +/// Stores `slice` [s] into `builder` [b] builder store_slice(builder b, slice s) asm "STSLICER"; -;;; Stores (serializes) an integer [x] in the range `0..2^120 − 1` into `builder` [b]. -;;; The serialization of [x] consists of a 4-bit unsigned big-endian integer `l`, -;;; which is the smallest integer `l ≥ 0`, such that `x < 2^8l`, -;;; followed by an `8l`-bit unsigned big-endian representation of [x]. -;;; If [x] does not belong to the supported range, a range check exception is thrown. -;;; -;;; Store amounts of TonCoins to the builder as VarUInteger 16 +/// Stores (serializes) an integer [x] in the range `0..2^120 − 1` into `builder` [b]. +/// The serialization of [x] consists of a 4-bit unsigned big-endian integer `l`, +/// which is the smallest integer `l ≥ 0`, such that `x < 2^8l`, +/// followed by an `8l`-bit unsigned big-endian representation of [x]. +/// If [x] does not belong to the supported range, a range check exception is thrown. +/// +/// Store amounts of TonCoins to the builder as VarUInteger 16 builder store_grams(builder b, int x) asm "STGRAMS"; builder store_coins(builder b, int x) asm "STGRAMS"; -;;; Stores dictionary `D` represented by `cell` [c] or `null` into `builder` [b]. -;;; In other words, stores a `1`-bit and a reference to [c] if [c] is not `null` and `0`-bit otherwise. +/// Stores dictionary `D` represented by `cell` [c] or `null` into `builder` [b]. +/// In other words, stores a `1`-bit and a reference to [c] if [c] is not `null` and `0`-bit otherwise. builder store_dict(builder b, cell c) asm(c b) "STDICT"; -;;; Stores (Maybe ^Cell) to builder: -;;; if cell is null store 1 zero bit -;;; otherwise store 1 true bit and ref to cell +/// Stores (Maybe ^Cell) to builder: +/// if cell is null store 1 zero bit +/// otherwise store 1 true bit and ref to cell builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; -{- +/* # Address manipulation primitives The address manipulation primitives listed below serialize and deserialize values according to the following TL-B scheme: ```TL-B @@ -496,39 +496,39 @@ builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; Next, integer `x` is the `workchain_id`, and slice `s` contains the address. - `addr_var` is represented by `t = (3, u, x, s)`, where `u`, `x`, and `s` have the same meaning as for `addr_std`. --} +*/ -;;; Loads from slice [s] the only prefix that is a valid `MsgAddress`, -;;; and returns both this prefix `s'` and the remainder `s''` of [s] as slices. +/// Loads from slice [s] the only prefix that is a valid `MsgAddress`, +/// and returns both this prefix `s'` and the remainder `s''` of [s] as slices. (slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -;;; Decomposes slice [s] containing a valid `MsgAddress` into a `tuple t` with separate fields of this `MsgAddress`. -;;; If [s] is not a valid `MsgAddress`, a cell deserialization exception is thrown. +/// Decomposes slice [s] containing a valid `MsgAddress` into a `tuple t` with separate fields of this `MsgAddress`. +/// If [s] is not a valid `MsgAddress`, a cell deserialization exception is thrown. tuple parse_addr(slice s) asm "PARSEMSGADDR"; -;;; Parses slice [s] containing a valid `MsgAddressInt` (usually a `msg_addr_std`), -;;; applies rewriting from the anycast (if present) to the same-length prefix of the address, -;;; and returns both the workchain and the 256-bit address as integers. -;;; If the address is not 256-bit, or if [s] is not a valid serialization of `MsgAddressInt`, -;;; throws a cell deserialization exception. +/// Parses slice [s] containing a valid `MsgAddressInt` (usually a `msg_addr_std`), +/// applies rewriting from the anycast (if present) to the same-length prefix of the address, +/// and returns both the workchain and the 256-bit address as integers. +/// If the address is not 256-bit, or if [s] is not a valid serialization of `MsgAddressInt`, +/// throws a cell deserialization exception. (int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -;;; A variant of [parse_std_addr] that returns the (rewritten) address as a slice [s], -;;; even if it is not exactly 256 bit long (represented by a `msg_addr_var`). +/// A variant of [parse_std_addr] that returns the (rewritten) address as a slice [s], +/// even if it is not exactly 256 bit long (represented by a `msg_addr_var`). (int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; -{- +/* # Dictionary primitives --} +*/ -;;; Sets the value associated with [key_len]-bit key signed index in dictionary [dict] to [value] (cell), -;;; and returns the resulting dictionary. +/// Sets the value associated with [key_len]-bit key signed index in dictionary [dict] to [value] (cell), +/// and returns the resulting dictionary. cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; (cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -;;; Sets the value associated with [key_len]-bit key unsigned index in dictionary [dict] to [value] (cell), -;;; and returns the resulting dictionary. +/// Sets the value associated with [key_len]-bit key unsigned index in dictionary [dict] to [value] (cell), +/// and returns the resulting dictionary. cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; (cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; @@ -594,46 +594,46 @@ cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(va (int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; (int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -;;; Creates an empty dictionary, which is actually a null value. Equivalent to PUSHNULL +/// Creates an empty dictionary, which is actually a null value. Equivalent to PUSHNULL cell new_dict() asm "NEWDICT"; -;;; Checks whether a dictionary is empty. Equivalent to cell_null?. +/// Checks whether a dictionary is empty. Equivalent to cell_null?. int dict_empty?(cell c) asm "DICTEMPTY"; -{- Prefix dictionary primitives -} +/* Prefix dictionary primitives */ (slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; (cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; (cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; -;;; Returns the value of the global configuration parameter with integer index `i` as a `cell` or `null` value. +/// Returns the value of the global configuration parameter with integer index `i` as a `cell` or `null` value. cell config_param(int x) asm "CONFIGOPTPARAM"; -;;; Checks whether c is a null. Note, that FunC also has polymorphic null? built-in. +/// Checks whether c is a null. Note, that FunC also has polymorphic null? built-in. int cell_null?(cell c) asm "ISNULL"; -;;; Creates an output action which would reserve exactly amount nanotoncoins (if mode = 0), at most amount nanotoncoins (if mode = 2), or all but amount nanotoncoins (if mode = 1 or mode = 3), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carrying amount nanotoncoins (or b − amount nanotoncoins, where b is the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit +2 in mode means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit +8 in mode means `amount <- -amount` before performing any further actions. Bit +4 in mode means that amount is increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currently, amount must be a non-negative integer, and mode must be in the range 0..15. +/// Creates an output action which would reserve exactly amount nanotoncoins (if mode = 0), at most amount nanotoncoins (if mode = 2), or all but amount nanotoncoins (if mode = 1 or mode = 3), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carrying amount nanotoncoins (or b − amount nanotoncoins, where b is the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit +2 in mode means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit +8 in mode means `amount <- -amount` before performing any further actions. Bit +4 in mode means that amount is increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currently, amount must be a non-negative integer, and mode must be in the range 0..15. () raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -;;; Similar to raw_reserve, but also accepts a dictionary extra_amount (represented by a cell or null) with extra currencies. In this way currencies other than TonCoin can be reserved. +/// Similar to raw_reserve, but also accepts a dictionary extra_amount (represented by a cell or null) with extra currencies. In this way currencies other than TonCoin can be reserved. () raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -;;; Sends a raw message contained in msg, which should contain a correctly serialized object Message X, with the only exception that the source address is allowed to have dummy value addr_none (to be automatically replaced with the current smart contract address), and ihr_fee, fwd_fee, created_lt and created_at fields can have arbitrary values (to be rewritten with correct values during the action phase of the current transaction). Integer parameter mode contains the flags. Currently mode = 0 is used for ordinary messages; mode = 128 is used for messages that are to carry all the remaining balance of the current smart contract (instead of the value originally indicated in the message); mode = 64 is used for messages that carry all the remaining value of the inbound message in addition to the value initially indicated in the new message (if bit 0 is not set, the gas fees are deducted from this amount); mode' = mode + 1 means that the sender wants to pay transfer fees separately; mode' = mode + 2 means that any errors arising while processing this message during the action phase should be ignored. Finally, mode' = mode + 32 means that the current account must be destroyed if its resulting balance is zero. This flag is usually employed together with +128. +/// Sends a raw message contained in msg, which should contain a correctly serialized object Message X, with the only exception that the source address is allowed to have dummy value addr_none (to be automatically replaced with the current smart contract address), and ihr_fee, fwd_fee, created_lt and created_at fields can have arbitrary values (to be rewritten with correct values during the action phase of the current transaction). Integer parameter mode contains the flags. Currently mode = 0 is used for ordinary messages; mode = 128 is used for messages that are to carry all the remaining balance of the current smart contract (instead of the value originally indicated in the message); mode = 64 is used for messages that carry all the remaining value of the inbound message in addition to the value initially indicated in the new message (if bit 0 is not set, the gas fees are deducted from this amount); mode' = mode + 1 means that the sender wants to pay transfer fees separately; mode' = mode + 2 means that any errors arising while processing this message during the action phase should be ignored. Finally, mode' = mode + 32 means that the current account must be destroyed if its resulting balance is zero. This flag is usually employed together with +128. () send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -;;; Creates an output action that would change this smart contract code to that given by cell new_code. Notice that this change will take effect only after the successful termination of the current run of the smart contract +/// Creates an output action that would change this smart contract code to that given by cell new_code. Notice that this change will take effect only after the successful termination of the current run of the smart contract () set_code(cell new_code) impure asm "SETCODE"; -;;; Generates a new pseudo-random unsigned 256-bit integer x. The algorithm is as follows: if r is the old value of the random seed, considered as a 32-byte array (by constructing the big-endian representation of an unsigned 256-bit integer), then its sha512(r) is computed; the first 32 bytes of this hash are stored as the new value r' of the random seed, and the remaining 32 bytes are returned as the next random value x. +/// Generates a new pseudo-random unsigned 256-bit integer x. The algorithm is as follows: if r is the old value of the random seed, considered as a 32-byte array (by constructing the big-endian representation of an unsigned 256-bit integer), then its sha512(r) is computed; the first 32 bytes of this hash are stored as the new value r' of the random seed, and the remaining 32 bytes are returned as the next random value x. int random() impure asm "RANDU256"; -;;; Generates a new pseudo-random integer z in the range 0..range−1 (or range..−1, if range < 0). More precisely, an unsigned random value x is generated as in random; then z := x * range / 2^256 is computed. +/// Generates a new pseudo-random integer z in the range 0..range−1 (or range..−1, if range < 0). More precisely, an unsigned random value x is generated as in random; then z := x * range / 2^256 is computed. int rand(int range) impure asm "RAND"; -;;; Returns the current random seed as an unsigned 256-bit Integer. +/// Returns the current random seed as an unsigned 256-bit Integer. int get_seed() impure asm "RANDSEED"; -;;; Sets the random seed to unsigned 256-bit seed. +/// Sets the random seed to unsigned 256-bit seed. () set_seed(int) impure asm "SETRAND"; -;;; Mixes unsigned 256-bit integer x into the random seed r by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed r, and the second with the big-endian representation of x. +/// Mixes unsigned 256-bit integer x into the random seed r by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed r, and the second with the big-endian representation of x. () randomize(int x) impure asm "ADDRAND"; -;;; Equivalent to randomize(cur_lt());. +/// Equivalent to randomize(cur_lt());. () randomize_lt() impure asm "LTIME" "ADDRAND"; -;;; Checks whether the data parts of two slices coinside +/// Checks whether the data parts of two slices coinside int equal_slice_bits (slice a, slice b) asm "SDEQ"; -;;; Concatenates two builders +/// Concatenates two builders builder store_builder(builder to, builder from) asm "STBR"; From f217a7d312b662d1dc8499c55898231abc6ec7ea Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Thu, 2 May 2024 20:54:07 +0300 Subject: [PATCH 10/30] [FunC] Forbid auto-creating undefined symbols --- crypto/func/auto-tests/legacy_tests.jsonl | 3 ++- .../legacy_tests/whales-nominators/nominators.fc | 2 +- crypto/func/auto-tests/tests/invalid-undef-1.fc | 12 ++++++++++++ crypto/func/auto-tests/tests/invalid-undef-2.fc | 10 ++++++++++ crypto/func/auto-tests/tests/invalid-undef-3.fc | 10 ++++++++++ crypto/func/func.cpp | 3 +-- crypto/func/parse-func.cpp | 16 ++++------------ 7 files changed, 40 insertions(+), 16 deletions(-) create mode 100644 crypto/func/auto-tests/tests/invalid-undef-1.fc create mode 100644 crypto/func/auto-tests/tests/invalid-undef-2.fc create mode 100644 crypto/func/auto-tests/tests/invalid-undef-3.fc diff --git a/crypto/func/auto-tests/legacy_tests.jsonl b/crypto/func/auto-tests/legacy_tests.jsonl index 0075bf830..c5eae136b 100644 --- a/crypto/func/auto-tests/legacy_tests.jsonl +++ b/crypto/func/auto-tests/legacy_tests.jsonl @@ -28,7 +28,8 @@ ["jetton-minter/jetton-minter.fc", 9028309926287301331466371999814928201427184114165428257502393474125007156494] ["gg-marketplace/nft-marketplace-v2.fc", 92199806964112524639740773542356508485601908152150843819273107618799016205930] ["jetton-wallet/jetton-wallet.fc", 86251125787443633057458168028617933212663498001665054651523310772884328206542] -["whales-nominators/nominators.fc", 8941364499854379927692172316865293429893094891593442801401542636695127885153] +// (May 2024) reordered includes, they were in a wrong order +["whales-nominators/nominators.fc", 64989185004203073400683226767264384908045055609681310145961012819587514238303] // (April 2024) tact hashes changed, because '__tact_address_eq()' is now inlined as a wrapper diff --git a/crypto/func/auto-tests/legacy_tests/whales-nominators/nominators.fc b/crypto/func/auto-tests/legacy_tests/whales-nominators/nominators.fc index 8dee4e5ec..198bb6d24 100644 --- a/crypto/func/auto-tests/legacy_tests/whales-nominators/nominators.fc +++ b/crypto/func/auto-tests/legacy_tests/whales-nominators/nominators.fc @@ -8,8 +8,8 @@ #include "modules/store-validator.fc"; #include "modules/model.fc"; #include "modules/op-controller.fc"; -#include "modules/op-owner.fc"; #include "modules/op-common.fc"; +#include "modules/op-owner.fc"; #include "modules/op-nominators.fc"; #include "modules/get.fc"; diff --git a/crypto/func/auto-tests/tests/invalid-undef-1.fc b/crypto/func/auto-tests/tests/invalid-undef-1.fc new file mode 100644 index 000000000..bb20d12c0 --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-undef-1.fc @@ -0,0 +1,12 @@ +int main(int x) { + return 1 + demo(); +} + +int demo() { + return 2; +} + +{- +@compilation_should_fail +@stderr undefined symbol `demo` +-} diff --git a/crypto/func/auto-tests/tests/invalid-undef-2.fc b/crypto/func/auto-tests/tests/invalid-undef-2.fc new file mode 100644 index 000000000..8313c6d16 --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-undef-2.fc @@ -0,0 +1,10 @@ +int main(int x) { + return 1 + demo; +} + +global int demo; + +{- +@compilation_should_fail +@stderr undefined symbol `demo` +-} diff --git a/crypto/func/auto-tests/tests/invalid-undef-3.fc b/crypto/func/auto-tests/tests/invalid-undef-3.fc new file mode 100644 index 000000000..81bccfda8 --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-undef-3.fc @@ -0,0 +1,10 @@ +int demo(int x); + +int main(int x) { + return 1 + demo(x); +} + +{- +@compilation_should_fail +@stderr function `demo` is just declared, not implemented +-} diff --git a/crypto/func/func.cpp b/crypto/func/func.cpp index 42cea2519..d2bc88353 100644 --- a/crypto/func/func.cpp +++ b/crypto/func/func.cpp @@ -107,8 +107,7 @@ void generate_output_func(SymDef* func_sym, std::ostream &outs, std::ostream &er errs << "\n\n=========================\nfunction " << name << " : " << func_val->get_type() << std::endl; } if (!func_val->code) { - errs << "( function `" << name << "` undefined )\n"; - throw src::ParseError(func_sym->loc, name); + throw src::ParseError(func_sym->loc, "function `" + name + "` is just declared, not implemented"); } else { CodeBlob& code = *(func_val->code); if (verbosity >= 3) { diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index abba60685..6e11b54ca 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -396,19 +396,11 @@ SymValCodeFunc* make_new_glob_func(SymDef* func_sym, TypeExpr* func_type, bool i return res; } -bool check_global_func(const Lexem& cur, sym_idx_t func_name = 0) { - if (!func_name) { - func_name = cur.val; - } +bool check_global_func(const Lexem& cur, sym_idx_t func_name) { SymDef* def = sym::lookup_symbol(func_name); if (!def) { - cur.loc.show_error(std::string{"undefined function `"} + symbols.get_name(func_name) + - "`, defining a global function of unknown type"); - def = sym::define_global_symbol(func_name, 0, cur.loc); - func_assert(def && "cannot define global function"); - ++undef_func_cnt; - make_new_glob_func(def, TypeExpr::new_func()); // was: ... ::new_func() - return true; + cur.error("undefined symbol `" + symbols.get_name(func_name) + "`"); + return false; } SymVal* val = dynamic_cast(def->value); if (!val) { @@ -652,7 +644,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { // std::cerr << "defined new variable " << lex.cur().str << " : " << res->e_type << std::endl; } else { if (!sym) { - check_global_func(lex.cur()); + check_global_func(lex.cur(), lex.cur().val); sym = sym::lookup_symbol(lex.cur().val); } res->sym = sym; From a3e9e030193e0ba5af1ebc4650b659545e0fa78e Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Fri, 3 May 2024 11:33:25 +0300 Subject: [PATCH 11/30] [FunC] Fixed some impure specifiers in stdlib.fc --- .../bsc-bridge-collector/stdlib.fc | 6 ++--- .../auto-tests/legacy_tests/config/stdlib.fc | 6 ++--- .../legacy_tests/dns-collection/stdlib.fc | 6 ++--- .../auto-tests/legacy_tests/elector/stdlib.fc | 6 ++--- .../eth-bridge-multisig/stdlib.fc | 6 ++--- .../legacy_tests/gg-marketplace/stdlib.fc | 8 +++---- .../jetton-minter/imports/stdlib.fc | 6 ++--- .../jetton-wallet/imports/stdlib.fc | 6 ++--- .../legacy_tests/nft-collection/stdlib.fc | 8 +++---- .../legacy_tests/nominator-pool/stdlib.fc | 8 +++---- .../auto-tests/legacy_tests/storage/stdlib.fc | 6 ++--- .../legacy_tests/tact-examples/stdlib.fc | 6 ++--- .../legacy_tests/tele-nft-item/stdlib.fc | 6 ++--- .../legacy_tests/uni-lock-wallet/stdlib.fc | 6 ++--- .../legacy_tests/wallet-v4/stdlib.fc | 6 ++--- .../legacy_tests/whales-nominators/stdlib.fc | 6 ++--- crypto/smartcont/stdlib.fc | 22 +++++++++---------- 17 files changed, 62 insertions(+), 62 deletions(-) diff --git a/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc b/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc index d5d5c8b86..d6b8b1113 100644 --- a/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc @@ -53,9 +53,9 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; () accept_message() impure asm "ACCEPT"; () set_gas_limit(int limit) impure asm "SETGASLIMIT"; @@ -202,7 +202,7 @@ int cell_null?(cell c) asm "ISNULL"; int random() impure asm "RANDU256"; int rand(int range) impure asm "RAND"; -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; int set_seed() impure asm "SETRAND"; () randomize(int x) impure asm "ADDRAND"; () randomize_lt() impure asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/config/stdlib.fc b/crypto/func/auto-tests/legacy_tests/config/stdlib.fc index 0b98eeb44..099533b74 100644 --- a/crypto/func/auto-tests/legacy_tests/config/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/config/stdlib.fc @@ -53,9 +53,9 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; () accept_message() impure asm "ACCEPT"; () set_gas_limit(int limit) impure asm "SETGASLIMIT"; @@ -202,7 +202,7 @@ int cell_null?(cell c) asm "ISNULL"; int random() impure asm "RANDU256"; int rand(int range) impure asm "RAND"; -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; int set_seed() impure asm "SETRAND"; () randomize(int x) impure asm "ADDRAND"; () randomize_lt() impure asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc b/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc index 40bac583c..1b43e221e 100644 --- a/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc @@ -53,9 +53,9 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; () accept_message() impure asm "ACCEPT"; () set_gas_limit(int limit) impure asm "SETGASLIMIT"; @@ -202,7 +202,7 @@ int cell_null?(cell c) asm "ISNULL"; int random() impure asm "RANDU256"; int rand(int range) impure asm "RAND"; -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; int set_seed() impure asm "SETRAND"; () randomize(int x) impure asm "ADDRAND"; () randomize_lt() impure asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc b/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc index b862b5ef8..41ab33823 100644 --- a/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc @@ -53,9 +53,9 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; () accept_message() impure asm "ACCEPT"; () set_gas_limit(int limit) impure asm "SETGASLIMIT"; @@ -202,7 +202,7 @@ int cell_null?(cell c) asm "ISNULL"; int random() impure asm "RANDU256"; int rand(int range) impure asm "RAND"; -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; int set_seed() impure asm "SETRAND"; () randomize(int x) impure asm "ADDRAND"; () randomize_lt() impure asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc b/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc index 1d144040f..04b6e4d3c 100644 --- a/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc @@ -53,9 +53,9 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; () accept_message() impure asm "ACCEPT"; () set_gas_limit(int limit) impure asm "SETGASLIMIT"; @@ -202,7 +202,7 @@ int cell_null?(cell c) asm "ISNULL"; int random() impure asm "RANDU256"; int rand(int range) impure asm "RAND"; -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; int set_seed() impure asm "SETRAND"; () randomize(int x) impure asm "ADDRAND"; () randomize_lt() impure asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc b/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc index ba9177e97..6ae2a28d2 100644 --- a/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc @@ -53,9 +53,9 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; () accept_message() impure asm "ACCEPT"; () set_gas_limit(int limit) impure asm "SETGASLIMIT"; @@ -202,7 +202,7 @@ int cell_null?(cell c) asm "ISNULL"; int random() impure asm "RANDU256"; int rand(int range) impure asm "RAND"; -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; int set_seed() impure asm "SETRAND"; () randomize(int x) impure asm "ADDRAND"; () randomize_lt() impure asm "LTIME" "ADDRAND"; @@ -212,4 +212,4 @@ builder store_coins(builder b, int x) asm "STVARUINT16"; int equal_slices (slice a, slice b) asm "SDEQ"; int builder_null?(builder b) asm "ISNULL"; -builder store_builder(builder to, builder from) asm "STBR"; \ No newline at end of file +builder store_builder(builder to, builder from) asm "STBR"; diff --git a/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc b/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc index 05c3a4c0c..f04be0b68 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc @@ -53,9 +53,9 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; () accept_message() impure asm "ACCEPT"; () set_gas_limit(int limit) impure asm "SETGASLIMIT"; @@ -202,7 +202,7 @@ int cell_null?(cell c) asm "ISNULL"; int random() impure asm "RANDU256"; int rand(int range) impure asm "RAND"; -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; int set_seed() impure asm "SETRAND"; () randomize(int x) impure asm "ADDRAND"; () randomize_lt() impure asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc b/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc index 05c3a4c0c..f04be0b68 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc @@ -53,9 +53,9 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; () accept_message() impure asm "ACCEPT"; () set_gas_limit(int limit) impure asm "SETGASLIMIT"; @@ -202,7 +202,7 @@ int cell_null?(cell c) asm "ISNULL"; int random() impure asm "RANDU256"; int rand(int range) impure asm "RAND"; -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; int set_seed() impure asm "SETRAND"; () randomize(int x) impure asm "ADDRAND"; () randomize_lt() impure asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc b/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc index ba9177e97..6ae2a28d2 100644 --- a/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc @@ -53,9 +53,9 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; () accept_message() impure asm "ACCEPT"; () set_gas_limit(int limit) impure asm "SETGASLIMIT"; @@ -202,7 +202,7 @@ int cell_null?(cell c) asm "ISNULL"; int random() impure asm "RANDU256"; int rand(int range) impure asm "RAND"; -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; int set_seed() impure asm "SETRAND"; () randomize(int x) impure asm "ADDRAND"; () randomize_lt() impure asm "LTIME" "ADDRAND"; @@ -212,4 +212,4 @@ builder store_coins(builder b, int x) asm "STVARUINT16"; int equal_slices (slice a, slice b) asm "SDEQ"; int builder_null?(builder b) asm "ISNULL"; -builder store_builder(builder to, builder from) asm "STBR"; \ No newline at end of file +builder store_builder(builder to, builder from) asm "STBR"; diff --git a/crypto/func/auto-tests/legacy_tests/nominator-pool/stdlib.fc b/crypto/func/auto-tests/legacy_tests/nominator-pool/stdlib.fc index 0431d32de..cddb5ae04 100644 --- a/crypto/func/auto-tests/legacy_tests/nominator-pool/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/nominator-pool/stdlib.fc @@ -53,9 +53,9 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; () accept_message() impure asm "ACCEPT"; () set_gas_limit(int limit) impure asm "SETGASLIMIT"; @@ -202,10 +202,10 @@ int cell_null?(cell c) asm "ISNULL"; int random() impure asm "RANDU256"; int rand(int range) impure asm "RAND"; -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; int set_seed() impure asm "SETRAND"; () randomize(int x) impure asm "ADDRAND"; () randomize_lt() impure asm "LTIME" "ADDRAND"; builder store_coins(builder b, int x) asm "STVARUINT16"; -(slice, int) load_coins(slice s) asm( -> 1 0) "LDVARUINT16"; \ No newline at end of file +(slice, int) load_coins(slice s) asm( -> 1 0) "LDVARUINT16"; diff --git a/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc b/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc index a33d39425..70b5d61d4 100644 --- a/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc @@ -209,7 +209,7 @@ cell get_data() asm "c4 PUSH"; */ /// Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls. /// The primitive returns the current value of `c3`. -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; /// Updates the current value of `c3`. Usually, it is used for updating smart contract code in run-time. /// Note that after execution of this primitive the current code @@ -218,7 +218,7 @@ cont get_c3() impure asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; /// Transforms a `slice` [s] into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist. -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; /*-- # Gas related primitives @@ -609,7 +609,7 @@ int random() impure asm "RANDU256"; /// Generates a new pseudo-random integer z in the range 0..range−1 (or range..−1, if range < 0). More precisely, an unsigned random value x is generated as in random; then z := x * range / 2^256 is computed. int rand(int range) impure asm "RAND"; /// Returns the current random seed as an unsigned 256-bit Integer. -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; /// Sets the random seed to unsigned 256-bit seed. () set_seed(int) impure asm "SETRAND"; /// Mixes unsigned 256-bit integer x into the random seed r by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed r, and the second with the big-endian representation of x. diff --git a/crypto/func/auto-tests/legacy_tests/tact-examples/stdlib.fc b/crypto/func/auto-tests/legacy_tests/tact-examples/stdlib.fc index 3531608a7..d5bd148e7 100644 --- a/crypto/func/auto-tests/legacy_tests/tact-examples/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/tact-examples/stdlib.fc @@ -209,7 +209,7 @@ cell get_data() asm "c4 PUSH"; -} ;;; Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls. ;;; The primitive returns the current value of `c3`. -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; ;;; Updates the current value of `c3`. Usually, it is used for updating smart contract code in run-time. ;;; Note that after execution of this primitive the current code @@ -218,7 +218,7 @@ cont get_c3() impure asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; ;;; Transforms a `slice` [s] into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist. -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; {--- # Gas related primitives @@ -609,7 +609,7 @@ int random() impure asm "RANDU256"; ;;; Generates a new pseudo-random integer z in the range 0..range−1 (or range..−1, if range < 0). More precisely, an unsigned random value x is generated as in random; then z := x * range / 2^256 is computed. int rand(int range) impure asm "RAND"; ;;; Returns the current random seed as an unsigned 256-bit Integer. -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; ;;; Sets the random seed to unsigned 256-bit seed. () set_seed(int) impure asm "SETRAND"; ;;; Mixes unsigned 256-bit integer x into the random seed r by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed r, and the second with the big-endian representation of x. diff --git a/crypto/func/auto-tests/legacy_tests/tele-nft-item/stdlib.fc b/crypto/func/auto-tests/legacy_tests/tele-nft-item/stdlib.fc index 45d01f322..7304a80e6 100644 --- a/crypto/func/auto-tests/legacy_tests/tele-nft-item/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/tele-nft-item/stdlib.fc @@ -53,9 +53,9 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; () accept_message() impure asm "ACCEPT"; () set_gas_limit(int limit) impure asm "SETGASLIMIT"; @@ -202,7 +202,7 @@ int cell_null?(cell c) asm "ISNULL"; int random() impure asm "RANDU256"; int rand(int range) impure asm "RAND"; -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; int set_seed() impure asm "SETRAND"; () randomize(int x) impure asm "ADDRAND"; () randomize_lt() impure asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/uni-lock-wallet/stdlib.fc b/crypto/func/auto-tests/legacy_tests/uni-lock-wallet/stdlib.fc index 266b69acd..cddb5ae04 100644 --- a/crypto/func/auto-tests/legacy_tests/uni-lock-wallet/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/uni-lock-wallet/stdlib.fc @@ -53,9 +53,9 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; () accept_message() impure asm "ACCEPT"; () set_gas_limit(int limit) impure asm "SETGASLIMIT"; @@ -202,7 +202,7 @@ int cell_null?(cell c) asm "ISNULL"; int random() impure asm "RANDU256"; int rand(int range) impure asm "RAND"; -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; int set_seed() impure asm "SETRAND"; () randomize(int x) impure asm "ADDRAND"; () randomize_lt() impure asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/wallet-v4/stdlib.fc b/crypto/func/auto-tests/legacy_tests/wallet-v4/stdlib.fc index 05c3a4c0c..f04be0b68 100644 --- a/crypto/func/auto-tests/legacy_tests/wallet-v4/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/wallet-v4/stdlib.fc @@ -53,9 +53,9 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; () accept_message() impure asm "ACCEPT"; () set_gas_limit(int limit) impure asm "SETGASLIMIT"; @@ -202,7 +202,7 @@ int cell_null?(cell c) asm "ISNULL"; int random() impure asm "RANDU256"; int rand(int range) impure asm "RAND"; -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; int set_seed() impure asm "SETRAND"; () randomize(int x) impure asm "ADDRAND"; () randomize_lt() impure asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/whales-nominators/stdlib.fc b/crypto/func/auto-tests/legacy_tests/whales-nominators/stdlib.fc index dcc5f423c..e69d91716 100644 --- a/crypto/func/auto-tests/legacy_tests/whales-nominators/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/whales-nominators/stdlib.fc @@ -53,9 +53,9 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI cell get_data() asm "c4 PUSH"; () set_data(cell c) impure asm "c4 POP"; -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; () accept_message() impure asm "ACCEPT"; () set_gas_limit(int limit) impure asm "SETGASLIMIT"; @@ -202,7 +202,7 @@ int cell_null?(cell c) asm "ISNULL"; int random() impure asm "RANDU256"; int rand(int range) impure asm "RAND"; -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; int set_seed() impure asm "SETRAND"; () randomize(int x) impure asm "ADDRAND"; () randomize_lt() impure asm "LTIME" "ADDRAND"; diff --git a/crypto/smartcont/stdlib.fc b/crypto/smartcont/stdlib.fc index 7049c6fb1..57ae7c6bf 100644 --- a/crypto/smartcont/stdlib.fc +++ b/crypto/smartcont/stdlib.fc @@ -177,6 +177,12 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI The primitives below may be useful for computing storage fees of user-provided data. */ +/// A non-quiet version of [compute_data_size?] that throws a cell overflow exception (`8`) on failure. +(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; + +/// A non-quiet version of [slice_compute_data_size?] that throws a cell overflow exception (`8`) on failure. +(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; + /// Returns `(x, y, z, -1)` or `(null, null, null, 0)`. /// Recursively computes the count of distinct cells `x`, data bits `y`, and cell references `z` /// in the DAG rooted at `cell` [c], effectively returning the total storage used by this DAG taking into account @@ -186,18 +192,12 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI /// The total count of visited cells `x` cannot exceed non-negative [max_cells]; /// otherwise the computation is aborted before visiting the `(max_cells + 1)`-st cell and /// a zero flag is returned to indicate failure. If [c] is `null`, returns `x = y = z = 0`. -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; /// Similar to [compute_data_size?], but accepting a `slice` [s] instead of a `cell`. /// The returned value of `x` does not take into account the cell that contains the `slice` [s] itself; /// however, the data bits and the cell references of [s] are accounted for in `y` and `z`. -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; - -/// A non-quiet version of [compute_data_size?] that throws a cell overflow exception (`8`) on failure. -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -/// A non-quiet version of [slice_compute_data_size?] that throws a cell overflow exception (8) on failure. -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(slice s, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; /// Throws an exception with exit_code excno if cond is not 0 (commented since implemented in compilator) // () throw_if(int excno, int cond) impure asm "THROWARGIF"; @@ -224,7 +224,7 @@ cell get_data() asm "c4 PUSH"; */ /// Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls. /// The primitive returns the current value of `c3`. -cont get_c3() impure asm "c3 PUSH"; +cont get_c3() asm "c3 PUSH"; /// Updates the current value of `c3`. Usually, it is used for updating smart contract code in run-time. /// Note that after execution of this primitive the current code @@ -233,7 +233,7 @@ cont get_c3() impure asm "c3 PUSH"; () set_c3(cont c) impure asm "c3 POP"; /// Transforms a `slice` [s] into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist. -cont bless(slice s) impure asm "BLESS"; +cont bless(slice s) asm "BLESS"; /*** # Gas related primitives @@ -624,7 +624,7 @@ int random() impure asm "RANDU256"; /// Generates a new pseudo-random integer z in the range 0..range−1 (or range..−1, if range < 0). More precisely, an unsigned random value x is generated as in random; then z := x * range / 2^256 is computed. int rand(int range) impure asm "RAND"; /// Returns the current random seed as an unsigned 256-bit Integer. -int get_seed() impure asm "RANDSEED"; +int get_seed() asm "RANDSEED"; /// Sets the random seed to unsigned 256-bit seed. () set_seed(int) impure asm "SETRAND"; /// Mixes unsigned 256-bit integer x into the random seed r by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed r, and the second with the big-endian representation of x. From 85c60d12636ee80b7d3487c1433050fbf8702079 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Fri, 3 May 2024 13:26:57 +0300 Subject: [PATCH 12/30] [FunC] Make all functions impure by default, add "pure" specifier --- crypto/func/auto-tests/legacy_tests.jsonl | 9 +- .../bsc-bridge-collector/stdlib.fc | 410 ++++++++--------- .../auto-tests/legacy_tests/config/stdlib.fc | 410 ++++++++--------- .../dns-collection/nft-collection.fc | 6 +- .../legacy_tests/dns-collection/params.fc | 4 +- .../legacy_tests/dns-collection/stdlib.fc | 424 +++++++++--------- .../legacy_tests/elector/elector-code.fc | 56 +-- .../auto-tests/legacy_tests/elector/stdlib.fc | 410 ++++++++--------- .../eth-bridge-multisig/stdlib.fc | 410 ++++++++--------- .../legacy_tests/gg-marketplace/stdlib.fc | 424 +++++++++--------- .../jetton-minter/imports/params.fc | 4 +- .../jetton-minter/imports/stdlib.fc | 424 +++++++++--------- .../jetton-minter/imports/utils.fc | 2 +- .../jetton-minter/jetton-minter.fc | 6 +- .../jetton-wallet/imports/params.fc | 4 +- .../jetton-wallet/imports/stdlib.fc | 424 +++++++++--------- .../jetton-wallet/imports/utils.fc | 2 +- .../jetton-wallet/jetton-wallet.fc | 12 +- .../nft-collection/nft-collection-editable.fc | 8 +- .../legacy_tests/nft-collection/params.fc | 4 +- .../legacy_tests/nft-collection/stdlib.fc | 424 +++++++++--------- .../legacy_tests/nominator-pool/stdlib.fc | 416 ++++++++--------- .../auto-tests/legacy_tests/storage/stdlib.fc | 380 ++++++++-------- .../legacy_tests/storage/storage-contract.fc | 6 +- .../legacy_tests/storage/storage-provider.fc | 6 +- .../legacy_tests/tact-examples/stdlib.fc | 380 ++++++++-------- .../legacy_tests/tele-nft-item/stdlib.fc | 402 ++++++++--------- .../legacy_tests/uni-lock-wallet/stdlib.fc | 416 ++++++++--------- .../legacy_tests/wallet-v4/stdlib.fc | 424 +++++++++--------- .../legacy_tests/wallet-v4/wallet-v4-code.fc | 4 +- .../whales-nominators/modules/utils.fc | 16 +- .../legacy_tests/whales-nominators/stdlib.fc | 418 ++++++++--------- crypto/func/auto-tests/tests/asm_arg_order.fc | 14 +- crypto/func/auto-tests/tests/camel1.fc | 60 +-- crypto/func/auto-tests/tests/camel2.fc | 18 +- crypto/func/auto-tests/tests/camel3.fc | 18 +- crypto/func/auto-tests/tests/camel4.fc | 21 +- crypto/func/auto-tests/tests/co1.fc | 10 +- crypto/func/auto-tests/tests/inline_loops.fc | 6 +- crypto/func/auto-tests/tests/s1.fc | 4 +- crypto/func/auto-tests/tests/test-math.fc | 2 +- crypto/func/builtins.cpp | 6 +- crypto/func/func.h | 45 +- crypto/func/keywords.cpp | 1 + crypto/func/parse-func.cpp | 39 +- crypto/func/test/b1.fc | 46 +- crypto/func/test/b2.fc | 46 +- crypto/func/test/b2_0.fc | 46 +- crypto/func/test/b2_1.fc | 48 +- crypto/func/test/b2_2.fc | 46 +- crypto/func/test/b3.fc | 4 +- crypto/func/test/c1.fc | 6 +- crypto/func/test/i1.fc | 6 +- crypto/func/test/i1sub1.fc | 2 +- crypto/func/test/i1sub2.fc | 2 +- crypto/func/test/tc1.fc | 12 +- crypto/func/test/tc2.fc | 4 +- crypto/func/test/w3.fc | 2 +- crypto/func/test/w5.fc | 4 +- crypto/func/test/w8.fc | 2 +- crypto/smartcont/stdlib.fc | 380 ++++++++-------- 61 files changed, 3828 insertions(+), 3817 deletions(-) diff --git a/crypto/func/auto-tests/legacy_tests.jsonl b/crypto/func/auto-tests/legacy_tests.jsonl index c5eae136b..06d58a8f3 100644 --- a/crypto/func/auto-tests/legacy_tests.jsonl +++ b/crypto/func/auto-tests/legacy_tests.jsonl @@ -33,7 +33,8 @@ // (April 2024) tact hashes changed, because '__tact_address_eq()' is now inlined as a wrapper -["tact-examples/treasure_Treasure.code.fc", 74579212939836529446778705921340099196942507859825095056546203678047252921894] -["tact-examples/jetton_SampleJetton.code.fc", 90109697379313597998231209537203822165325184678797680193687781490465875320451] -["tact-examples/jetton_JettonDefaultWallet.code.fc", 40972091374757565863193840427121230466303309310521439431197914284004190565629] -["tact-examples/maps_MapTestContract.code.fc", 22556550222249123835909180266811414538971143565993192846012583552876721649744] +// (May 2024) tact hashes changed, because '__tact_verify_address()' wasn't marked 'impure', its calls were optimized out, but now all functions are impure by default +["tact-examples/treasure_Treasure.code.fc", 30910931405335759315065032463773878427855191049444026038533177550379770294016] +["tact-examples/jetton_SampleJetton.code.fc", 113366726152288202116967819512003292371082270049030855507946195024152087708689] +["tact-examples/jetton_JettonDefaultWallet.code.fc", 51854826936807357767718095298932278700078280434421329524498524733409271908380] +["tact-examples/maps_MapTestContract.code.fc", 86004071444084135394990759334664637743689750108042267324839281046456545168857] diff --git a/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc b/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc index d6b8b1113..b168d558b 100644 --- a/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc @@ -1,209 +1,209 @@ // Standard library for funC // -forall X -> tuple cons(X head, tuple tail) asm "CONS"; -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -forall X -> X car(tuple list) asm "CAR"; -tuple cdr(tuple list) asm "CDR"; -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> [X] single(X x) asm "SINGLE"; -forall X -> X unsingle([X] t) asm "UNSINGLE"; -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -forall X -> X first(tuple t) asm "FIRST"; -forall X -> X second(tuple t) asm "SECOND"; -forall X -> X third(tuple t) asm "THIRD"; -forall X -> X fourth(tuple t) asm "3 INDEX"; -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -forall X -> X null() asm "PUSHNULL"; -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; - -int now() asm "NOW"; -slice my_address() asm "MYADDR"; -[int, cell] get_balance() asm "BALANCE"; -int cur_lt() asm "LTIME"; -int block_lt() asm "BLOCKLT"; - -int cell_hash(cell c) asm "HASHCU"; -int slice_hash(slice s) asm "HASHSU"; -int string_hash(slice s) asm "SHA256U"; - -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; - -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -// () throw_if(int excno, int cond) impure asm "THROWARGIF"; - -() dump_stack() impure asm "DUMPSTK"; - -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -cont get_c3() asm "c3 PUSH"; -() set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) asm "BLESS"; - -() accept_message() impure asm "ACCEPT"; -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; -() commit() impure asm "COMMIT"; -() buy_gas(int gram) impure asm "BUYGAS"; - -int min(int x, int y) asm "MIN"; -int max(int x, int y) asm "MAX"; -(int, int) minmax(int x, int y) asm "MINMAX"; -int abs(int x) asm "ABS"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -cell preload_ref(slice s) asm "PLDREF"; -// (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -// (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -// int preload_int(slice s, int len) asm "PLDIX"; -// int preload_uint(slice s, int len) asm "PLDUX"; -// (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -// slice preload_bits(slice s, int len) asm "PLDSLICEX"; -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -slice first_bits(slice s, int len) asm "SDCUTFIRST"; -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -slice slice_last(slice s, int len) asm "SDCUTLAST"; -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -cell preload_dict(slice s) asm "PLDDICT"; -slice skip_dict(slice s) asm "SKIPDICT"; - -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; - -int cell_depth(cell c) asm "CDEPTH"; - -int slice_refs(slice s) asm "SREFS"; -int slice_bits(slice s) asm "SBITS"; -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; -int slice_empty?(slice s) asm "SEMPTY"; -int slice_data_empty?(slice s) asm "SDEMPTY"; -int slice_refs_empty?(slice s) asm "SREMPTY"; -int slice_depth(slice s) asm "SDEPTH"; - -int builder_refs(builder b) asm "BREFS"; -int builder_bits(builder b) asm "BBITS"; -int builder_depth(builder b) asm "BDEPTH"; - -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -// builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -// builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -builder store_slice(builder b, slice s) asm "STSLICER"; -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_dict(builder b, cell c) asm(c b) "STDICT"; - -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -tuple parse_addr(slice s) asm "PARSEMSGADDR"; -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; - -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -cell new_dict() asm "NEWDICT"; -int dict_empty?(cell c) asm "DICTEMPTY"; - -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; - -cell config_param(int x) asm "CONFIGOPTPARAM"; -int cell_null?(cell c) asm "ISNULL"; - -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -() set_code(cell new_code) impure asm "SETCODE"; - -int random() impure asm "RANDU256"; -int rand(int range) impure asm "RAND"; -int get_seed() asm "RANDSEED"; -int set_seed() impure asm "SETRAND"; -() randomize(int x) impure asm "ADDRAND"; -() randomize_lt() impure asm "LTIME" "ADDRAND"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; +forall X -> X car(tuple list) pure asm "CAR"; +tuple cdr(tuple list) pure asm "CDR"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> [X] single(X x) pure asm "SINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; +forall X -> X first(tuple t) pure asm "FIRST"; +forall X -> X second(tuple t) pure asm "SECOND"; +forall X -> X third(tuple t) pure asm "THIRD"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; +forall X -> X null() pure asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; + +int now() pure asm "NOW"; +slice my_address() pure asm "MYADDR"; +[int, cell] get_balance() pure asm "BALANCE"; +int cur_lt() pure asm "LTIME"; +int block_lt() pure asm "BLOCKLT"; + +int cell_hash(cell c) pure asm "HASHCU"; +int slice_hash(slice s) pure asm "HASHSU"; +int string_hash(slice s) pure asm "SHA256U"; + +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; + +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; + +// () throw_if(int excno, int cond) asm "THROWARGIF"; + +() dump_stack() asm "DUMPSTK"; + +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +cont get_c3() pure asm "c3 PUSH"; +() set_c3(cont c) asm "c3 POP"; +cont bless(slice s) pure asm "BLESS"; + +() accept_message() asm "ACCEPT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; +() commit() asm "COMMIT"; +() buy_gas(int gram) asm "BUYGAS"; + +int min(int x, int y) pure asm "MIN"; +int max(int x, int y) pure asm "MAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; +int abs(int x) pure asm "ABS"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; +// (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +// (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +// int preload_int(slice s, int len) pure asm "PLDIX"; +// int preload_uint(slice s, int len) pure asm "PLDUX"; +// (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +// slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; + +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; + +int cell_depth(cell c) pure asm "CDEPTH"; + +int slice_refs(slice s) pure asm "SREFS"; +int slice_bits(slice s) pure asm "SBITS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; +int slice_empty?(slice s) pure asm "SEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; +int slice_depth(slice s) pure asm "SDEPTH"; + +int builder_refs(builder b) pure asm "BREFS"; +int builder_bits(builder b) pure asm "BBITS"; +int builder_depth(builder b) pure asm "BDEPTH"; + +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +// builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +// builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; + +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; + +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; + +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; + +cell config_param(int x) pure asm "CONFIGOPTPARAM"; +int cell_null?(cell c) pure asm "ISNULL"; + +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; +() set_code(cell new_code) asm "SETCODE"; + +int random() asm "RANDU256"; +int rand(int range) asm "RAND"; +int get_seed() pure asm "RANDSEED"; +int set_seed() asm "SETRAND"; +() randomize(int x) asm "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/config/stdlib.fc b/crypto/func/auto-tests/legacy_tests/config/stdlib.fc index 099533b74..5614d76fb 100644 --- a/crypto/func/auto-tests/legacy_tests/config/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/config/stdlib.fc @@ -1,208 +1,208 @@ ;; Standard library for funC ;; -forall X -> tuple cons(X head, tuple tail) asm "CONS"; -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -forall X -> X car(tuple list) asm "CAR"; -tuple cdr(tuple list) asm "CDR"; -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> [X] single(X x) asm "SINGLE"; -forall X -> X unsingle([X] t) asm "UNSINGLE"; -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -forall X -> X first(tuple t) asm "FIRST"; -forall X -> X second(tuple t) asm "SECOND"; -forall X -> X third(tuple t) asm "THIRD"; -forall X -> X fourth(tuple t) asm "3 INDEX"; -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -forall X -> X null() asm "PUSHNULL"; -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; - -int now() asm "NOW"; -slice my_address() asm "MYADDR"; -[int, cell] get_balance() asm "BALANCE"; -int cur_lt() asm "LTIME"; -int block_lt() asm "BLOCKLT"; - -int cell_hash(cell c) asm "HASHCU"; -int slice_hash(slice s) asm "HASHSU"; -int string_hash(slice s) asm "SHA256U"; - -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; - -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; - -() dump_stack() impure asm "DUMPSTK"; - -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -cont get_c3() asm "c3 PUSH"; -() set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) asm "BLESS"; - -() accept_message() impure asm "ACCEPT"; -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; -() commit() impure asm "COMMIT"; -() buy_gas(int gram) impure asm "BUYGAS"; - -int min(int x, int y) asm "MIN"; -int max(int x, int y) asm "MAX"; -(int, int) minmax(int x, int y) asm "MINMAX"; -int abs(int x) asm "ABS"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -cell preload_ref(slice s) asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -slice first_bits(slice s, int len) asm "SDCUTFIRST"; -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -slice slice_last(slice s, int len) asm "SDCUTLAST"; -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -cell preload_dict(slice s) asm "PLDDICT"; -slice skip_dict(slice s) asm "SKIPDICT"; - -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; - -int cell_depth(cell c) asm "CDEPTH"; - -int slice_refs(slice s) asm "SREFS"; -int slice_bits(slice s) asm "SBITS"; -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; -int slice_empty?(slice s) asm "SEMPTY"; -int slice_data_empty?(slice s) asm "SDEMPTY"; -int slice_refs_empty?(slice s) asm "SREMPTY"; -int slice_depth(slice s) asm "SDEPTH"; - -int builder_refs(builder b) asm "BREFS"; -int builder_bits(builder b) asm "BBITS"; -int builder_depth(builder b) asm "BDEPTH"; - -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -builder store_slice(builder b, slice s) asm "STSLICER"; -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_dict(builder b, cell c) asm(c b) "STDICT"; - -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -tuple parse_addr(slice s) asm "PARSEMSGADDR"; -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; - -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -cell new_dict() asm "NEWDICT"; -int dict_empty?(cell c) asm "DICTEMPTY"; - -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; - -cell config_param(int x) asm "CONFIGOPTPARAM"; -int cell_null?(cell c) asm "ISNULL"; - -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -() set_code(cell new_code) impure asm "SETCODE"; - -int random() impure asm "RANDU256"; -int rand(int range) impure asm "RAND"; -int get_seed() asm "RANDSEED"; -int set_seed() impure asm "SETRAND"; -() randomize(int x) impure asm "ADDRAND"; -() randomize_lt() impure asm "LTIME" "ADDRAND"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; +forall X -> X car(tuple list) pure asm "CAR"; +tuple cdr(tuple list) pure asm "CDR"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> [X] single(X x) pure asm "SINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; +forall X -> X first(tuple t) pure asm "FIRST"; +forall X -> X second(tuple t) pure asm "SECOND"; +forall X -> X third(tuple t) pure asm "THIRD"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; +forall X -> X null() pure asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; + +int now() pure asm "NOW"; +slice my_address() pure asm "MYADDR"; +[int, cell] get_balance() pure asm "BALANCE"; +int cur_lt() pure asm "LTIME"; +int block_lt() pure asm "BLOCKLT"; + +int cell_hash(cell c) pure asm "HASHCU"; +int slice_hash(slice s) pure asm "HASHSU"; +int string_hash(slice s) pure asm "SHA256U"; + +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; + +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; + +;; () throw_if(int excno, int cond) asm "THROWARGIF"; + +() dump_stack() asm "DUMPSTK"; + +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +cont get_c3() pure asm "c3 PUSH"; +() set_c3(cont c) asm "c3 POP"; +cont bless(slice s) pure asm "BLESS"; + +() accept_message() asm "ACCEPT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; +() commit() asm "COMMIT"; +() buy_gas(int gram) asm "BUYGAS"; + +int min(int x, int y) pure asm "MIN"; +int max(int x, int y) pure asm "MAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; +int abs(int x) pure asm "ABS"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; +;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; +;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; + +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; + +int cell_depth(cell c) pure asm "CDEPTH"; + +int slice_refs(slice s) pure asm "SREFS"; +int slice_bits(slice s) pure asm "SBITS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; +int slice_empty?(slice s) pure asm "SEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; +int slice_depth(slice s) pure asm "SDEPTH"; + +int builder_refs(builder b) pure asm "BREFS"; +int builder_bits(builder b) pure asm "BBITS"; +int builder_depth(builder b) pure asm "BDEPTH"; + +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; + +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; + +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; + +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; + +cell config_param(int x) pure asm "CONFIGOPTPARAM"; +int cell_null?(cell c) pure asm "ISNULL"; + +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; +() set_code(cell new_code) asm "SETCODE"; + +int random() asm "RANDU256"; +int rand(int range) asm "RAND"; +int get_seed() pure asm "RANDSEED"; +int set_seed() asm "SETRAND"; +() randomize(int x) asm "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/dns-collection/nft-collection.fc b/crypto/func/auto-tests/legacy_tests/dns-collection/nft-collection.fc index 4e1425879..aa98945c8 100644 --- a/crypto/func/auto-tests/legacy_tests/dns-collection/nft-collection.fc +++ b/crypto/func/auto-tests/legacy_tests/dns-collection/nft-collection.fc @@ -18,7 +18,7 @@ ); } -() save_data(cell content, cell nft_item_code) impure inline { +() save_data(cell content, cell nft_item_code) inline { set_data(begin_cell() .store_ref(content) .store_ref(nft_item_code) @@ -39,7 +39,7 @@ slice calculate_nft_item_address(int wc, cell state_init) { .begin_parse(); } -() deploy_nft_item(int item_index, cell nft_item_code, cell nft_content) impure { +() deploy_nft_item(int item_index, cell nft_item_code, cell nft_content) { cell state_init = calculate_nft_item_state_init(item_index, nft_item_code); slice nft_address = calculate_nft_item_address(workchain(), state_init); var msg = begin_cell() @@ -52,7 +52,7 @@ slice calculate_nft_item_address(int wc, cell state_init) { send_raw_message(msg.end_cell(), 64); ;; carry all the remaining value of the inbound message, fee deducted from amount } -() recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) impure { +() recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) { if (in_msg_body.slice_empty?()) { ;; bounce back empty messages throw(0xffff); } diff --git a/crypto/func/auto-tests/legacy_tests/dns-collection/params.fc b/crypto/func/auto-tests/legacy_tests/dns-collection/params.fc index e28eac458..471ed9fdf 100644 --- a/crypto/func/auto-tests/legacy_tests/dns-collection/params.fc +++ b/crypto/func/auto-tests/legacy_tests/dns-collection/params.fc @@ -1,6 +1,6 @@ int workchain() asm "0 PUSHINT"; -() force_chain(slice addr) impure { +() force_chain(slice addr) { (int wc, _) = parse_std_addr(addr); throw_unless(333, wc == workchain()); -} \ No newline at end of file +} diff --git a/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc b/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc index 1b43e221e..aaa71720f 100644 --- a/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc @@ -1,216 +1,216 @@ ;; Standard library for funC ;; -forall X -> tuple cons(X head, tuple tail) asm "CONS"; -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -forall X -> X car(tuple list) asm "CAR"; -tuple cdr(tuple list) asm "CDR"; -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> [X] single(X x) asm "SINGLE"; -forall X -> X unsingle([X] t) asm "UNSINGLE"; -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -forall X -> X first(tuple t) asm "FIRST"; -forall X -> X second(tuple t) asm "SECOND"; -forall X -> X third(tuple t) asm "THIRD"; -forall X -> X fourth(tuple t) asm "3 INDEX"; -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -forall X -> X null() asm "PUSHNULL"; -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; - -int now() asm "NOW"; -slice my_address() asm "MYADDR"; -[int, cell] get_balance() asm "BALANCE"; -int cur_lt() asm "LTIME"; -int block_lt() asm "BLOCKLT"; - -int cell_hash(cell c) asm "HASHCU"; -int slice_hash(slice s) asm "HASHSU"; -int string_hash(slice s) asm "SHA256U"; - -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; - -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; - -() dump_stack() impure asm "DUMPSTK"; - -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -cont get_c3() asm "c3 PUSH"; -() set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) asm "BLESS"; - -() accept_message() impure asm "ACCEPT"; -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; -() commit() impure asm "COMMIT"; -() buy_gas(int gram) impure asm "BUYGAS"; - -int min(int x, int y) asm "MIN"; -int max(int x, int y) asm "MAX"; -(int, int) minmax(int x, int y) asm "MINMAX"; -int abs(int x) asm "ABS"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -cell preload_ref(slice s) asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -slice first_bits(slice s, int len) asm "SDCUTFIRST"; -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -slice slice_last(slice s, int len) asm "SDCUTLAST"; -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -cell preload_dict(slice s) asm "PLDDICT"; -slice skip_dict(slice s) asm "SKIPDICT"; - -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; - -int cell_depth(cell c) asm "CDEPTH"; - -int slice_refs(slice s) asm "SREFS"; -int slice_bits(slice s) asm "SBITS"; -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; -int slice_empty?(slice s) asm "SEMPTY"; -int slice_data_empty?(slice s) asm "SDEMPTY"; -int slice_refs_empty?(slice s) asm "SREMPTY"; -int slice_depth(slice s) asm "SDEPTH"; - -int builder_refs(builder b) asm "BREFS"; -int builder_bits(builder b) asm "BBITS"; -int builder_depth(builder b) asm "BDEPTH"; - -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -builder store_slice(builder b, slice s) asm "STSLICER"; -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_dict(builder b, cell c) asm(c b) "STDICT"; - -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -tuple parse_addr(slice s) asm "PARSEMSGADDR"; -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; - -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF" "NULLSWAPIFNOT"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF" "NULLSWAPIFNOT"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -cell new_dict() asm "NEWDICT"; -int dict_empty?(cell c) asm "DICTEMPTY"; - -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; - -cell config_param(int x) asm "CONFIGOPTPARAM"; -int cell_null?(cell c) asm "ISNULL"; - -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -() set_code(cell new_code) impure asm "SETCODE"; - -int random() impure asm "RANDU256"; -int rand(int range) impure asm "RAND"; -int get_seed() asm "RANDSEED"; -int set_seed() impure asm "SETRAND"; -() randomize(int x) impure asm "ADDRAND"; -() randomize_lt() impure asm "LTIME" "ADDRAND"; - -builder store_coins(builder b, int x) asm "STVARUINT16"; -(slice, int) load_coins(slice s) asm( -> 1 0) "LDVARUINT16"; - -int equal_slices (slice a, slice b) asm "SDEQ"; -int builder_null?(builder b) asm "ISNULL"; -builder store_builder(builder to, builder from) asm "STBR"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; +forall X -> X car(tuple list) pure asm "CAR"; +tuple cdr(tuple list) pure asm "CDR"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> [X] single(X x) pure asm "SINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; +forall X -> X first(tuple t) pure asm "FIRST"; +forall X -> X second(tuple t) pure asm "SECOND"; +forall X -> X third(tuple t) pure asm "THIRD"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; +forall X -> X null() pure asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; + +int now() pure asm "NOW"; +slice my_address() pure asm "MYADDR"; +[int, cell] get_balance() pure asm "BALANCE"; +int cur_lt() pure asm "LTIME"; +int block_lt() pure asm "BLOCKLT"; + +int cell_hash(cell c) pure asm "HASHCU"; +int slice_hash(slice s) pure asm "HASHSU"; +int string_hash(slice s) pure asm "SHA256U"; + +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; + +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; + +;; () throw_if(int excno, int cond) asm "THROWARGIF"; + +() dump_stack() asm "DUMPSTK"; + +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +cont get_c3() pure asm "c3 PUSH"; +() set_c3(cont c) asm "c3 POP"; +cont bless(slice s) pure asm "BLESS"; + +() accept_message() asm "ACCEPT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; +() commit() asm "COMMIT"; +() buy_gas(int gram) asm "BUYGAS"; + +int min(int x, int y) pure asm "MIN"; +int max(int x, int y) pure asm "MAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; +int abs(int x) pure asm "ABS"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; +;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; +;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; + +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; + +int cell_depth(cell c) pure asm "CDEPTH"; + +int slice_refs(slice s) pure asm "SREFS"; +int slice_bits(slice s) pure asm "SBITS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; +int slice_empty?(slice s) pure asm "SEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; +int slice_depth(slice s) pure asm "SDEPTH"; + +int builder_refs(builder b) pure asm "BREFS"; +int builder_bits(builder b) pure asm "BBITS"; +int builder_depth(builder b) pure asm "BDEPTH"; + +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; + +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; + +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF" "NULLSWAPIFNOT"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF" "NULLSWAPIFNOT"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; + +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; + +cell config_param(int x) pure asm "CONFIGOPTPARAM"; +int cell_null?(cell c) pure asm "ISNULL"; + +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; +() set_code(cell new_code) asm "SETCODE"; + +int random() asm "RANDU256"; +int rand(int range) asm "RAND"; +int get_seed() pure asm "RANDSEED"; +int set_seed() asm "SETRAND"; +() randomize(int x) asm "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; + +builder store_coins(builder b, int x) pure asm "STVARUINT16"; +(slice, int) load_coins(slice s) pure asm( -> 1 0) "LDVARUINT16"; + +int equal_slices (slice a, slice b) pure asm "SDEQ"; +int builder_null?(builder b) pure asm "ISNULL"; +builder store_builder(builder to, builder from) pure asm "STBR"; diff --git a/crypto/func/auto-tests/legacy_tests/elector/elector-code.fc b/crypto/func/auto-tests/legacy_tests/elector/elector-code.fc index f32858666..f39cab345 100644 --- a/crypto/func/auto-tests/legacy_tests/elector/elector-code.fc +++ b/crypto/func/auto-tests/legacy_tests/elector/elector-code.fc @@ -2,16 +2,16 @@ #include "stdlib.fc"; -(slice, cell) loadDict(slice s) { return load_dict(s); } -(slice, int) loadGrams(slice s) { return load_grams(s); } -(slice, int) loadUint(slice s, int len) { return load_uint(s, len); } -() endParse(slice s) impure { return end_parse(s); } -builder storeDict(builder b, cell c) { return store_dict(b, c); } -builder storeUint(builder b, int x, int len) { return store_uint(b, x, len); } -() throwUnless(int excno, int cond) impure { return throw_unless(excno, cond); } -cell configParam(int paramNo) { return config_param(paramNo); } -forall X -> int isNull(X x) { return null?(x); } -(slice, int) tryUDictGet(cell dict, int keyLen, int index) { return udict_get?(dict, keyLen, index); } +(slice, cell) loadDict(slice s) pure { return load_dict(s); } +(slice, int) loadGrams(slice s) pure { return load_grams(s); } +(slice, int) loadUint(slice s, int len) pure { return load_uint(s, len); } +() endParse(slice s) { return end_parse(s); } +builder storeDict(builder b, cell c) pure { return store_dict(b, c); } +builder storeUint(builder b, int x, int len) pure { return store_uint(b, x, len); } +() throwUnless(int excno, int cond) { return throw_unless(excno, cond); } +cell configParam(int paramNo) pure { return config_param(paramNo); } +forall X -> int isNull(X x) pure { return null?(x); } +(slice, int) tryUDictGet(cell dict, int keyLen, int index) pure { return udict_get?(dict, keyLen, index); } ;; cur_elect credits past_elections grams active_id active_hash @@ -23,7 +23,7 @@ forall X -> int isNull(X x) { return null?(x); } } ;; cur_elect credits past_elections grams active_id active_hash -() store_data(elect, credits, past_elections, grams, active_id, active_hash) impure inline_ref { +() store_data(elect, credits, past_elections, grams, active_id, active_hash) inline_ref { set_data(begin_cell() .storeDict(elect) .store_dict(credits) @@ -164,7 +164,7 @@ builder pack_complaint(int validator_pubkey, cell description, int created_at, i return (cs~load_uint(256), cs~load_uint(64)); } -() send_message_back(addr, ans_tag, query_id, body, grams, mode) impure inline_ref { +() send_message_back(addr, ans_tag, query_id, body, grams, mode) inline_ref { ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 011000 var msg = begin_cell() .store_uint(0x18, 6) @@ -179,15 +179,15 @@ builder pack_complaint(int validator_pubkey, cell description, int created_at, i send_raw_message(msg.end_cell(), mode); } -() return_stake(addr, query_id, reason) impure inline_ref { +() return_stake(addr, query_id, reason) inline_ref { return send_message_back(addr, 0xee6f454c, query_id, reason, 0, 64); } -() send_confirmation(addr, query_id, comment) impure inline_ref { +() send_confirmation(addr, query_id, comment) inline_ref { return send_message_back(addr, 0xf374484c, query_id, comment, 1000000000, 2); } -() send_validator_set_to_config(config_addr, vset, query_id) impure inline_ref { +() send_validator_set_to_config(config_addr, vset, query_id) inline_ref { var msg = begin_cell() .store_uint(0xc4ff, 17) ;; 0 11000100 0xff .store_uint(config_addr, 256) @@ -209,7 +209,7 @@ _ ~credit_to(credits, addr, amount) inline_ref { return (credits, ()); } -() process_new_stake(s_addr, msg_value, cs, query_id) impure inline_ref { +() process_new_stake(s_addr, msg_value, cs, query_id) inline_ref { var (src_wc, src_addr) = parse_std_addr(s_addr); var ds = get_data().begin_parse(); var elect = ds~load_dict(); @@ -359,7 +359,7 @@ _ unfreeze_all(credits, past_elections, elect_id) inline_ref { return (credits, past_elections, unused_prizes); } -() config_set_confirmed(s_addr, cs, query_id, ok) impure inline_ref { +() config_set_confirmed(s_addr, cs, query_id, ok) inline_ref { var (src_wc, src_addr) = parse_std_addr(s_addr); var config_addr = config_param(0).begin_parse().preload_uint(256); var ds = get_data().begin_parse(); @@ -390,7 +390,7 @@ _ unfreeze_all(credits, past_elections, elect_id) inline_ref { ;; ... do not remove elect until we see this set as the next elected validator set } -() process_simple_transfer(s_addr, msg_value) impure inline_ref { +() process_simple_transfer(s_addr, msg_value) inline_ref { var (elect, credits, past_elections, grams, active_id, active_hash) = load_data(); (int src_wc, int src_addr) = parse_std_addr(s_addr); if (src_addr | (src_wc + 1) | (active_id == 0)) { @@ -414,7 +414,7 @@ _ unfreeze_all(credits, past_elections, elect_id) inline_ref { return store_data(elect, credits, past_elections, grams, active_id, active_hash); } -() recover_stake(op, s_addr, cs, query_id) impure inline_ref { +() recover_stake(op, s_addr, cs, query_id) inline_ref { (int src_wc, int src_addr) = parse_std_addr(s_addr); if (src_wc + 1) { ;; not from masterchain, return error @@ -442,7 +442,7 @@ _ unfreeze_all(credits, past_elections, elect_id) inline_ref { .end_cell(), 64); } -() after_code_upgrade(slice s_addr, slice cs, int query_id) impure method_id(1666) { +() after_code_upgrade(slice s_addr, slice cs, int query_id) method_id(1666) { var op = 0x4e436f64; return send_message_back(s_addr, 0xce436f64, query_id, op, 0, 64); } @@ -592,7 +592,7 @@ int register_complaint(s_addr, complaint, msg_value) { return (complaints, complaint, 2); } -int proceed_register_vote(election_id, chash, idx, weight) impure inline_ref { +int proceed_register_vote(election_id, chash, idx, weight) inline_ref { var (elect, credits, past_elections, grams, active_id, active_hash) = load_data(); var (fs, f) = past_elections.udict_get?(32, election_id); ifnot (f) { ;; election not found @@ -613,7 +613,7 @@ int proceed_register_vote(election_id, chash, idx, weight) impure inline_ref { return status; } -() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure { +() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) { ;; do nothing for internal messages var cs = in_msg_cell.begin_parse(); var flags = cs~load_uint(4); ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool @@ -685,7 +685,7 @@ int proceed_register_vote(election_id, chash, idx, weight) impure inline_ref { return (); } -int postpone_elections() impure { +int postpone_elections() { return false; } @@ -813,7 +813,7 @@ _ compute_total_stake(l, n, m_stake) inline_ref { return (credits, vset, tot_weight, frozen, tot_stake, m); } -int conduct_elections(ds, elect, credits) impure { +int conduct_elections(ds, elect, credits) { var (elect_at, elect_close, min_stake, total_stake, members, failed, finished) = elect.unpack_elect(); if (now() < elect_close) { ;; elections not finished yet @@ -882,7 +882,7 @@ int conduct_elections(ds, elect, credits) impure { return true; } -int update_active_vset_id() impure { +int update_active_vset_id() { var (elect, credits, past_elections, grams, active_id, active_hash) = load_data(); var cur_hash = config_param(34).cell_hash(); if (cur_hash == active_hash) { @@ -940,7 +940,7 @@ int cell_hash_eq?(cell vset, int expected_vset_hash) inline_ref { return vset.null?() ? false : cell_hash(vset) == expected_vset_hash; } -int validator_set_installed(ds, elect, credits) impure { +int validator_set_installed(ds, elect, credits) { var (elect_at, elect_close, min_stake, total_stake, members, failed, finished) = elect.unpack_elect(); ifnot (finished) { ;; elections not finished yet @@ -968,7 +968,7 @@ int validator_set_installed(ds, elect, credits) impure { return false; } -int check_unfreeze() impure { +int check_unfreeze() { var (elect, credits, past_elections, grams, active_id, active_hash) = load_data(); int id = -1; do { @@ -1029,7 +1029,7 @@ int announce_new_elections(ds, elect, credits) { return true; } -() run_ticktock(int is_tock) impure { +() run_ticktock(int is_tock) { ;; check whether an election is being conducted var ds = get_data().begin_parse(); var (elect, credits) = (ds~load_dict(), ds~load_dict()); diff --git a/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc b/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc index 41ab33823..8d0224d02 100644 --- a/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc @@ -1,208 +1,208 @@ // Standard library for funC // -forall X -> tuple cons(X head, tuple tail) asm "CONS"; -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -forall X -> X car(tuple list) asm "CAR"; -tuple cdr(tuple list) asm "CDR"; -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> [X] single(X x) asm "SINGLE"; -forall X -> X unsingle([X] t) asm "UNSINGLE"; -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -forall X -> X first(tuple t) asm "FIRST"; -forall X -> X second(tuple t) asm "SECOND"; -forall X -> X third(tuple t) asm "THIRD"; -forall X -> X fourth(tuple t) asm "3 INDEX"; -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -forall X -> X null() asm "PUSHNULL"; -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; - -int now() asm "NOW"; -slice my_address() asm "MYADDR"; -[int, cell] get_balance() asm "BALANCE"; -int cur_lt() asm "LTIME"; -int block_lt() asm "BLOCKLT"; - -int cell_hash(cell c) asm "HASHCU"; -int slice_hash(slice s) asm "HASHSU"; -int string_hash(slice s) asm "SHA256U"; - -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; - -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -// () throw_if(int excno, int cond) impure asm "THROWARGIF"; - -() dump_stack() impure asm "DUMPSTK"; - -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -cont get_c3() asm "c3 PUSH"; -() set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) asm "BLESS"; - -() accept_message() impure asm "ACCEPT"; -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; -() commit() impure asm "COMMIT"; -() buy_gas(int gram) impure asm "BUYGAS"; - -int min(int x, int y) asm "MIN"; -int max(int x, int y) asm "MAX"; -(int, int) minmax(int x, int y) asm "MINMAX"; -int abs(int x) asm "ABS"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -cell preload_ref(slice s) asm "PLDREF"; -// (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -// (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -// int preload_int(slice s, int len) asm "PLDIX"; -// int preload_uint(slice s, int len) asm "PLDUX"; -// (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -// slice preload_bits(slice s, int len) asm "PLDSLICEX"; -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -slice first_bits(slice s, int len) asm "SDCUTFIRST"; -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -slice slice_last(slice s, int len) asm "SDCUTLAST"; -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -cell preload_dict(slice s) asm "PLDDICT"; -slice skip_dict(slice s) asm "SKIPDICT"; - -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; - -int cell_depth(cell c) asm "CDEPTH"; - -int slice_refs(slice s) asm "SREFS"; -int slice_bits(slice s) asm "SBITS"; -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; -int slice_empty?(slice s) asm "SEMPTY"; -int slice_data_empty?(slice s) asm "SDEMPTY"; -int slice_refs_empty?(slice s) asm "SREMPTY"; -int slice_depth(slice s) asm "SDEPTH"; - -int builder_refs(builder b) asm "BREFS"; -int builder_bits(builder b) asm "BBITS"; -int builder_depth(builder b) asm "BDEPTH"; - -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -// builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -// builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -builder store_slice(builder b, slice s) asm "STSLICER"; -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_dict(builder b, cell c) asm(c b) "STDICT"; - -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -tuple parse_addr(slice s) asm "PARSEMSGADDR"; -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; - -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -cell new_dict() asm "NEWDICT"; -int dict_empty?(cell c) asm "DICTEMPTY"; - -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; - -cell config_param(int x) asm "CONFIGOPTPARAM"; -int cell_null?(cell c) asm "ISNULL"; - -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -() set_code(cell new_code) impure asm "SETCODE"; - -int random() impure asm "RANDU256"; -int rand(int range) impure asm "RAND"; -int get_seed() asm "RANDSEED"; -int set_seed() impure asm "SETRAND"; -() randomize(int x) impure asm "ADDRAND"; -() randomize_lt() impure asm "LTIME" "ADDRAND"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; +forall X -> X car(tuple list) pure asm "CAR"; +tuple cdr(tuple list) pure asm "CDR"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> [X] single(X x) pure asm "SINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; +forall X -> X first(tuple t) pure asm "FIRST"; +forall X -> X second(tuple t) pure asm "SECOND"; +forall X -> X third(tuple t) pure asm "THIRD"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; +forall X -> X null() pure asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; + +int now() pure asm "NOW"; +slice my_address() pure asm "MYADDR"; +[int, cell] get_balance() pure asm "BALANCE"; +int cur_lt() pure asm "LTIME"; +int block_lt() pure asm "BLOCKLT"; + +int cell_hash(cell c) pure asm "HASHCU"; +int slice_hash(slice s) pure asm "HASHSU"; +int string_hash(slice s) pure asm "SHA256U"; + +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; + +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; + +// () throw_if(int excno, int cond) asm "THROWARGIF"; + +() dump_stack() asm "DUMPSTK"; + +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +cont get_c3() pure asm "c3 PUSH"; +() set_c3(cont c) asm "c3 POP"; +cont bless(slice s) pure asm "BLESS"; + +() accept_message() asm "ACCEPT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; +() commit() asm "COMMIT"; +() buy_gas(int gram) asm "BUYGAS"; + +int min(int x, int y) pure asm "MIN"; +int max(int x, int y) pure asm "MAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; +int abs(int x) pure asm "ABS"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; +// (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +// (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +// int preload_int(slice s, int len) pure asm "PLDIX"; +// int preload_uint(slice s, int len) pure asm "PLDUX"; +// (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +// slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; + +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; + +int cell_depth(cell c) pure asm "CDEPTH"; + +int slice_refs(slice s) pure asm "SREFS"; +int slice_bits(slice s) pure asm "SBITS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; +int slice_empty?(slice s) pure asm "SEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; +int slice_depth(slice s) pure asm "SDEPTH"; + +int builder_refs(builder b) pure asm "BREFS"; +int builder_bits(builder b) pure asm "BBITS"; +int builder_depth(builder b) pure asm "BDEPTH"; + +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +// builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +// builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; + +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; + +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; + +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; + +cell config_param(int x) pure asm "CONFIGOPTPARAM"; +int cell_null?(cell c) pure asm "ISNULL"; + +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; +() set_code(cell new_code) asm "SETCODE"; + +int random() asm "RANDU256"; +int rand(int range) asm "RAND"; +int get_seed() pure asm "RANDSEED"; +int set_seed() asm "SETRAND"; +() randomize(int x) asm "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc b/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc index 04b6e4d3c..15d7bcbe8 100644 --- a/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc @@ -1,209 +1,209 @@ ;; Standard library for funC ;; -forall X -> tuple cons(X head, tuple tail) asm "CONS"; -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -forall X -> X car(tuple list) asm "CAR"; -tuple cdr(tuple list) asm "CDR"; -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> [X] single(X x) asm "SINGLE"; -forall X -> X unsingle([X] t) asm "UNSINGLE"; -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -forall X -> X first(tuple t) asm "FIRST"; -forall X -> X second(tuple t) asm "SECOND"; -forall X -> X third(tuple t) asm "THIRD"; -forall X -> X fourth(tuple t) asm "3 INDEX"; -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -forall X -> X null() asm "PUSHNULL"; -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; - -int now() asm "NOW"; -slice my_address() asm "MYADDR"; -[int, cell] get_balance() asm "BALANCE"; -int cur_lt() asm "LTIME"; -int block_lt() asm "BLOCKLT"; - -int cell_hash(cell c) asm "HASHCU"; -int slice_hash(slice s) asm "HASHSU"; -int string_hash(slice s) asm "SHA256U"; - -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; - -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; - -() dump_stack() impure asm "DUMPSTK"; - -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -cont get_c3() asm "c3 PUSH"; -() set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) asm "BLESS"; - -() accept_message() impure asm "ACCEPT"; -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; -() commit() impure asm "COMMIT"; -() buy_gas(int gram) impure asm "BUYGAS"; - -int min(int x, int y) asm "MIN"; -int max(int x, int y) asm "MAX"; -(int, int) minmax(int x, int y) asm "MINMAX"; -int abs(int x) asm "ABS"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -cell preload_ref(slice s) asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -slice first_bits(slice s, int len) asm "SDCUTFIRST"; -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -slice slice_last(slice s, int len) asm "SDCUTLAST"; -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -cell preload_dict(slice s) asm "PLDDICT"; -slice skip_dict(slice s) asm "SKIPDICT"; - -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; - -int cell_depth(cell c) asm "CDEPTH"; - -int slice_refs(slice s) asm "SREFS"; -int slice_bits(slice s) asm "SBITS"; -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; -int slice_empty?(slice s) asm "SEMPTY"; -int slice_data_empty?(slice s) asm "SDEMPTY"; -int slice_refs_empty?(slice s) asm "SREMPTY"; -int slice_depth(slice s) asm "SDEPTH"; - -int builder_refs(builder b) asm "BREFS"; -int builder_bits(builder b) asm "BBITS"; -int builder_depth(builder b) asm "BDEPTH"; - -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -builder store_slice(builder b, slice s) asm "STSLICER"; -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_dict(builder b, cell c) asm(c b) "STDICT"; - -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -tuple parse_addr(slice s) asm "PARSEMSGADDR"; -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; - -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -cell new_dict() asm "NEWDICT"; -int dict_empty?(cell c) asm "DICTEMPTY"; - -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; - -cell config_param(int x) asm "CONFIGOPTPARAM"; -int cell_null?(cell c) asm "ISNULL"; - -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -() set_code(cell new_code) impure asm "SETCODE"; - -int random() impure asm "RANDU256"; -int rand(int range) impure asm "RAND"; -int get_seed() asm "RANDSEED"; -int set_seed() impure asm "SETRAND"; -() randomize(int x) impure asm "ADDRAND"; -() randomize_lt() impure asm "LTIME" "ADDRAND"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; +forall X -> X car(tuple list) pure asm "CAR"; +tuple cdr(tuple list) pure asm "CDR"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> [X] single(X x) pure asm "SINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; +forall X -> X first(tuple t) pure asm "FIRST"; +forall X -> X second(tuple t) pure asm "SECOND"; +forall X -> X third(tuple t) pure asm "THIRD"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; +forall X -> X null() pure asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; + +int now() pure asm "NOW"; +slice my_address() pure asm "MYADDR"; +[int, cell] get_balance() pure asm "BALANCE"; +int cur_lt() pure asm "LTIME"; +int block_lt() pure asm "BLOCKLT"; + +int cell_hash(cell c) pure asm "HASHCU"; +int slice_hash(slice s) pure asm "HASHSU"; +int string_hash(slice s) pure asm "SHA256U"; + +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; + +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; + +;; () throw_if(int excno, int cond) asm "THROWARGIF"; + +() dump_stack() asm "DUMPSTK"; + +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +cont get_c3() pure asm "c3 PUSH"; +() set_c3(cont c) asm "c3 POP"; +cont bless(slice s) pure asm "BLESS"; + +() accept_message() asm "ACCEPT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; +() commit() asm "COMMIT"; +() buy_gas(int gram) asm "BUYGAS"; + +int min(int x, int y) pure asm "MIN"; +int max(int x, int y) pure asm "MAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; +int abs(int x) pure asm "ABS"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; +;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; +;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; + +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; + +int cell_depth(cell c) pure asm "CDEPTH"; + +int slice_refs(slice s) pure asm "SREFS"; +int slice_bits(slice s) pure asm "SBITS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; +int slice_empty?(slice s) pure asm "SEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; +int slice_depth(slice s) pure asm "SDEPTH"; + +int builder_refs(builder b) pure asm "BREFS"; +int builder_bits(builder b) pure asm "BBITS"; +int builder_depth(builder b) pure asm "BDEPTH"; + +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; + +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; + +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; + +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; + +cell config_param(int x) pure asm "CONFIGOPTPARAM"; +int cell_null?(cell c) pure asm "ISNULL"; + +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; +() set_code(cell new_code) asm "SETCODE"; + +int random() asm "RANDU256"; +int rand(int range) asm "RAND"; +int get_seed() pure asm "RANDSEED"; +int set_seed() asm "SETRAND"; +() randomize(int x) asm "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc b/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc index 6ae2a28d2..f4b671bd9 100644 --- a/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc @@ -1,215 +1,215 @@ ;; Standard library for funC ;; -forall X -> tuple cons(X head, tuple tail) asm "CONS"; -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -forall X -> X car(tuple list) asm "CAR"; -tuple cdr(tuple list) asm "CDR"; -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> [X] single(X x) asm "SINGLE"; -forall X -> X unsingle([X] t) asm "UNSINGLE"; -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -forall X -> X first(tuple t) asm "FIRST"; -forall X -> X second(tuple t) asm "SECOND"; -forall X -> X third(tuple t) asm "THIRD"; -forall X -> X fourth(tuple t) asm "3 INDEX"; -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -forall X -> X null() asm "PUSHNULL"; -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; - -int now() asm "NOW"; -slice my_address() asm "MYADDR"; -[int, cell] get_balance() asm "BALANCE"; -int cur_lt() asm "LTIME"; -int block_lt() asm "BLOCKLT"; - -int cell_hash(cell c) asm "HASHCU"; -int slice_hash(slice s) asm "HASHSU"; -int string_hash(slice s) asm "SHA256U"; - -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; - -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; - -() dump_stack() impure asm "DUMPSTK"; - -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -cont get_c3() asm "c3 PUSH"; -() set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) asm "BLESS"; - -() accept_message() impure asm "ACCEPT"; -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; -() commit() impure asm "COMMIT"; -() buy_gas(int gram) impure asm "BUYGAS"; - -int min(int x, int y) asm "MIN"; -int max(int x, int y) asm "MAX"; -(int, int) minmax(int x, int y) asm "MINMAX"; -int abs(int x) asm "ABS"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -cell preload_ref(slice s) asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -slice first_bits(slice s, int len) asm "SDCUTFIRST"; -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -slice slice_last(slice s, int len) asm "SDCUTLAST"; -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -cell preload_dict(slice s) asm "PLDDICT"; -slice skip_dict(slice s) asm "SKIPDICT"; - -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; - -int cell_depth(cell c) asm "CDEPTH"; - -int slice_refs(slice s) asm "SREFS"; -int slice_bits(slice s) asm "SBITS"; -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; -int slice_empty?(slice s) asm "SEMPTY"; -int slice_data_empty?(slice s) asm "SDEMPTY"; -int slice_refs_empty?(slice s) asm "SREMPTY"; -int slice_depth(slice s) asm "SDEPTH"; - -int builder_refs(builder b) asm "BREFS"; -int builder_bits(builder b) asm "BBITS"; -int builder_depth(builder b) asm "BDEPTH"; - -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; - builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -builder store_slice(builder b, slice s) asm "STSLICER"; -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_dict(builder b, cell c) asm(c b) "STDICT"; - -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -tuple parse_addr(slice s) asm "PARSEMSGADDR"; -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; - -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -cell new_dict() asm "NEWDICT"; -int dict_empty?(cell c) asm "DICTEMPTY"; - -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; - -cell config_param(int x) asm "CONFIGOPTPARAM"; -int cell_null?(cell c) asm "ISNULL"; - -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -() set_code(cell new_code) impure asm "SETCODE"; - -int random() impure asm "RANDU256"; -int rand(int range) impure asm "RAND"; -int get_seed() asm "RANDSEED"; -int set_seed() impure asm "SETRAND"; -() randomize(int x) impure asm "ADDRAND"; -() randomize_lt() impure asm "LTIME" "ADDRAND"; - -builder store_coins(builder b, int x) asm "STVARUINT16"; -(slice, int) load_coins(slice s) asm( -> 1 0) "LDVARUINT16"; - -int equal_slices (slice a, slice b) asm "SDEQ"; -int builder_null?(builder b) asm "ISNULL"; -builder store_builder(builder to, builder from) asm "STBR"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; +forall X -> X car(tuple list) pure asm "CAR"; +tuple cdr(tuple list) pure asm "CDR"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> [X] single(X x) pure asm "SINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; +forall X -> X first(tuple t) pure asm "FIRST"; +forall X -> X second(tuple t) pure asm "SECOND"; +forall X -> X third(tuple t) pure asm "THIRD"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; +forall X -> X null() pure asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; + +int now() pure asm "NOW"; +slice my_address() pure asm "MYADDR"; +[int, cell] get_balance() pure asm "BALANCE"; +int cur_lt() pure asm "LTIME"; +int block_lt() pure asm "BLOCKLT"; + +int cell_hash(cell c) pure asm "HASHCU"; +int slice_hash(slice s) pure asm "HASHSU"; +int string_hash(slice s) pure asm "SHA256U"; + +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; + +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; + +;; () throw_if(int excno, int cond) asm "THROWARGIF"; + +() dump_stack() asm "DUMPSTK"; + +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +cont get_c3() pure asm "c3 PUSH"; +() set_c3(cont c) asm "c3 POP"; +cont bless(slice s) pure asm "BLESS"; + +() accept_message() asm "ACCEPT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; +() commit() asm "COMMIT"; +() buy_gas(int gram) asm "BUYGAS"; + +int min(int x, int y) pure asm "MIN"; +int max(int x, int y) pure asm "MAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; +int abs(int x) pure asm "ABS"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; +;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; +;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; + +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; + +int cell_depth(cell c) pure asm "CDEPTH"; + +int slice_refs(slice s) pure asm "SREFS"; +int slice_bits(slice s) pure asm "SBITS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; +int slice_empty?(slice s) pure asm "SEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; +int slice_depth(slice s) pure asm "SDEPTH"; + +int builder_refs(builder b) pure asm "BREFS"; +int builder_bits(builder b) pure asm "BBITS"; +int builder_depth(builder b) pure asm "BDEPTH"; + +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; + builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; + +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; + +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; + +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; + +cell config_param(int x) pure asm "CONFIGOPTPARAM"; +int cell_null?(cell c) pure asm "ISNULL"; + +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; +() set_code(cell new_code) asm "SETCODE"; + +int random() asm "RANDU256"; +int rand(int range) asm "RAND"; +int get_seed() pure asm "RANDSEED"; +int set_seed() asm "SETRAND"; +() randomize(int x) asm "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; + +builder store_coins(builder b, int x) pure asm "STVARUINT16"; +(slice, int) load_coins(slice s) pure asm( -> 1 0) "LDVARUINT16"; + +int equal_slices (slice a, slice b) pure asm "SDEQ"; +int builder_null?(builder b) pure asm "ISNULL"; +builder store_builder(builder to, builder from) pure asm "STBR"; diff --git a/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/params.fc b/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/params.fc index e28eac458..471ed9fdf 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/params.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/params.fc @@ -1,6 +1,6 @@ int workchain() asm "0 PUSHINT"; -() force_chain(slice addr) impure { +() force_chain(slice addr) { (int wc, _) = parse_std_addr(addr); throw_unless(333, wc == workchain()); -} \ No newline at end of file +} diff --git a/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc b/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc index f04be0b68..a76e869dc 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc @@ -1,215 +1,215 @@ ;; Standard library for funC ;; -forall X -> tuple cons(X head, tuple tail) asm "CONS"; -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -forall X -> X car(tuple list) asm "CAR"; -tuple cdr(tuple list) asm "CDR"; -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> [X] single(X x) asm "SINGLE"; -forall X -> X unsingle([X] t) asm "UNSINGLE"; -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -forall X -> X first(tuple t) asm "FIRST"; -forall X -> X second(tuple t) asm "SECOND"; -forall X -> X third(tuple t) asm "THIRD"; -forall X -> X fourth(tuple t) asm "3 INDEX"; -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -forall X -> X null() asm "PUSHNULL"; -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; - -int now() asm "NOW"; -slice my_address() asm "MYADDR"; -[int, cell] get_balance() asm "BALANCE"; -int cur_lt() asm "LTIME"; -int block_lt() asm "BLOCKLT"; - -int cell_hash(cell c) asm "HASHCU"; -int slice_hash(slice s) asm "HASHSU"; -int string_hash(slice s) asm "SHA256U"; - -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; - -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; - -() dump_stack() impure asm "DUMPSTK"; - -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -cont get_c3() asm "c3 PUSH"; -() set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) asm "BLESS"; - -() accept_message() impure asm "ACCEPT"; -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; -() commit() impure asm "COMMIT"; -() buy_gas(int gram) impure asm "BUYGAS"; - -int min(int x, int y) asm "MIN"; -int max(int x, int y) asm "MAX"; -(int, int) minmax(int x, int y) asm "MINMAX"; -int abs(int x) asm "ABS"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -cell preload_ref(slice s) asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -slice first_bits(slice s, int len) asm "SDCUTFIRST"; -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -slice slice_last(slice s, int len) asm "SDCUTLAST"; -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -cell preload_dict(slice s) asm "PLDDICT"; -slice skip_dict(slice s) asm "SKIPDICT"; - -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; - -int cell_depth(cell c) asm "CDEPTH"; - -int slice_refs(slice s) asm "SREFS"; -int slice_bits(slice s) asm "SBITS"; -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; -int slice_empty?(slice s) asm "SEMPTY"; -int slice_data_empty?(slice s) asm "SDEMPTY"; -int slice_refs_empty?(slice s) asm "SREMPTY"; -int slice_depth(slice s) asm "SDEPTH"; - -int builder_refs(builder b) asm "BREFS"; -int builder_bits(builder b) asm "BBITS"; -int builder_depth(builder b) asm "BDEPTH"; - -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -builder store_slice(builder b, slice s) asm "STSLICER"; -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_dict(builder b, cell c) asm(c b) "STDICT"; - -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -tuple parse_addr(slice s) asm "PARSEMSGADDR"; -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; - -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -cell new_dict() asm "NEWDICT"; -int dict_empty?(cell c) asm "DICTEMPTY"; - -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; - -cell config_param(int x) asm "CONFIGOPTPARAM"; -int cell_null?(cell c) asm "ISNULL"; - -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -() set_code(cell new_code) impure asm "SETCODE"; - -int random() impure asm "RANDU256"; -int rand(int range) impure asm "RAND"; -int get_seed() asm "RANDSEED"; -int set_seed() impure asm "SETRAND"; -() randomize(int x) impure asm "ADDRAND"; -() randomize_lt() impure asm "LTIME" "ADDRAND"; - -builder store_coins(builder b, int x) asm "STVARUINT16"; -(slice, int) load_coins(slice s) asm( -> 1 0) "LDVARUINT16"; - -int equal_slices (slice a, slice b) asm "SDEQ"; -int builder_null?(builder b) asm "ISNULL"; -builder store_builder(builder to, builder from) asm "STBR"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; +forall X -> X car(tuple list) pure asm "CAR"; +tuple cdr(tuple list) pure asm "CDR"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> [X] single(X x) pure asm "SINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; +forall X -> X first(tuple t) pure asm "FIRST"; +forall X -> X second(tuple t) pure asm "SECOND"; +forall X -> X third(tuple t) pure asm "THIRD"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; +forall X -> X null() pure asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; + +int now() pure asm "NOW"; +slice my_address() pure asm "MYADDR"; +[int, cell] get_balance() pure asm "BALANCE"; +int cur_lt() pure asm "LTIME"; +int block_lt() pure asm "BLOCKLT"; + +int cell_hash(cell c) pure asm "HASHCU"; +int slice_hash(slice s) pure asm "HASHSU"; +int string_hash(slice s) pure asm "SHA256U"; + +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; + +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; + +;; () throw_if(int excno, int cond) asm "THROWARGIF"; + +() dump_stack() asm "DUMPSTK"; + +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +cont get_c3() pure asm "c3 PUSH"; +() set_c3(cont c) asm "c3 POP"; +cont bless(slice s) pure asm "BLESS"; + +() accept_message() asm "ACCEPT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; +() commit() asm "COMMIT"; +() buy_gas(int gram) asm "BUYGAS"; + +int min(int x, int y) pure asm "MIN"; +int max(int x, int y) pure asm "MAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; +int abs(int x) pure asm "ABS"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; +;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; +;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; + +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; + +int cell_depth(cell c) pure asm "CDEPTH"; + +int slice_refs(slice s) pure asm "SREFS"; +int slice_bits(slice s) pure asm "SBITS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; +int slice_empty?(slice s) pure asm "SEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; +int slice_depth(slice s) pure asm "SDEPTH"; + +int builder_refs(builder b) pure asm "BREFS"; +int builder_bits(builder b) pure asm "BBITS"; +int builder_depth(builder b) pure asm "BDEPTH"; + +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; + +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; + +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; + +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; + +cell config_param(int x) pure asm "CONFIGOPTPARAM"; +int cell_null?(cell c) pure asm "ISNULL"; + +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; +() set_code(cell new_code) asm "SETCODE"; + +int random() asm "RANDU256"; +int rand(int range) asm "RAND"; +int get_seed() pure asm "RANDSEED"; +int set_seed() asm "SETRAND"; +() randomize(int x) asm "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; + +builder store_coins(builder b, int x) pure asm "STVARUINT16"; +(slice, int) load_coins(slice s) pure asm( -> 1 0) "LDVARUINT16"; + +int equal_slices (slice a, slice b) pure asm "SDEQ"; +int builder_null?(builder b) pure asm "ISNULL"; +builder store_builder(builder to, builder from) pure asm "STBR"; diff --git a/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/utils.fc b/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/utils.fc index 230a8f798..b8582878f 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/utils.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/utils.fc @@ -1,4 +1,4 @@ -() send_grams(slice address, int amount) impure { +() send_grams(slice address, int amount) { cell msg = begin_cell() .store_uint (0x18, 6) ;; bounce .store_slice(address) ;; 267 bit address diff --git a/crypto/func/auto-tests/legacy_tests/jetton-minter/jetton-minter.fc b/crypto/func/auto-tests/legacy_tests/jetton-minter/jetton-minter.fc index 73776e646..3db37e1c3 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-minter/jetton-minter.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-minter/jetton-minter.fc @@ -21,7 +21,7 @@ ); } -() save_data(int total_supply, slice admin_address, cell content, cell jetton_wallet_code) impure inline { +() save_data(int total_supply, slice admin_address, cell content, cell jetton_wallet_code) inline { set_data(begin_cell() .store_coins(total_supply) .store_slice(admin_address) @@ -31,7 +31,7 @@ ); } -() mint_tokens(slice to_address, cell jetton_wallet_code, int amount, cell master_msg) impure { +() mint_tokens(slice to_address, cell jetton_wallet_code, int amount, cell master_msg) { cell state_init = calculate_jetton_wallet_state_init(to_address, my_address(), jetton_wallet_code); slice to_wallet_address = calculate_jetton_wallet_address(state_init); var msg = begin_cell() @@ -44,7 +44,7 @@ send_raw_message(msg.end_cell(), 1); ;; pay transfer fees separately, revert on errors } -() recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) impure { +() recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) { if (in_msg_body.slice_empty?()) { ;; ignore empty messages return (); } diff --git a/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/params.fc b/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/params.fc index e28eac458..471ed9fdf 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/params.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/params.fc @@ -1,6 +1,6 @@ int workchain() asm "0 PUSHINT"; -() force_chain(slice addr) impure { +() force_chain(slice addr) { (int wc, _) = parse_std_addr(addr); throw_unless(333, wc == workchain()); -} \ No newline at end of file +} diff --git a/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc b/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc index f04be0b68..a76e869dc 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc @@ -1,215 +1,215 @@ ;; Standard library for funC ;; -forall X -> tuple cons(X head, tuple tail) asm "CONS"; -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -forall X -> X car(tuple list) asm "CAR"; -tuple cdr(tuple list) asm "CDR"; -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> [X] single(X x) asm "SINGLE"; -forall X -> X unsingle([X] t) asm "UNSINGLE"; -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -forall X -> X first(tuple t) asm "FIRST"; -forall X -> X second(tuple t) asm "SECOND"; -forall X -> X third(tuple t) asm "THIRD"; -forall X -> X fourth(tuple t) asm "3 INDEX"; -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -forall X -> X null() asm "PUSHNULL"; -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; - -int now() asm "NOW"; -slice my_address() asm "MYADDR"; -[int, cell] get_balance() asm "BALANCE"; -int cur_lt() asm "LTIME"; -int block_lt() asm "BLOCKLT"; - -int cell_hash(cell c) asm "HASHCU"; -int slice_hash(slice s) asm "HASHSU"; -int string_hash(slice s) asm "SHA256U"; - -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; - -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; - -() dump_stack() impure asm "DUMPSTK"; - -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -cont get_c3() asm "c3 PUSH"; -() set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) asm "BLESS"; - -() accept_message() impure asm "ACCEPT"; -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; -() commit() impure asm "COMMIT"; -() buy_gas(int gram) impure asm "BUYGAS"; - -int min(int x, int y) asm "MIN"; -int max(int x, int y) asm "MAX"; -(int, int) minmax(int x, int y) asm "MINMAX"; -int abs(int x) asm "ABS"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -cell preload_ref(slice s) asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -slice first_bits(slice s, int len) asm "SDCUTFIRST"; -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -slice slice_last(slice s, int len) asm "SDCUTLAST"; -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -cell preload_dict(slice s) asm "PLDDICT"; -slice skip_dict(slice s) asm "SKIPDICT"; - -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; - -int cell_depth(cell c) asm "CDEPTH"; - -int slice_refs(slice s) asm "SREFS"; -int slice_bits(slice s) asm "SBITS"; -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; -int slice_empty?(slice s) asm "SEMPTY"; -int slice_data_empty?(slice s) asm "SDEMPTY"; -int slice_refs_empty?(slice s) asm "SREMPTY"; -int slice_depth(slice s) asm "SDEPTH"; - -int builder_refs(builder b) asm "BREFS"; -int builder_bits(builder b) asm "BBITS"; -int builder_depth(builder b) asm "BDEPTH"; - -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -builder store_slice(builder b, slice s) asm "STSLICER"; -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_dict(builder b, cell c) asm(c b) "STDICT"; - -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -tuple parse_addr(slice s) asm "PARSEMSGADDR"; -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; - -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -cell new_dict() asm "NEWDICT"; -int dict_empty?(cell c) asm "DICTEMPTY"; - -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; - -cell config_param(int x) asm "CONFIGOPTPARAM"; -int cell_null?(cell c) asm "ISNULL"; - -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -() set_code(cell new_code) impure asm "SETCODE"; - -int random() impure asm "RANDU256"; -int rand(int range) impure asm "RAND"; -int get_seed() asm "RANDSEED"; -int set_seed() impure asm "SETRAND"; -() randomize(int x) impure asm "ADDRAND"; -() randomize_lt() impure asm "LTIME" "ADDRAND"; - -builder store_coins(builder b, int x) asm "STVARUINT16"; -(slice, int) load_coins(slice s) asm( -> 1 0) "LDVARUINT16"; - -int equal_slices (slice a, slice b) asm "SDEQ"; -int builder_null?(builder b) asm "ISNULL"; -builder store_builder(builder to, builder from) asm "STBR"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; +forall X -> X car(tuple list) pure asm "CAR"; +tuple cdr(tuple list) pure asm "CDR"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> [X] single(X x) pure asm "SINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; +forall X -> X first(tuple t) pure asm "FIRST"; +forall X -> X second(tuple t) pure asm "SECOND"; +forall X -> X third(tuple t) pure asm "THIRD"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; +forall X -> X null() pure asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; + +int now() pure asm "NOW"; +slice my_address() pure asm "MYADDR"; +[int, cell] get_balance() pure asm "BALANCE"; +int cur_lt() pure asm "LTIME"; +int block_lt() pure asm "BLOCKLT"; + +int cell_hash(cell c) pure asm "HASHCU"; +int slice_hash(slice s) pure asm "HASHSU"; +int string_hash(slice s) pure asm "SHA256U"; + +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; + +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; + +;; () throw_if(int excno, int cond) asm "THROWARGIF"; + +() dump_stack() asm "DUMPSTK"; + +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +cont get_c3() pure asm "c3 PUSH"; +() set_c3(cont c) asm "c3 POP"; +cont bless(slice s) pure asm "BLESS"; + +() accept_message() asm "ACCEPT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; +() commit() asm "COMMIT"; +() buy_gas(int gram) asm "BUYGAS"; + +int min(int x, int y) pure asm "MIN"; +int max(int x, int y) pure asm "MAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; +int abs(int x) pure asm "ABS"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; +;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; +;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; + +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; + +int cell_depth(cell c) pure asm "CDEPTH"; + +int slice_refs(slice s) pure asm "SREFS"; +int slice_bits(slice s) pure asm "SBITS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; +int slice_empty?(slice s) pure asm "SEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; +int slice_depth(slice s) pure asm "SDEPTH"; + +int builder_refs(builder b) pure asm "BREFS"; +int builder_bits(builder b) pure asm "BBITS"; +int builder_depth(builder b) pure asm "BDEPTH"; + +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; + +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; + +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; + +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; + +cell config_param(int x) pure asm "CONFIGOPTPARAM"; +int cell_null?(cell c) pure asm "ISNULL"; + +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; +() set_code(cell new_code) asm "SETCODE"; + +int random() asm "RANDU256"; +int rand(int range) asm "RAND"; +int get_seed() pure asm "RANDSEED"; +int set_seed() asm "SETRAND"; +() randomize(int x) asm "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; + +builder store_coins(builder b, int x) pure asm "STVARUINT16"; +(slice, int) load_coins(slice s) pure asm( -> 1 0) "LDVARUINT16"; + +int equal_slices (slice a, slice b) pure asm "SDEQ"; +int builder_null?(builder b) pure asm "ISNULL"; +builder store_builder(builder to, builder from) pure asm "STBR"; diff --git a/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/utils.fc b/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/utils.fc index 230a8f798..b8582878f 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/utils.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/utils.fc @@ -1,4 +1,4 @@ -() send_grams(slice address, int amount) impure { +() send_grams(slice address, int amount) { cell msg = begin_cell() .store_uint (0x18, 6) ;; bounce .store_slice(address) ;; 267 bit address diff --git a/crypto/func/auto-tests/legacy_tests/jetton-wallet/jetton-wallet.fc b/crypto/func/auto-tests/legacy_tests/jetton-wallet/jetton-wallet.fc index 01cc91bce..41bc443ab 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-wallet/jetton-wallet.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-wallet/jetton-wallet.fc @@ -33,7 +33,7 @@ const gas_consumption = 10000000; ;; 0.01 TON return (ds~load_coins(), ds~load_msg_addr(), ds~load_msg_addr(), ds~load_ref()); } -() save_data (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) impure inline { +() save_data (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) inline { set_data(pack_jetton_wallet_data(balance, owner_address, jetton_master_address, jetton_wallet_code)); } @@ -49,7 +49,7 @@ const gas_consumption = 10000000; ;; 0.01 TON = InternalMsgBody; -} -() send_tokens (slice in_msg_body, slice sender_address, int msg_value, int fwd_fee) impure { +() send_tokens (slice in_msg_body, slice sender_address, int msg_value, int fwd_fee) { int query_id = in_msg_body~load_uint(64); int jetton_amount = in_msg_body~load_coins(); slice to_owner_address = in_msg_body~load_msg_addr(); @@ -107,7 +107,7 @@ const gas_consumption = 10000000; ;; 0.01 TON = InternalMsgBody; -} -() receive_tokens (slice in_msg_body, slice sender_address, int my_ton_balance, int fwd_fee, int msg_value) impure { +() receive_tokens (slice in_msg_body, slice sender_address, int my_ton_balance, int fwd_fee, int msg_value) { ;; NOTE we can not allow fails in action phase since in that case there will be ;; no bounce. Thus check and throw in computation phase. (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data(); @@ -162,7 +162,7 @@ const gas_consumption = 10000000; ;; 0.01 TON save_data(balance, owner_address, jetton_master_address, jetton_wallet_code); } -() burn_tokens (slice in_msg_body, slice sender_address, int msg_value, int fwd_fee) impure { +() burn_tokens (slice in_msg_body, slice sender_address, int msg_value, int fwd_fee) { ;; NOTE we can not allow fails in action phase since in that case there will be ;; no bounce. Thus check and throw in computation phase. (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data(); @@ -196,7 +196,7 @@ const gas_consumption = 10000000; ;; 0.01 TON save_data(balance, owner_address, jetton_master_address, jetton_wallet_code); } -() on_bounce (slice in_msg_body) impure { +() on_bounce (slice in_msg_body) { in_msg_body~skip_bits(32); ;; 0xFFFFFFFF (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data(); int op = in_msg_body~load_uint(32); @@ -207,7 +207,7 @@ const gas_consumption = 10000000; ;; 0.01 TON save_data(balance, owner_address, jetton_master_address, jetton_wallet_code); } -() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure { +() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) { if (in_msg_body.slice_empty?()) { ;; ignore empty messages return (); } diff --git a/crypto/func/auto-tests/legacy_tests/nft-collection/nft-collection-editable.fc b/crypto/func/auto-tests/legacy_tests/nft-collection/nft-collection-editable.fc index 73d86b169..8417f8df6 100644 --- a/crypto/func/auto-tests/legacy_tests/nft-collection/nft-collection-editable.fc +++ b/crypto/func/auto-tests/legacy_tests/nft-collection/nft-collection-editable.fc @@ -23,7 +23,7 @@ ); } -() save_data(slice owner_address, int next_item_index, cell content, cell nft_item_code, cell royalty_params) impure inline { +() save_data(slice owner_address, int next_item_index, cell content, cell nft_item_code, cell royalty_params) inline { set_data(begin_cell() .store_slice(owner_address) .store_uint(next_item_index, 64) @@ -46,7 +46,7 @@ slice calculate_nft_item_address(int wc, cell state_init) { .begin_parse(); } -() deploy_nft_item(int item_index, cell nft_item_code, int amount, cell nft_content) impure { +() deploy_nft_item(int item_index, cell nft_item_code, int amount, cell nft_content) { cell state_init = calculate_nft_item_state_init(item_index, nft_item_code); slice nft_address = calculate_nft_item_address(workchain(), state_init); var msg = begin_cell() @@ -59,7 +59,7 @@ slice calculate_nft_item_address(int wc, cell state_init) { send_raw_message(msg.end_cell(), 1); ;; pay transfer fees separately, revert on errors } -() send_royalty_params(slice to_address, int query_id, slice data) impure inline { +() send_royalty_params(slice to_address, int query_id, slice data) inline { var msg = begin_cell() .store_uint(0x10, 6) ;; nobounce - int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool packages:MsgAddress -> 011000 .store_slice(to_address) @@ -71,7 +71,7 @@ slice calculate_nft_item_address(int wc, cell state_init) { send_raw_message(msg.end_cell(), 64); ;; carry all the remaining value of the inbound message } -() recv_internal(cell in_msg_full, slice in_msg_body) impure { +() recv_internal(cell in_msg_full, slice in_msg_body) { if (in_msg_body.slice_empty?()) { ;; ignore empty messages return (); } diff --git a/crypto/func/auto-tests/legacy_tests/nft-collection/params.fc b/crypto/func/auto-tests/legacy_tests/nft-collection/params.fc index 27a42748a..acec264e2 100644 --- a/crypto/func/auto-tests/legacy_tests/nft-collection/params.fc +++ b/crypto/func/auto-tests/legacy_tests/nft-collection/params.fc @@ -1,10 +1,10 @@ int workchain() asm "0 PUSHINT"; -() force_chain(slice addr) impure { +() force_chain(slice addr) { (int wc, _) = parse_std_addr(addr); throw_unless(333, wc == workchain()); } slice null_addr() asm "b{00} PUSHSLICE"; int flag::regular() asm "0x10 PUSHINT"; -int flag::bounce() asm "0x8 PUSHINT"; \ No newline at end of file +int flag::bounce() asm "0x8 PUSHINT"; diff --git a/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc b/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc index 6ae2a28d2..f4b671bd9 100644 --- a/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc @@ -1,215 +1,215 @@ ;; Standard library for funC ;; -forall X -> tuple cons(X head, tuple tail) asm "CONS"; -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -forall X -> X car(tuple list) asm "CAR"; -tuple cdr(tuple list) asm "CDR"; -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> [X] single(X x) asm "SINGLE"; -forall X -> X unsingle([X] t) asm "UNSINGLE"; -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -forall X -> X first(tuple t) asm "FIRST"; -forall X -> X second(tuple t) asm "SECOND"; -forall X -> X third(tuple t) asm "THIRD"; -forall X -> X fourth(tuple t) asm "3 INDEX"; -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -forall X -> X null() asm "PUSHNULL"; -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; - -int now() asm "NOW"; -slice my_address() asm "MYADDR"; -[int, cell] get_balance() asm "BALANCE"; -int cur_lt() asm "LTIME"; -int block_lt() asm "BLOCKLT"; - -int cell_hash(cell c) asm "HASHCU"; -int slice_hash(slice s) asm "HASHSU"; -int string_hash(slice s) asm "SHA256U"; - -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; - -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; - -() dump_stack() impure asm "DUMPSTK"; - -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -cont get_c3() asm "c3 PUSH"; -() set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) asm "BLESS"; - -() accept_message() impure asm "ACCEPT"; -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; -() commit() impure asm "COMMIT"; -() buy_gas(int gram) impure asm "BUYGAS"; - -int min(int x, int y) asm "MIN"; -int max(int x, int y) asm "MAX"; -(int, int) minmax(int x, int y) asm "MINMAX"; -int abs(int x) asm "ABS"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -cell preload_ref(slice s) asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -slice first_bits(slice s, int len) asm "SDCUTFIRST"; -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -slice slice_last(slice s, int len) asm "SDCUTLAST"; -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -cell preload_dict(slice s) asm "PLDDICT"; -slice skip_dict(slice s) asm "SKIPDICT"; - -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; - -int cell_depth(cell c) asm "CDEPTH"; - -int slice_refs(slice s) asm "SREFS"; -int slice_bits(slice s) asm "SBITS"; -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; -int slice_empty?(slice s) asm "SEMPTY"; -int slice_data_empty?(slice s) asm "SDEMPTY"; -int slice_refs_empty?(slice s) asm "SREMPTY"; -int slice_depth(slice s) asm "SDEPTH"; - -int builder_refs(builder b) asm "BREFS"; -int builder_bits(builder b) asm "BBITS"; -int builder_depth(builder b) asm "BDEPTH"; - -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; - builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -builder store_slice(builder b, slice s) asm "STSLICER"; -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_dict(builder b, cell c) asm(c b) "STDICT"; - -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -tuple parse_addr(slice s) asm "PARSEMSGADDR"; -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; - -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -cell new_dict() asm "NEWDICT"; -int dict_empty?(cell c) asm "DICTEMPTY"; - -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; - -cell config_param(int x) asm "CONFIGOPTPARAM"; -int cell_null?(cell c) asm "ISNULL"; - -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -() set_code(cell new_code) impure asm "SETCODE"; - -int random() impure asm "RANDU256"; -int rand(int range) impure asm "RAND"; -int get_seed() asm "RANDSEED"; -int set_seed() impure asm "SETRAND"; -() randomize(int x) impure asm "ADDRAND"; -() randomize_lt() impure asm "LTIME" "ADDRAND"; - -builder store_coins(builder b, int x) asm "STVARUINT16"; -(slice, int) load_coins(slice s) asm( -> 1 0) "LDVARUINT16"; - -int equal_slices (slice a, slice b) asm "SDEQ"; -int builder_null?(builder b) asm "ISNULL"; -builder store_builder(builder to, builder from) asm "STBR"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; +forall X -> X car(tuple list) pure asm "CAR"; +tuple cdr(tuple list) pure asm "CDR"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> [X] single(X x) pure asm "SINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; +forall X -> X first(tuple t) pure asm "FIRST"; +forall X -> X second(tuple t) pure asm "SECOND"; +forall X -> X third(tuple t) pure asm "THIRD"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; +forall X -> X null() pure asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; + +int now() pure asm "NOW"; +slice my_address() pure asm "MYADDR"; +[int, cell] get_balance() pure asm "BALANCE"; +int cur_lt() pure asm "LTIME"; +int block_lt() pure asm "BLOCKLT"; + +int cell_hash(cell c) pure asm "HASHCU"; +int slice_hash(slice s) pure asm "HASHSU"; +int string_hash(slice s) pure asm "SHA256U"; + +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; + +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; + +;; () throw_if(int excno, int cond) asm "THROWARGIF"; + +() dump_stack() asm "DUMPSTK"; + +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +cont get_c3() pure asm "c3 PUSH"; +() set_c3(cont c) asm "c3 POP"; +cont bless(slice s) pure asm "BLESS"; + +() accept_message() asm "ACCEPT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; +() commit() asm "COMMIT"; +() buy_gas(int gram) asm "BUYGAS"; + +int min(int x, int y) pure asm "MIN"; +int max(int x, int y) pure asm "MAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; +int abs(int x) pure asm "ABS"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; +;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; +;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; + +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; + +int cell_depth(cell c) pure asm "CDEPTH"; + +int slice_refs(slice s) pure asm "SREFS"; +int slice_bits(slice s) pure asm "SBITS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; +int slice_empty?(slice s) pure asm "SEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; +int slice_depth(slice s) pure asm "SDEPTH"; + +int builder_refs(builder b) pure asm "BREFS"; +int builder_bits(builder b) pure asm "BBITS"; +int builder_depth(builder b) pure asm "BDEPTH"; + +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; + builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; + +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; + +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; + +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; + +cell config_param(int x) pure asm "CONFIGOPTPARAM"; +int cell_null?(cell c) pure asm "ISNULL"; + +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; +() set_code(cell new_code) asm "SETCODE"; + +int random() asm "RANDU256"; +int rand(int range) asm "RAND"; +int get_seed() pure asm "RANDSEED"; +int set_seed() asm "SETRAND"; +() randomize(int x) asm "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; + +builder store_coins(builder b, int x) pure asm "STVARUINT16"; +(slice, int) load_coins(slice s) pure asm( -> 1 0) "LDVARUINT16"; + +int equal_slices (slice a, slice b) pure asm "SDEQ"; +int builder_null?(builder b) pure asm "ISNULL"; +builder store_builder(builder to, builder from) pure asm "STBR"; diff --git a/crypto/func/auto-tests/legacy_tests/nominator-pool/stdlib.fc b/crypto/func/auto-tests/legacy_tests/nominator-pool/stdlib.fc index cddb5ae04..7f45a6dd7 100644 --- a/crypto/func/auto-tests/legacy_tests/nominator-pool/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/nominator-pool/stdlib.fc @@ -1,211 +1,211 @@ ;; Standard library for funC ;; -forall X -> tuple cons(X head, tuple tail) asm "CONS"; -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -forall X -> X car(tuple list) asm "CAR"; -tuple cdr(tuple list) asm "CDR"; -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> [X] single(X x) asm "SINGLE"; -forall X -> X unsingle([X] t) asm "UNSINGLE"; -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -forall X -> X first(tuple t) asm "FIRST"; -forall X -> X second(tuple t) asm "SECOND"; -forall X -> X third(tuple t) asm "THIRD"; -forall X -> X fourth(tuple t) asm "3 INDEX"; -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -forall X -> X null() asm "PUSHNULL"; -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; - -int now() asm "NOW"; -slice my_address() asm "MYADDR"; -[int, cell] get_balance() asm "BALANCE"; -int cur_lt() asm "LTIME"; -int block_lt() asm "BLOCKLT"; - -int cell_hash(cell c) asm "HASHCU"; -int slice_hash(slice s) asm "HASHSU"; -int string_hash(slice s) asm "SHA256U"; - -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; - -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; - -() dump_stack() impure asm "DUMPSTK"; - -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -cont get_c3() asm "c3 PUSH"; -() set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) asm "BLESS"; - -() accept_message() impure asm "ACCEPT"; -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; -() commit() impure asm "COMMIT"; -() buy_gas(int gram) impure asm "BUYGAS"; - -int min(int x, int y) asm "MIN"; -int max(int x, int y) asm "MAX"; -(int, int) minmax(int x, int y) asm "MINMAX"; -int abs(int x) asm "ABS"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -cell preload_ref(slice s) asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -slice first_bits(slice s, int len) asm "SDCUTFIRST"; -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -slice slice_last(slice s, int len) asm "SDCUTLAST"; -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -cell preload_dict(slice s) asm "PLDDICT"; -slice skip_dict(slice s) asm "SKIPDICT"; - -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; - -int cell_depth(cell c) asm "CDEPTH"; - -int slice_refs(slice s) asm "SREFS"; -int slice_bits(slice s) asm "SBITS"; -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; -int slice_empty?(slice s) asm "SEMPTY"; -int slice_data_empty?(slice s) asm "SDEMPTY"; -int slice_refs_empty?(slice s) asm "SREMPTY"; -int slice_depth(slice s) asm "SDEPTH"; - -int builder_refs(builder b) asm "BREFS"; -int builder_bits(builder b) asm "BBITS"; -int builder_depth(builder b) asm "BDEPTH"; - -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -builder store_slice(builder b, slice s) asm "STSLICER"; -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_dict(builder b, cell c) asm(c b) "STDICT"; - -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -tuple parse_addr(slice s) asm "PARSEMSGADDR"; -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; - -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -cell new_dict() asm "NEWDICT"; -int dict_empty?(cell c) asm "DICTEMPTY"; - -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; - -cell config_param(int x) asm "CONFIGOPTPARAM"; -int cell_null?(cell c) asm "ISNULL"; - -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -() set_code(cell new_code) impure asm "SETCODE"; - -int random() impure asm "RANDU256"; -int rand(int range) impure asm "RAND"; -int get_seed() asm "RANDSEED"; -int set_seed() impure asm "SETRAND"; -() randomize(int x) impure asm "ADDRAND"; -() randomize_lt() impure asm "LTIME" "ADDRAND"; - -builder store_coins(builder b, int x) asm "STVARUINT16"; -(slice, int) load_coins(slice s) asm( -> 1 0) "LDVARUINT16"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; +forall X -> X car(tuple list) pure asm "CAR"; +tuple cdr(tuple list) pure asm "CDR"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> [X] single(X x) pure asm "SINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; +forall X -> X first(tuple t) pure asm "FIRST"; +forall X -> X second(tuple t) pure asm "SECOND"; +forall X -> X third(tuple t) pure asm "THIRD"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; +forall X -> X null() pure asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; + +int now() pure asm "NOW"; +slice my_address() pure asm "MYADDR"; +[int, cell] get_balance() pure asm "BALANCE"; +int cur_lt() pure asm "LTIME"; +int block_lt() pure asm "BLOCKLT"; + +int cell_hash(cell c) pure asm "HASHCU"; +int slice_hash(slice s) pure asm "HASHSU"; +int string_hash(slice s) pure asm "SHA256U"; + +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; + +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; + +;; () throw_if(int excno, int cond) asm "THROWARGIF"; + +() dump_stack() asm "DUMPSTK"; + +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +cont get_c3() pure asm "c3 PUSH"; +() set_c3(cont c) asm "c3 POP"; +cont bless(slice s) pure asm "BLESS"; + +() accept_message() asm "ACCEPT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; +() commit() asm "COMMIT"; +() buy_gas(int gram) asm "BUYGAS"; + +int min(int x, int y) pure asm "MIN"; +int max(int x, int y) pure asm "MAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; +int abs(int x) pure asm "ABS"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; +;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; +;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; + +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; + +int cell_depth(cell c) pure asm "CDEPTH"; + +int slice_refs(slice s) pure asm "SREFS"; +int slice_bits(slice s) pure asm "SBITS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; +int slice_empty?(slice s) pure asm "SEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; +int slice_depth(slice s) pure asm "SDEPTH"; + +int builder_refs(builder b) pure asm "BREFS"; +int builder_bits(builder b) pure asm "BBITS"; +int builder_depth(builder b) pure asm "BDEPTH"; + +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; + +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; + +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; + +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; + +cell config_param(int x) pure asm "CONFIGOPTPARAM"; +int cell_null?(cell c) pure asm "ISNULL"; + +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; +() set_code(cell new_code) asm "SETCODE"; + +int random() asm "RANDU256"; +int rand(int range) asm "RAND"; +int get_seed() pure asm "RANDSEED"; +int set_seed() asm "SETRAND"; +() randomize(int x) asm "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; + +builder store_coins(builder b, int x) pure asm "STVARUINT16"; +(slice, int) load_coins(slice s) pure asm( -> 1 0) "LDVARUINT16"; diff --git a/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc b/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc index 70b5d61d4..8f966b378 100644 --- a/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc @@ -20,122 +20,122 @@ */ /// Adds an element to the beginning of lisp-style list. -forall X -> tuple cons(X head, tuple tail) asm "CONS"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; /// Extracts the head and the tail of lisp-style list. -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; /// Extracts the tail and the head of lisp-style list. -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; /// Returns the head of lisp-style list. -forall X -> X car(tuple list) asm "CAR"; +forall X -> X car(tuple list) pure asm "CAR"; /// Returns the tail of lisp-style list. -tuple cdr(tuple list) asm "CDR"; +tuple cdr(tuple list) pure asm "CDR"; /// Creates tuple with zero elements. -tuple empty_tuple() asm "NIL"; +tuple empty_tuple() pure asm "NIL"; /// Appends a value `x` to a `Tuple t = (x1, ..., xn)`, but only if the resulting `Tuple t' = (x1, ..., xn, x)` /// is of length at most 255. Otherwise throws a type check exception. -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; /// Creates a tuple of length one with given argument as element. -forall X -> [X] single(X x) asm "SINGLE"; +forall X -> [X] single(X x) pure asm "SINGLE"; /// Unpacks a tuple of length one -forall X -> X unsingle([X] t) asm "UNSINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; /// Creates a tuple of length two with given arguments as elements. -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; /// Unpacks a tuple of length two -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; /// Creates a tuple of length three with given arguments as elements. -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; /// Unpacks a tuple of length three -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; /// Creates a tuple of length four with given arguments as elements. -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; /// Unpacks a tuple of length four -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; /// Returns the first element of a tuple (with unknown element types). -forall X -> X first(tuple t) asm "FIRST"; +forall X -> X first(tuple t) pure asm "FIRST"; /// Returns the second element of a tuple (with unknown element types). -forall X -> X second(tuple t) asm "SECOND"; +forall X -> X second(tuple t) pure asm "SECOND"; /// Returns the third element of a tuple (with unknown element types). -forall X -> X third(tuple t) asm "THIRD"; +forall X -> X third(tuple t) pure asm "THIRD"; /// Returns the fourth element of a tuple (with unknown element types). -forall X -> X fourth(tuple t) asm "3 INDEX"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; /// Returns the first element of a pair tuple. -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; /// Returns the second element of a pair tuple. -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; /// Returns the first element of a triple tuple. -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; /// Returns the second element of a triple tuple. -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; /// Returns the third element of a triple tuple. -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; /// Push null element (casted to given type) /// By the TVM type `Null` FunC represents absence of a value of some atomic type. /// So `null` can actually have any atomic type. -forall X -> X null() asm "PUSHNULL"; +forall X -> X null() pure asm "PUSHNULL"; /// Moves a variable [x] to the top of the stack -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; /// Returns the current Unix time as an Integer -int now() asm "NOW"; +int now() pure asm "NOW"; /// Returns the internal address of the current smart contract as a Slice with a `MsgAddressInt`. /// If necessary, it can be parsed further using primitives such as [parse_std_addr]. -slice my_address() asm "MYADDR"; +slice my_address() pure asm "MYADDR"; /// Returns the balance of the smart contract as a tuple consisting of an int /// (balance in nanotoncoins) and a `cell` /// (a dictionary with 32-bit keys representing the balance of "extra currencies") /// at the start of Computation Phase. /// Note that RAW primitives such as [send_raw_message] do not update this field. -[int, cell] get_balance() asm "BALANCE"; +[int, cell] get_balance() pure asm "BALANCE"; /// Returns the logical time of the current transaction. -int cur_lt() asm "LTIME"; +int cur_lt() pure asm "LTIME"; /// Returns the starting logical time of the current block. -int block_lt() asm "BLOCKLT"; +int block_lt() pure asm "BLOCKLT"; /// Computes the representation hash of a `cell` [c] and returns it as a 256-bit unsigned integer `x`. /// Useful for signing and checking signatures of arbitrary entities represented by a tree of cells. -int cell_hash(cell c) asm "HASHCU"; +int cell_hash(cell c) pure asm "HASHCU"; /// Computes the hash of a `slice s` and returns it as a 256-bit unsigned integer `x`. /// The result is the same as if an ordinary cell containing only data and references from `s` had been created /// and its hash computed by [cell_hash]. -int slice_hash(slice s) asm "HASHSU"; +int slice_hash(slice s) pure asm "HASHSU"; /// Computes sha256 of the data bits of `slice` [s]. If the bit length of `s` is not divisible by eight, /// throws a cell underflow exception. The hash value is returned as a 256-bit unsigned integer `x`. -int string_hash(slice s) asm "SHA256U"; +int string_hash(slice s) pure asm "SHA256U"; /* # Signature checks @@ -148,14 +148,14 @@ int string_hash(slice s) asm "SHA256U"; /// Note that `CHKSIGNU` creates a 256-bit slice with the hash and calls `CHKSIGNS`. /// That is, if [hash] is computed as the hash of some data, these data are hashed twice, /// the second hashing occurring inside `CHKSIGNS`. -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; /// Checks whether [signature] is a valid Ed25519-signature of the data portion of `slice data` using `public_key`, /// similarly to [check_signature]. /// If the bit length of [data] is not divisible by eight, throws a cell underflow exception. /// The verification of Ed25519 signatures is the standard one, /// with sha256 used to reduce [data] to the 256-bit number that is actually signed. -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; /*-- # Computation of boc size @@ -171,54 +171,54 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI /// The total count of visited cells `x` cannot exceed non-negative [max_cells]; /// otherwise the computation is aborted before visiting the `(max_cells + 1)`-st cell and /// a zero flag is returned to indicate failure. If [c] is `null`, returns `x = y = z = 0`. -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; /// Similar to [compute_data_size?], but accepting a `slice` [s] instead of a `cell`. /// The returned value of `x` does not take into account the cell that contains the `slice` [s] itself; /// however, the data bits and the cell references of [s] are accounted for in `y` and `z`. -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; /// A non-quiet version of [compute_data_size?] that throws a cell overflow exception (`8`) on failure. -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; /// A non-quiet version of [slice_compute_data_size?] that throws a cell overflow exception (8) on failure. -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; /// Throws an exception with exit_code excno if cond is not 0 (commented since implemented in compilator) -// () throw_if(int excno, int cond) impure asm "THROWARGIF"; +// () throw_if(int excno, int cond) asm "THROWARGIF"; /*- # Debug primitives Only works for local TVM execution with debug level verbosity */ /// Dumps the stack (at most the top 255 values) and shows the total stack depth. -() dump_stack() impure asm "DUMPSTK"; +() dump_stack() asm "DUMPSTK"; /* # Persistent storage save and load */ /// Returns the persistent contract storage cell. It can be parsed or modified with slice and builder primitives later. -cell get_data() asm "c4 PUSH"; +cell get_data() pure asm "c4 PUSH"; /// Sets `cell` [c] as persistent contract data. You can update persistent contract storage with this primitive. -() set_data(cell c) impure asm "c4 POP"; +() set_data(cell c) asm "c4 POP"; /* # Continuation primitives */ /// Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls. /// The primitive returns the current value of `c3`. -cont get_c3() asm "c3 PUSH"; +cont get_c3() pure asm "c3 PUSH"; /// Updates the current value of `c3`. Usually, it is used for updating smart contract code in run-time. /// Note that after execution of this primitive the current code /// (and the stack of recursive function calls) won't change, /// but any other function call will use a function from the new code. -() set_c3(cont c) impure asm "c3 POP"; +() set_c3(cont c) asm "c3 POP"; /// Transforms a `slice` [s] into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist. -cont bless(slice s) asm "BLESS"; +cont bless(slice s) pure asm "BLESS"; /*-- # Gas related primitives @@ -230,37 +230,37 @@ cont bless(slice s) asm "BLESS"; /// This action is required to process external messages, which bring no value (hence no gas) with themselves. /// /// For more details check [accept_message effects](https://ton.org/docs/#/smart-contracts/accept). -() accept_message() impure asm "ACCEPT"; +() accept_message() asm "ACCEPT"; /// Sets current gas limit `gl` to the minimum of limit and `gm`, and resets the gas credit `gc` to zero. /// If the gas consumed so far (including the present instruction) exceeds the resulting value of `gl`, /// an (unhandled) out of gas exception is thrown before setting new gas limits. /// Notice that [set_gas_limit] with an argument `limit ≥ 2^63 − 1` is equivalent to [accept_message]. -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; /// Commits the current state of registers `c4` (“persistent data”) and `c5` (“actions”) /// so that the current execution is considered “successful” with the saved values even if an exception /// in Computation Phase is thrown later. -() commit() impure asm "COMMIT"; +() commit() asm "COMMIT"; /// Not implemented -//() buy_gas(int gram) impure asm "BUYGAS"; +//() buy_gas(int gram) asm "BUYGAS"; /// Computes the amount of gas that can be bought for `amount` nanoTONs, /// and sets `gl` accordingly in the same way as [set_gas_limit]. -() buy_gas(int amount) impure asm "BUYGAS"; +() buy_gas(int amount) asm "BUYGAS"; /// Computes the minimum of two integers [x] and [y]. -int min(int x, int y) asm "MIN"; +int min(int x, int y) pure asm "MIN"; /// Computes the maximum of two integers [x] and [y]. -int max(int x, int y) asm "MAX"; +int max(int x, int y) pure asm "MAX"; /// Sorts two integers. -(int, int) minmax(int x, int y) asm "MINMAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; /// Computes the absolute value of an integer [x]. -int abs(int x) asm "ABS"; +int abs(int x) pure asm "ABS"; /* # Slice primitives @@ -279,80 +279,80 @@ int abs(int x) asm "ABS"; /// Converts a `cell` [c] into a `slice`. Notice that [c] must be either an ordinary cell, /// or an exotic cell (see [TVM.pdf](https://ton-blockchain.github.io/docs/tvm.pdf), 3.1.2) /// which is automatically loaded to yield an ordinary cell `c'`, converted into a `slice` afterwards. -slice begin_parse(cell c) asm "CTOS"; +slice begin_parse(cell c) pure asm "CTOS"; /// Checks if [s] is empty. If not, throws an exception. -() end_parse(slice s) impure asm "ENDS"; +() end_parse(slice s) asm "ENDS"; /// Loads the first reference from the slice. -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; /// Preloads the first reference from the slice. -cell preload_ref(slice s) asm "PLDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; /* Functions below are commented because are implemented on compilator level for optimisation */ /// Loads a signed [len]-bit integer from a slice [s]. -// (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; +// (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; /// Loads an unsigned [len]-bit integer from a slice [s]. -// (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; +// (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; /// Preloads a signed [len]-bit integer from a slice [s]. -// int preload_int(slice s, int len) asm "PLDIX"; +// int preload_int(slice s, int len) pure asm "PLDIX"; /// Preloads an unsigned [len]-bit integer from a slice [s]. -// int preload_uint(slice s, int len) asm "PLDUX"; +// int preload_uint(slice s, int len) pure asm "PLDUX"; /// Loads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. -// (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; +// (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; /// Preloads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. -// slice preload_bits(slice s, int len) asm "PLDSLICEX"; +// slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; /// Loads serialized amount of TonCoins (any unsigned integer up to `2^128 - 1`). -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -(slice, int) load_coins(slice s) asm( -> 1 0) "LDGRAMS"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +(slice, int) load_coins(slice s) pure asm( -> 1 0) "LDGRAMS"; /// Returns all but the first `0 ≤ len ≤ 1023` bits of `slice` [s]. -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; /// Returns the first `0 ≤ len ≤ 1023` bits of `slice` [s]. -slice first_bits(slice s, int len) asm "SDCUTFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; /// Returns all but the last `0 ≤ len ≤ 1023` bits of `slice` [s]. -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; /// Returns the last `0 ≤ len ≤ 1023` bits of `slice` [s]. -slice slice_last(slice s, int len) asm "SDCUTLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; /// Loads a dictionary `D` (HashMapE) from `slice` [s]. /// (returns `null` if `nothing` constructor is used). -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; /// Preloads a dictionary `D` from `slice` [s]. -cell preload_dict(slice s) asm "PLDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; /// Loads a dictionary as [load_dict], but returns only the remainder of the slice. -slice skip_dict(slice s) asm "SKIPDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; /// Loads (Maybe ^Cell) from `slice` [s]. /// In other words loads 1 bit and if it is true /// loads first ref and return it with slice remainder /// otherwise returns `null` and slice remainder -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; /// Preloads (Maybe ^Cell) from `slice` [s]. -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; /// Returns the depth of `cell` [c]. /// If [c] has no references, then return `0`; /// otherwise the returned value is one plus the maximum of depths of cells referred to from [c]. /// If [c] is a `null` instead of a cell, returns zero. -int cell_depth(cell c) asm "CDEPTH"; +int cell_depth(cell c) pure asm "CDEPTH"; /* @@ -360,42 +360,42 @@ int cell_depth(cell c) asm "CDEPTH"; */ /// Returns the number of references in `slice` [s]. -int slice_refs(slice s) asm "SREFS"; +int slice_refs(slice s) pure asm "SREFS"; /// Returns the number of data bits in `slice` [s]. -int slice_bits(slice s) asm "SBITS"; +int slice_bits(slice s) pure asm "SBITS"; /// Returns both the number of data bits and the number of references in `slice` [s]. -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; /// Checks whether a `slice` [s] is empty (i.e., contains no bits of data and no cell references). -int slice_empty?(slice s) asm "SEMPTY"; +int slice_empty?(slice s) pure asm "SEMPTY"; /// Checks whether `slice` [s] has no bits of data. -int slice_data_empty?(slice s) asm "SDEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; /// Checks whether `slice` [s] has no references. -int slice_refs_empty?(slice s) asm "SREMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; /// Returns the depth of `slice` [s]. /// If [s] has no references, then returns `0`; /// otherwise the returned value is one plus the maximum of depths of cells referred to from [s]. -int slice_depth(slice s) asm "SDEPTH"; +int slice_depth(slice s) pure asm "SDEPTH"; /* # Builder size primitives */ /// Returns the number of cell references already stored in `builder` [b] -int builder_refs(builder b) asm "BREFS"; +int builder_refs(builder b) pure asm "BREFS"; /// Returns the number of data bits already stored in `builder` [b]. -int builder_bits(builder b) asm "BBITS"; +int builder_bits(builder b) pure asm "BBITS"; /// Returns the depth of `builder` [b]. /// If no cell references are stored in [b], then returns 0; /// otherwise the returned value is one plus the maximum of depths of cells referred to from [b]. -int builder_depth(builder b) asm "BDEPTH"; +int builder_depth(builder b) pure asm "BDEPTH"; /* # Builder primitives @@ -408,23 +408,23 @@ int builder_depth(builder b) asm "BDEPTH"; */ /// Creates a new empty `builder`. -builder begin_cell() asm "NEWC"; +builder begin_cell() pure asm "NEWC"; /// Converts a `builder` into an ordinary `cell`. -cell end_cell(builder b) asm "ENDC"; +cell end_cell(builder b) pure asm "ENDC"; /// Stores a reference to `cell` [c] into `builder` [b]. -builder store_ref(builder b, cell c) asm(c b) "STREF"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; /// Stores an unsigned [len]-bit integer `x` into `b` for `0 ≤ len ≤ 256`. -// builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; +// builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; /// Stores a signed [len]-bit integer `x` into `b` for` 0 ≤ len ≤ 257`. -// builder store_int(builder b, int x, int len) asm(x b len) "STIX"; +// builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; /// Stores `slice` [s] into `builder` [b] -builder store_slice(builder b, slice s) asm "STSLICER"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; /// Stores (serializes) an integer [x] in the range `0..2^128 − 1` into `builder` [b]. /// The serialization of [x] consists of a 4-bit unsigned big-endian integer `l`, @@ -433,17 +433,17 @@ builder store_slice(builder b, slice s) asm "STSLICER"; /// If [x] does not belong to the supported range, a range check exception is thrown. /// /// Store amounts of TonCoins to the builder as VarUInteger 16 -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_coins(builder b, int x) asm "STGRAMS"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_coins(builder b, int x) pure asm "STGRAMS"; /// Stores dictionary `D` represented by `cell` [c] or `null` into `builder` [b]. /// In other words, stores a `1`-bit and a reference to [c] if [c] is not `null` and `0`-bit otherwise. -builder store_dict(builder b, cell c) asm(c b) "STDICT"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; /// Stores (Maybe ^Cell) to builder: /// if cell is null store 1 zero bit /// otherwise store 1 true bit and ref to cell -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; /* @@ -485,22 +485,22 @@ builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; /// Loads from slice [s] the only prefix that is a valid `MsgAddress`, /// and returns both this prefix `s'` and the remainder `s''` of [s] as slices. -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; /// Decomposes slice [s] containing a valid `MsgAddress` into a `tuple t` with separate fields of this `MsgAddress`. /// If [s] is not a valid `MsgAddress`, a cell deserialization exception is thrown. -tuple parse_addr(slice s) asm "PARSEMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; /// Parses slice [s] containing a valid `MsgAddressInt` (usually a `msg_addr_std`), /// applies rewriting from the anycast (if present) to the same-length prefix of the address, /// and returns both the workchain and the 256-bit address as integers. /// If the address is not 256-bit, or if [s] is not a valid serialization of `MsgAddressInt`, /// throws a cell deserialization exception. -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; /// A variant of [parse_std_addr] that returns the (rewritten) address as a slice [s], /// even if it is not exactly 256 bit long (represented by a `msg_addr_var`). -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; /* # Dictionary primitives @@ -509,117 +509,117 @@ tuple parse_addr(slice s) asm "PARSEMSGADDR"; /// Sets the value associated with [key_len]-bit key signed index in dictionary [dict] to [value] (cell), /// and returns the resulting dictionary. -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; /// Sets the value associated with [key_len]-bit key unsigned index in dictionary [dict] to [value] (cell), /// and returns the resulting dictionary. -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; - -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF" "NULLSWAPIFNOT"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF" "NULLSWAPIFNOT"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; + +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF" "NULLSWAPIFNOT"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF" "NULLSWAPIFNOT"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; /// Creates an empty dictionary, which is actually a null value. Equivalent to PUSHNULL -cell new_dict() asm "NEWDICT"; +cell new_dict() pure asm "NEWDICT"; /// Checks whether a dictionary is empty. Equivalent to cell_null?. -int dict_empty?(cell c) asm "DICTEMPTY"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; /* Prefix dictionary primitives */ -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; /// Returns the value of the global configuration parameter with integer index `i` as a `cell` or `null` value. -cell config_param(int x) asm "CONFIGOPTPARAM"; +cell config_param(int x) pure asm "CONFIGOPTPARAM"; /// Checks whether c is a null. Note, that FunC also has polymorphic null? built-in. -int cell_null?(cell c) asm "ISNULL"; +int cell_null?(cell c) pure asm "ISNULL"; /// Creates an output action which would reserve exactly amount nanotoncoins (if mode = 0), at most amount nanotoncoins (if mode = 2), or all but amount nanotoncoins (if mode = 1 or mode = 3), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carrying amount nanotoncoins (or b − amount nanotoncoins, where b is the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit +2 in mode means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit +8 in mode means `amount <- -amount` before performing any further actions. Bit +4 in mode means that amount is increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currently, amount must be a non-negative integer, and mode must be in the range 0..15. -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; /// Similar to raw_reserve, but also accepts a dictionary extra_amount (represented by a cell or null) with extra currencies. In this way currencies other than TonCoin can be reserved. -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; /// Sends a raw message contained in msg, which should contain a correctly serialized object Message X, with the only exception that the source address is allowed to have dummy value addr_none (to be automatically replaced with the current smart contract address), and ihr_fee, fwd_fee, created_lt and created_at fields can have arbitrary values (to be rewritten with correct values during the action phase of the current transaction). Integer parameter mode contains the flags. Currently mode = 0 is used for ordinary messages; mode = 128 is used for messages that are to carry all the remaining balance of the current smart contract (instead of the value originally indicated in the message); mode = 64 is used for messages that carry all the remaining value of the inbound message in addition to the value initially indicated in the new message (if bit 0 is not set, the gas fees are deducted from this amount); mode' = mode + 1 means that the sender wants to pay transfer fees separately; mode' = mode + 2 means that any errors arising while processing this message during the action phase should be ignored. Finally, mode' = mode + 32 means that the current account must be destroyed if its resulting balance is zero. This flag is usually employed together with +128. -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; /// Creates an output action that would change this smart contract code to that given by cell new_code. Notice that this change will take effect only after the successful termination of the current run of the smart contract -() set_code(cell new_code) impure asm "SETCODE"; +() set_code(cell new_code) asm "SETCODE"; /// Generates a new pseudo-random unsigned 256-bit integer x. The algorithm is as follows: if r is the old value of the random seed, considered as a 32-byte array (by constructing the big-endian representation of an unsigned 256-bit integer), then its sha512(r) is computed; the first 32 bytes of this hash are stored as the new value r' of the random seed, and the remaining 32 bytes are returned as the next random value x. -int random() impure asm "RANDU256"; +int random() asm "RANDU256"; /// Generates a new pseudo-random integer z in the range 0..range−1 (or range..−1, if range < 0). More precisely, an unsigned random value x is generated as in random; then z := x * range / 2^256 is computed. -int rand(int range) impure asm "RAND"; +int rand(int range) asm "RAND"; /// Returns the current random seed as an unsigned 256-bit Integer. -int get_seed() asm "RANDSEED"; +int get_seed() pure asm "RANDSEED"; /// Sets the random seed to unsigned 256-bit seed. -() set_seed(int) impure asm "SETRAND"; +() set_seed(int) asm "SETRAND"; /// Mixes unsigned 256-bit integer x into the random seed r by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed r, and the second with the big-endian representation of x. -() randomize(int x) impure asm "ADDRAND"; +() randomize(int x) asm "ADDRAND"; /// Equivalent to randomize(cur_lt());. -() randomize_lt() impure asm "LTIME" "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; /// Checks whether the data parts of two slices coinside -int equal_slice_bits (slice a, slice b) asm "SDEQ"; +int equal_slice_bits (slice a, slice b) pure asm "SDEQ"; /// Concatenates two builders -builder store_builder(builder to, builder from) asm "STBR"; +builder store_builder(builder to, builder from) pure asm "STBR"; diff --git a/crypto/func/auto-tests/legacy_tests/storage/storage-contract.fc b/crypto/func/auto-tests/legacy_tests/storage/storage-contract.fc index 3dfe3ff1e..05df1de10 100644 --- a/crypto/func/auto-tests/legacy_tests/storage/storage-contract.fc +++ b/crypto/func/auto-tests/legacy_tests/storage/storage-contract.fc @@ -41,7 +41,7 @@ int check_proof(int merkle_hash, int byte_to_proof, int file_size, cell file_dic return false; } -() add_to_balance(int amount) impure inline_ref { +() add_to_balance(int amount) inline_ref { var ds = get_data().begin_parse(); var (active, balance, residue) = (ds~load_int(1), ds~load_grams(), ds); balance += amount; @@ -52,12 +52,12 @@ int check_proof(int merkle_hash, int byte_to_proof, int file_size, cell file_dic .end_cell().set_data(); } -(slice, int) get_client_data(ds) { +(slice, int) get_client_data(ds) pure { ds = ds.preload_ref().begin_parse(); return (ds~load_msg_addr(), ds~load_uint(256)); } -() recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) impure { +() recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) { slice cs = in_msg_full.begin_parse(); int flags = cs~load_uint(4); diff --git a/crypto/func/auto-tests/legacy_tests/storage/storage-provider.fc b/crypto/func/auto-tests/legacy_tests/storage/storage-provider.fc index 7df5739d5..bc120f264 100644 --- a/crypto/func/auto-tests/legacy_tests/storage/storage-provider.fc +++ b/crypto/func/auto-tests/legacy_tests/storage/storage-provider.fc @@ -42,7 +42,7 @@ cell build_storage_contract_stateinit(int merkle_hash, int file_size, int rate_p } () deploy_storage_contract (slice client, int query_id, int file_size, int merkle_hash, int torrent_hash, - int expected_rate, int expected_max_span) impure { + int expected_rate, int expected_max_span) { var ds = get_data().begin_parse(); var (wallet_data, accept_new_contracts?, @@ -74,7 +74,7 @@ cell build_storage_contract_stateinit(int merkle_hash, int file_size, int rate_p send_raw_message(msg, 64); } -() recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) impure { +() recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) { slice cs = in_msg_full.begin_parse(); int flags = cs~load_uint(4); @@ -156,7 +156,7 @@ cell build_storage_contract_stateinit(int merkle_hash, int file_size, int rate_p } } -() recv_external(slice in_msg) impure { +() recv_external(slice in_msg) { var signature = in_msg~load_bits(512); var cs = in_msg; var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32)); diff --git a/crypto/func/auto-tests/legacy_tests/tact-examples/stdlib.fc b/crypto/func/auto-tests/legacy_tests/tact-examples/stdlib.fc index d5bd148e7..f78729eeb 100644 --- a/crypto/func/auto-tests/legacy_tests/tact-examples/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/tact-examples/stdlib.fc @@ -20,122 +20,122 @@ -} ;;; Adds an element to the beginning of lisp-style list. -forall X -> tuple cons(X head, tuple tail) asm "CONS"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; ;;; Extracts the head and the tail of lisp-style list. -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; ;;; Extracts the tail and the head of lisp-style list. -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; ;;; Returns the head of lisp-style list. -forall X -> X car(tuple list) asm "CAR"; +forall X -> X car(tuple list) pure asm "CAR"; ;;; Returns the tail of lisp-style list. -tuple cdr(tuple list) asm "CDR"; +tuple cdr(tuple list) pure asm "CDR"; ;;; Creates tuple with zero elements. -tuple empty_tuple() asm "NIL"; +tuple empty_tuple() pure asm "NIL"; ;;; Appends a value `x` to a `Tuple t = (x1, ..., xn)`, but only if the resulting `Tuple t' = (x1, ..., xn, x)` ;;; is of length at most 255. Otherwise throws a type check exception. -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; ;;; Creates a tuple of length one with given argument as element. -forall X -> [X] single(X x) asm "SINGLE"; +forall X -> [X] single(X x) pure asm "SINGLE"; ;;; Unpacks a tuple of length one -forall X -> X unsingle([X] t) asm "UNSINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; ;;; Creates a tuple of length two with given arguments as elements. -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; ;;; Unpacks a tuple of length two -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; ;;; Creates a tuple of length three with given arguments as elements. -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; ;;; Unpacks a tuple of length three -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; ;;; Creates a tuple of length four with given arguments as elements. -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; ;;; Unpacks a tuple of length four -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; ;;; Returns the first element of a tuple (with unknown element types). -forall X -> X first(tuple t) asm "FIRST"; +forall X -> X first(tuple t) pure asm "FIRST"; ;;; Returns the second element of a tuple (with unknown element types). -forall X -> X second(tuple t) asm "SECOND"; +forall X -> X second(tuple t) pure asm "SECOND"; ;;; Returns the third element of a tuple (with unknown element types). -forall X -> X third(tuple t) asm "THIRD"; +forall X -> X third(tuple t) pure asm "THIRD"; ;;; Returns the fourth element of a tuple (with unknown element types). -forall X -> X fourth(tuple t) asm "3 INDEX"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; ;;; Returns the first element of a pair tuple. -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; ;;; Returns the second element of a pair tuple. -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; ;;; Returns the first element of a triple tuple. -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; ;;; Returns the second element of a triple tuple. -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; ;;; Returns the third element of a triple tuple. -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; ;;; Push null element (casted to given type) ;;; By the TVM type `Null` FunC represents absence of a value of some atomic type. ;;; So `null` can actually have any atomic type. -forall X -> X null() asm "PUSHNULL"; +forall X -> X null() pure asm "PUSHNULL"; ;;; Moves a variable [x] to the top of the stack -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; ;;; Returns the current Unix time as an Integer -int now() asm "NOW"; +int now() pure asm "NOW"; ;;; Returns the internal address of the current smart contract as a Slice with a `MsgAddressInt`. ;;; If necessary, it can be parsed further using primitives such as [parse_std_addr]. -slice my_address() asm "MYADDR"; +slice my_address() pure asm "MYADDR"; ;;; Returns the balance of the smart contract as a tuple consisting of an int ;;; (balance in nanotoncoins) and a `cell` ;;; (a dictionary with 32-bit keys representing the balance of "extra currencies") ;;; at the start of Computation Phase. ;;; Note that RAW primitives such as [send_raw_message] do not update this field. -[int, cell] get_balance() asm "BALANCE"; +[int, cell] get_balance() pure asm "BALANCE"; ;;; Returns the logical time of the current transaction. -int cur_lt() asm "LTIME"; +int cur_lt() pure asm "LTIME"; ;;; Returns the starting logical time of the current block. -int block_lt() asm "BLOCKLT"; +int block_lt() pure asm "BLOCKLT"; ;;; Computes the representation hash of a `cell` [c] and returns it as a 256-bit unsigned integer `x`. ;;; Useful for signing and checking signatures of arbitrary entities represented by a tree of cells. -int cell_hash(cell c) asm "HASHCU"; +int cell_hash(cell c) pure asm "HASHCU"; ;;; Computes the hash of a `slice s` and returns it as a 256-bit unsigned integer `x`. ;;; The result is the same as if an ordinary cell containing only data and references from `s` had been created ;;; and its hash computed by [cell_hash]. -int slice_hash(slice s) asm "HASHSU"; +int slice_hash(slice s) pure asm "HASHSU"; ;;; Computes sha256 of the data bits of `slice` [s]. If the bit length of `s` is not divisible by eight, ;;; throws a cell underflow exception. The hash value is returned as a 256-bit unsigned integer `x`. -int string_hash(slice s) asm "SHA256U"; +int string_hash(slice s) pure asm "SHA256U"; {- # Signature checks @@ -148,14 +148,14 @@ int string_hash(slice s) asm "SHA256U"; ;;; Note that `CHKSIGNU` creates a 256-bit slice with the hash and calls `CHKSIGNS`. ;;; That is, if [hash] is computed as the hash of some data, these data are hashed twice, ;;; the second hashing occurring inside `CHKSIGNS`. -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; ;;; Checks whether [signature] is a valid Ed25519-signature of the data portion of `slice data` using `public_key`, ;;; similarly to [check_signature]. ;;; If the bit length of [data] is not divisible by eight, throws a cell underflow exception. ;;; The verification of Ed25519 signatures is the standard one, ;;; with sha256 used to reduce [data] to the 256-bit number that is actually signed. -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; {--- # Computation of boc size @@ -171,54 +171,54 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI ;;; The total count of visited cells `x` cannot exceed non-negative [max_cells]; ;;; otherwise the computation is aborted before visiting the `(max_cells + 1)`-st cell and ;;; a zero flag is returned to indicate failure. If [c] is `null`, returns `x = y = z = 0`. -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; ;;; Similar to [compute_data_size?], but accepting a `slice` [s] instead of a `cell`. ;;; The returned value of `x` does not take into account the cell that contains the `slice` [s] itself; ;;; however, the data bits and the cell references of [s] are accounted for in `y` and `z`. -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; ;;; A non-quiet version of [compute_data_size?] that throws a cell overflow exception (`8`) on failure. -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; ;;; A non-quiet version of [slice_compute_data_size?] that throws a cell overflow exception (8) on failure. -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; ;;; Throws an exception with exit_code excno if cond is not 0 (commented since implemented in compilator) -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; +;; () throw_if(int excno, int cond) asm "THROWARGIF"; {-- # Debug primitives Only works for local TVM execution with debug level verbosity -} ;;; Dumps the stack (at most the top 255 values) and shows the total stack depth. -() dump_stack() impure asm "DUMPSTK"; +() dump_stack() asm "DUMPSTK"; {- # Persistent storage save and load -} ;;; Returns the persistent contract storage cell. It can be parsed or modified with slice and builder primitives later. -cell get_data() asm "c4 PUSH"; +cell get_data() pure asm "c4 PUSH"; ;;; Sets `cell` [c] as persistent contract data. You can update persistent contract storage with this primitive. -() set_data(cell c) impure asm "c4 POP"; +() set_data(cell c) asm "c4 POP"; {- # Continuation primitives -} ;;; Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls. ;;; The primitive returns the current value of `c3`. -cont get_c3() asm "c3 PUSH"; +cont get_c3() pure asm "c3 PUSH"; ;;; Updates the current value of `c3`. Usually, it is used for updating smart contract code in run-time. ;;; Note that after execution of this primitive the current code ;;; (and the stack of recursive function calls) won't change, ;;; but any other function call will use a function from the new code. -() set_c3(cont c) impure asm "c3 POP"; +() set_c3(cont c) asm "c3 POP"; ;;; Transforms a `slice` [s] into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist. -cont bless(slice s) asm "BLESS"; +cont bless(slice s) pure asm "BLESS"; {--- # Gas related primitives @@ -230,37 +230,37 @@ cont bless(slice s) asm "BLESS"; ;;; This action is required to process external messages, which bring no value (hence no gas) with themselves. ;;; ;;; For more details check [accept_message effects](https://ton.org/docs/#/smart-contracts/accept). -() accept_message() impure asm "ACCEPT"; +() accept_message() asm "ACCEPT"; ;;; Sets current gas limit `gl` to the minimum of limit and `gm`, and resets the gas credit `gc` to zero. ;;; If the gas consumed so far (including the present instruction) exceeds the resulting value of `gl`, ;;; an (unhandled) out of gas exception is thrown before setting new gas limits. ;;; Notice that [set_gas_limit] with an argument `limit ≥ 2^63 − 1` is equivalent to [accept_message]. -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; ;;; Commits the current state of registers `c4` (“persistent data”) and `c5` (“actions”) ;;; so that the current execution is considered “successful” with the saved values even if an exception ;;; in Computation Phase is thrown later. -() commit() impure asm "COMMIT"; +() commit() asm "COMMIT"; ;;; Not implemented -;;() buy_gas(int gram) impure asm "BUYGAS"; +;;() buy_gas(int gram) asm "BUYGAS"; ;;; Computes the amount of gas that can be bought for `amount` nanoTONs, ;;; and sets `gl` accordingly in the same way as [set_gas_limit]. -() buy_gas(int amount) impure asm "BUYGAS"; +() buy_gas(int amount) asm "BUYGAS"; ;;; Computes the minimum of two integers [x] and [y]. -int min(int x, int y) asm "MIN"; +int min(int x, int y) pure asm "MIN"; ;;; Computes the maximum of two integers [x] and [y]. -int max(int x, int y) asm "MAX"; +int max(int x, int y) pure asm "MAX"; ;;; Sorts two integers. -(int, int) minmax(int x, int y) asm "MINMAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; ;;; Computes the absolute value of an integer [x]. -int abs(int x) asm "ABS"; +int abs(int x) pure asm "ABS"; {- # Slice primitives @@ -279,80 +279,80 @@ int abs(int x) asm "ABS"; ;;; Converts a `cell` [c] into a `slice`. Notice that [c] must be either an ordinary cell, ;;; or an exotic cell (see [TVM.pdf](https://ton-blockchain.github.io/docs/tvm.pdf), 3.1.2) ;;; which is automatically loaded to yield an ordinary cell `c'`, converted into a `slice` afterwards. -slice begin_parse(cell c) asm "CTOS"; +slice begin_parse(cell c) pure asm "CTOS"; ;;; Checks if [s] is empty. If not, throws an exception. -() end_parse(slice s) impure asm "ENDS"; +() end_parse(slice s) asm "ENDS"; ;;; Loads the first reference from the slice. -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; ;;; Preloads the first reference from the slice. -cell preload_ref(slice s) asm "PLDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; {- Functions below are commented because are implemented on compilator level for optimisation -} ;;; Loads a signed [len]-bit integer from a slice [s]. -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; +;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; ;;; Loads an unsigned [len]-bit integer from a slice [s]. -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; +;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; ;;; Preloads a signed [len]-bit integer from a slice [s]. -;; int preload_int(slice s, int len) asm "PLDIX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; ;;; Preloads an unsigned [len]-bit integer from a slice [s]. -;; int preload_uint(slice s, int len) asm "PLDUX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; ;;; Loads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; +;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; ;;; Preloads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; +;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; ;;; Loads serialized amount of TonCoins (any unsigned integer up to `2^128 - 1`). -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -(slice, int) load_coins(slice s) asm( -> 1 0) "LDGRAMS"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +(slice, int) load_coins(slice s) pure asm( -> 1 0) "LDGRAMS"; ;;; Returns all but the first `0 ≤ len ≤ 1023` bits of `slice` [s]. -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; ;;; Returns the first `0 ≤ len ≤ 1023` bits of `slice` [s]. -slice first_bits(slice s, int len) asm "SDCUTFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; ;;; Returns all but the last `0 ≤ len ≤ 1023` bits of `slice` [s]. -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; ;;; Returns the last `0 ≤ len ≤ 1023` bits of `slice` [s]. -slice slice_last(slice s, int len) asm "SDCUTLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; ;;; Loads a dictionary `D` (HashMapE) from `slice` [s]. ;;; (returns `null` if `nothing` constructor is used). -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; ;;; Preloads a dictionary `D` from `slice` [s]. -cell preload_dict(slice s) asm "PLDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; ;;; Loads a dictionary as [load_dict], but returns only the remainder of the slice. -slice skip_dict(slice s) asm "SKIPDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; ;;; Loads (Maybe ^Cell) from `slice` [s]. ;;; In other words loads 1 bit and if it is true ;;; loads first ref and return it with slice remainder ;;; otherwise returns `null` and slice remainder -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; ;;; Preloads (Maybe ^Cell) from `slice` [s]. -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; ;;; Returns the depth of `cell` [c]. ;;; If [c] has no references, then return `0`; ;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [c]. ;;; If [c] is a `null` instead of a cell, returns zero. -int cell_depth(cell c) asm "CDEPTH"; +int cell_depth(cell c) pure asm "CDEPTH"; {- @@ -360,42 +360,42 @@ int cell_depth(cell c) asm "CDEPTH"; -} ;;; Returns the number of references in `slice` [s]. -int slice_refs(slice s) asm "SREFS"; +int slice_refs(slice s) pure asm "SREFS"; ;;; Returns the number of data bits in `slice` [s]. -int slice_bits(slice s) asm "SBITS"; +int slice_bits(slice s) pure asm "SBITS"; ;;; Returns both the number of data bits and the number of references in `slice` [s]. -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; ;;; Checks whether a `slice` [s] is empty (i.e., contains no bits of data and no cell references). -int slice_empty?(slice s) asm "SEMPTY"; +int slice_empty?(slice s) pure asm "SEMPTY"; ;;; Checks whether `slice` [s] has no bits of data. -int slice_data_empty?(slice s) asm "SDEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; ;;; Checks whether `slice` [s] has no references. -int slice_refs_empty?(slice s) asm "SREMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; ;;; Returns the depth of `slice` [s]. ;;; If [s] has no references, then returns `0`; ;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [s]. -int slice_depth(slice s) asm "SDEPTH"; +int slice_depth(slice s) pure asm "SDEPTH"; {- # Builder size primitives -} ;;; Returns the number of cell references already stored in `builder` [b] -int builder_refs(builder b) asm "BREFS"; +int builder_refs(builder b) pure asm "BREFS"; ;;; Returns the number of data bits already stored in `builder` [b]. -int builder_bits(builder b) asm "BBITS"; +int builder_bits(builder b) pure asm "BBITS"; ;;; Returns the depth of `builder` [b]. ;;; If no cell references are stored in [b], then returns 0; ;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [b]. -int builder_depth(builder b) asm "BDEPTH"; +int builder_depth(builder b) pure asm "BDEPTH"; {- # Builder primitives @@ -408,23 +408,23 @@ int builder_depth(builder b) asm "BDEPTH"; -} ;;; Creates a new empty `builder`. -builder begin_cell() asm "NEWC"; +builder begin_cell() pure asm "NEWC"; ;;; Converts a `builder` into an ordinary `cell`. -cell end_cell(builder b) asm "ENDC"; +cell end_cell(builder b) pure asm "ENDC"; ;;; Stores a reference to `cell` [c] into `builder` [b]. -builder store_ref(builder b, cell c) asm(c b) "STREF"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; ;;; Stores an unsigned [len]-bit integer `x` into `b` for `0 ≤ len ≤ 256`. -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; ;;; Stores a signed [len]-bit integer `x` into `b` for` 0 ≤ len ≤ 257`. -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; ;;; Stores `slice` [s] into `builder` [b] -builder store_slice(builder b, slice s) asm "STSLICER"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; ;;; Stores (serializes) an integer [x] in the range `0..2^128 − 1` into `builder` [b]. ;;; The serialization of [x] consists of a 4-bit unsigned big-endian integer `l`, @@ -433,17 +433,17 @@ builder store_slice(builder b, slice s) asm "STSLICER"; ;;; If [x] does not belong to the supported range, a range check exception is thrown. ;;; ;;; Store amounts of TonCoins to the builder as VarUInteger 16 -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_coins(builder b, int x) asm "STGRAMS"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_coins(builder b, int x) pure asm "STGRAMS"; ;;; Stores dictionary `D` represented by `cell` [c] or `null` into `builder` [b]. ;;; In other words, stores a `1`-bit and a reference to [c] if [c] is not `null` and `0`-bit otherwise. -builder store_dict(builder b, cell c) asm(c b) "STDICT"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; ;;; Stores (Maybe ^Cell) to builder: ;;; if cell is null store 1 zero bit ;;; otherwise store 1 true bit and ref to cell -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; {- @@ -485,22 +485,22 @@ builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; ;;; Loads from slice [s] the only prefix that is a valid `MsgAddress`, ;;; and returns both this prefix `s'` and the remainder `s''` of [s] as slices. -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; ;;; Decomposes slice [s] containing a valid `MsgAddress` into a `tuple t` with separate fields of this `MsgAddress`. ;;; If [s] is not a valid `MsgAddress`, a cell deserialization exception is thrown. -tuple parse_addr(slice s) asm "PARSEMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; ;;; Parses slice [s] containing a valid `MsgAddressInt` (usually a `msg_addr_std`), ;;; applies rewriting from the anycast (if present) to the same-length prefix of the address, ;;; and returns both the workchain and the 256-bit address as integers. ;;; If the address is not 256-bit, or if [s] is not a valid serialization of `MsgAddressInt`, ;;; throws a cell deserialization exception. -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; ;;; A variant of [parse_std_addr] that returns the (rewritten) address as a slice [s], ;;; even if it is not exactly 256 bit long (represented by a `msg_addr_var`). -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; {- # Dictionary primitives @@ -509,116 +509,116 @@ tuple parse_addr(slice s) asm "PARSEMSGADDR"; ;;; Sets the value associated with [key_len]-bit key signed index in dictionary [dict] to [value] (cell), ;;; and returns the resulting dictionary. -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; ;;; Sets the value associated with [key_len]-bit key unsigned index in dictionary [dict] to [value] (cell), ;;; and returns the resulting dictionary. -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; - -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF" "NULLSWAPIFNOT"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF" "NULLSWAPIFNOT"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; + +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF" "NULLSWAPIFNOT"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF" "NULLSWAPIFNOT"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; ;;; Creates an empty dictionary, which is actually a null value. Equivalent to PUSHNULL -cell new_dict() asm "NEWDICT"; +cell new_dict() pure asm "NEWDICT"; ;;; Checks whether a dictionary is empty. Equivalent to cell_null?. -int dict_empty?(cell c) asm "DICTEMPTY"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; {- Prefix dictionary primitives -} -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; ;;; Returns the value of the global configuration parameter with integer index `i` as a `cell` or `null` value. -cell config_param(int x) asm "CONFIGOPTPARAM"; +cell config_param(int x) pure asm "CONFIGOPTPARAM"; ;;; Checks whether c is a null. Note, that FunC also has polymorphic null? built-in. -int cell_null?(cell c) asm "ISNULL"; +int cell_null?(cell c) pure asm "ISNULL"; ;;; Creates an output action which would reserve exactly amount nanotoncoins (if mode = 0), at most amount nanotoncoins (if mode = 2), or all but amount nanotoncoins (if mode = 1 or mode = 3), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carrying amount nanotoncoins (or b − amount nanotoncoins, where b is the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit +2 in mode means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit +8 in mode means `amount <- -amount` before performing any further actions. Bit +4 in mode means that amount is increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currently, amount must be a non-negative integer, and mode must be in the range 0..15. -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; ;;; Similar to raw_reserve, but also accepts a dictionary extra_amount (represented by a cell or null) with extra currencies. In this way currencies other than TonCoin can be reserved. -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; ;;; Sends a raw message contained in msg, which should contain a correctly serialized object Message X, with the only exception that the source address is allowed to have dummy value addr_none (to be automatically replaced with the current smart contract address), and ihr_fee, fwd_fee, created_lt and created_at fields can have arbitrary values (to be rewritten with correct values during the action phase of the current transaction). Integer parameter mode contains the flags. Currently mode = 0 is used for ordinary messages; mode = 128 is used for messages that are to carry all the remaining balance of the current smart contract (instead of the value originally indicated in the message); mode = 64 is used for messages that carry all the remaining value of the inbound message in addition to the value initially indicated in the new message (if bit 0 is not set, the gas fees are deducted from this amount); mode' = mode + 1 means that the sender wants to pay transfer fees separately; mode' = mode + 2 means that any errors arising while processing this message during the action phase should be ignored. Finally, mode' = mode + 32 means that the current account must be destroyed if its resulting balance is zero. This flag is usually employed together with +128. -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; ;;; Creates an output action that would change this smart contract code to that given by cell new_code. Notice that this change will take effect only after the successful termination of the current run of the smart contract -() set_code(cell new_code) impure asm "SETCODE"; +() set_code(cell new_code) asm "SETCODE"; ;;; Generates a new pseudo-random unsigned 256-bit integer x. The algorithm is as follows: if r is the old value of the random seed, considered as a 32-byte array (by constructing the big-endian representation of an unsigned 256-bit integer), then its sha512(r) is computed; the first 32 bytes of this hash are stored as the new value r' of the random seed, and the remaining 32 bytes are returned as the next random value x. -int random() impure asm "RANDU256"; +int random() asm "RANDU256"; ;;; Generates a new pseudo-random integer z in the range 0..range−1 (or range..−1, if range < 0). More precisely, an unsigned random value x is generated as in random; then z := x * range / 2^256 is computed. -int rand(int range) impure asm "RAND"; +int rand(int range) asm "RAND"; ;;; Returns the current random seed as an unsigned 256-bit Integer. -int get_seed() asm "RANDSEED"; +int get_seed() pure asm "RANDSEED"; ;;; Sets the random seed to unsigned 256-bit seed. -() set_seed(int) impure asm "SETRAND"; +() set_seed(int) asm "SETRAND"; ;;; Mixes unsigned 256-bit integer x into the random seed r by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed r, and the second with the big-endian representation of x. -() randomize(int x) impure asm "ADDRAND"; +() randomize(int x) asm "ADDRAND"; ;;; Equivalent to randomize(cur_lt());. -() randomize_lt() impure asm "LTIME" "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; ;;; Checks whether the data parts of two slices coinside -int equal_slice_bits (slice a, slice b) asm "SDEQ"; +int equal_slice_bits (slice a, slice b) pure asm "SDEQ"; ;;; Concatenates two builders -builder store_builder(builder to, builder from) asm "STBR"; +builder store_builder(builder to, builder from) pure asm "STBR"; diff --git a/crypto/func/auto-tests/legacy_tests/tele-nft-item/stdlib.fc b/crypto/func/auto-tests/legacy_tests/tele-nft-item/stdlib.fc index 7304a80e6..f93ebf792 100644 --- a/crypto/func/auto-tests/legacy_tests/tele-nft-item/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/tele-nft-item/stdlib.fc @@ -1,208 +1,208 @@ ;; Standard library for funC ;; -forall X -> tuple cons(X head, tuple tail) asm "CONS"; -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -forall X -> X car(tuple list) asm "CAR"; -tuple cdr(tuple list) asm "CDR"; -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> [X] single(X x) asm "SINGLE"; -forall X -> X unsingle([X] t) asm "UNSINGLE"; -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -forall X -> X first(tuple t) asm "FIRST"; -forall X -> X second(tuple t) asm "SECOND"; -forall X -> X third(tuple t) asm "THIRD"; -forall X -> X fourth(tuple t) asm "3 INDEX"; -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -forall X -> X null() asm "PUSHNULL"; -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; - -int now() asm "NOW"; -slice my_address() asm "MYADDR"; -[int, cell] get_balance() asm "BALANCE"; -int cur_lt() asm "LTIME"; -int block_lt() asm "BLOCKLT"; - -int cell_hash(cell c) asm "HASHCU"; -int slice_hash(slice s) asm "HASHSU"; -int string_hash(slice s) asm "SHA256U"; - -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; - -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; - -() dump_stack() impure asm "DUMPSTK"; - -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; +forall X -> X car(tuple list) pure asm "CAR"; +tuple cdr(tuple list) pure asm "CDR"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> [X] single(X x) pure asm "SINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; +forall X -> X first(tuple t) pure asm "FIRST"; +forall X -> X second(tuple t) pure asm "SECOND"; +forall X -> X third(tuple t) pure asm "THIRD"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; +forall X -> X null() pure asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; + +int now() pure asm "NOW"; +slice my_address() pure asm "MYADDR"; +[int, cell] get_balance() pure asm "BALANCE"; +int cur_lt() pure asm "LTIME"; +int block_lt() pure asm "BLOCKLT"; + +int cell_hash(cell c) pure asm "HASHCU"; +int slice_hash(slice s) pure asm "HASHSU"; +int string_hash(slice s) pure asm "SHA256U"; + +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; + +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; + +;; () throw_if(int excno, int cond) asm "THROWARGIF"; + +() dump_stack() asm "DUMPSTK"; + +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; cont get_c3() asm "c3 PUSH"; -() set_c3(cont c) impure asm "c3 POP"; +() set_c3(cont c) asm "c3 POP"; cont bless(slice s) asm "BLESS"; -() accept_message() impure asm "ACCEPT"; -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; -() commit() impure asm "COMMIT"; -() buy_gas(int gram) impure asm "BUYGAS"; - -int min(int x, int y) asm "MIN"; -int max(int x, int y) asm "MAX"; -(int, int) minmax(int x, int y) asm "MINMAX"; -int abs(int x) asm "ABS"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -cell preload_ref(slice s) asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -slice first_bits(slice s, int len) asm "SDCUTFIRST"; -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -slice slice_last(slice s, int len) asm "SDCUTLAST"; -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -cell preload_dict(slice s) asm "PLDDICT"; -slice skip_dict(slice s) asm "SKIPDICT"; - -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; - -int cell_depth(cell c) asm "CDEPTH"; - -int slice_refs(slice s) asm "SREFS"; -int slice_bits(slice s) asm "SBITS"; -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; -int slice_empty?(slice s) asm "SEMPTY"; -int slice_data_empty?(slice s) asm "SDEMPTY"; -int slice_refs_empty?(slice s) asm "SREMPTY"; -int slice_depth(slice s) asm "SDEPTH"; - -int builder_refs(builder b) asm "BREFS"; -int builder_bits(builder b) asm "BBITS"; -int builder_depth(builder b) asm "BDEPTH"; - -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -builder store_slice(builder b, slice s) asm "STSLICER"; -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_dict(builder b, cell c) asm(c b) "STDICT"; - -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -tuple parse_addr(slice s) asm "PARSEMSGADDR"; -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; - -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF" "NULLSWAPIFNOT"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF" "NULLSWAPIFNOT"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -cell new_dict() asm "NEWDICT"; -int dict_empty?(cell c) asm "DICTEMPTY"; - -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; - -cell config_param(int x) asm "CONFIGOPTPARAM"; -int cell_null?(cell c) asm "ISNULL"; - -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -() set_code(cell new_code) impure asm "SETCODE"; - -int random() impure asm "RANDU256"; -int rand(int range) impure asm "RAND"; +() accept_message() asm "ACCEPT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; +() commit() asm "COMMIT"; +() buy_gas(int gram) asm "BUYGAS"; + +int min(int x, int y) pure asm "MIN"; +int max(int x, int y) pure asm "MAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; +int abs(int x) pure asm "ABS"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; +;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; +;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; + +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; + +int cell_depth(cell c) pure asm "CDEPTH"; + +int slice_refs(slice s) pure asm "SREFS"; +int slice_bits(slice s) pure asm "SBITS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; +int slice_empty?(slice s) pure asm "SEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; +int slice_depth(slice s) pure asm "SDEPTH"; + +int builder_refs(builder b) pure asm "BREFS"; +int builder_bits(builder b) pure asm "BBITS"; +int builder_depth(builder b) pure asm "BDEPTH"; + +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; + +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; + +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF" "NULLSWAPIFNOT"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF" "NULLSWAPIFNOT"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; + +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; + +cell config_param(int x) pure asm "CONFIGOPTPARAM"; +int cell_null?(cell c) pure asm "ISNULL"; + +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; +() set_code(cell new_code) asm "SETCODE"; + +int random() asm "RANDU256"; +int rand(int range) asm "RAND"; int get_seed() asm "RANDSEED"; -int set_seed() impure asm "SETRAND"; -() randomize(int x) impure asm "ADDRAND"; -() randomize_lt() impure asm "LTIME" "ADDRAND"; +int set_seed() asm "SETRAND"; +() randomize(int x) asm "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; diff --git a/crypto/func/auto-tests/legacy_tests/uni-lock-wallet/stdlib.fc b/crypto/func/auto-tests/legacy_tests/uni-lock-wallet/stdlib.fc index cddb5ae04..7f45a6dd7 100644 --- a/crypto/func/auto-tests/legacy_tests/uni-lock-wallet/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/uni-lock-wallet/stdlib.fc @@ -1,211 +1,211 @@ ;; Standard library for funC ;; -forall X -> tuple cons(X head, tuple tail) asm "CONS"; -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -forall X -> X car(tuple list) asm "CAR"; -tuple cdr(tuple list) asm "CDR"; -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> [X] single(X x) asm "SINGLE"; -forall X -> X unsingle([X] t) asm "UNSINGLE"; -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -forall X -> X first(tuple t) asm "FIRST"; -forall X -> X second(tuple t) asm "SECOND"; -forall X -> X third(tuple t) asm "THIRD"; -forall X -> X fourth(tuple t) asm "3 INDEX"; -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -forall X -> X null() asm "PUSHNULL"; -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; - -int now() asm "NOW"; -slice my_address() asm "MYADDR"; -[int, cell] get_balance() asm "BALANCE"; -int cur_lt() asm "LTIME"; -int block_lt() asm "BLOCKLT"; - -int cell_hash(cell c) asm "HASHCU"; -int slice_hash(slice s) asm "HASHSU"; -int string_hash(slice s) asm "SHA256U"; - -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; - -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; - -() dump_stack() impure asm "DUMPSTK"; - -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -cont get_c3() asm "c3 PUSH"; -() set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) asm "BLESS"; - -() accept_message() impure asm "ACCEPT"; -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; -() commit() impure asm "COMMIT"; -() buy_gas(int gram) impure asm "BUYGAS"; - -int min(int x, int y) asm "MIN"; -int max(int x, int y) asm "MAX"; -(int, int) minmax(int x, int y) asm "MINMAX"; -int abs(int x) asm "ABS"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -cell preload_ref(slice s) asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -slice first_bits(slice s, int len) asm "SDCUTFIRST"; -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -slice slice_last(slice s, int len) asm "SDCUTLAST"; -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -cell preload_dict(slice s) asm "PLDDICT"; -slice skip_dict(slice s) asm "SKIPDICT"; - -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; - -int cell_depth(cell c) asm "CDEPTH"; - -int slice_refs(slice s) asm "SREFS"; -int slice_bits(slice s) asm "SBITS"; -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; -int slice_empty?(slice s) asm "SEMPTY"; -int slice_data_empty?(slice s) asm "SDEMPTY"; -int slice_refs_empty?(slice s) asm "SREMPTY"; -int slice_depth(slice s) asm "SDEPTH"; - -int builder_refs(builder b) asm "BREFS"; -int builder_bits(builder b) asm "BBITS"; -int builder_depth(builder b) asm "BDEPTH"; - -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -builder store_slice(builder b, slice s) asm "STSLICER"; -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_dict(builder b, cell c) asm(c b) "STDICT"; - -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -tuple parse_addr(slice s) asm "PARSEMSGADDR"; -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; - -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -cell new_dict() asm "NEWDICT"; -int dict_empty?(cell c) asm "DICTEMPTY"; - -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; - -cell config_param(int x) asm "CONFIGOPTPARAM"; -int cell_null?(cell c) asm "ISNULL"; - -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -() set_code(cell new_code) impure asm "SETCODE"; - -int random() impure asm "RANDU256"; -int rand(int range) impure asm "RAND"; -int get_seed() asm "RANDSEED"; -int set_seed() impure asm "SETRAND"; -() randomize(int x) impure asm "ADDRAND"; -() randomize_lt() impure asm "LTIME" "ADDRAND"; - -builder store_coins(builder b, int x) asm "STVARUINT16"; -(slice, int) load_coins(slice s) asm( -> 1 0) "LDVARUINT16"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; +forall X -> X car(tuple list) pure asm "CAR"; +tuple cdr(tuple list) pure asm "CDR"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> [X] single(X x) pure asm "SINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; +forall X -> X first(tuple t) pure asm "FIRST"; +forall X -> X second(tuple t) pure asm "SECOND"; +forall X -> X third(tuple t) pure asm "THIRD"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; +forall X -> X null() pure asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; + +int now() pure asm "NOW"; +slice my_address() pure asm "MYADDR"; +[int, cell] get_balance() pure asm "BALANCE"; +int cur_lt() pure asm "LTIME"; +int block_lt() pure asm "BLOCKLT"; + +int cell_hash(cell c) pure asm "HASHCU"; +int slice_hash(slice s) pure asm "HASHSU"; +int string_hash(slice s) pure asm "SHA256U"; + +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; + +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; + +;; () throw_if(int excno, int cond) asm "THROWARGIF"; + +() dump_stack() asm "DUMPSTK"; + +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +cont get_c3() pure asm "c3 PUSH"; +() set_c3(cont c) asm "c3 POP"; +cont bless(slice s) pure asm "BLESS"; + +() accept_message() asm "ACCEPT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; +() commit() asm "COMMIT"; +() buy_gas(int gram) asm "BUYGAS"; + +int min(int x, int y) pure asm "MIN"; +int max(int x, int y) pure asm "MAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; +int abs(int x) pure asm "ABS"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; +;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; +;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; + +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; + +int cell_depth(cell c) pure asm "CDEPTH"; + +int slice_refs(slice s) pure asm "SREFS"; +int slice_bits(slice s) pure asm "SBITS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; +int slice_empty?(slice s) pure asm "SEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; +int slice_depth(slice s) pure asm "SDEPTH"; + +int builder_refs(builder b) pure asm "BREFS"; +int builder_bits(builder b) pure asm "BBITS"; +int builder_depth(builder b) pure asm "BDEPTH"; + +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; + +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; + +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; + +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; + +cell config_param(int x) pure asm "CONFIGOPTPARAM"; +int cell_null?(cell c) pure asm "ISNULL"; + +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; +() set_code(cell new_code) asm "SETCODE"; + +int random() asm "RANDU256"; +int rand(int range) asm "RAND"; +int get_seed() pure asm "RANDSEED"; +int set_seed() asm "SETRAND"; +() randomize(int x) asm "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; + +builder store_coins(builder b, int x) pure asm "STVARUINT16"; +(slice, int) load_coins(slice s) pure asm( -> 1 0) "LDVARUINT16"; diff --git a/crypto/func/auto-tests/legacy_tests/wallet-v4/stdlib.fc b/crypto/func/auto-tests/legacy_tests/wallet-v4/stdlib.fc index f04be0b68..a76e869dc 100644 --- a/crypto/func/auto-tests/legacy_tests/wallet-v4/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/wallet-v4/stdlib.fc @@ -1,215 +1,215 @@ ;; Standard library for funC ;; -forall X -> tuple cons(X head, tuple tail) asm "CONS"; -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -forall X -> X car(tuple list) asm "CAR"; -tuple cdr(tuple list) asm "CDR"; -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> [X] single(X x) asm "SINGLE"; -forall X -> X unsingle([X] t) asm "UNSINGLE"; -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -forall X -> X first(tuple t) asm "FIRST"; -forall X -> X second(tuple t) asm "SECOND"; -forall X -> X third(tuple t) asm "THIRD"; -forall X -> X fourth(tuple t) asm "3 INDEX"; -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -forall X -> X null() asm "PUSHNULL"; -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; - -int now() asm "NOW"; -slice my_address() asm "MYADDR"; -[int, cell] get_balance() asm "BALANCE"; -int cur_lt() asm "LTIME"; -int block_lt() asm "BLOCKLT"; - -int cell_hash(cell c) asm "HASHCU"; -int slice_hash(slice s) asm "HASHSU"; -int string_hash(slice s) asm "SHA256U"; - -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; - -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; - -() dump_stack() impure asm "DUMPSTK"; - -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -cont get_c3() asm "c3 PUSH"; -() set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) asm "BLESS"; - -() accept_message() impure asm "ACCEPT"; -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; -() commit() impure asm "COMMIT"; -() buy_gas(int gram) impure asm "BUYGAS"; - -int min(int x, int y) asm "MIN"; -int max(int x, int y) asm "MAX"; -(int, int) minmax(int x, int y) asm "MINMAX"; -int abs(int x) asm "ABS"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -cell preload_ref(slice s) asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -slice first_bits(slice s, int len) asm "SDCUTFIRST"; -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -slice slice_last(slice s, int len) asm "SDCUTLAST"; -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -cell preload_dict(slice s) asm "PLDDICT"; -slice skip_dict(slice s) asm "SKIPDICT"; - -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; - -int cell_depth(cell c) asm "CDEPTH"; - -int slice_refs(slice s) asm "SREFS"; -int slice_bits(slice s) asm "SBITS"; -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; -int slice_empty?(slice s) asm "SEMPTY"; -int slice_data_empty?(slice s) asm "SDEMPTY"; -int slice_refs_empty?(slice s) asm "SREMPTY"; -int slice_depth(slice s) asm "SDEPTH"; - -int builder_refs(builder b) asm "BREFS"; -int builder_bits(builder b) asm "BBITS"; -int builder_depth(builder b) asm "BDEPTH"; - -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -builder store_slice(builder b, slice s) asm "STSLICER"; -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_dict(builder b, cell c) asm(c b) "STDICT"; - -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -tuple parse_addr(slice s) asm "PARSEMSGADDR"; -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; - -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -cell new_dict() asm "NEWDICT"; -int dict_empty?(cell c) asm "DICTEMPTY"; - -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; - -cell config_param(int x) asm "CONFIGOPTPARAM"; -int cell_null?(cell c) asm "ISNULL"; - -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -() set_code(cell new_code) impure asm "SETCODE"; - -int random() impure asm "RANDU256"; -int rand(int range) impure asm "RAND"; -int get_seed() asm "RANDSEED"; -int set_seed() impure asm "SETRAND"; -() randomize(int x) impure asm "ADDRAND"; -() randomize_lt() impure asm "LTIME" "ADDRAND"; - -builder store_coins(builder b, int x) asm "STVARUINT16"; -(slice, int) load_coins(slice s) asm( -> 1 0) "LDVARUINT16"; - -int equal_slices (slice a, slice b) asm "SDEQ"; -int builder_null?(builder b) asm "ISNULL"; -builder store_builder(builder to, builder from) asm "STBR"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; +forall X -> X car(tuple list) pure asm "CAR"; +tuple cdr(tuple list) pure asm "CDR"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> [X] single(X x) pure asm "SINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; +forall X -> X first(tuple t) pure asm "FIRST"; +forall X -> X second(tuple t) pure asm "SECOND"; +forall X -> X third(tuple t) pure asm "THIRD"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; +forall X -> X null() pure asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; + +int now() pure asm "NOW"; +slice my_address() pure asm "MYADDR"; +[int, cell] get_balance() pure asm "BALANCE"; +int cur_lt() pure asm "LTIME"; +int block_lt() pure asm "BLOCKLT"; + +int cell_hash(cell c) pure asm "HASHCU"; +int slice_hash(slice s) pure asm "HASHSU"; +int string_hash(slice s) pure asm "SHA256U"; + +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; + +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; + +;; () throw_if(int excno, int cond) asm "THROWARGIF"; + +() dump_stack() asm "DUMPSTK"; + +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +cont get_c3() pure asm "c3 PUSH"; +() set_c3(cont c) asm "c3 POP"; +cont bless(slice s) pure asm "BLESS"; + +() accept_message() asm "ACCEPT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; +() commit() asm "COMMIT"; +() buy_gas(int gram) asm "BUYGAS"; + +int min(int x, int y) pure asm "MIN"; +int max(int x, int y) pure asm "MAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; +int abs(int x) pure asm "ABS"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; +;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; +;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; + +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; + +int cell_depth(cell c) pure asm "CDEPTH"; + +int slice_refs(slice s) pure asm "SREFS"; +int slice_bits(slice s) pure asm "SBITS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; +int slice_empty?(slice s) pure asm "SEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; +int slice_depth(slice s) pure asm "SDEPTH"; + +int builder_refs(builder b) pure asm "BREFS"; +int builder_bits(builder b) pure asm "BBITS"; +int builder_depth(builder b) pure asm "BDEPTH"; + +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; + +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; + +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; + +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; + +cell config_param(int x) pure asm "CONFIGOPTPARAM"; +int cell_null?(cell c) pure asm "ISNULL"; + +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; +() set_code(cell new_code) asm "SETCODE"; + +int random() asm "RANDU256"; +int rand(int range) asm "RAND"; +int get_seed() pure asm "RANDSEED"; +int set_seed() asm "SETRAND"; +() randomize(int x) asm "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; + +builder store_coins(builder b, int x) pure asm "STVARUINT16"; +(slice, int) load_coins(slice s) pure asm( -> 1 0) "LDVARUINT16"; + +int equal_slices (slice a, slice b) pure asm "SDEQ"; +int builder_null?(builder b) pure asm "ISNULL"; +builder store_builder(builder to, builder from) pure asm "STBR"; diff --git a/crypto/func/auto-tests/legacy_tests/wallet-v4/wallet-v4-code.fc b/crypto/func/auto-tests/legacy_tests/wallet-v4/wallet-v4-code.fc index 2b6b279fa..d6fa24d87 100644 --- a/crypto/func/auto-tests/legacy_tests/wallet-v4/wallet-v4-code.fc +++ b/crypto/func/auto-tests/legacy_tests/wallet-v4/wallet-v4-code.fc @@ -10,7 +10,7 @@ _ skipBits(slice s, int len) { return skip_bits(s, len); } (cell, int) tryDictDelete(cell dict, int keyLen, slice index) { return dict_delete?(dict, keyLen, index); } -() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure { +() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) { var cs = in_msg_cell.begin_parse(); var flags = cs~load_uint(4); ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool if (flags & 1) { @@ -74,7 +74,7 @@ _ skipBits(slice s, int len) { return skip_bits(s, len); } } } -() recv_external(slice in_msg) impure { +() recv_external(slice in_msg) { var signature = in_msg~load_bits(512); var cs = in_msg; var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32)); diff --git a/crypto/func/auto-tests/legacy_tests/whales-nominators/modules/utils.fc b/crypto/func/auto-tests/legacy_tests/whales-nominators/modules/utils.fc index 50e4e57c1..2a90710b0 100644 --- a/crypto/func/auto-tests/legacy_tests/whales-nominators/modules/utils.fc +++ b/crypto/func/auto-tests/legacy_tests/whales-nominators/modules/utils.fc @@ -21,13 +21,13 @@ int parse_work_addr(slice cs) { ;; Custom Commands ;; -(int) equal_slices (slice s1, slice s2) asm "SDEQ"; -builder store_builder(builder to, builder what) asm(what to) "STB"; -builder store_builder_ref(builder to, builder what) asm(what to) "STBREFR"; -(slice, cell) load_maybe_cell(slice s) asm( -> 1 0) "LDDICT"; -(int) mod (int x, int y) asm "MOD"; -builder store_coins(builder b, int x) asm "STGRAMS"; -(slice, int) load_coins(slice s) asm( -> 1 0) "LDGRAMS"; +(int) equal_slices (slice s1, slice s2) pure asm "SDEQ"; +builder store_builder(builder to, builder what) pure asm(what to) "STB"; +builder store_builder_ref(builder to, builder what) pure asm(what to) "STBREFR"; +(slice, cell) load_maybe_cell(slice s) pure asm( -> 1 0) "LDDICT"; +(int) mod (int x, int y) pure asm "MOD"; +builder store_coins(builder b, int x) pure asm "STGRAMS"; +(slice, int) load_coins(slice s) pure asm( -> 1 0) "LDGRAMS"; ;; @@ -182,4 +182,4 @@ builder store_withdraw_delayed(builder b) inline { .store_uint(555062058613674355757418046597367430905687018487295295368960255172568430, 240) ;; 'Please, retry the command when' .store_text_space() .store_uint(45434371896731988359547695118970428857702208118225198, 176); ;; 'your balance is ready.' -} \ No newline at end of file +} diff --git a/crypto/func/auto-tests/legacy_tests/whales-nominators/stdlib.fc b/crypto/func/auto-tests/legacy_tests/whales-nominators/stdlib.fc index e69d91716..c23048349 100644 --- a/crypto/func/auto-tests/legacy_tests/whales-nominators/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/whales-nominators/stdlib.fc @@ -1,212 +1,212 @@ ;; Standard library for funC ;; -forall X -> tuple cons(X head, tuple tail) asm "CONS"; -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; -forall X -> X car(tuple list) asm "CAR"; -tuple cdr(tuple list) asm "CDR"; -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> [X] single(X x) asm "SINGLE"; -forall X -> X unsingle([X] t) asm "UNSINGLE"; -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; -forall X -> X first(tuple t) asm "FIRST"; -forall X -> X second(tuple t) asm "SECOND"; -forall X -> X third(tuple t) asm "THIRD"; -forall X -> X fourth(tuple t) asm "3 INDEX"; -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; -forall X -> X null() asm "PUSHNULL"; -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; - -int now() asm "NOW"; -slice my_address() asm "MYADDR"; -[int, cell] get_balance() asm "BALANCE"; -int cur_lt() asm "LTIME"; -int block_lt() asm "BLOCKLT"; - -int cell_hash(cell c) asm "HASHCU"; -int slice_hash(slice s) asm "HASHSU"; -int string_hash(slice s) asm "SHA256U"; - -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; - -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; - -;; () throw_if(int excno, int cond) impure asm "THROWARGIF"; - -() dump_stack() impure asm "DUMPSTK"; - -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -cont get_c3() asm "c3 PUSH"; -() set_c3(cont c) impure asm "c3 POP"; -cont bless(slice s) asm "BLESS"; - -() accept_message() impure asm "ACCEPT"; -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; -() commit() impure asm "COMMIT"; -() buy_gas(int gram) impure asm "BUYGAS"; - -int min(int x, int y) asm "MIN"; -int max(int x, int y) asm "MAX"; -(int, int) minmax(int x, int y) asm "MINMAX"; -int abs(int x) asm "ABS"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -cell preload_ref(slice s) asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; -slice first_bits(slice s, int len) asm "SDCUTFIRST"; -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -slice slice_last(slice s, int len) asm "SDCUTLAST"; -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; -cell preload_dict(slice s) asm "PLDDICT"; -slice skip_dict(slice s) asm "SKIPDICT"; - -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; - -int cell_depth(cell c) asm "CDEPTH"; - -int slice_refs(slice s) asm "SREFS"; -int slice_bits(slice s) asm "SBITS"; -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; -int slice_empty?(slice s) asm "SEMPTY"; -int slice_data_empty?(slice s) asm "SDEMPTY"; -int slice_refs_empty?(slice s) asm "SREMPTY"; -int slice_depth(slice s) asm "SDEPTH"; - -int builder_refs(builder b) asm "BREFS"; -int builder_bits(builder b) asm "BBITS"; -int builder_depth(builder b) asm "BDEPTH"; - -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; - builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -builder store_slice(builder b, slice s) asm "STSLICER"; -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_dict(builder b, cell c) asm(c b) "STDICT"; - -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; -tuple parse_addr(slice s) asm "PARSEMSGADDR"; -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; - -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; -cell new_dict() asm "NEWDICT"; -int dict_empty?(cell c) asm "DICTEMPTY"; - -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; - -cell config_param(int x) asm "CONFIGOPTPARAM"; -int cell_null?(cell c) asm "ISNULL"; - -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; -() set_code(cell new_code) impure asm "SETCODE"; - -int random() impure asm "RANDU256"; -int rand(int range) impure asm "RAND"; -int get_seed() asm "RANDSEED"; -int set_seed() impure asm "SETRAND"; -() randomize(int x) impure asm "ADDRAND"; -() randomize_lt() impure asm "LTIME" "ADDRAND"; - - -int equal_slices (slice a, slice b) asm "SDEQ"; -int builder_null?(builder b) asm "ISNULL"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; +forall X -> X car(tuple list) pure asm "CAR"; +tuple cdr(tuple list) pure asm "CDR"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> [X] single(X x) pure asm "SINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; +forall X -> X first(tuple t) pure asm "FIRST"; +forall X -> X second(tuple t) pure asm "SECOND"; +forall X -> X third(tuple t) pure asm "THIRD"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; +forall X -> X null() pure asm "PUSHNULL"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; + +int now() pure asm "NOW"; +slice my_address() pure asm "MYADDR"; +[int, cell] get_balance() pure asm "BALANCE"; +int cur_lt() pure asm "LTIME"; +int block_lt() pure asm "BLOCKLT"; + +int cell_hash(cell c) pure asm "HASHCU"; +int slice_hash(slice s) pure asm "HASHSU"; +int string_hash(slice s) pure asm "SHA256U"; + +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; + +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; + +;; () throw_if(int excno, int cond) asm "THROWARGIF"; + +() dump_stack() asm "DUMPSTK"; + +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +cont get_c3() pure asm "c3 PUSH"; +() set_c3(cont c) asm "c3 POP"; +cont bless(slice s) pure asm "BLESS"; + +() accept_message() asm "ACCEPT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; +() commit() asm "COMMIT"; +() buy_gas(int gram) asm "BUYGAS"; + +int min(int x, int y) pure asm "MIN"; +int max(int x, int y) pure asm "MAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; +int abs(int x) pure asm "ABS"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; +;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; +;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; + +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; + +int cell_depth(cell c) pure asm "CDEPTH"; + +int slice_refs(slice s) pure asm "SREFS"; +int slice_bits(slice s) pure asm "SBITS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; +int slice_empty?(slice s) pure asm "SEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; +int slice_depth(slice s) pure asm "SDEPTH"; + +int builder_refs(builder b) pure asm "BREFS"; +int builder_bits(builder b) pure asm "BBITS"; +int builder_depth(builder b) pure asm "BDEPTH"; + +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; + builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; + +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; + +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; + +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; + +cell config_param(int x) pure asm "CONFIGOPTPARAM"; +int cell_null?(cell c) pure asm "ISNULL"; + +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; +() set_code(cell new_code) asm "SETCODE"; + +int random() asm "RANDU256"; +int rand(int range) asm "RAND"; +int get_seed() pure asm "RANDSEED"; +int set_seed() asm "SETRAND"; +() randomize(int x) asm "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; + + +int equal_slices (slice a, slice b) pure asm "SDEQ"; +int builder_null?(builder b) pure asm "ISNULL"; diff --git a/crypto/func/auto-tests/tests/asm_arg_order.fc b/crypto/func/auto-tests/tests/asm_arg_order.fc index 1824b84ad..8e056cacf 100644 --- a/crypto/func/auto-tests/tests/asm_arg_order.fc +++ b/crypto/func/auto-tests/tests/asm_arg_order.fc @@ -1,17 +1,17 @@ -tuple empty_tuple() asm "NIL"; -forall X -> (tuple, ()) tpush(tuple t, X x) asm "TPUSH"; +tuple empty_tuple() pure asm "NIL"; +forall X -> (tuple, ()) tpush(tuple t, X x) pure asm "TPUSH"; tuple emptyTuple() { return empty_tuple(); } forall X -> (tuple, ()) tuplePush(tuple t, X value) { return tpush(t, value); } -tuple asm_func_1(int x, int y, int z) asm "3 TUPLE"; -tuple asm_func_2(int x, int y, int z) asm (z y x -> 0) "3 TUPLE"; -tuple asm_func_3(int x, int y, int z) asm (y z x -> 0) "3 TUPLE"; -tuple asm_func_4(int a, (int, (int, int)) b, int c) asm (b a c -> 0) "5 TUPLE"; +tuple asm_func_1(int x, int y, int z) pure asm "3 TUPLE"; +tuple asm_func_2(int x, int y, int z) pure asm (z y x -> 0) "3 TUPLE"; +tuple asm_func_3(int x, int y, int z) pure asm (y z x -> 0) "3 TUPLE"; +tuple asm_func_4(int a, (int, (int, int)) b, int c) pure asm (b a c -> 0) "5 TUPLE"; _ asmFunc1(int x, int y, int z) { return asm_func_1(x, y, z); } _ asmFunc3(int x, int y, int z) { return asm_func_3(x, y, z); } -(tuple, ()) asm_func_modify(tuple a, int b, int c) asm (c b a -> 0) "SWAP TPUSH SWAP TPUSH"; +(tuple, ()) asm_func_modify(tuple a, int b, int c) pure asm (c b a -> 0) "SWAP TPUSH SWAP TPUSH"; (tuple, ()) asmFuncModify(tuple a, int b, int c) { return asm_func_modify(a, b, c); } global tuple t; diff --git a/crypto/func/auto-tests/tests/camel1.fc b/crypto/func/auto-tests/tests/camel1.fc index 1146f6977..705264682 100644 --- a/crypto/func/auto-tests/tests/camel1.fc +++ b/crypto/func/auto-tests/tests/camel1.fc @@ -8,12 +8,12 @@ ;; This works with ~functions also. And even works with wrappers of wrappers. ;; Moreover, such wrappers can reorder input parameters, see a separate test camel2.fc. -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -slice begin_parse(cell c) asm "CTOS"; -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +slice begin_parse(cell c) pure asm "CTOS"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; builder beginCell() { return begin_cell(); } cell endCell(builder b) { return end_cell(b); } @@ -21,19 +21,19 @@ builder storeRef(builder b, cell c) { return store_ref(b, c); } builder storeUint(builder b, int i, int bw) { return store_uint(b, i, bw); } ;; 'inline' is not needed actually, but if it exists, it's just ignored -slice beginParse(cell c) inline { return begin_parse(c); } -slice skipBits(slice s, int len) inline { return skip_bits(s, len); } -(slice, ()) ~skipBits(slice s, int len) inline { return ~skip_bits(s, len); } -(slice, int) ~loadUint(slice s, int len) inline { return load_uint(s, len); } +slice beginParse(cell c) pure inline { return begin_parse(c); } +slice skipBits(slice s, int len) pure inline { return skip_bits(s, len); } +(slice, ()) ~skipBits(slice s, int len) pure inline { return ~skip_bits(s, len); } +(slice, int) ~loadUint(slice s, int len) pure inline { return load_uint(s, len); } -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) computeDataSize(cell c, int maxCells) impure { return compute_data_size(c, maxCells); } +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) computeDataSize(cell c, int maxCells) { return compute_data_size(c, maxCells); } -cell new_dict() asm "NEWDICT"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +cell new_dict() pure asm "NEWDICT"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; cell dict::new() { return new_dict(); } cell dict::iset(cell dict, int keyLen, int index, slice value) { return idict_set(dict, keyLen, index, value); } @@ -41,11 +41,11 @@ cell dict::iset(cell dict, int keyLen, int index, slice value) { return idict_se (slice, int) dict::tryIGet(cell dict, int keyLen, int index) { return idict_get?(dict, keyLen, index); } (int, slice, int) dict::tryIGetMin(cell dict, int keyLen) { return idict_get_min?(dict, keyLen); } -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; -forall X -> X null() asm "PUSHNULL"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; +forall X -> X null() pure asm "PUSHNULL"; tuple emptyTuple() { return empty_tuple(); } tuple emptyTuple1() { return emptyTuple(); } @@ -54,19 +54,19 @@ forall X -> tuple tuplePush(tuple t, X value) { return tpush(t, value); } forall X -> (tuple, ()) ~tuplePush(tuple t, X value) { return ~tpush(t, value); } forall X -> X tupleAt(tuple t, int index) { return at(t, index); } forall X1, Y2, Z3 -> Y2 tripleSecond([X1, Y2, Z3] p) { return triple_second(p); } -forall X -> X nullValue() asm "PUSHNULL"; +forall X -> X nullValue() pure asm "PUSHNULL"; -() throwIf(int excNo, int condition) impure { return throw_if(excNo, condition); } +() throwIf(int excNo, int condition) { return throw_if(excNo, condition); } tuple initial1(tuple x) { return x; } _ initial2(x) { return initial1(x); } int add(int x, int y) { return x + y; } ;; this is also a wrapper, as its body is _+_(x,y) -() fake1(int a, int b, int c) impure asm(a b c) "DROP DROP DROP"; -() fake2(int a, int b, int c) impure asm(b c a) "DROP DROP DROP"; -() fake3(int a, int b, int c) impure asm(c a b) "DROP DROP DROP"; -() fake4(int a, int b, int c) impure asm(c b a) "DROP DROP DROP"; +() fake1(int a, int b, int c) asm(a b c) "DROP DROP DROP"; +() fake2(int a, int b, int c) asm(b c a) "DROP DROP DROP"; +() fake3(int a, int b, int c) asm(c a b) "DROP DROP DROP"; +() fake4(int a, int b, int c) asm(c b a) "DROP DROP DROP"; () fake1Wrapper(int a, int b, int c) { return fake1(a, b, c); } () fake2Wrapper(int a, int b, int c) { return fake2(a, b, c); } @@ -95,9 +95,9 @@ int add(int x, int y) { return x + y; } ;; this is also a wrapper, as its body i ;; skip 64 bits minv~skipBits(16); minv = minv.skipBits(16); - minv.skipBits(16000); ;; does nothing + minv.skipBits(11); ;; does nothing (minv, _) = ~skipBits(minv, 16); - skipBits(minv, 16000); ;; does nothing + skipBits(minv, 11); ;; does nothing minv~skipBits(16); ;; load 3*32 var minv1 = minv~loadUint(32); diff --git a/crypto/func/auto-tests/tests/camel2.fc b/crypto/func/auto-tests/tests/camel2.fc index 32c32e088..463597a63 100644 --- a/crypto/func/auto-tests/tests/camel2.fc +++ b/crypto/func/auto-tests/tests/camel2.fc @@ -7,10 +7,10 @@ #pragma compute-asm-ltr; -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -slice begin_parse(cell c) asm "CTOS"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +slice begin_parse(cell c) pure asm "CTOS"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; builder beginCell() { return begin_cell(); } cell endCell(builder b) { return end_cell(b); } @@ -19,13 +19,13 @@ builder storeRef2(cell c, builder b) { return store_ref(b, c); } builder storeUint1(builder b, int x, int bw) { return store_uint(b, x, bw); } builder storeUint2(builder b, int bw, int x) { return store_uint(b, x, bw); } -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) computeDataSize1(cell c, int maxCells) impure { return compute_data_size(c, maxCells); } -(int, int, int) computeDataSize2(int maxCells, cell c) impure { return compute_data_size(c, maxCells); } +(int, int, int) compute_data_size(cell c, int max_cells) pure asm "CDATASIZE"; +(int, int, int) computeDataSize1(cell c, int maxCells) { return compute_data_size(c, maxCells); } +(int, int, int) computeDataSize2(int maxCells, cell c) { return compute_data_size(c, maxCells); } -() throwIf(int condition, int excNo) impure { return throw_if(excNo, condition); } +() throwIf(int condition, int excNo) { return throw_if(excNo, condition); } -() fake(int a, int b, int c) impure asm "DROP DROP DROP"; +() fake(int a, int b, int c) asm "DROP DROP DROP"; () fake2(int b, int c, int a) { return fake(a,b,c); } () fake3(int c, int a, int b) { return fake(a,b,c); } () fake4(int c, int b, int a) { return fake(a,b,c); } diff --git a/crypto/func/auto-tests/tests/camel3.fc b/crypto/func/auto-tests/tests/camel3.fc index 4ae2fc413..2cccdf061 100644 --- a/crypto/func/auto-tests/tests/camel3.fc +++ b/crypto/func/auto-tests/tests/camel3.fc @@ -4,22 +4,22 @@ ;; (save to a variable, return from a function, etc.) ;; it also works, since a function becomes codegenerated (though direct calls are expectedly inlined). -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; builder beginCell() { return begin_cell(); } cell endCell(builder b) { return end_cell(b); } builder storeRef(builder b, cell c) { return store_ref(b, c); } builder storeUint3(int i, int bw, builder b) { return store_uint(b, i, bw); } -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; -(int, int, int) computeDataSize2(int maxCells, cell c) impure { return compute_data_size(c, maxCells); } +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; +(int, int, int) computeDataSize2(int maxCells, cell c) { return compute_data_size(c, maxCells); } -tuple empty_tuple() asm "NIL"; -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; -forall X -> X first(tuple t) asm "FIRST"; +tuple empty_tuple() pure asm "NIL"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> X first(tuple t) pure asm "FIRST"; tuple emptyTuple() { return empty_tuple(); } forall X -> tuple tuplePush(tuple t, X value) { return tpush(t, value); } diff --git a/crypto/func/auto-tests/tests/camel4.fc b/crypto/func/auto-tests/tests/camel4.fc index 1f014dc01..92ef37bda 100644 --- a/crypto/func/auto-tests/tests/camel4.fc +++ b/crypto/func/auto-tests/tests/camel4.fc @@ -1,22 +1,21 @@ ;; Here we test that a just-return function is not a valid wrapper, it will not be inlined. ;; (doesn't use all arguments, has different pureness, has method_id, etc.) -builder begin_cell() asm "NEWC"; -cell end_cell(builder b) asm "ENDC"; -slice begin_parse(cell c) asm "CTOS"; -() set_data(cell c) impure asm "c4 POP"; -cell get_data() asm "c4 PUSH"; -tuple empty_tuple() asm "NIL"; -forall X -> (tuple, ()) tpush(tuple t, X x) asm "TPUSH"; +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +slice begin_parse(cell c) pure asm "CTOS"; +() set_data(cell c) asm "c4 POP"; +cell get_data() pure asm "c4 PUSH"; +tuple empty_tuple() pure asm "NIL"; +forall X -> (tuple, ()) tpush(tuple t, X x) pure asm "TPUSH"; builder storeUint(builder b, int x, int unused) { return store_uint(b, x, x); } -() throwIf(int excNo, int cond) impure { throw_if(excNo, cond); } -() throwIf2(int excNo, int cond) { return throw_if(excNo, cond); } +() throwIf(int excNo, int cond) { throw_if(excNo, cond); } _ initial1(x) { return x; } _ initial2(x) { return initial1(x); } -tuple asm_func_4(int a, (int, (int, int)) b, int c) asm (b a c -> 0) "5 TUPLE"; +tuple asm_func_4(int a, (int, (int, int)) b, int c) pure asm (b a c -> 0) "5 TUPLE"; _ asmFunc4(int a, (int, (int, int)) b, int c) { return asm_func_4(a, b, c); } int postpone_elections() { @@ -28,7 +27,6 @@ int postpone_elections() { set_data(c); slice s = get_data().begin_parse(); throwIf(101, 0); - var unused = throwIf2(101, 0); return s~load_uint(8); } @@ -90,7 +88,6 @@ TESTCASE | -1 | 97 | 97 @fif_codegen DECLPROC storeUint @fif_codegen DECLPROC throwIf -@fif_codegen DECLPROC throwIf2 @fif_codegen DECLPROC postpone_elections @fif_codegen 74435 DECLMETHOD test2 diff --git a/crypto/func/auto-tests/tests/co1.fc b/crypto/func/auto-tests/tests/co1.fc index a89d5922f..b6fbd77c1 100644 --- a/crypto/func/auto-tests/tests/co1.fc +++ b/crypto/func/auto-tests/tests/co1.fc @@ -28,14 +28,14 @@ const int int240 = ((int1 + int2) * 10) << 3; int iget240() { return int240; } -builder newc() asm "NEWC"; -slice endcs(builder b) asm "ENDC" "CTOS"; -int sdeq (slice s1, slice s2) asm "SDEQ"; -builder stslicer(builder b, slice s) asm "STSLICER"; +builder newc() pure asm "NEWC"; +slice endcs(builder b) pure asm "ENDC" "CTOS"; +int sdeq (slice s1, slice s2) pure asm "SDEQ"; +builder stslicer(builder b, slice s) pure asm "STSLICER"; builder storeUint(builder b, int x, int len) { return store_uint(b, x, len); } _ endSlice(builder b) { return endcs(b); } -() throwUnless(int excno, int cond) impure { return throw_unless(excno, cond); } +() throwUnless(int excno, int cond) { return throw_unless(excno, cond); } _ main() { int i1 = iget1(); diff --git a/crypto/func/auto-tests/tests/inline_loops.fc b/crypto/func/auto-tests/tests/inline_loops.fc index 9f1f45fc9..b58d4274c 100644 --- a/crypto/func/auto-tests/tests/inline_loops.fc +++ b/crypto/func/auto-tests/tests/inline_loops.fc @@ -1,13 +1,13 @@ global int g; -_ foo_repeat() impure inline { +_ foo_repeat() inline { g = 1; repeat(5) { g *= 2; } } -int foo_until() impure inline { +int foo_until() inline { g = 1; int i = 0; do { @@ -17,7 +17,7 @@ int foo_until() impure inline { return i; } -int foo_while() impure inline { +int foo_while() inline { g = 1; int i = 0; while (i < 10) { diff --git a/crypto/func/auto-tests/tests/s1.fc b/crypto/func/auto-tests/tests/s1.fc index 97b19f166..ef9977070 100644 --- a/crypto/func/auto-tests/tests/s1.fc +++ b/crypto/func/auto-tests/tests/s1.fc @@ -26,9 +26,9 @@ int string_crc32() method_id { return "transfer(slice, int)"c; } -builder newc() asm "NEWC"; +builder newc() pure asm "NEWC"; slice endcs(builder b) asm "ENDC" "CTOS"; -int sdeq (slice s1, slice s2) asm "SDEQ"; +int sdeq (slice s1, slice s2) pure asm "SDEQ"; _ main() { slice s_ascii = ascii_slice(); diff --git a/crypto/func/auto-tests/tests/test-math.fc b/crypto/func/auto-tests/tests/test-math.fc index 5bba3370b..27fea3612 100644 --- a/crypto/func/auto-tests/tests/test-math.fc +++ b/crypto/func/auto-tests/tests/test-math.fc @@ -1,6 +1,6 @@ #include "../../../smartcont/mathlib.fc"; -forall X -> (tuple, ()) ~tset(tuple t, int idx, X val) asm(t val idx) "SETINDEXVAR"; +forall X -> (tuple, ()) ~tset(tuple t, int idx, X val) pure asm(t val idx) "SETINDEXVAR"; ;; computes 1-acos(x)/Pi by a very simple, extremely slow (~70k gas) and imprecise method ;; fixed256 acos_prepare_slow(fixed255 x); diff --git a/crypto/func/builtins.cpp b/crypto/func/builtins.cpp index d86ab7ecd..a0d6d951f 100644 --- a/crypto/func/builtins.cpp +++ b/crypto/func/builtins.cpp @@ -50,7 +50,7 @@ SymDef* predefine_builtin_func(std::string name, TypeExpr* func_type) { template SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const T& func, bool impure = false) { SymDef* def = predefine_builtin_func(name, func_type); - def->value = new SymValAsmFunc{func_type, func, impure}; + def->value = new SymValAsmFunc{func_type, func, !impure}; #ifdef FUNC_DEBUG dynamic_cast(def->value)->name = name; #endif @@ -61,7 +61,7 @@ template SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const T& func, std::initializer_list arg_order, std::initializer_list ret_order = {}, bool impure = false) { SymDef* def = predefine_builtin_func(name, func_type); - def->value = new SymValAsmFunc{func_type, func, arg_order, ret_order, impure}; + def->value = new SymValAsmFunc{func_type, func, arg_order, ret_order, !impure}; #ifdef FUNC_DEBUG dynamic_cast(def->value)->name = name; #endif @@ -72,7 +72,7 @@ SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const AsmOp& std::initializer_list arg_order, std::initializer_list ret_order = {}, bool impure = false) { SymDef* def = predefine_builtin_func(name, func_type); - def->value = new SymValAsmFunc{func_type, make_simple_compile(macro), arg_order, ret_order, impure}; + def->value = new SymValAsmFunc{func_type, make_simple_compile(macro), arg_order, ret_order, !impure}; #ifdef FUNC_DEBUG dynamic_cast(def->value)->name = name; #endif diff --git a/crypto/func/func.h b/crypto/func/func.h index e968978c2..ca844947f 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -108,6 +108,7 @@ enum Keyword { _Forall, _Asm, _Impure, + _Pure, _Global, _Extern, _Inline, @@ -754,10 +755,9 @@ struct CodeBlob { struct SymVal : sym::SymValBase { TypeExpr* sym_type; - bool impure; bool auto_apply{false}; - SymVal(int _type, int _idx, TypeExpr* _stype = nullptr, bool _impure = false) - : sym::SymValBase(_type, _idx), sym_type(_stype), impure(_impure) { + SymVal(int _type, int _idx, TypeExpr* _stype = nullptr) + : sym::SymValBase(_type, _idx), sym_type(_stype) { } ~SymVal() override = default; TypeExpr* get_type() const { @@ -771,6 +771,7 @@ struct SymValFunc : SymVal { flagInlineRef = 2, // function marked `inline_ref` flagWrapsAnotherF = 4, // (T) thisF(...args) { return anotherF(...args); } (calls to thisF will be replaced) flagUsedAsNonCall = 8, // used not only as `f()`, but as a 1-st class function (assigned to var, pushed to tuple, etc.) + flagMarkedAsPure = 16, // declared as `pure`, can't call impure and access globals, unused invocations are optimized out }; td::RefInt256 method_id; // todo why int256? it's small @@ -780,11 +781,10 @@ struct SymValFunc : SymVal { std::string name; // seeing function name in debugger makes it much easier to delve into FunC sources #endif ~SymValFunc() override = default; - SymValFunc(int val, TypeExpr* _ft, bool _impure = false) : SymVal(_Func, val, _ft, _impure) { - } - SymValFunc(int val, TypeExpr* _ft, std::initializer_list _arg_order, std::initializer_list _ret_order = {}, - bool _impure = false) - : SymVal(_Func, val, _ft, _impure), arg_order(_arg_order), ret_order(_ret_order) { + SymValFunc(int val, TypeExpr* _ft, bool marked_as_pure) + : SymVal(_Func, val, _ft), flags(marked_as_pure ? flagMarkedAsPure : 0) {} + SymValFunc(int val, TypeExpr* _ft, std::initializer_list _arg_order, std::initializer_list _ret_order, bool marked_as_pure) + : SymVal(_Func, val, _ft), flags(marked_as_pure ? flagMarkedAsPure : 0), arg_order(_arg_order), ret_order(_ret_order) { } const std::vector* get_arg_order() const { @@ -804,12 +804,15 @@ struct SymValFunc : SymVal { bool is_just_wrapper_for_another_f() const { return flags & flagWrapsAnotherF; } + bool is_marked_as_pure() const { + return flags & flagMarkedAsPure; + } }; struct SymValCodeFunc : SymValFunc { CodeBlob* code; ~SymValCodeFunc() override = default; - SymValCodeFunc(int val, TypeExpr* _ft, bool _impure = false) : SymValFunc(val, _ft, _impure), code(nullptr) { + SymValCodeFunc(int val, TypeExpr* _ft, bool marked_as_pure) : SymValFunc(val, _ft, marked_as_pure), code(nullptr) { } bool does_need_codegen() const; }; @@ -1716,25 +1719,25 @@ struct SymValAsmFunc : SymValFunc { compile_func_t ext_compile; td::uint64 crc; ~SymValAsmFunc() override = default; - SymValAsmFunc(TypeExpr* ft, const AsmOp& _macro, bool impure = false) - : SymValFunc(-1, ft, impure), simple_compile(make_simple_compile(_macro)) { + SymValAsmFunc(TypeExpr* ft, const AsmOp& _macro, bool marked_as_pure) + : SymValFunc(-1, ft, marked_as_pure), simple_compile(make_simple_compile(_macro)) { } - SymValAsmFunc(TypeExpr* ft, std::vector _macro, bool impure = false) - : SymValFunc(-1, ft, impure), ext_compile(make_ext_compile(std::move(_macro))) { + SymValAsmFunc(TypeExpr* ft, std::vector _macro, bool marked_as_pure) + : SymValFunc(-1, ft, marked_as_pure), ext_compile(make_ext_compile(std::move(_macro))) { } - SymValAsmFunc(TypeExpr* ft, simple_compile_func_t _compile, bool impure = false) - : SymValFunc(-1, ft, impure), simple_compile(std::move(_compile)) { + SymValAsmFunc(TypeExpr* ft, simple_compile_func_t _compile, bool marked_as_pure) + : SymValFunc(-1, ft, marked_as_pure), simple_compile(std::move(_compile)) { } - SymValAsmFunc(TypeExpr* ft, compile_func_t _compile, bool impure = false) - : SymValFunc(-1, ft, impure), ext_compile(std::move(_compile)) { + SymValAsmFunc(TypeExpr* ft, compile_func_t _compile, bool marked_as_pure) + : SymValFunc(-1, ft, marked_as_pure), ext_compile(std::move(_compile)) { } SymValAsmFunc(TypeExpr* ft, simple_compile_func_t _compile, std::initializer_list arg_order, - std::initializer_list ret_order = {}, bool impure = false) - : SymValFunc(-1, ft, arg_order, ret_order, impure), simple_compile(std::move(_compile)) { + std::initializer_list ret_order = {}, bool marked_as_pure = false) + : SymValFunc(-1, ft, arg_order, ret_order, marked_as_pure), simple_compile(std::move(_compile)) { } SymValAsmFunc(TypeExpr* ft, compile_func_t _compile, std::initializer_list arg_order, - std::initializer_list ret_order = {}, bool impure = false) - : SymValFunc(-1, ft, arg_order, ret_order, impure), ext_compile(std::move(_compile)) { + std::initializer_list ret_order = {}, bool marked_as_pure = false) + : SymValFunc(-1, ft, arg_order, ret_order, marked_as_pure), ext_compile(std::move(_compile)) { } bool compile(AsmOpList& dest, std::vector& out, std::vector& in, const SrcLocation& where) const; }; diff --git a/crypto/func/keywords.cpp b/crypto/func/keywords.cpp index fedce9db2..0248a65ac 100644 --- a/crypto/func/keywords.cpp +++ b/crypto/func/keywords.cpp @@ -120,6 +120,7 @@ void define_keywords() { .add_keyword("global", Kw::_Global) .add_keyword("asm", Kw::_Asm) .add_keyword("impure", Kw::_Impure) + .add_keyword("pure", Kw::_Pure) .add_keyword("inline", Kw::_Inline) .add_keyword("inline_ref", Kw::_InlineRef) .add_keyword("auto_apply", Kw::_AutoApply) diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index 6e11b54ca..bc298caa9 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -385,8 +385,8 @@ void parse_global_var_decls(Lexer& lex) { lex.expect(';'); } -SymValCodeFunc* make_new_glob_func(SymDef* func_sym, TypeExpr* func_type, bool impure = false) { - SymValCodeFunc* res = new SymValCodeFunc{glob_func_cnt, func_type, impure}; +SymValCodeFunc* make_new_glob_func(SymDef* func_sym, TypeExpr* func_type, bool marked_as_pure) { + SymValCodeFunc* res = new SymValCodeFunc{glob_func_cnt, func_type, marked_as_pure}; #ifdef FUNC_DEBUG res->name = func_sym->name(); #endif @@ -649,6 +649,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { } res->sym = sym; SymVal* val = nullptr; + bool impure = false; if (sym) { val = dynamic_cast(sym->value); } @@ -658,6 +659,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { res->e_type = val->get_type(); res->cls = Expr::_GlobFunc; auto_apply = val->auto_apply; + impure = !dynamic_cast(val)->is_marked_as_pure(); } else if (val->idx < 0) { lex.cur().error_at("accessing variable `", "` being defined"); } else { @@ -666,7 +668,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { // std::cerr << "accessing variable " << lex.cur().str << " : " << res->e_type << std::endl; } // std::cerr << "accessing symbol " << lex.cur().str << " : " << res->e_type << (val->impure ? " (impure)" : " (pure)") << std::endl; - res->flags = Expr::_IsLvalue | Expr::_IsRvalue | (val->impure ? Expr::_IsImpure : 0); + res->flags = Expr::_IsLvalue | Expr::_IsRvalue | (impure ? Expr::_IsImpure : 0); } if (auto_apply) { int impure = res->flags & Expr::_IsImpure; @@ -757,7 +759,7 @@ Expr* parse_expr80(Lexer& lex, CodeBlob& code, bool nv) { res = new Expr{Expr::_Apply, name, {obj, x}}; } res->here = loc; - res->flags = Expr::_IsRvalue | (val->impure ? Expr::_IsImpure : 0); + res->flags = Expr::_IsRvalue | (val->is_marked_as_pure() ? 0 : Expr::_IsImpure); res->deduce_type(lex.cur()); if (modify) { auto tmp = res; @@ -1242,7 +1244,7 @@ CodeBlob* parse_func_body(Lexer& lex, FormalArgList arg_list, TypeExpr* ret_type } SymValAsmFunc* parse_asm_func_body(Lexer& lex, TypeExpr* func_type, const FormalArgList& arg_list, TypeExpr* ret_type, - bool impure = false) { + bool marked_as_pure) { auto loc = lex.cur().loc; lex.expect(_Asm); int cnt = (int)arg_list.size(); @@ -1346,14 +1348,14 @@ SymValAsmFunc* parse_asm_func_body(Lexer& lex, TypeExpr* func_type, const Formal for (const AsmOp& asm_op : asm_ops) { crc_s += asm_op.op; } - crc_s.push_back(impure); + crc_s.push_back(!marked_as_pure); for (const int& x : arg_order) { crc_s += std::string((const char*) (&x), (const char*) (&x + 1)); } for (const int& x : ret_order) { crc_s += std::string((const char*) (&x), (const char*) (&x + 1)); } - auto res = new SymValAsmFunc{func_type, asm_ops, impure}; + auto res = new SymValAsmFunc{func_type, asm_ops, marked_as_pure}; res->arg_order = std::move(arg_order); res->ret_order = std::move(ret_order); res->crc = td::crc64(crc_s); @@ -1487,9 +1489,8 @@ void detect_if_function_just_wraps_another(SymValCodeFunc* v_current, const td:: // 'return true;' (false, nil) are (surprisingly) also function calls, with auto_apply=true if (v_called->auto_apply) return; - - // they must have the same pureness - if (v_called->impure != v_current->impure || v_current->is_inline_ref()) + // if an original is marked `pure`, and this one doesn't, it's okay; just check for inline_ref storage + if (v_current->is_inline_ref()) return; // ok, f_current is a wrapper @@ -1513,8 +1514,16 @@ void parse_func_def(Lexer& lex) { Lexem func_name = lex.cur(); lex.next(); FormalArgList arg_list = parse_formal_args(lex); - bool impure = (lex.tp() == _Impure); - if (impure) { + bool marked_as_pure = false; + if (lex.tp() == _Impure) { + static bool warning_shown = false; + if (!warning_shown) { + lex.cur().loc.show_warning("`impure` specifier is deprecated. All functions are impure by default, use `pure` to mark a function as pure"); + warning_shown = true; + } + lex.next(); + } else if (lex.tp() == _Pure) { + marked_as_pure = true; lex.next(); } int flags_inline = 0; @@ -1577,7 +1586,7 @@ void parse_func_def(Lexer& lex) { } } if (lex.tp() == ';') { - make_new_glob_func(func_sym, func_type, impure); + make_new_glob_func(func_sym, func_type, marked_as_pure); lex.next(); } else if (lex.tp() == '{') { if (dynamic_cast(func_sym_val)) { @@ -1590,7 +1599,7 @@ void parse_func_def(Lexer& lex) { lex.cur().error("function `"s + func_name.str + "` has been already defined in an yet-unknown way"); } } else { - func_sym_code = make_new_glob_func(func_sym, func_type, impure); + func_sym_code = make_new_glob_func(func_sym, func_type, marked_as_pure); } if (func_sym_code->code) { lex.cur().error("redefinition of function `"s + func_name.str + "`"); @@ -1603,7 +1612,7 @@ void parse_func_def(Lexer& lex) { detect_if_function_just_wraps_another(func_sym_code, method_id); } else { Lexem asm_lexem = lex.cur(); - SymValAsmFunc* asm_func = parse_asm_func_body(lex, func_type, arg_list, ret_type, impure); + SymValAsmFunc* asm_func = parse_asm_func_body(lex, func_type, arg_list, ret_type, marked_as_pure); #ifdef FUNC_DEBUG asm_func->name = func_name.str; #endif diff --git a/crypto/func/test/b1.fc b/crypto/func/test/b1.fc index ce522934c..420ac6ead 100644 --- a/crypto/func/test/b1.fc +++ b/crypto/func/test/b1.fc @@ -1,4 +1,4 @@ -int now() asm "NOW"; +int now() pure asm "NOW"; int cell_hash(cell c) asm "HASHCU"; @@ -9,36 +9,36 @@ asm "HASHSU"; int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -;; () throw_if(int excno, int cond) impure +;; () throw_if(int excno, int cond) ;; asm "THROWARGIF"; -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -() accept_message() impure asm "ACCEPT"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(cell, slice) load_ref(slice s) asm "LDREF"; -(int, slice) zload_int(slice s, int len) asm "LDIX"; -(int, slice) zload_uint(slice s, int len) asm "LDUX"; -int zpreload_int(slice s, int len) asm "PLDIX"; -int zpreload_uint(slice s, int len) asm "PLDUX"; -(slice, slice) load_bits(slice s, int len) asm "LDSLICEX"; -slice preload_bits(slice s, int len) asm "PLDSLICEX"; -cell set_idict_ref(cell value, int index, cell dict, int key_len) asm "DICTISETREF"; -builder begin_cell() asm "NEWC"; -builder store_ref(cell c, builder b) asm "STREF"; -builder zstore_uint(int x, builder b, int len) asm "STUX"; -builder zstore_int(int x, builder b, int len) asm "STIX"; -cell end_cell(builder b) asm "ENDC"; +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +() accept_message() asm "ACCEPT"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(cell, slice) load_ref(slice s) pure asm "LDREF"; +(int, slice) zload_int(slice s, int len) pure asm "LDIX"; +(int, slice) zload_uint(slice s, int len) pure asm "LDUX"; +int zpreload_int(slice s, int len) pure asm "PLDIX"; +int zpreload_uint(slice s, int len) pure asm "PLDUX"; +(slice, slice) load_bits(slice s, int len) pure asm "LDSLICEX"; +slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +cell set_idict_ref(cell value, int index, cell dict, int key_len) pure asm "DICTISETREF"; +builder begin_cell() pure asm "NEWC"; +builder store_ref(cell c, builder b) pure asm "STREF"; +builder zstore_uint(int x, builder b, int len) pure asm "STUX"; +builder zstore_int(int x, builder b, int len) pure asm "STIX"; +cell end_cell(builder b) pure asm "ENDC"; ;; Simple configuration smart contract -() recv_internal(cell in_msg) impure { +() recv_internal(cell in_msg) { ;; do nothing for internal messages } -() recv_external(cell in_msg) impure { +() recv_external(cell in_msg) { var (signature, cs0) = load_bits(begin_parse(in_msg), 512); var (msg_seqno, cs) = zload_uint(cs0, 32); (var valid_until, cs) = zload_uint(cs, 32); diff --git a/crypto/func/test/b2.fc b/crypto/func/test/b2.fc index 90322ae01..c889db03e 100644 --- a/crypto/func/test/b2.fc +++ b/crypto/func/test/b2.fc @@ -1,4 +1,4 @@ -int now() asm "NOW"; +int now() pure asm "NOW"; int cell_hash(cell c) asm "HASHCU"; @@ -9,36 +9,36 @@ asm "HASHSU"; int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -;; () throw_if(int excno, int cond) impure +;; () throw_if(int excno, int cond) ;; asm "THROWARGIF"; -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -() accept_message() impure asm "ACCEPT"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -;; (slice, int) load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -(slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -slice preload_bits(slice s, int len) asm "PLDSLICEX"; -cell set_idict_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -builder begin_cell() asm "NEWC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -cell end_cell(builder b) asm "ENDC"; +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +() accept_message() asm "ACCEPT"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +;; (slice, int) load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; +(slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +cell set_idict_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +builder begin_cell() pure asm "NEWC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +cell end_cell(builder b) pure asm "ENDC"; ;; Simple configuration smart contract -() recv_internal(cell in_msg) impure { +() recv_internal(cell in_msg) { ;; do nothing for internal messages } -() recv_external(cell in_msg) impure { +() recv_external(cell in_msg) { var (cs0, signature) = load_bits(begin_parse(in_msg), 512); var (cs, msg_seqno) = load_uint(cs0, 32); (cs, var valid_until) = load_uint(cs, 32); diff --git a/crypto/func/test/b2_0.fc b/crypto/func/test/b2_0.fc index c2783f86f..a6337871f 100644 --- a/crypto/func/test/b2_0.fc +++ b/crypto/func/test/b2_0.fc @@ -1,4 +1,4 @@ -int now() asm "NOW"; +int now() pure asm "NOW"; int cell_hash(cell c) asm "HASHCU"; @@ -9,36 +9,36 @@ asm "HASHSU"; int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -;; () throw_if(int excno, int cond) impure +;; () throw_if(int excno, int cond) ;; asm "THROWARGIF"; -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -() accept_message() impure asm "ACCEPT"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -(slice, int) zload_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -(slice, int) zload_uint(slice s, int len) asm( -> 1 0) "LDUX"; -int zpreload_int(slice s, int len) asm "PLDIX"; -int zpreload_uint(slice s, int len) asm "PLDUX"; -(slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -slice preload_bits(slice s, int len) asm "PLDSLICEX"; -cell set_idict_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -builder begin_cell() asm "NEWC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -builder zstore_uint(builder b, int x, int len) asm(x b len) "STUX"; -builder zstore_int(builder b, int x, int len) asm(x b len) "STIX"; -cell end_cell(builder b) asm "ENDC"; +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +() accept_message() asm "ACCEPT"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +(slice, int) zload_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +(slice, int) zload_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +int zpreload_int(slice s, int len) pure asm "PLDIX"; +int zpreload_uint(slice s, int len) pure asm "PLDUX"; +(slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +cell set_idict_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +builder begin_cell() pure asm "NEWC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +builder zstore_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +builder zstore_int(builder b, int x, int len) pure asm(x b len) "STIX"; +cell end_cell(builder b) pure asm "ENDC"; ;; Simple configuration smart contract -() recv_internal(cell in_msg) impure { +() recv_internal(cell in_msg) { ;; do nothing for internal messages } -() recv_external(cell in_msg) impure { +() recv_external(cell in_msg) { var (cs0, signature) = load_bits(begin_parse(in_msg), 512); var (cs, msg_seqno) = zload_uint(cs0, 32); (cs, var valid_until) = zload_uint(cs, 32); diff --git a/crypto/func/test/b2_1.fc b/crypto/func/test/b2_1.fc index 1ff79d05b..dfa4e6ea5 100644 --- a/crypto/func/test/b2_1.fc +++ b/crypto/func/test/b2_1.fc @@ -1,4 +1,4 @@ -int now() asm "NOW"; +int now() pure asm "NOW"; int cell_hash(cell c) asm "HASHCU"; @@ -9,37 +9,37 @@ asm "HASHSU"; int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -;; () throw_if(int excno, int cond) impure +;; () throw_if(int excno, int cond) ;; asm "THROWARGIF"; -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -() accept_message() impure asm "ACCEPT"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) asm "PLDIX"; -;; int preload_uint(slice s, int len) asm "PLDUX"; -(slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -slice preload_bits(slice s, int len) asm "PLDSLICEX"; -cell set_idict_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~set_idict_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -builder begin_cell() asm "NEWC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; -cell end_cell(builder b) asm "ENDC"; +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +() accept_message() asm "ACCEPT"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int preload_int(slice s, int len) pure asm "PLDIX"; +;; int preload_uint(slice s, int len) pure asm "PLDUX"; +(slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +cell set_idict_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~set_idict_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +builder begin_cell() pure asm "NEWC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +cell end_cell(builder b) pure asm "ENDC"; ;; Simple configuration smart contract -() recv_internal(cell in_msg) impure { +() recv_internal(cell in_msg) { ;; do nothing for internal messages } -() recv_external(cell in_msg) impure { +() recv_external(cell in_msg) { var cs = begin_parse(in_msg); var signature = cs~load_bits(512); var cs0 = cs; diff --git a/crypto/func/test/b2_2.fc b/crypto/func/test/b2_2.fc index d137ff687..62328f681 100644 --- a/crypto/func/test/b2_2.fc +++ b/crypto/func/test/b2_2.fc @@ -1,4 +1,4 @@ -int now() asm "NOW"; +int now() pure asm "NOW"; int cell_hash(cell c) asm "HASHCU"; @@ -9,36 +9,36 @@ asm "HASHSU"; int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; -;; () throw_if(int excno, int cond) impure +;; () throw_if(int excno, int cond) ;; asm "THROWARGIF"; -cell get_data() asm "c4 PUSH"; -() set_data(cell c) impure asm "c4 POP"; -() accept_message() impure asm "ACCEPT"; - -slice begin_parse(cell c) asm "CTOS"; -() end_parse(slice s) impure asm "ENDS"; -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; -;; (slice, int) load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; -;; (slice, int) load_uint(slice s, int len) asm( -> 1 0) "LDUX"; -;; int .preload_int(slice s, int len) asm "PLDIX"; -;; int .preload_uint(slice s, int len) asm "PLDUX"; -(slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; -;; slice .preload_bits(slice s, int len) asm "PLDSLICEX"; -cell set_idict_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -builder begin_cell() asm "NEWC"; -builder store_ref(builder b, cell c) asm(c b) "STREF"; -;;builder .store_uint(builder b, int x, int len) asm(x b len) "STUX"; -;;builder .store_int(builder b, int x, int len) asm(x b len) "STIX"; -cell .end_cell(builder b) asm "ENDC"; +cell get_data() pure asm "c4 PUSH"; +() set_data(cell c) asm "c4 POP"; +() accept_message() asm "ACCEPT"; + +slice begin_parse(cell c) pure asm "CTOS"; +() end_parse(slice s) asm "ENDS"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; +;; (slice, int) load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +;; (slice, int) load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +;; int .preload_int(slice s, int len) pure asm "PLDIX"; +;; int .preload_uint(slice s, int len) pure asm "PLDUX"; +(slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +;; slice .preload_bits(slice s, int len) pure asm "PLDSLICEX"; +cell set_idict_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +builder begin_cell() pure asm "NEWC"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +;;builder .store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; +;;builder .store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +cell .end_cell(builder b) pure asm "ENDC"; ;; Simple configuration smart contract -() recv_internal(cell in_msg) impure { +() recv_internal(cell in_msg) { ;; do nothing for internal messages } -() recv_external(cell in_msg) impure { +() recv_external(cell in_msg) { var (cs0, signature) = load_bits(begin_parse(in_msg), 512); var (cs, msg_seqno) = load_uint(cs0, 32); (cs, var valid_until) = load_uint(cs, 32); diff --git a/crypto/func/test/b3.fc b/crypto/func/test/b3.fc index 0e1e40347..ba3aa7680 100644 --- a/crypto/func/test/b3.fc +++ b/crypto/func/test/b3.fc @@ -5,7 +5,7 @@ _ unpack() inline { return res; } -() pack(a, x, y) impure inline_ref { +() pack(a, x, y) inline_ref { set_data(begin_cell() .store_uint(a, 8) .store_int(x, 32) @@ -13,7 +13,7 @@ _ unpack() inline { .end_cell()); } -() main() impure { +() main() { var (a, x, y) = unpack(); x += y; pack(a, x, y); diff --git a/crypto/func/test/c1.fc b/crypto/func/test/c1.fc index 1a07baca1..eb844f6fd 100644 --- a/crypto/func/test/c1.fc +++ b/crypto/func/test/c1.fc @@ -11,12 +11,12 @@ _ pre_next() { return x + 1; } -() init() impure { +() init() { ;; global x; x = 0; } -int next() impure { +int next() { ;; global x; return x += 1; } @@ -25,7 +25,7 @@ _ set_y(x, w) { y = (w, x); } -_ get_y() impure { +_ get_y() { return y; } diff --git a/crypto/func/test/i1.fc b/crypto/func/test/i1.fc index 04f7889e0..9544e099e 100644 --- a/crypto/func/test/i1.fc +++ b/crypto/func/test/i1.fc @@ -2,15 +2,15 @@ global int i; #include "i1sub1.fc"; -() sub0() impure { i = 0; } +() sub0() { i = 0; } #include "i1sub2.fc"; -() main() impure { +() main() { sub0(); sub1(); sub2(); i = 9; } -#include "../test/i1sub2.fc"; \ No newline at end of file +#include "../test/i1sub2.fc"; diff --git a/crypto/func/test/i1sub1.fc b/crypto/func/test/i1sub1.fc index 62bdd177c..ba90a80fd 100644 --- a/crypto/func/test/i1sub1.fc +++ b/crypto/func/test/i1sub1.fc @@ -3,6 +3,6 @@ #include "i1sub1.fc"; -() sub1() impure { +() sub1() { i = 1; } diff --git a/crypto/func/test/i1sub2.fc b/crypto/func/test/i1sub2.fc index 0c48e192a..b79da1cf1 100644 --- a/crypto/func/test/i1sub2.fc +++ b/crypto/func/test/i1sub2.fc @@ -3,7 +3,7 @@ #include "./i1sub1.fc"; -() sub2() impure { +() sub2() { sub1(); sub0(); i = 2; diff --git a/crypto/func/test/tc1.fc b/crypto/func/test/tc1.fc index 245fc521e..985c50d96 100644 --- a/crypto/func/test/tc1.fc +++ b/crypto/func/test/tc1.fc @@ -1,4 +1,4 @@ -() test1() impure { +() test1() { int i = 3; repeat (3) { try { @@ -22,7 +22,7 @@ int divide_by_ten(int num) { return 0; } -() test2() impure { +() test2() { int n = divide_by_ten(37); throw_unless(502, n == 3); } @@ -39,7 +39,7 @@ int divide_by_ten(int num) { return (0, a); } -() test3() impure { +() test3() { int a = 0; int b = 57; try { @@ -68,7 +68,7 @@ int get_y(int x, int y) { return y; } -() test4() impure { +() test4() { throw_unless(504, get_x(3, 4) == 3); throw_unless(504, get_y(3, 4) == -1); } @@ -86,12 +86,12 @@ int get_y(int x, int y) { return (a, b, c, d, e); } -() test5() impure { +() test5() { var (a, b, c, d, e) = foo(10, 20, 30, 40, 50); throw_unless(505, (a == 11) & (b == 22) & (c == 33) & (d == 44) & (e == 55)); } -() test6() impure { +() test6() { int a = 0; int b = 0; int c = 0; diff --git a/crypto/func/test/tc2.fc b/crypto/func/test/tc2.fc index 2bde68131..00a577697 100644 --- a/crypto/func/test/tc2.fc +++ b/crypto/func/test/tc2.fc @@ -14,7 +14,7 @@ _ test1_body() { return (0, null()); } -() test1() impure { +() test1() { var (x, y) = test1_body(); throw_unless(101, x == 104); throw_unless(102, y.builder_refs() == y.builder_bits()); @@ -67,7 +67,7 @@ _ test2_body(int a, int b, int c) { return null(); } -() test2() impure { +() test2() { throw_unless(201, test2_body(0, 4, 0) == 1); throw_unless(202, test2_body(0, 5, 0) == 2); throw_unless(203, test2_body(3, 4, 0) == 3); diff --git a/crypto/func/test/w3.fc b/crypto/func/test/w3.fc index 0de8e551f..133918826 100644 --- a/crypto/func/test/w3.fc +++ b/crypto/func/test/w3.fc @@ -1,4 +1,4 @@ -() main(cs) impure { +() main(cs) { int i = 0; if (cs.slice_refs()) { do { diff --git a/crypto/func/test/w5.fc b/crypto/func/test/w5.fc index 330a50504..61136c54c 100644 --- a/crypto/func/test/w5.fc +++ b/crypto/func/test/w5.fc @@ -1,4 +1,4 @@ -(cell) recv_external(slice in_msg) impure { +(cell) recv_external(slice in_msg) { cell mydict = new_dict(); builder r = begin_cell().store_int(10, 16); mydict~udict_set_builder(32, 1, r ); @@ -9,6 +9,6 @@ return mydict; } -() recv_internal() impure { +() recv_internal() { ;; Nothing } diff --git a/crypto/func/test/w8.fc b/crypto/func/test/w8.fc index bd0696e73..c236b1f12 100644 --- a/crypto/func/test/w8.fc +++ b/crypto/func/test/w8.fc @@ -1,4 +1,4 @@ -int check_signatures(msg_hash, signatures, signers, bitmask_size) impure { +int check_signatures(msg_hash, signatures, signers, bitmask_size) { var bitmask = 0; var id = -1; do { diff --git a/crypto/smartcont/stdlib.fc b/crypto/smartcont/stdlib.fc index 57ae7c6bf..9540603a0 100644 --- a/crypto/smartcont/stdlib.fc +++ b/crypto/smartcont/stdlib.fc @@ -35,122 +35,122 @@ */ /// Adds an element to the beginning of lisp-style list. -forall X -> tuple cons(X head, tuple tail) asm "CONS"; +forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; /// Extracts the head and the tail of lisp-style list. -forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; +forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; /// Extracts the tail and the head of lisp-style list. -forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; +forall X -> (tuple, X) list_next(tuple list) pure asm( -> 1 0) "UNCONS"; /// Returns the head of lisp-style list. -forall X -> X car(tuple list) asm "CAR"; +forall X -> X car(tuple list) pure asm "CAR"; /// Returns the tail of lisp-style list. -tuple cdr(tuple list) asm "CDR"; +tuple cdr(tuple list) pure asm "CDR"; /// Creates tuple with zero elements. -tuple empty_tuple() asm "NIL"; +tuple empty_tuple() pure asm "NIL"; /// Appends a value `x` to a `Tuple t = (x1, ..., xn)`, but only if the resulting `Tuple t' = (x1, ..., xn, x)` /// is of length at most 255. Otherwise throws a type check exception. -forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; -forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; +forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH"; /// Creates a tuple of length one with given argument as element. -forall X -> [X] single(X x) asm "SINGLE"; +forall X -> [X] single(X x) pure asm "SINGLE"; /// Unpacks a tuple of length one -forall X -> X unsingle([X] t) asm "UNSINGLE"; +forall X -> X unsingle([X] t) pure asm "UNSINGLE"; /// Creates a tuple of length two with given arguments as elements. -forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; +forall X, Y -> [X, Y] pair(X x, Y y) pure asm "PAIR"; /// Unpacks a tuple of length two -forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; +forall X, Y -> (X, Y) unpair([X, Y] t) pure asm "UNPAIR"; /// Creates a tuple of length three with given arguments as elements. -forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) pure asm "TRIPLE"; /// Unpacks a tuple of length three -forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) pure asm "UNTRIPLE"; /// Creates a tuple of length four with given arguments as elements. -forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) pure asm "4 TUPLE"; /// Unpacks a tuple of length four -forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) pure asm "4 UNTUPLE"; /// Returns the first element of a tuple (with unknown element types). -forall X -> X first(tuple t) asm "FIRST"; +forall X -> X first(tuple t) pure asm "FIRST"; /// Returns the second element of a tuple (with unknown element types). -forall X -> X second(tuple t) asm "SECOND"; +forall X -> X second(tuple t) pure asm "SECOND"; /// Returns the third element of a tuple (with unknown element types). -forall X -> X third(tuple t) asm "THIRD"; +forall X -> X third(tuple t) pure asm "THIRD"; /// Returns the fourth element of a tuple (with unknown element types). -forall X -> X fourth(tuple t) asm "3 INDEX"; +forall X -> X fourth(tuple t) pure asm "3 INDEX"; /// Returns the first element of a pair tuple. -forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; +forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; /// Returns the second element of a pair tuple. -forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; +forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; /// Returns the first element of a triple tuple. -forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; +forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; /// Returns the second element of a triple tuple. -forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; +forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; /// Returns the third element of a triple tuple. -forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; +forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; /// Push null element (casted to given type) /// By the TVM type `Null` FunC represents absence of a value of some atomic type. /// So `null` can actually have any atomic type. -forall X -> X null() asm "PUSHNULL"; +forall X -> X null() pure asm "PUSHNULL"; /// Moves a variable [x] to the top of the stack -forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; +forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; /// Returns the current Unix time as an Integer -int now() asm "NOW"; +int now() pure asm "NOW"; /// Returns the internal address of the current smart contract as a Slice with a `MsgAddressInt`. /// If necessary, it can be parsed further using primitives such as [parse_std_addr]. -slice my_address() asm "MYADDR"; +slice my_address() pure asm "MYADDR"; /// Returns the balance of the smart contract as a tuple consisting of an int /// (balance in nanotoncoins) and a `cell` /// (a dictionary with 32-bit keys representing the balance of "extra currencies") /// at the start of Computation Phase. /// Note that RAW primitives such as [send_raw_message] do not update this field. -[int, cell] get_balance() asm "BALANCE"; +[int, cell] get_balance() pure asm "BALANCE"; /// Returns the logical time of the current transaction. -int cur_lt() asm "LTIME"; +int cur_lt() pure asm "LTIME"; /// Returns the starting logical time of the current block. -int block_lt() asm "BLOCKLT"; +int block_lt() pure asm "BLOCKLT"; /// Computes the representation hash of a `cell` [c] and returns it as a 256-bit unsigned integer `x`. /// Useful for signing and checking signatures of arbitrary entities represented by a tree of cells. -int cell_hash(cell c) asm "HASHCU"; +int cell_hash(cell c) pure asm "HASHCU"; /// Computes the hash of a `slice s` and returns it as a 256-bit unsigned integer `x`. /// The result is the same as if an ordinary cell containing only data and references from `s` had been created /// and its hash computed by [cell_hash]. -int slice_hash(slice s) asm "HASHSU"; +int slice_hash(slice s) pure asm "HASHSU"; /// Computes sha256 of the data bits of `slice` [s]. If the bit length of `s` is not divisible by eight, /// throws a cell underflow exception. The hash value is returned as a 256-bit unsigned integer `x`. -int string_hash(slice s) asm "SHA256U"; +int string_hash(slice s) pure asm "SHA256U"; /* # Signature checks @@ -163,14 +163,14 @@ int string_hash(slice s) asm "SHA256U"; /// Note that `CHKSIGNU` creates a 256-bit slice with the hash and calls `CHKSIGNS`. /// That is, if [hash] is computed as the hash of some data, these data are hashed twice, /// the second hashing occurring inside `CHKSIGNS`. -int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; +int check_signature(int hash, slice signature, int public_key) pure asm "CHKSIGNU"; /// Checks whether [signature] is a valid Ed25519-signature of the data portion of `slice data` using `public_key`, /// similarly to [check_signature]. /// If the bit length of [data] is not divisible by eight, throws a cell underflow exception. /// The verification of Ed25519 signatures is the standard one, /// with sha256 used to reduce [data] to the 256-bit number that is actually signed. -int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; +int check_data_signature(slice data, slice signature, int public_key) pure asm "CHKSIGNS"; /*** # Computation of boc size @@ -178,10 +178,10 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI */ /// A non-quiet version of [compute_data_size?] that throws a cell overflow exception (`8`) on failure. -(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; +(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE"; /// A non-quiet version of [slice_compute_data_size?] that throws a cell overflow exception (`8`) on failure. -(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; +(int, int, int) slice_compute_data_size(slice s, int max_cells) asm "SDATASIZE"; /// Returns `(x, y, z, -1)` or `(null, null, null, 0)`. /// Recursively computes the count of distinct cells `x`, data bits `y`, and cell references `z` @@ -192,48 +192,48 @@ int check_data_signature(slice data, slice signature, int public_key) asm "CHKSI /// The total count of visited cells `x` cannot exceed non-negative [max_cells]; /// otherwise the computation is aborted before visiting the `(max_cells + 1)`-st cell and /// a zero flag is returned to indicate failure. If [c] is `null`, returns `x = y = z = 0`. -(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; /// Similar to [compute_data_size?], but accepting a `slice` [s] instead of a `cell`. /// The returned value of `x` does not take into account the cell that contains the `slice` [s] itself; /// however, the data bits and the cell references of [s] are accounted for in `y` and `z`. -(int, int, int, int) slice_compute_data_size?(slice s, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +(int, int, int, int) slice_compute_data_size?(slice s, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; /// Throws an exception with exit_code excno if cond is not 0 (commented since implemented in compilator) -// () throw_if(int excno, int cond) impure asm "THROWARGIF"; +// () throw_if(int excno, int cond) asm "THROWARGIF"; /*** # Debug primitives Only works for local TVM execution with debug level verbosity */ /// Dumps the stack (at most the top 255 values) and shows the total stack depth. -() dump_stack() impure asm "DUMPSTK"; +() dump_stack() asm "DUMPSTK"; /* # Persistent storage save and load */ /// Returns the persistent contract storage cell. It can be parsed or modified with slice and builder primitives later. -cell get_data() asm "c4 PUSH"; +cell get_data() pure asm "c4 PUSH"; /// Sets `cell` [c] as persistent contract data. You can update persistent contract storage with this primitive. -() set_data(cell c) impure asm "c4 POP"; +() set_data(cell c) asm "c4 POP"; /* # Continuation primitives */ /// Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls. /// The primitive returns the current value of `c3`. -cont get_c3() asm "c3 PUSH"; +cont get_c3() pure asm "c3 PUSH"; /// Updates the current value of `c3`. Usually, it is used for updating smart contract code in run-time. /// Note that after execution of this primitive the current code /// (and the stack of recursive function calls) won't change, /// but any other function call will use a function from the new code. -() set_c3(cont c) impure asm "c3 POP"; +() set_c3(cont c) asm "c3 POP"; /// Transforms a `slice` [s] into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist. -cont bless(slice s) asm "BLESS"; +cont bless(slice s) pure asm "BLESS"; /*** # Gas related primitives @@ -245,37 +245,37 @@ cont bless(slice s) asm "BLESS"; /// This action is required to process external messages, which bring no value (hence no gas) with themselves. /// /// For more details check [accept_message effects](https://ton.org/docs/#/smart-contracts/accept). -() accept_message() impure asm "ACCEPT"; +() accept_message() asm "ACCEPT"; /// Sets current gas limit `gl` to the minimum of limit and `gm`, and resets the gas credit `gc` to zero. /// If the gas consumed so far (including the present instruction) exceeds the resulting value of `gl`, /// an (unhandled) out of gas exception is thrown before setting new gas limits. /// Notice that [set_gas_limit] with an argument `limit ≥ 2^63 − 1` is equivalent to [accept_message]. -() set_gas_limit(int limit) impure asm "SETGASLIMIT"; +() set_gas_limit(int limit) asm "SETGASLIMIT"; /// Commits the current state of registers `c4` (“persistent data”) and `c5` (“actions”) /// so that the current execution is considered “successful” with the saved values even if an exception /// in Computation Phase is thrown later. -() commit() impure asm "COMMIT"; +() commit() asm "COMMIT"; /// Not implemented -//() buy_gas(int gram) impure asm "BUYGAS"; +//() buy_gas(int gram) asm "BUYGAS"; /// Computes the amount of gas that can be bought for `amount` nanoTONs, /// and sets `gl` accordingly in the same way as [set_gas_limit]. -() buy_gas(int amount) impure asm "BUYGAS"; +() buy_gas(int amount) asm "BUYGAS"; /// Computes the minimum of two integers [x] and [y]. -int min(int x, int y) asm "MIN"; +int min(int x, int y) pure asm "MIN"; /// Computes the maximum of two integers [x] and [y]. -int max(int x, int y) asm "MAX"; +int max(int x, int y) pure asm "MAX"; /// Sorts two integers. -(int, int) minmax(int x, int y) asm "MINMAX"; +(int, int) minmax(int x, int y) pure asm "MINMAX"; /// Computes the absolute value of an integer [x]. -int abs(int x) asm "ABS"; +int abs(int x) pure asm "ABS"; /* # Slice primitives @@ -294,80 +294,80 @@ int abs(int x) asm "ABS"; /// Converts a `cell` [c] into a `slice`. Notice that [c] must be either an ordinary cell, /// or an exotic cell (see [TVM.pdf](https://ton-blockchain.github.io/docs/tvm.pdf), 3.1.2) /// which is automatically loaded to yield an ordinary cell `c'`, converted into a `slice` afterwards. -slice begin_parse(cell c) asm "CTOS"; +slice begin_parse(cell c) pure asm "CTOS"; /// Checks if [s] is empty. If not, throws an exception. -() end_parse(slice s) impure asm "ENDS"; +() end_parse(slice s) asm "ENDS"; /// Loads the first reference from the slice. -(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; +(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; /// Preloads the first reference from the slice. -cell preload_ref(slice s) asm "PLDREF"; +cell preload_ref(slice s) pure asm "PLDREF"; /* Functions below are commented because are implemented on compilator level for optimisation */ /// Loads a signed [len]-bit integer from a slice [s]. -// (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; +// (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; /// Loads an unsigned [len]-bit integer from a slice [s]. -// (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; +// (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; /// Preloads a signed [len]-bit integer from a slice [s]. -// int preload_int(slice s, int len) asm "PLDIX"; +// int preload_int(slice s, int len) pure asm "PLDIX"; /// Preloads an unsigned [len]-bit integer from a slice [s]. -// int preload_uint(slice s, int len) asm "PLDUX"; +// int preload_uint(slice s, int len) pure asm "PLDUX"; /// Loads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. -// (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; +// (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; /// Preloads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. -// slice preload_bits(slice s, int len) asm "PLDSLICEX"; +// slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; /// Loads serialized amount of TonCoins (any unsigned integer up to `2^120 - 1`). -(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; -(slice, int) load_coins(slice s) asm( -> 1 0) "LDGRAMS"; +(slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; +(slice, int) load_coins(slice s) pure asm( -> 1 0) "LDGRAMS"; /// Returns all but the first `0 ≤ len ≤ 1023` bits of `slice` [s]. -slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; -(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; +slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; /// Returns the first `0 ≤ len ≤ 1023` bits of `slice` [s]. -slice first_bits(slice s, int len) asm "SDCUTFIRST"; +slice first_bits(slice s, int len) pure asm "SDCUTFIRST"; /// Returns all but the last `0 ≤ len ≤ 1023` bits of `slice` [s]. -slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; -(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; +slice skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) pure asm "SDSKIPLAST"; /// Returns the last `0 ≤ len ≤ 1023` bits of `slice` [s]. -slice slice_last(slice s, int len) asm "SDCUTLAST"; +slice slice_last(slice s, int len) pure asm "SDCUTLAST"; /// Loads a dictionary `D` (HashMapE) from `slice` [s]. /// (returns `null` if `nothing` constructor is used). -(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; +(slice, cell) load_dict(slice s) pure asm( -> 1 0) "LDDICT"; /// Preloads a dictionary `D` from `slice` [s]. -cell preload_dict(slice s) asm "PLDDICT"; +cell preload_dict(slice s) pure asm "PLDDICT"; /// Loads a dictionary as [load_dict], but returns only the remainder of the slice. -slice skip_dict(slice s) asm "SKIPDICT"; +slice skip_dict(slice s) pure asm "SKIPDICT"; /// Loads (Maybe ^Cell) from `slice` [s]. /// In other words loads 1 bit and if it is true /// loads first ref and return it with slice remainder /// otherwise returns `null` and slice remainder -(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF"; +(slice, cell) load_maybe_ref(slice s) pure asm( -> 1 0) "LDOPTREF"; /// Preloads (Maybe ^Cell) from `slice` [s]. -cell preload_maybe_ref(slice s) asm "PLDOPTREF"; +cell preload_maybe_ref(slice s) pure asm "PLDOPTREF"; /// Returns the depth of `cell` [c]. /// If [c] has no references, then return `0`; /// otherwise the returned value is one plus the maximum of depths of cells referred to from [c]. /// If [c] is a `null` instead of a cell, returns zero. -int cell_depth(cell c) asm "CDEPTH"; +int cell_depth(cell c) pure asm "CDEPTH"; /* @@ -375,42 +375,42 @@ int cell_depth(cell c) asm "CDEPTH"; */ /// Returns the number of references in `slice` [s]. -int slice_refs(slice s) asm "SREFS"; +int slice_refs(slice s) pure asm "SREFS"; /// Returns the number of data bits in `slice` [s]. -int slice_bits(slice s) asm "SBITS"; +int slice_bits(slice s) pure asm "SBITS"; /// Returns both the number of data bits and the number of references in `slice` [s]. -(int, int) slice_bits_refs(slice s) asm "SBITREFS"; +(int, int) slice_bits_refs(slice s) pure asm "SBITREFS"; /// Checks whether a `slice` [s] is empty (i.e., contains no bits of data and no cell references). -int slice_empty?(slice s) asm "SEMPTY"; +int slice_empty?(slice s) pure asm "SEMPTY"; /// Checks whether `slice` [s] has no bits of data. -int slice_data_empty?(slice s) asm "SDEMPTY"; +int slice_data_empty?(slice s) pure asm "SDEMPTY"; /// Checks whether `slice` [s] has no references. -int slice_refs_empty?(slice s) asm "SREMPTY"; +int slice_refs_empty?(slice s) pure asm "SREMPTY"; /// Returns the depth of `slice` [s]. /// If [s] has no references, then returns `0`; /// otherwise the returned value is one plus the maximum of depths of cells referred to from [s]. -int slice_depth(slice s) asm "SDEPTH"; +int slice_depth(slice s) pure asm "SDEPTH"; /* # Builder size primitives */ /// Returns the number of cell references already stored in `builder` [b] -int builder_refs(builder b) asm "BREFS"; +int builder_refs(builder b) pure asm "BREFS"; /// Returns the number of data bits already stored in `builder` [b]. -int builder_bits(builder b) asm "BBITS"; +int builder_bits(builder b) pure asm "BBITS"; /// Returns the depth of `builder` [b]. /// If no cell references are stored in [b], then returns 0; /// otherwise the returned value is one plus the maximum of depths of cells referred to from [b]. -int builder_depth(builder b) asm "BDEPTH"; +int builder_depth(builder b) pure asm "BDEPTH"; /* # Builder primitives @@ -423,23 +423,23 @@ int builder_depth(builder b) asm "BDEPTH"; */ /// Creates a new empty `builder`. -builder begin_cell() asm "NEWC"; +builder begin_cell() pure asm "NEWC"; /// Converts a `builder` into an ordinary `cell`. -cell end_cell(builder b) asm "ENDC"; +cell end_cell(builder b) pure asm "ENDC"; /// Stores a reference to `cell` [c] into `builder` [b]. -builder store_ref(builder b, cell c) asm(c b) "STREF"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; /// Stores an unsigned [len]-bit integer `x` into `b` for `0 ≤ len ≤ 256`. -// builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; +// builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; /// Stores a signed [len]-bit integer `x` into `b` for` 0 ≤ len ≤ 257`. -// builder store_int(builder b, int x, int len) asm(x b len) "STIX"; +// builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; /// Stores `slice` [s] into `builder` [b] -builder store_slice(builder b, slice s) asm "STSLICER"; +builder store_slice(builder b, slice s) pure asm "STSLICER"; /// Stores (serializes) an integer [x] in the range `0..2^120 − 1` into `builder` [b]. /// The serialization of [x] consists of a 4-bit unsigned big-endian integer `l`, @@ -448,17 +448,17 @@ builder store_slice(builder b, slice s) asm "STSLICER"; /// If [x] does not belong to the supported range, a range check exception is thrown. /// /// Store amounts of TonCoins to the builder as VarUInteger 16 -builder store_grams(builder b, int x) asm "STGRAMS"; -builder store_coins(builder b, int x) asm "STGRAMS"; +builder store_grams(builder b, int x) pure asm "STGRAMS"; +builder store_coins(builder b, int x) pure asm "STGRAMS"; /// Stores dictionary `D` represented by `cell` [c] or `null` into `builder` [b]. /// In other words, stores a `1`-bit and a reference to [c] if [c] is not `null` and `0`-bit otherwise. -builder store_dict(builder b, cell c) asm(c b) "STDICT"; +builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; /// Stores (Maybe ^Cell) to builder: /// if cell is null store 1 zero bit /// otherwise store 1 true bit and ref to cell -builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; +builder store_maybe_ref(builder b, cell c) pure asm(c b) "STOPTREF"; /* @@ -500,22 +500,22 @@ builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; /// Loads from slice [s] the only prefix that is a valid `MsgAddress`, /// and returns both this prefix `s'` and the remainder `s''` of [s] as slices. -(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; +(slice, slice) load_msg_addr(slice s) pure asm( -> 1 0) "LDMSGADDR"; /// Decomposes slice [s] containing a valid `MsgAddress` into a `tuple t` with separate fields of this `MsgAddress`. /// If [s] is not a valid `MsgAddress`, a cell deserialization exception is thrown. -tuple parse_addr(slice s) asm "PARSEMSGADDR"; +tuple parse_addr(slice s) pure asm "PARSEMSGADDR"; /// Parses slice [s] containing a valid `MsgAddressInt` (usually a `msg_addr_std`), /// applies rewriting from the anycast (if present) to the same-length prefix of the address, /// and returns both the workchain and the 256-bit address as integers. /// If the address is not 256-bit, or if [s] is not a valid serialization of `MsgAddressInt`, /// throws a cell deserialization exception. -(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; +(int, int) parse_std_addr(slice s) pure asm "REWRITESTDADDR"; /// A variant of [parse_std_addr] that returns the (rewritten) address as a slice [s], /// even if it is not exactly 256 bit long (represented by a `msg_addr_var`). -(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; +(int, slice) parse_var_addr(slice s) pure asm "REWRITEVARADDR"; /* # Dictionary primitives @@ -524,116 +524,116 @@ tuple parse_addr(slice s) asm "PARSEMSGADDR"; /// Sets the value associated with [key_len]-bit key signed index in dictionary [dict] to [value] (cell), /// and returns the resulting dictionary. -cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; +cell idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; /// Sets the value associated with [key_len]-bit key unsigned index in dictionary [dict] to [value] (cell), /// and returns the resulting dictionary. -cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; -(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; - -cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; -(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF" "NULLSWAPIFNOT"; -(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF" "NULLSWAPIFNOT"; -(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; -(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; -(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; -(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; -(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; -(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; -(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; -(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; -cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; -cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; -cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; -(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; -(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; -(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; -(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; -cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; -cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; -cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; -(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; -(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; -(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; -(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; -(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; -(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; -(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; -(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; -(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; -(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETREF"; + +cell idict_get_ref(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETOPTREF"; +(cell, int) idict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGETREF" "NULLSWAPIFNOT"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGETREF" "NULLSWAPIFNOT"; +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTUSETGETOPTREF"; +(cell, int) idict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDEL"; +(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +cell udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) pure asm(value index dict key_len) "DICTSET"; +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUADD"; +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIADD"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTIREPLACE"; +cell udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) pure asm(value index dict key_len) "DICTSETB"; +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUADDB"; +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIADDB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) pure asm(value index dict key_len) "DICTIREPLACEB"; +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) pure asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) pure asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; /// Creates an empty dictionary, which is actually a null value. Equivalent to PUSHNULL -cell new_dict() asm "NEWDICT"; +cell new_dict() pure asm "NEWDICT"; /// Checks whether a dictionary is empty. Equivalent to cell_null?. -int dict_empty?(cell c) asm "DICTEMPTY"; +int dict_empty?(cell c) pure asm "DICTEMPTY"; /* Prefix dictionary primitives */ -(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; -(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; -(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) pure asm(value key dict key_len) "PFXDICTSET"; +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) pure asm(key dict key_len) "PFXDICTDEL"; /// Returns the value of the global configuration parameter with integer index `i` as a `cell` or `null` value. -cell config_param(int x) asm "CONFIGOPTPARAM"; +cell config_param(int x) pure asm "CONFIGOPTPARAM"; /// Checks whether c is a null. Note, that FunC also has polymorphic null? built-in. -int cell_null?(cell c) asm "ISNULL"; +int cell_null?(cell c) pure asm "ISNULL"; /// Creates an output action which would reserve exactly amount nanotoncoins (if mode = 0), at most amount nanotoncoins (if mode = 2), or all but amount nanotoncoins (if mode = 1 or mode = 3), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carrying amount nanotoncoins (or b − amount nanotoncoins, where b is the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit +2 in mode means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit +8 in mode means `amount <- -amount` before performing any further actions. Bit +4 in mode means that amount is increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currently, amount must be a non-negative integer, and mode must be in the range 0..15. -() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; +() raw_reserve(int amount, int mode) asm "RAWRESERVE"; /// Similar to raw_reserve, but also accepts a dictionary extra_amount (represented by a cell or null) with extra currencies. In this way currencies other than TonCoin can be reserved. -() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; +() raw_reserve_extra(int amount, cell extra_amount, int mode) asm "RAWRESERVEX"; /// Sends a raw message contained in msg, which should contain a correctly serialized object Message X, with the only exception that the source address is allowed to have dummy value addr_none (to be automatically replaced with the current smart contract address), and ihr_fee, fwd_fee, created_lt and created_at fields can have arbitrary values (to be rewritten with correct values during the action phase of the current transaction). Integer parameter mode contains the flags. Currently mode = 0 is used for ordinary messages; mode = 128 is used for messages that are to carry all the remaining balance of the current smart contract (instead of the value originally indicated in the message); mode = 64 is used for messages that carry all the remaining value of the inbound message in addition to the value initially indicated in the new message (if bit 0 is not set, the gas fees are deducted from this amount); mode' = mode + 1 means that the sender wants to pay transfer fees separately; mode' = mode + 2 means that any errors arising while processing this message during the action phase should be ignored. Finally, mode' = mode + 32 means that the current account must be destroyed if its resulting balance is zero. This flag is usually employed together with +128. -() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; +() send_raw_message(cell msg, int mode) asm "SENDRAWMSG"; /// Creates an output action that would change this smart contract code to that given by cell new_code. Notice that this change will take effect only after the successful termination of the current run of the smart contract -() set_code(cell new_code) impure asm "SETCODE"; +() set_code(cell new_code) asm "SETCODE"; /// Generates a new pseudo-random unsigned 256-bit integer x. The algorithm is as follows: if r is the old value of the random seed, considered as a 32-byte array (by constructing the big-endian representation of an unsigned 256-bit integer), then its sha512(r) is computed; the first 32 bytes of this hash are stored as the new value r' of the random seed, and the remaining 32 bytes are returned as the next random value x. -int random() impure asm "RANDU256"; +int random() asm "RANDU256"; /// Generates a new pseudo-random integer z in the range 0..range−1 (or range..−1, if range < 0). More precisely, an unsigned random value x is generated as in random; then z := x * range / 2^256 is computed. -int rand(int range) impure asm "RAND"; +int rand(int range) asm "RAND"; /// Returns the current random seed as an unsigned 256-bit Integer. -int get_seed() asm "RANDSEED"; +int get_seed() pure asm "RANDSEED"; /// Sets the random seed to unsigned 256-bit seed. -() set_seed(int) impure asm "SETRAND"; +() set_seed(int) asm "SETRAND"; /// Mixes unsigned 256-bit integer x into the random seed r by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed r, and the second with the big-endian representation of x. -() randomize(int x) impure asm "ADDRAND"; +() randomize(int x) asm "ADDRAND"; /// Equivalent to randomize(cur_lt());. -() randomize_lt() impure asm "LTIME" "ADDRAND"; +() randomize_lt() asm "LTIME" "ADDRAND"; /// Checks whether the data parts of two slices coinside -int equal_slice_bits (slice a, slice b) asm "SDEQ"; +int equal_slice_bits (slice a, slice b) pure asm "SDEQ"; /// Concatenates two builders -builder store_builder(builder to, builder from) asm "STBR"; +builder store_builder(builder to, builder from) pure asm "STBR"; From ef5719d7e6e2ed02e0f1d241a977e785f0371335 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Fri, 3 May 2024 20:58:21 +0300 Subject: [PATCH 13/30] [FunC] Forbid impure operations inside pure functions In stdlib, all existing pure functions are asm-implemented. But since we introduced a `pure` keyword applicable to user-defined functions, we need to check that they won't have any side effects (exceptions, globals modification, etc.) --- crypto/func/abscode.cpp | 17 +------ crypto/func/analyzer.cpp | 49 +++++++++++++++---- .../func/auto-tests/tests/invalid-pure-1.fc | 18 +++++++ .../func/auto-tests/tests/invalid-pure-2.fc | 25 ++++++++++ .../func/auto-tests/tests/invalid-pure-3.fc | 23 +++++++++ .../func/auto-tests/tests/pure-functions.fc | 47 ++++++++++++++++++ crypto/func/func.h | 33 ++++++------- crypto/func/gen-abscode.cpp | 10 ++-- crypto/func/parse-func.cpp | 10 +++- 9 files changed, 181 insertions(+), 51 deletions(-) create mode 100644 crypto/func/auto-tests/tests/invalid-pure-1.fc create mode 100644 crypto/func/auto-tests/tests/invalid-pure-2.fc create mode 100644 crypto/func/auto-tests/tests/invalid-pure-3.fc create mode 100644 crypto/func/auto-tests/tests/pure-functions.fc diff --git a/crypto/func/abscode.cpp b/crypto/func/abscode.cpp index f1ffcfa49..d5e1fb0ef 100644 --- a/crypto/func/abscode.cpp +++ b/crypto/func/abscode.cpp @@ -223,15 +223,6 @@ void VarDescrList::show(std::ostream& os) const { os << " ]\n"; } -void Op::flags_set_clear(int set, int clear) { - flags = (flags | set) & ~clear; - for (auto& op : block0) { - op.flags_set_clear(set, clear); - } - for (auto& op : block1) { - op.flags_set_clear(set, clear); - } -} void Op::split_vars(const std::vector& vars) { split_var_list(left, vars); split_var_list(right, vars); @@ -296,7 +287,7 @@ void Op::show(std::ostream& os, const std::vector& vars, std::string pfx if (noreturn()) { dis += " "; } - if (!is_pure()) { + if (impure()) { dis += " "; } switch (cl) { @@ -469,12 +460,6 @@ void Op::show_block(std::ostream& os, const Op* block, const std::vector os << pfx << "}"; } -void CodeBlob::flags_set_clear(int set, int clear) { - for (auto& op : ops) { - op.flags_set_clear(set, clear); - } -} - std::ostream& operator<<(std::ostream& os, const CodeBlob& code) { code.print(os); return os; diff --git a/crypto/func/analyzer.cpp b/crypto/func/analyzer.cpp index ec6931af0..3e3f42acd 100644 --- a/crypto/func/analyzer.cpp +++ b/crypto/func/analyzer.cpp @@ -360,10 +360,10 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) { case _Tuple: case _UnTuple: { // left = EXEC right; - if (!next_var_info.count_used(left) && is_pure()) { + if (!next_var_info.count_used(left) && !impure()) { // all variables in `left` are not needed if (edit) { - disable(); + set_disabled(); } return std_compute_used_vars(true); } @@ -372,7 +372,7 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) { case _SetGlob: { // GLOB = right if (right.empty() && edit) { - disable(); + set_disabled(); } return std_compute_used_vars(right.empty()); } @@ -399,7 +399,7 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) { } if (!cnt && edit) { // all variables in `left` are not needed - disable(); + set_disabled(); } return set_var_info(std::move(new_var_info)); } @@ -860,15 +860,45 @@ VarDescrList Op::fwd_analyze(VarDescrList values) { } } -bool Op::set_noreturn(bool nr) { - if (nr) { +void Op::set_disabled(bool flag) { + if (flag) { + flags |= _Disabled; + } else { + flags &= ~_Disabled; + } +} + + +bool Op::set_noreturn(bool flag) { + if (flag) { flags |= _NoReturn; } else { flags &= ~_NoReturn; } - return nr; + return flag; +} + +void Op::set_impure(const CodeBlob &code) { + // todo calling this function with `code` is a bad design (flags are assigned after Op is constructed) + // later it's better to check this somewhere in code.emplace_back() + if (code.flags & CodeBlob::_ForbidImpure) { + throw src::ParseError(where, "An impure operation in a pure function"); + } + flags |= _Impure; } +void Op::set_impure(const CodeBlob &code, bool flag) { + if (flag) { + if (code.flags & CodeBlob::_ForbidImpure) { + throw src::ParseError(where, "An impure operation in a pure function"); + } + flags |= _Impure; + } else { + flags &= ~_Impure; + } +} + + bool Op::mark_noreturn() { switch (cl) { case _Nop: @@ -888,13 +918,14 @@ bool Op::mark_noreturn() { case _Call: return set_noreturn(next->mark_noreturn()); case _Return: - return set_noreturn(true); + return set_noreturn(); case _If: case _TryCatch: + // note, that & | (not && ||) here and below is mandatory to invoke both left and right calls return set_noreturn((block0->mark_noreturn() & (block1 && block1->mark_noreturn())) | next->mark_noreturn()); case _Again: block0->mark_noreturn(); - return set_noreturn(true); + return set_noreturn(); case _Until: return set_noreturn(block0->mark_noreturn() | next->mark_noreturn()); case _While: diff --git a/crypto/func/auto-tests/tests/invalid-pure-1.fc b/crypto/func/auto-tests/tests/invalid-pure-1.fc new file mode 100644 index 000000000..284fa7056 --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-pure-1.fc @@ -0,0 +1,18 @@ +int f_impure(); + +int f_pure() pure { + return f_impure(); +} + +int main() { + return f_pure(); +} + +{- +@compilation_should_fail +@stderr +""" +An impure operation in a pure function +return f_impure(); +""" +-} diff --git a/crypto/func/auto-tests/tests/invalid-pure-2.fc b/crypto/func/auto-tests/tests/invalid-pure-2.fc new file mode 100644 index 000000000..9def660bb --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-pure-2.fc @@ -0,0 +1,25 @@ +builder begin_cell() pure asm "NEWC"; + +global int g; + +(builder) f_pure() pure { + var g; // strange, but this doesn't make a variable local, it still refers to a global one + builder b = begin_cell(); + g = g + 1; + return b; +} + +int main() { + g = 0; + f_pure(); + return g; +} + +{- +@compilation_should_fail +@stderr +""" +An impure operation in a pure function +g = g + 1; +""" +-} diff --git a/crypto/func/auto-tests/tests/invalid-pure-3.fc b/crypto/func/auto-tests/tests/invalid-pure-3.fc new file mode 100644 index 000000000..98b2fdede --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-pure-3.fc @@ -0,0 +1,23 @@ +(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; + +(int, int) validate_input(cell input) pure { + var (x, y, z, correct) = compute_data_size?(input, 10); + throw_unless(102, correct); +} + +int main() pure { + cell c = begin_cell().end_cell(); + validate_input(c); + return 0; +} + +{- +@compilation_should_fail +@stderr +""" +An impure operation in a pure function +throw_unless +""" +-} diff --git a/crypto/func/auto-tests/tests/pure-functions.fc b/crypto/func/auto-tests/tests/pure-functions.fc new file mode 100644 index 000000000..983a650f5 --- /dev/null +++ b/crypto/func/auto-tests/tests/pure-functions.fc @@ -0,0 +1,47 @@ +cell get_data() pure asm "c4 PUSH"; +slice begin_parse(cell c) pure asm "CTOS"; +builder begin_cell() pure asm "NEWC"; +cell end_cell(builder b) pure asm "ENDC"; +() set_data(cell c) asm "c4 POP"; + +int f_pure2() pure; + +int f_pure1() pure { + return f_pure2(); +} + +int f_pure2() pure { + return 2; +} + +(int, int) get_contract_data() pure { + cell c = get_data(); + slice cs = c.begin_parse(); + cs~load_bits(32); + int value = cs~load_uint(16); + return (1, value); +} + +() save_contract_data(int value) { + builder b = begin_cell().store_int(1, 32).store_uint(value, 16); + set_data(b.end_cell()); +} + +int test1() pure method_id(101) { + return f_pure1(); +} + +int test2(int value) method_id(102) { + save_contract_data(value); + (_, var restored) = get_contract_data(); + return restored; +} + +() main() { return (); } + +{- + +TESTCASE | 101 | | 2 +TESTCASE | 102 | 44 | 44 + +-} diff --git a/crypto/func/func.h b/crypto/func/func.h index ca844947f..db1da728e 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -593,16 +593,19 @@ struct Op { SymDef* _fun = nullptr) : cl(_cl), flags(0), fun_ref(_fun), where(_where), left(std::move(_left)), right(std::move(_right)) { } - bool disabled() const { - return flags & _Disabled; - } - bool enabled() const { - return !disabled(); - } - void disable() { - flags |= _Disabled; - } - void flags_set_clear(int set, int clear); + + bool disabled() const { return flags & _Disabled; } + void set_disabled() { flags |= _Disabled; } + void set_disabled(bool flag); + + bool noreturn() const { return flags & _NoReturn; } + bool set_noreturn() { flags |= _NoReturn; return true; } + bool set_noreturn(bool flag); + + bool impure() const { return flags & _Impure; } + void set_impure(const CodeBlob &code); + void set_impure(const CodeBlob &code, bool flag); + void show(std::ostream& os, const std::vector& vars, std::string pfx = "", int mode = 0) const; void show_var_list(std::ostream& os, const std::vector& idx_list, const std::vector& vars) const; void show_var_list(std::ostream& os, const std::vector& list, const std::vector& vars) const; @@ -618,17 +621,10 @@ struct Op { bool set_var_info_except(VarDescrList&& new_var_info, const std::vector& var_list); void prepare_args(VarDescrList values); VarDescrList fwd_analyze(VarDescrList values); - bool set_noreturn(bool nr); bool mark_noreturn(); - bool noreturn() const { - return flags & _NoReturn; - } bool is_empty() const { return cl == _Nop && !next; } - bool is_pure() const { - return !(flags & _Impure); - } bool generate_code_step(Stack& stack); void generate_code_all(Stack& stack); Op& last() { @@ -689,7 +685,7 @@ typedef std::vector FormalArgList; struct AsmOpList; struct CodeBlob { - enum { _AllowPostModification = 1, _ComputeAsmLtr = 2 }; + enum { _AllowPostModification = 1, _ComputeAsmLtr = 2, _ForbidImpure = 4 }; int var_cnt, in_var_cnt, op_cnt; TypeExpr* ret_type; std::string name; @@ -733,7 +729,6 @@ struct CodeBlob { pop_cur(); } void simplify_var_types(); - void flags_set_clear(int set, int clear); void prune_unreachable_code(); void fwd_analyze(); void mark_noreturn(); diff --git a/crypto/func/gen-abscode.cpp b/crypto/func/gen-abscode.cpp index 60e8c8e72..5e8a8761d 100644 --- a/crypto/func/gen-abscode.cpp +++ b/crypto/func/gen-abscode.cpp @@ -229,7 +229,7 @@ var_idx_t Expr::new_tmp(CodeBlob& code) const { void add_set_globs(CodeBlob& code, std::vector>& globs, const SrcLocation& here) { for (const auto& p : globs) { auto& op = code.emplace_back(here, Op::_SetGlob, std::vector{}, std::vector{ p.second }, p.first); - op.flags |= Op::_Impure; + op.set_impure(code); } } @@ -289,7 +289,7 @@ std::vector pre_compile_tensor(const std::vector args, CodeBl if (code.flags & CodeBlob::_AllowPostModification) { if (!lval_globs && (var.cls & TmpVar::_Named)) { Op *op = &code.emplace_back(nullptr, Op::_Let, std::vector(), std::vector()); - op->flags |= Op::_Disabled; + op->set_disabled(); var.on_modification.push_back([modified_vars, i, j, op, done = false](const SrcLocation &here) mutable { if (!done) { done = true; @@ -319,7 +319,7 @@ std::vector pre_compile_tensor(const std::vector args, CodeBl var_idx_t v2 = code.create_tmp_var(code.vars[v].v_type, code.vars[v].where.get()); m.op->left = {v2}; m.op->right = {v}; - m.op->flags &= ~Op::_Disabled; + m.op->set_disabled(false); v = v2; } std::vector res; @@ -371,7 +371,7 @@ std::vector Expr::pre_compile(CodeBlob& code, std::vector Expr::pre_compile(CodeBlob& code, std::vectorsym); if (args[0]->flags & _IsImpure) { - op.flags |= Op::_Impure; + op.set_impure(code); } return rvect; } else { diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index bc298caa9..a9c771dfc 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -1216,7 +1216,7 @@ blk_fl::val parse_stmt(Lexer& lex, CodeBlob& code) { } } -CodeBlob* parse_func_body(Lexer& lex, FormalArgList arg_list, TypeExpr* ret_type) { +CodeBlob* parse_func_body(Lexer& lex, FormalArgList arg_list, TypeExpr* ret_type, bool marked_as_pure) { lex.expect('{'); CodeBlob* blob = new CodeBlob{ret_type}; if (pragma_allow_post_modification.enabled()) { @@ -1225,6 +1225,9 @@ CodeBlob* parse_func_body(Lexer& lex, FormalArgList arg_list, TypeExpr* ret_type if (pragma_compute_asm_ltr.enabled()) { blob->flags |= CodeBlob::_ComputeAsmLtr; } + if (marked_as_pure) { + blob->flags |= CodeBlob::_ForbidImpure; + } blob->import_params(std::move(arg_list)); blk_fl::val res = blk_fl::init; bool warned = false; @@ -1604,7 +1607,10 @@ void parse_func_def(Lexer& lex) { if (func_sym_code->code) { lex.cur().error("redefinition of function `"s + func_name.str + "`"); } - CodeBlob* code = parse_func_body(lex, arg_list, ret_type); + if (marked_as_pure && ret_type->get_width() == 0) { + lex.cur().error("a pure function should return something, otherwise it will be optimized out anyway"); + } + CodeBlob* code = parse_func_body(lex, arg_list, ret_type, marked_as_pure); code->name = func_name.str; code->loc = loc; // code->print(std::cerr); // !!!DEBUG!!! From 0628e17c7d98f62284af2009718a6414703488b9 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Sun, 5 May 2024 11:54:14 +0300 Subject: [PATCH 14/30] [FunC] Use td::OptionParser in func-main.cpp --- crypto/func/func-main.cpp | 136 +++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 75 deletions(-) diff --git a/crypto/func/func-main.cpp b/crypto/func/func-main.cpp index c8208eeea..923212820 100644 --- a/crypto/func/func-main.cpp +++ b/crypto/func/func-main.cpp @@ -26,83 +26,69 @@ Copyright 2017-2020 Telegram Systems LLP */ #include "func.h" -#include "parser/srcread.h" -#include "parser/lexer.h" -#include "parser/symtable.h" -#include +#include "td/utils/OptionParser.h" #include #include "git.h" -void usage(const char* progname) { - std::cerr - << "usage: " << progname - << " [-vIAPSR][-O][-i][-o][-W] { ...}\n" - "\tGenerates Fift TVM assembler code from a funC source\n" - "-I\tEnables interactive mode (parse stdin)\n" - "-o\tWrites generated code into specified file instead of stdout\n" - "-v\tIncreases verbosity level (extra information output into stderr)\n" - "-i\tSets indentation for the output code (in two-space units)\n" - "-A\tPrefix code with `\"Asm.fif\" include` preamble\n" - "-O\tSets optimization level (2 by default)\n" - "-P\tEnvelope code into PROGRAM{ ... }END>c\n" - "-S\tInclude stack layout comments in the output code\n" - "-R\tInclude operation rewrite comments in the output code\n" - "-W\tInclude Fift code to serialize and save generated code into specified BoC file. Enables " - "-A and -P.\n" - "\t-s\tOutput semantic version of FunC and exit\n" - "\t-V\tShow func build information\n"; - std::exit(2); -} - -int main(int argc, char* const argv[]) { - int i; +int main(int argc, char* argv[]) { std::string output_filename; - while ((i = getopt(argc, argv, "Ahi:Io:O:PRsSvW:V")) != -1) { - switch (i) { - case 'A': - funC::asm_preamble = true; - break; - case 'I': - funC::interactive = true; - break; - case 'i': - funC::indent = std::max(0, atoi(optarg)); - break; - case 'o': - output_filename = optarg; - break; - case 'O': - funC::opt_level = std::max(0, atoi(optarg)); - break; - case 'P': - funC::program_envelope = true; - break; - case 'R': - funC::op_rewrite_comments = true; - break; - case 'S': - funC::stack_layout_comments = true; - break; - case 'v': - ++funC::verbosity; - break; - case 'W': - funC::boc_output_filename = optarg; - funC::asm_preamble = funC::program_envelope = true; - break; - case 's': - std::cout << funC::func_version << "\n"; - std::exit(0); - break; - case 'V': - std::cout << "FunC semantic version: v" << funC::func_version << "\n"; - std::cout << "Build information: [ Commit: " << GitMetadata::CommitSHA1() << ", Date: " << GitMetadata::CommitDate() << "]\n"; - std::exit(0); - break; - case 'h': - default: - usage(argv[0]); - } + td::OptionParser p; + p.set_description("usage: func " + "[-vIAPSR][-O][-i][-o][-W] { ...}\n" + "Generates Fift TVM assembler code from FunC sources"); + + p.add_option('I', "interactive", "Enables interactive mode (parse stdin)", [] { + funC::interactive = true; + }); + p.add_option('o', "output", "Writes generated code into specified file instead of stdout", [&output_filename](td::Slice arg) { + output_filename = arg.str(); + }); + p.add_option('v', "verbose", "Increases verbosity level (extra information output into stderr)", [] { + ++funC::verbosity; + }); + p.add_option('i', "indent", "Sets indentation for the output code (in two-space units)", [](td::Slice arg) { + funC::indent = std::max(0, std::atoi(arg.str().c_str())); + }); + p.add_option('A', "asm-preamble", "prefix code with `\"Asm.fif\" include` preamble", [] { + funC::asm_preamble = true; + }); + p.add_option('O', "opt-level", "Sets optimization level (2 by default)", [](td::Slice arg) { + funC::opt_level = std::max(0, std::atoi(arg.str().c_str())); + }); + p.add_option('P', "program-envelope", "Envelope code into PROGRAM{ ... }END>c", [] { + funC::program_envelope = true; + }); + p.add_option('S', "stack-comments", "Include stack layout comments in the output code", []{ + funC::stack_layout_comments = true; + }); + p.add_option('R', "rewrite-comments", "Include operation rewrite comments in the output code", [] { + funC::op_rewrite_comments = true; + }); + p.add_option('W', "boc-output", "Include Fift code to serialize and save generated code into specified BoC file. Enables -A and -P", [](td::Slice arg) { + funC::boc_output_filename = arg.str(); + funC::asm_preamble = funC::program_envelope = true; + }); + p.add_option('s', "version", "Output semantic version of FunC and exit", [] { + std::cout << funC::func_version << "\n"; + std::exit(0); + }); + p.add_option('V', "full-version", "Show FunC build information and exit", [] { + std::cout << "FunC semantic version: v" << funC::func_version << "\n"; + std::cout << "Build information: [ Commit: " << GitMetadata::CommitSHA1() << ", Date: " << GitMetadata::CommitDate() << "]\n"; + std::exit(0); + }); + p.add_option('h', "help", "Print help and exit", [&p] { + char b[10240]; + td::StringBuilder sb(td::MutableSlice{b, 10000}); + sb << p; + std::cout << sb.as_cslice().c_str(); + std::exit(2); + }); + + auto parse_result = p.run(argc, argv); + if (parse_result.is_error()) { + std::cerr << "failed to parse options: " << parse_result.error().message().c_str() << "\n"; + return 2; } std::ostream *outs = &std::cout; @@ -119,8 +105,8 @@ int main(int argc, char* const argv[]) { std::vector sources; - while (optind < argc) { - sources.push_back(std::string(argv[optind++])); + for (const char* in_filename : parse_result.ok()) { + sources.emplace_back(in_filename); } funC::read_callback = funC::fs_read_callback; From acf0043342614e0334c0cf6b48feac191d513d65 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Mon, 6 May 2024 18:36:37 +0300 Subject: [PATCH 15/30] [FunC] Add pragma remove-unused-functions for simple dead code elimination --- .../tests/remove-unused-functions.fc | 47 +++++++++++++ crypto/func/func.cpp | 67 ++++++++++++++++++- crypto/func/func.h | 6 +- crypto/func/parse-func.cpp | 4 +- 4 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 crypto/func/auto-tests/tests/remove-unused-functions.fc diff --git a/crypto/func/auto-tests/tests/remove-unused-functions.fc b/crypto/func/auto-tests/tests/remove-unused-functions.fc new file mode 100644 index 000000000..773994943 --- /dev/null +++ b/crypto/func/auto-tests/tests/remove-unused-functions.fc @@ -0,0 +1,47 @@ +#pragma remove-unused-functions; + +int unused1() { return 2; } +int unused2() { return unused1(); } +int unused3(int x) { return x * 2 + unused2(); } + +int used_from_noncall1() { return 10; } +int used_as_noncall1() { return used_from_noncall1(); } + +const int int20 = 20; +int used_from_noncall2() { return int20; } +int used_as_noncall2() { return 0 * 0 + used_from_noncall2() + (0 << 0); } + +global int unused_gv; +global _ used_gv; + +(() -> int) receiveGetter() { return used_as_noncall2; } + +(int) usedButOptimizedOut(int x) pure { return x + 2; } + +(int, int, int) main() { + used_gv = 1; + used_gv = used_gv + 2; + var getter1 = used_as_noncall1; + var getter2 = receiveGetter(); + usedButOptimizedOut(used_gv); + return (used_gv, getter1(), getter2()); +} + +{- +TESTCASE | 0 | | 3 10 20 + +@fif_codegen DECLPROC used_as_noncall1 +@fif_codegen DECLGLOBVAR used_gv + +@fif_codegen_avoid DECLPROC unused1 +@fif_codegen_avoid DECLPROC unused2 +@fif_codegen_avoid DECLPROC unused3 +@fif_codegen_avoid DECLGLOBVAR unused_gv + +Note, that `usedButOptimizedOut()` (a pure function which result is unused) +is currently codegenerated, since it's formally reachable. +This is because optimizing code is a moment of codegen for now (later than marking unused symbols). + +@fif_codegen DECLPROC usedButOptimizedOut +@fif_codegen_avoid usedButOptimizedOut CALLDICT +-} diff --git a/crypto/func/func.cpp b/crypto/func/func.cpp index d2bc88353..416376b84 100644 --- a/crypto/func/func.cpp +++ b/crypto/func/func.cpp @@ -40,6 +40,7 @@ bool stack_layout_comments, op_rewrite_comments, program_envelope, asm_preamble; bool interactive = false; GlobalPragma pragma_allow_post_modification{"allow-post-modification"}; GlobalPragma pragma_compute_asm_ltr{"compute-asm-ltr"}; +GlobalPragma pragma_remove_unused_functions{"remove-unused-functions"}; std::string generated_from, boc_output_filename; ReadCallback::Callback read_callback; @@ -62,6 +63,11 @@ const TypeExpr *SymValFunc::get_arg_type() const { bool SymValCodeFunc::does_need_codegen() const { + // when a function is declared, but not referenced from code in any way, don't generate its body + if (!is_really_used && pragma_remove_unused_functions.enabled()) { + return false; + } + // when a function is referenced like `var a = some_fn;` (or in some other non-call way), its continuation should exist if (flags & flagUsedAsNonCall) { return true; } @@ -69,7 +75,6 @@ bool SymValCodeFunc::does_need_codegen() const { // since all its usages are inlined return !is_just_wrapper_for_another_f(); // in the future, we may want to implement a true AST inlining for `inline` functions also - // in the future, unused functions may also be excluded from codegen } td::Result fs_read_callback(ReadCallback::Kind kind, const char* query) { @@ -93,6 +98,55 @@ td::Result fs_read_callback(ReadCallback::Kind kind, const char* qu } } +void mark_function_used_dfs(const std::unique_ptr& op); + +void mark_function_used(SymValCodeFunc* func_val) { + if (!func_val->code || func_val->is_really_used) { // already handled + return; + } + + func_val->is_really_used = true; + mark_function_used_dfs(func_val->code->ops); +} + +void mark_global_var_used(SymValGlobVar* glob_val) { + glob_val->is_really_used = true; +} + +void mark_function_used_dfs(const std::unique_ptr& op) { + if (!op) { + return; + } + // op->fun_ref, despite its name, may actually ref global var + // note, that for non-calls, e.g. `var a = some_fn` (Op::_Let), some_fn is Op::_GlobVar + // (in other words, fun_ref exists not only for direct Op::_Call, but for non-call references also) + if (op->fun_ref) { + if (auto* func_val = dynamic_cast(op->fun_ref->value)) { + mark_function_used(func_val); + } else if (auto* glob_val = dynamic_cast(op->fun_ref->value)) { + mark_global_var_used(glob_val); + } else if (auto* asm_val = dynamic_cast(op->fun_ref->value)) { + } else { + func_assert(false); + } + } + mark_function_used_dfs(op->next); + mark_function_used_dfs(op->block0); + mark_function_used_dfs(op->block1); +} + +void mark_used_symbols() { + for (SymDef* func_sym : glob_func) { + auto* func_val = dynamic_cast(func_sym->value); + std::string name = sym::symbols.get_name(func_sym->sym_idx); + if (func_val->method_id.not_null() || + name == "main" || name == "recv_internal" || name == "recv_external" || + name == "run_ticktock" || name == "split_prepare" || name == "split_install") { + mark_function_used(func_val); + } + } +} + /* * * OUTPUT CODE GENERATOR @@ -188,6 +242,7 @@ int generate_output(std::ostream &outs, std::ostream &errs) { if (program_envelope) { outs << "PROGRAM{\n"; } + mark_used_symbols(); for (SymDef* func_sym : glob_func) { SymValCodeFunc* func_val = dynamic_cast(func_sym->value); func_assert(func_val); @@ -207,7 +262,14 @@ int generate_output(std::ostream &outs, std::ostream &errs) { } } for (SymDef* gvar_sym : glob_vars) { - func_assert(dynamic_cast(gvar_sym->value)); + auto* glob_val = dynamic_cast(gvar_sym->value); + func_assert(glob_val); + if (!glob_val->is_really_used && pragma_remove_unused_functions.enabled()) { + if (verbosity >= 2) { + errs << gvar_sym->name() << ": variable not generated, it's unused\n"; + } + continue; + } std::string name = sym::symbols.get_name(gvar_sym->sym_idx); outs << std::string(indent * 2, ' ') << "DECLGLOBVAR " << name << "\n"; } @@ -274,6 +336,7 @@ int func_proceed(const std::vector &sources, std::ostream &outs, st } pragma_allow_post_modification.check_enable_in_libs(); pragma_compute_asm_ltr.check_enable_in_libs(); + pragma_remove_unused_functions.check_enable_in_libs(); return funC::generate_output(outs, errs); } catch (src::Fatal& fatal) { errs << "fatal: " << fatal << std::endl; diff --git a/crypto/func/func.h b/crypto/func/func.h index db1da728e..f168b9333 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -563,7 +563,7 @@ struct Op { enum { _Disabled = 1, _NoReturn = 4, _Impure = 24 }; int flags; std::unique_ptr next; - SymDef* fun_ref; + SymDef* fun_ref; // despite its name, it may actually ref global var; applicable not only to Op::_Call, but for other kinds also SrcLocation where; VarDescrList var_info; std::vector args; @@ -806,6 +806,7 @@ struct SymValFunc : SymVal { struct SymValCodeFunc : SymValFunc { CodeBlob* code; + bool is_really_used{false}; // calculated via dfs; unused functions are not codegenerated ~SymValCodeFunc() override = default; SymValCodeFunc(int val, TypeExpr* _ft, bool marked_as_pure) : SymValFunc(val, _ft, marked_as_pure), code(nullptr) { } @@ -825,6 +826,7 @@ struct SymValType : sym::SymValBase { struct SymValGlobVar : sym::SymValBase { TypeExpr* sym_type; int out_idx{0}; + bool is_really_used{false}; // calculated via dfs from used functions; unused globals are not codegenerated #ifdef FUNC_DEBUG std::string name; // seeing variable name in debugger makes it much easier to delve into FunC sources #endif @@ -1788,7 +1790,7 @@ class GlobalPragma { bool enabled_ = false; std::vector locs_; }; -extern GlobalPragma pragma_allow_post_modification, pragma_compute_asm_ltr; +extern GlobalPragma pragma_allow_post_modification, pragma_compute_asm_ltr, pragma_remove_unused_functions; /* * diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index a9c771dfc..c9b5f2cb6 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -287,7 +287,7 @@ void parse_const_decl(Lexer& lex) { new_value = new SymValConst{const_cnt++, x->intval}; } else if (x->cls == Expr::_SliceConst) { // Slice constant (string) new_value = new SymValConst{const_cnt++, x->strval}; - } else if (x->cls == Expr::_Apply) { + } else if (x->cls == Expr::_Apply) { // even "1 + 2" is Expr::_Apply (it applies `_+_`) code.emplace_back(loc, Op::_Import, std::vector()); auto tmp_vars = x->pre_compile(code); code.emplace_back(loc, Op::_Return, std::move(tmp_vars)); @@ -1798,6 +1798,8 @@ void parse_pragma(Lexer& lex) { pragma_allow_post_modification.enable(lex.cur().loc); } else if (pragma_name == pragma_compute_asm_ltr.name()) { pragma_compute_asm_ltr.enable(lex.cur().loc); + } else if (pragma_name == pragma_remove_unused_functions.name()) { + pragma_remove_unused_functions.enable(lex.cur().loc); } else { lex.cur().error(std::string{"unknown pragma `"} + pragma_name + "`"); } From cdef8302b005d41caae00b033d7fb00ad6bf3510 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Tue, 7 May 2024 13:10:56 +0300 Subject: [PATCH 16/30] [FunC] Add `builtin` keyword to be used in stdlib later on --- .../func/auto-tests/tests/builtin-keyword.fc | 33 ++++++++++++ .../auto-tests/tests/invalid-builtin-1.fc | 10 ++++ crypto/func/builtins.cpp | 53 ++++++++++--------- crypto/func/func.h | 14 ++--- crypto/func/keywords.cpp | 1 + crypto/func/parse-func.cpp | 24 +++++++-- 6 files changed, 99 insertions(+), 36 deletions(-) create mode 100644 crypto/func/auto-tests/tests/builtin-keyword.fc create mode 100644 crypto/func/auto-tests/tests/invalid-builtin-1.fc diff --git a/crypto/func/auto-tests/tests/builtin-keyword.fc b/crypto/func/auto-tests/tests/builtin-keyword.fc new file mode 100644 index 000000000..9a1050dc3 --- /dev/null +++ b/crypto/func/auto-tests/tests/builtin-keyword.fc @@ -0,0 +1,33 @@ +(int, int) moddiv(int x, int y) pure builtin; +() throw_if(int excno, int cond) builtin; + +() throwIf(int excNo, int cond) { return throw_if(excNo, cond); } + +forall X -> int null?(X x) pure builtin; + +_ test1() method_id(101) { + try { + var (rem, _) = moddiv(1, 1); + throwIf(101, rem != 100500); + return 0; + } catch(_, excNo) { + return excNo; + } +} + +(int, int, int) main() { + int x = 112; + int y = 3; + var wh = x~moddiv(y); + throwIf(103, wh != 37); + var cc = nil; + return (wh, x, null?(cc)); +} + +{- +TESTCASE | 0 | | 37 1 -1 +TESTCASE | 101 | | 101 + +@fif_codegen_avoid DECLPROC moddiv +@fif_codegen_avoid DECLPROC throwIf +-} diff --git a/crypto/func/auto-tests/tests/invalid-builtin-1.fc b/crypto/func/auto-tests/tests/invalid-builtin-1.fc new file mode 100644 index 000000000..9a8b8b73c --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-builtin-1.fc @@ -0,0 +1,10 @@ +(int, int) moddiv2(int x, int y) builtin; + +{- +@compilation_should_fail +@stderr +""" +`builtin` used for non-builtin function +(int, int) moddiv2 +""" +-} diff --git a/crypto/func/builtins.cpp b/crypto/func/builtins.cpp index a0d6d951f..aafa9bef7 100644 --- a/crypto/func/builtins.cpp +++ b/crypto/func/builtins.cpp @@ -31,7 +31,7 @@ int glob_func_cnt, undef_func_cnt, glob_var_cnt, const_cnt; std::vector glob_func, glob_vars; std::set prohibited_var_names; -SymDef* predefine_builtin_func(std::string name, TypeExpr* func_type) { +SymDef* define_builtin_func_impl(const std::string& name, SymValAsmFunc* func_val) { if (name.back() == '_') { prohibited_var_names.insert(name); } @@ -44,39 +44,40 @@ SymDef* predefine_builtin_func(std::string name, TypeExpr* func_type) { std::cerr << "fatal: global function `" << name << "` already defined" << std::endl; std::exit(1); } - return def; -} - -template -SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const T& func, bool impure = false) { - SymDef* def = predefine_builtin_func(name, func_type); - def->value = new SymValAsmFunc{func_type, func, !impure}; + func_val->flags |= SymValFunc::flagBuiltinFunction; + def->value = func_val; #ifdef FUNC_DEBUG dynamic_cast(def->value)->name = name; #endif return def; } -template -SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const T& func, std::initializer_list arg_order, +SymDef* define_builtin_func(const std::string& name, TypeExpr* func_type, const simple_compile_func_t& func, bool impure = false) { + return define_builtin_func_impl(name, new SymValAsmFunc{func_type, func, !impure}); +} + +SymDef* define_builtin_func(const std::string& name, TypeExpr* func_type, const compile_func_t& func, bool impure = false) { + return define_builtin_func_impl(name, new SymValAsmFunc{func_type, func, !impure}); +} + +SymDef* define_builtin_func(const std::string& name, TypeExpr* func_type, const AsmOp& macro, bool impure = false) { + return define_builtin_func_impl(name, new SymValAsmFunc{func_type, make_simple_compile(macro), !impure}); +} + +SymDef* define_builtin_func(const std::string& name, TypeExpr* func_type, const simple_compile_func_t& func, std::initializer_list arg_order, std::initializer_list ret_order = {}, bool impure = false) { - SymDef* def = predefine_builtin_func(name, func_type); - def->value = new SymValAsmFunc{func_type, func, arg_order, ret_order, !impure}; -#ifdef FUNC_DEBUG - dynamic_cast(def->value)->name = name; -#endif - return def; + return define_builtin_func_impl(name, new SymValAsmFunc{func_type, func, arg_order, ret_order, !impure}); +} + +SymDef* define_builtin_func(const std::string& name, TypeExpr* func_type, const compile_func_t& func, std::initializer_list arg_order, + std::initializer_list ret_order = {}, bool impure = false) { + return define_builtin_func_impl(name, new SymValAsmFunc{func_type, func, arg_order, ret_order, !impure}); } -SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const AsmOp& macro, +SymDef* define_builtin_func(const std::string& name, TypeExpr* func_type, const AsmOp& macro, std::initializer_list arg_order, std::initializer_list ret_order = {}, bool impure = false) { - SymDef* def = predefine_builtin_func(name, func_type); - def->value = new SymValAsmFunc{func_type, make_simple_compile(macro), arg_order, ret_order, !impure}; -#ifdef FUNC_DEBUG - dynamic_cast(def->value)->name = name; -#endif - return def; + return define_builtin_func_impl(name, new SymValAsmFunc{func_type, make_simple_compile(macro), arg_order, ret_order, !impure}); } SymDef* force_autoapply(SymDef* def) { @@ -1152,9 +1153,9 @@ void define_builtins() { auto Int3 = TypeExpr::new_tensor({Int, Int, Int}); auto TupleInt = TypeExpr::new_tensor({Tuple, Int}); auto SliceInt = TypeExpr::new_tensor({Slice, Int}); - auto X = TypeExpr::new_var(); - auto Y = TypeExpr::new_var(); - auto Z = TypeExpr::new_var(); + auto X = TypeExpr::new_var(0); + auto Y = TypeExpr::new_var(1); + auto Z = TypeExpr::new_var(2); auto XY = TypeExpr::new_tensor({X, Y}); auto arith_bin_op = TypeExpr::new_map(Int2, Int); auto arith_un_op = TypeExpr::new_map(Int, Int); diff --git a/crypto/func/func.h b/crypto/func/func.h index f168b9333..07737cb98 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -113,6 +113,7 @@ enum Keyword { _Extern, _Inline, _InlineRef, + _Builtin, _AutoApply, _MethodId, _Operator, @@ -767,6 +768,7 @@ struct SymValFunc : SymVal { flagWrapsAnotherF = 4, // (T) thisF(...args) { return anotherF(...args); } (calls to thisF will be replaced) flagUsedAsNonCall = 8, // used not only as `f()`, but as a 1-st class function (assigned to var, pushed to tuple, etc.) flagMarkedAsPure = 16, // declared as `pure`, can't call impure and access globals, unused invocations are optimized out + flagBuiltinFunction = 32, // was created via `define_builtin_func()`, not from source code }; td::RefInt256 method_id; // todo why int256? it's small @@ -802,6 +804,9 @@ struct SymValFunc : SymVal { bool is_marked_as_pure() const { return flags & flagMarkedAsPure; } + bool is_builtin() const { + return flags & flagBuiltinFunction; + } }; struct SymValCodeFunc : SymValFunc { @@ -1700,8 +1705,8 @@ inline simple_compile_func_t make_simple_compile(AsmOp op) { return [op](std::vector& out, std::vector& in, const SrcLocation&) -> AsmOp { return op; }; } -inline compile_func_t make_ext_compile(std::vector ops) { - return [ops = std::move(ops)](AsmOpList & dest, std::vector & out, std::vector & in)->bool { +inline compile_func_t make_ext_compile(std::vector&& ops) { + return [ops = std::move(ops)](AsmOpList& dest, std::vector& out, std::vector& in)->bool { return dest.append(ops); }; } @@ -1716,10 +1721,7 @@ struct SymValAsmFunc : SymValFunc { compile_func_t ext_compile; td::uint64 crc; ~SymValAsmFunc() override = default; - SymValAsmFunc(TypeExpr* ft, const AsmOp& _macro, bool marked_as_pure) - : SymValFunc(-1, ft, marked_as_pure), simple_compile(make_simple_compile(_macro)) { - } - SymValAsmFunc(TypeExpr* ft, std::vector _macro, bool marked_as_pure) + SymValAsmFunc(TypeExpr* ft, std::vector&& _macro, bool marked_as_pure) : SymValFunc(-1, ft, marked_as_pure), ext_compile(make_ext_compile(std::move(_macro))) { } SymValAsmFunc(TypeExpr* ft, simple_compile_func_t _compile, bool marked_as_pure) diff --git a/crypto/func/keywords.cpp b/crypto/func/keywords.cpp index 0248a65ac..9de9fb730 100644 --- a/crypto/func/keywords.cpp +++ b/crypto/func/keywords.cpp @@ -123,6 +123,7 @@ void define_keywords() { .add_keyword("pure", Kw::_Pure) .add_keyword("inline", Kw::_Inline) .add_keyword("inline_ref", Kw::_InlineRef) + .add_keyword("builtin", Kw::_Builtin) .add_keyword("auto_apply", Kw::_AutoApply) .add_keyword("method_id", Kw::_MethodId) .add_keyword("operator", Kw::_Operator) diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index c9b5f2cb6..b06933dbe 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -1358,7 +1358,7 @@ SymValAsmFunc* parse_asm_func_body(Lexer& lex, TypeExpr* func_type, const Formal for (const int& x : ret_order) { crc_s += std::string((const char*) (&x), (const char*) (&x + 1)); } - auto res = new SymValAsmFunc{func_type, asm_ops, marked_as_pure}; + auto res = new SymValAsmFunc{func_type, std::move(asm_ops), marked_as_pure}; res->arg_order = std::move(arg_order); res->ret_order = std::move(ret_order); res->crc = td::crc64(crc_s); @@ -1564,11 +1564,27 @@ void parse_func_def(Lexer& lex) { method_id = td::make_refint((crc & 0xffff) | 0x10000); } } - if (lex.tp() != ';' && lex.tp() != '{' && lex.tp() != _Asm) { - lex.expect('{', "function body block expected"); - } TypeExpr* func_type = TypeExpr::new_map(extract_total_arg_type(arg_list), ret_type); func_type = compute_type_closure(func_type, type_vars); + if (lex.tp() == _Builtin) { + const SymDef* builtin_func = sym::lookup_symbol(func_name.str); + const SymValFunc* func_val = builtin_func ? dynamic_cast(builtin_func->value) : nullptr; + if (!func_val || !func_val->is_builtin()) { + lex.cur().error("`builtin` used for non-builtin function"); + } +#ifdef FUNC_DEBUG + // in release, we don't need this check, since `builtin` is used only in stdlib.fc, which is our responsibility + if (!func_val->sym_type->equals_to(func_type) || func_val->is_marked_as_pure() != marked_as_pure) { + lex.cur().error("declaration for `builtin` function doesn't match an actual one"); + } +#endif + lex.next(); + lex.expect(';'); + return; + } + if (lex.tp() != ';' && lex.tp() != '{' && lex.tp() != _Asm) { + lex.expect('{', "function body block"); + } if (verbosity >= 1) { std::cerr << "function " << func_name.str << " : " << func_type << std::endl; } From de570873d7f62c0a82df3916375dd7398790551b Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Wed, 8 May 2024 13:24:11 +0300 Subject: [PATCH 17/30] [FunC] Add builtin functions to stdlib.fc Note, that I have not added all builtin functions. I filtered out strange and actually unused in practice, like "int_at()" and similar, or "run_method0()" and similar. (Probably, they should be dropped off even from builtins) Also, I've modified some stdlib.fc legacy tests just to ensure that a resulting hash doesn't change. --- .../bsc-bridge-collector/stdlib.fc | 35 ++++++-- .../auto-tests/legacy_tests/config/stdlib.fc | 35 ++++++-- .../legacy_tests/dns-collection/stdlib.fc | 35 ++++++-- .../auto-tests/legacy_tests/elector/stdlib.fc | 35 ++++++-- .../eth-bridge-multisig/stdlib.fc | 35 ++++++-- .../legacy_tests/gg-marketplace/stdlib.fc | 37 +++++--- .../jetton-minter/imports/stdlib.fc | 35 ++++++-- .../jetton-wallet/imports/stdlib.fc | 35 ++++++-- .../legacy_tests/nft-collection/stdlib.fc | 37 +++++--- crypto/smartcont/stdlib.fc | 89 +++++++++++++++---- 10 files changed, 307 insertions(+), 101 deletions(-) diff --git a/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc b/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc index b168d558b..3fac94f11 100644 --- a/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc @@ -21,12 +21,16 @@ forall X -> X first(tuple t) pure asm "FIRST"; forall X -> X second(tuple t) pure asm "SECOND"; forall X -> X third(tuple t) pure asm "THIRD"; forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X -> X at(tuple t, int index) pure builtin; forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; forall X -> X null() pure asm "PUSHNULL"; +forall X -> int null?(X x) pure builtin; +forall X -> X touch(X x) pure builtin; +forall X -> (X, ()) ~touch(X x) pure builtin; forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; int now() pure asm "NOW"; @@ -47,8 +51,15 @@ int check_data_signature(slice data, slice signature, int public_key) pure asm " (int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; (int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -// () throw_if(int excno, int cond) asm "THROWARGIF"; +() throw(int excno) builtin; +() throw_if(int excno, int cond) builtin; +() throw_unless(int excno, int cond) builtin; +forall X -> () throw_arg(X x, int excno) builtin; +forall X -> () throw_arg_if(X x, int excno, int cond) builtin; +forall X -> () throw_arg_unless(X x, int excno, int cond) builtin; +forall X -> (X, ()) ~dump(X x) builtin; +forall X -> (X, ()) ~strdump(X x) builtin; () dump_stack() asm "DUMPSTK"; cell get_data() pure asm "c4 PUSH"; @@ -66,17 +77,23 @@ int min(int x, int y) pure asm "MIN"; int max(int x, int y) pure asm "MAX"; (int, int) minmax(int x, int y) pure asm "MINMAX"; int abs(int x) pure asm "ABS"; +(int, int) divmod(int x, int y) pure builtin; +(int, int) moddiv(int x, int y) pure builtin; +int muldiv(int x, int y, int z) pure builtin; +int muldivr(int x, int y, int z) pure builtin; +int muldivc(int x, int y, int z) pure builtin; +(int, int) muldivmod(int x, int y, int z) pure builtin; slice begin_parse(cell c) pure asm "CTOS"; () end_parse(slice s) asm "ENDS"; (slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; cell preload_ref(slice s) pure asm "PLDREF"; -// (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; -// (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; -// int preload_int(slice s, int len) pure asm "PLDIX"; -// int preload_uint(slice s, int len) pure asm "PLDUX"; -// (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; -// slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_int(slice s, int len) pure builtin; +(slice, int) load_uint(slice s, int len) pure builtin; +int preload_int(slice s, int len) pure builtin; +int preload_uint(slice s, int len) pure builtin; +(slice, slice) load_bits(slice s, int len) pure builtin; +slice preload_bits(slice s, int len) pure builtin; (slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; (slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; @@ -109,8 +126,8 @@ int builder_depth(builder b) pure asm "BDEPTH"; builder begin_cell() pure asm "NEWC"; cell end_cell(builder b) pure asm "ENDC"; builder store_ref(builder b, cell c) pure asm(c b) "STREF"; -// builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; -// builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_uint(builder b, int x, int len) pure builtin; +builder store_int(builder b, int x, int len) pure builtin; builder store_slice(builder b, slice s) pure asm "STSLICER"; builder store_grams(builder b, int x) pure asm "STGRAMS"; builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; diff --git a/crypto/func/auto-tests/legacy_tests/config/stdlib.fc b/crypto/func/auto-tests/legacy_tests/config/stdlib.fc index 5614d76fb..f85fd9072 100644 --- a/crypto/func/auto-tests/legacy_tests/config/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/config/stdlib.fc @@ -21,12 +21,16 @@ forall X -> X first(tuple t) pure asm "FIRST"; forall X -> X second(tuple t) pure asm "SECOND"; forall X -> X third(tuple t) pure asm "THIRD"; forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X -> X at(tuple t, int index) pure builtin; forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; forall X -> X null() pure asm "PUSHNULL"; +forall X -> int null?(X x) pure builtin; +forall X -> X touch(X x) pure builtin; +forall X -> (X, ()) ~touch(X x) pure builtin; forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; int now() pure asm "NOW"; @@ -47,8 +51,15 @@ int check_data_signature(slice data, slice signature, int public_key) pure asm " (int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; (int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -;; () throw_if(int excno, int cond) asm "THROWARGIF"; +() throw(int excno) builtin; +() throw_if(int excno, int cond) builtin; +() throw_unless(int excno, int cond) builtin; +forall X -> () throw_arg(X x, int excno) builtin; +forall X -> () throw_arg_if(X x, int excno, int cond) builtin; +forall X -> () throw_arg_unless(X x, int excno, int cond) builtin; +forall X -> (X, ()) ~dump(X x) builtin; +forall X -> (X, ()) ~strdump(X x) builtin; () dump_stack() asm "DUMPSTK"; cell get_data() pure asm "c4 PUSH"; @@ -66,17 +77,23 @@ int min(int x, int y) pure asm "MIN"; int max(int x, int y) pure asm "MAX"; (int, int) minmax(int x, int y) pure asm "MINMAX"; int abs(int x) pure asm "ABS"; +(int, int) divmod(int x, int y) pure builtin; +(int, int) moddiv(int x, int y) pure builtin; +int muldiv(int x, int y, int z) pure builtin; +int muldivr(int x, int y, int z) pure builtin; +int muldivc(int x, int y, int z) pure builtin; +(int, int) muldivmod(int x, int y, int z) pure builtin; slice begin_parse(cell c) pure asm "CTOS"; () end_parse(slice s) asm "ENDS"; (slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; cell preload_ref(slice s) pure asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) pure asm "PLDIX"; -;; int preload_uint(slice s, int len) pure asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_int(slice s, int len) pure builtin; +(slice, int) load_uint(slice s, int len) pure builtin; +int preload_int(slice s, int len) pure builtin; +int preload_uint(slice s, int len) pure builtin; +(slice, slice) load_bits(slice s, int len) pure builtin; +slice preload_bits(slice s, int len) pure builtin; (slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; (slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; @@ -109,8 +126,8 @@ int builder_depth(builder b) pure asm "BDEPTH"; builder begin_cell() pure asm "NEWC"; cell end_cell(builder b) pure asm "ENDC"; builder store_ref(builder b, cell c) pure asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_uint(builder b, int x, int len) pure builtin; +builder store_int(builder b, int x, int len) pure builtin; builder store_slice(builder b, slice s) pure asm "STSLICER"; builder store_grams(builder b, int x) pure asm "STGRAMS"; builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; diff --git a/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc b/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc index aaa71720f..f07218152 100644 --- a/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc @@ -21,12 +21,16 @@ forall X -> X first(tuple t) pure asm "FIRST"; forall X -> X second(tuple t) pure asm "SECOND"; forall X -> X third(tuple t) pure asm "THIRD"; forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X -> X at(tuple t, int index) pure builtin; forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; forall X -> X null() pure asm "PUSHNULL"; +forall X -> int null?(X x) pure builtin; +forall X -> X touch(X x) pure builtin; +forall X -> (X, ()) ~touch(X x) pure builtin; forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; int now() pure asm "NOW"; @@ -47,8 +51,15 @@ int check_data_signature(slice data, slice signature, int public_key) pure asm " (int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; (int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -;; () throw_if(int excno, int cond) asm "THROWARGIF"; +() throw(int excno) builtin; +() throw_if(int excno, int cond) builtin; +() throw_unless(int excno, int cond) builtin; +forall X -> () throw_arg(X x, int excno) builtin; +forall X -> () throw_arg_if(X x, int excno, int cond) builtin; +forall X -> () throw_arg_unless(X x, int excno, int cond) builtin; +forall X -> (X, ()) ~dump(X x) builtin; +forall X -> (X, ()) ~strdump(X x) builtin; () dump_stack() asm "DUMPSTK"; cell get_data() pure asm "c4 PUSH"; @@ -66,17 +77,23 @@ int min(int x, int y) pure asm "MIN"; int max(int x, int y) pure asm "MAX"; (int, int) minmax(int x, int y) pure asm "MINMAX"; int abs(int x) pure asm "ABS"; +(int, int) divmod(int x, int y) pure builtin; +(int, int) moddiv(int x, int y) pure builtin; +int muldiv(int x, int y, int z) pure builtin; +int muldivr(int x, int y, int z) pure builtin; +int muldivc(int x, int y, int z) pure builtin; +(int, int) muldivmod(int x, int y, int z) pure builtin; slice begin_parse(cell c) pure asm "CTOS"; () end_parse(slice s) asm "ENDS"; (slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; cell preload_ref(slice s) pure asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) pure asm "PLDIX"; -;; int preload_uint(slice s, int len) pure asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_int(slice s, int len) pure builtin; +(slice, int) load_uint(slice s, int len) pure builtin; +int preload_int(slice s, int len) pure builtin; +int preload_uint(slice s, int len) pure builtin; +(slice, slice) load_bits(slice s, int len) pure builtin; +slice preload_bits(slice s, int len) pure builtin; (slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; (slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; @@ -109,8 +126,8 @@ int builder_depth(builder b) pure asm "BDEPTH"; builder begin_cell() pure asm "NEWC"; cell end_cell(builder b) pure asm "ENDC"; builder store_ref(builder b, cell c) pure asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_uint(builder b, int x, int len) pure builtin; +builder store_int(builder b, int x, int len) pure builtin; builder store_slice(builder b, slice s) pure asm "STSLICER"; builder store_grams(builder b, int x) pure asm "STGRAMS"; builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; diff --git a/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc b/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc index 8d0224d02..49af552bb 100644 --- a/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc @@ -21,12 +21,16 @@ forall X -> X first(tuple t) pure asm "FIRST"; forall X -> X second(tuple t) pure asm "SECOND"; forall X -> X third(tuple t) pure asm "THIRD"; forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X -> X at(tuple t, int index) pure builtin; forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; forall X -> X null() pure asm "PUSHNULL"; +forall X -> int null?(X x) pure builtin; +forall X -> X touch(X x) pure builtin; +forall X -> (X, ()) ~touch(X x) pure builtin; forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; int now() pure asm "NOW"; @@ -47,8 +51,15 @@ int check_data_signature(slice data, slice signature, int public_key) pure asm " (int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; (int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -// () throw_if(int excno, int cond) asm "THROWARGIF"; +() throw(int excno) builtin; +() throw_if(int excno, int cond) builtin; +() throw_unless(int excno, int cond) builtin; +forall X -> () throw_arg(X x, int excno) builtin; +forall X -> () throw_arg_if(X x, int excno, int cond) builtin; +forall X -> () throw_arg_unless(X x, int excno, int cond) builtin; +forall X -> (X, ()) ~dump(X x) builtin; +forall X -> (X, ()) ~strdump(X x) builtin; () dump_stack() asm "DUMPSTK"; cell get_data() pure asm "c4 PUSH"; @@ -66,17 +77,23 @@ int min(int x, int y) pure asm "MIN"; int max(int x, int y) pure asm "MAX"; (int, int) minmax(int x, int y) pure asm "MINMAX"; int abs(int x) pure asm "ABS"; +(int, int) divmod(int x, int y) pure builtin; +(int, int) moddiv(int x, int y) pure builtin; +int muldiv(int x, int y, int z) pure builtin; +int muldivr(int x, int y, int z) pure builtin; +int muldivc(int x, int y, int z) pure builtin; +(int, int) muldivmod(int x, int y, int z) pure builtin; slice begin_parse(cell c) pure asm "CTOS"; () end_parse(slice s) asm "ENDS"; (slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; cell preload_ref(slice s) pure asm "PLDREF"; -// (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; -// (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; -// int preload_int(slice s, int len) pure asm "PLDIX"; -// int preload_uint(slice s, int len) pure asm "PLDUX"; -// (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; -// slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_int(slice s, int len) pure builtin; +(slice, int) load_uint(slice s, int len) pure builtin; +int preload_int(slice s, int len) pure builtin; +int preload_uint(slice s, int len) pure builtin; +(slice, slice) load_bits(slice s, int len) pure builtin; +slice preload_bits(slice s, int len) pure builtin; (slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; (slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; @@ -109,8 +126,8 @@ int builder_depth(builder b) pure asm "BDEPTH"; builder begin_cell() pure asm "NEWC"; cell end_cell(builder b) pure asm "ENDC"; builder store_ref(builder b, cell c) pure asm(c b) "STREF"; -// builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; -// builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_uint(builder b, int x, int len) pure builtin; +builder store_int(builder b, int x, int len) pure builtin; builder store_slice(builder b, slice s) pure asm "STSLICER"; builder store_grams(builder b, int x) pure asm "STGRAMS"; builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; diff --git a/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc b/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc index 15d7bcbe8..9fb900c51 100644 --- a/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc @@ -21,12 +21,16 @@ forall X -> X first(tuple t) pure asm "FIRST"; forall X -> X second(tuple t) pure asm "SECOND"; forall X -> X third(tuple t) pure asm "THIRD"; forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X -> X at(tuple t, int index) pure builtin; forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; forall X -> X null() pure asm "PUSHNULL"; +forall X -> int null?(X x) pure builtin; +forall X -> X touch(X x) pure builtin; +forall X -> (X, ()) ~touch(X x) pure builtin; forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; int now() pure asm "NOW"; @@ -47,8 +51,15 @@ int check_data_signature(slice data, slice signature, int public_key) pure asm " (int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; (int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -;; () throw_if(int excno, int cond) asm "THROWARGIF"; +() throw(int excno) builtin; +() throw_if(int excno, int cond) builtin; +() throw_unless(int excno, int cond) builtin; +forall X -> () throw_arg(X x, int excno) builtin; +forall X -> () throw_arg_if(X x, int excno, int cond) builtin; +forall X -> () throw_arg_unless(X x, int excno, int cond) builtin; +forall X -> (X, ()) ~dump(X x) builtin; +forall X -> (X, ()) ~strdump(X x) builtin; () dump_stack() asm "DUMPSTK"; cell get_data() pure asm "c4 PUSH"; @@ -66,17 +77,23 @@ int min(int x, int y) pure asm "MIN"; int max(int x, int y) pure asm "MAX"; (int, int) minmax(int x, int y) pure asm "MINMAX"; int abs(int x) pure asm "ABS"; +(int, int) divmod(int x, int y) pure builtin; +(int, int) moddiv(int x, int y) pure builtin; +int muldiv(int x, int y, int z) pure builtin; +int muldivr(int x, int y, int z) pure builtin; +int muldivc(int x, int y, int z) pure builtin; +(int, int) muldivmod(int x, int y, int z) pure builtin; slice begin_parse(cell c) pure asm "CTOS"; () end_parse(slice s) asm "ENDS"; (slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; cell preload_ref(slice s) pure asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) pure asm "PLDIX"; -;; int preload_uint(slice s, int len) pure asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_int(slice s, int len) pure builtin; +(slice, int) load_uint(slice s, int len) pure builtin; +int preload_int(slice s, int len) pure builtin; +int preload_uint(slice s, int len) pure builtin; +(slice, slice) load_bits(slice s, int len) pure builtin; +slice preload_bits(slice s, int len) pure builtin; (slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; (slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; @@ -109,8 +126,8 @@ int builder_depth(builder b) pure asm "BDEPTH"; builder begin_cell() pure asm "NEWC"; cell end_cell(builder b) pure asm "ENDC"; builder store_ref(builder b, cell c) pure asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_uint(builder b, int x, int len) pure builtin; +builder store_int(builder b, int x, int len) pure builtin; builder store_slice(builder b, slice s) pure asm "STSLICER"; builder store_grams(builder b, int x) pure asm "STGRAMS"; builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; diff --git a/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc b/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc index f4b671bd9..ddcb2396f 100644 --- a/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc @@ -21,12 +21,16 @@ forall X -> X first(tuple t) pure asm "FIRST"; forall X -> X second(tuple t) pure asm "SECOND"; forall X -> X third(tuple t) pure asm "THIRD"; forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X -> X at(tuple t, int index) pure builtin; forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; forall X -> X null() pure asm "PUSHNULL"; +forall X -> int null?(X x) pure builtin; +forall X -> X touch(X x) pure builtin; +forall X -> (X, ()) ~touch(X x) pure builtin; forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; int now() pure asm "NOW"; @@ -47,8 +51,15 @@ int check_data_signature(slice data, slice signature, int public_key) pure asm " (int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; (int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -;; () throw_if(int excno, int cond) asm "THROWARGIF"; +() throw(int excno) builtin; +() throw_if(int excno, int cond) builtin; +() throw_unless(int excno, int cond) builtin; +forall X -> () throw_arg(X x, int excno) builtin; +forall X -> () throw_arg_if(X x, int excno, int cond) builtin; +forall X -> () throw_arg_unless(X x, int excno, int cond) builtin; +forall X -> (X, ()) ~dump(X x) builtin; +forall X -> (X, ()) ~strdump(X x) builtin; () dump_stack() asm "DUMPSTK"; cell get_data() pure asm "c4 PUSH"; @@ -66,17 +77,23 @@ int min(int x, int y) pure asm "MIN"; int max(int x, int y) pure asm "MAX"; (int, int) minmax(int x, int y) pure asm "MINMAX"; int abs(int x) pure asm "ABS"; +(int, int) divmod(int x, int y) pure builtin; +(int, int) moddiv(int x, int y) pure builtin; +int muldiv(int x, int y, int z) pure builtin; +int muldivr(int x, int y, int z) pure builtin; +int muldivc(int x, int y, int z) pure builtin; +(int, int) muldivmod(int x, int y, int z) pure builtin; slice begin_parse(cell c) pure asm "CTOS"; () end_parse(slice s) asm "ENDS"; (slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; cell preload_ref(slice s) pure asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) pure asm "PLDIX"; -;; int preload_uint(slice s, int len) pure asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_int(slice s, int len) pure builtin; +(slice, int) load_uint(slice s, int len) pure builtin; +int preload_int(slice s, int len) pure builtin; +int preload_uint(slice s, int len) pure builtin; +(slice, slice) load_bits(slice s, int len) pure builtin; +slice preload_bits(slice s, int len) pure builtin; (slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; (slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; @@ -108,9 +125,9 @@ int builder_depth(builder b) pure asm "BDEPTH"; builder begin_cell() pure asm "NEWC"; cell end_cell(builder b) pure asm "ENDC"; - builder store_ref(builder b, cell c) pure asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +builder store_uint(builder b, int x, int len) pure builtin; +builder store_int(builder b, int x, int len) pure builtin; builder store_slice(builder b, slice s) pure asm "STSLICER"; builder store_grams(builder b, int x) pure asm "STGRAMS"; builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; diff --git a/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc b/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc index a76e869dc..ddcb2396f 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc @@ -21,12 +21,16 @@ forall X -> X first(tuple t) pure asm "FIRST"; forall X -> X second(tuple t) pure asm "SECOND"; forall X -> X third(tuple t) pure asm "THIRD"; forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X -> X at(tuple t, int index) pure builtin; forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; forall X -> X null() pure asm "PUSHNULL"; +forall X -> int null?(X x) pure builtin; +forall X -> X touch(X x) pure builtin; +forall X -> (X, ()) ~touch(X x) pure builtin; forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; int now() pure asm "NOW"; @@ -47,8 +51,15 @@ int check_data_signature(slice data, slice signature, int public_key) pure asm " (int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; (int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -;; () throw_if(int excno, int cond) asm "THROWARGIF"; +() throw(int excno) builtin; +() throw_if(int excno, int cond) builtin; +() throw_unless(int excno, int cond) builtin; +forall X -> () throw_arg(X x, int excno) builtin; +forall X -> () throw_arg_if(X x, int excno, int cond) builtin; +forall X -> () throw_arg_unless(X x, int excno, int cond) builtin; +forall X -> (X, ()) ~dump(X x) builtin; +forall X -> (X, ()) ~strdump(X x) builtin; () dump_stack() asm "DUMPSTK"; cell get_data() pure asm "c4 PUSH"; @@ -66,17 +77,23 @@ int min(int x, int y) pure asm "MIN"; int max(int x, int y) pure asm "MAX"; (int, int) minmax(int x, int y) pure asm "MINMAX"; int abs(int x) pure asm "ABS"; +(int, int) divmod(int x, int y) pure builtin; +(int, int) moddiv(int x, int y) pure builtin; +int muldiv(int x, int y, int z) pure builtin; +int muldivr(int x, int y, int z) pure builtin; +int muldivc(int x, int y, int z) pure builtin; +(int, int) muldivmod(int x, int y, int z) pure builtin; slice begin_parse(cell c) pure asm "CTOS"; () end_parse(slice s) asm "ENDS"; (slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; cell preload_ref(slice s) pure asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) pure asm "PLDIX"; -;; int preload_uint(slice s, int len) pure asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_int(slice s, int len) pure builtin; +(slice, int) load_uint(slice s, int len) pure builtin; +int preload_int(slice s, int len) pure builtin; +int preload_uint(slice s, int len) pure builtin; +(slice, slice) load_bits(slice s, int len) pure builtin; +slice preload_bits(slice s, int len) pure builtin; (slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; (slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; @@ -109,8 +126,8 @@ int builder_depth(builder b) pure asm "BDEPTH"; builder begin_cell() pure asm "NEWC"; cell end_cell(builder b) pure asm "ENDC"; builder store_ref(builder b, cell c) pure asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_uint(builder b, int x, int len) pure builtin; +builder store_int(builder b, int x, int len) pure builtin; builder store_slice(builder b, slice s) pure asm "STSLICER"; builder store_grams(builder b, int x) pure asm "STGRAMS"; builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; diff --git a/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc b/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc index a76e869dc..ddcb2396f 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc @@ -21,12 +21,16 @@ forall X -> X first(tuple t) pure asm "FIRST"; forall X -> X second(tuple t) pure asm "SECOND"; forall X -> X third(tuple t) pure asm "THIRD"; forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X -> X at(tuple t, int index) pure builtin; forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; forall X -> X null() pure asm "PUSHNULL"; +forall X -> int null?(X x) pure builtin; +forall X -> X touch(X x) pure builtin; +forall X -> (X, ()) ~touch(X x) pure builtin; forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; int now() pure asm "NOW"; @@ -47,8 +51,15 @@ int check_data_signature(slice data, slice signature, int public_key) pure asm " (int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; (int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -;; () throw_if(int excno, int cond) asm "THROWARGIF"; +() throw(int excno) builtin; +() throw_if(int excno, int cond) builtin; +() throw_unless(int excno, int cond) builtin; +forall X -> () throw_arg(X x, int excno) builtin; +forall X -> () throw_arg_if(X x, int excno, int cond) builtin; +forall X -> () throw_arg_unless(X x, int excno, int cond) builtin; +forall X -> (X, ()) ~dump(X x) builtin; +forall X -> (X, ()) ~strdump(X x) builtin; () dump_stack() asm "DUMPSTK"; cell get_data() pure asm "c4 PUSH"; @@ -66,17 +77,23 @@ int min(int x, int y) pure asm "MIN"; int max(int x, int y) pure asm "MAX"; (int, int) minmax(int x, int y) pure asm "MINMAX"; int abs(int x) pure asm "ABS"; +(int, int) divmod(int x, int y) pure builtin; +(int, int) moddiv(int x, int y) pure builtin; +int muldiv(int x, int y, int z) pure builtin; +int muldivr(int x, int y, int z) pure builtin; +int muldivc(int x, int y, int z) pure builtin; +(int, int) muldivmod(int x, int y, int z) pure builtin; slice begin_parse(cell c) pure asm "CTOS"; () end_parse(slice s) asm "ENDS"; (slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; cell preload_ref(slice s) pure asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) pure asm "PLDIX"; -;; int preload_uint(slice s, int len) pure asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_int(slice s, int len) pure builtin; +(slice, int) load_uint(slice s, int len) pure builtin; +int preload_int(slice s, int len) pure builtin; +int preload_uint(slice s, int len) pure builtin; +(slice, slice) load_bits(slice s, int len) pure builtin; +slice preload_bits(slice s, int len) pure builtin; (slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; (slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; @@ -109,8 +126,8 @@ int builder_depth(builder b) pure asm "BDEPTH"; builder begin_cell() pure asm "NEWC"; cell end_cell(builder b) pure asm "ENDC"; builder store_ref(builder b, cell c) pure asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_uint(builder b, int x, int len) pure builtin; +builder store_int(builder b, int x, int len) pure builtin; builder store_slice(builder b, slice s) pure asm "STSLICER"; builder store_grams(builder b, int x) pure asm "STGRAMS"; builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; diff --git a/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc b/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc index f4b671bd9..ddcb2396f 100644 --- a/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc @@ -21,12 +21,16 @@ forall X -> X first(tuple t) pure asm "FIRST"; forall X -> X second(tuple t) pure asm "SECOND"; forall X -> X third(tuple t) pure asm "THIRD"; forall X -> X fourth(tuple t) pure asm "3 INDEX"; +forall X -> X at(tuple t, int index) pure builtin; forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; forall X, Y -> Y pair_second([X, Y] p) pure asm "SECOND"; forall X, Y, Z -> X triple_first([X, Y, Z] p) pure asm "FIRST"; forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND"; forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; forall X -> X null() pure asm "PUSHNULL"; +forall X -> int null?(X x) pure builtin; +forall X -> X touch(X x) pure builtin; +forall X -> (X, ()) ~touch(X x) pure builtin; forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; int now() pure asm "NOW"; @@ -47,8 +51,15 @@ int check_data_signature(slice data, slice signature, int public_key) pure asm " (int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; (int, int, int, int) slice_compute_data_size?(cell c, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -;; () throw_if(int excno, int cond) asm "THROWARGIF"; +() throw(int excno) builtin; +() throw_if(int excno, int cond) builtin; +() throw_unless(int excno, int cond) builtin; +forall X -> () throw_arg(X x, int excno) builtin; +forall X -> () throw_arg_if(X x, int excno, int cond) builtin; +forall X -> () throw_arg_unless(X x, int excno, int cond) builtin; +forall X -> (X, ()) ~dump(X x) builtin; +forall X -> (X, ()) ~strdump(X x) builtin; () dump_stack() asm "DUMPSTK"; cell get_data() pure asm "c4 PUSH"; @@ -66,17 +77,23 @@ int min(int x, int y) pure asm "MIN"; int max(int x, int y) pure asm "MAX"; (int, int) minmax(int x, int y) pure asm "MINMAX"; int abs(int x) pure asm "ABS"; +(int, int) divmod(int x, int y) pure builtin; +(int, int) moddiv(int x, int y) pure builtin; +int muldiv(int x, int y, int z) pure builtin; +int muldivr(int x, int y, int z) pure builtin; +int muldivc(int x, int y, int z) pure builtin; +(int, int) muldivmod(int x, int y, int z) pure builtin; slice begin_parse(cell c) pure asm "CTOS"; () end_parse(slice s) asm "ENDS"; (slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; cell preload_ref(slice s) pure asm "PLDREF"; -;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) pure asm "PLDIX"; -;; int preload_uint(slice s, int len) pure asm "PLDUX"; -;; (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; -;; slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +(slice, int) load_int(slice s, int len) pure builtin; +(slice, int) load_uint(slice s, int len) pure builtin; +int preload_int(slice s, int len) pure builtin; +int preload_uint(slice s, int len) pure builtin; +(slice, slice) load_bits(slice s, int len) pure builtin; +slice preload_bits(slice s, int len) pure builtin; (slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; (slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST"; @@ -108,9 +125,9 @@ int builder_depth(builder b) pure asm "BDEPTH"; builder begin_cell() pure asm "NEWC"; cell end_cell(builder b) pure asm "ENDC"; - builder store_ref(builder b, cell c) pure asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_ref(builder b, cell c) pure asm(c b) "STREF"; +builder store_uint(builder b, int x, int len) pure builtin; +builder store_int(builder b, int x, int len) pure builtin; builder store_slice(builder b, slice s) pure asm "STSLICER"; builder store_grams(builder b, int x) pure asm "STGRAMS"; builder store_dict(builder b, cell c) pure asm(c b) "STDICT"; diff --git a/crypto/smartcont/stdlib.fc b/crypto/smartcont/stdlib.fc index 9540603a0..bf6d738b6 100644 --- a/crypto/smartcont/stdlib.fc +++ b/crypto/smartcont/stdlib.fc @@ -93,6 +93,9 @@ forall X -> X third(tuple t) pure asm "THIRD"; /// Returns the fourth element of a tuple (with unknown element types). forall X -> X fourth(tuple t) pure asm "3 INDEX"; +/// Returns the [`index`]-th element of tuple [`t`]. +forall X -> X at(tuple t, int index) pure builtin; + /// Returns the first element of a pair tuple. forall X, Y -> X pair_first([X, Y] p) pure asm "FIRST"; @@ -114,7 +117,16 @@ forall X, Y, Z -> Z triple_third([X, Y, Z] p) pure asm "THIRD"; /// So `null` can actually have any atomic type. forall X -> X null() pure asm "PUSHNULL"; -/// Moves a variable [x] to the top of the stack +/// Checks whether the argument is null. +forall X -> int null?(X x) pure builtin; + +/// Moves a variable [x] to the top of the stack. +forall X -> X touch(X x) pure builtin; + +/// Moves a variable [x] to the top of the stack. +forall X -> (X, ()) ~touch(X x) pure builtin; + +/// Mark a variable as used, such that the code which produced it won't be deleted even if it is not impure. forall X -> (X, ()) ~impure_touch(X x) asm "NOP"; @@ -199,13 +211,38 @@ int check_data_signature(slice data, slice signature, int public_key) pure asm " /// however, the data bits and the cell references of [s] are accounted for in `y` and `z`. (int, int, int, int) slice_compute_data_size?(slice s, int max_cells) pure asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; -/// Throws an exception with exit_code excno if cond is not 0 (commented since implemented in compilator) -// () throw_if(int excno, int cond) asm "THROWARGIF"; +/// Throws exception [`excno`] with parameter zero. +/// In other words, it transfers control to the continuation in `c2`, +/// pushing `0` and [`excno`] into it's stack, and discarding the old stack altogether. +() throw(int excno) builtin; + +/// Throws exception [`excno`] with parameter zero only if [`cond`] != `0`. +() throw_if(int excno, int cond) builtin; + +/// Throws exception [`excno`] with parameter zero only if [`cond`] == `0`. +() throw_unless(int excno, int cond) builtin; + +/// Throws exception [`excno`] with parameter [`x`], +/// by copying [`x`] and [`excno`] into the stack of `c2` and transferring control to `c2`. +forall X -> () throw_arg(X x, int excno) builtin; + +/// Throws exception [`excno`] with parameter [`x`] only if [`cond`] != `0`. +forall X -> () throw_arg_if(X x, int excno, int cond) builtin; + +/// Throws exception [`excno`] with parameter [`x`] only if [`cond`] == `0`. +forall X -> () throw_arg_unless(X x, int excno, int cond) builtin; /*** # Debug primitives Only works for local TVM execution with debug level verbosity */ + +/// Dump a variable [x] to the debug log. +forall X -> (X, ()) ~dump(X x) builtin; + +/// Dump a string [x] to the debug log. +forall X -> (X, ()) ~strdump(X x) builtin; + /// Dumps the stack (at most the top 255 values) and shows the total stack depth. () dump_stack() asm "DUMPSTK"; @@ -277,6 +314,25 @@ int max(int x, int y) pure asm "MAX"; /// Computes the absolute value of an integer [x]. int abs(int x) pure asm "ABS"; +/// Computes the quotient and remainder of [x] / [y]. Example: divmod(112,3) = (37,1) +(int, int) divmod(int x, int y) pure builtin; + +/// Computes the remainder and quotient of [x] / [y]. Example: moddiv(112,3) = (1,37) +(int, int) moddiv(int x, int y) pure builtin; + +/// Computes multiple-then-divide: floor([x] * [y] / [z]). +/// The intermediate result is stored in a 513-bit integer to prevent precision loss. +int muldiv(int x, int y, int z) pure builtin; + +/// Similar to `muldiv`, but rounds the result: round([x] * [y] / [z]). +int muldivr(int x, int y, int z) pure builtin; + +/// Similar to `muldiv`, but ceils the result: ceil([x] * [y] / [z]). +int muldivc(int x, int y, int z) pure builtin; + +/// Computes the quotient and remainder of ([x] * [y] / [z]). Example: muldivmod(112,3,10) = (33,6) +(int, int) muldivmod(int x, int y, int z) pure builtin; + /* # Slice primitives @@ -305,25 +361,23 @@ slice begin_parse(cell c) pure asm "CTOS"; /// Preloads the first reference from the slice. cell preload_ref(slice s) pure asm "PLDREF"; - /* Functions below are commented because are implemented on compilator level for optimisation */ - /// Loads a signed [len]-bit integer from a slice [s]. -// (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; +(slice, int) load_int(slice s, int len) pure builtin; /// Loads an unsigned [len]-bit integer from a slice [s]. -// (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; +(slice, int) load_uint(slice s, int len) pure builtin; /// Preloads a signed [len]-bit integer from a slice [s]. -// int preload_int(slice s, int len) pure asm "PLDIX"; +int preload_int(slice s, int len) pure builtin; /// Preloads an unsigned [len]-bit integer from a slice [s]. -// int preload_uint(slice s, int len) pure asm "PLDUX"; +int preload_uint(slice s, int len) pure builtin; -/// Loads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. -// (slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; +/// Loads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate slice `s''`. +(slice, slice) load_bits(slice s, int len) pure builtin; -/// Preloads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`. -// slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; +/// Preloads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate slice `s''`. +slice preload_bits(slice s, int len) pure builtin; /// Loads serialized amount of TonCoins (any unsigned integer up to `2^120 - 1`). (slice, int) load_grams(slice s) pure asm( -> 1 0) "LDGRAMS"; @@ -432,13 +486,12 @@ cell end_cell(builder b) pure asm "ENDC"; builder store_ref(builder b, cell c) pure asm(c b) "STREF"; /// Stores an unsigned [len]-bit integer `x` into `b` for `0 ≤ len ≤ 256`. -// builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; - -/// Stores a signed [len]-bit integer `x` into `b` for` 0 ≤ len ≤ 257`. -// builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; +builder store_uint(builder b, int x, int len) pure builtin; +/// Stores a signed [len]-bit integer `x` into `b` for `0 ≤ len ≤ 257`. +builder store_int(builder b, int x, int len) pure builtin; -/// Stores `slice` [s] into `builder` [b] +/// Stores `slice` [s] into `builder` [b]. builder store_slice(builder b, slice s) pure asm "STSLICER"; /// Stores (serializes) an integer [x] in the range `0..2^120 − 1` into `builder` [b]. From bb86dc0f96044feaebd2cae7543332d856008c43 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Fri, 10 May 2024 15:38:28 +0300 Subject: [PATCH 18/30] [FunC] Add an ability to deprecate pragmas --- crypto/func/func.cpp | 31 +++++++++++++++++++++++++++++++ crypto/func/func.h | 21 ++++----------------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/crypto/func/func.cpp b/crypto/func/func.cpp index 416376b84..7847184f5 100644 --- a/crypto/func/func.cpp +++ b/crypto/func/func.cpp @@ -77,6 +77,37 @@ bool SymValCodeFunc::does_need_codegen() const { // in the future, we may want to implement a true AST inlining for `inline` functions also } +void GlobalPragma::enable(SrcLocation loc) { + if (deprecated_from_v_) { + loc.show_warning(PSTRING() << "#pragma " << name_ << + " is deprecated since FunC v" << deprecated_from_v_ << + ". Please, remove this line from your code."); + return; + } + + enabled_ = true; + locs_.push_back(std::move(loc)); +} + +void GlobalPragma::check_enable_in_libs() { + if (locs_.empty()) { + return; + } + for (const SrcLocation& loc : locs_) { + if (loc.fdescr->is_main) { + return; + } + } + locs_[0].show_warning(PSTRING() << "#pragma " << name_ + << " is enabled in included libraries, it may change the behavior of your code. " + << "Add this #pragma to the main source file to suppress this warning."); +} + +void GlobalPragma::always_on_and_deprecated(const char *deprecated_from_v) { + deprecated_from_v_ = deprecated_from_v; + enabled_ = true; +} + td::Result fs_read_callback(ReadCallback::Kind kind, const char* query) { switch (kind) { case ReadCallback::Kind::ReadFile: { diff --git a/crypto/func/func.h b/crypto/func/func.h index 07737cb98..140641895 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -1769,27 +1769,14 @@ class GlobalPragma { bool enabled() const { return enabled_; } - void enable(SrcLocation loc) { - enabled_ = true; - locs_.push_back(std::move(loc)); - } - void check_enable_in_libs() { - if (locs_.empty()) { - return; - } - for (const SrcLocation& loc : locs_) { - if (loc.fdescr->is_main) { - return; - } - } - locs_[0].show_warning(PSTRING() << "#pragma " << name_ - << " is enabled in included libraries, it may change the behavior of your code. " - << "Add this #pragma to the main source file to suppress this warning."); - } + void enable(SrcLocation loc); + void check_enable_in_libs(); + void always_on_and_deprecated(const char *deprecated_from_v); private: std::string name_; bool enabled_ = false; + const char *deprecated_from_v_ = nullptr; std::vector locs_; }; extern GlobalPragma pragma_allow_post_modification, pragma_compute_asm_ltr, pragma_remove_unused_functions; From aaf3ca335d3362e1c28a81d67063d4d84a73154c Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Fri, 10 May 2024 15:56:11 +0300 Subject: [PATCH 19/30] [FunC] Deprecate pragma allow-post-modification All tests pass: it does not affect hashes (since modifying variables in a single expression was an error) --- .../tests/allow_post_modification.fc | 2 -- crypto/func/func.cpp | 2 +- crypto/func/func.h | 2 +- crypto/func/gen-abscode.cpp | 27 +++++++------------ crypto/func/parse-func.cpp | 6 ----- 5 files changed, 12 insertions(+), 27 deletions(-) diff --git a/crypto/func/auto-tests/tests/allow_post_modification.fc b/crypto/func/auto-tests/tests/allow_post_modification.fc index 36a310316..02bfc7ae1 100644 --- a/crypto/func/auto-tests/tests/allow_post_modification.fc +++ b/crypto/func/auto-tests/tests/allow_post_modification.fc @@ -1,5 +1,3 @@ -#pragma allow-post-modification; - forall X -> tuple unsafe_tuple(X x) asm "NOP"; (int, int) inc(int x, int y) { diff --git a/crypto/func/func.cpp b/crypto/func/func.cpp index 7847184f5..e3e871b4b 100644 --- a/crypto/func/func.cpp +++ b/crypto/func/func.cpp @@ -347,6 +347,7 @@ int func_proceed(const std::vector &sources, std::ostream &outs, st funC::define_keywords(); funC::define_builtins(); + pragma_allow_post_modification.always_on_and_deprecated("0.5.0"); int ok = 0, proc = 0; try { @@ -365,7 +366,6 @@ int func_proceed(const std::vector &sources, std::ostream &outs, st if (!proc) { throw src::Fatal{"no source files, no output"}; } - pragma_allow_post_modification.check_enable_in_libs(); pragma_compute_asm_ltr.check_enable_in_libs(); pragma_remove_unused_functions.check_enable_in_libs(); return funC::generate_output(outs, errs); diff --git a/crypto/func/func.h b/crypto/func/func.h index 140641895..d0fddef61 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -686,7 +686,7 @@ typedef std::vector FormalArgList; struct AsmOpList; struct CodeBlob { - enum { _AllowPostModification = 1, _ComputeAsmLtr = 2, _ForbidImpure = 4 }; + enum { _ComputeAsmLtr = 2, _ForbidImpure = 4 }; int var_cnt, in_var_cnt, op_cnt; TypeExpr* ret_type; std::string name; diff --git a/crypto/func/gen-abscode.cpp b/crypto/func/gen-abscode.cpp index 5e8a8761d..52ba33cda 100644 --- a/crypto/func/gen-abscode.cpp +++ b/crypto/func/gen-abscode.cpp @@ -286,24 +286,17 @@ std::vector pre_compile_tensor(const std::vector args, CodeBl res_lists[i] = args[i]->pre_compile(code, lval_globs); for (size_t j = 0; j < res_lists[i].size(); ++j) { TmpVar& var = code.vars.at(res_lists[i][j]); - if (code.flags & CodeBlob::_AllowPostModification) { - if (!lval_globs && (var.cls & TmpVar::_Named)) { - Op *op = &code.emplace_back(nullptr, Op::_Let, std::vector(), std::vector()); - op->set_disabled(); - var.on_modification.push_back([modified_vars, i, j, op, done = false](const SrcLocation &here) mutable { - if (!done) { - done = true; - modified_vars->push_back({i, j, op}); - } - }); - } else { - var.on_modification.push_back([](const SrcLocation &) { - }); - } + if (!lval_globs && (var.cls & TmpVar::_Named)) { + Op *op = &code.emplace_back(nullptr, Op::_Let, std::vector(), std::vector()); + op->set_disabled(); + var.on_modification.push_back([modified_vars, i, j, op, done = false](const SrcLocation &here) mutable { + if (!done) { + done = true; + modified_vars->push_back({i, j, op}); + } + }); } else { - var.on_modification.push_back([name = var.to_string()](const SrcLocation &here) { - throw src::ParseError{here, PSTRING() << "Modifying local variable " << name - << " after using it in the same expression"}; + var.on_modification.push_back([](const SrcLocation &) { }); } } diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index b06933dbe..6573df709 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -266,9 +266,6 @@ void parse_const_decl(Lexer& lex) { } lex.next(); CodeBlob code; - if (pragma_allow_post_modification.enabled()) { - code.flags |= CodeBlob::_AllowPostModification; - } if (pragma_compute_asm_ltr.enabled()) { code.flags |= CodeBlob::_ComputeAsmLtr; } @@ -1219,9 +1216,6 @@ blk_fl::val parse_stmt(Lexer& lex, CodeBlob& code) { CodeBlob* parse_func_body(Lexer& lex, FormalArgList arg_list, TypeExpr* ret_type, bool marked_as_pure) { lex.expect('{'); CodeBlob* blob = new CodeBlob{ret_type}; - if (pragma_allow_post_modification.enabled()) { - blob->flags |= CodeBlob::_AllowPostModification; - } if (pragma_compute_asm_ltr.enabled()) { blob->flags |= CodeBlob::_ComputeAsmLtr; } From 1e4b20a06105ee16abf33f4ebd1c3a58b4513122 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Fri, 10 May 2024 16:08:50 +0300 Subject: [PATCH 20/30] [FunC] Deprecate pragma compute-asm-ltr It changes all hashes, since the compiler needs to manipulate the stack in a different way now. --- crypto/func/auto-tests/legacy_tests.jsonl | 38 ++++++++----------- .../tests/allow_post_modification.fc | 6 +-- crypto/func/auto-tests/tests/asm_arg_order.fc | 12 +++--- crypto/func/auto-tests/tests/camel1.fc | 16 ++++---- crypto/func/auto-tests/tests/camel2.fc | 2 - crypto/func/auto-tests/tests/co1.fc | 2 +- crypto/func/auto-tests/tests/s1.fc | 2 +- crypto/func/func.cpp | 2 +- crypto/func/func.h | 2 +- crypto/func/gen-abscode.cpp | 24 +++--------- crypto/func/parse-func.cpp | 6 --- 11 files changed, 41 insertions(+), 71 deletions(-) diff --git a/crypto/func/auto-tests/legacy_tests.jsonl b/crypto/func/auto-tests/legacy_tests.jsonl index 06d58a8f3..422be1038 100644 --- a/crypto/func/auto-tests/legacy_tests.jsonl +++ b/crypto/func/auto-tests/legacy_tests.jsonl @@ -4,32 +4,26 @@ // and is parsed just using regexp ^\[\s*"(.*?)"\s*,\s*(.*?)\s*] // Some tests can be commented out, or they can be multiline, it works. -// note, that deployed version of elector,config and multisig differ since it is compiled with func-0.1.0. -// Newer compilers optimize arithmetic and logic expression that can be calculated at the compile time -["elector/elector-code.fc", 115226404411715505328583639896096915745686314074575650766750648324043316883483] -["config/config-code.fc", 10913070768607625342121305745084703121685937915388357634624451844356456145601] -["eth-bridge-multisig/multisig-code.fc", 101509909129354488841890823627011033360100627957439967918234053299675481277954] +// Since pragma compute-asm-ltr became deprecated (and always on), it changed all hashes +["elector/elector-code.fc", 96915288474895095375636985346314354662782784860648058159878921867365312683154] +["config/config-code.fc", 22290399841823616942485152190379024190655691555189464909245612965253206016940] +["eth-bridge-multisig/multisig-code.fc", 61794576422183943960272839720117943378686303983578297509099019523440847170337] -["bsc-bridge-collector/votes-collector.fc", 62190447221288642706570413295807615918589884489514159926097051017036969900417] -["uni-lock-wallet/uni-lockup-wallet.fc", 61959738324779104851267145467044677651344601417998258530238254441977103654381] -["nft-collection/nft-collection-editable.fc", 45561997735512210616567774035540357815786262097548276229169737015839077731274] -["dns-collection/nft-collection.fc", 107999822699841936063083742021519765435859194241091312445235370766165379261859] +["bsc-bridge-collector/votes-collector.fc", 92944270384900724656771477263840139047476985690583064733832286422277180224175] +["uni-lock-wallet/uni-lockup-wallet.fc", 27323712737699566411771249412638860892056222617959925563185009479925143218351] +["nft-collection/nft-collection-editable.fc", 3265272879406938912616104900469474227258611213495548733729957432831667074606] +["dns-collection/nft-collection.fc", 50100285311144683401305558797522852568981620193836838830789475785944491291928] -// note, that deployed version of tele-nft-item differs since it is compiled with func-0.3.0. -// After introducing of try/catch construction, c2 register is not always the default one. -// Thus it is necessary to save it upon jumps, differences of deployed and below compiled is that -// "c2 SAVE" is added to the beginning of recv_internal. It does not change behavior. -["tele-nft-item/nft-item.fc", 69777543125381987786450436977742010705076866061362104025338034583422166453344] +["tele-nft-item/nft-item.fc", 112456603551352598193405120624678866030139400186800709562240012518003340977105] -["storage/storage-contract.fc", 91377830060355733016937375216020277778264560226873154627574229667513068328151] -["storage/storage-provider.fc", 13618336676213331164384407184540461509022654507176709588621016553953760588122] -["nominator-pool/pool.fc", 69767057279163099864792356875696330339149706521019810113334238732928422055375] -["jetton-minter/jetton-minter.fc", 9028309926287301331466371999814928201427184114165428257502393474125007156494] -["gg-marketplace/nft-marketplace-v2.fc", 92199806964112524639740773542356508485601908152150843819273107618799016205930] -["jetton-wallet/jetton-wallet.fc", 86251125787443633057458168028617933212663498001665054651523310772884328206542] -// (May 2024) reordered includes, they were in a wrong order -["whales-nominators/nominators.fc", 64989185004203073400683226767264384908045055609681310145961012819587514238303] +["storage/storage-contract.fc", 44542652015163304335966522853331133393011733370692441537470366854345658892851] +["storage/storage-provider.fc", 108677173951298337060746154977967122806502520160062519672276937694037317935577] +["nominator-pool/pool.fc", 113824867250406571749406540634759859835643042958487527298742314026185451318138] +["jetton-minter/jetton-minter.fc", 59172251235013928378816323931018560572240088017859486196396002876800156186183] +["gg-marketplace/nft-marketplace-v2.fc", 65550944551194537105854154716861234168502062117999272754502885031166440057836] +["jetton-wallet/jetton-wallet.fc", 26109413028643307141901410795152471606217725316052170190064118584402007124948] +["whales-nominators/nominators.fc", 32017040532734767645954674692768344406402364921654403435168703583553605058036] // (April 2024) tact hashes changed, because '__tact_address_eq()' is now inlined as a wrapper diff --git a/crypto/func/auto-tests/tests/allow_post_modification.fc b/crypto/func/auto-tests/tests/allow_post_modification.fc index 02bfc7ae1..b2f3be636 100644 --- a/crypto/func/auto-tests/tests/allow_post_modification.fc +++ b/crypto/func/auto-tests/tests/allow_post_modification.fc @@ -51,8 +51,6 @@ tuple test_tuple(int x) method_id(13) { return asm_func(x, x += 1, x, x, x~inc(x / 20), x, x = x * 2); } -#pragma compute-asm-ltr; - (int, int, int, int, int, int, int) test_call_asm_new(int x) method_id(18) { return asm_func(x, x~incWrap(x / 20), x, x = x * 2, x, x += 1, x); } @@ -83,11 +81,11 @@ TESTCASE | 13 | 100 | [ 100 50 105 210 210 211 211 ] TESTCASE | 14 | 100 | 100 50 105 210 210 211 211 TESTCASE | 15 | 100 | 100 50 105 210 210 211 211 TESTCASE | 16 | 100 | 100 50 105 210 210 211 211 -TESTCASE | 17 | 100 | 100 50 105 210 210 211 211 +TESTCASE | 17 | 100 | 101 50 106 212 100 101 101 TESTCASE | 18 | 100 | 210 210 211 211 100 50 105 TESTCASE | 19 | 100 | 100 50 105 210 210 211 211 TESTCASE | 20 | 80 | 80 89 1 8 8 TESTCASE | 20 | 9 | 9 -40 -10 -1 13 -@code_hash 67078680159561921827850021610104736412668316252257881932102553152922274405210 +@code_hash 91381947614024372269097215913018978221053550615790649489637387647848569490128 -} diff --git a/crypto/func/auto-tests/tests/asm_arg_order.fc b/crypto/func/auto-tests/tests/asm_arg_order.fc index 8e056cacf..ad6f7cc97 100644 --- a/crypto/func/auto-tests/tests/asm_arg_order.fc +++ b/crypto/func/auto-tests/tests/asm_arg_order.fc @@ -60,8 +60,6 @@ int foo(int x) { return (t, t2); } -#pragma compute-asm-ltr; - (tuple, tuple) test_new_1() method_id(21) { t = empty_tuple(); tuple t2 = asmFunc1(foo(11), foo(22), foo(33)); @@ -105,11 +103,11 @@ int foo(int x) { {- method_id | in | out TESTCASE | 11 | | [ 11 22 33 ] [ 110 220 330 ] -TESTCASE | 12 | | [ 33 22 11 ] [ 330 220 110 ] -TESTCASE | 13 | | [ 22 33 11 ] [ 220 330 110 ] +TESTCASE | 12 | | [ 11 22 33 ] [ 330 220 110 ] +TESTCASE | 13 | | [ 11 22 33 ] [ 220 330 110 ] TESTCASE | 14 | | [ 11 22 33 44 55 ] [ 220 330 440 110 550 ] -TESTCASE | 15 | | [ 33 22 ] [ 220 330 ] -TESTCASE | 16 | | [ 22 33 11 ] [ 220 330 110 ] +TESTCASE | 15 | | [ 22 33 ] [ 220 330 ] +TESTCASE | 16 | | [ 11 22 33 ] [ 220 330 110 ] TESTCASE | 21 | | [ 11 22 33 ] [ 110 220 330 ] TESTCASE | 22 | | [ 11 22 33 ] [ 330 220 110 ] TESTCASE | 23 | | [ 11 22 33 ] [ 220 330 110 ] @@ -117,5 +115,5 @@ TESTCASE | 24 | | [ 11 22 33 44 55 ] [ 220 330 440 110 550 ] TESTCASE | 25 | | [ 22 33 ] [ 220 330 ] TESTCASE | 26 | | [ 11 22 33 ] [ 220 330 110 ] -@code_hash 53895312198338603934600244087571743055624960603383611438828666636202841531600 +@code_hash 93068291567112337250118419287631047120002003622184251973082208096953112184588 -} diff --git a/crypto/func/auto-tests/tests/camel1.fc b/crypto/func/auto-tests/tests/camel1.fc index 705264682..0a3d276f5 100644 --- a/crypto/func/auto-tests/tests/camel1.fc +++ b/crypto/func/auto-tests/tests/camel1.fc @@ -152,8 +152,9 @@ TESTCASE | 103 | | [ 12 [] 34 91 ] // NEWC // _5 ENDC // to_be_ref - 123 PUSHINT // to_be_ref _8=123 - NEWC // to_be_ref _8=123 _9 + NEWC // to_be_ref _8 + 123 PUSHINT // to_be_ref _8 _9=123 + SWAP // to_be_ref _9=123 _8 8 STU // to_be_ref in_c STREF // in_c ENDC // _16 @@ -186,13 +187,12 @@ TESTCASE | 103 | | [ 12 [] 34 91 ] 16 PUSHINT // dict minv _57=16 SDSKIPFIRST // dict minv ... - 32 PUSHINT // dict minv1 minv2 minv3 found123 _78=456 dict _79=32 + 32 PUSHINT // dict minv1 minv2 minv3 found123 found456 _83=32 + 789 PUSHINT // dict minv1 minv2 minv3 found123 found456 _83=32 _84=789 + s0 s7 s7 XCHG3 // found456 minv1 minv2 minv3 found123 _84=789 dict _83=32 DICTIGET - NULLSWAPIFNOT // dict minv1 minv2 minv3 found123 _99 _100 - 789 PUSHINT - s2 POP - s0 s6 XCHG - 32 PUSHINT // found456 minv1 minv2 minv3 found123 _83=789 dict _84=32 + NULLSWAPIFNOT // found456 minv1 minv2 minv3 found123 _101 _102 + NIP // found456 minv1 minv2 minv3 found123 found789 ... 4 TUPLE // _86 }> diff --git a/crypto/func/auto-tests/tests/camel2.fc b/crypto/func/auto-tests/tests/camel2.fc index 463597a63..59a7ba323 100644 --- a/crypto/func/auto-tests/tests/camel2.fc +++ b/crypto/func/auto-tests/tests/camel2.fc @@ -5,8 +5,6 @@ ;; But swapping arguments may sometimes lead to bytecode changes (see test2), ;; both with compute-asm-ltr and without it. -#pragma compute-asm-ltr; - builder begin_cell() pure asm "NEWC"; cell end_cell(builder b) pure asm "ENDC"; slice begin_parse(cell c) pure asm "CTOS"; diff --git a/crypto/func/auto-tests/tests/co1.fc b/crypto/func/auto-tests/tests/co1.fc index b6fbd77c1..b57d973bd 100644 --- a/crypto/func/auto-tests/tests/co1.fc +++ b/crypto/func/auto-tests/tests/co1.fc @@ -62,5 +62,5 @@ _ main() { {- TESTCASE | 0 | | 0 -@code_hash 98157584761932576648981760908342408003231747902562138202913714302941716912743 +@code_hash 61273295789179921867241079778489100375537711211918844448475493726205774530743 -} diff --git a/crypto/func/auto-tests/tests/s1.fc b/crypto/func/auto-tests/tests/s1.fc index ef9977070..aa7e52c59 100644 --- a/crypto/func/auto-tests/tests/s1.fc +++ b/crypto/func/auto-tests/tests/s1.fc @@ -52,5 +52,5 @@ _ main() { {- TESTCASE | 0 | | 0 -@code_hash 35542701048549611407499491204004197688673151742407097578098250360682143458214 +@code_hash 13830542019509784148027107880226447201604257839069192762244575629978154217223 -} diff --git a/crypto/func/func.cpp b/crypto/func/func.cpp index e3e871b4b..b06f49057 100644 --- a/crypto/func/func.cpp +++ b/crypto/func/func.cpp @@ -348,6 +348,7 @@ int func_proceed(const std::vector &sources, std::ostream &outs, st funC::define_keywords(); funC::define_builtins(); pragma_allow_post_modification.always_on_and_deprecated("0.5.0"); + pragma_compute_asm_ltr.always_on_and_deprecated("0.5.0"); int ok = 0, proc = 0; try { @@ -366,7 +367,6 @@ int func_proceed(const std::vector &sources, std::ostream &outs, st if (!proc) { throw src::Fatal{"no source files, no output"}; } - pragma_compute_asm_ltr.check_enable_in_libs(); pragma_remove_unused_functions.check_enable_in_libs(); return funC::generate_output(outs, errs); } catch (src::Fatal& fatal) { diff --git a/crypto/func/func.h b/crypto/func/func.h index d0fddef61..04c7e8305 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -686,7 +686,7 @@ typedef std::vector FormalArgList; struct AsmOpList; struct CodeBlob { - enum { _ComputeAsmLtr = 2, _ForbidImpure = 4 }; + enum { _ForbidImpure = 4 }; int var_cnt, in_var_cnt, op_cnt; TypeExpr* ret_type; std::string name; diff --git a/crypto/func/gen-abscode.cpp b/crypto/func/gen-abscode.cpp index 52ba33cda..9d71ec5b5 100644 --- a/crypto/func/gen-abscode.cpp +++ b/crypto/func/gen-abscode.cpp @@ -267,14 +267,8 @@ std::vector pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, con return right; } -std::vector pre_compile_tensor(const std::vector args, CodeBlob &code, - std::vector> *lval_globs, - std::vector arg_order) { - if (arg_order.empty()) { - arg_order.resize(args.size()); - std::iota(arg_order.begin(), arg_order.end(), 0); - } - func_assert(args.size() == arg_order.size()); +std::vector pre_compile_tensor(const std::vector& args, CodeBlob &code, + std::vector> *lval_globs) { std::vector> res_lists(args.size()); struct ModifiedVar { @@ -282,7 +276,7 @@ std::vector pre_compile_tensor(const std::vector args, CodeBl Op* op; }; auto modified_vars = std::make_shared>(); - for (size_t i : arg_order) { + for (size_t i = 0; i < args.size(); ++i) { res_lists[i] = args[i]->pre_compile(code, lval_globs); for (size_t j = 0; j < res_lists[i].size(); ++j) { TmpVar& var = code.vars.at(res_lists[i][j]); @@ -329,7 +323,7 @@ std::vector Expr::pre_compile(CodeBlob& code, std::vector Expr::pre_compile(CodeBlob& code, std::vectornext.get(); } applied_sym = op_call->fun_ref; - func = dynamic_cast(applied_sym->value); - // soon we'll get rid of this pragma: it will be always on, we'll pass just {} here and below - bool compute_asm_ltr = code.flags & CodeBlob::_ComputeAsmLtr; // a function may call anotherF with shuffled arguments: f(x,y) { return anotherF(y,x) } // then op_call looks like (_1,_0), so use op_call->right for correct positions in Op::_Call below // it's correct, since every argument has width 1 - std::vector res_inner = pre_compile_tensor(args, code, lval_globs, compute_asm_ltr ? std::vector{} : func->arg_order); + std::vector res_inner = pre_compile_tensor(args, code, lval_globs); res.reserve(res_inner.size()); for (var_idx_t right_idx : op_call->right) { res.emplace_back(res_inner[right_idx]); } - } else if (func && func->arg_order.size() == args.size() && !(code.flags & CodeBlob::_ComputeAsmLtr)) { - //std::cerr << "!!! reordering " << args.size() << " arguments of " << sym->name() << std::endl; - res = pre_compile_tensor(args, code, lval_globs, func->arg_order); } else { - res = pre_compile_tensor(args, code, lval_globs, {}); + res = pre_compile_tensor(args, code, lval_globs); } auto rvect = new_tmp_vect(code); auto& op = code.emplace_back(here, Op::_Call, rvect, res, applied_sym); diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index 6573df709..0f17a0c3f 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -266,9 +266,6 @@ void parse_const_decl(Lexer& lex) { } lex.next(); CodeBlob code; - if (pragma_compute_asm_ltr.enabled()) { - code.flags |= CodeBlob::_ComputeAsmLtr; - } // Handles processing and resolution of literals and consts auto x = parse_expr(lex, code, false); // also does lex.next() ! if (x->flags != Expr::_IsRvalue) { @@ -1216,9 +1213,6 @@ blk_fl::val parse_stmt(Lexer& lex, CodeBlob& code) { CodeBlob* parse_func_body(Lexer& lex, FormalArgList arg_list, TypeExpr* ret_type, bool marked_as_pure) { lex.expect('{'); CodeBlob* blob = new CodeBlob{ret_type}; - if (pragma_compute_asm_ltr.enabled()) { - blob->flags |= CodeBlob::_ComputeAsmLtr; - } if (marked_as_pure) { blob->flags |= CodeBlob::_ForbidImpure; } From aee51731ce66cdfca285df3d5627b26385d5484f Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Fri, 10 May 2024 16:34:15 +0300 Subject: [PATCH 21/30] [FunC] Refactor allow-post-modification, stop producing disabled Op::_Let Before, #pragma allow-post-modification produced Op::_Let for every tensor entity (which became non-disabled if modification really happened). Although they are stripped off by the compiler and don't affect fif output, they pollute intermediate "AST" representation (ops). Now, Op::_Let is added only if var modification actually happens (which is very uncommon for real-wise code) --- crypto/func/gen-abscode.cpp | 43 +++++++++++++++++++++---------------- crypto/func/parse-func.cpp | 3 --- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/crypto/func/gen-abscode.cpp b/crypto/func/gen-abscode.cpp index 9d71ec5b5..bba42bd93 100644 --- a/crypto/func/gen-abscode.cpp +++ b/crypto/func/gen-abscode.cpp @@ -269,24 +269,29 @@ std::vector pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, con std::vector pre_compile_tensor(const std::vector& args, CodeBlob &code, std::vector> *lval_globs) { - std::vector> res_lists(args.size()); + const size_t n = args.size(); + if (n == 0) { // just `()` + return {}; + } + if (n == 1) { // just `(x)`: even if x is modified (e.g. `f(x=x+2)`), there are no next arguments + return args[0]->pre_compile(code, lval_globs); + } + std::vector> res_lists(n); struct ModifiedVar { size_t i, j; - Op* op; + std::unique_ptr* cur_ops; // `LET tmp = v_ij` will be inserted before this }; - auto modified_vars = std::make_shared>(); - for (size_t i = 0; i < args.size(); ++i) { + std::vector modified_vars; + for (size_t i = 0; i < n; ++i) { res_lists[i] = args[i]->pre_compile(code, lval_globs); for (size_t j = 0; j < res_lists[i].size(); ++j) { TmpVar& var = code.vars.at(res_lists[i][j]); if (!lval_globs && (var.cls & TmpVar::_Named)) { - Op *op = &code.emplace_back(nullptr, Op::_Let, std::vector(), std::vector()); - op->set_disabled(); - var.on_modification.push_back([modified_vars, i, j, op, done = false](const SrcLocation &here) mutable { + var.on_modification.push_back([&modified_vars, i, j, cur_ops = code.cur_ops, done = false](const SrcLocation &here) mutable { if (!done) { done = true; - modified_vars->push_back({i, j, op}); + modified_vars.push_back({i, j, cur_ops}); } }); } else { @@ -301,13 +306,16 @@ std::vector pre_compile_tensor(const std::vector& args, CodeB code.vars.at(v).on_modification.pop_back(); } } - for (const ModifiedVar &m : *modified_vars) { - var_idx_t& v = res_lists[m.i][m.j]; - var_idx_t v2 = code.create_tmp_var(code.vars[v].v_type, code.vars[v].where.get()); - m.op->left = {v2}; - m.op->right = {v}; - m.op->set_disabled(false); - v = v2; + for (size_t idx = modified_vars.size(); idx--; ) { + const ModifiedVar &m = modified_vars[idx]; + var_idx_t orig_v = res_lists[m.i][m.j]; + var_idx_t tmp_v = code.create_tmp_var(code.vars[orig_v].v_type, code.vars[orig_v].where.get()); + std::unique_ptr op = std::make_unique(*code.vars[orig_v].where, Op::_Let); + op->left = {tmp_v}; + op->right = {orig_v}; + op->next = std::move((*m.cur_ops)); + *m.cur_ops = std::move(op); + res_lists[m.i][m.j] = tmp_v; } std::vector res; for (const auto& list : res_lists) { @@ -333,10 +341,7 @@ std::vector Expr::pre_compile(CodeBlob& code, std::vectoris_just_wrapper_for_another_f()) { // body is { Op::_Import; Op::_Call; Op::_Return; } - const Op *op_call = dynamic_cast(func)->code->ops.get(); - while (op_call->cl != Op::_Call) { - op_call = op_call->next.get(); - } + const std::unique_ptr& op_call = dynamic_cast(func)->code->ops->next; applied_sym = op_call->fun_ref; // a function may call anotherF with shuffled arguments: f(x,y) { return anotherF(y,x) } // then op_call looks like (_1,_0), so use op_call->right for correct positions in Op::_Call below diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index 0f17a0c3f..c58732f80 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -1431,10 +1431,7 @@ void detect_if_function_just_wraps_another(SymValCodeFunc* v_current, const td:: func_assert(op_import && op_import->cl == Op::_Import); // then Op::_Call (anotherF) - // when pragma allow-post-modification, it might be prepended with empty Op::_Let todo I don't like this const Op* op_call = op_import->next.get(); - while (op_call && op_call->cl == Op::_Let && op_call->disabled()) - op_call = op_call->next.get(); if (!op_call || op_call->cl != Op::_Call) return; func_assert(op_call->left.size() == 1); From 7afa9292c3262b965fe418c23203ab1d0189cfc0 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Sat, 11 May 2024 13:57:42 +0300 Subject: [PATCH 22/30] [FunC] Change priority of `& | ^` operators to a more intuitive one Before, such code `if (slices_equal() & status == 1)` was parsed as `if( (slices_equal()&status) == 1 )`. Note, that this change leads to hash changes of some verified contracts, but a new priority is more expected from the user experience. --- .../whales-nominators/modules/model.fc | 4 +- crypto/func/auto-tests/tests/op_priority.fc | 48 +++++++++++++++++++ crypto/func/parse-func.cpp | 33 ++++++++++--- 3 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 crypto/func/auto-tests/tests/op_priority.fc diff --git a/crypto/func/auto-tests/legacy_tests/whales-nominators/modules/model.fc b/crypto/func/auto-tests/legacy_tests/whales-nominators/modules/model.fc index 9c28b42a1..102b64ee0 100644 --- a/crypto/func/auto-tests/legacy_tests/whales-nominators/modules/model.fc +++ b/crypto/func/auto-tests/legacy_tests/whales-nominators/modules/model.fc @@ -137,7 +137,7 @@ int apply_profit(int value, int value_profit, int profit) { } ;; Try to withdraw from withdraw balance - if ((remaining > 0) & ctx_member_withdraw > 0) { + if (((remaining > 0) & ctx_member_withdraw) > 0) { ;; such strange brackets to remain hash stable after & priority fix int delta = min(ctx_member_withdraw, remaining); ctx_member_withdraw = ctx_member_withdraw - delta; ctx_balance_withdraw = ctx_balance_withdraw - delta; @@ -294,4 +294,4 @@ int owned_balance() { ;; Reset sent amount ctx_balance_sent = 0; -} \ No newline at end of file +} diff --git a/crypto/func/auto-tests/tests/op_priority.fc b/crypto/func/auto-tests/tests/op_priority.fc new file mode 100644 index 000000000..f8eff74cc --- /dev/null +++ b/crypto/func/auto-tests/tests/op_priority.fc @@ -0,0 +1,48 @@ +int justTrue() { return true; } + +int test1(int x, int y, int z) method_id(101) { + return x > 0 & y > 0 & z > 0; +} + +int test2(int x, int y, int z) method_id(102) { + return x > (0 & y > 0 & z > 0); +} + +int test3(int x, int y, int z) method_id(103) { + if (x < 0 | y < 0) { + return z < 0; + } + return x > 0 & y > 0; +} + +int test4(int x, int y, int mode) method_id(104) { + if (mode == 1) { + return x == 10 | (y == 20); + } if (mode == 2) { + return x == 10 | y == 20; + } else { + return x == (10 | (y == 20)); + } +} + +int test5(int status) method_id(105) { + return justTrue() & status == 1 & (justTrue() & status) == 1; +} + +() main() { } + +{- +TESTCASE | 101 | 1 2 3 | -1 +TESTCASE | 101 | 1 0 3 | 0 +TESTCASE | 101 | 1 2 -1 | 0 +TESTCASE | 102 | 1 0 0 | -1 +TESTCASE | 103 | -1 -2 -3 | -1 +TESTCASE | 103 | -1 -2 0 | 0 +TESTCASE | 103 | 1 2 0 | -1 +TESTCASE | 103 | 1 0 2 | 0 +TESTCASE | 104 | 10 20 1 | -1 +TESTCASE | 104 | 10 20 2 | -1 +TESTCASE | 104 | 10 20 3 | 0 +TESTCASE | 105 | 1 | -1 +TESTCASE | 105 | 0 | 0 +-} diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index c58732f80..07e8b8add 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -787,11 +787,11 @@ Expr* parse_expr75(Lexer& lex, CodeBlob& code, bool nv) { } } -// parse E { (* | / | % | /% ) E } +// parse E { (* | / | % | /% | ^/ | ~/ | ^% | ~% ) E } Expr* parse_expr30(Lexer& lex, CodeBlob& code, bool nv) { Expr* res = parse_expr75(lex, code, nv); while (lex.tp() == '*' || lex.tp() == '/' || lex.tp() == '%' || lex.tp() == _DivMod || lex.tp() == _DivC || - lex.tp() == _DivR || lex.tp() == _ModC || lex.tp() == _ModR || lex.tp() == '&') { + lex.tp() == _DivR || lex.tp() == _ModC || lex.tp() == _ModR) { res->chk_rvalue(lex.cur()); int t = lex.tp(); sym_idx_t name = symbols.lookup_add(std::string{"_"} + lex.cur().str + "_"); @@ -809,7 +809,7 @@ Expr* parse_expr30(Lexer& lex, CodeBlob& code, bool nv) { return res; } -// parse [-] E { (+ | - | `|` | ^) E } +// parse [-] E { (+ | -) E } Expr* parse_expr20(Lexer& lex, CodeBlob& code, bool nv) { Expr* res; int t = lex.tp(); @@ -828,7 +828,7 @@ Expr* parse_expr20(Lexer& lex, CodeBlob& code, bool nv) { } else { res = parse_expr30(lex, code, nv); } - while (lex.tp() == '-' || lex.tp() == '+' || lex.tp() == '|' || lex.tp() == '^') { + while (lex.tp() == '-' || lex.tp() == '+') { res->chk_rvalue(lex.cur()); t = lex.tp(); sym_idx_t name = symbols.lookup_add(std::string{"_"} + lex.cur().str + "_"); @@ -846,7 +846,7 @@ Expr* parse_expr20(Lexer& lex, CodeBlob& code, bool nv) { return res; } -// parse E { ( << | >> | >>~ | >>^ ) E } +// parse E { ( << | >> | ~>> | ^>> ) E } Expr* parse_expr17(Lexer& lex, CodeBlob& code, bool nv) { Expr* res = parse_expr20(lex, code, nv); while (lex.tp() == _Lshift || lex.tp() == _Rshift || lex.tp() == _RshiftC || lex.tp() == _RshiftR) { @@ -889,9 +889,30 @@ Expr* parse_expr15(Lexer& lex, CodeBlob& code, bool nv) { return res; } +// parse E { ( & | `|` | ^ ) E } +Expr* parse_expr14(Lexer& lex, CodeBlob& code, bool nv) { + Expr* res = parse_expr15(lex, code, nv); + while (lex.tp() == '&' || lex.tp() == '|' || lex.tp() == '^') { + res->chk_rvalue(lex.cur()); + int t = lex.tp(); + sym_idx_t name = symbols.lookup_add(std::string{"_"} + lex.cur().str + "_"); + check_global_func(lex.cur(), name); + SrcLocation loc{lex.cur().loc}; + lex.next(); + auto x = parse_expr15(lex, code, false); + x->chk_rvalue(lex.cur()); + res = new Expr{Expr::_Apply, name, {res, x}}; + res->here = loc; + res->set_val(t); + res->flags = Expr::_IsRvalue; + res->deduce_type(lex.cur()); + } + return res; +} + // parse E [ ? E : E ] Expr* parse_expr13(Lexer& lex, CodeBlob& code, bool nv) { - Expr* res = parse_expr15(lex, code, nv); + Expr* res = parse_expr14(lex, code, nv); if (lex.tp() == '?') { res->chk_rvalue(lex.cur()); SrcLocation loc{lex.cur().loc}; From 7b8268d99f18356fffe47f840c27d2f2b0825f07 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Tue, 21 May 2024 15:34:37 +0300 Subject: [PATCH 23/30] [FunC] Deprecate `method_id` specifier, introduce `get` keyword `get` keyword behaves exactly like `method_id` (auto-calc hash), but it's placed on the left, similar to Tact: `get T name()`. `method_id(n)` is still valid, considering it can't be invoked by name, since a client will compute another hash. It's supposed it will be still used in tests and in low-level code (not to be called externally, but to be called after replacing c3). `get(hash)` is invalid, this keyword does not accept anything. --- .../bsc-bridge-collector/votes-collector.fc | 2 +- .../dns-collection/nft-collection.fc | 8 +-- .../eth-bridge-multisig/multisig-code.fc | 8 +-- .../jetton-minter/jetton-minter.fc | 4 +- .../legacy_tests/nominator-pool/pool.fc | 14 ++--- .../legacy_tests/tele-nft-item/nft-item.fc | 14 ++--- .../legacy_tests/wallet-v4/wallet-v4-code.fc | 10 ++-- .../whales-nominators/modules/get.fc | 28 +++++----- crypto/func/auto-tests/tests/camel4.fc | 2 +- .../auto-tests/tests/invalid-get-method-1.fc | 8 +++ crypto/func/auto-tests/tests/s1.fc | 14 ++--- crypto/func/func.h | 5 ++ crypto/func/keywords.cpp | 1 + crypto/func/parse-func.cpp | 53 ++++++++++++------- lite-client/lite-client.cpp | 2 +- tonlib/tonlib/tonlib-cli.cpp | 2 +- 16 files changed, 103 insertions(+), 72 deletions(-) create mode 100644 crypto/func/auto-tests/tests/invalid-get-method-1.fc diff --git a/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/votes-collector.fc b/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/votes-collector.fc index 2a74e3644..20c87e968 100644 --- a/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/votes-collector.fc +++ b/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/votes-collector.fc @@ -103,7 +103,7 @@ cell loadData() { } } -(tuple) get_external_voting_data(int voting_id) method_id { +get (tuple) get_external_voting_data(int voting_id) { cell external_votings = loadData(); (slice voting_data, int found?) = external_votings.udict_get?(256, voting_id); throw_unless(309, found?); diff --git a/crypto/func/auto-tests/legacy_tests/dns-collection/nft-collection.fc b/crypto/func/auto-tests/legacy_tests/dns-collection/nft-collection.fc index aa98945c8..da919ede3 100644 --- a/crypto/func/auto-tests/legacy_tests/dns-collection/nft-collection.fc +++ b/crypto/func/auto-tests/legacy_tests/dns-collection/nft-collection.fc @@ -106,22 +106,22 @@ slice calculate_nft_item_address(int wc, cell state_init) { ;; Get methods -(int, cell, slice) get_collection_data() method_id { +get (int, cell, slice) get_collection_data() { var (content, nft_item_code) = load_data(); return (-1, content, zero_address()); } -slice get_nft_address_by_index(int index) method_id { +get slice get_nft_address_by_index(int index) { var (content, nft_item_code) = load_data(); cell state_init = calculate_nft_item_state_init(index, nft_item_code); return calculate_nft_item_address(workchain(), state_init); } -cell get_nft_content(int index, cell individual_nft_content) method_id { +get cell get_nft_content(int index, cell individual_nft_content) { return individual_nft_content; } -(int, cell) dnsresolve(slice subdomain, int category) method_id { +get (int, cell) dnsresolve(slice subdomain, int category) { throw_unless(70, mod(slice_bits(subdomain), 8) == 0); int starts_with_zero_byte = subdomain.preload_int(8) == 0; diff --git a/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/multisig-code.fc b/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/multisig-code.fc index 0bfdfb727..391ea1a19 100644 --- a/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/multisig-code.fc +++ b/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/multisig-code.fc @@ -248,7 +248,7 @@ _ unpack_owner_info(slice cs) inline_ref { ;; Get methods ;; returns -1 for processed queries, 0 for unprocessed, 1 for unknown (forgotten) -(int, int) get_query_state(int query_id) method_id { +get (int, int) get_query_state(int query_id) { (_, int n, _, int last_cleaned, _, cell pending_queries, _) = unpack_state(); (slice cs, var found) = pending_queries.udict_get?(64, query_id); if (found) { @@ -263,12 +263,12 @@ _ unpack_owner_info(slice cs) inline_ref { } } -int processed?(int query_id) method_id { +get int processed?(int query_id) { (int x, _) = get_query_state(query_id); return x; } -cell create_init_state(int wallet_id, int n, int k, cell owners_info, int spend_delay) method_id { +get cell create_init_state(int wallet_id, int n, int k, cell owners_info, int spend_delay) { return pack_state(new_dict(), owners_info, 0, k, n, wallet_id, spend_delay); } @@ -291,7 +291,7 @@ cell merge_list(cell a, cell b) { } -cell get_public_keys() method_id { +get cell get_public_keys() { (_, _, _, _, cell public_keys, _, _) = unpack_state(); return public_keys; } diff --git a/crypto/func/auto-tests/legacy_tests/jetton-minter/jetton-minter.fc b/crypto/func/auto-tests/legacy_tests/jetton-minter/jetton-minter.fc index 3db37e1c3..be964bfba 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-minter/jetton-minter.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-minter/jetton-minter.fc @@ -111,12 +111,12 @@ throw(0xffff); } -(int, int, slice, cell, cell) get_jetton_data() method_id { +get (int, int, slice, cell, cell) get_jetton_data() { (int total_supply, slice admin_address, cell content, cell jetton_wallet_code) = load_data(); return (total_supply, -1, admin_address, content, jetton_wallet_code); } -slice get_wallet_address(slice owner_address) method_id { +get slice get_wallet_address(slice owner_address) { (int total_supply, slice admin_address, cell content, cell jetton_wallet_code) = load_data(); return calculate_user_jetton_wallet_address(owner_address, my_address(), jetton_wallet_code); } diff --git a/crypto/func/auto-tests/legacy_tests/nominator-pool/pool.fc b/crypto/func/auto-tests/legacy_tests/nominator-pool/pool.fc index 25d6cb389..c12f1884b 100644 --- a/crypto/func/auto-tests/legacy_tests/nominator-pool/pool.fc +++ b/crypto/func/auto-tests/legacy_tests/nominator-pool/pool.fc @@ -674,16 +674,16 @@ cell distribute_share(int reward, cell nominators) inline_ref { ;; Get methods -_ get_pool_data() method_id { +get _ get_pool_data() { return load_data(); } -int has_withdraw_requests() method_id { +get int has_withdraw_requests() { (int state, int nominators_count, int stake_amount_sent, int validator_amount, (int validator_address, int validator_reward_share, int max_nominators_count, int min_validator_stake, int min_nominator_stake), cell nominators, cell withdraw_requests, int stake_at, int saved_validator_set_hash, int validator_set_changes_count, int validator_set_change_time, int stake_held_for, cell config_proposal_votings) = load_data(); return ~ cell_null?(withdraw_requests); } -(int, int, int) get_nominator_data(int nominator_address) method_id { +get (int, int, int) get_nominator_data(int nominator_address) { (int state, int nominators_count, int stake_amount_sent, int validator_amount, (int validator_address, int validator_reward_share, int max_nominators_count, int min_validator_stake, int min_nominator_stake), cell nominators, cell withdraw_requests, int stake_at, int saved_validator_set_hash, int validator_set_changes_count, int validator_set_change_time, int stake_held_for, cell config_proposal_votings) = load_data(); (slice nominator, int found) = nominators.udict_get?(ADDR_SIZE(), nominator_address); @@ -694,11 +694,11 @@ int has_withdraw_requests() method_id { return (amount, pending_deposit_amount, withdraw_found); } -int get_max_punishment(int stake) method_id { +get int get_max_punishment(int stake) { return max_recommended_punishment_for_validator_misbehaviour(stake); } -tuple list_nominators() method_id { +get tuple list_nominators() { (int state, int nominators_count, int stake_amount_sent, int validator_amount, (int validator_address, int validator_reward_share, int max_nominators_count, int min_validator_stake, int min_nominator_stake), cell nominators, cell withdraw_requests, int stake_at, int saved_validator_set_hash, int validator_set_changes_count, int validator_set_change_time, int stake_held_for, cell config_proposal_votings) = load_data(); var list = null(); int address = -1; @@ -713,7 +713,7 @@ tuple list_nominators() method_id { return list; } -tuple list_votes() method_id { +get tuple list_votes() { (int state, int nominators_count, int stake_amount_sent, int validator_amount, (int validator_address, int validator_reward_share, int max_nominators_count, int min_validator_stake, int min_nominator_stake), cell nominators, cell withdraw_requests, int stake_at, int saved_validator_set_hash, int validator_set_changes_count, int validator_set_change_time, int stake_held_for, cell config_proposal_votings) = load_data(); var list = null(); int proposal_hash = -1; @@ -727,7 +727,7 @@ tuple list_votes() method_id { return list; } -tuple list_voters(int proposal_hash) method_id { +get tuple list_voters(int proposal_hash) { (int state, int nominators_count, int stake_amount_sent, int validator_amount, (int validator_address, int validator_reward_share, int max_nominators_count, int min_validator_stake, int min_nominator_stake), cell nominators, cell withdraw_requests, int stake_at, int saved_validator_set_hash, int validator_set_changes_count, int validator_set_change_time, int stake_held_for, cell config_proposal_votings) = load_data(); var list = null(); (slice votes_slice, int found) = config_proposal_votings.udict_get?(256, proposal_hash); diff --git a/crypto/func/auto-tests/legacy_tests/tele-nft-item/nft-item.fc b/crypto/func/auto-tests/legacy_tests/tele-nft-item/nft-item.fc index 93c18edae..f39dd39bb 100644 --- a/crypto/func/auto-tests/legacy_tests/tele-nft-item/nft-item.fc +++ b/crypto/func/auto-tests/legacy_tests/tele-nft-item/nft-item.fc @@ -283,7 +283,7 @@ cell change_dns_record(cell dns, slice in_msg_body) { ;; GET Methods ;; -(int, int, slice, slice, cell) get_nft_data() method_id { +get (int, int, slice, slice, cell) get_nft_data() { (cell config, cell state) = unpack_item_data(); (int item_index, slice collection_address) = unpack_item_config(config); if (cell_null?(state)) { @@ -294,7 +294,7 @@ cell change_dns_record(cell dns, slice in_msg_body) { return (-1, item_index, collection_address, owner_address, nft_content); } -slice get_full_domain() method_id { +get slice get_full_domain() { (cell config, cell state) = unpack_item_data(); (slice owner_address, cell content, cell auction, cell royalty_params) = unpack_item_state(state); (cell nft_content, cell dns, cell token_info) = unpack_item_content(content); @@ -302,7 +302,7 @@ slice get_full_domain() method_id { return begin_cell().store_slice(domain).store_slice(token_name).store_int(0, 8).end_cell().begin_parse(); } -slice get_telemint_token_name() method_id { +get slice get_telemint_token_name() { (cell config, cell state) = unpack_item_data(); (slice owner_address, cell content, cell auction, cell royalty_params) = unpack_item_state(state); (cell nft_content, cell dns, cell token_info) = unpack_item_content(content); @@ -310,7 +310,7 @@ slice get_telemint_token_name() method_id { return token_name; } -(slice, int, int, int, int) get_telemint_auction_state() method_id { +get (slice, int, int, int, int) get_telemint_auction_state() { (cell config, cell state) = unpack_item_data(); (slice owner_address, cell content, cell auction, cell royalty_params) = unpack_item_state(state); throw_if (err::no_auction, cell_null?(auction)); @@ -323,7 +323,7 @@ slice get_telemint_token_name() method_id { return (bidder_address, bid, bid_ts, min_bid, end_time); } -(slice, int, int, int, int, int) get_telemint_auction_config() method_id { +get (slice, int, int, int, int, int) get_telemint_auction_config() { (cell config, cell state) = unpack_item_data(); (slice owner_address, cell content, cell auction, cell royalty_params) = unpack_item_state(state); if (cell_null?(auction)) { @@ -336,14 +336,14 @@ slice get_telemint_token_name() method_id { return (beneficiary_address, initial_min_bid, max_bid, min_bid_step, min_extend_time, duration); } -(int, int, slice) royalty_params() method_id { +get (int, int, slice) royalty_params() { (cell config, cell state) = unpack_item_data(); (slice owner_address, cell content, cell auction, cell royalty_params) = unpack_item_state(state); (int numerator, int denominator, slice destination) = unpack_nft_royalty_params(royalty_params); return (numerator, denominator, destination); } -(int, cell) dnsresolve(slice subdomain, int category) method_id { +get (int, cell) dnsresolve(slice subdomain, int category) { (cell config, cell state) = unpack_item_data(); (slice owner_address, cell content, cell auction, cell royalty_params) = unpack_item_state(state); (cell nft_content, cell dns, cell token_info) = unpack_item_content(content); diff --git a/crypto/func/auto-tests/legacy_tests/wallet-v4/wallet-v4-code.fc b/crypto/func/auto-tests/legacy_tests/wallet-v4/wallet-v4-code.fc index d6fa24d87..fea5faddb 100644 --- a/crypto/func/auto-tests/legacy_tests/wallet-v4/wallet-v4-code.fc +++ b/crypto/func/auto-tests/legacy_tests/wallet-v4/wallet-v4-code.fc @@ -168,27 +168,27 @@ _ skipBits(slice s, int len) { return skip_bits(s, len); } ;; Get methods -int seqno() method_id { +get int seqno() { return get_data().begin_parse().preload_uint(32); } -int get_subwallet_id() method_id { +get int get_subwallet_id() { return get_data().begin_parse().skip_bits(32).preload_uint(32); } -int get_public_key() method_id { +get int get_public_key() { var cs = get_data().begin_parse().skip_bits(64); return cs.preload_uint(256); } -int is_plugin_installed(int wc, int addr_hash) method_id { +get int is_plugin_installed(int wc, int addr_hash) { var ds = get_data().begin_parse().skipBits(32 + 32 + 256); var plugins = ds~load_dict(); var (_, success?) = plugins.dict_get?(8 + 256, begin_cell().store_int(wc, 8).store_uint(addr_hash, 256).end_cell().begin_parse()); return success?; } -tuple get_plugin_list() method_id { +get tuple get_plugin_list() { var list = null(); var ds = get_data().begin_parse().skip_bits(32 + 32 + 256); var plugins = ds~load_dict(); diff --git a/crypto/func/auto-tests/legacy_tests/whales-nominators/modules/get.fc b/crypto/func/auto-tests/legacy_tests/whales-nominators/modules/get.fc index c9152e1cc..8b8cd7386 100644 --- a/crypto/func/auto-tests/legacy_tests/whales-nominators/modules/get.fc +++ b/crypto/func/auto-tests/legacy_tests/whales-nominators/modules/get.fc @@ -2,17 +2,17 @@ ;; Related contracts ;; -_ get_proxy() method_id { +get _ get_proxy() { load_base_data(); return ctx_proxy; } -_ get_owner() method_id { +get _ get_owner() { load_base_data(); return ctx_owner; } -_ get_controller() method_id { +get _ get_controller() { load_base_data(); return ctx_controller; } @@ -21,13 +21,13 @@ _ get_controller() method_id { ;; Balances for controller ;; -_ get_unowned() method_id { +get _ get_unowned() { load_base_data(); var [balance, extra] = get_balance(); return max(balance - owned_balance(), 0); } -_ get_available() method_id { +get _ get_available() { load_base_data(); return ctx_balance - ctx_balance_sent; } @@ -36,7 +36,7 @@ _ get_available() method_id { ;; Pool and staking status ;; -_ get_staking_status() method_id { +get _ get_staking_status() { load_base_data(); load_validator_data(); @@ -50,7 +50,7 @@ _ get_staking_status() method_id { return (proxy_stake_at, until_val, proxy_stake_sent, querySent, unlocked, ctx_locked); } -_ get_pool_status() method_id { +get _ get_pool_status() { load_base_data(); load_member(owner_id()); return (ctx_balance, ctx_balance_sent, ctx_balance_pending_deposits, ctx_balance_pending_withdraw, ctx_balance_withdraw); @@ -59,7 +59,7 @@ _ get_pool_status() method_id { ;; ;; Params ;; -_ get_params() method_id { +get _ get_params() { load_base_data(); var (enabled, udpates_enabled, min_stake, deposit_fee, withdraw_fee, pool_fee, receipt_price) = ctx_extras; return (enabled, udpates_enabled, min_stake, deposit_fee, withdraw_fee, pool_fee, receipt_price); @@ -69,7 +69,7 @@ _ get_params() method_id { ;; Members ;; -_ get_member_balance(slice address) method_id { +get _ get_member_balance(slice address) { load_base_data(); load_member(parse_work_addr(address)); @@ -77,12 +77,12 @@ _ get_member_balance(slice address) method_id { return (ctx_member_balance, ctx_member_pending_deposit, ctx_member_pending_withdraw, ctx_member_withdraw); } -_ get_members_raw() method_id { +get _ get_members_raw() { load_base_data(); return ctx_nominators; } -_ get_members() method_id { +get _ get_members() { load_base_data(); ;; Init with owner @@ -110,16 +110,16 @@ _ get_members() method_id { return list; } -_ get_member(slice address) method_id { +get _ get_member(slice address) { load_base_data(); load_member(parse_work_addr(address)); member_update_balance(); return (ctx_member_balance, ctx_member_pending_deposit, ctx_member_pending_withdraw, ctx_member_withdraw); } -_ supported_interfaces() method_id { +get _ supported_interfaces() { return ( 123515602279859691144772641439386770278, ;; org.ton.introspection.v0 256184278959413194623484780286929323492 ;; com.tonwhales.nominators:v0 ); -} \ No newline at end of file +} diff --git a/crypto/func/auto-tests/tests/camel4.fc b/crypto/func/auto-tests/tests/camel4.fc index 92ef37bda..4013ab332 100644 --- a/crypto/func/auto-tests/tests/camel4.fc +++ b/crypto/func/auto-tests/tests/camel4.fc @@ -40,7 +40,7 @@ int test1() method_id(101) { return s~load_uint(32); } -int test2(int ret) method_id { +get int test2(int ret) { return setAndGetDataWrapper(ret); } diff --git a/crypto/func/auto-tests/tests/invalid-get-method-1.fc b/crypto/func/auto-tests/tests/invalid-get-method-1.fc new file mode 100644 index 000000000..a3234aad1 --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-get-method-1.fc @@ -0,0 +1,8 @@ +get (int, int) hello(int x, int y) method_id(123) { + return (x, y); +} + +{- +@compilation_should_fail +@stderr both `get` and `method_id` are not allowed +-} diff --git a/crypto/func/auto-tests/tests/s1.fc b/crypto/func/auto-tests/tests/s1.fc index aa7e52c59..0dce5d979 100644 --- a/crypto/func/auto-tests/tests/s1.fc +++ b/crypto/func/auto-tests/tests/s1.fc @@ -1,28 +1,28 @@ -slice ascii_slice() method_id { +get slice ascii_slice() { return "string"; } -slice raw_slice() method_id { +get slice raw_slice() { return "abcdef"s; } -slice addr_slice() method_id { +get slice addr_slice() { return "Ef8zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM0vF"a; } -int string_hex() method_id { +get int string_hex() { return "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"u; } -int string_minihash() method_id { +get int string_minihash() { return "transfer(slice, int)"h; } -int string_maxihash() method_id { +get int string_maxihash() { return "transfer(slice, int)"H; } -int string_crc32() method_id { +get int string_crc32() { return "transfer(slice, int)"c; } diff --git a/crypto/func/func.h b/crypto/func/func.h index 04c7e8305..0a79c712e 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -116,6 +116,7 @@ enum Keyword { _Builtin, _AutoApply, _MethodId, + _Get, _Operator, _Infix, _Infixl, @@ -769,6 +770,7 @@ struct SymValFunc : SymVal { flagUsedAsNonCall = 8, // used not only as `f()`, but as a 1-st class function (assigned to var, pushed to tuple, etc.) flagMarkedAsPure = 16, // declared as `pure`, can't call impure and access globals, unused invocations are optimized out flagBuiltinFunction = 32, // was created via `define_builtin_func()`, not from source code + flagGetMethod = 64, // was declared via `get T func()`, method_id is auto-assigned }; td::RefInt256 method_id; // todo why int256? it's small @@ -807,6 +809,9 @@ struct SymValFunc : SymVal { bool is_builtin() const { return flags & flagBuiltinFunction; } + bool is_get_method() const { + return flags & flagGetMethod; + } }; struct SymValCodeFunc : SymValFunc { diff --git a/crypto/func/keywords.cpp b/crypto/func/keywords.cpp index 9de9fb730..bd4d3de91 100644 --- a/crypto/func/keywords.cpp +++ b/crypto/func/keywords.cpp @@ -126,6 +126,7 @@ void define_keywords() { .add_keyword("builtin", Kw::_Builtin) .add_keyword("auto_apply", Kw::_AutoApply) .add_keyword("method_id", Kw::_MethodId) + .add_keyword("get", Kw::_Get) .add_keyword("operator", Kw::_Operator) .add_keyword("infix", Kw::_Infix) .add_keyword("infixl", Kw::_Infixl) diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index 07e8b8add..4e73247c5 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -1509,12 +1509,22 @@ void detect_if_function_just_wraps_another(SymValCodeFunc* v_current, const td:: } } +static td::RefInt256 calculate_method_id_by_func_name(const std::string &func_name) { + unsigned int crc = td::crc16(func_name); + return td::make_refint((crc & 0xffff) | 0x10000); +} + +// todo rewrite function declaration parsing completely, it's weird void parse_func_def(Lexer& lex) { SrcLocation loc{lex.cur().loc}; sym::open_scope(lex); std::vector type_vars; + bool is_get_method = false; if (lex.tp() == _Forall) { type_vars = parse_type_var_list(lex); + } else if (lex.tp() == _Get) { + is_get_method = true; + lex.next(); } auto ret_type = parse_type(lex); if (lex.tp() != _Ident) { @@ -1544,32 +1554,32 @@ void parse_func_def(Lexer& lex) { lex.next(); } td::RefInt256 method_id; - std::string method_name; if (lex.tp() == _MethodId) { + if (is_get_method) { + lex.cur().error("both `get` and `method_id` are not allowed"); + } lex.next(); - if (lex.tp() == '(') { + if (lex.tp() == '(') { // method_id(N) lex.expect('('); - if (lex.tp() == Lexem::String) { - method_name = lex.cur().str; - } else if (lex.tp() == Lexem::Number) { - method_name = lex.cur().str; - method_id = td::string_to_int256(method_name); - if (method_id.is_null()) { - lex.cur().error_at("invalid integer constant `", "`"); - } - } else { - throw src::ParseError{lex.cur().loc, "integer or string method identifier expected"}; + method_id = td::string_to_int256(lex.cur().str); + lex.expect(Lexem::Number); + if (method_id.is_null()) { + lex.cur().error_at("invalid integer constant `", "`"); } - lex.next(); lex.expect(')'); } else { - method_name = func_name.str; - } - if (method_id.is_null()) { - unsigned crc = td::crc16(method_name); - method_id = td::make_refint((crc & 0xffff) | 0x10000); + static bool warning_shown = false; + if (!warning_shown) { + lex.cur().loc.show_warning("`method_id` specifier is deprecated, use `get` keyword.\nExample: `get int seqno() { ... }`"); + warning_shown = true; + } + method_id = calculate_method_id_by_func_name(func_name.str); } } + if (is_get_method) { + func_assert(method_id.is_null()); + method_id = calculate_method_id_by_func_name(func_name.str); + } TypeExpr* func_type = TypeExpr::new_map(extract_total_arg_type(arg_list), ret_type); func_type = compute_type_closure(func_type, type_vars); if (lex.tp() == _Builtin) { @@ -1682,6 +1692,13 @@ void parse_func_def(Lexer& lex) { lex.cur().error("inline mode for `"s + func_name.str + "` changed with respect to a previous declaration"); } } + if (is_get_method) { + auto val = dynamic_cast(func_sym->value); + if (!val) { + lex.cur().error("cannot set unknown function `"s + func_name.str + "` as a get method"); + } + val->flags |= SymValFunc::flagGetMethod; + } if (verbosity >= 1) { std::cerr << "new type of function " << func_name.str << " : " << func_type << std::endl; } diff --git a/lite-client/lite-client.cpp b/lite-client/lite-client.cpp index 55d46ad1f..df053b4c4 100644 --- a/lite-client/lite-client.cpp +++ b/lite-client/lite-client.cpp @@ -926,7 +926,7 @@ bool TestNode::show_help(std::string command) { "saveaccount[code|data] []\tSaves into specified file the most recent state " "(StateInit) or just the code or data of specified account; is in " "[:] format\n" - "runmethod[full] [] ...\tRuns GET method of account " + "runmethod[full] [] ...\tRuns GET method of account " " " "with specified parameters\n" "dnsresolve [] []\tResolves a domain starting from root dns smart contract\n" diff --git a/tonlib/tonlib/tonlib-cli.cpp b/tonlib/tonlib/tonlib-cli.cpp index 5a32b50f3..ff0fb95e6 100644 --- a/tonlib/tonlib/tonlib-cli.cpp +++ b/tonlib/tonlib/tonlib-cli.cpp @@ -386,7 +386,7 @@ class TonlibCli : public td::actor::Actor { td::TerminalIO::out() << "sendfile \tLoad a serialized message from and send it to server\n"; td::TerminalIO::out() << "setconfig|validateconfig [] [] [] - set or validate " "lite server config\n"; - td::TerminalIO::out() << "runmethod ...\tRuns GET method of account " + td::TerminalIO::out() << "runmethod ...\tRuns GET method of account " " with specified parameters\n"; td::TerminalIO::out() << "getstate \tget state of wallet with requested key\n"; td::TerminalIO::out() << "getstatebytransaction \tget state of wallet with requested key after transaction with local time and hash (base64url)\n"; From 8932c515c9b5173ecc045164b970ae03bb4b50c8 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Tue, 21 May 2024 17:50:06 +0300 Subject: [PATCH 24/30] [FunC] Produce an error on get methods hash (method_id) collision --- .../func/auto-tests/tests/invalid-get-method-2.fc | 15 +++++++++++++++ crypto/func/builtins.cpp | 2 +- crypto/func/func.h | 2 +- crypto/func/parse-func.cpp | 6 ++++++ 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 crypto/func/auto-tests/tests/invalid-get-method-2.fc diff --git a/crypto/func/auto-tests/tests/invalid-get-method-2.fc b/crypto/func/auto-tests/tests/invalid-get-method-2.fc new file mode 100644 index 000000000..e2a8556b5 --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-get-method-2.fc @@ -0,0 +1,15 @@ +get int secret() pure { + return 0; +} +get int balanced() pure { + return 1; +} + +int main() { + return secret() + balanced(); +} + +{- +@compilation_should_fail +@stderr GET methods hash collision: `secret` and `balanced` produce the same hash +-} diff --git a/crypto/func/builtins.cpp b/crypto/func/builtins.cpp index aafa9bef7..218e173d7 100644 --- a/crypto/func/builtins.cpp +++ b/crypto/func/builtins.cpp @@ -28,7 +28,7 @@ using namespace std::literals::string_literals; */ int glob_func_cnt, undef_func_cnt, glob_var_cnt, const_cnt; -std::vector glob_func, glob_vars; +std::vector glob_func, glob_vars, glob_get_methods; std::set prohibited_var_names; SymDef* define_builtin_func_impl(const std::string& name, SymValAsmFunc* func_val) { diff --git a/crypto/func/func.h b/crypto/func/func.h index 0a79c712e..faf71f5d5 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -874,7 +874,7 @@ struct SymValConst : sym::SymValBase { }; extern int glob_func_cnt, undef_func_cnt, glob_var_cnt; -extern std::vector glob_func, glob_vars; +extern std::vector glob_func, glob_vars, glob_get_methods; extern std::set prohibited_var_names; /* diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index 4e73247c5..f2e48f33e 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -1579,6 +1579,11 @@ void parse_func_def(Lexer& lex) { if (is_get_method) { func_assert(method_id.is_null()); method_id = calculate_method_id_by_func_name(func_name.str); + for (const SymDef* other : glob_get_methods) { + if (!td::cmp(dynamic_cast(other->value)->method_id, method_id)) { + lex.cur().error(PSTRING() << "GET methods hash collision: `" << other->name() << "` and `" + func_name.str + "` produce the same hash. Consider renaming one of these functions."); + } + } } TypeExpr* func_type = TypeExpr::new_map(extract_total_arg_type(arg_list), ret_type); func_type = compute_type_closure(func_type, type_vars); @@ -1698,6 +1703,7 @@ void parse_func_def(Lexer& lex) { lex.cur().error("cannot set unknown function `"s + func_name.str + "` as a get method"); } val->flags |= SymValFunc::flagGetMethod; + glob_get_methods.push_back(func_sym); } if (verbosity >= 1) { std::cerr << "new type of function " << func_name.str << " : " << func_type << std::endl; From 2da85a646cf139dca9f4f67196fb75fa05cc6b26 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Wed, 22 May 2024 11:49:41 +0300 Subject: [PATCH 25/30] [FunC] Fix an issue of funcfiftlib.wasm which truncated long fif output As it turned out, PSTRING() created a buffer of 128K. If asm_code exceeded this buffer, it was truncated. I've just dropped PSTRING() from there in favor of std::string. --- crypto/fift/utils.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/crypto/fift/utils.cpp b/crypto/fift/utils.cpp index 68fc18c03..37f72c87a 100644 --- a/crypto/fift/utils.cpp +++ b/crypto/fift/utils.cpp @@ -112,7 +112,7 @@ class MemoryFileLoader : public fift::FileLoader { std::map> files_; }; -td::Result create_source_lookup(std::string main, bool need_preamble = true, bool need_asm = true, +td::Result create_source_lookup(std::string&& main, bool need_preamble = true, bool need_asm = true, bool need_ton_util = true, bool need_lisp = true, bool need_w3_code = true, bool need_fift_ext = true, bool need_disasm = true, std::string dir = "") { @@ -187,7 +187,7 @@ td::Result run_fift(fift::SourceLookup source_lookup, std::o } // namespace td::Result mem_run_fift(std::string source, std::vector args, std::string fift_dir) { std::stringstream ss; - TRY_RESULT(source_lookup, create_source_lookup(source, true, true, true, true, true, true, true, fift_dir)); + TRY_RESULT(source_lookup, create_source_lookup(std::move(source), true, true, true, 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); @@ -205,16 +205,21 @@ td::Result mem_run_fift(SourceLookup source_lookup, std::vector create_mem_source_lookup(std::string main, std::string fift_dir, bool need_preamble, bool need_asm, bool need_ton_util, bool need_lisp, bool need_w3_code) { - return create_source_lookup(main, need_preamble, need_asm, need_ton_util, need_lisp, need_w3_code, false, false, + return create_source_lookup(std::move(main), need_preamble, need_asm, need_ton_util, need_lisp, need_w3_code, false, false, fift_dir); } td::Result> compile_asm(td::Slice asm_code, std::string fift_dir, bool is_raw) { std::stringstream ss; - 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, false, false, false, false, fift_dir)); + std::string sb; + sb.reserve(asm_code.size() + 100); + sb.append("\"Asm.fif\" include\n "); + sb.append(is_raw ? "<{" : ""); + sb.append(asm_code.data(), asm_code.size()); + sb.append(is_raw ? "}>c" : ""); + sb.append(" boc>B \"res\" B>file"); + + TRY_RESULT(source_lookup, create_source_lookup(std::move(sb), true, true, true, false, false, false, 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)); From 49a0d32c1bec31e905147432b1f07572ad566740 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Wed, 22 May 2024 11:52:34 +0300 Subject: [PATCH 26/30] [FunC] Drop a folder crypto/func/test, it's unused --- crypto/func/test/a10.fc | 9 --- crypto/func/test/a11.fc | 28 -------- crypto/func/test/a12.fc | 4 -- crypto/func/test/a12_1.fc | 4 -- crypto/func/test/a12_2.fc | 4 -- crypto/func/test/a12_3.fc | 4 -- crypto/func/test/a12_4.fc | 4 -- crypto/func/test/a12_5.fc | 4 -- crypto/func/test/a12_6.fc | 4 -- crypto/func/test/a12_7.fc | 4 -- crypto/func/test/a12_8.fc | 4 -- crypto/func/test/a12_9.fc | 4 -- crypto/func/test/a6.fc | 89 ------------------------- crypto/func/test/a6.fp | 75 --------------------- crypto/func/test/a6_1.fc | 6 -- crypto/func/test/a6_2.fc | 130 ------------------------------------- crypto/func/test/a6_3.fc | 22 ------- crypto/func/test/a6_4.fc | 20 ------ crypto/func/test/a6_5.fc | 20 ------ crypto/func/test/a7.fc | 12 ---- crypto/func/test/a8.fc | 28 -------- crypto/func/test/a9.fc | 23 ------- crypto/func/test/a9_1.fc | 28 -------- crypto/func/test/b1.fc | 63 ------------------ crypto/func/test/b2.fc | 60 ----------------- crypto/func/test/b2_0.fc | 63 ------------------ crypto/func/test/b2_1.fc | 62 ------------------ crypto/func/test/b2_2.fc | 58 ----------------- crypto/func/test/b3.fc | 20 ------ crypto/func/test/c1.fc | 37 ----------- crypto/func/test/c2.fc | 10 --- crypto/func/test/c2_1.fc | 7 -- crypto/func/test/co1.fc | 55 ---------------- crypto/func/test/co2.fc | 15 ----- crypto/func/test/co3.fc | 24 ------- crypto/func/test/i1.fc | 16 ----- crypto/func/test/i1sub1.fc | 8 --- crypto/func/test/i1sub2.fc | 10 --- crypto/func/test/pv.fc | 53 --------------- crypto/func/test/s1.fc | 49 -------------- crypto/func/test/s2.fc | 26 -------- crypto/func/test/tc1.fc | 113 -------------------------------- crypto/func/test/tc2.fc | 84 ------------------------ crypto/func/test/w1.fc | 9 --- crypto/func/test/w2.fc | 14 ---- crypto/func/test/w3.fc | 13 ---- crypto/func/test/w4.fc | 13 ---- crypto/func/test/w5.fc | 14 ---- crypto/func/test/w6.fc | 12 ---- crypto/func/test/w7.fc | 14 ---- crypto/func/test/w8.fc | 22 ------- crypto/func/test/w9.fc | 8 --- 52 files changed, 1482 deletions(-) delete mode 100644 crypto/func/test/a10.fc delete mode 100644 crypto/func/test/a11.fc delete mode 100644 crypto/func/test/a12.fc delete mode 100644 crypto/func/test/a12_1.fc delete mode 100644 crypto/func/test/a12_2.fc delete mode 100644 crypto/func/test/a12_3.fc delete mode 100644 crypto/func/test/a12_4.fc delete mode 100644 crypto/func/test/a12_5.fc delete mode 100644 crypto/func/test/a12_6.fc delete mode 100644 crypto/func/test/a12_7.fc delete mode 100644 crypto/func/test/a12_8.fc delete mode 100644 crypto/func/test/a12_9.fc delete mode 100644 crypto/func/test/a6.fc delete mode 100644 crypto/func/test/a6.fp delete mode 100644 crypto/func/test/a6_1.fc delete mode 100644 crypto/func/test/a6_2.fc delete mode 100644 crypto/func/test/a6_3.fc delete mode 100644 crypto/func/test/a6_4.fc delete mode 100644 crypto/func/test/a6_5.fc delete mode 100644 crypto/func/test/a7.fc delete mode 100644 crypto/func/test/a8.fc delete mode 100644 crypto/func/test/a9.fc delete mode 100644 crypto/func/test/a9_1.fc delete mode 100644 crypto/func/test/b1.fc delete mode 100644 crypto/func/test/b2.fc delete mode 100644 crypto/func/test/b2_0.fc delete mode 100644 crypto/func/test/b2_1.fc delete mode 100644 crypto/func/test/b2_2.fc delete mode 100644 crypto/func/test/b3.fc delete mode 100644 crypto/func/test/c1.fc delete mode 100644 crypto/func/test/c2.fc delete mode 100644 crypto/func/test/c2_1.fc delete mode 100644 crypto/func/test/co1.fc delete mode 100644 crypto/func/test/co2.fc delete mode 100644 crypto/func/test/co3.fc delete mode 100644 crypto/func/test/i1.fc delete mode 100644 crypto/func/test/i1sub1.fc delete mode 100644 crypto/func/test/i1sub2.fc delete mode 100644 crypto/func/test/pv.fc delete mode 100644 crypto/func/test/s1.fc delete mode 100644 crypto/func/test/s2.fc delete mode 100644 crypto/func/test/tc1.fc delete mode 100644 crypto/func/test/tc2.fc delete mode 100644 crypto/func/test/w1.fc delete mode 100644 crypto/func/test/w2.fc delete mode 100644 crypto/func/test/w3.fc delete mode 100644 crypto/func/test/w4.fc delete mode 100644 crypto/func/test/w5.fc delete mode 100644 crypto/func/test/w6.fc delete mode 100644 crypto/func/test/w7.fc delete mode 100644 crypto/func/test/w8.fc delete mode 100644 crypto/func/test/w9.fc diff --git a/crypto/func/test/a10.fc b/crypto/func/test/a10.fc deleted file mode 100644 index 70c7871d7..000000000 --- a/crypto/func/test/a10.fc +++ /dev/null @@ -1,9 +0,0 @@ -_ f(int a, int x) { - int y = 0; - int z = 0; - while ((y = x * x) > a) { - x -= 1; - z = 1; - } - return (y, z); -} diff --git a/crypto/func/test/a11.fc b/crypto/func/test/a11.fc deleted file mode 100644 index 45bdf1f36..000000000 --- a/crypto/func/test/a11.fc +++ /dev/null @@ -1,28 +0,0 @@ -_ f(slice ds, int total_weight, int elect_at, cell frozen, int total_stakes, int cnt, cell credits, cell vdict, int elect) { - return (ds, elect, credits); -} - -_ g(slice ds, int total_weight, int elect_at, cell frozen, int total_stakes, int cnt, cell credits, int elect) { - return (ds, elect, credits); -} - -_ h(slice ds, int total_weight, int elect_at, cell frozen, int total_stakes, cell credits, int elect) { - return (ds, elect, credits); -} - -_ h2(slice ds, int total_weight, int elect_at, cell frozen, int total_stakes, cell credits, int elect) { - return (ds, credits, elect); -} - -_ h3(int pubkey, int adnl_addr, int stake, int tot_weight, tuple vinfo) { - return (pubkey, tot_weight, stake, vinfo); -} - -_ z(int a, int b) { - return (b, 0, a); -} - -_ z2(int a, int b) { - return (0, a, b); -} - diff --git a/crypto/func/test/a12.fc b/crypto/func/test/a12.fc deleted file mode 100644 index 4f668ed3a..000000000 --- a/crypto/func/test/a12.fc +++ /dev/null @@ -1,4 +0,0 @@ -_ f(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o) { - return (a, i, o, j, e, f, g, h, k, l, m, d, b, c, n); - ;; optimal code is 6-byte: s11 s12 XCHG2 2 5 BLKSWAP s13 s13 s11 XCHG3 -} diff --git a/crypto/func/test/a12_1.fc b/crypto/func/test/a12_1.fc deleted file mode 100644 index 2f59e07e7..000000000 --- a/crypto/func/test/a12_1.fc +++ /dev/null @@ -1,4 +0,0 @@ -_ f(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) { - return (f, j, a, b, i, g, d, e, h, c); ;; optimal code is 3 ops, 6 bytes - ;; s6 s0 s4 XCHG3 s4 s8 s9 XCHG3 8 0 REVERSE -} diff --git a/crypto/func/test/a12_2.fc b/crypto/func/test/a12_2.fc deleted file mode 100644 index 7c60c6fd5..000000000 --- a/crypto/func/test/a12_2.fc +++ /dev/null @@ -1,4 +0,0 @@ -_ f(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) { - return (f, d, j, a, i, g, b, e, h, c); ;; optimal code is 4 ops, 6 bytes - ;; s1 s8 XCHG s1 s6 XCHG 7 3 BLKSWAP s9 s4 XCHG2 -} diff --git a/crypto/func/test/a12_3.fc b/crypto/func/test/a12_3.fc deleted file mode 100644 index 86b3409a9..000000000 --- a/crypto/func/test/a12_3.fc +++ /dev/null @@ -1,4 +0,0 @@ -_ f(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k) { - return (e, h, d, a, c, g, f, b, i, j, k); ;; optimal code is 4 ops, 8 bytes - ;; s9 s9 XCHG2 s6 s6 s8 XCHG3 s10 s7 s3 XCHG3 10 0 REVERSE -} diff --git a/crypto/func/test/a12_4.fc b/crypto/func/test/a12_4.fc deleted file mode 100644 index a4132917c..000000000 --- a/crypto/func/test/a12_4.fc +++ /dev/null @@ -1,4 +0,0 @@ -_ f(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k) { - return (b, a, c, e, g, d, f, k, i, j, h); ;; optimal code is 4 ops, 8 bytes - ;; s5 s0 s8 XCHG3 2 9 BLKSWAP s8 s9 s10 XCHG3 s7 s0 s5 XCHG3 -} diff --git a/crypto/func/test/a12_5.fc b/crypto/func/test/a12_5.fc deleted file mode 100644 index 277308a17..000000000 --- a/crypto/func/test/a12_5.fc +++ /dev/null @@ -1,4 +0,0 @@ -_ f(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k) { - return (c, g, d, k, a, f, e, h, i, j, b); ;; optimal code is 6 ops, 6 bytes - ;; s0 s7 XCHG s0 s8 XCHG s0 s10 XCHG s0 s6 XCHG s0 s4 XCHG s0 s9 XCHG -} diff --git a/crypto/func/test/a12_6.fc b/crypto/func/test/a12_6.fc deleted file mode 100644 index 01f7a5862..000000000 --- a/crypto/func/test/a12_6.fc +++ /dev/null @@ -1,4 +0,0 @@ -_ f(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k) { - return (h, e, d, j, k, f, i, a, b, c, g); ;; optimal code is 3 ops, 6 bytes - ;; s3 s10 XCHG s6 s7 s6 XCHG3 s9 s8 s4 XCHG3 -} diff --git a/crypto/func/test/a12_7.fc b/crypto/func/test/a12_7.fc deleted file mode 100644 index 99c42b0c4..000000000 --- a/crypto/func/test/a12_7.fc +++ /dev/null @@ -1,4 +0,0 @@ -_ f(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o, int p) { - return (m, f, l, j, b, e, a, d, p, k, c, n, g, i, h, o); ;; optimal code is 6 ops, 11 bytes - ;; s12 s0 s14 XCHG3 s0 s5 XCHG 6 8 BLKSWAP s3 s3 s9 XCHG3 s10 s14 s15 XCHG3 s13 s9 s9 XCHG3 -} diff --git a/crypto/func/test/a12_8.fc b/crypto/func/test/a12_8.fc deleted file mode 100644 index 054ae81d5..000000000 --- a/crypto/func/test/a12_8.fc +++ /dev/null @@ -1,4 +0,0 @@ -_ f(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o, int p) { - return (l, i, o, h, a, m, j, d, p, g, n, b, k, e, c, f); ;; optimal code is 5 ops, 10 bytes - ;; 8 0 REVERSE s3 s9 s14 XCHG3 s15 s6 s4 XCHG3 s8 s12 XCHG s11 s13 s10 XCHG3 -} diff --git a/crypto/func/test/a12_9.fc b/crypto/func/test/a12_9.fc deleted file mode 100644 index cd5789e24..000000000 --- a/crypto/func/test/a12_9.fc +++ /dev/null @@ -1,4 +0,0 @@ -_ f(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o, int p) { - return (g, j, n, f, o, i, e, l, d, h, b, k, m, c, p, a); ;; optimal code is 5 ops, 10 bytes - ;; s7 s5 s14 XCHG3 s10 s4 s5 XCHG3 s12 s8 s11 XCHG3 s7 s6 s9 XCHG3 s13 s14 s15 XCHG3 -} diff --git a/crypto/func/test/a6.fc b/crypto/func/test/a6.fc deleted file mode 100644 index 3a387aace..000000000 --- a/crypto/func/test/a6.fc +++ /dev/null @@ -1,89 +0,0 @@ -(int, int) f(int a, int b, int c, int d, int e, int f) { - ;; solve a 2x2 linear equation - int D = a * d - b * c; - int Dx = e * d - b * f; - int Dy = a * f - e * c; - return (Dx / D, Dy / D); -} - -int calc_phi() { - var n = 1; - repeat (70) { n *= 10; } - var p = var q = 1; - do { - (p, q) = (q, p + q); - } until (q > n); - return muldivr(p, n, q); -} - -int calc_sqrt2() { - var n = 1; - repeat (70) { n *= 10; } - var p = var q = 1; - do { - var t = p + q; - (p, q) = (q, t + q); - } until (q > n); - return muldivr(p, n, q); -} - -var calc_root(m) { - int base = 1; - repeat(70) { base *= 10; } - var (a, b, c) = (1, 0, - m); - var (p1, q1, p2, q2) = (1, 0, 0, 1); - do { - int k = -1; - var (a1, b1, c1) = (0, 0, 0); - do { - k += 1; - (a1, b1, c1) = (a, b, c); - c += b; - c += b += a; - } until (c > 0); - (a, b, c) = (- c1, - b1, - a1); - (p1, q1) = (k * p1 + q1, p1); - (p2, q2) = (k * p2 + q2, p2); - } until (p1 > base); - return (p1, q1, p2, q2); -} - -{- -operator _/%_ infix 20; - -(int, int) ((int x) /% (int y)) { - return (x / y, x % y); -} - -(int, int) _/%_ (int x, int y) { - return (x / y, x % y); -} --} - -forall A, B, C -> -(B, C, A) rot (A x, B y, C z) { - return (y, z, x); -} - -int ataninv(int base, int q) { ;; computes base*atan(1/q) - base ~/= q; - q *= - q; - int sum = 0; - int n = 1; - do { - sum += base ~/ n; - base ~/= q; - n += 2; - } until base == 0; - return sum; -} - -int calc_pi() { - int base = 64; - repeat (70) { base *= 10; } - return (ataninv(base << 2, 5) - ataninv(base, 239)) ~>> 4; -} - -int main() { - return calc_pi(); -} diff --git a/crypto/func/test/a6.fp b/crypto/func/test/a6.fp deleted file mode 100644 index 00c2e76e4..000000000 --- a/crypto/func/test/a6.fp +++ /dev/null @@ -1,75 +0,0 @@ -f(int a, int b, int c, int d, int e, int f) : (int, int) { - var D = a * d - b * c; - var Dx : int = e * d - b * f; - var Dy : int = a * f - e * c; - return (Dx / D, Dy / D); -} - -calc_phi() : int = { - var n : int = 1; - repeat (10) { - n *= 10; - } - var p = var q = 1; - do { - (p, q) = (q, p + q); - } until q > n; - return muldivr(p, n, q); -} - -calc_sqrt2() : int = { - var n = 1; - repeat (70) { n *= 10; } - var p = var q = 1; - do { - var t = p + q; - (p, q) = (q, t + q); - } until q > n; - return muldivr(p, n, q); -} - -calc_phi() : int = { - var n = 1; - repeat (70) { n *= 10; } - var p = var q = 1; - do { - (p, q) = (q, p + q); - } until q > n; - return muldivr(p, n, q); -} - -operator _/%_ infix 20; - -(x : int) /% (y : int) : (int, int) = { - return (x / y, x % y); -} - -{- -_/%_ (int x, int y) : (int, int) = { - return (x / y, x % y); -} --} - -rot < A : type, B : type, C : type > - (x : A, y : B, z : C) : (B, C, A) { - return (y, z, x); -} - -ataninv(base : int, q : int) : int { ;; computes base*atan(1/q) - base /~= q; - q *= - q; - var sum : int = 0; - var n = 1; - do { - sum += base /~ n; - base /~= q; - n += 2; - } while base; - return sum; -} - -calc_pi() : int { - var base = 64; - repeat (70) { base *= 10; } - return (ataninv(base << 2, 5) - ataninv(base, 239)) >>~ 4; -} diff --git a/crypto/func/test/a6_1.fc b/crypto/func/test/a6_1.fc deleted file mode 100644 index 9af7f2549..000000000 --- a/crypto/func/test/a6_1.fc +++ /dev/null @@ -1,6 +0,0 @@ -(int, int) f(int a, int b, int c, int d, int e, int f) { - int D = a * d - b * c; - int Dx = e * d - b * f; - int Dy = a * f - e * c; - return (Dx / D, Dy / D); -} diff --git a/crypto/func/test/a6_2.fc b/crypto/func/test/a6_2.fc deleted file mode 100644 index 970ad6242..000000000 --- a/crypto/func/test/a6_2.fc +++ /dev/null @@ -1,130 +0,0 @@ -var f(a, b, c, d, e, f) { - var D = a * d - b * c; - var Dx = e * d - b * f; - var Dy = a * f - e * c; - return (Dx / D, Dy / D); -} - -var test8() { - return -4; -} - -var test3(a) { - int x = a * 10; - a += 1; - int x = x + 3; - { - int y = x + 2; - x = y + a; - } - int z = 5; - return x * (z + a); -} - -var test2(a) { - (var x, var y) = a /% 10; - return x + y; -} - -var test2a(a) { - var (x, y) = a /% 10; - return x + y; -} - -var test2b(a) { - var z = a /% 10; - return _+_ z; -} - -var test2c(a) { - return _+_ (a /% 10); -} - -var twice(f, x) { - return f (f x); -} - -var test() { - return f(1, 2, 3, 4, 7, 17); -} - -var rot(a, b, c) { - return (b, c, a); -} - -var rot_int(int a, int b, int c) { - return (b, c, a); -} - -(int, _) dup_int(x) { - return (x, x); -} - -var calc_phi() { - var n = 10; - n *= n; - n *= n; - n *= n; - n *= n; - n *= n; - n *= n; - var p = var q = 1; - (p, q) = (q, p + q); - (p, q) = (q, p + q); - (p, q) = (q, p + q); - (p, q) = (q, p + q); - (p, q) = (q, p + q); - (p, q) = (q, p + q); - (p, q) = (q, p + q); - return muldivr(p, n, q); -} - -var t0() { - var x = 1; - return x; -} - -var t1() { - return 2; -} - -var t2(int x) { - return 2; - return x += 1; -} - -var t3(int x, var y) { - int z = (x + y) * (x - y); -} - -var t3b(int x, var y) { - int z = (x + y) * (x - y); - return z; -} - -var t4((int, int, int) z) { - var (_, u, _) = z; - return u; -} - -int foo(int t); - -var t5(x) { - var f = t2; - return twice(f, x) * f(x); -} - -var proj1(a, b) { return a; } -var proj1a(a, b) { var c = a; return c; } -var proj1b(a, b) { int c = a; return c; } -var proj1c(a, b) { var c = a + 2; return c; } -var proj1d(a, b) { return a + 2; } -var proj1e(int a, _) { return a; } -int proj1f(_ a, int) { return a; } -int proj1g(int, a) { return a; } - -var test1(a) { - a = a + 1; - return a; -} - diff --git a/crypto/func/test/a6_3.fc b/crypto/func/test/a6_3.fc deleted file mode 100644 index 7c8ff3af2..000000000 --- a/crypto/func/test/a6_3.fc +++ /dev/null @@ -1,22 +0,0 @@ -forall A, B, C -> -(B, C, A) rot(A x, B y, C z) { - return (y, z, x); -} - -forall A, B, C -> -_ rot2(A x, B y, C z) { - return rot(rot(x, y, z)); -} - -_ test() { - return rot2(2, 3, 9); -} - -_ test2(cell x, slice y, tuple z) { - return rot2(x, y, z); -} - -forall A -> -_ test3(cell x, A y, int z) { - return rot2(x, y, z); -} diff --git a/crypto/func/test/a6_4.fc b/crypto/func/test/a6_4.fc deleted file mode 100644 index d7e6596a0..000000000 --- a/crypto/func/test/a6_4.fc +++ /dev/null @@ -1,20 +0,0 @@ -var calc_root(m) { - int base = 1; - repeat(70) { base *= 10; } - var (a, b, c) = (1, 0, - m); - var (p1, q1, p2, q2) = (1, 0, 0, 1); - do { - int k = -1; - var (a1, b1, c1) = (0, 0, 0); - do { - k += 1; - (a1, b1, c1) = (a, b, c); - c += b; - c += b += a; - } until (c > 0); - (a, b, c) = (- c1, - b1, - a1); - (p1, q1) = (k * p1 + q1, p1); - (p2, q2) = (k * p2 + q2, p2); - } until (p1 > base); - return (p1, q1, p2, q2); -} diff --git a/crypto/func/test/a6_5.fc b/crypto/func/test/a6_5.fc deleted file mode 100644 index ece7cd38d..000000000 --- a/crypto/func/test/a6_5.fc +++ /dev/null @@ -1,20 +0,0 @@ -var twice(f, x) { - return f (f x); -} - -_ sqr(x) { - return x * x; -} - -var main(x) { - var f = sqr; - return twice(f, x) * f(x); -} - -var pow6(x) { - return twice(sqr, x) * sqr(x); -} - -_ q() { - return false; -} diff --git a/crypto/func/test/a7.fc b/crypto/func/test/a7.fc deleted file mode 100644 index f86be30a1..000000000 --- a/crypto/func/test/a7.fc +++ /dev/null @@ -1,12 +0,0 @@ -int steps(int x) { - var n = 0; - while (x > 1) { - n += 1; - if (x & 1) { - x = 3 * x + 1; - } else { - x >>= 1; - } - } - return n; -} diff --git a/crypto/func/test/a8.fc b/crypto/func/test/a8.fc deleted file mode 100644 index 1cd18a339..000000000 --- a/crypto/func/test/a8.fc +++ /dev/null @@ -1,28 +0,0 @@ -int A(int a, int b, int c, int d, int e, int f) { - return muldiv(a, b, c) + muldiv(d, e, f); -} - -int B(int a, int b, int c, int d, int e, int f) { - return muldiv(a, b, c) + muldiv(b, d, e) + f; -} - -int C(int a, int b, int c, int d, int e, int f) { - return muldiv(a, b, c) + muldiv(b, d, c) + muldiv(d, d, f); -} - -int D(int a, int b, int c, int d, int e, int f) { - return muldiv(a, b, c) + muldiv(b, d, c) + muldiv(e, e, f); -} - -int E(int a, int b, int c, int d, int e, int f) { - return muldiv(a, b, c) + muldiv(c, d, e) + muldiv(c, c, f); -} - -int F(int a, int b, int c, int d, int e, int f) { - return muldiv(a, b, c) + muldiv(a, d, c) + muldiv(f, f, e); -} - -int G(int a, int b, int c, int d, int e, int f) { - return muldiv(a, b, c) + muldiv(b, c, d) + muldiv(b, c, e) + f; -} - diff --git a/crypto/func/test/a9.fc b/crypto/func/test/a9.fc deleted file mode 100644 index e9cc14507..000000000 --- a/crypto/func/test/a9.fc +++ /dev/null @@ -1,23 +0,0 @@ -int f(int x) { - if (2 * x + 1 == 7) { - return x + 17; - } else { - return 239; - } -} - -int f2(int x) { - return 2 * x + 1 == 6 ? x + 17 : 239; -} - -int g(int x) { - return x & 1 ? 3 * x + 1 : x / 2; -} - -_ H(int x, int y) { - return (x < y, x <= y, x == y, x >= y, x > y, x != y, x <=> y); -} - -int q() { - return 4; -} diff --git a/crypto/func/test/a9_1.fc b/crypto/func/test/a9_1.fc deleted file mode 100644 index 0dc9de0c1..000000000 --- a/crypto/func/test/a9_1.fc +++ /dev/null @@ -1,28 +0,0 @@ -_ F(int x) { - x = 2; - return x + 1; -} - -_ G(x) { - var y = x + 1; - x = 2; - return (x - 1, y); -} - -_ H(x) { - var y = x + 1; - x = 2; - return (x * y, y); -} - -_ I(x) { - int y = 17; - int z = x - y; - return (z, y); -} - -_ J(x) { - int y = 239; - int z = x - y; - return (z, y); -} diff --git a/crypto/func/test/b1.fc b/crypto/func/test/b1.fc deleted file mode 100644 index 420ac6ead..000000000 --- a/crypto/func/test/b1.fc +++ /dev/null @@ -1,63 +0,0 @@ -int now() pure asm "NOW"; - -int cell_hash(cell c) -asm "HASHCU"; - -int slice_hash(slice s) -asm "HASHSU"; - -int check_signature(int hash, slice signature, int public_key) -asm "CHKSIGNU"; - -;; () throw_if(int excno, int cond) -;; asm "THROWARGIF"; - -cell get_data() pure asm "c4 PUSH"; -() set_data(cell c) asm "c4 POP"; -() accept_message() asm "ACCEPT"; - -slice begin_parse(cell c) pure asm "CTOS"; -() end_parse(slice s) asm "ENDS"; -(cell, slice) load_ref(slice s) pure asm "LDREF"; -(int, slice) zload_int(slice s, int len) pure asm "LDIX"; -(int, slice) zload_uint(slice s, int len) pure asm "LDUX"; -int zpreload_int(slice s, int len) pure asm "PLDIX"; -int zpreload_uint(slice s, int len) pure asm "PLDUX"; -(slice, slice) load_bits(slice s, int len) pure asm "LDSLICEX"; -slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; -cell set_idict_ref(cell value, int index, cell dict, int key_len) pure asm "DICTISETREF"; -builder begin_cell() pure asm "NEWC"; -builder store_ref(cell c, builder b) pure asm "STREF"; -builder zstore_uint(int x, builder b, int len) pure asm "STUX"; -builder zstore_int(int x, builder b, int len) pure asm "STIX"; -cell end_cell(builder b) pure asm "ENDC"; - -;; Simple configuration smart contract - -() recv_internal(cell in_msg) { - ;; do nothing for internal messages -} - -() recv_external(cell in_msg) { - var (signature, cs0) = load_bits(begin_parse(in_msg), 512); - var (msg_seqno, cs) = zload_uint(cs0, 32); - (var valid_until, cs) = zload_uint(cs, 32); - throw_if(35, valid_until < now()); - var (cfg_dict, cs2) = load_ref(begin_parse(get_data())); - (var stored_seqno, cs2) = zload_uint(cs2, 32); - (var public_key, cs2) = zload_uint(cs2, 256); - end_parse(cs2); - throw_unless(33, msg_seqno == stored_seqno); - throw_unless(34, check_signature(slice_hash(cs0), signature, public_key)); - accept_message(); - (var param_index, cs) = zload_uint(cs, 32); - (var param_value, cs) = load_ref(cs); - end_parse(cs); -;; cfg_dict = set_idict_ref(param_value, param_index, cfg_dict, 32); -;; var cb = begin_cell(); -;; cb = store_ref(cfg_dict, cb); - var cb = store_ref(set_idict_ref(param_value, param_index, cfg_dict, 32), begin_cell()); - cb = zstore_uint(stored_seqno + 1, cb, 32); - cb = zstore_uint(public_key, cb, 256); - set_data(end_cell(cb)); -} diff --git a/crypto/func/test/b2.fc b/crypto/func/test/b2.fc deleted file mode 100644 index c889db03e..000000000 --- a/crypto/func/test/b2.fc +++ /dev/null @@ -1,60 +0,0 @@ -int now() pure asm "NOW"; - -int cell_hash(cell c) -asm "HASHCU"; - -int slice_hash(slice s) -asm "HASHSU"; - -int check_signature(int hash, slice signature, int public_key) -asm "CHKSIGNU"; - -;; () throw_if(int excno, int cond) -;; asm "THROWARGIF"; - -cell get_data() pure asm "c4 PUSH"; -() set_data(cell c) asm "c4 POP"; -() accept_message() asm "ACCEPT"; - -slice begin_parse(cell c) pure asm "CTOS"; -() end_parse(slice s) asm "ENDS"; -(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; -;; (slice, int) load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; -;; (slice, int) load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) pure asm "PLDIX"; -;; int preload_uint(slice s, int len) pure asm "PLDUX"; -(slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; -slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; -cell set_idict_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; -builder begin_cell() pure asm "NEWC"; -builder store_ref(builder b, cell c) pure asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; -cell end_cell(builder b) pure asm "ENDC"; - -;; Simple configuration smart contract - -() recv_internal(cell in_msg) { - ;; do nothing for internal messages -} - -() recv_external(cell in_msg) { - var (cs0, signature) = load_bits(begin_parse(in_msg), 512); - var (cs, msg_seqno) = load_uint(cs0, 32); - (cs, var valid_until) = load_uint(cs, 32); - throw_if(35, valid_until < now()); - var (cs2, cfg_dict) = load_ref(begin_parse(get_data())); - (cs2, var stored_seqno) = load_uint(cs2, 32); - (cs2, var public_key) = load_uint(cs2, 256); - end_parse(cs2); - throw_unless(33, msg_seqno == stored_seqno); - throw_unless(34, check_signature(slice_hash(cs0), signature, public_key)); - accept_message(); - (cs, var param_index) = load_uint(cs, 32); - (cs, var param_value) = load_ref(cs); - end_parse(cs); - var cb = store_ref(begin_cell(), set_idict_ref(cfg_dict, 32, param_index, param_value)); - cb = store_uint(cb, stored_seqno + 1, 32); - cb = store_uint(cb, public_key, 256); - set_data(end_cell(cb)); -} diff --git a/crypto/func/test/b2_0.fc b/crypto/func/test/b2_0.fc deleted file mode 100644 index a6337871f..000000000 --- a/crypto/func/test/b2_0.fc +++ /dev/null @@ -1,63 +0,0 @@ -int now() pure asm "NOW"; - -int cell_hash(cell c) -asm "HASHCU"; - -int slice_hash(slice s) -asm "HASHSU"; - -int check_signature(int hash, slice signature, int public_key) -asm "CHKSIGNU"; - -;; () throw_if(int excno, int cond) -;; asm "THROWARGIF"; - -cell get_data() pure asm "c4 PUSH"; -() set_data(cell c) asm "c4 POP"; -() accept_message() asm "ACCEPT"; - -slice begin_parse(cell c) pure asm "CTOS"; -() end_parse(slice s) asm "ENDS"; -(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; -(slice, int) zload_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; -(slice, int) zload_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; -int zpreload_int(slice s, int len) pure asm "PLDIX"; -int zpreload_uint(slice s, int len) pure asm "PLDUX"; -(slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; -slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; -cell set_idict_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; -builder begin_cell() pure asm "NEWC"; -builder store_ref(builder b, cell c) pure asm(c b) "STREF"; -builder zstore_uint(builder b, int x, int len) pure asm(x b len) "STUX"; -builder zstore_int(builder b, int x, int len) pure asm(x b len) "STIX"; -cell end_cell(builder b) pure asm "ENDC"; - -;; Simple configuration smart contract - -() recv_internal(cell in_msg) { - ;; do nothing for internal messages -} - -() recv_external(cell in_msg) { - var (cs0, signature) = load_bits(begin_parse(in_msg), 512); - var (cs, msg_seqno) = zload_uint(cs0, 32); - (cs, var valid_until) = zload_uint(cs, 32); - throw_if(35, valid_until < now()); - var (cs2, cfg_dict) = load_ref(begin_parse(get_data())); - (cs2, var stored_seqno) = zload_uint(cs2, 32); - (cs2, var public_key) = zload_uint(cs2, 256); - end_parse(cs2); - throw_unless(33, msg_seqno == stored_seqno); - throw_unless(34, check_signature(slice_hash(cs0), signature, public_key)); - accept_message(); - (cs, var param_index) = zload_uint(cs, 32); - (cs, var param_value) = load_ref(cs); - end_parse(cs); -;; cfg_dict = set_idict_ref(cfg_dict, 32, param_index, param_value); -;; var cb = begin_cell(); -;; cb = store_ref(cb, cfg_dict); - var cb = store_ref(begin_cell(), set_idict_ref(cfg_dict, 32, param_index, param_value)); - cb = zstore_uint(cb, stored_seqno + 1, 32); - cb = zstore_uint(cb, public_key, 256); - set_data(end_cell(cb)); -} diff --git a/crypto/func/test/b2_1.fc b/crypto/func/test/b2_1.fc deleted file mode 100644 index dfa4e6ea5..000000000 --- a/crypto/func/test/b2_1.fc +++ /dev/null @@ -1,62 +0,0 @@ -int now() pure asm "NOW"; - -int cell_hash(cell c) -asm "HASHCU"; - -int slice_hash(slice s) -asm "HASHSU"; - -int check_signature(int hash, slice signature, int public_key) -asm "CHKSIGNU"; - -;; () throw_if(int excno, int cond) -;; asm "THROWARGIF"; - -cell get_data() pure asm "c4 PUSH"; -() set_data(cell c) asm "c4 POP"; -() accept_message() asm "ACCEPT"; - -slice begin_parse(cell c) pure asm "CTOS"; -() end_parse(slice s) asm "ENDS"; -(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; -;; (slice, int) ~load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; -;; (slice, int) ~load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; -;; int preload_int(slice s, int len) pure asm "PLDIX"; -;; int preload_uint(slice s, int len) pure asm "PLDUX"; -(slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; -slice preload_bits(slice s, int len) pure asm "PLDSLICEX"; -cell set_idict_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; -(cell, ()) ~set_idict_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; -builder begin_cell() pure asm "NEWC"; -builder store_ref(builder b, cell c) pure asm(c b) "STREF"; -;; builder store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; -;; builder store_int(builder b, int x, int len) pure asm(x b len) "STIX"; -cell end_cell(builder b) pure asm "ENDC"; - -;; Simple configuration smart contract - -() recv_internal(cell in_msg) { - ;; do nothing for internal messages -} - -() recv_external(cell in_msg) { - var cs = begin_parse(in_msg); - var signature = cs~load_bits(512); - var cs0 = cs; - int msg_seqno = cs~load_uint(32); - var valid_until = cs~load_uint(32); - throw_if(35, valid_until < now()); - var cs2 = begin_parse(get_data()); - var cfg_dict = cs2~load_ref(); - var stored_seqno = cs2~load_uint(32); - var public_key = cs2~load_uint(256); - cs2.end_parse(); - throw_unless(33, msg_seqno == stored_seqno); - throw_unless(34, check_signature(slice_hash(cs0), signature, public_key)); - accept_message(); - var param_index = cs~load_uint(32); - var param_value = cs~load_ref(); - cs.end_parse(); - cfg_dict~set_idict_ref(32, param_index, param_value); - set_data(begin_cell().store_ref(cfg_dict).store_uint(stored_seqno + 1, 32).store_uint(public_key, 256).end_cell()); -} diff --git a/crypto/func/test/b2_2.fc b/crypto/func/test/b2_2.fc deleted file mode 100644 index 62328f681..000000000 --- a/crypto/func/test/b2_2.fc +++ /dev/null @@ -1,58 +0,0 @@ -int now() pure asm "NOW"; - -int cell_hash(cell c) -asm "HASHCU"; - -int slice_hash(slice s) -asm "HASHSU"; - -int check_signature(int hash, slice signature, int public_key) -asm "CHKSIGNU"; - -;; () throw_if(int excno, int cond) -;; asm "THROWARGIF"; - -cell get_data() pure asm "c4 PUSH"; -() set_data(cell c) asm "c4 POP"; -() accept_message() asm "ACCEPT"; - -slice begin_parse(cell c) pure asm "CTOS"; -() end_parse(slice s) asm "ENDS"; -(slice, cell) load_ref(slice s) pure asm( -> 1 0) "LDREF"; -;; (slice, int) load_int(slice s, int len) pure asm(s len -> 1 0) "LDIX"; -;; (slice, int) load_uint(slice s, int len) pure asm( -> 1 0) "LDUX"; -;; int .preload_int(slice s, int len) pure asm "PLDIX"; -;; int .preload_uint(slice s, int len) pure asm "PLDUX"; -(slice, slice) load_bits(slice s, int len) pure asm(s len -> 1 0) "LDSLICEX"; -;; slice .preload_bits(slice s, int len) pure asm "PLDSLICEX"; -cell set_idict_ref(cell dict, int key_len, int index, cell value) pure asm(value index dict key_len) "DICTISETREF"; -builder begin_cell() pure asm "NEWC"; -builder store_ref(builder b, cell c) pure asm(c b) "STREF"; -;;builder .store_uint(builder b, int x, int len) pure asm(x b len) "STUX"; -;;builder .store_int(builder b, int x, int len) pure asm(x b len) "STIX"; -cell .end_cell(builder b) pure asm "ENDC"; - -;; Simple configuration smart contract - -() recv_internal(cell in_msg) { - ;; do nothing for internal messages -} - -() recv_external(cell in_msg) { - var (cs0, signature) = load_bits(begin_parse(in_msg), 512); - var (cs, msg_seqno) = load_uint(cs0, 32); - (cs, var valid_until) = load_uint(cs, 32); - throw_if(35, valid_until < now()); - var (cs2, cfg_dict) = load_ref(begin_parse(get_data())); - (cs2, var stored_seqno) = load_uint(cs2, 32); - (cs2, var public_key) = load_uint(cs2, 256); - end_parse(cs2); - throw_unless(33, msg_seqno == stored_seqno); - throw_unless(34, check_signature(slice_hash(cs0), signature, public_key)); - accept_message(); - (cs, var param_index) = load_uint(cs, 32); - (cs, var param_value) = load_ref(cs); - end_parse(cs); - set_data(begin_cell().store_ref(cfg_dict.set_idict_ref(32, param_index, param_value)) - .store_uint(stored_seqno + 1, 32).store_uint(public_key, 256).end_cell()); -} diff --git a/crypto/func/test/b3.fc b/crypto/func/test/b3.fc deleted file mode 100644 index ba3aa7680..000000000 --- a/crypto/func/test/b3.fc +++ /dev/null @@ -1,20 +0,0 @@ -;; 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) inline_ref { - set_data(begin_cell() - .store_uint(a, 8) - .store_int(x, 32) - .store_int(y, 32) - .end_cell()); -} - -() main() { - var (a, x, y) = unpack(); - x += y; - pack(a, x, y); -} diff --git a/crypto/func/test/c1.fc b/crypto/func/test/c1.fc deleted file mode 100644 index eb844f6fd..000000000 --- a/crypto/func/test/c1.fc +++ /dev/null @@ -1,37 +0,0 @@ -global int x, y, z; -global (cell, slice) y; -global ((int, int) -> int) op; - -_ get() { - var t = z + 1; - return x; -} - -_ pre_next() { - return x + 1; -} - -() init() { - ;; global x; - x = 0; -} - -int next() { - ;; global x; - return x += 1; -} - -_ set_y(x, w) { - y = (w, x); -} - -_ get_y() { - return y; -} - -int main(int c) { - init(); - c += next(); - return c + pre_next(); -} - diff --git a/crypto/func/test/c2.fc b/crypto/func/test/c2.fc deleted file mode 100644 index 277c70530..000000000 --- a/crypto/func/test/c2.fc +++ /dev/null @@ -1,10 +0,0 @@ -global ((int, int) -> int) op; - -int check_assoc(int a, int b, int c) { - return op(op(a, b), c) == op(a, op(b, c)); -} - -int main() { - op = _+_; - return check_assoc(2, 3, 9); -} diff --git a/crypto/func/test/c2_1.fc b/crypto/func/test/c2_1.fc deleted file mode 100644 index 3bf863a6d..000000000 --- a/crypto/func/test/c2_1.fc +++ /dev/null @@ -1,7 +0,0 @@ -_ check_assoc(op, a, b, c) { - return op(op(a, b), c) == op(a, op(b, c)); -} - -int main() { - return check_assoc(_+_, 2, 3, 9); -} diff --git a/crypto/func/test/co1.fc b/crypto/func/test/co1.fc deleted file mode 100644 index 82071e456..000000000 --- a/crypto/func/test/co1.fc +++ /dev/null @@ -1,55 +0,0 @@ -const int1 = 1, int2 = 2; - -const int int101 = 101; -const int int111 = 111; - -const int1r = int1; - -const str1 = "const1", str2 = "aabbcc"s; - -const slice str2r = str2; - -const str1int = 0x636f6e737431; -const str2int = 0xAABBCC; - -const int nibbles = 4; - -int iget1() { return int1; } -int iget2() { return int2; } -int iget3() { return int1 + int2; } - -int iget1r() { return int1r; } - -slice sget1() { return str1; } -slice sget2() { return str2; } -slice sget2r() { return str2r; } - -const int int240 = ((int1 + int2) * 10) << 3; - -int iget240() { return int240; } - -builder newc() asm "NEWC"; -slice endcs(builder b) asm "ENDC" "CTOS"; -int sdeq (slice s1, slice s2) asm "SDEQ"; -builder stslicer(builder b, slice s) asm "STSLICER"; - -_ main() { - int i1 = iget1(); - int i2 = iget2(); - int i3 = iget3(); - - throw_unless(int101, i1 == 1); - throw_unless(102, i2 == 2); - throw_unless(103, i3 == 3); - - slice s1 = sget1(); - slice s2 = sget2(); - slice s3 = newc().stslicer(str1).stslicer(str2r).endcs(); - - throw_unless(int111, sdeq(s1, newc().store_uint(str1int, 12 * nibbles).endcs())); - throw_unless(112, sdeq(s2, newc().store_uint(str2int, 6 * nibbles).endcs())); - throw_unless(113, sdeq(s3, newc().store_uint(0x636f6e737431ABCDEF, 18 * nibbles).endcs())); - - int i4 = iget240(); - throw_unless(104, i4 == 240); -} diff --git a/crypto/func/test/co2.fc b/crypto/func/test/co2.fc deleted file mode 100644 index f5fcb7488..000000000 --- a/crypto/func/test/co2.fc +++ /dev/null @@ -1,15 +0,0 @@ -const int x = 5; -const slice s = "abacaba"; -const int y = 3; -const slice s = "abacaba"; -const int x = 5; -const int z = 4, z = 4; - -int sdeq (slice s1, slice s2) asm "SDEQ"; - -() main() { - throw_unless(101, x == 5); - throw_unless(102, y == 3); - throw_unless(103, z == 4); - throw_unless(104, sdeq(s, "abacaba")); -} diff --git a/crypto/func/test/co3.fc b/crypto/func/test/co3.fc deleted file mode 100644 index 398592d35..000000000 --- a/crypto/func/test/co3.fc +++ /dev/null @@ -1,24 +0,0 @@ -const val1 = 123456789; -const val2 = 987654321; -const val3 = 135792468; -const val4 = 246813579; - -const prec_and = val1 & val2; -const prec_or = val1 | val2; -const prec_xor = val1 ^ val2; -const prec_logic = ((val1 & val2) | val3) ^ val4; -const prec_nand = val1 & (~ val2); - -int get_and() { return prec_and; } -int get_or() { return prec_or; } -int get_xor() { return prec_xor; } -int get_logic() { return prec_logic; } -int get_nand() { return prec_nand; } - -_ main() { - throw_unless(101, get_and() == 39471121); - throw_unless(102, get_or() == 1071639989); - throw_unless(103, get_xor() == 1032168868); - throw_unless(104, get_logic() == 82599134); - throw_unless(105, get_nand() == 83985668); -} diff --git a/crypto/func/test/i1.fc b/crypto/func/test/i1.fc deleted file mode 100644 index 9544e099e..000000000 --- a/crypto/func/test/i1.fc +++ /dev/null @@ -1,16 +0,0 @@ -global int i; - -#include "i1sub1.fc"; - -() sub0() { i = 0; } - -#include "i1sub2.fc"; - -() main() { - sub0(); - sub1(); - sub2(); - i = 9; -} - -#include "../test/i1sub2.fc"; diff --git a/crypto/func/test/i1sub1.fc b/crypto/func/test/i1sub1.fc deleted file mode 100644 index ba90a80fd..000000000 --- a/crypto/func/test/i1sub1.fc +++ /dev/null @@ -1,8 +0,0 @@ -;; DO NOT COMPILE DIRECTLY! -;; Compile i1.fc - -#include "i1sub1.fc"; - -() sub1() { - i = 1; -} diff --git a/crypto/func/test/i1sub2.fc b/crypto/func/test/i1sub2.fc deleted file mode 100644 index b79da1cf1..000000000 --- a/crypto/func/test/i1sub2.fc +++ /dev/null @@ -1,10 +0,0 @@ -;; DO NOT COMPILE DIRECTLY! -;; Compile i1.fc - -#include "./i1sub1.fc"; - -() sub2() { - sub1(); - sub0(); - i = 2; -} diff --git a/crypto/func/test/pv.fc b/crypto/func/test/pv.fc deleted file mode 100644 index d9bcd570a..000000000 --- a/crypto/func/test/pv.fc +++ /dev/null @@ -1,53 +0,0 @@ -#pragma test-version-set "1.2.3"; - -;; Positive tests -#pragma version ^1.2.0; -#pragma version ^1.2.3; -#pragma version >1.2.0; -#pragma version >0.9.9; -#pragma version <1.3.0; -#pragma version <2.0.0; -#pragma version >=1.2.0; -#pragma version <=1.3.0; -#pragma version >=1.2.3; -#pragma version <=1.2.3; -#pragma version ^1.2.3; -#pragma version 1.2.3; -#pragma version =1.2.3; - -;; Negative tests -#pragma not-version ^1.1.0; -#pragma not-version ^1.0.0; -#pragma not-version ^0.2.3; -#pragma not-version ^2.2.3; -#pragma not-version ^1.3.3; -#pragma not-version >1.2.3; -#pragma not-version <1.2.3; -#pragma not-version ^1.2.4; -#pragma not-version >=1.2.4; -#pragma not-version <=1.2.2; -#pragma not-version 3.2.1; -#pragma not-version =3.2.1; - -;; Test incomplete (partial) version -#pragma version ^1.2; -#pragma version >1.2; -#pragma version <1.3; -#pragma version <2; -#pragma version >=1.2; -#pragma version <=1.3; - -;; Advanced ^ behaviour (partials) -#pragma version ^1.2; -#pragma version ^1.0; -#pragma version ^1; -#pragma version ^0; -#pragma not-version ^1.0.0; -#pragma not-version ^0.0.0; -#pragma not-version ^0.0; -#pragma not-version ^1.3; -#pragma not-version ^2; - -(int) main(int a) { - return a; -} diff --git a/crypto/func/test/s1.fc b/crypto/func/test/s1.fc deleted file mode 100644 index 630d01803..000000000 --- a/crypto/func/test/s1.fc +++ /dev/null @@ -1,49 +0,0 @@ -slice ascii_slice() method_id { - return "string"; -} - -slice raw_slice() method_id { - return "abcdef"s; -} - -slice addr_slice() method_id { - return "Ef8zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM0vF"a; -} - -int string_hex() method_id { - return "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"u; -} - -int string_minihash() method_id { - return "transfer(slice, int)"h; -} - -int string_maxihash() method_id { - return "transfer(slice, int)"H; -} - -int string_crc32() method_id { - return "transfer(slice, int)"c; -} - -builder newc() asm "NEWC"; -slice endcs(builder b) asm "ENDC" "CTOS"; -int sdeq (slice s1, slice s2) asm "SDEQ"; - -_ main() { - slice s_ascii = ascii_slice(); - slice s_raw = raw_slice(); - slice s_addr = addr_slice(); - int i_hex = string_hex(); - int i_mini = string_minihash(); - int i_maxi = string_maxihash(); - int i_crc = string_crc32(); - throw_unless(101, sdeq(s_ascii, newc().store_uint(0x737472696E67, 12 * 4).endcs())); - throw_unless(102, sdeq(s_raw, newc().store_uint(0xABCDEF, 6 * 4).endcs())); - throw_unless(103, sdeq(s_addr, newc().store_uint(4, 3).store_int(-1, 8) - .store_uint(0x3333333333333333333333333333333333333333333333333333333333333333, 256).endcs())); - throw_unless(104, i_hex == 0x4142434445464748494A4B4C4D4E4F505152535455565758595A303132333435); - throw_unless(105, i_mini == 0x7a62e8a8); - throw_unless(106, i_maxi == 0x7a62e8a8ebac41bd6de16c65e7be363bc2d2cbc6a0873778dead4795c13db979); - throw_unless(107, i_crc == 2235694568); -} diff --git a/crypto/func/test/s2.fc b/crypto/func/test/s2.fc deleted file mode 100644 index c6df49d5b..000000000 --- a/crypto/func/test/s2.fc +++ /dev/null @@ -1,26 +0,0 @@ -slice test1() asm """ - "Test" $>s - PUSHSLICE -"""; - -slice test2() asm """ - "Hello" - " " - "World" - $+ $+ $>s - PUSHSLICE -"""; - -int sdeq (slice s1, slice s2) asm """SDEQ"""; -int sdeq (slice s1, slice s2) asm "SDEQ" ""; -int sdeq (slice s1, slice s2) asm "" """ -SDEQ -"""; - -() main() { - slice s = test1(); - throw_unless(101, sdeq(s, "Test")); - - slice s = test2(); - throw_unless(102, sdeq(s, "Hello World")); -} diff --git a/crypto/func/test/tc1.fc b/crypto/func/test/tc1.fc deleted file mode 100644 index 985c50d96..000000000 --- a/crypto/func/test/tc1.fc +++ /dev/null @@ -1,113 +0,0 @@ -() test1() { - int i = 3; - repeat (3) { - try { - int j = i; - i *= 2; - throw_unless(500, j <= 10); - } catch (x, e) { - i -= 2; - } - i += i + 1; - } - throw_unless(501, i == 43); -} - -int divide_by_ten(int num) { - try { - throw_unless(500, num < 10); - } catch (x, e) { - return divide_by_ten(num - 10) + 1; - } - return 0; -} - -() test2() { - int n = divide_by_ten(37); - throw_unless(502, n == 3); -} - -(int, int) swap_int(int a, int b) { - try { - a = a * b; - b = a / b; - a = a / b; - return (a, b); - } catch (x, e) { - throw_unless(500, b == 0); - } - return (0, a); -} - -() test3() { - int a = 0; - int b = 57; - try { - (a, b) = swap_int(a, b); - } catch (x, e) { - throw_unless(500, a == 0); - a = b; - b = 0; - } - throw_unless(503, (a == 57) & (b == 0)); -} - -int get_x(int x, int y) { - try { - } catch (x, e) { - return -1; - } - return x; -} - -int get_y(int x, int y) { - try { - return -1; - } catch (x, e) { - } - return y; -} - -() test4() { - throw_unless(504, get_x(3, 4) == 3); - throw_unless(504, get_y(3, 4) == -1); -} - -(int, int, int, int, int) foo(int a, int b, int c, int d, int e) { - try { - throw(11); - } catch (x, y) { - a += 1; - b += 2; - c += 3; - d += 4; - e += 5; - } - return (a, b, c, d, e); -} - -() test5() { - var (a, b, c, d, e) = foo(10, 20, 30, 40, 50); - throw_unless(505, (a == 11) & (b == 22) & (c == 33) & (d == 44) & (e == 55)); -} - -() test6() { - int a = 0; - int b = 0; - int c = 0; - try { - b = 3; - } catch (x, y) { - b = 12; - } - throw_unless(506, (a == 0) & (b == 3) & (c == 0)); -} - -() main() { - test1(); - test2(); - test3(); - test4(); - test5(); - test6(); -} diff --git a/crypto/func/test/tc2.fc b/crypto/func/test/tc2.fc deleted file mode 100644 index 00a577697..000000000 --- a/crypto/func/test/tc2.fc +++ /dev/null @@ -1,84 +0,0 @@ -forall X -> int cast_to_int(X x) asm "NOP"; -forall X -> builder cast_to_builder(X x) asm "NOP"; - -_ test1_body() { - int a = 3; - builder b = begin_cell(); - int c = 1; - try { - c = 3; - throw_arg(b, 100); - } catch (x, y) { - return (a + c + y, cast_to_builder(x)); - } - return (0, null()); -} - -() test1() { - var (x, y) = test1_body(); - throw_unless(101, x == 104); - throw_unless(102, y.builder_refs() == y.builder_bits()); -} - -_ test2_body(int a, int b, int c) { - try { - try { - try { - try { - throw_arg_if(1, 201, a + b + c == 3); - throw_arg_if(2, 201, a == 3); - throw_arg_unless(1, 202, b == 4); - return 1; - } catch (y, x) { - int y = y.cast_to_int(); - throw_arg_unless(y, x, x == 202); - throw_arg(y + 1, 200); - } - } catch (y, x) { - int y = y.cast_to_int(); - throw_arg_if(y, x, x == 200); - throw_arg_if(y + 2, x, y < 2); - throw_arg_if(y + 3, 203, a + b + c == 4); - throw_arg_unless(y + 4, 204, b == 4); - return 3; - } - } catch (y, x) { - int y = y.cast_to_int(); - try { - throw_arg_if(y, x, x == 200); - throw_arg_if(y + 1, 200, x == 201); - throw_arg_if(x - 203, 200, x == 202); - throw_arg_if(y, 200, x == 203); - throw_arg_if(a + 4, 205, a + b + c == 5); - throw_arg(7, 200); - } catch (v, u) { - int v = v.cast_to_int(); - throw_arg_unless(v, u, u == 205); - if (c == 0) { - return b + 4; - } - throw_arg(v + 1, 200); - } - } - } catch (y, x) { - throw_unless(x, x == 200); - return y.cast_to_int(); - } - return null(); -} - -() test2() { - throw_unless(201, test2_body(0, 4, 0) == 1); - throw_unless(202, test2_body(0, 5, 0) == 2); - throw_unless(203, test2_body(3, 4, 0) == 3); - throw_unless(204, test2_body(3, 0, 0) == 4); - throw_unless(205, test2_body(3, 1, 0) == 5); - throw_unless(206, test2_body(3, 2, 0) == 6); - throw_unless(207, test2_body(3, 1, 2) == 7); - throw_unless(208, test2_body(3, 1, 1) == 8); -} - -() main() { - test1(); - test2(); -} diff --git a/crypto/func/test/w1.fc b/crypto/func/test/w1.fc deleted file mode 100644 index 6efd4f3e1..000000000 --- a/crypto/func/test/w1.fc +++ /dev/null @@ -1,9 +0,0 @@ -(int, int) nested_if(int id) method_id { - dump_stack(); - if (id > 0) { - if (id > 10) { - return (2 * id, 3 * id); - } - } - return (5, 6); -} diff --git a/crypto/func/test/w2.fc b/crypto/func/test/w2.fc deleted file mode 100644 index 3bbcd415a..000000000 --- a/crypto/func/test/w2.fc +++ /dev/null @@ -1,14 +0,0 @@ -_ 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; -} diff --git a/crypto/func/test/w3.fc b/crypto/func/test/w3.fc deleted file mode 100644 index 133918826..000000000 --- a/crypto/func/test/w3.fc +++ /dev/null @@ -1,13 +0,0 @@ -() main(cs) { - int i = 0; - if (cs.slice_refs()) { - do { - i = i + 1; - } until(i > 10); - } - set_data(begin_cell() - .store_uint(1, 32) - .store_uint(2, 32) - .store_uint(i, 32) - .end_cell()); -} diff --git a/crypto/func/test/w4.fc b/crypto/func/test/w4.fc deleted file mode 100644 index 1c0e2cefe..000000000 --- a/crypto/func/test/w4.fc +++ /dev/null @@ -1,13 +0,0 @@ -_ main(cell dict, int t3) { - int index = -1; - do { - (index, slice value, int found) = dict.udict_get_next?(32, index); - if (found) { - (int temp1, int temp2) = (value~load_uint(16), value~load_uint(32)); - if (t3 > temp2) { - dict~udict_delete_get?(32, index); - } - } - } until ( ~ found); - return dict; -} diff --git a/crypto/func/test/w5.fc b/crypto/func/test/w5.fc deleted file mode 100644 index 61136c54c..000000000 --- a/crypto/func/test/w5.fc +++ /dev/null @@ -1,14 +0,0 @@ -(cell) recv_external(slice in_msg) { - cell mydict = new_dict(); - builder r = begin_cell().store_int(10, 16); - mydict~udict_set_builder(32, 1, r ); - int index = -1; - do { - (var index, var value, var found) = mydict.udict_get_next?(32, index); - } until ( ~ found ); - return mydict; -} - -() recv_internal() { - ;; Nothing -} diff --git a/crypto/func/test/w6.fc b/crypto/func/test/w6.fc deleted file mode 100644 index 37251a58e..000000000 --- a/crypto/func/test/w6.fc +++ /dev/null @@ -1,12 +0,0 @@ -int test(int x) method_id { - int i = 0; - ;; int f = false; - do { - i = i + 1; - if (i > 5) { - return 1; - } - int f = (i * i == 64); - } until (f); - return -1; -} diff --git a/crypto/func/test/w7.fc b/crypto/func/test/w7.fc deleted file mode 100644 index dddfd627b..000000000 --- a/crypto/func/test/w7.fc +++ /dev/null @@ -1,14 +0,0 @@ -int test(int y) { - int x = 1; - if (y > 0) { - return 1; - } - return x > 0; -} - -int f(int y) { - if (y > 0) { - return 1; - } - return 2; -} diff --git a/crypto/func/test/w8.fc b/crypto/func/test/w8.fc deleted file mode 100644 index c236b1f12..000000000 --- a/crypto/func/test/w8.fc +++ /dev/null @@ -1,22 +0,0 @@ -int check_signatures(msg_hash, signatures, signers, bitmask_size) { - var bitmask = 0; - var id = -1; - do { - (id, var signature, var f) = signatures.udict_get_next?(32, id); - if (f){ - var sig = signature.preload_bits(512); - var public_key = -1; - do { - (public_key, var cs, var _found) = signers.udict_get_next?(256, public_key); - if (_found){ - if (check_signature(msg_hash, sig, public_key)){ - var signer_index = cs~load_uint(bitmask_size); - bitmask = bitmask | (1 << (signer_index - 1)); - } - } - } until (~ _found); - ;; signature~touch(); - } - } until (~ f); - return bitmask; -} diff --git a/crypto/func/test/w9.fc b/crypto/func/test/w9.fc deleted file mode 100644 index d94355421..000000000 --- a/crypto/func/test/w9.fc +++ /dev/null @@ -1,8 +0,0 @@ -_ g(s) { - var (z, t) = (17, s); - while (z > 0) { - t = s; - z -= 1; - } - return ~ t; -} From 35201845535f9b886a046e03a440af180a29f56a Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Thu, 13 Jun 2024 12:24:08 +0200 Subject: [PATCH 27/30] [FunC] Fix a bug with << operator to zero value --- crypto/func/auto-tests/tests/bit-operators.fc | 53 +++++++++++++++++++ crypto/func/builtins.cpp | 4 +- 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 crypto/func/auto-tests/tests/bit-operators.fc diff --git a/crypto/func/auto-tests/tests/bit-operators.fc b/crypto/func/auto-tests/tests/bit-operators.fc new file mode 100644 index 000000000..3cc5b5226 --- /dev/null +++ b/crypto/func/auto-tests/tests/bit-operators.fc @@ -0,0 +1,53 @@ + +int lshift() { + return (1 << 0) == 1; +} + +int rshift() { + return (1 >> 0) == 1; +} + +int lshift_var(int i) { + return (1 << i) == 1; +} + +int rshift_var(int i) { + return (1 >> i) == 1; +} + +int main(int x) { + if (x == 0) { + return lshift(); + } elseif (x == 1) { + return rshift(); + } elseif (x == 2) { + return lshift_var(0); + } elseif (x == 3) { + return rshift_var(0); + } elseif (x == 4) { + return lshift_var(1); + } else { + return rshift_var(1); + } +} + +int is_claimed(int index) method_id(11) { + int claim_bit_index = index % 256; + int mask = 1 << claim_bit_index; + return (255 & mask) == mask; +} + + +{- + method_id | in | out +TESTCASE | 0 | 0 | -1 +TESTCASE | 0 | 1 | -1 +TESTCASE | 0 | 2 | -1 +TESTCASE | 0 | 3 | -1 +TESTCASE | 0 | 4 | 0 +TESTCASE | 0 | 5 | 0 +TESTCASE | 11 | 0 | -1 +TESTCASE | 11 | 1 | -1 +TESTCASE | 11 | 256 | -1 +TESTCASE | 11 | 8 | 0 +-} diff --git a/crypto/func/builtins.cpp b/crypto/func/builtins.cpp index 218e173d7..b985b56e6 100644 --- a/crypto/func/builtins.cpp +++ b/crypto/func/builtins.cpp @@ -274,7 +274,7 @@ int emulate_lshift(int a, int b) { } int t = ((b & VarDescr::_NonZero) ? VarDescr::_Even : 0); t |= b & VarDescr::_Finite; - return emulate_mul(a, VarDescr::_Int | VarDescr::_Pos | VarDescr::_NonZero | VarDescr::_Even | t); + return emulate_mul(a, VarDescr::_Int | VarDescr::_Pos | VarDescr::_NonZero | t); } int emulate_div(int a, int b) { @@ -320,7 +320,7 @@ int emulate_rshift(int a, int b) { } int t = ((b & VarDescr::_NonZero) ? VarDescr::_Even : 0); t |= b & VarDescr::_Finite; - return emulate_div(a, VarDescr::_Int | VarDescr::_Pos | VarDescr::_NonZero | VarDescr::_Even | t); + return emulate_div(a, VarDescr::_Int | VarDescr::_Pos | VarDescr::_NonZero | t); } int emulate_mod(int a, int b, int round_mode = -1) { From 5867d529269b7f4664deea8901f1176aae25fe7b Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Thu, 13 Jun 2024 12:51:15 +0200 Subject: [PATCH 28/30] [FunC] Bump FunC version to v0.5.0 --- .../auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc | 1 + crypto/func/auto-tests/legacy_tests/config/stdlib.fc | 1 + .../func/auto-tests/legacy_tests/dns-collection/stdlib.fc | 1 + crypto/func/auto-tests/legacy_tests/elector/stdlib.fc | 1 + .../auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc | 1 + .../func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc | 1 + .../auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc | 1 + .../auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc | 1 + .../func/auto-tests/legacy_tests/nft-collection/stdlib.fc | 1 + .../func/auto-tests/legacy_tests/nominator-pool/stdlib.fc | 1 + crypto/func/auto-tests/legacy_tests/storage/stdlib.fc | 1 + crypto/func/auto-tests/legacy_tests/tele-nft-item/stdlib.fc | 1 + .../func/auto-tests/legacy_tests/uni-lock-wallet/stdlib.fc | 1 + crypto/func/auto-tests/legacy_tests/wallet-v4/stdlib.fc | 1 + .../auto-tests/legacy_tests/whales-nominators/stdlib.fc | 1 + crypto/func/func.h | 2 +- crypto/smartcont/stdlib.fc | 6 +++--- 17 files changed, 19 insertions(+), 4 deletions(-) diff --git a/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc b/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc index 3fac94f11..be65b76ee 100644 --- a/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/bsc-bridge-collector/stdlib.fc @@ -1,5 +1,6 @@ // Standard library for funC // +#pragma version >=0.5.0; forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; diff --git a/crypto/func/auto-tests/legacy_tests/config/stdlib.fc b/crypto/func/auto-tests/legacy_tests/config/stdlib.fc index f85fd9072..378566aa5 100644 --- a/crypto/func/auto-tests/legacy_tests/config/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/config/stdlib.fc @@ -1,5 +1,6 @@ ;; Standard library for funC ;; +#pragma version >=0.5.0; forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; diff --git a/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc b/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc index f07218152..6444245c5 100644 --- a/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/dns-collection/stdlib.fc @@ -1,5 +1,6 @@ ;; Standard library for funC ;; +#pragma version >=0.5.0; forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; diff --git a/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc b/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc index 49af552bb..d6298f3b9 100644 --- a/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/elector/stdlib.fc @@ -1,5 +1,6 @@ // Standard library for funC // +#pragma version >=0.5.0; forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; diff --git a/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc b/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc index 9fb900c51..b66293504 100644 --- a/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/eth-bridge-multisig/stdlib.fc @@ -1,5 +1,6 @@ ;; Standard library for funC ;; +#pragma version >=0.5.0; forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; diff --git a/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc b/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc index ddcb2396f..6b9dfa0ef 100644 --- a/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/gg-marketplace/stdlib.fc @@ -1,5 +1,6 @@ ;; Standard library for funC ;; +#pragma version >=0.5.0; forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; diff --git a/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc b/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc index ddcb2396f..6b9dfa0ef 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-minter/imports/stdlib.fc @@ -1,5 +1,6 @@ ;; Standard library for funC ;; +#pragma version >=0.5.0; forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; diff --git a/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc b/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc index ddcb2396f..6b9dfa0ef 100644 --- a/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/jetton-wallet/imports/stdlib.fc @@ -1,5 +1,6 @@ ;; Standard library for funC ;; +#pragma version >=0.5.0; forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; diff --git a/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc b/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc index ddcb2396f..6b9dfa0ef 100644 --- a/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/nft-collection/stdlib.fc @@ -1,5 +1,6 @@ ;; Standard library for funC ;; +#pragma version >=0.5.0; forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; diff --git a/crypto/func/auto-tests/legacy_tests/nominator-pool/stdlib.fc b/crypto/func/auto-tests/legacy_tests/nominator-pool/stdlib.fc index 7f45a6dd7..79c175d7d 100644 --- a/crypto/func/auto-tests/legacy_tests/nominator-pool/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/nominator-pool/stdlib.fc @@ -1,5 +1,6 @@ ;; Standard library for funC ;; +#pragma version >=0.5.0; forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; diff --git a/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc b/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc index 8f966b378..345939aee 100644 --- a/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/storage/stdlib.fc @@ -1,5 +1,6 @@ // Standard library for funC // +#pragma version >=0.5.0; /* # Tuple manipulation primitives diff --git a/crypto/func/auto-tests/legacy_tests/tele-nft-item/stdlib.fc b/crypto/func/auto-tests/legacy_tests/tele-nft-item/stdlib.fc index f93ebf792..7179b1a57 100644 --- a/crypto/func/auto-tests/legacy_tests/tele-nft-item/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/tele-nft-item/stdlib.fc @@ -1,5 +1,6 @@ ;; Standard library for funC ;; +#pragma version >=0.5.0; forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; diff --git a/crypto/func/auto-tests/legacy_tests/uni-lock-wallet/stdlib.fc b/crypto/func/auto-tests/legacy_tests/uni-lock-wallet/stdlib.fc index 7f45a6dd7..79c175d7d 100644 --- a/crypto/func/auto-tests/legacy_tests/uni-lock-wallet/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/uni-lock-wallet/stdlib.fc @@ -1,5 +1,6 @@ ;; Standard library for funC ;; +#pragma version >=0.5.0; forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; diff --git a/crypto/func/auto-tests/legacy_tests/wallet-v4/stdlib.fc b/crypto/func/auto-tests/legacy_tests/wallet-v4/stdlib.fc index a76e869dc..d8f0ead9c 100644 --- a/crypto/func/auto-tests/legacy_tests/wallet-v4/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/wallet-v4/stdlib.fc @@ -1,5 +1,6 @@ ;; Standard library for funC ;; +#pragma version >=0.5.0; forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; diff --git a/crypto/func/auto-tests/legacy_tests/whales-nominators/stdlib.fc b/crypto/func/auto-tests/legacy_tests/whales-nominators/stdlib.fc index c23048349..c918807bd 100644 --- a/crypto/func/auto-tests/legacy_tests/whales-nominators/stdlib.fc +++ b/crypto/func/auto-tests/legacy_tests/whales-nominators/stdlib.fc @@ -1,5 +1,6 @@ ;; Standard library for funC ;; +#pragma version >=0.5.0; forall X -> tuple cons(X head, tuple tail) pure asm "CONS"; forall X -> (X, tuple) uncons(tuple list) pure asm "UNCONS"; diff --git a/crypto/func/func.h b/crypto/func/func.h index faf71f5d5..563d874ee 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -45,7 +45,7 @@ extern std::string generated_from; constexpr int optimize_depth = 20; -const std::string func_version{"0.4.4"}; +const std::string func_version{"0.5.0"}; enum Keyword { _Eof = -1, diff --git a/crypto/smartcont/stdlib.fc b/crypto/smartcont/stdlib.fc index bf6d738b6..33a71ff92 100644 --- a/crypto/smartcont/stdlib.fc +++ b/crypto/smartcont/stdlib.fc @@ -1,6 +1,3 @@ -// Standard library for funC -// - /* This file is part of TON FunC Standard Library. @@ -14,7 +11,10 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + Note, that currently stdlib.fc is distributed as a standalone file, + but since FunC v0.6.0 it will be a part of FunC installation. */ +#pragma version >=0.5.0; /* # Tuple manipulation primitives From 79721d230e6f0888fbb9ee80bf7bdab7072bab31 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Fri, 21 Jun 2024 15:39:19 +0300 Subject: [PATCH 29/30] [FunC] Require parenthesis in tricky bitwise precedence cases Example: "flags & 0xFF != 0" is equivalent to "flags & 1", most likely it's unexpected. Example: "a << 2 + 1" (equal to "a << 3", probably unexpected). The only way to suppress this error for the programmer is to use parenthesis. --- .../auto-tests/tests/invalid-bitwise-1.fc | 9 ++ .../auto-tests/tests/invalid-bitwise-2.fc | 8 ++ .../auto-tests/tests/invalid-bitwise-3.fc | 8 ++ .../auto-tests/tests/invalid-bitwise-4.fc | 6 + .../auto-tests/tests/invalid-bitwise-5.fc | 11 ++ .../auto-tests/tests/invalid-bitwise-6.fc | 9 ++ .../func/auto-tests/tests/invalid-shift-1.fc | 8 ++ crypto/func/auto-tests/tests/op_priority.fc | 25 ++-- crypto/func/func.h | 5 +- crypto/func/parse-func.cpp | 110 +++++++++++++++++- 10 files changed, 189 insertions(+), 10 deletions(-) create mode 100644 crypto/func/auto-tests/tests/invalid-bitwise-1.fc create mode 100644 crypto/func/auto-tests/tests/invalid-bitwise-2.fc create mode 100644 crypto/func/auto-tests/tests/invalid-bitwise-3.fc create mode 100644 crypto/func/auto-tests/tests/invalid-bitwise-4.fc create mode 100644 crypto/func/auto-tests/tests/invalid-bitwise-5.fc create mode 100644 crypto/func/auto-tests/tests/invalid-bitwise-6.fc create mode 100644 crypto/func/auto-tests/tests/invalid-shift-1.fc diff --git a/crypto/func/auto-tests/tests/invalid-bitwise-1.fc b/crypto/func/auto-tests/tests/invalid-bitwise-1.fc new file mode 100644 index 000000000..545681d59 --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-bitwise-1.fc @@ -0,0 +1,9 @@ +int main(int flags) { + return flags & 0xFF != 0; +} + +{- +@compilation_should_fail +@stderr & has lower precedence than != +@stderr Use parenthesis +-} diff --git a/crypto/func/auto-tests/tests/invalid-bitwise-2.fc b/crypto/func/auto-tests/tests/invalid-bitwise-2.fc new file mode 100644 index 000000000..eaf83bebd --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-bitwise-2.fc @@ -0,0 +1,8 @@ +int justTrue() { return true; } + +const a = justTrue() | 1 < 9; + +{- +@compilation_should_fail +@stderr | has lower precedence than < +-} diff --git a/crypto/func/auto-tests/tests/invalid-bitwise-3.fc b/crypto/func/auto-tests/tests/invalid-bitwise-3.fc new file mode 100644 index 000000000..b083acd66 --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-bitwise-3.fc @@ -0,0 +1,8 @@ +int justTrue() { return true; } + +const a = justTrue() | (1 < 9) | justTrue() != true; + +{- +@compilation_should_fail +@stderr | has lower precedence than != +-} diff --git a/crypto/func/auto-tests/tests/invalid-bitwise-4.fc b/crypto/func/auto-tests/tests/invalid-bitwise-4.fc new file mode 100644 index 000000000..c13f73d55 --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-bitwise-4.fc @@ -0,0 +1,6 @@ +const a = (1) <=> (0) ^ 8; + +{- +@compilation_should_fail +@stderr ^ has lower precedence than <=> +-} diff --git a/crypto/func/auto-tests/tests/invalid-bitwise-5.fc b/crypto/func/auto-tests/tests/invalid-bitwise-5.fc new file mode 100644 index 000000000..1a1d61178 --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-bitwise-5.fc @@ -0,0 +1,11 @@ +const MAX_SLIPAGE = 100; + +_ main(int jetton_amount, int msg_value, int slippage) { + if (0 == jetton_amount) | (msg_value == 0) | true | false | slippage > MAX_SLIPAGE { + } +} + +{- +@compilation_should_fail +@stderr | has lower precedence than > +-} diff --git a/crypto/func/auto-tests/tests/invalid-bitwise-6.fc b/crypto/func/auto-tests/tests/invalid-bitwise-6.fc new file mode 100644 index 000000000..e2825f958 --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-bitwise-6.fc @@ -0,0 +1,9 @@ +_ main() { + if ((1 == 1) | (2 == 2) & (3 == 3)) { + } +} + +{- +@compilation_should_fail +@stderr mixing | with & without parenthesis +-} diff --git a/crypto/func/auto-tests/tests/invalid-shift-1.fc b/crypto/func/auto-tests/tests/invalid-shift-1.fc new file mode 100644 index 000000000..2c0d3f23c --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-shift-1.fc @@ -0,0 +1,8 @@ +_ main(int flags) { + return flags << 1 + 32; +} + +{- +@compilation_should_fail +@stderr << has lower precedence than + +-} diff --git a/crypto/func/auto-tests/tests/op_priority.fc b/crypto/func/auto-tests/tests/op_priority.fc index f8eff74cc..ac358f070 100644 --- a/crypto/func/auto-tests/tests/op_priority.fc +++ b/crypto/func/auto-tests/tests/op_priority.fc @@ -1,35 +1,44 @@ int justTrue() { return true; } int test1(int x, int y, int z) method_id(101) { - return x > 0 & y > 0 & z > 0; + return (x > 0) & (y > 0) & (z > 0); } int test2(int x, int y, int z) method_id(102) { - return x > (0 & y > 0 & z > 0); + return x > (0 & (y > 0) & (z > 0)); } int test3(int x, int y, int z) method_id(103) { - if (x < 0 | y < 0) { + if ((x < 0) | (y < 0)) { return z < 0; } - return x > 0 & y > 0; + return (x > 0) & (y > 0); } int test4(int x, int y, int mode) method_id(104) { if (mode == 1) { - return x == 10 | (y == 20); + return (x == 10) | (y == 20); } if (mode == 2) { - return x == 10 | y == 20; + return (x == 10) | (y == 20); } else { return x == (10 | (y == 20)); } } int test5(int status) method_id(105) { - return justTrue() & status == 1 & (justTrue() & status) == 1; + return justTrue() & (status == 1) & ((justTrue() & status) == 1); } -() main() { } +int _ 0, 3 & (3 > 0), 3 & (_<_(3, 0)), + 3 & _, or similar +// (an expression `1 < 2` is expressed as `_<_(1,2)`, see builtins.cpp) +static bool is_comparison_binary_op(const Expr* e_apply) { + const std::string& name = e_apply->sym->name(); + const size_t len = name.size(); + if (len < 3 || len > 5 || name[0] != '_' || name[len-1] != '_') { + return false; // not "_<_" and similar + } + + char c1 = name[1]; + char c2 = name[2]; + // < > <= != == >= <=> + return (len == 3 && (c1 == '<' || c1 == '>')) || + (len == 4 && (c1 == '<' || c1 == '>' || c1 == '!' || c1 == '=') && c2 == '=') || + (len == 5 && (c1 == '<' && c2 == '=' && name[3] == '>')); +} + +// same as above, but to detect bitwise operators: & | ^ +// (in FunC, they are used as logical ones due to absence of a boolean type and && || operators) +static bool is_bitwise_binary_op(const Expr* e_apply) { + const std::string& name = e_apply->sym->name(); + const size_t len = name.size(); + if (len != 3 || name[0] != '_' || name[len-1] != '_') { + return false; + } + + char c1 = name[1]; + return c1 == '&' || c1 == '|' || c1 == '^'; +} + +// same as above, but to detect addition/subtraction +static bool is_add_or_sub_binary_op(const Expr* e_apply) { + const std::string& name = e_apply->sym->name(); + const size_t len = name.size(); + if (len != 3 || name[0] != '_' || name[len-1] != '_') { + return false; + } + + char c1 = name[1]; + return c1 == '+' || c1 == '-'; +} + +static inline std::string get_builtin_operator_name(sym_idx_t sym_builtin) { + std::string underscored = symbols.get_name(sym_builtin); + return underscored.substr(1, underscored.size() - 2); +} + +// fire an error for a case "flags & 0xFF != 0" (equivalent to "flags & 1", probably unexpected) +// it would better be a warning, but we decided to make it a strict error +[[gnu::cold]] static void fire_error_lower_precedence(const SrcLocation& loc, sym_idx_t op_lower, sym_idx_t op_higher) { + std::string name_lower = get_builtin_operator_name(op_lower); + std::string name_higher = get_builtin_operator_name(op_higher); + throw src::ParseError(loc, name_lower + " has lower precedence than " + name_higher + + ", probably this code won't work as you expected. " + "Use parenthesis: either (... " + name_lower + " ...) to evaluate it first, or (... " + name_higher + " ...) to suppress this error."); +} + +// fire an error for a case "arg1 & arg2 | arg3" +[[gnu::cold]] static void fire_error_mix_bitwise_and_or(const SrcLocation& loc, sym_idx_t op1, sym_idx_t op2) { + std::string name1 = get_builtin_operator_name(op1); + std::string name2 = get_builtin_operator_name(op2); + throw src::ParseError(loc, "mixing " + name1 + " with " + name2 + " without parenthesis" + ", probably this code won't work as you expected. " + "Use parenthesis to emphasize operator precedence."); +} + +// diagnose when bitwise operators are used in a probably wrong way due to tricky precedence +// example: "flags & 0xFF != 0" is equivalent to "flags & 1", most likely it's unexpected +// the only way to suppress this error for the programmer is to use parenthesis +static void diagnose_bitwise_precedence(const SrcLocation& loc, sym_idx_t bitwise_sym, const Expr* lhs, const Expr* rhs) { + // handle "0 != flags & 0xFF" (lhs = "0 != flags") + if (!lhs->is_inside_parenthesis() && + lhs->cls == Expr::_Apply && lhs->e_type->is_int() && // fast false if 100% not + is_comparison_binary_op(lhs)) { + fire_error_lower_precedence(loc, bitwise_sym, lhs->sym->sym_idx); + // there is a tiny bug: "flags & _!=_(0xFF,0)" will also suggest to wrap rhs into parenthesis + } + + // handle "flags & 0xFF != 0" (rhs = "0xFF != 0") + if (!rhs->is_inside_parenthesis() && + rhs->cls == Expr::_Apply && rhs->e_type->is_int() && + is_comparison_binary_op(rhs)) { + fire_error_lower_precedence(loc, bitwise_sym, rhs->sym->sym_idx); + } + + // handle "arg1 & arg2 | arg3" (lhs = "arg1 & arg2") + if (!lhs->is_inside_parenthesis() && + lhs->cls == Expr::_Apply && lhs->e_type->is_int() && + is_bitwise_binary_op(lhs) && + lhs->sym->sym_idx != bitwise_sym) { + fire_error_mix_bitwise_and_or(loc, lhs->sym->sym_idx, bitwise_sym); + } +} + +// diagnose "a << 8 + 1" (equivalent to "a << 9", probably unexpected) +static void diagnose_addition_in_bitshift(const SrcLocation& loc, sym_idx_t bitshift_sym, const Expr* rhs) { + if (!rhs->is_inside_parenthesis() && + rhs->cls == Expr::_Apply && rhs->e_type->is_int() && + is_add_or_sub_binary_op(rhs)) { + fire_error_lower_precedence(loc, bitshift_sym, rhs->sym->sym_idx); + } +} + /* * * PARSE SOURCE @@ -268,7 +371,7 @@ void parse_const_decl(Lexer& lex) { CodeBlob code; // Handles processing and resolution of literals and consts auto x = parse_expr(lex, code, false); // also does lex.next() ! - if (x->flags != Expr::_IsRvalue) { + if (!x->is_rvalue()) { lex.cur().error("expression is not strictly Rvalue"); } if ((wanted_type == Expr::_Const) && (x->cls == Expr::_Apply)) @@ -447,6 +550,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { } Expr* res = parse_expr(lex, code, nv); if (lex.tp() == ')') { + res->flags |= Expr::_IsInsideParenthesis; lex.expect(clbr); return res; } @@ -858,6 +962,7 @@ Expr* parse_expr17(Lexer& lex, CodeBlob& code, bool nv) { lex.next(); auto x = parse_expr20(lex, code, false); x->chk_rvalue(lex.cur()); + diagnose_addition_in_bitshift(loc, name, x); res = new Expr{Expr::_Apply, name, {res, x}}; res->here = loc; res->set_val(t); @@ -901,6 +1006,9 @@ Expr* parse_expr14(Lexer& lex, CodeBlob& code, bool nv) { lex.next(); auto x = parse_expr15(lex, code, false); x->chk_rvalue(lex.cur()); + // diagnose tricky bitwise precedence, like "flags & 0xFF != 0" (& has lower precedence) + diagnose_bitwise_precedence(loc, name, res, x); + res = new Expr{Expr::_Apply, name, {res, x}}; res->here = loc; res->set_val(t); From e2467b8ba4718d33f4c3fa6b096e6d60b45733c6 Mon Sep 17 00:00:00 2001 From: Aleksandr Kirsanov Date: Sat, 22 Jun 2024 01:19:57 +0300 Subject: [PATCH 30/30] [FunC] Reserve '!' for the future, identifiers can't start with it --- crypto/func/auto-tests/tests/invalid-ident-1.fc | 15 +++++++++++++++ crypto/func/auto-tests/tests/invalid-ident-2.fc | 11 +++++++++++ crypto/func/auto-tests/tests/s1.fc | 3 +++ crypto/func/auto-tests/tests/test-math.fc | 14 +++++++------- crypto/parser/lexer.cpp | 7 +++++++ crypto/parser/lexer.h | 5 +++++ 6 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 crypto/func/auto-tests/tests/invalid-ident-1.fc create mode 100644 crypto/func/auto-tests/tests/invalid-ident-2.fc diff --git a/crypto/func/auto-tests/tests/invalid-ident-1.fc b/crypto/func/auto-tests/tests/invalid-ident-1.fc new file mode 100644 index 000000000..32d5406af --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-ident-1.fc @@ -0,0 +1,15 @@ +;; this is allowed, lexer doesn't stop on it +int get_false!() { return false; } + +_ main() { + var x = false; + if (!x) { + return 1; + } + return 0; +} + +{- +@compilation_should_fail +@stderr '!' is reserved for the future +-} diff --git a/crypto/func/auto-tests/tests/invalid-ident-2.fc b/crypto/func/auto-tests/tests/invalid-ident-2.fc new file mode 100644 index 000000000..c42727f7f --- /dev/null +++ b/crypto/func/auto-tests/tests/invalid-ident-2.fc @@ -0,0 +1,11 @@ +_ main() { + var x = false; + var b = ! x; + return b; +} + +{- +@compilation_should_fail +@stderr var b = ! x; +@stderr '!' is reserved for the future +-} diff --git a/crypto/func/auto-tests/tests/s1.fc b/crypto/func/auto-tests/tests/s1.fc index 0dce5d979..f320df9f2 100644 --- a/crypto/func/auto-tests/tests/s1.fc +++ b/crypto/func/auto-tests/tests/s1.fc @@ -1,4 +1,7 @@ get slice ascii_slice() { + if (false) { + return "!string!"; // !string! + } return "string"; } diff --git a/crypto/func/auto-tests/tests/test-math.fc b/crypto/func/auto-tests/tests/test-math.fc index 27fea3612..67d74fde9 100644 --- a/crypto/func/auto-tests/tests/test-math.fc +++ b/crypto/func/auto-tests/tests/test-math.fc @@ -4,7 +4,7 @@ forall X -> (tuple, ()) ~tset(tuple t, int idx, X val) pure asm(t val idx) "SETI ;; computes 1-acos(x)/Pi by a very simple, extremely slow (~70k gas) and imprecise method ;; fixed256 acos_prepare_slow(fixed255 x); -int acos_prepare_slow_f255(int x) inline { +int acos_prepare_slow_f255!(int x) inline { x -= (x == 0); int t = 1; repeat (255) { @@ -16,14 +16,14 @@ int acos_prepare_slow_f255(int x) inline { ;; extremely slow (~70k gas) and somewhat imprecise (very imprecise when x is small), for testing only ;; fixed254 acos_slow(fixed255 x); -int acos_slow_f255(int x) inline_ref { - int t = acos_prepare_slow_f255(x); +int acos_slow_f255@(int x) inline_ref { + int t = acos_prepare_slow_f255!(x); return - mulrshiftr256(t + (-1 << 256), Pi_const_f254()); } ;; fixed255 asin_slow(fixed255 x); -int asin_slow_f255(int x) inline_ref { - int t = acos_prepare_slow_f255(abs(x)) % (1 << 255); +int asin_slow_f255%(int x) inline_ref { + int t = acos_prepare_slow_f255!(abs(x)) % (1 << 255); return muldivr(t, Pi_const_f254(), 1 << 255) * sgn(x); } @@ -116,13 +116,13 @@ int asin_f255_test(x) method_id(10023) { return asin_f255(x); } int asin_slow_f255_test(x) method_id(10024) { - return asin_slow_f255(x); + return asin_slow_f255%(x); } int acos_f255_test(x) method_id(10025) { return acos_f255(x); } int acos_slow_f255_test(x) method_id(10026) { - return acos_slow_f255(x); + return acos_slow_f255@(x); } int fixed248::atan_test(x) method_id(10027) { return fixed248::atan(x); diff --git a/crypto/parser/lexer.cpp b/crypto/parser/lexer.cpp index 418860ebe..db19911f1 100644 --- a/crypto/parser/lexer.cpp +++ b/crypto/parser/lexer.cpp @@ -311,12 +311,16 @@ const Lexem& Lexer::next() { return lexem; } int len = 0, pc = -0x100; + bool starts_with_excl = false; while (end < src.get_end_ptr()) { c = *end; bool repeated = (c == pc && is_repeatable(c)); if (c == ' ' || c == 9 || (len && is_left_active(c) && !repeated)) { break; } + if (c == '!' && !len) { + starts_with_excl = true; + } ++len; ++end; if (is_right_active(c) && !repeated) { @@ -325,6 +329,9 @@ const Lexem& Lexer::next() { pc = c; } lexem.set(std::string{src.get_ptr(), end}, src.here()); + if (starts_with_excl && is_FunC() && lexem.str != "!=") { + throw ParseError(lexem.loc, "'!' is reserved for the future, don't use it in FunC code"); + } src.set_ptr(end); // std::cerr << lexem.name_str() << ' ' << lexem.str << std::endl; return lexem; diff --git a/crypto/parser/lexer.h b/crypto/parser/lexer.h index 904d8b31d..38f163240 100644 --- a/crypto/parser/lexer.h +++ b/crypto/parser/lexer.h @@ -120,6 +120,11 @@ class Lexer { private: void set_spec(std::array& arr, std::string setup); bool is_multiline_quote(const char* begin, const char* end); + + // this class (like all sources in /ton/crypto/parser) is shared between FunC and tlbc + // (in the future, I'll implement lexer from scratch, FunC/TL lexers would have nothing in common) + bool is_FunC() const { return cmt_op2[1] == 47; } + bool is_TLB() const { return !is_FunC(); } }; } // namespace src