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

[Tolk] v0.6 syntax: fun, import, var, types on the right, etc.

Lots of changes, actually. Most noticeable are:
- traditional //comments
- #include -> import
- a rule "import what you use"
- ~ found -> !found (for -1/0)
- null() -> null
- is_null?(v) -> v == null
- throw is a keyword
- catch with swapped arguments
- throw_if, throw_unless -> assert
- do until -> do while
- elseif -> else if
- drop ifnot, elseifnot
- drop rarely used operators

A testing framework also appears here. All tests existed earlier,
but due to significant syntax changes, their history is useless.
This commit is contained in:
tolk-vm 2024-10-31 11:11:41 +04:00
parent 5a3e3595d6
commit e2edadba92
No known key found for this signature in database
GPG key ID: 7905DD7FE0324B12
133 changed files with 8196 additions and 2605 deletions

View file

@ -627,6 +627,30 @@ if (NOT NIX)
endif()
endif()
# Tolk tests
if (NOT NIX)
if (MSVC)
set(PYTHON_VER "python")
else()
set(PYTHON_VER "python3")
endif()
add_test(
NAME test-tolk
COMMAND ${PYTHON_VER} tolk-tester.py tests/
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tolk-tester)
if (WIN32)
set_property(TEST test-tolk PROPERTY ENVIRONMENT
"TOLK_EXECUTABLE=${CMAKE_CURRENT_BINARY_DIR}/tolk/tolk.exe"
"FIFT_EXECUTABLE=${CMAKE_CURRENT_BINARY_DIR}/crypto/fift.exe"
"FIFTPATH=${CMAKE_CURRENT_SOURCE_DIR}/crypto/fift/lib/")
else()
set_property(TEST test-tolk PROPERTY ENVIRONMENT
"TOLK_EXECUTABLE=${CMAKE_CURRENT_BINARY_DIR}/tolk/tolk"
"FIFT_EXECUTABLE=${CMAKE_CURRENT_BINARY_DIR}/crypto/fift"
"FIFTPATH=${CMAKE_CURRENT_SOURCE_DIR}/crypto/fift/lib/")
endif()
endif()
#BEGIN internal
if (NOT TON_ONLY_TONLIB)
add_test(test-adnl test-adnl)

View file

@ -1589,6 +1589,9 @@ forget @proclist forget @proccnt
{ }END> b> } : }END>c
{ }END>c <s } : }END>s
// This is the way how FunC assigns method_id for reserved functions.
// Note, that Tolk entrypoints have other names (`onInternalMessage`, etc.),
// but method_id is assigned not by Fift, but by Tolk code generation.
0 constant recv_internal
-1 constant recv_external
-2 constant run_ticktock

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
fun one(dummy: tuple) {
return 1;
}
fun main(a: int, x: int) {
var y: int = 0;
var z: int = 0;
while ((y = x * x) > a) {
x -= 1;
z = one(null);
}
return (y, z);
}
fun throwIfLt10(x: int): void {
if (x > 10) {
return;
}
throw 234;
return;
}
@method_id(88)
fun test88(x: int) {
try {
var x: void = throwIfLt10(x);
return 0;
} catch(code) {
return code;
}
}
/**
method_id | in | out
@testcase | 0 | 101 15 | 100 1
@testcase | 0 | 101 14 | 100 1
@testcase | 0 | 101 10 | 100 0
@testcase | 0 | 100 10 | 100 0
@testcase | 0 | 100 10 | 100 0
@testcase | 88 | 5 | 234
@testcase | 88 | 50 | 0
*/

85
tolk-tester/tests/a6.tolk Normal file
View file

@ -0,0 +1,85 @@
fun f(a: int, b: int, c: int, d: int, e: int, f: int): (int, int) {
// solve a 2x2 linear equation
var D: int = a*d - b*c;;;; var Dx: int = e*d-b*f ;;;; var Dy: int = a * f - e * c;
return (Dx/D,Dy/D);
};;;;
fun mulDivR(x: int, y: int, z: int): int { return muldivr(x, y, z); }
fun calc_phi(): int {
var n = 1;
repeat (70) { n*=10; };
var p= 1;
var `q`=1;
do {
(p,q)=(q,p+q);
} while (q <= n); //;;
return mulDivR(p, n, q);
}
fun calc_sqrt2(): int {
var n = 1;
repeat (70) { n *= 10; }
var p = 1;
var q = 1;
do {
var t = p + q;
(p, q) = (q, t + q);
} while (q <= n);
return mulDivR(p, n, q);
}
fun calc_root(m: auto): auto {
var base: int=1;
repeat(70) { base *= 10; }
var (a, b, c) = (1,0,-m);
var (p1, q1, p2, q2) = (1, 0, 0, 1);
do {
var k: int=-1;
var (a1, b1, c1) = (0, 0, 0);
do {
k+=1;
(a1, b1, c1) = (a, b, c);
c+=b;
c += b += a;
} while (c <= 0);
(a, b, c) = (-c1, -b1, -a1);
(p1, q1) = (k * p1+q1, p1);
(p2, q2) = (k * p2+q2, p2);
} while (p1 <= base);
return (p1, q1, p2, q2);
}
fun ataninv(base: int, q: int): int { // computes base*atan(1/q)
base=base~/q;
q*=-q;
var sum: int = 0;
var n: int = 1;
do {
sum += base~/n;
base = base~/q;
n += 2;
} while (base != 0);
return sum;
}
fun arctanInv(base: int, q: int): int { return ataninv(base, q); }
fun calc_pi(): int {
var base: int = 64;
repeat (70) { base *= 10; }
return (arctanInv(base << 2, 5) - arctanInv(base, 239))~>>4;
}
fun calcPi(): int { return calc_pi(); }
fun main(): int {
return calcPi();
}
/**
method_id | in | out
@testcase | 0 | | 31415926535897932384626433832795028841971693993751058209749445923078164
@code_hash 84337043972311674339187056298873613816389434478842780265748859098303774481976
*/

View file

@ -0,0 +1,16 @@
fun main(a: int, b: int, c: int, d: int, e: int, f: int): (int, int) {
var D: int = a * d - b * c;
var Dx: int = e * d - b * f;
var Dy: int = a * f - e * c;
return (Dx / D, Dy / D);
}
/**
method_id | in | out
@testcase | 0 | 1 1 1 -1 10 6 | 8 2
@testcase | 0 | 817 -31 624 -241 132272 272276 | 132 -788
@testcase | 0 | -886 562 498 -212 -36452 -68958 | -505 -861
@testcase | 0 | 448 -433 -444 792 150012 -356232 | -218 -572
@testcase | 0 | -40 -821 433 -734 -721629 -741724 | -206 889
@testcase | 0 | -261 -98 -494 868 -166153 733738 | 263 995
*/

View file

@ -0,0 +1,26 @@
@deprecated
fun twice(f: auto, x: auto): auto {
return f (f (x));
}
fun sqr(x: int) {
return x * x;
}
fun main(x: int): int {
var f = sqr;
return twice(f, x) * f(x);
}
@method_id(4)
fun pow6(x: int): int {
return twice(sqr, x) * sqr(x);
}
/**
method_id | in | out
@testcase | 0 | 3 | 729
@testcase | 0 | 10 | 1000000
@testcase | 4 | 3 | 729
@testcase | 4 | 10 | 1000000
*/

24
tolk-tester/tests/a7.tolk Normal file
View file

@ -0,0 +1,24 @@
fun main() { }
@method_id(1)
fun steps(x: int): int {
var n = 0;
while (x > 1) {
n += 1;
if (x & 1) {
x = 3 * x + 1;
} else {
x >>= 1;
}
}
return n;
}
/**
method_id | in | out
@testcase | 1 | 1 | 0
@testcase | 1 | 2 | 1
@testcase | 1 | 5 | 5
@testcase | 1 | 19 | 20
@testcase | 1 | 27 | 111
@testcase | 1 | 100 | 25
*/

View file

@ -0,0 +1,108 @@
fun unsafe_tuple<X>(x: X): tuple
asm "NOP";
fun inc(x: int, y: int): (int, int) {
return (x + y, y * 10);
}
fun ~inc(x: int, y: int): (int, int) {
(x, y) = inc(x, y);
return (x, y);
}
fun ~incWrap(x: int, y: int): (int, int) {
return ~inc(x, y);
}
@method_id(11)
fun test_return(x: int): (int, int, int, int, int, int, int) {
return (x, x~incWrap(x / 20), x, x = x * 2, x, x += 1, x);
}
@method_id(12)
fun test_assign(x: int): (int, int, int, int, int, int, int) {
var (x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int) = (x, x~inc(x / 20), x, x=x*2, x, x+=1, x);
return (x1, x2, x3, x4, x5, x6, x7);
}
@method_id(13)
fun test_tuple(x: int): tuple {
var t: tuple = unsafe_tuple([x, x~incWrap(x / 20), x, x = x * 2, x, x += 1, x]);
return t;
}
@method_id(14)
fun test_tuple_assign(x: int): (int, int, int, int, int, int, int) {
var [x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int] = [x, x~inc(x / 20), x, x = x * 2, x, x += 1, x];
return (x1, x2, x3, x4, x5, x6, x7);
}
fun foo1(x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int): (int, int, int, int, int, int, int) {
return (x1, x2, x3, x4, x5, x6, x7);
}
@method_id(15)
fun test_call_1(x: int): (int, int, int, int, int, int, int) {
return foo1(x, x~inc(x / 20), x, x = x * 2, x, x += 1, x);
}
fun foo2(x1: int, x2: int, x3456: (int, int, int, int), x7: int): (int, int, int, int, int, int, int) {
var (x3: int, x4: int, x5: int, x6: int) = x3456;
return (x1, x2, x3, x4, x5, x6, x7);
}
@method_id(16)
fun test_call_2(x: int): (int, int, int, int, int, int, int) {
return foo2(x, x~incWrap(x / 20), (x, x = x * 2, x, x += 1), x);
}
fun asm_func(x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int): (int, int, int, int, int, int, int)
asm
(x4 x5 x6 x7 x1 x2 x3->0 1 2 3 4 5 6) "NOP";
@method_id(17)
fun test_call_asm_old(x: int): (int, int, int, int, int, int, int) {
return asm_func(x, x += 1, x, x, x~inc(x / 20), x, x = x * 2);
}
@method_id(18)
fun test_call_asm_new(x: int): (int, int, int, int, int, int, int) {
return asm_func(x, x~incWrap(x / 20), x, x = x * 2, x, x += 1, x);
}
global xx: int;
@method_id(19)
fun test_global(x: int): (int, int, int, int, int, int, int) {
xx = x;
return (xx, xx~incWrap(xx / 20), xx, xx = xx * 2, xx, xx += 1, xx);
}
@method_id(20)
fun test_if_else(x: int): (int, int, int, int, int) {
if (x > 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);
}
}
fun main() {
}
/**
method_id | in | out
@testcase | 11 | 100 | 100 50 105 210 210 211 211
@testcase | 12 | 100 | 100 50 105 210 210 211 211
@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 | 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
@fif_codegen_avoid ~incWrap
@code_hash 97139400653362069936987769894397430077752335662822462908581556703209313861576
*/

View file

@ -0,0 +1,145 @@
@pure
fun empty_tuple2(): tuple
asm "NIL";
@pure
fun tpush2<X>(t: tuple, x: X): (tuple, ())
asm "TPUSH";
fun emptyTuple(): tuple { return empty_tuple2(); }
fun tuplePush<X>(t: tuple, value: X): (tuple, ()) { return tpush2(t, value); }
@pure
fun asm_func_1(x: int, y: int, z: int): tuple
asm "3 TUPLE";
@pure
fun asm_func_2(x: int, y: int, z: int): tuple
asm (z y x -> 0) "3 TUPLE";
@pure
fun asm_func_3(x: int, y: int, z: int): tuple
asm (y z x -> 0) "3 TUPLE";
@pure
fun asm_func_4(a: int, b: (int, (int, int)), c: int): tuple
asm (b a c -> 0) "5 TUPLE";
fun asmFunc1(x: int, y: int, z: int): tuple { return asm_func_1(x, y, z); }
fun asmFunc3(x: int, y: int, z: int): tuple { return asm_func_3(x, y, z); }
@pure
fun asm_func_modify(a: tuple, b: int, c: int): (tuple, ())
asm (c b a -> 0) "SWAP TPUSH SWAP TPUSH";
fun asmFuncModify(a: tuple, b: int, c: int): (tuple, ()) { return asm_func_modify(a, b, c); }
global t: tuple;
fun foo(x: int): int {
t~tuplePush(x);
return x * 10;
}
@method_id(11)
fun test_old_1(): (tuple, tuple) {
t = empty_tuple2();
var t2: tuple = asmFunc1(foo(11), foo(22), foo(33));
return (t, t2);
}
@method_id(12)
fun test_old_2(): (tuple, tuple) {
t = emptyTuple();
var t2: tuple = asm_func_2(foo(11), foo(22), foo(33));
return (t, t2);
}
@method_id(13)
fun test_old_3(): (tuple, tuple) {
t = empty_tuple2();
var t2: tuple = asm_func_3(foo(11), foo(22), foo(33));
return (t, t2);
}
@method_id(14)
fun test_old_4(): (tuple, tuple) {
t = emptyTuple();
var t2: tuple = empty_tuple2();
// This actually computes left-to-right even without compute-asm-ltr
t2 = asm_func_4(foo(11), (foo(22), (foo(33), foo(44))), foo(55));
return (t, t2);
}
@method_id(15)
fun test_old_modify(): (tuple, tuple) {
t = empty_tuple2();
var t2: tuple = empty_tuple2();
t2~asmFuncModify(foo(22), foo(33));
return (t, t2);
}
@method_id(16)
fun test_old_dot(): (tuple, tuple) {
t = empty_tuple2();
var t2: tuple = foo(11).asmFunc3(foo(22), foo(33));
return (t, t2);
}
@method_id(21)
fun test_new_1(): (tuple, tuple) {
t = empty_tuple2();
var t2: tuple = asmFunc1(foo(11), foo(22), foo(33));
return (t, t2);
}
@method_id(22)
fun test_new_2(): (tuple, tuple) {
t = empty_tuple2();
var t2: tuple = asm_func_2(foo(11), foo(22), foo(33));
return (t, t2);
}
@method_id(23)
fun test_new_3(): (tuple, tuple) {
t = empty_tuple2();
var t2: tuple = asm_func_3(foo(11), foo(22), foo(33));
return (t, t2);
}
@method_id(24)
fun test_new_4(): (tuple, tuple) {
t = empty_tuple2();
var t2: tuple = asm_func_4(foo(11), (foo(22), (foo(33), foo(44))), foo(55));
return (t, t2);
}
@method_id(25)
fun test_new_modify(): (tuple, tuple) {
t = empty_tuple2();
var t2: tuple = empty_tuple2();
t2~asm_func_modify(foo(22), foo(33));
return (t, t2);
}
@method_id(26)
fun test_new_dot(): (tuple, tuple) {
t = empty_tuple2();
var t2: tuple = foo(11).asm_func_3(foo(22), foo(33));
return (t, t2);
}
fun main() {
}
/**
method_id | in | out
@testcase | 11 | | [ 11 22 33 ] [ 110 220 330 ]
@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 | | [ 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 ]
@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 93068291567112337250118419287631047120002003622184251973082208096953112184588
*/

View file

@ -0,0 +1,53 @@
fun lshift(): int {
return (1 << 0) == 1;
}
fun rshift(): int {
return (1 >> 0) == 1;
}
fun lshift_var(i: int): int {
return (1 << i) == 1;
}
fun rshift_var(i: int): int {
return (1 >> i) == 1;
}
fun main(x: int): int {
if (x == 0) {
return lshift();
} else if (x == 1) {
return rshift();
} else if (x == 2) {
return lshift_var(0);
} else if (x == 3) {
return rshift_var(0);
} else if (x == 4) {
return lshift_var(1);
} else {
return rshift_var(1);
}
}
@method_id(11)
fun is_claimed(index: int): int {
var claim_bit_index: int = index % 256;
var mask: int = 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
*/

27
tolk-tester/tests/c2.tolk Normal file
View file

@ -0,0 +1,27 @@
global op: (int, int) -> int;
fun check_assoc(a: int, b: int, c: int): int {
return op(op(a, b), c) == op(a, op(b, c));
}
fun unnamed_args(_: int, _: slice, _: auto): auto {
return true;
}
fun main(x: int, y: int, z: int): int {
op = `_+_`;
return check_assoc(x, y, z);
}
@method_id(101)
fun test101(x: int, z: int): auto {
return unnamed_args(x, "asdf", z);
}
/**
method_id | in | out
@testcase | 0 | 2 3 9 | -1
@testcase | 0 | 11 22 44 | -1
@testcase | 0 | -1 -10 -20 | -1
@testcase | 101 | 1 10 | -1
*/

View file

@ -0,0 +1,14 @@
fun check_assoc(op: auto, a: int, b: int, c: int) {
return op(op(a, b), c) == op(a, op(b, c));
}
fun main(x: int, y: int, z: int): int {
return check_assoc(`_+_`, x, y, z);
}
/**
method_id | in | out
@testcase | 0 | 2 3 9 | -1
@testcase | 0 | 11 22 44 | -1
@testcase | 0 | -1 -10 -20 | -1
*/

View file

@ -0,0 +1,245 @@
// 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.tolk.
fun myBeginCell(): builder { return begin_cell(); }
fun myEndCell(b: builder): cell { return end_cell(b); }
fun myStoreRef(b: builder, c: cell): builder { return store_ref(b, c); }
fun myStoreUint(b: builder, i: int, bw: int): builder { return store_uint(b, i, bw); }
// 'inline' is not needed actually, but if it exists, it's just ignored
@inline
@pure
fun myBeginParse(c: cell): slice { return begin_parse(c); }
@inline
@pure
fun mySkipBits(s: slice, len: int): slice { return skip_bits(s, len); }
@inline
@pure
fun ~mySkipBits(s: slice, len: int): (slice, ()) { return ~skip_bits(s, len); }
@inline
@pure
fun ~myLoadUint(s: slice, len: int): (slice, int) { return load_uint(s, len); }
fun myComputeDataSize(c: cell, maxCells: int): (int, int, int) { return compute_data_size(c, maxCells); }
fun dict__new(): cell { return new_dict(); }
fun dict__iset(dict: cell, keyLen: int, index: int, value: slice): cell { return idict_set(dict, keyLen, index, value); }
fun ~dict__iset(dict: cell, keyLen: int, index: int, value: slice): (cell, ()) { return ~idict_set(dict, keyLen, index, value); }
fun dict__tryIGet(dict: cell, keyLen: int, index: int): (slice, int) { return idict_get?(dict, keyLen, index); }
fun dict__tryIGetMin(dict: cell, keyLen: int): (int, slice, int) { return idict_get_min?(dict, keyLen); }
fun myEmptyTuple(): tuple { return empty_tuple(); }
fun emptyTuple1(): tuple { return myEmptyTuple(); }
fun emptyTuple11(): tuple { return emptyTuple1(); }
fun myTuplePush<X>(t: tuple, value: X): tuple { return tpush(t, value); }
fun ~myTuplePush<X>(t: tuple, value: X): (tuple, ()) { return ~tpush(t, value); }
fun myTupleAt<X>(t: tuple, index: int): X { return at(t, index); }
fun tripleSecond<X1, Y2, Z3>(p: [X1, Y2, Z3]): Y2 { return triple_second(p); }
@pure
fun nullValue<X>(): X
asm "PUSHNULL";
fun initial1(x: tuple): tuple { return x; }
fun initial2(x: tuple): tuple { return initial1(x); }
// int add(int x, int y) { return x + y; } // this is also a wrapper, as its body is _+_(x,y)
fun fake1(a: int, b: int, c: int): void
asm(a b c) "DROP DROP DROP";
fun fake2(a: int, b: int, c: int): void
asm(b c a) "DROP DROP DROP";
fun fake3(a: int, b: int, c: int): ()
asm(c a b) "DROP DROP DROP";
fun fake4(a: int, b: int, c: int): ()
asm(c b a) "DROP DROP DROP";
fun fake1Wrapper(a: int, b: int, c: int) { return fake1(a, b, c); }
fun fake2Wrapper(a: int, b: int, c: int) { return fake2(a, b, c); }
fun fake3Wrapper(a: int, b: int, c: int) { return fake3(a, b, c); }
fun fake4Wrapper(a: int, b: int, c: int) { return fake4(a, b, c); }
@method_id(101)
fun test1(): [int, int, int] {
var x: int = 1;
var y: int = 1;
var to_be_ref: cell = myBeginCell().myEndCell();
var in_c: builder = myBeginCell().myStoreUint(123, 8);
in_c = myStoreRef(in_c, to_be_ref);
var (a, b, c) = myComputeDataSize(in_c.myEndCell(), 10);
assert(!(b != 8)) throw 101;
assert(!(c != 1), 101);
return [a, b + x, c + y];
}
@method_id(102)
fun test2(): [[int, int, int], int, int, int] {
var dict: cell = dict__new();
dict = dict__iset(dict, 32, 456, myBeginCell().myStoreUint(4560, 32).myEndCell().myBeginParse());
dict.dict__iset(32, 789, myBeginCell().myStoreUint(7890, 32).myEndCell().myBeginParse());
dict~dict__iset(32, 123, myBeginCell().myStoreUint(0, 64).myStoreUint(1230, 32).myStoreUint(1231, 32).myStoreUint(1232, 32).myEndCell().myBeginParse());
var (mink, minv, _) = dict__tryIGetMin(dict, 32);
// skip 64 bits
minv~mySkipBits(16);
minv = minv.mySkipBits(16);
minv.mySkipBits(11); // does nothing
(minv, _) = ~mySkipBits(minv, 16);
mySkipBits(minv, 11); // does nothing
minv~mySkipBits(16);
// load 3*32
var minv1 = minv~myLoadUint(32);
var minv2 = minv~myLoadUint(32);
var minv3 = minv~myLoadUint(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];
}
@method_id(103)
fun test3(): tuple {
var with34: tuple = initial2(emptyTuple1());
with34~myTuplePush(34);
var t: tuple = emptyTuple11();
t = myTuplePush(t, 12);
myTuplePush(t, emptyTuple11()); // does nothing
t~myTuplePush(emptyTuple1());
t~myTuplePush(with34.myTupleAt(0));
t.myTuplePush("123"s); // does nothing
var tri: [cell, int, cell] = [nullValue(), 90 + 1, null];
var f: int = tripleSecond(tri);
(t, _) = ~myTuplePush(t, f);
return t;
}
@method_id(104)
fun test4(a: int, b: int, c: int): int {
fake1Wrapper(a, b, c);
fake2Wrapper(a, b, c);
fake3Wrapper(a, b, c);
fake4Wrapper(a, b, c);
return 10;
}
fun main(): int {
var x: int = now();
return 30;
}
/**
method_id | in | out
@testcase | 101 | | [ 2 9 2 ]
@testcase | 102 | | [ [ 1230 1231 1232 ] -1 -1 0 ]
@testcase | 103 | | [ 12 [] 34 91 ]
@fif_codegen
"""
main PROC:<{
//
30 PUSHINT
}>
"""
@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
OVER // a b c b
8 NEQINT // a b c _21
101 THROWIF
DUP // a b c c
1 NEQINT // a b c _26
101 THROWIF
SWAP // a c b
INC // a c _30
SWAP // a _30 c
INC // a _30 _31
TRIPLE // _29
}>
"""
@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 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 // found456 minv1 minv2 minv3 found123 _101 _102
NIP // found456 minv1 minv2 minv3 found123 found789
...
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 myBeginCell
@fif_codegen_avoid DECLPROC myStoreUint
@fif_codegen_avoid DECLPROC myStoreRef
@fif_codegen_avoid DECLPROC myComputeDataSize
@fif_codegen_avoid DECLPROC tryIdictGet
@fif_codegen_avoid DECLPROC myEmptyTuple
@fif_codegen_avoid DECLPROC myStoreUint
@fif_codegen_avoid DECLPROC initial2
@fif_codegen_avoid DECLPROC add
@fif_codegen_avoid DECLPROC increase
*/

View file

@ -0,0 +1,204 @@
// Here we also test "functions that just wrap other functions" like in camel1.tolk,
// 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.
fun myBeginCell(): builder { return begin_cell(); }
fun myEndCell(b: builder): cell { return end_cell(b); }
fun myStoreRef1(b: builder, c: cell): builder { return store_ref(b, c); }
fun myStoreRef2(c: cell, b: builder): builder { return store_ref(b, c); }
fun myStoreUint1(b: builder, x: int, bw: int): builder { return store_uint(b, x, bw); }
fun myStoreUint2(b: builder, bw: int, x: int): builder { return store_uint(b, x, bw); }
fun computeDataSize1(c: cell, maxCells: int): (int, int, int) { return compute_data_size(c, maxCells); }
fun computeDataSize2(maxCells: int, c: cell): (int, int, int) { return compute_data_size(c, maxCells); }
fun fake(a: int, b: int, c: int): void
asm "DROP DROP DROP";
fun fake2(b: int, c: int, a: int) { return fake(a,b,c); }
fun fake3(c: int, a: int, b: int) { return fake(a,b,c); }
fun fake4(c: int, b: int, a: int) { return fake(a,b,c); }
@method_id(101)
fun test1(): (int, int, int) {
var x: int = 1;
var y: int = 1;
var to_be_ref: cell = myBeginCell().myEndCell();
var in_c: builder = myBeginCell().myStoreUint1(123, 8);
in_c = myStoreRef1(in_c, to_be_ref);
var (a, b, c) = computeDataSize1(in_c.myEndCell(), 10);
assert(!0, 101);
return (a, b + x, c + y);
}
@method_id(102)
fun test2(): (int, int, int) {
var x: int = 1;
var y: int = 1;
var to_be_ref: cell = myBeginCell().myEndCell();
var in_c: builder = myBeginCell().myStoreUint2(8, 123);
in_c = myStoreRef2(to_be_ref, in_c);
var (a, b, c) = computeDataSize2(10, in_c.myEndCell());
return (a, b + x, c + y);
}
@method_id(103)
fun test3(): (int, int, int) {
var x: int = 1;
var y: int = 1;
var to_be_ref: cell = begin_cell().end_cell();
var in_c: builder = 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);
}
fun beginCell1(): builder { return begin_cell(); }
fun beginCell11(): builder { return beginCell1(); }
fun beginCell111(): builder { return beginCell11(); }
fun endCell1(b: builder): cell { return end_cell(b); }
fun endCell11(b: builder): cell { return endCell1(b); }
fun beginParse1(c: cell): slice { return begin_parse(c); }
fun beginParse11(c: cell): slice { return beginParse1(c); }
fun storeInt1(b: builder, bw: int, x: int): builder { return store_int(b, x, bw); }
fun storeInt11(bw: int, x: int, b: builder): builder { return storeInt1(b, bw, x); }
fun storeInt111(b: builder, x: int, bw: int): builder { return storeInt11(bw, x, b); }
@method_id(104)
fun test4(): slice {
var b: builder = beginCell111();
b = storeInt11(32, 1, b);
b = storeInt111(b, 2, 32).storeInt111(3, 32);
return b.endCell11().beginParse11();
}
@method_id(105)
fun test5(a: int, b: int, c: int): int {
fake(a, b, c);
fake2(b, c, a);
fake3(c, a, b);
fake4(c, b, a);
return a;
}
fun 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 _23
SWAP // a _23 c
INC // a _23 _24
}>
"""
@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 myStoreUint1
@fif_codegen_avoid myStoreUint2
*/

View file

@ -0,0 +1,95 @@
// 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).
fun myBeginCell(): builder { return begin_cell(); }
fun myEndCell(b: builder): cell { return end_cell(b); }
fun myStoreRef(b: builder, c: cell): builder { return store_ref(b, c); }
fun myStoreUint3(i: int, bw: int, b: builder): builder { return store_uint(b, i, bw); }
fun computeDataSize2(maxCells: int, c: cell): (int, int, int) { return compute_data_size(c, maxCells); }
fun myEmptyTuple(): tuple { return empty_tuple(); }
fun myTuplePush<X>(t: tuple, value: X): tuple { return tpush(t, value); }
fun ~myTuplePush<X>(t: tuple, value: X): (tuple, ()) { return ~tpush(t, value); }
fun tupleGetFirst<X>(t: tuple): X { return first(t); }
@inline
fun getBeginEnd(): (auto, auto) {
return (myBeginCell, myEndCell);
}
fun begAndStore(beg: auto, store: auto, x: int): builder {
return store(x, 8, beg());
}
fun test1(): (int, int, int) {
var (_, computer) = (0, computeDataSize2);
var (beg, end) = getBeginEnd();
var t: tuple = myEmptyTuple();
t~myTuplePush(myStoreRef);
var refStorer = tupleGetFirst(t);
var x: int = 1;
var y: int = 1;
var to_be_ref: cell = myBeginCell().myEndCell();
var in_c: builder = begAndStore(beg, myStoreUint3, 123);
in_c = refStorer(in_c, to_be_ref);
var (a, b, c) = computer(10, end(in_c));
return (a, b + x, c + y);
}
fun main(): (int, int, int) {
return test1();
}
/**
method_id | in | out
@testcase | 0 | | 2 9 2
@fif_codegen DECLPROC myBeginCell
@fif_codegen DECLPROC computeDataSize2
@fif_codegen
"""
myStoreUint3 PROC:<{
// i bw b
SWAP // i b bw
STUX // _3
}>
"""
@fif_codegen
"""
myStoreRef 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:<{
myStoreUint3 CALLDICT
}>
...
begAndStore CALLDICT // computer to_be_ref end refStorer in_c
"""
@fif_codegen_avoid myEmptyTuple
@fif_codegen_avoid myTuplePush
*/

View file

@ -0,0 +1,145 @@
// 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.)
fun myStoreUint(b: builder, x: int, unused: int): builder { return store_uint(b, x, x); }
fun throwIf(excNo: int, cond: int) { assert(!cond) throw excNo; }
fun initial1(x: auto) { return x; }
fun initial2(x: auto) { return initial1(x); }
@pure
fun asm_func_4(a: int, b: (int, (int, int)), c: int): tuple
asm (b a c -> 0) "5 TUPLE";
fun asmFunc4(a: int, b: (int, (int, int)), c: int): tuple { return asm_func_4(a, b, c); }
fun postpone_elections(): int {
return false;
}
fun setAndGetData(ret: int): int {
var c: cell = begin_cell().store_uint(ret, 8).end_cell();
set_data(c);
var s: slice = get_data().begin_parse();
throwIf(101, 0);
return s~load_uint(8);
}
fun setAndGetDataWrapper(ret: int): int {
return setAndGetData(ret);
}
@method_id(101)
fun test1(): int {
var c: cell = begin_cell().myStoreUint(32, 10000000).end_cell();
var s: slice = c.begin_parse();
return s~load_uint(32);
}
get fun test2(ret: int): int {
return setAndGetDataWrapper(ret);
}
@method_id(103)
fun test3(): int {
return initial2(10);
}
global t: tuple;
fun foo(x: int): int {
t~tpush(x);
return x * 10;
}
@method_id(104)
fun test4(): (tuple, tuple) {
t = empty_tuple();
var t2: tuple = asmFunc4(foo(11), (foo(22), (foo(33), foo(44))), foo(55));
return (t, t2);
}
@method_id(105)
fun test5(): int {
if (1) {
return postpone_elections();
}
return 123;
}
@method_id(106)
fun test6(): int {
return add2(1, 2); // doesn't inline since declared below
}
fun main(ret: int): int {
return setAndGetDataWrapper(ret);
}
fun onExternalMessage(ret: int): int {
return setAndGetData(ret);
}
// currently, functions implemented after usage, can't be inlined, since inlining is legacy, not AST
fun add2(x: int, y: int): int { return x + y; }
/**
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 | 106 | | 3
@testcase | 74435 | 99 | 99
@testcase | 0 | 98 | 98
@testcase | -1 | 97 | 97
@fif_codegen DECLPROC myStoreUint
@fif_codegen DECLPROC throwIf
@fif_codegen DECLPROC postpone_elections
@fif_codegen DECLPROC add2
@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
"""
test6 PROC:<{
//
1 PUSHINT // _0=1
2 PUSHINT // _0=1 _1=2
add2 CALLDICT // _2
}>
"""
@fif_codegen_avoid setAndGetDataWrapper
*/

View file

@ -0,0 +1,163 @@
fun store_u32(b: builder, value: int): builder {
return b.store_uint(value, 32);
}
fun ~store_u32(b: builder, value: int): (builder, ()) {
return ~store_uint(b, value, 32);
}
fun load_u32(cs: slice): (slice, int) {
return cs.load_uint(32);
}
fun my_load_int(s: slice, len: int): (slice, int)
asm(s len -> 1 0) "LDIX"; // top is "value slice"
fun my_store_int(b: builder, x: int, len: int): builder
asm(x b len) "STIX";
fun ~my_store_int(b: builder, x: int, len: int): (builder, ())
asm(x b len) "STIX";
@method_id(101)
fun test1(): [int,int,int,int,int] {
var b: builder = begin_cell().store_uint(1, 32);
b = b.store_uint(2, 32);
b~store_uint(3, 32);
b = b.store_u32(4);
b~store_u32(5);
var cs: slice = b.end_cell().begin_parse();
var (cs redef, one: int) = cs.load_uint(32);
var (two: int, three: int) = (cs~load_uint(32), cs~load_u32());
var (cs redef, four: int) = cs.load_u32();
var five: int = cs~load_u32();
return [one,two,three,four,five];
}
@method_id(102)
fun test2(): [int,int,int] {
var b: builder = begin_cell().my_store_int(1, 32);
b = b.my_store_int(2, 32);
b~my_store_int(3, 32);
var cs: slice = b.end_cell().begin_parse();
var (cs redef, one: int) = cs.my_load_int(32);
var (two: int, three: int) = (cs~my_load_int(32), cs~my_load_int(32));
return [one,two,three];
}
@method_id(103)
fun test3(ret: int): int {
var (_, same: int) = begin_cell().store_uint(ret,32).end_cell().begin_parse().load_uint(32);
return same;
}
@method_id(104)
fun test4(): [int,int] {
var b: builder = my_store_int(begin_cell(), 1, 32);
b = store_int(store_int(b, 2, 32), 3, 32);
var cs: slice = b.end_cell().begin_parse();
var cs32: slice = cs.first_bits(32); // todo s.first_bits()~load_uint() doesn't work, 'lvalue expected'
var (one, _, three) = (cs32~load_int(32), cs~skip_bits(64), cs~load_u32());
return [one,three];
}
@method_id(105)
fun test5(): [int,int] {
var cref: cell = end_cell(store_u32(begin_cell(), 105));
var c: cell = begin_cell().store_ref(cref).store_ref(cref).store_u32(1).end_cell();
var cs: slice = begin_parse(c);
// todo I want cs~load_ref().begin_parse()~load_u32(), but 'lvalue expected'
var ref1 = cs~load_ref().begin_parse();
var ref2 = cs~load_ref().begin_parse();
var sto5x2: int = ref1~load_u32() + ref2~load_uint(32);
return [sto5x2, cs~load_u32()];
}
fun ~sumNumbersInSlice(s: slice): (slice, int) {
var result = 0;
while (!slice_data_empty?(s)) {
result += s~load_uint(32);
}
return (s, result);
}
@method_id(106)
fun test6() {
var ref = begin_cell().store_int(100, 32).end_cell();
var s: slice = begin_cell().store_int(1, 32).store_int(2, 32).store_ref(ref).end_cell().begin_parse();
var result = (slice_bits(s), s~sumNumbersInSlice(), slice_bits(s), slice_empty?(s), slice_data_empty?(s), slice_refs_empty?(s));
var ref2: cell = s~load_ref();
var s2: slice = ref2.begin_parse();
s.end_parse();
return (result, s2~load_int(32), s2.slice_empty?());
}
@method_id(107)
fun test7() {
var s: slice = begin_cell().store_int(1, 32).store_int(2, 32).store_int(3, 32).store_int(4, 32).store_int(5, 32).store_int(6, 32).store_int(7, 32).end_cell().begin_parse();
var size1 = slice_bits(s);
s~skip_bits(32);
var s1: slice = s.first_bits(64);
var n1 = s1~load_int(32);
var size2 = slice_bits(s);
s~load_int(32);
var size3 = slice_bits(s);
s~skip_last_bits(32);
var size4 = slice_bits(s);
var n2 = s~load_int(32);
var size5 = slice_bits(s);
return (n1, n2, size1, size2, size3, size4, size5);
}
@method_id(108)
fun test108() {
var (result1, result2) = (0, 0);
try {
begin_cell().store_ref(begin_cell().end_cell()).end_cell().begin_parse().end_parse();
result1 = 100;
} catch (code) {
result1 = code;
}
try {
begin_cell().end_cell().begin_parse().end_parse();
result2 = 100;
} catch (code) {
result2 = code;
}
return (result1, result2);
}
@method_id(109)
fun test109() {
var ref2 = begin_cell().store_int(1, 32).end_cell();
var ref1 = begin_cell().store_int(1, 32).store_ref(ref2).end_cell();
var c = begin_cell().store_int(444, 32).store_ref(ref1).store_ref(ref1).store_ref(ref1).store_ref(ref2).store_int(4, 32).end_cell();
var (n_cells1, n_bits1, n_refs1) = c.compute_data_size(10);
var s = c.begin_parse();
s~load_ref();
s~load_ref();
var n = s~load_int(32);
var (n_cells2, n_bits2, n_refs2) = s.slice_compute_data_size(10);
return ([n_cells1, n_bits1, n_refs1], [n_cells2, n_bits2, n_refs2], n);
}
fun main(): int {
return 0;
}
/**
@testcase | 101 | | [ 1 2 3 4 5 ]
@testcase | 102 | | [ 1 2 3 ]
@testcase | 103 | 103 | 103
@testcase | 104 | | [ 1 3 ]
@testcase | 105 | | [ 210 1 ]
@testcase | 106 | | 64 3 0 0 -1 0 100 -1
@testcase | 107 | | 2 3 224 192 160 128 96
@testcase | 108 | | 9 100
@testcase | 109 | | [ 3 128 5 ] [ 2 96 3 ] 444
*/

View file

@ -0,0 +1,75 @@
const int1 = 1;
const int2 = 2;
const int101: int = 101;
const int111: int = 111;
const int1r = int1;
const str1 = "const1";
const str2 = "aabbcc"s;
const str2r: slice = str2;
const str1int = 0x636f6e737431;
const str2int = 0xAABBCC;
const nibbles: int = 4;
fun iget1(): int { return int1; }
fun iget2(): int { return int2; }
fun iget3(): int { return int1+int2; }
fun iget1r(): int { return int1r; }
fun sget1(): slice { return str1; }
fun sget2(): slice { return str2; }
fun sget2r(): slice { return str2r; }
const int240: int = ((int1+int2)*10)<<3;
fun iget240(): int { return int240; }
@pure
fun newc(): builder
asm "NEWC";
@pure
fun endcs(b: builder): slice
asm "ENDC" "CTOS";
@pure
fun sdeq(s1: slice, s2: slice): int
asm "SDEQ";
@pure
fun stslicer(b: builder, s: slice): builder
asm "STSLICER";
fun storeUint(b: builder, x: int, len: int): builder { return store_uint(b, x, len); }
fun endSlice(b: builder): slice { return endcs(b); }
fun main() {
var i1: int = iget1();
var i2: int = iget2();
var i3: int = iget3();
assert(i1 == 1) throw int101;
assert(i2 == 2) throw 102;
assert(i3 == 3) throw 103;
var s1: slice = sget1();
var s2: slice = sget2();
var s3: slice = newc().stslicer(str1).stslicer(str2r).endcs();
assert(sdeq(s1, newc().storeUint(str1int, 12 * nibbles).endcs())) throw int111;
assert(sdeq(s2, newc().store_uint(str2int, 6 * nibbles).endSlice())) throw 112;
assert(sdeq(s3, newc().store_uint(0x636f6e737431AABBCC, 18 * nibbles).endcs())) throw 113;
var i4: int = iget240();
assert(i4 == 240) throw ((104));
return 0;
}
/**
@testcase | 0 | | 0
@code_hash 61273295789179921867241079778489100375537711211918844448475493726205774530743
*/

View file

@ -0,0 +1,41 @@
fun elseif(cond: int) {
if (cond > 0) {
throw(cond);
}
}
@inline
@method_id(101)
fun foo(x: int): int {
if (x==1) {
return 111;
} else {
x *= 2;
}
return x + 1;
}
fun main(x: int): (int, int) {
return (foo(x), 222);
}
@method_id(102)
fun test2(x: int) {
try {
if (x < 0) { return -1; }
elseif (x);
} catch(excNo) {
return excNo * 1000;
}
return 0;
}
/**
method_id | in | out
@testcase | 0 | 1 | 111 222
@testcase | 0 | 3 | 7 222
@testcase | 101 | 1 | 111
@testcase | 101 | 3 | 7
@testcase | 102 | -5 | -1
@testcase | 102 | 5 | 5000
*/

View file

@ -0,0 +1,96 @@
@method_id(101)
fun test1(): int {
var x = false;
if (x == true) {
x= 100500;
}
return x;
}
fun main(s: int) {
var (z, t) = (17, s);
while (z > 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
"""
*/

View file

@ -0,0 +1,31 @@
fun main(): int
// 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 not be nested
// line comment
// ends */1 +
1;
/* moreover, different comment styles
may be used for opening and closing
*/
}
/***
first line
//two-lined*/
@method_id(10)
fun get10(): int {
return 10;
}
/**
@testcase | 0 | | 12
@testcase | 10 | | 10
*/

View file

@ -0,0 +1,66 @@
@method_id(101)
fun test1(x: int): int {
if (x > 200) {
return 200;
} else if (x > 100) {
return 100;
} else if (!(x <= 50)) {
if (!(x > 90)) {
return x;
} else {
return 90;
}
} else {
return 0;
}
}
@method_id(102)
fun test2(x: int) {
if (x == 20) { return 20; }
if (x != 50) { return 50; }
if (x == 0) { return 0; }
return -1;
}
@method_id(103)
fun test3(x: int) {
if (!(x != 20)) { return 20; }
if (!(x == 50)) { return 50; }
if (!x) { return 0; }
return -1;
}
fun main() {
}
/**
@testcase | 101 | 0 | 0
@testcase | 101 | 1000 | 200
@testcase | 101 | 150 | 100
@testcase | 101 | -1 | 0
@testcase | 101 | 87 | 87
@testcase | 101 | 94 | 90
@testcase | 102 | 20 | 20
@testcase | 102 | 40 | 50
@testcase | 102 | 50 | -1
@testcase | 103 | 20 | 20
@testcase | 103 | 40 | 50
@testcase | 103 | 50 | -1
@fif_codegen
"""
test3 PROC:<{
// x
DUP // x x
20 NEQINT // x _2
IFNOTJMP:<{ // x
DROP //
20 PUSHINT // _3=20
}> // x
DUP // x x
50 EQINT // x _5
IFNOTJMP:<{ // x
"""
*/

View file

@ -0,0 +1,4 @@
fun demoOfInvalid(): (int) {
var f = someAdd;
return f(1, 2);
}

View file

@ -0,0 +1,3 @@
fun someAdd(a: int, b: int): int {
return a + b + 0;
}

View file

@ -0,0 +1,62 @@
@inline
fun foo(x: int): int {
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
x = x * 10 + 1;
return x;
}
fun main(x: int): int {
return foo(x) * 10 + 5;
}
/**
method_id | in | out
@testcase | 0 | 9 | 9111111111111111111111111111111111111111111111111115
*/

View file

@ -0,0 +1,28 @@
fun foo1(x: int): int {
if (x == 1) {
return 1;
}
return 2;
}
@inline
fun foo2(x: int): int {
if (x == 1) {
return 11;
}
return 22;
}
@inline_ref
fun foo3(x: int): int {
if (x == 1) {
return 111;
}
return 222;
}
fun main(x: int): (int, int, int) {
return (foo1(x)+1, foo2(x)+1, foo3(x)+1);
}
/**
method_id | in | out
@testcase | 0 | 1 | 2 12 112
@testcase | 0 | 2 | 3 23 223
*/

View file

@ -0,0 +1,48 @@
global g: int;
@inline
fun foo_repeat() {
g = 1;
repeat(5) {
g *= 2;
}
}
@inline
fun foo_until(): int {
g = 1;
var i: int = 0;
do {
g *= 2;
i += 1;
} while (i < 8);
return i;
}
@inline
fun foo_while(): int {
g = 1;
var i: int = 0;
while (i < 10) {
g *= 2;
i += 1;
}
return i;
}
fun main() {
foo_repeat();
var x: int = g;
foo_until();
var y: int = g;
foo_while();
var z: int = g;
return (x, y, z);
}
/**
method_id | in | out
@testcase | 0 | | 32 256 1024
@code_hash 102749806552989901976653997041637095139193406161777448419603700344770997608788
*/

View file

@ -0,0 +1,9 @@
fun main(flags: int): int {
return flags&0xFF!=0;
}
/**
@compilation_should_fail
@stderr & has lower precedence than !=
@stderr Use parenthesis
*/

View file

@ -0,0 +1,8 @@
fun justTrue(): int { return true; }
const a = justTrue() | 1 < 9;
/**
@compilation_should_fail
@stderr | has lower precedence than <
*/

View file

@ -0,0 +1,8 @@
fun justTrue(): int { return true; }
const a = justTrue() | (1 < 9) | justTrue() != true;
/**
@compilation_should_fail
@stderr | has lower precedence than !=
*/

View file

@ -0,0 +1,6 @@
const a = (1) <=> (0) ^ 8;
/**
@compilation_should_fail
@stderr ^ has lower precedence than <=>
*/

View file

@ -0,0 +1,11 @@
const MAX_SLIPAGE = 100;
fun main(jetton_amount: int, msg_value: int, slippage: int) {
if ((0 == jetton_amount) | (msg_value == 0) | true | false | slippage > MAX_SLIPAGE) {
}
}
/**
@compilation_should_fail
@stderr | has lower precedence than >
*/

View file

@ -0,0 +1,9 @@
fun main() {
if ((1==1)|(2==2)&(3==3)) {
}
}
/**
@compilation_should_fail
@stderr mixing | with & without parenthesis
*/

View file

@ -0,0 +1,8 @@
fun main() {
var c = x && y || x && y;
}
/**
@compilation_should_fail
@stderr mixing && with || without parenthesis
*/

View file

@ -0,0 +1,10 @@
fun moddiv2(x: int, y: int): (int, int) builtin;
/**
@compilation_should_fail
@stderr
"""
`builtin` used for non-builtin function
fun moddiv2
"""
*/

View file

@ -0,0 +1,12 @@
fun main() {
try {
} catch(int, arg) {}
return 0;
}
/**
@compilation_should_fail
@stderr expected identifier, got `int`
@stderr catch(int
*/

View file

@ -0,0 +1,9 @@
fun main() {
try {}
catch(err, arg, more) {}
}
/**
@compilation_should_fail
@stderr expected `)`, got `,`
*/

View file

@ -0,0 +1,11 @@
/*
in tolk we decided to drop nested comments support
/*
not nested
*/
*/
/**
@compilation_should_fail
@stderr error: expected fun or get, got `*`
*/

View file

@ -0,0 +1,8 @@
fun main(): int {
;; this is not a comment
}
/**
@compilation_should_fail
@stderr error: expected `;`, got `is`
*/

View file

@ -0,0 +1,8 @@
const ONE = TWO - 1;
const TWO = ONE + 1;
/**
@compilation_should_fail
@stderr const ONE
@stderr undefined symbol `TWO`
*/

View file

@ -0,0 +1,6 @@
const a = 10, b = 20;
/**
@compilation_should_fail
@stderr multiple declarations are not allowed
*/

View file

@ -0,0 +1,8 @@
get fun onInternalMessage() {
return 0;
}
/**
@compilation_should_fail
@stderr invalid declaration of a reserved function
*/

View file

@ -0,0 +1,8 @@
fun main(int): int {
}
/**
@compilation_should_fail
@stderr expected parameter name, got `int`
*/

View file

@ -0,0 +1,8 @@
int main() {
}
/**
@compilation_should_fail
@stderr expected fun or get, got `int`
*/

View file

@ -0,0 +1,8 @@
fun main() {
int x = 0;
}
/**
@compilation_should_fail
@stderr probably, you use FunC-like declarations; valid syntax is `var x: int = ...`
*/

View file

@ -0,0 +1,6 @@
enum MyKind { }
/**
@compilation_should_fail
@stderr `enum` is not supported yet
*/

View file

@ -0,0 +1,8 @@
fun main() {
val imm = 10;
}
/**
@compilation_should_fail
@stderr immutable variables are not supported yet
*/

View file

@ -0,0 +1,8 @@
fun main() {
var a = 10, b = 20;
}
/**
@compilation_should_fail
@stderr multiple declarations are not allowed
*/

View file

@ -0,0 +1,8 @@
fun someDemo() {
return 0;
}
/**
@compilation_should_fail
@stderr the contract has no entrypoint
*/

View file

@ -0,0 +1,9 @@
fun recv_internal() {
return 0;
}
/**
@compilation_should_fail
@stderr this is a reserved FunC/Fift identifier
@stderr you need `onInternalMessage`
*/

View file

@ -0,0 +1,9 @@
@method_id(123)
get fun hello(x: int, y: int): (int, int) {
return (x, y);
}
/**
@compilation_should_fail
@stderr @method_id can be specified only for regular functions
*/

View file

@ -0,0 +1,17 @@
@pure
get fun secret(): int {
return 0;
}
@pure
get fun balanced(): int {
return 1;
}
fun main(): int {
return secret() + balanced();
}
/**
@compilation_should_fail
@stderr GET methods hash collision: `secret` and `balanced` produce the same hash
*/

View file

@ -0,0 +1,9 @@
// line1
/* */ import "unexisting.tolk";
// line3
/**
@compilation_should_fail
@stderr invalid-import.tolk:2:7: error: Failed to import: cannot find file
@stderr import "unexisting.tolk";
*/

View file

@ -0,0 +1,8 @@
fun main() {
return 1 && 2;
}
/**
@compilation_should_fail
@stderr logical operators are not supported yet
*/

View file

@ -0,0 +1,8 @@
import "imports/some-math.tolk";
import "imports/invalid-no-import.tolk";
/**
@compilation_should_fail
@stderr imports/invalid-no-import.tolk:2:13
@stderr Using a non-imported symbol `someAdd`
*/

View file

@ -0,0 +1,12 @@
fun eq(x: int): int {
return x;
}
fun main(x: int): int {
return eq x;
}
/**
@compilation_should_fail
@stderr expected `;`, got `x`
*/

View file

@ -0,0 +1,12 @@
fun main(x: int): int {
if x {
return 10;
}
return 0;
}
/**
@compilation_should_fail
@stderr expected `(`, got `x`
*/

View file

@ -0,0 +1,12 @@
fun main(x: int): int {
if (x, 1) {
return 10;
}
return 0;
}
/**
@compilation_should_fail
@stderr expected `)`, got `,`
*/

View file

@ -0,0 +1,8 @@
fun load_u32(cs: slice): (slice, int) {
return cs.load_uint 32;
}
/**
@compilation_should_fail
@stderr expected `(`, got `32`
*/

View file

@ -0,0 +1,20 @@
@pure
fun f_pure(): int {
return f_impure();
}
fun f_impure(): int {}
fun main(): int {
return f_pure();
}
/**
@compilation_should_fail
@stderr
"""
an impure operation in a pure function
return f_impure();
"""
*/

View file

@ -0,0 +1,23 @@
global g: int;
@pure
fun f_pure(): builder {
var b: builder = begin_cell();
g = g + 1;
return b;
}
fun main(): int {
g = 0;
f_pure();
return g;
}
/**
@compilation_should_fail
@stderr
"""
an impure operation in a pure function
g = g + 1;
"""
*/

View file

@ -0,0 +1,23 @@
@pure
fun validate_input(input: cell): (int, int) {
var (x, y, z, correct) = compute_data_size?(input, 10);
assert(correct) throw 102;
}
@pure
fun someF(): int {
var c: cell = begin_cell().end_cell();
validate_input(c);
return 0;
}
fun main() {}
/**
@compilation_should_fail
@stderr
"""
an impure operation in a pure function
assert(correct)
"""
*/

View file

@ -0,0 +1,7 @@
global moddiv: int;
/**
@compilation_should_fail
@stderr global moddiv: int;
@stderr redefinition of built-in symbol
*/

View file

@ -0,0 +1,12 @@
global hello: int;
fun hello(): int {
}
/**
@compilation_should_fail
@stderr fun hello()
@stderr redefinition of symbol, previous was at
@stderr invalid-redefinition-2.tolk:1:1
*/

View file

@ -0,0 +1,8 @@
fun main(): int {
var demo_10: int = demo_10;
}
/**
@compilation_should_fail
@stderr undefined symbol `demo_10`
*/

View file

@ -0,0 +1,9 @@
fun main(): int {
var (a: int, b: int) = (10, 20);
var (a, b: int) = (10, 20);
}
/**
@compilation_should_fail
@stderr redeclaration of local variable `a`
*/

View file

@ -0,0 +1,9 @@
fun main(x: int): int {
var (a: int, b: int) = (10, 20);
var (a redef, x: int) = (10, 20);
}
/**
@compilation_should_fail
@stderr redeclaration of local variable `x`
*/

View file

@ -0,0 +1,8 @@
fun main(flags: int) {
return flags << 1 + 32;
}
/**
@compilation_should_fail
@stderr << has lower precedence than +
*/

View file

@ -0,0 +1,14 @@
fun main(x: int): int {
if (x > 0) {
var y: int = 10;
} else {
var y: slice = "20";
}
~dump(y);
}
/**
@compilation_should_fail
@stderr ~dump(y);
@stderr undefined symbol `y`
*/

View file

@ -0,0 +1,12 @@
fun main(x: int): int {
try {
if (x > 10) { throw(44); }
} catch(code) {}
return code;
}
/**
@compilation_should_fail
@stderr return code;
@stderr undefined symbol `code`
*/

View file

@ -0,0 +1,15 @@
fun main(x: int): int {
if (x > 0) {
return 1;
}
// 'elseif' doesn't exist anymore, it's treated as 'someFunction(arg)'
elseif(x < 0) {
return -1;
}
return x;
}
/**
@compilation_should_fail
@stderr expected `;`, got `{`
*/

View file

@ -0,0 +1,13 @@
fun main(x: int) {
while (x > 0) {
if (x == 10) {
break;
}
x = x -1;
}
}
/**
@compilation_should_fail
@stderr break/continue from loops are not supported yet
*/

View file

@ -0,0 +1,8 @@
fun main(x: int) {
return null();
}
/**
@compilation_should_fail
@stderr null is not a function: use `null`, not `null()`
*/

View file

@ -0,0 +1,8 @@
fun main(x: int) {
assert(x > 0);
}
/**
@compilation_should_fail
@stderr expected `throw excNo` after assert, got `;`
*/

View file

@ -0,0 +1,7 @@
tolk asdf;
/**
@compilation_should_fail
@stderr semver expected
@stderr tolk asdf;
*/

View file

@ -0,0 +1,10 @@
fun main() {
var tri: [int, scli] = [10, null()];
return;
}
/**
@compilation_should_fail
@stderr .tolk:2
@stderr expected <type>, got `scli`
*/

View file

@ -0,0 +1,9 @@
fun main() {
var tri: (int, bool) = (10, false);
return;
}
/**
@compilation_should_fail
@stderr bool type is not supported yet
*/

View file

@ -0,0 +1,8 @@
fun main(s: auto) {
var (z, t) = ;
/**
@compilation_should_fail
@stderr expected <expression>, got `;`
@stderr var (z, t) = ;
*/

View file

@ -0,0 +1,154 @@
fun simpleAllConst() {
return (!0, !!0 & !false, !!!0, !1, !!1, !-1, !!-1, (!5 == 0) == !0, !0 == true);
}
fun compileTimeEval1(x: int) {
// todo now compiler doesn't understand that bool can't be equal to number other than 0/-1
// (but understands that it can't be positive)
// that's why for now, the last condition is evaluated at runtime
return (!x, !x > 10, !x < 10, !!x == 5, !x == -10);
}
@method_id(101)
fun withIfNot(x: int, y: int) {
if (!x) { return 10; }
else if (!y) { return 20; }
return x+y;
}
@method_id(102)
fun withAndOr(x: int, y: int, z: int) {
var return_at_end = -1;
if (!x & !y) {
if (!z & !y) { return 10; }
else if (z | !!y) { return_at_end = 20; }
} else if (!!x & !!y & !z) {
if (!z & (x > 10)) { return_at_end = 30; }
if ((x != 11) & !z) { return 40; }
return_at_end = 50;
} else {
return_at_end = !x ? !y : !z | 1;
}
return return_at_end;
}
@method_id(103)
fun someSum(upto: int) {
var x = 0;
var should_break = false;
while (!x & !should_break) {
if (upto < 10) { x = upto; should_break = true; }
else { upto = upto - 1; }
}
return x;
}
fun lookupIdxByValue(idict32: cell, value: int) {
var cur_key = -1;
do {
var (cur_key redef, cs: slice, found: int) = idict32.idict_get_next?(32, cur_key);
// todo one-line condition (via &) doesn't work, since right side is calculated immediately
if (found) {
if (cs~load_int(32) == value) {
return cur_key;
}
}
} while (found);
return -1;
}
@method_id(104)
fun testDict(last: int) {
// prepare dict: [3 => 30, 4 => 40, 5 => 50]
var dict: cell = new_dict();
dict~idict_set_builder(32, 3, begin_cell().store_int(30, 32));
dict~idict_set_builder(32, 4, begin_cell().store_int(40, 32));
dict~idict_set_builder(32, 5, begin_cell().store_int(!last ? 100 : last, 32));
return (lookupIdxByValue(dict, 30), lookupIdxByValue(dict, last), lookupIdxByValue(dict, 100));
}
@method_id(105)
fun testNotNull(x: int) {
return [x == null, null == x, !(x == null), null == null, +(null != null)];
}
fun main() {
}
/**
@testcase | 101 | 0 0 | 10
@testcase | 101 | 5 0 | 20
@testcase | 101 | 5 8 | 13
@testcase | 102 | 0 0 0 | 10
@testcase | 102 | 0 0 5 | 20
@testcase | 102 | 1 2 0 | 40
@testcase | 102 | 11 2 0 | 50
@testcase | 102 | 1 0 0 | -1
@testcase | 102 | 0 1 0 | 0
@testcase | 102 | 1 0 1 | 1
@testcase | 103 | 15 | 9
@testcase | 103 | 6 | 6
@testcase | 103 | -1 | -1
@testcase | 104 | 50 | 3 5 -1
@testcase | 104 | 100 | 3 5 5
@testcase | 104 | 0 | 3 -1 5
@testcase | 105 | 0 | [ 0 0 -1 -1 0 ]
@testcase | 105 | null | [ -1 -1 0 -1 0 ]
@fif_codegen
"""
simpleAllConst PROC:<{
//
-1 PUSHINT
0 PUSHINT
-1 PUSHINT
0 PUSHINT
-1 PUSHINT
0 PUSHINT
-1 PUSHINT
TRUE
TRUE
}>
"""
@fif_codegen
"""
compileTimeEval1 PROC:<{
// x
DUP // x x
0 EQINT // x _1
FALSE // x _1 _4
TRUE // x _1 _4 _7
FALSE // x _1 _4 _7 _11
s0 s4 XCHG // _11 _1 _4 _7 x
0 EQINT // _11 _1 _4 _7 _12
-10 EQINT // _11 _1 _4 _7 _14
s3 s4 XCHG
s1 s3 s0 XCHG3 // _1 _4 _7 _11 _14
}>
"""
@fif_codegen
"""
withIfNot PROC:<{
c2 SAVE
SAMEALTSAVE // x y
OVER // x y x
IFNOTJMP:<{ // x y
2DROP //
10 PUSHINT // _2=10
}> // x y
DUP // x y y
IFNOTJMP:<{ // x y
2DROP //
20 PUSHINT // _3=20
RETALT
}> // x y
ADD // _4
}>
"""
*/

View file

@ -0,0 +1,15 @@
@method_id(1)
fun foo1(): int { return 111; }
@method_id(3)
fun foo2(): int { return 222; }
@method_id(10)
fun foo3(): int { return 333; }
fun main(): int { return 999; }
/**
method_id | in | out
@testcase | 1 | | 111
@testcase | 3 | | 222
@testcase | 10 | | 333
@testcase | 0 | | 999
*/

View file

@ -0,0 +1,117 @@
const int10:int=10;
fun just10(): int { return int10; }
fun eq(v: int): int { return`v`; }
@method_id(101) fun `get_-1` (): int {return-1;}
@method_id(102) fun `get_--1` (): int {return--1;}
@method_id(103) fun `get_---1`(): int {return---1;}
@method_id(104) fun `get_+++1`(): int {return+++1;}
@method_id(105) fun `get_+-+1`(): int {return+-+1;}
global `some()var`:int;
@method_id(110) fun `some_math`(): int {
`some()var`=--6;
return 1*-2*-3*-4*just10()*-5+-`some()var`+--`some()var`---`some()var`;
}
@method_id(111) fun `negative_nums`(a:int):int {
var m$0:int=1;
var m1:int=-(+0x1)*m$0;
return `a`*-1*-(1)*---(1)*+just10()+-`just10`()*m1*-m1+-eq(m1)----0x1;
}
@method_id(112) fun `bitwise~ops`(flags:int):[int,int] {
return[
(just10()-3==just10()-(4)--1)|((2==2)&(eq(eq(10)) -3==just10()--13)),
((flags&0xFF)!=0)
];
}
@method_id(113)fun`unary+bitwise-constant`():[int,int,int]{
// todo spaces are still not allowed before ~
return [~-~~+-3, ~+3-~ 9, -(-~+-20-~ 10+3+~ 38&39)];
}
@method_id(114)fun`unary+bitwize-parametrized`(c3:int, c9:int, c20:int, c10:int, c38:int):[int,int,int]{
// todo spaces are still not allowed before ~
return [~-~~+-c3, ~+c3-~ `c9`, -(-~+-c20-~ c10+c3+~ c38&39)];
}
fun add3(a: int, b: int, c: int) { return a+b+c; }
@method_id(115) fun unary_const_check(): [int,int] {
var fst1: int=-1;
var snd1: int=-1;
var trd1: int=+2;
var (fst2,snd2,trd2)=(-1,-1,+2);
return [add3(fst2,snd2,trd2),add3(fst1,snd1,trd1)];
}
fun `load:u32`(cs: slice): (slice, int) {
return cs.load_uint(32);
}
@method_id(116) fun `call_~_via_backticks`():[int,int,int,int] {
var b:builder = begin_cell().store_uint(1, 32).store_uint(2, 32).store_uint(3, 32).store_uint(4, 32);
var `cs`:slice = b.end_cell().begin_parse();
var (`cs` redef,one:int) = `cs`.`load_uint`(32);
var (two:int,three:int) = (`cs`~`load_uint`(32), cs~`load:u32`());
var (cs redef,four:int) = cs.`load:u32`();
return [one,two,three,four];
}
fun`main`(){}
/**
method_id | in | out
@testcase | 101 | | -1
@testcase | 102 | | 1
@testcase | 103 | | -1
@testcase | 104 | | 1
@testcase | 105 | | -1
@testcase | 110 | | 1194
@testcase | 111 | -1 | 22
@testcase | 112 | 0 | [ -1 0 ]
@testcase | 113 | | [ -4 6 -4 ]
@testcase | 114 | 3 9 20 10 38 | [ -4 6 -4 ]
@testcase | 115 | | [ 0 0 ]
@testcase | 116 | | [ 1 2 3 4 ]
@fif_codegen
"""
get_+-+1 PROC:<{
//
-1 PUSHINT
}>
"""
@fif_codegen
"""
unary+bitwise-constant PROC:<{
//
-4 PUSHINT
6 PUSHINT
-4 PUSHINT
TRIPLE
}>
"""
@fif_codegen
"""
unary_const_check PROC:<{
//
-1 PUSHINT // fst1=-1
DUP // fst1=-1 snd1=-1
2 PUSHINT // fst1=-1 snd1=-1 trd1=2
s1 s1 s0 PUSH3 // fst1=-1 snd1=-1 trd1=2 fst2=-1 snd2=-1 trd2=2
add3 CALLDICT // fst1=-1 snd1=-1 trd1=2 _13
3 -ROLL // _13 fst1=-1 snd1=-1 trd1=2
add3 CALLDICT // _13 _14
PAIR // _12
}>
"""
*/

View file

@ -0,0 +1,157 @@
import "../../crypto/smartcont/stdlib.tolk"
@method_id(101)
fun test1() {
var numbers: tuple = null;
numbers = cons(1, numbers);
numbers = cons(2, numbers);
numbers = cons(3, numbers);
numbers = cons(4, numbers);
var (h, numbers redef) = uncons(numbers);
h += car(numbers);
var t = empty_tuple();
do {
var num = numbers~list_next();
t~tpush(num);
} while (numbers != null);
return (h, numbers == null, t);
}
@method_id(102)
fun test2(x: int) {
if (null != x) {
var y: int = null;
if (y != null) { return 10; }
return y;
}
try {
return x + 10; // will throw, since not a number
} catch {
return -1;
}
return 100;
}
fun myIsNull(x: int): int {
return x == null ? -1 : x;
}
@method_id(103)
fun test3(x: int) {
return myIsNull(x > 10 ? null : x);
}
fun getUntypedNull() {
var untyped = null;
if (true) {
return untyped;
}
return untyped;
}
@method_id(104)
fun test4() {
var (_, (_, untyped)) = (3, (empty_tuple, null));
if (true) {
return untyped;
}
return untyped;
}
@method_id(105)
fun test5() {
var n = getUntypedNull();
return !(null == n) ? n~load_int(32) : 100;
}
@method_id(106)
fun test6(x: int) {
return x > null; // this compiles (for now), but fails at runtime
}
@method_id(107)
fun test7() {
var b = begin_cell().store_maybe_ref(null);
var s = b.end_cell().begin_parse();
var c = s~load_maybe_ref();
return (null == c) * 10 + (b != null);
}
fun main() {
// now, the compiler doesn't optimize this at compile-time, fif codegen contains ifs
var i: int = null;
if (i == null) {
return 1;
}
return 10;
}
/**
@testcase | 101 | | 7 -1 [ 3 2 1 ]
@testcase | 102 | 5 | (null)
@testcase | 102 | null | -1
@testcase | 103 | 5 | 5
@testcase | 103 | 15 | -1
@testcase | 104 | | (null)
@testcase | 105 | | 100
@testcase | 107 | | -11
@fif_codegen
"""
test1 PROC:<{
//
PUSHNULL // numbers
1 PUSHINT // numbers _2=1
SWAP // _2=1 numbers
CONS // numbers
2 PUSHINT // numbers _4=2
SWAP // _4=2 numbers
CONS // numbers
3 PUSHINT // numbers _6=3
SWAP // _6=3 numbers
CONS // numbers
4 PUSHINT // numbers _8=4
SWAP // _8=4 numbers
CONS // numbers
UNCONS // h numbers
DUP // h numbers numbers
CAR // h numbers _12
"""
@fif_codegen
"""
main PROC:<{
//
PUSHNULL // i
ISNULL // _2
IFJMP:<{ //
1 PUSHINT // _3=1
}> //
10 PUSHINT // _4=10
}>
"""
@fif_codegen
"""
test6 PROC:<{
// x
PUSHNULL // x _1
GREATER // _2
}>
"""
@fif_codegen
"""
test7 PROC:<{
...
LDOPTREF // b _17 _16
DROP // b c
ISNULL // b _10
10 MULCONST // b _12
SWAP // _12 b
ISNULL // _12 _13
0 EQINT // _12 _14
ADD // _15
}>
"""
*/

View file

@ -0,0 +1,121 @@
fun justTrue(): int { return true; }
fun unary_minus_1(a: int, b: int, c: int): int{return -(a+b) *c;}
fun unary_minus_2(a: int, b: int, c: int): int{return(-(a+b))*c;}
fun unary_minus_3(a: int, b: int, c: int): int{return-((a+b) *c);}
@method_id(101)
fun test1(x: int, y: int, z: int): int {
return (x > 0) & (y > 0) & (z > 0);
}
@method_id(102)
fun test2(x: int, y: int, z: int): int {
return x > (0 & (y > 0) & (z > 0));
}
@method_id(103)
fun test3(x: int, y: int, z: int): int {
if ((x < 0) | (y < 0)) {
return z < 0;
}
return (x > 0) & (y > 0);
}
@method_id(104)
fun test4(x: int, y: int, mode: int): int {
if (mode == 1) {
return (x == 10) | (y == 20);
} if (mode == 2) {
return (x == 10) | (y == 20);
} else {
return x == (10 | (y == 20));
}
}
@method_id(105)
fun test5(status: int): int {
return justTrue() & (status == 1) & ((justTrue() & status) == 1);
}
@method_id(106)
fun test6(a: int, b: int, c: int): int {
return (unary_minus_1(a,b,c) == unary_minus_2(a,b,c)) & (unary_minus_1(a,b,c) == unary_minus_3(a,b,c));
}
@method_id(107)
fun test7(b: int): int {
var a = b == 3 ? 3 : b == 4 ? 4 : (b == 5) & 1 ? 5 : 100;
return a;
}
@method_id(108)
fun test8(b: int): int {
var a = b == 3 ? 3 : b == 4 ? 4 : b = 5 ? 5 : 100;
return a;
}
fun `_<p`(a: auto, b: auto): int { return true; }
fun main() {
// ok to parse
var c = [
(3 & 3) > 0, 3 & (3 > 0), 3 & (`_<_`(3, 0)),
3 & `_<p`(3, 0), (1 & 2) ^ (3 | 4),
1 & ((1) == 1)
];
}
/**
@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
@testcase | 106 | 1 2 3 | -1
@testcase | 107 | 3 | 3
@testcase | 107 | 4 | 4
@testcase | 107 | 5 | 5
@testcase | 107 | 6 | 100
@testcase | 108 | 3 | 3
@testcase | 108 | 4 | 4
@testcase | 108 | 6 | 5
@fif_codegen
"""
unary_minus_1 PROC:<{
// a b c
-ROT // c a b
ADD // c _3
NEGATE // c _4
SWAP // _4 c
MUL // _5
}>
unary_minus_2 PROC:<{
// a b c
-ROT // c a b
ADD // c _3
NEGATE // c _4
SWAP // _4 c
MUL // _5
}>
unary_minus_3 PROC:<{
// a b c
-ROT // c a b
ADD // c _3
SWAP // _3 c
MUL // _4
NEGATE // _5
}>
"""
*/

View file

@ -0,0 +1,46 @@
@pure
fun f_pure1(): int {
return f_pure2();
}
@pure
fun f_pure2(): int {
return 2;
}
@pure
fun get_contract_data(): (int, int) {
var c: cell = get_data();
var cs: slice = c.begin_parse();
cs~load_bits(32);
var value: int = cs~load_uint(16);
return (1, value);
}
fun save_contract_data(value: int) {
var b: builder = begin_cell().store_int(1, 32).store_uint(value, 16);
set_data(b.end_cell());
}
@pure
@method_id(101)
fun test1(): int {
return f_pure1();
}
@method_id(102)
fun test2(value: int): int {
save_contract_data(value);
var (_, restored: auto) = get_contract_data();
return restored;
}
fun main() { return; }
/**
@testcase | 101 | | 2
@testcase | 102 | 44 | 44
*/

View file

@ -0,0 +1,48 @@
fun unused1(): int { return 2; }
fun unused2(): int { return unused1(); }
fun unused3(x: int): int { return x * 2+unused2(); }
fun used_from_noncall1(): int { return 10; }
fun used_as_noncall1(): int { return used_from_noncall1(); }
const int20: int = 20;
fun used_from_noncall2(): int { return int20; }
fun used_as_noncall2(): int { return 0 * 0 + used_from_noncall2() + (0 << 0); }
global unused_gv: int;
global used_gv: auto;
fun receiveGetter(): (() -> int) { return used_as_noncall2; }
@pure
fun usedButOptimizedOut(x: int): int { return x + 2; }
fun main(): (int, int, int) {
used_gv = 1;
used_gv = used_gv + 2;
var getter1 = used_as_noncall1;
var getter2 = receiveGetter();
usedButOptimizedOut(used_gv);
return (used_gv, getter1(), getter2());
}
/**
@experimental_options remove-unused-functions
@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
*/

61
tolk-tester/tests/s1.tolk Normal file
View file

@ -0,0 +1,61 @@
get ascii_slice(): slice {
return"string";
}
get raw_slice(): slice {
return "abcdef"s;
}
get addr_slice(): slice {
return "Ef8zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM0vF"a;
}
get string_hex(): int {
return "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"u;
}
get fun string_minihash(): int { // 'get' and 'get fun' both possible
return "transfer(slice, int)"h;
}
get fun string_maxihash(): int {
return "transfer(slice, int)"H;
}
get fun string_crc32(): int {
return "transfer(slice, int)"c;
}
@pure
fun newc(): builder
asm "NEWC";
fun endcs(b: builder): slice
asm "ENDC" "CTOS";
@pure
fun sdeq(s1: slice, s2: slice): int
asm "SDEQ";
fun main() {
var s_ascii: slice = ascii_slice();
var s_raw: slice = raw_slice();
var s_addr: slice = addr_slice();
var i_hex: int = string_hex();
var i_mini: int = string_minihash();
var i_maxi: int = string_maxihash();
var i_crc: int = string_crc32();
assert(sdeq(s_ascii, newc().store_uint(0x737472696E67, 12 * 4).endcs())) throw 101;
assert(sdeq(s_raw, newc().store_uint(0xABCDEF, 6 * 4).endcs())) throw 102;
assert(sdeq(s_addr, newc().store_uint(4, 3).store_int(-1, 8)
.store_uint(0x3333333333333333333333333333333333333333333333333333333333333333, 256).endcs()), 103);
assert(i_hex == 0x4142434445464748494A4B4C4D4E4F505152535455565758595A303132333435) throw 104;
assert(i_mini == 0x7a62e8a8) throw 105;
assert(i_maxi == 0x7a62e8a8ebac41bd6de16c65e7be363bc2d2cbc6a0873778dead4795c13db979) throw 106;
assert(i_crc == 2235694568) throw 107;
return 0;
}
/**
@testcase | 0 | | 0
@code_hash 13830542019509784148027107880226447201604257839069192762244575629978154217223
*/

View file

@ -0,0 +1,24 @@
fun onInternalMessage() { return 0; }
fun onExternalMessage() { return -1; }
fun onRunTickTock() { return -2; }
fun onSplitPrepare() { return -3; }
fun onSplitInstall() { return -4; }
/**
@experimental_options remove-unused-functions
@testcase | 0 | | 0
@testcase | -1 | | -1
@testcase | -2 | | -2
@testcase | -3 | | -3
@testcase | -4 | | -4
@fif_codegen
"""
0 DECLMETHOD onInternalMessage
-1 DECLMETHOD onExternalMessage
-2 DECLMETHOD onRunTickTock
-3 DECLMETHOD onSplitPrepare
-4 DECLMETHOD onSplitInstall
"""
*/

View file

@ -0,0 +1,309 @@
import "../../crypto/smartcont/mathlib.tolk";
@pure
fun ~tset<X>(t: tuple, idx: int, value: X): (tuple, ())
asm(t value idx) "SETINDEXVAR";
// computes 1-acos(x)/Pi by a very simple, extremely slow (~70k gas) and imprecise method
// fixed256 acos_prepare_slow(fixed255 x);
@inline
fun acos_prepare_slow_f255(x: int): int {
x -= (x == 0);
var t: int = 1;
repeat (255) {
t = t * sgn(x) * 2 + 1; // decode Gray code (sgn(x_0), sgn(x_1), ...)
x = (-1 << 255) - muldivr(x, - x, 1 << 254); // iterate x := 2*x^2 - 1 = cos(2*acos(x))
}
return abs(t);
}
// extremely slow (~70k gas) and somewhat imprecise (very imprecise when x is small), for testing only
// fixed254 acos_slow(fixed255 x);
@inline_ref
fun acos_slow_f255(x: int): int {
var t: int = acos_prepare_slow_f255(x);
return - mulrshiftr256(t + (-1<<256), Pi_const_f254());
}
// fixed255 asin_slow(fixed255 x);
@inline_ref
fun asin_slow_f255(x: int): int {
var t: int = acos_prepare_slow_f255(abs(x)) % (1 << 255);
return muldivr(t, Pi_const_f254(), 1 << 255) * sgn(x);
}
@inline_ref
fun test_nrand(n: int): tuple {
var t: tuple = empty_tuple();
repeat (255) {
t~tpush(0);
}
repeat (n) {
var x: int = fixed248_nrand();
var bucket: int = (abs(x) >> 243); // 255 buckets starting from x=0, each 1/32 wide
t~tset(bucket, t.at(bucket) + 1);
}
return t;
}
@method_id(10000)
fun geom_mean_test(x: int, y: int): int {
return geom_mean(x, y);
}
@method_id(10001)
fun tan_f260_test(x: int): int {
return tan_f260(x);
}
@method_id(10002)
fun sincosm1_f259_test(x: int): (int, int) {
return sincosm1_f259(x);
}
@method_id(10003)
fun sincosn_f256_test(x: int, y: int): (int, int) {
return sincosn_f256(x, y);
}
@method_id(10004)
fun sincosm1_f256_test(x: int): (int, int) {
return sincosm1_f256(x);
}
@method_id(10005)
fun tan_aux_f256_test(x: int): (int, int) {
return tan_aux_f256(x);
}
@method_id(10006)
fun fixed248_tan_test(x: int): int {
return fixed248_tan(x);
}
/*
(int) atanh_alt_f258_test(x) method_id(10007) {
return atanh_alt_f258(x);
}
*/
@method_id(10008)
fun atanh_f258_test(x:int, y:int): int {
return atanh_f258(x, y);
}
@method_id(10009)
fun atanh_f261_test(x:int, y:int): int {
return atanh_f261(x, y);
}
@method_id(10010)
fun log2_aux_f256_test(x:int): (int, int) {
return log2_aux_f256(x);
}
@method_id(10011)
fun log_aux_f256_test(x:int): (int, int) {
return log_aux_f256(x);
}
@method_id(10012)
fun fixed248_pow_test(x:int, y:int): int {
return fixed248_pow(x, y);
}
@method_id(10013)
fun exp_log_div(x:int, y:int): int {
return fixed248_exp(fixed248_log(x << 248) ~/ y);
}
@method_id(10014)
fun fixed248_log_test(x:int): int {
return fixed248_log(x);
}
@method_id(10015)
fun log_aux_f257_test(x:int): (int,int) {
return log_aux_f257(x);
}
@method_id(10016)
fun fixed248_sincos_test(x:int): (int,int) {
return fixed248_sincos(x);
}
@method_id(10017)
fun fixed248_exp_test(x:int): int {
return fixed248_exp(x);
}
@method_id(10018)
fun fixed248_exp2_test(x:int): int {
return fixed248_exp2(x);
}
@method_id(10019)
fun expm1_f257_test(x:int): int {
return expm1_f257(x);
}
@method_id(10020)
fun atan_f255_test(x:int): int {
return atan_f255(x);
}
@method_id(10021)
fun atan_f259_test(x:int, n:int): int {
return atan_f259(x, n);
}
@method_id(10022)
fun atan_aux_f256_test(x:int): (int, int) {
return atan_aux_f256(x);
}
@method_id(10023)
fun asin_f255_test(x:int): int {
return asin_f255(x);
}
@method_id(10024)
fun asin_slow_f255_test(x:int): int {
return asin_slow_f255(x);
}
@method_id(10025)
fun acos_f255_test(x:int): int {
return acos_f255(x);
}
@method_id(10026)
fun acos_slow_f255_test(x:int): int {
return acos_slow_f255(x);
}
@method_id(10027)
fun fixed248_atan_test(x:int): int {
return fixed248_atan(x);
}
@method_id(10028)
fun fixed248_acot_test(x:int): int {
return fixed248_acot(x);
}
fun main() {
var One: int = 1;
// repeat(76 / 4) { One *= 10000; }
var sqrt2: int = geom_mean(One, 2 * One);
var sqrt3: int = geom_mean(One, 3 * One);
// return geom_mean(-1 - (-1 << 256), -1 - (-1 << 256));
// return geom_mean(-1 - (-1 << 256), -2 - (-1 << 256));
// return geom_mean(-1 - (-1 << 256), 1 << 255);
// return (sqrt2, geom_mean(sqrt2, One)); // (sqrt(2), 2^(1/4))
// return (sqrt3, geom_mean(sqrt3, One)); // (sqrt(3), 3^(1/4))
// return geom_mean(3 << 254, 1 << 254);
// return geom_mean(3, 5);
// return tan_f260(115641670674223639132965820642403718536242645001775371762318060545014644837101 - 1);
// return tan_f260(15 << 252); // tan(15/256) * 2^260
// return sincosm1_f259(1 << 255); // (sin,1-cos)(1/16) * 2^259
// return sincosm1_f259(115641670674223639132965820642403718536242645001775371762318060545014644837101 - 1);
// return sincosm1_f256((1 << 255) - 1 + (1 << 255)); // (sin,1-cos)(1-2^(-256))
// return sincosm1_f256(Pi_const_f254()); // (sin,1-cos)(Pi/4)
// return sincosn_f256(Pi_const_f254(), 0); // (sin,-cos)(Pi/4)
// return sincosn_f256((1 << 255) + 1, 0); // (sin,-cos)(1/2+1/2^256)
// return sincosn_f256(1 << 254, 0);
// return sincosn_f256(touch(15) << 252, 0); // (sin,-cos)(15/16)
// return sincosm1_f256(touch(15) << 252); // (sin,1-cos)(15/16)
// return sincosn_f256(60628596148627720713372490462954977108898896221398738326462025186323149077698, 0); // (sin,-cos)(Pi/6)
// return sincosm1_f256(60628596148627720713372490462954977108898896221398738326462025186323149077698); // (sin,1-cos)(Pi/6)
// return tan_aux_f256(1899 << 245); // (p,q) such that p/q=tan(1899/2048)
// return fixed248_tan(11 << 248); // tan(11)
// return atanh_alt_f258(1 << 252); // atanh(1/64) * 2^258
// return atanh_f258(1 << 252, 18); // atanh(1/64) * 2^258
// return atanh_f261(muldivr(64, 1 << 255, 55), 18); // atanh(1/55) * 2^261
// return log2_aux_f256(1 << 255);
// return log2_aux_f256(-1 - (-1 << 256)); // log2(2-1/2^255))*2^256 ~ 2^256 - 1.43
// return log_aux_f256(-1 - (-1 << 256));
// return log_aux_f256(3); // log(3/2)*2^256
// return fixed248_pow(3 << 248, 3 << 248); // 3^3
// return fixed248_exp(fixed248_log(5 << 248) ~/ 7); // exp(log(5)/7) = 5^(1/7)
// return fixed248_log(Pi_const_f254() ~>> 6); // log(Pi)
// return atanh_alt_f258(1 << 255); // atanh(1/8) * 2^258
// return atanh_f258(1 << 255, 37); // atanh(1/8) * 2^258
// return atanh_f258(81877371507464127617551201542979628307507432471243237061821853600756754782485, 36); // atanh(sqrt(2)/8) * 2^258
// return log_aux_f257(Pi_const_f254()); // log(Pi/4)
// return log_aux_f257(3 << 254); // log(3)
// return atanh_alt_f258(81877371507464127617551201542979628307507432471243237061821853600756754782485); // atanh(sqrt(2)/8) * 2^258
// return fixed248_sincos(Pi_const_f254() ~/ (64 * 3)); // (sin,cos)(Pi/3)
// return fixed248_exp(3 << 248); // exp(3)*2^248
// return fixed248_exp2((1 << 248) ~/ 5); // 2^(1/5)*2^248
// return fixed248_pow(3 << 248, -3 << 247); // 3^(-1.5)
// return fixed248_pow(10 << 248, -70 << 248); // 10^(-70)
// return fixed248_pow(fixed248_Pi_const(), touch(3) << 248); // Pi^3 ~ 31.006, computed more precisely
// return fixed248_pow(fixed248_Pi_const(), fixed248_Pi_const()); // Pi^Pi, more precisely
// return fixed248_exp(fixed248_log(fixed248_Pi_const()) * 3); // Pi^3 ~ 31.006
// return fixed248_exp(muldivr(fixed248_log(fixed248_Pi_const()), fixed248_Pi_const(), 1 << 248)); // Pi^Pi
// return fixed248_sin(fixed248_log(fixed248_exp(fixed248_Pi_const()))); // sin(log(e^Pi))
// return expm1_f257(1 << 255); // (exp(1/4)-1)*2^256
// return expm1_f257(-1 << 256); // (exp(-1/2)-1)*2^256 (argument out of range, will overflow)
// return expm1_f257(log2_const_f256()); // (exp(log(2)/2)-1)*2^256
// return expm1_f257(- log2_const_f256()); // (exp(-log(2)/2)-1)*2^256
// return tanh_f258(log2_const_f256(), 17); // tanh(log(2)/4)*2^258
// return atan_f255(0xa0 << 247);
// return atan_f259(1 << 255, 26); // atan(1/16)
// return atan_f259(touch(2273) << 244, 26); // atan(2273/2^15)
// return atan_aux_f256(0xa0 << 248);
// return atan_aux_f256(-1 - (-1 << 256));
// return atan_aux_f256(-1 << 256);
// return atan_aux_f256(1); // atan(1/2^256)*2^261 = 32
//return fixed248_nrand();
// return test_nrand(100000);
var One2: int = touch(1 << 255);
// return asin_f255(One);
// return asin_f255(-2 * One ~/ -3);
var arg: int = muldivr(12, One2, 17); // 12/17
// return [ asin_slow_f255(arg), asin_f255(arg) ];
// return [ acos_slow_f255(arg), acos_f255(arg) ];
// return 4 * atan_f255(One ~/ 5) - atan_f255(One ~/ 239); // 4 * atan(1/5) - atan(1/239) = Pi/4 as fixed255
var One3: int = touch(1 << 248);
// return fixed248_atan(One) ~/ 5); // atan(1/5)
// return fixed248_acot(One ~/ 239); // atan(1/5)
}
/**
method_id | in | out
@testcase | 10000 | -1-(-1<<256) -1-(-1<<256) | 115792089237316195423570985008687907853269984665640564039457584007913129639935
@testcase | 10000 | -1-(-1<<256) -2-(-1<<256) | 115792089237316195423570985008687907853269984665640564039457584007913129639934
@testcase | 10000 | -1-(-1<<256) 1<<255 | 81877371507464127617551201542979628307507432471243237061821853600756754782485
@testcase | 10000 | 1 2 | 1
@testcase | 10000 | 1 3 | 2
@testcase | 10000 | 3<<254 1<<254 | 50139445418395255283694704271811692336355250894665672355503583528635147053497
@testcase | 10000 | 3 5 | 4
@testcase | 10001 | 115641670674223639132965820642403718536242645001775371762318060545014644837101-1 | 115792089237316195423570985008687907853269984665640564039457584007913129639935
@testcase | 10001 | 15<<252 | 108679485937549714997960660780289583146059954551846264494610741505469565211201
@testcase | 10002 | 1<<255 | 57858359242454268843682786479537198006144860419130642837770554273561536355094 28938600351875109040123440645416448095273333920390487381363947585666516031269
@testcase | 10002 | 90942894222941581070058735694432465663348344332098107489693037779484723616546 | 90796875678616203090520439851979829600860326752181983760731669850687818036503 71369031536005973567205947792557760023823761636922618688720973932041901854510
@testcase | 10002 | 115641670674223639132965820642403718536242645001775371762318060545014644837100 | 115341536360906404779899502576747487978354537254490211650198994186870666100480 115341536360906404779899502576747487978354537254490211650198994186870666100479
@testcase | 10003 | 90942894222941581070058735694432465663348344332098107489693037779484723616546 0 | 81877371507464127617551201542979628307507432471243237061821853600756754782485 -81877371507464127617551201542979628307507432471243237061821853600756754782486
@testcase | 10003 | (1<<255)+1 0 | 55513684748706254392157395574451324146997108788015526773113170656738693667657 -101617118319522600545601981648807607350213579319835970884288805016705398675944
@testcase | 10003 | 1<<254 0 | 28647421327665059059430596260119789787021370826354543144805343654507971817712 -112192393597863122712065585177748900737784171216163716639418346853706594800924
@testcase | 10003 | 15<<252 0 | 93337815620236900315136494926097782162348358704087992554326802765553037216157 -68526346066204767396483080633934170508153877799043171682610011603005473885083
@testcase | 10004 | 15<<252 | 93337815620236900315136494926097782162348358704087992554326802765553037216158 94531486342222856054175808749507474690232213733194784713695144809815311509707
@testcase | 10003 | 60628596148627720713372490462954977108898896221398738326462025186323149077698 0 | 57896044618658097711785492504343953926634992332820282019728792003956564819968 -100278890836790510567389408543623384672710501789331344711007167057270294106993
@testcase | 10004 | 60628596148627720713372490462954977108898896221398738326462025186323149077698 | 57896044618658097711785492504343953926634992332820282019728792003956564819968 31026396801051369712363152930129046361118965752618438656900833901285671065886
@testcase | 10005 | 1899<<245 | -115784979074977116522606932816046735344768048129666123117516779696532375620701 -86847621900007587791673148476644866514014227467564880140262768165345715058771
@testcase | 10006 | 11<<248 | -102200470999497240398685962406597118965525125432278008915850368651878945159221
@testcase | 10008 | 1<<252 18 | 7237594612640731814076778712183932891481921212865048737772958953246047977071
@testcase! | 10009 | 64*(1<<255)//55 18 | 67377367986958444187782963285047188951340314639925508148698906136973510008513
@testcase | 10010 | 1<<255 | 0 255
@testcase | 10011 | -1-(-1<<256) | 80260960185991308862233904206310070533990667611589946606122867505419956976171 255
@testcase | 10012 | 3<<248 3<<248 | 12212446911748192486079752325135052781399568695204278238536542063334587891712
@testcase | 10013 | 5 7 | 569235245303856216139605450142923208167703167128528666640203654338408315932
@testcase | 10014 | 1420982722233462204219667745225507275989817880189032929526453715304448806508 | 517776035526939558040896860590142614178014859368681705591403663865964112176
@testcase | 10008 | 1<<255 37 | 58200445412255555045265806996802932280233368707362818578692888102488340124094
@testcase | 10008 | 81877371507464127617551201542979628307507432471243237061821853600756754782485 36 | 82746618329032515754939514227666784789465120373484337368014239356561508382845
@testcase | 10015 | 90942894222941581070058735694432465663348344332098107489693037779484723616546 | -55942510554172181731996424203087263676819062449594753161692794122306202470292 256
@testcase | 10015 | 3<<254 | -66622616410625360568738677407433830899150908037353507097280251369610028875158 256
@testcase | 10016 | 90942894222941581070058735694432465663348344332098107489693037779484723616546//(64*3) | 391714417331212931903864877123528846377775397614575565277371746317462086355 226156424291633194186662080095093570025917938800079226639565593765455331328
@testcase | 10017 | 3<<248 | 9084946421051389814103830025729847734065792062362132089390904679466687950835
@testcase | 10018 | (1<<248)//5 | 519571025111621076330285524602776985448579272766894385941850747946908706857
@testcase | 10012 | 3<<248 -3<<247 | 87047648295825095978636639360784188083950088358794570061638165848324908079
@testcase | 10012 | 10<<248 -70<<248 | 45231
@testcase | 10012 | 1420982722233462204219667745225507275989817880189032929526453715304448806508 3<<248 | 14024537329227316173680050897643053638073167245065581681188087336877135047241
@testcase | 10012 | 1420982722233462204219667745225507275989817880189032929526453715304448806508 1420982722233462204219667745225507275989817880189032929526453715304448806508 | 16492303277433924047657446877966346821161732581471802839855102123372676002295
@testcase | 10019 | 1<<255 | 65775792789545756849501669218806308540691279864498696756901136302101823231959
@testcase | 10019 | -1<<255 | -51226238931640701466578648374135745377468902266335737558089915608594425303282
@testcase | 10020 | 160<<247 | 32340690885082755723307749066376646841771751777398167772823878380310576779097
@testcase | 10021 | 1<<255 26 | 57820835337111819566482910321201859268121322500887685881159030272507322418551
@testcase | 10021 | 2273<<244 26 | 64153929153128256059565403901040178355488584937372975321150754259394300105908
@testcase | 10022 | 160<<248 | 18 -13775317617017974742132028403521581424991093186766868001115299479309514610238
@testcase | 10022 | -1-(-1<<256) | 25 16312150880916231694896252427912541090503675654570543195394548083530005073282
@testcase | 10022 | -1<<256 | -25 -16312150880916231694896252427912541090503675654570543195394548083530005073298
@testcase | 10022 | 1 | 0 32
@testcase | 10023 | 1<<255 | 90942894222941581070058735694432465663348344332098107489693037779484723616546
@testcase | 10023 | (1-(1<<255))//-3 | 19675212872822715586637341573564384553677006914302429002469838095945333339604
@testcase | 10023 | 12*(1<<255)//17 | 45371280744427205854111943101074857545572584208710061167826656461897302968384
@testcase | 10024 | 12*(1<<255)//17 | 45371280744427205854111943101074857545572584208710061167826656461897302968387
@testcase | 10025 | 12*(1<<255)//17 | 22785806739257187607973396296678804058887880061694023160933190658793710324081
@testcase | 10026 | 12*(1<<255)//17 | 22785806739257187607973396296678804058887880061694023160933190658793710324080
@testcase | 10027 | (1<<248)//5 | 89284547973388213553327350968415123522888028497458323165947767504203347189
@testcase | 10028 | (1<<248)//239 | 708598849781543798951441405045469962900811296151941404481049216461523216127
*/

View file

@ -0,0 +1,151 @@
fun unsafeGetInt<X>(any: X): int
asm "NOP";
@method_id(11)
fun foo(x: int): int {
try {
if (x == 7) {
throw 44;
}
return x;
} catch {
return 2;
}
}
@inline
@method_id(12)
fun foo_inline(x: int): int {
try {
assert(!(x == 7)) throw 44;
return x;
} catch {
return 2;
}
}
@inline_ref
@method_id(13)
fun foo_inlineref(x: int): int {
try {
if (x == 7) { throw (44, 2); }
return x;
} catch (_, arg) {
return unsafeGetInt(arg);
}
}
@method_id(1)
fun test(x: int, y: int, z: int): int {
y = foo(y);
return x * 100 + y * 10 + z;
}
@method_id(2)
fun test_inline(x: int, y: int, z: int): int {
y = foo_inline(y);
return x * 100 + y * 10 + z;
}
@method_id(3)
fun test_inlineref(x: int, y: int, z: int): int {
y = foo_inlineref(y);
return x * 100 + y * 10 + z;
}
@inline
@method_id(14)
fun foo_inline_big(
x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int, x8: int, x9: int, x10: int,
x11: int, x12: int, x13: int, x14: int, x15: int, x16: int, x17: int, x18: int, x19: int, x20: int
): int {
try {
if (x1 == 7) {
throw 44;
}
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20;
} catch {
return 1;
}
}
@method_id(4)
fun test_inline_big(x: int, y: int, z: int): int {
y = foo_inline_big(
y, y + 1, y + 2, y + 3, y + 4, y + 5, y + 6, y + 7, y + 8, y + 9,
y + 10, y + 11, y + 12, y + 13, y + 14, y + 15, y + 16, y + 17, y + 18, y + 19);
return x * 1000000 + y * 1000 + z;
}
@method_id(15)
fun foo_big(
x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int, x8: int, x9: int, x10: int,
x11: int, x12: int, x13: int, x14: int, x15: int, x16: int, x17: int, x18: int, x19: int, x20: int
): int {
try {
if (x1 == 7) {
throw (44, 1);
}
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20;
} catch (code, arg) {
return unsafeGetInt(arg);
}
}
@method_id(5)
fun test_big(x: int, y: int, z: int): int {
y = foo_big(
y, y + 1, y + 2, y + 3, y + 4, y + 5, y + 6, y + 7, y + 8, y + 9,
y + 10, y + 11, y + 12, y + 13, y + 14, y + 15, y + 16, y + 17, y + 18, y + 19);
return x * 1000000 + y * 1000 + z;
}
@method_id(16)
fun test_catch_into_same(x: int): int {
var code = x;
try {
assert(x <= 10, 44);
} catch(code) {
return code;
}
return code;
}
@method_id(17)
fun test_catch_into_same_2(x: int): int {
var code = x;
try {
if (x > 10) {
throw 44;
}
} catch(code) {
}
return code;
}
fun main() {
}
/**
method_id | in | out
@testcase | 1 | 1 2 3 | 123
@testcase | 1 | 3 8 9 | 389
@testcase | 1 | 3 7 9 | 329
@testcase | 2 | 1 2 3 | 123
@testcase | 2 | 3 8 9 | 389
@testcase | 2 | 3 7 9 | 329
@testcase | 3 | 1 2 3 | 123
@testcase | 3 | 3 8 9 | 389
@testcase | 3 | 3 7 9 | 329
@testcase | 4 | 4 8 9 | 4350009
@testcase | 4 | 4 7 9 | 4001009
@testcase | 5 | 4 8 9 | 4350009
@testcase | 5 | 4 7 9 | 4001009
@testcase | 16 | 5 | 5
@testcase | 16 | 20 | 44
@testcase | 17 | 5 | 5
@testcase | 17 | 20 | 20
@code_hash 73240939343624734070640372352271282883450660826541545137654364443860257436623
*/

View file

@ -0,0 +1,17 @@
fun main(x: int): (int, int) {
var y: int = 5;
if (x < 0) {
x *= 2;
y += 1;
if (x == -10) {
return (111, 0);
}
}
return (x + 1, y);
}
/**
method_id | in | out
@testcase | 0 | 10 | 11 5
@testcase | 0 | -5 | 111 0
@testcase | 0 | -4 | -7 6
*/

View file

@ -0,0 +1,19 @@
@inline
fun foo(x: int): int {
if (x < 0) {
x *= 2;
if (x == -10) {
return 111;
}
}
return x + 1;
}
fun main(x: int): int {
return foo(x) * 10;
}
/**
method_id | in | out
@testcase | 0 | 10 | 110
@testcase | 0 | -5 | 1110
@testcase | 0 | -4 | -70
*/

View file

@ -0,0 +1,68 @@
fun main() { }
@method_id(1)
fun foo_repeat(x: int): int {
repeat(10) {
x += 10;
if (x >= 100) {
return x;
}
}
return -1;
}
@method_id(2)
fun foo_while(x: int): int {
var i: int = 0;
while (i < 10) {
x += 10;
if (x >= 100) {
return x;
}
i += 1;
}
return -1;
}
@method_id(3)
fun foo_until(x: int): int {
var i: int = 0;
do {
x += 10;
if (x >= 100) {
return x;
}
i += 1;
} while (i < 10);
return -1;
}
@method_id(4)
fun test4(x: int): (int, int) {
var s = 0;
var reached = false;
do {
x = x - 1;
s = s + 1;
if (x < 10) {
reached = true;
}
} while (!reached);
return (s, reached);
}
/**
method_id | in | out
@testcase | 1 | 40 | 100
@testcase | 1 | 33 | 103
@testcase | 1 | -5 | -1
@testcase | 2 | 40 | 100
@testcase | 2 | 33 | 103
@testcase | 2 | -5 | -1
@testcase | 3 | 40 | 100
@testcase | 3 | 33 | 103
@testcase | 3 | -5 | -1
@testcase | 4 | 18 | 9 -1
@code_hash 12359153928622198176298534554187062238616102949658930329300859312625793323482
*/

View file

@ -0,0 +1,40 @@
fun foo(y: int): int {
if (y < 0) {
y *= 2;
if (y == -10) {
return 111;
}
}
return y + 1;
}
fun bar(x: int, y: int): (int, int) {
if (x < 0) {
y = foo(y);
x *= 2;
if (x == -10) {
return (111, y);
}
}
return (x + 1, y);
}
fun bar2(x: int, y: int): (int,int) {
return bar(x, y);
}
fun main(x: int, y: int): (int, int) {
(x, y) = bar2(x, y);
return (x, y * 10);
}
/**
method_id | in | out
@testcase | 0 | 3 3 | 4 30
@testcase | 0 | 3 -5 | 4 -50
@testcase | 0 | 3 -4 | 4 -40
@testcase | 0 | -5 3 | 111 40
@testcase | 0 | -5 -5 | 111 1110
@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
*/

View file

@ -0,0 +1,49 @@
fun main(): int {
var c: cell = my_begin_cell().store_int(demo_10, 32).my_end_cell();
var cs: slice = my_begin_parse(c);
var ten: int = cs~load_int(32);
return 1 + demo1(ten) + demo_var;
}
@pure
fun my_begin_cell(): builder
asm "NEWC";
@pure
fun my_end_cell(b: builder): cell
asm "ENDC";
@pure
fun my_begin_parse(c: cell): slice
asm "CTOS";
fun demo1(v: int): int {
demo_var = 23;
return v;
}
global demo_var: int;
const demo_10: int = 10;
fun test1(): int {
var demo_var: int = demo_10;
var demo_slice: int = demo_20;
if (demo_var > 0) {
var demo_var: tuple = null;
var demo_slice: tuple = null;
}
return demo_var + demo_slice;
}
global demo_slice: slice;
const demo_20: int = 20;
/**
@testcase | 0 | | 34
@fif_codegen
"""
test1 PROC:<{
//
30 PUSHINT // _10
}>
"""
*/

14
tolk-tester/tests/w1.tolk Normal file
View file

@ -0,0 +1,14 @@
fun main(id: int): (int, int) {
if (id > 0) {
if (id > 10) {
return (2 * id, 3 * id);
}
}
return (5, 6);
}
/**
method_id | in | out
@testcase | 0 | 0 | 5 6
@testcase | 0 | 4 | 5 6
@testcase | 0 | 11 | 22 33
*/

34
tolk-tester/tests/w2.tolk Normal file
View file

@ -0,0 +1,34 @@
@method_id(101)
fun test1(cs: slice) {
return cs~load_uint(8)+cs~load_uint(8)+cs~load_uint(8)+cs~load_uint(8);
}
@method_id(102)
fun test2(cs: slice) {
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;
}
fun main(cs: slice) {
return (cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8));
}
fun f(cs: slice) {
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));
}
/**
method_id | in | out
@testcase | 102 | x{000102030405060708090a0b0c0d0e0f10111213} | 190
@testcase | 101 | x{000102030405060708090a0b0c0d0e0f10111213} | 6
@testcase | 0 | x{000102030405060708090a0b0c0d0e0f10111213} | 0 1 2 3
@code_hash 58474889199998908444151060994149070836199913191952040273624197630531731101157
*/

19
tolk-tester/tests/w6.tolk Normal file
View file

@ -0,0 +1,19 @@
fun main(x: int): int {
var i: int = 0;
// int f = false;
do {
i = i + 1;
if (i > 5) {
return 1;
}
var f: int = (i * i == 64);
} while (!f);
return -1;
}
/**
method_id | in | out
@testcase | 0 | 0 | 1
@code_hash 36599880583276393028571473830850694081778552118303309411432666239740650614479
*/

26
tolk-tester/tests/w7.tolk Normal file
View file

@ -0,0 +1,26 @@
@method_id(1)
fun test(y: int): int {
var x: int = 1;
if (y > 0) {
return 1;
}
return x > 0;
}
@method_id(2)
fun f(y: int): int {
if (y > 0) {
return 1;
}
return 2;
}
fun main() { }
/**
method_id | in | out
@testcase | 1 | 10 | 1
@testcase | 1 | -5 | -1
@testcase | 2 | 10 | 1
@testcase | 2 | -5 | 2
*/

Some files were not shown because too many files have changed in this diff Show more