mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 19:22:37 +00:00
Unary logical NOT was already implemented earlier. Logical AND OR are expressed via conditional expression: * a && b -> a ? (b != 0) : 0 * a || b -> a ? 1 : (b != 0) They work as expected in any expressions. For instance, having `cond && f()`, f is called only if cond is true. For primitive cases, like `a > 0 && b > 0`, Fift code is not optimal, it could potentially be without IFs. These are moments of future optimizations. For now, it's more than enough.
295 lines
6.4 KiB
Text
295 lines
6.4 KiB
Text
import "imports/use-dicts.tolk"
|
|
|
|
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;
|
|
}
|
|
|
|
@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)];
|
|
}
|
|
|
|
@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);
|
|
}
|
|
|
|
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 ]
|
|
@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
|
|
|
|
@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
|
|
}>
|
|
"""
|
|
|
|
@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
|
|
}>
|
|
}>
|
|
"""
|
|
|
|
*/
|