1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-12 19:22:37 +00:00
ton/tolk-tester/tests/logical-operators.tolk
tolk-vm 7a1602f591
[Tolk] Support syntax tensorVar.0 and tupleVar.0
It works both for reading and writing:
> var t = (1, 2);
> t.0;      // 1
> t.0 = 5;
> t;        // (5, 2)

It also works for typed/untyped tuples, producing INDEX and SETINDEX.

Global tensors and tuples works. Nesting `t.0.1.2` works. `mutate` works.
Even mixing tuples inside tensors inside a global for writing works.
2025-01-27 15:30:21 +03:00

347 lines
7.5 KiB
Text

import "imports/use-dicts.tolk"
fun simpleAllConst() {
return (!0, !!0 & !false, !!!0, !1, !!1, !-1, !!-1, (!5 as int == 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 as int > 10, (!x as int) < 10, !!x as int == 5, !x as int == -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 != 0) | !!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 as int : (!z as int) | 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;
}
@method_id(104)
fun testDict(last: int) {
// prepare dict: [3 => 30, 4 => 40, 5 => x]
var dict = prepareDict_3_30_4_40_5_x(!last ? 100 : last);
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)];
return [x == null, null == x, !(x == null)];
}
@method_id(106)
fun testAndConstCodegen() {
return (
[1 && 0, 0 && 1, 0 && 0, 1 && 1],
[4 && 3 && 0, 5 && 0 && 7 && 8, (7 && 0) && -19],
[4 && 3 && -1, 5 && -100 && 7 && 8, (7 && (1 + 2)) && -19],
[true && false, true && true]
);
}
@method_id(107)
fun testOrConstCodegen() {
return (
[1 || 0, 0 || 1, 0 || 0, 1 || 1],
[0 || 0 || 0, 0 || (0 || 0), ((0 || 0) || 0) || 0],
[4 || 3 || -1, 0 || -100 || 0 || 0, (0 || (1 + -1)) || -19],
[true || false, false || false]
);
}
global eqCallsCnt: int;
fun eq(x: int) { return x; }
fun eqCnt(x: int) { eqCallsCnt += 1; return x; }
fun isGt0(x: int) { return x > 0; }
fun alwaysThrows(): int { throw 444 ; return 444; }
@method_id(108)
fun testAndSimpleCodegen(a: int, b: int) {
return a && b;
}
@method_id(109)
fun testOrSimpleCodegen(a: int, b: int) {
return a > 0 || b > 0;
}
@method_id(110)
fun testLogicalOps1(x: int) {
eqCallsCnt = 0;
return (
isGt0(x) || !isGt0(x) || alwaysThrows(),
x && eqCnt(x) && eqCnt(x - 1) && eqCnt(x - 2),
(400 == eq(x)) && alwaysThrows(),
(500 == eq(x)) || eqCnt(x) || false,
(500 == eq(x)) || eqCnt(x) || true,
eqCallsCnt
);
}
@method_id(111)
fun testLogicalOps2(first: int) {
var s = beginCell().storeInt(1, 32).storeInt(2, 32).storeInt(3, 32).storeInt(4, 32).storeInt(5, 32).endCell().beginParse();
var sum = 0;
if (first && s.loadUint(32)) {
(2 == s.loadUint(32)) && (sum += s.loadUint(32));
(3 == s.loadUint(32)) && (sum += s.loadUint(32));
(5 == s.preloadUint(32)) && (sum += s.loadUint(32));
} else {
(10 == s.loadUint(32)) || (20 == s.loadUint(32)) || (3 == s.loadUint(32)) || (4 == s.loadUint(32));
sum += s.loadUint(32);
}
return (s.getRemainingBitsCount(), sum);
}
@method_id(112)
fun mixLogicalIntsAndBools(first: int, cond: bool) {
return (
(first && cond) || (!first && cond),
((first & -1) & cond as int) == ((first && true) && cond) as int,
7 && cond,
first || cond || !cond || alwaysThrows(),
cond || first || !first || alwaysThrows()
);
}
@method_id(113)
fun testConvertIfToIfnot(x: bool) {
assert(!!(x == false), 100);
assert(!x, 100);
if (x == !!false) {
return 1;
}
if (!!(x != !false)) {
return 1;
}
assert(!!x, 100);
return -4;
}
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 ]
@testcase | 105 | null | [ -1 -1 0 ]
@testcase | 106 | | [ 0 0 0 -1 ] [ 0 0 0 ] [ -1 -1 -1 ] [ 0 -1 ]
@testcase | 107 | | [ -1 -1 0 -1 ] [ 0 0 0 ] [ -1 -1 -1 ] [ -1 0 ]
@testcase | 108 | 1 2 | -1
@testcase | 108 | 1 0 | 0
@testcase | 109 | -5 -4 | 0
@testcase | 109 | -5 4 | -1
@testcase | 109 | 1 99 | -1
@testcase | 110 | 0 | -1 0 0 0 -1 2
@testcase | 110 | 1 | -1 0 0 -1 -1 4
@testcase | 110 | 2 | -1 0 0 -1 -1 5
@testcase | 110 | 500 | -1 -1 0 -1 -1 3
@testcase | 111 | 0 | 32 4
@testcase | 111 | -1 | 0 8
@testcase | 112 | 5 0 | 0 -1 0 -1 -1
@testcase | 112 | 0 -1 | -1 -1 -1 -1 -1
@testcase | 113 | 0 | 1
@fif_codegen
"""
simpleAllConst PROC:<{
//
TRUE
0 PUSHINT
TRUE
FALSE
TRUE
FALSE
TRUE
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
}>
"""
@fif_codegen
"""
testAndConstCodegen PROC:<{
//
FALSE
0 PUSHINT
DUP
TRUE
4 TUPLE
FALSE
0 PUSHINT
DUP
TRIPLE
TRUE
TRUE
TRUE
TRIPLE
FALSE
TRUE
PAIR
}>
"""
@fif_codegen
"""
testOrConstCodegen PROC:<{
//
-1 PUSHINT
TRUE
FALSE
s2 PUSH
4 TUPLE
FALSE
FALSE
FALSE
TRIPLE
-1 PUSHINT
DUP
TRUE
TRIPLE
-1 PUSHINT
FALSE
PAIR
}>
"""
Currently, && operator is implemented via ?: and is not optimal in primitive cases.
For example, `a && b` can be expressed without IFs.
These are moments of future optimizations. For now, it's more than enough.
@fif_codegen
"""
testAndSimpleCodegen PROC:<{
// a b
SWAP // b a
IF:<{ // b
0 NEQINT // '2
}>ELSE<{ // b
DROP //
0 PUSHINT // '2=0
}>
}>
"""
@fif_codegen
"""
testOrSimpleCodegen PROC:<{
// a b
SWAP // b a
0 GTINT // b '3
IF:<{ // b
DROP //
-1 PUSHINT // '4=-1
}>ELSE<{ // b
0 GTINT // '7
0 NEQINT // '4
}>
}>
"""
@fif_codegen
"""
testConvertIfToIfnot PROC:<{
// x
DUP // x x
100 THROWIF
DUP // x x
100 THROWIF
DUP // x x
IFNOTJMP:<{ // x
DROP //
1 PUSHINT // '5=1
}> // x
DUP // x x
IFNOTJMP:<{ // x
DROP //
1 PUSHINT // '6=1
}> // x
100 THROWIFNOT
-4 PUSHINT // '9=-4
}>
"""
*/