Skip to content

Commit ebbab54

Browse files
committed
[Tolk] Tolk v0.5.0 as FunC v0.5.0 could have been like
All changes from PR "FunC v0.5.0": #1026 Instead of developing FunC, we decided to fork it. BTW, the first Tolk release will be v0.6, a metaphor of FunC v0.5 that missed a chance to occur.
1 parent 82648eb commit ebbab54

File tree

21 files changed

+1362
-806
lines changed

21 files changed

+1362
-806
lines changed

crypto/smartcont/mathlib.tolk

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,14 @@ int fixed248::acot(int x) inline_ref;
8181

8282
;; random number uniformly distributed in [0..1)
8383
;; fixed248 random();
84-
int fixed248::random() impure inline;
84+
int fixed248::random() inline;
8585
;; random number with standard normal distribution (2100 gas on average)
8686
;; fixed248 nrand();
87-
int fixed248::nrand() impure inline;
87+
int fixed248::nrand() inline;
8888
;; generates a random number approximately distributed according to the standard normal distribution (1200 gas)
8989
;; (fails chi-squared test, but it is shorter and faster than fixed248::nrand())
9090
;; fixed248 nrand_fast();
91-
int fixed248::nrand_fast() impure inline;
91+
int fixed248::nrand_fast() inline;
9292

9393
-} ;; end (declarations)
9494

@@ -880,7 +880,7 @@ int fixed248::acot(int x) inline_ref {
880880
;; generated by Kinderman--Monahan ratio method modified by J.Leva
881881
;; spends ~ 2k..3k gas on average
882882
;; fixed252 nrand();
883-
int nrand_f252() impure inline_ref {
883+
int nrand_f252() inline_ref {
884884
var (x, s, t, A, B, r0) = (nan(), touch(29483) << 236, touch(-3167) << 239, 12845, 16693, 9043);
885885
;; 4/sqrt(e*Pi) = 1.369 loop iterations on average
886886
do {
@@ -910,7 +910,7 @@ int nrand_f252() impure inline_ref {
910910
;; generates a random number approximately distributed according to the standard normal distribution
911911
;; much faster than nrand_f252(), should be suitable for most purposes when only several random numbers are needed
912912
;; fixed252 nrand_fast();
913-
int nrand_fast_f252() impure inline_ref {
913+
int nrand_fast_f252() inline_ref {
914914
int t = touch(-3) << 253; ;; -6. as fixed252
915915
repeat (12) {
916916
t += random() / 16; ;; add together 12 uniformly random numbers
@@ -920,18 +920,18 @@ int nrand_fast_f252() impure inline_ref {
920920

921921
;; random number uniformly distributed in [0..1)
922922
;; fixed248 random();
923-
int fixed248::random() impure inline {
923+
int fixed248::random() inline {
924924
return random() >> 8;
925925
}
926926

927927
;; random number with standard normal distribution
928928
;; fixed248 nrand();
929-
int fixed248::nrand() impure inline {
929+
int fixed248::nrand() inline {
930930
return nrand_f252() ~>> 4;
931931
}
932932

933933
;; generates a random number approximately distributed according to the standard normal distribution
934934
;; fixed248 nrand_fast();
935-
int fixed248::nrand_fast() impure inline {
935+
int fixed248::nrand_fast() inline {
936936
return nrand_fast_f252() ~>> 4;
937937
}

crypto/smartcont/stdlib.tolk

Lines changed: 496 additions & 443 deletions
Large diffs are not rendered by default.

lite-client/lite-client.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ bool TestNode::show_help(std::string command) {
926926
"saveaccount[code|data] <filename> <addr> [<block-id-ext>]\tSaves into specified file the most recent state "
927927
"(StateInit) or just the code or data of specified account; <addr> is in "
928928
"[<workchain>:]<hex-or-base64-addr> format\n"
929-
"runmethod[full] <addr> [<block-id-ext>] <method-id> <params>...\tRuns GET method <method-id> of account "
929+
"runmethod[full] <addr> [<block-id-ext>] <name> <params>...\tRuns GET method <name> of account "
930930
"<addr> "
931931
"with specified parameters\n"
932932
"dnsresolve [<block-id-ext>] <domain> [<category>]\tResolves a domain starting from root dns smart contract\n"

tolk/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ target_link_libraries(tolk PUBLIC git ton_crypto) # todo replace with ton_crypt
2424
if (WINGETOPT_FOUND)
2525
target_link_libraries_system(tolk wingetopt)
2626
endif ()
27+
if (${TOLK_DEBUG}) # -DTOLK_DEBUG=1 in CMake options => #define TOLK_DEBUG (for development purposes)
28+
message(STATUS "TOLK_DEBUG is ON")
29+
target_compile_definitions(tolk PRIVATE TOLK_DEBUG=1)
30+
endif()
2731

2832
if (USE_EMSCRIPTEN)
2933
add_executable(tolkfiftlib tolk-wasm.cpp ${TOLK_SOURCE})

tolk/abscode.cpp

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -221,15 +221,6 @@ void VarDescrList::show(std::ostream& os) const {
221221
os << " ]\n";
222222
}
223223

224-
void Op::flags_set_clear(int set, int clear) {
225-
flags = (flags | set) & ~clear;
226-
for (auto& op : block0) {
227-
op.flags_set_clear(set, clear);
228-
}
229-
for (auto& op : block1) {
230-
op.flags_set_clear(set, clear);
231-
}
232-
}
233224
void Op::split_vars(const std::vector<TmpVar>& vars) {
234225
split_var_list(left, vars);
235226
split_var_list(right, vars);
@@ -294,7 +285,7 @@ void Op::show(std::ostream& os, const std::vector<TmpVar>& vars, std::string pfx
294285
if (noreturn()) {
295286
dis += "<noret> ";
296287
}
297-
if (!is_pure()) {
288+
if (impure()) {
298289
dis += "<impure> ";
299290
}
300291
switch (cl) {
@@ -467,12 +458,6 @@ void Op::show_block(std::ostream& os, const Op* block, const std::vector<TmpVar>
467458
os << pfx << "}";
468459
}
469460

470-
void CodeBlob::flags_set_clear(int set, int clear) {
471-
for (auto& op : ops) {
472-
op.flags_set_clear(set, clear);
473-
}
474-
}
475-
476461
std::ostream& operator<<(std::ostream& os, const CodeBlob& code) {
477462
code.print(os);
478463
return os;

tolk/analyzer.cpp

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -360,10 +360,10 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) {
360360
case _Tuple:
361361
case _UnTuple: {
362362
// left = EXEC right;
363-
if (!next_var_info.count_used(left) && is_pure()) {
363+
if (!next_var_info.count_used(left) && !impure()) {
364364
// all variables in `left` are not needed
365365
if (edit) {
366-
disable();
366+
set_disabled();
367367
}
368368
return std_compute_used_vars(true);
369369
}
@@ -372,7 +372,7 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) {
372372
case _SetGlob: {
373373
// GLOB = right
374374
if (right.empty() && edit) {
375-
disable();
375+
set_disabled();
376376
}
377377
return std_compute_used_vars(right.empty());
378378
}
@@ -399,7 +399,7 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) {
399399
}
400400
if (!cnt && edit) {
401401
// all variables in `left` are not needed
402-
disable();
402+
set_disabled();
403403
}
404404
return set_var_info(std::move(new_var_info));
405405
}
@@ -860,15 +860,45 @@ VarDescrList Op::fwd_analyze(VarDescrList values) {
860860
}
861861
}
862862

863-
bool Op::set_noreturn(bool nr) {
864-
if (nr) {
863+
void Op::set_disabled(bool flag) {
864+
if (flag) {
865+
flags |= _Disabled;
866+
} else {
867+
flags &= ~_Disabled;
868+
}
869+
}
870+
871+
872+
bool Op::set_noreturn(bool flag) {
873+
if (flag) {
865874
flags |= _NoReturn;
866875
} else {
867876
flags &= ~_NoReturn;
868877
}
869-
return nr;
878+
return flag;
879+
}
880+
881+
void Op::set_impure(const CodeBlob &code) {
882+
// todo calling this function with `code` is a bad design (flags are assigned after Op is constructed)
883+
// later it's better to check this somewhere in code.emplace_back()
884+
if (code.flags & CodeBlob::_ForbidImpure) {
885+
throw ParseError(where, "An impure operation in a pure function");
886+
}
887+
flags |= _Impure;
870888
}
871889

890+
void Op::set_impure(const CodeBlob &code, bool flag) {
891+
if (flag) {
892+
if (code.flags & CodeBlob::_ForbidImpure) {
893+
throw ParseError(where, "An impure operation in a pure function");
894+
}
895+
flags |= _Impure;
896+
} else {
897+
flags &= ~_Impure;
898+
}
899+
}
900+
901+
872902
bool Op::mark_noreturn() {
873903
switch (cl) {
874904
case _Nop:
@@ -888,13 +918,14 @@ bool Op::mark_noreturn() {
888918
case _Call:
889919
return set_noreturn(next->mark_noreturn());
890920
case _Return:
891-
return set_noreturn(true);
921+
return set_noreturn();
892922
case _If:
893923
case _TryCatch:
924+
// note, that & | (not && ||) here and below is mandatory to invoke both left and right calls
894925
return set_noreturn((static_cast<int>(block0->mark_noreturn()) & static_cast<int>(block1 && block1->mark_noreturn())) | static_cast<int>(next->mark_noreturn()));
895926
case _Again:
896927
block0->mark_noreturn();
897-
return set_noreturn(true);
928+
return set_noreturn();
898929
case _Until:
899930
return set_noreturn(static_cast<int>(block0->mark_noreturn()) | static_cast<int>(next->mark_noreturn()));
900931
case _While:

tolk/asmops.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,9 @@ void AsmOpList::show_var_ext(std::ostream& os, std::pair<var_idx_t, const_idx_t>
317317
os << '_' << i;
318318
} else {
319319
var_names_->at(i).show(os, 2);
320+
// if (!var_names_->at(i).v_type->is_int()) {
321+
// os << '<'; var_names_->at(i).v_type->print(os); os << '>';
322+
// }
320323
}
321324
if ((unsigned)j < constants_.size() && constants_[j].not_null()) {
322325
os << '=' << constants_[j];

tolk/builtins.cpp

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ using namespace std::literals::string_literals;
2626
*/
2727

2828
int glob_func_cnt, undef_func_cnt, glob_var_cnt, const_cnt;
29-
std::vector<SymDef*> glob_func, glob_vars;
29+
std::vector<SymDef*> glob_func, glob_vars, glob_get_methods;
3030
std::set<std::string> prohibited_var_names;
3131

32-
SymDef* predefine_builtin_func(std::string name, TypeExpr* func_type) {
32+
SymDef* define_builtin_func_impl(const std::string& name, SymValAsmFunc* func_val) {
3333
if (name.back() == '_') {
3434
prohibited_var_names.insert(name);
3535
}
@@ -42,30 +42,40 @@ SymDef* predefine_builtin_func(std::string name, TypeExpr* func_type) {
4242
std::cerr << "fatal: global function `" << name << "` already defined" << std::endl;
4343
std::exit(1);
4444
}
45+
func_val->flags |= SymValFunc::flagBuiltinFunction;
46+
def->value = func_val;
47+
#ifdef TOLK_DEBUG
48+
dynamic_cast<SymValAsmFunc*>(def->value)->name = name;
49+
#endif
4550
return def;
4651
}
4752

48-
template <typename T>
49-
SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const T& func, bool impure = false) {
50-
SymDef* def = predefine_builtin_func(name, func_type);
51-
def->value = new SymValAsmFunc{func_type, func, impure};
52-
return def;
53+
SymDef* define_builtin_func(const std::string& name, TypeExpr* func_type, const simple_compile_func_t& func, bool impure = false) {
54+
return define_builtin_func_impl(name, new SymValAsmFunc{func_type, func, !impure});
55+
}
56+
57+
SymDef* define_builtin_func(const std::string& name, TypeExpr* func_type, const compile_func_t& func, bool impure = false) {
58+
return define_builtin_func_impl(name, new SymValAsmFunc{func_type, func, !impure});
59+
}
60+
61+
SymDef* define_builtin_func(const std::string& name, TypeExpr* func_type, const AsmOp& macro, bool impure = false) {
62+
return define_builtin_func_impl(name, new SymValAsmFunc{func_type, make_simple_compile(macro), !impure});
5363
}
5464

55-
template <typename T>
56-
SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const T& func, std::initializer_list<int> arg_order,
65+
SymDef* define_builtin_func(const std::string& name, TypeExpr* func_type, const simple_compile_func_t& func, std::initializer_list<int> arg_order,
5766
std::initializer_list<int> ret_order = {}, bool impure = false) {
58-
SymDef* def = predefine_builtin_func(name, func_type);
59-
def->value = new SymValAsmFunc{func_type, func, arg_order, ret_order, impure};
60-
return def;
67+
return define_builtin_func_impl(name, new SymValAsmFunc{func_type, func, arg_order, ret_order, !impure});
6168
}
6269

63-
SymDef* define_builtin_func(std::string name, TypeExpr* func_type, const AsmOp& macro,
70+
SymDef* define_builtin_func(const std::string& name, TypeExpr* func_type, const compile_func_t& func, std::initializer_list<int> arg_order,
71+
std::initializer_list<int> ret_order = {}, bool impure = false) {
72+
return define_builtin_func_impl(name, new SymValAsmFunc{func_type, func, arg_order, ret_order, !impure});
73+
}
74+
75+
SymDef* define_builtin_func(const std::string& name, TypeExpr* func_type, const AsmOp& macro,
6476
std::initializer_list<int> arg_order, std::initializer_list<int> ret_order = {},
6577
bool impure = false) {
66-
SymDef* def = predefine_builtin_func(name, func_type);
67-
def->value = new SymValAsmFunc{func_type, make_simple_compile(macro), arg_order, ret_order, impure};
68-
return def;
78+
return define_builtin_func_impl(name, new SymValAsmFunc{func_type, make_simple_compile(macro), arg_order, ret_order, !impure});
6979
}
7080

7181
SymDef* force_autoapply(SymDef* def) {
@@ -262,7 +272,7 @@ int emulate_lshift(int a, int b) {
262272
}
263273
int t = ((b & VarDescr::_NonZero) ? VarDescr::_Even : 0);
264274
t |= b & VarDescr::_Finite;
265-
return emulate_mul(a, VarDescr::_Int | VarDescr::_Pos | VarDescr::_NonZero | VarDescr::_Even | t);
275+
return emulate_mul(a, VarDescr::_Int | VarDescr::_Pos | VarDescr::_NonZero | t);
266276
}
267277

268278
int emulate_div(int a, int b) {
@@ -308,7 +318,7 @@ int emulate_rshift(int a, int b) {
308318
}
309319
int t = ((b & VarDescr::_NonZero) ? VarDescr::_Even : 0);
310320
t |= b & VarDescr::_Finite;
311-
return emulate_div(a, VarDescr::_Int | VarDescr::_Pos | VarDescr::_NonZero | VarDescr::_Even | t);
321+
return emulate_div(a, VarDescr::_Int | VarDescr::_Pos | VarDescr::_NonZero | t);
312322
}
313323

314324
int emulate_mod(int a, int b, int round_mode = -1) {
@@ -1128,9 +1138,9 @@ void define_builtins() {
11281138
auto Int3 = TypeExpr::new_tensor({Int, Int, Int});
11291139
auto TupleInt = TypeExpr::new_tensor({Tuple, Int});
11301140
auto SliceInt = TypeExpr::new_tensor({Slice, Int});
1131-
auto X = TypeExpr::new_var();
1132-
auto Y = TypeExpr::new_var();
1133-
auto Z = TypeExpr::new_var();
1141+
auto X = TypeExpr::new_var(0);
1142+
auto Y = TypeExpr::new_var(1);
1143+
auto Z = TypeExpr::new_var(2);
11341144
auto XY = TypeExpr::new_tensor({X, Y});
11351145
auto arith_bin_op = TypeExpr::new_map(Int2, Int);
11361146
auto arith_un_op = TypeExpr::new_map(Int, Int);

tolk/codegen.cpp

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ bool Op::generate_code_step(Stack& stack) {
437437
if (disabled()) {
438438
return true;
439439
}
440+
// fun_ref can be nullptr for Op::_CallInd (invoke a variable, not a function)
440441
SymValFunc* func = (fun_ref ? dynamic_cast<SymValFunc*>(fun_ref->value) : nullptr);
441442
auto arg_order = (func ? func->get_arg_order() : nullptr);
442443
auto ret_order = (func ? func->get_ret_order() : nullptr);
@@ -486,27 +487,24 @@ bool Op::generate_code_step(Stack& stack) {
486487
};
487488
if (cl == _CallInd) {
488489
exec_callxargs((int)right.size() - 1, (int)left.size());
490+
} else if (auto asm_fv = dynamic_cast<const SymValAsmFunc*>(fun_ref->value)) {
491+
std::vector<VarDescr> res;
492+
res.reserve(left.size());
493+
for (var_idx_t i : left) {
494+
res.emplace_back(i);
495+
}
496+
asm_fv->compile(stack.o, res, args, where); // compile res := f (args)
489497
} else {
490-
auto func = dynamic_cast<const SymValAsmFunc*>(fun_ref->value);
491-
if (func) {
492-
std::vector<VarDescr> res;
493-
res.reserve(left.size());
494-
for (var_idx_t i : left) {
495-
res.emplace_back(i);
496-
}
497-
func->compile(stack.o, res, args, where); // compile res := f (args)
498+
auto fv = dynamic_cast<const SymValCodeFunc*>(fun_ref->value);
499+
// todo can be fv == nullptr?
500+
std::string name = symbols.get_name(fun_ref->sym_idx);
501+
if (fv && (fv->is_inline() || fv->is_inline_ref())) {
502+
stack.o << AsmOp::Custom(name + " INLINECALLDICT", (int)right.size(), (int)left.size());
503+
} else if (fv && fv->code && fv->code->require_callxargs) {
504+
stack.o << AsmOp::Custom(name + (" PREPAREDICT"), 0, 2);
505+
exec_callxargs((int)right.size() + 1, (int)left.size());
498506
} else {
499-
auto fv = dynamic_cast<const SymValCodeFunc*>(fun_ref->value);
500-
std::string name = symbols.get_name(fun_ref->sym_idx);
501-
bool is_inline = (fv && (fv->flags & 3));
502-
if (is_inline) {
503-
stack.o << AsmOp::Custom(name + " INLINECALLDICT", (int)right.size(), (int)left.size());
504-
} else if (fv && fv->code && fv->code->require_callxargs) {
505-
stack.o << AsmOp::Custom(name + (" PREPAREDICT"), 0, 2);
506-
exec_callxargs((int)right.size() + 1, (int)left.size());
507-
} else {
508-
stack.o << AsmOp::Custom(name + " CALLDICT", (int)right.size(), (int)left.size());
509-
}
507+
stack.o << AsmOp::Custom(name + " CALLDICT", (int)right.size(), (int)left.size());
510508
}
511509
}
512510
stack.s.resize(k);

0 commit comments

Comments
 (0)