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

[Tolk] Change order of assignment evaluation, lhs first

In FunC (and in Tolk before), the assignment
> lhs = rhs
evaluation order (at IR level) was "rhs first, lhs second".
In practice, this did not matter, because lhs could only
be a primitive:
> (v1, v2) = getValue()
Left side of assignment actually has no "evaluation".
Since Tolk implemented indexed access, there could be
> getTensor().0 = getValue()
or (in the future)
> getObject().field = getValue()
where evaluation order becomes significant.

Now evaluation order will be to "lhs first, rhs second"
(more expected from user's point of view), which will become
significant when building control flow graph.
This commit is contained in:
tolk-vm 2025-02-10 12:57:25 +04:00
parent 2a68c8610b
commit 1389ff6789
No known key found for this signature in database
GPG key ID: 7905DD7FE0324B12
20 changed files with 602 additions and 456 deletions

View file

@ -144,15 +144,16 @@ fun test95() {
"""
test95 PROC:<{
...
next GETGLOB // '10
3 PUSHINT // '10 '12=3
4 PUSHINT // '10 '12=3 '13=4
5 PUSHINT // '10 '12=3 '13=4 '14=5
TRIPLE // '15 '16
next SETGLOB
next GETGLOB // g_next
3 PUSHINT // g_next '14=3
4 PUSHINT // g_next '14=3 '15=4
5 PUSHINT // g_next '14=3 '15=4 '16=5
TRIPLE // '10 '11
SWAP
cur SETGLOB
cur GETGLOB // '17
next GETGLOB // '17 '18
next SETGLOB
cur GETGLOB // g_cur
next GETGLOB // g_cur g_next
}>
"""
*/

View file

@ -147,5 +147,5 @@ fun main() {
// x.0 x.1
"""
@code_hash 7627024945492125068389905298530400936797031708759561372406088054030801992712
@code_hash 61280273714870328160131559159866470128402169974050439159015534193532598351244
*/

View file

@ -26,6 +26,185 @@ fun typesAsIdentifiers(builder: builder) {
return int;
}
global callOrder: tuple;
fun getTensor_12() {
callOrder.tuplePush(100);
return (1, 2);
}
fun getTensor_1X(x: int) {
callOrder.tuplePush(101);
return (1, x);
}
fun getTuple_12() {
callOrder.tuplePush(110);
return [1, 2];
}
fun getTuple_1X(x: int) {
callOrder.tuplePush(111);
return [1, x];
}
fun getUntypedTuple_12() {
callOrder.tuplePush(120);
var t = createEmptyTuple(); t.tuplePush(1); t.tuplePush(2);
return t;
}
fun getUntypedTuple_1X(x: int) {
callOrder.tuplePush(121);
var t = createEmptyTuple(); t.tuplePush(1); t.tuplePush(x);
return t;
}
fun getIntValue5() {
callOrder.tuplePush(10);
return 5;
}
fun getIntValueX(x: int) {
callOrder.tuplePush(11);
return x;
}
@method_id(102)
fun test102() {
callOrder = createEmptyTuple();
var x = 0;
getTensor_12().0 = getIntValue5();
getTensor_1X(5).1 = getIntValue5();
getTensor_1X(x = 10).0 = getIntValueX(x);
return (callOrder, x);
}
@method_id(103)
fun test103() {
callOrder = createEmptyTuple();
var x = 0;
getTuple_12().0 = getIntValue5();
getTuple_1X(5).1 = getIntValue5();
getTuple_1X(x = 10).0 = getIntValueX(x);
return (callOrder, x);
}
@method_id(104)
fun test104() {
callOrder = createEmptyTuple();
var x = 0;
getUntypedTuple_12().0 = getIntValue5();
getUntypedTuple_1X(5).1 = getIntValue5();
getUntypedTuple_1X(x = 10).0 = getIntValueX(x);
return (callOrder, x);
}
@method_id(105)
fun test105() {
callOrder = createEmptyTuple();
getTensor_12().0 = getTensor_1X(getIntValue5()).1 = getIntValueX(getTensor_12().1);
return callOrder;
}
@method_id(106)
fun test106() {
callOrder = createEmptyTuple();
getTuple_12().0 = getTuple_1X(getIntValue5()).1 = getIntValueX(getTuple_12().1);
return callOrder;
}
global t107: (int, int);
@method_id(107)
fun test107() {
((t107 = (1, 2)).0, (t107 = (3, 4)).1) = (5, 6);
return t107;
}
global g108: int;
fun assertEq(a: int, b: int) {
assert(a == b, 10);
return b;
}
@method_id(108)
fun test108() {
callOrder = createEmptyTuple();
g108 = 0;
getTensor_1X(g108 = 8).1 = assertEq(g108, 8);
return (callOrder, g108);
}
@method_id(109)
fun test109() {
callOrder = createEmptyTuple();
var x = 0;
[getTuple_12().0, getTuple_1X(x = getIntValue5()).1, getTuple_1X(x += 10).0] = [getIntValue5(), getIntValue5(), getIntValueX(x)];
return (callOrder, x);
}
global g110: int;
global t110: (int, int);
@method_id(110)
fun test110() {
callOrder = createEmptyTuple();
var xy = [0, 0];
[xy.0, getTuple_1X(g110 = 8).0] = [g110 += 5, getIntValueX(g110 += 10)];
[xy.1, getTuple_1X((t110 = (8, 9)).0).1] = [t110.0 += 5, getIntValueX(t110.1 += 10)];
return (xy, callOrder, g110, t110);
}
@method_id(111)
fun test111() {
callOrder = createEmptyTuple();
var z = -1;
var xy = [0, z = 0];
var rhs = [getIntValueX(xy.1 += 10), xy.1, xy.0, z += 50];
[xy.0, getTuple_1X(g110 = 8 + getIntValueX(xy.1)).0, xy.1, z] = rhs;
return (xy, g110, callOrder, z);
}
@method_id(112)
fun test112() {
var xy = [1, 2];
((((xy))).0, ((xy.1))) = ((xy).1, ((xy.0)));
return xy;
}
@method_id(113)
fun test113() {
var (a, t, z) = (1, [2,3], (-1,-1));
(a, t, a, z, t.1, z.1) = (10, [a,12], 13, (a, t.1), 14, t.1);
return (a, t, z);
}
global g114: int;
global t114: [int, int];
global z114: (int, int);
@method_id(114)
fun test114() {
g114 = 1;
t114 = [2, 3];
(g114, t114, g114, z114, t114.1, z114.1) = (10, [g114,12], 13, (g114, t114.1), 14, t114.1);
return (g114, t114, z114);
}
@method_id(115)
fun test115() {
callOrder = createEmptyTuple();
var x = 0;
var y = 0;
[getTensor_1X(x = 5).0, y] = getTuple_1X(x = 9);
return (callOrder, x, y);
}
@method_id(116)
fun test116() {
var (a,b,c,d) = (0,0,0,0);
var rhs = [1, 2, 3, 4];
var rhs2 = ([a,b,c,d] = rhs);
__expect_type(rhs2, "[int, int, int, int]");
return (a, b, c, d, rhs2);
}
fun main(value: int) {
var (x: int, y) = (autoInferIntNull(value), autoInferIntNull(value * 2));
if (x == null && y == null) { return null; }
@ -37,4 +216,35 @@ fun main(value: int) {
@testcase | 0 | 6 | -1
@testcase | 0 | 11 | (null)
@testcase | 101 | 78 | 88
@testcase | 102 | | [ 100 10 101 10 101 11 ] 10
@testcase | 103 | | [ 110 10 111 10 111 11 ] 10
@testcase | 104 | | [ 120 10 121 10 121 11 ] 10
@testcase | 105 | | [ 100 10 101 100 11 ]
@testcase | 106 | | [ 110 10 111 110 11 ]
@testcase | 107 | | 3 4
@testcase | 108 | | [ 101 ] 8
@testcase | 109 | | [ 110 10 111 111 10 10 11 ] 15
@testcase | 110 | | [ 13 13 ] [ 111 11 111 11 ] 23 13 19
@testcase | 111 | | [ 10 0 ] 18 [ 11 11 111 ] 50
@testcase | 112 | | [ 2 1 ]
@testcase | 113 | | 13 [ 1 14 ] 1 3
@testcase | 114 | | 13 [ 1 14 ] 1 3
@testcase | 115 | | [ 101 111 ] 9 9
@testcase | 116 | | 1 2 3 4 [ 1 2 3 4 ]
@fif_codegen
"""
test116 PROC:<{
//
1 PUSHINT // '10=1
2 PUSHINT // '10=1 '11=2
3 PUSHINT // '10=1 '11=2 '12=3
4 PUSHINT // '10=1 '11=2 '12=3 '13=4
4 TUPLE // rhs
DUP // rhs rhs
4 UNTUPLE // rhs2 a b c d
4 ROLL // a b c d rhs2
}>
"""
*/

View file

@ -35,7 +35,7 @@ Below, I just give examples of @fif_codegen tag:
"""
main PROC:<{
// s
17 PUSHINT // s '1=17
17 PUSHINT // s '3=17
OVER // s z=17 t
WHILE:<{
...

View file

@ -21,6 +21,26 @@ fun plus(mutate self: int, y: int): int {
fun eq<X>(v: X): X { return v; }
global gTup: [int];
global gTens: (int, int);
@method_id(100)
fun testCodegenSimple() {
var t1 = [1];
t1.0 = 2;
debugPrintString("");
var t2 = [[1]];
t2.0.0 = 2;
debugPrintString("");
gTup = [1];
gTup.0 = 2;
debugPrintString("");
gTens = (1,2);
gTens.1 = 4;
debugPrintString("");
return (t1, t2, gTup, gTens);
}
@method_id(101)
fun test101() {
var t = (1, (2, 3), [4, 5, [6, 7]], 8);
@ -241,30 +261,60 @@ fun main(){}
@fif_codegen
"""
testCodegenNoPureIndexedAccess PROC:<{
testCodegenSimple PROC:<{
//
0 PUSHINT // '8=0
1 PUSHINT // '2=1
SINGLE // t1
2 PUSHINT // t1 '3=2
0 SETINDEX // t1
x{} PUSHSLICE // t1 '6
STRDUMP DROP
1 PUSHINT // t1 '10=1
SINGLE // t1 '9
SINGLE // t1 t2
2 PUSHINT // t1 t2 '11=2
OVER // t1 t2 '11=2 t2
0 INDEX // t1 t2 '11=2 '14
SWAP // t1 t2 '14 '11=2
0 SETINDEX // t1 t2 '14
0 SETINDEX // t1 t2
x{} PUSHSLICE // t1 t2 '17
STRDUMP DROP
1 PUSHINT // t1 t2 '20=1
SINGLE // t1 t2 '18
gTup SETGLOB
2 PUSHINT // t1 t2 '21=2
gTup GETGLOB // t1 t2 '21=2 g_gTup
SWAP // t1 t2 g_gTup '21=2
0 SETINDEX // t1 t2 g_gTup
gTup SETGLOB
x{} PUSHSLICE // t1 t2 '25
STRDUMP DROP
1 PUSHINT // t1 t2 '28=1
2 PUSHINT // t1 t2 '26=1 '27=2
PAIR
gTens SETGLOB
4 PUSHINT // t1 t2 g_gTens.1=4
gTens GETGLOB
UNPAIR // t1 t2 g_gTens.1=4 g_gTens.0 g_gTens.1
DROP // t1 t2 g_gTens.1=4 g_gTens.0
SWAP // t1 t2 g_gTens.0 g_gTens.1=4
PAIR
gTens SETGLOB
x{} PUSHSLICE // t1 t2 '36
STRDUMP DROP
gTup GETGLOB // t1 t2 g_gTup
gTens GETGLOB
UNPAIR // t1 t2 g_gTup g_gTens.0 g_gTens.1
}>
"""
@fif_codegen
"""
test104 PROC:<{
testCodegenNoPureIndexedAccess PROC:<{
//
5 PUSHINT // '2=5
DUP // '2=5 '3=5
PAIR // '1
SINGLE // m
10 PUSHINT // m '5=10
20 PUSHINT // m '5=10 '6=20
s2 PUSH // m '5=10 '6=20 m
0 INDEX // m '10=10 '12=20 '8
SWAP // m '10=10 '8 '12=20
1 SETINDEX // m '10=10 '8
SWAP // m '8 '10=10
0 SETINDEX // m '8
0 SETINDEX // m
...
0 PUSHINT // '8=0
}>
"""
@fif_codegen

View file

@ -1,9 +1,9 @@
fun main() {
var c = 1;
(c, c) = (2, 3);
var t = createEmptyTuple();
t.0 = (1, 2);
}
/**
@compilation_should_fail
@stderr one variable modified twice inside the same expression
@stderr a tuple can not have `(int, int)` inside, because it occupies 2 stack slots in TVM, not 1
*/

View file

@ -1,11 +1,8 @@
fun incThree(mutate a: int, mutate b: int, mutate c: int) {}
fun main() {
var c = [[[1, 2]]];
incThree(mutate c.0.0.0, mutate c.0.0.1, mutate c.0.0.0);
fun main(cs: slice) {
var cb = cs.tupleSize;
}
/**
@compilation_should_fail
@stderr one variable modified twice inside the same expression
@stderr referencing a method for `tuple` with object of type `slice`
*/

View file

@ -1,10 +1,9 @@
global gg: (int, int);
fun main() {
[gg.0, gg.1, gg.0] = [0, 1, 0];
var t = createEmptyTuple();
var xy = t.0 as (int, int);
}
/**
@compilation_should_fail
@stderr one variable modified twice inside the same expression
@stderr a tuple can not have `(int, int)` inside, because it occupies 2 stack slots in TVM, not 1
*/

View file

@ -1,10 +0,0 @@
global gg: (int, [int, int]);
fun main() {
(gg.1.0, gg.1, gg.1.1) = (0, [1, 2], 3);
}
/**
@compilation_should_fail
@stderr one variable both modified and read inside the same expression
*/

View file

@ -1,9 +0,0 @@
fun main() {
var ab = (1, 2);
(ab, ab.1) = ((2, 3), 4);
}
/**
@compilation_should_fail
@stderr one variable both modified and read inside the same expression
*/

View file

@ -1,9 +0,0 @@
fun main() {
var t = createEmptyTuple();
t.0 = (1, 2);
}
/**
@compilation_should_fail
@stderr can not put `(int, int)` into a tuple, because it occupies 2 stack slots in TVM, not 1
*/

View file

@ -1,8 +0,0 @@
fun main(cs: slice) {
var cb = cs.tupleSize;
}
/**
@compilation_should_fail
@stderr referencing a method for `tuple` with object of type `slice`
*/

View file

@ -7,5 +7,5 @@ fun main() {
/**
@compilation_should_fail
@stderr can not put `(int, builder)` into a tuple, because it occupies 2 stack slots in TVM, not 1
@stderr a tuple can not have `(int, builder)` inside, because it occupies 2 stack slots in TVM, not 1
*/

View file

@ -307,7 +307,7 @@ fun main(){}
...
incrementTwoInPlace CALLDICT // x y sum1
-ROT
10 PUSHINT // sum1 x y '10=10
10 PUSHINT // sum1 x y '11=10
incrementTwoInPlace CALLDICT // sum1 x y sum2
s1 s3 s0 XCHG3 // x y sum1 sum2
}>

View file

@ -133,7 +133,7 @@ fun main() {
"""
test7 PROC:<{
...
LDOPTREF // b '8 '7
LDOPTREF // b '9 '8
DROP // b c
ISNULL // b '11
10 MULCONST // b '13