Skip to content

Commit 1382059

Browse files
authored
Merge pull request #1795 from ton-blockchain/tolk-v1.1
Tolk v1.1: built-in map<K,V>, enums, private and readonly fields, methods overloading
2 parents b40c28f + 506273c commit 1382059

File tree

163 files changed

+6959
-1247
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

163 files changed

+6959
-1247
lines changed

crypto/smartcont/tolk-stdlib/common.tolk

Lines changed: 533 additions & 180 deletions
Large diffs are not rendered by default.

crypto/smartcont/tolk-stdlib/gas-payments.tolk

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// A part of standard library for Tolk
2-
tolk 1.0
2+
tolk 1.1
33

44
/**
55
Gas and payment related primitives.
@@ -32,24 +32,24 @@ fun setGasLimitToMaximum(): void
3232
fun setGasLimit(limit: int): void
3333
asm "SETGASLIMIT"
3434

35-
/// Calculates fee (amount in nanotoncoins to be paid) for a transaction which consumed [gasUsed] gas units.
35+
/// Calculates fee (amount in nanotoncoins to be paid) for a transaction which consumed `gasUsed` gas units.
3636
fun calculateGasFee(workchain: int8, gasUsed: int): coins
3737
asm(gasUsed workchain) "GETGASFEE"
3838

39-
/// Same as [calculateGasFee], but without flat price (you have supposed to read https://docs.ton.org/develop/howto/fees-low-level)
39+
/// Same as [calculateGasFee], but without flat price. [Docs about fees](https://docs.ton.org/develop/howto/fees-low-level)
4040
fun calculateGasFeeWithoutFlatPrice(workchain: int8, gasUsed: coins): coins
4141
asm(gasUsed workchain) "GETGASFEESIMPLE"
4242

43-
/// Calculates amount of nanotoncoins you should pay for storing a contract of provided size for [seconds].
44-
/// [bits] and [cells] represent contract state (code + data).
43+
/// Calculates amount of nanotoncoins you should pay for storing a contract of provided size for `seconds`.
44+
/// `bits` and `cells` represent contract state (code + data).
4545
fun calculateStorageFee(workchain: int8, seconds: int, bits: int, cells: int): coins
4646
asm(cells bits seconds workchain) "GETSTORAGEFEE"
4747

4848
/// Calculates amount of nanotoncoins you should pay to send a message of a specified size.
4949
fun calculateForwardFee(workchain: int8, bits: int, cells: int): coins
5050
asm(cells bits workchain) "GETFORWARDFEE"
5151

52-
/// Same as [calculateForwardFee], but without lump price (you have supposed to read https://docs.ton.org/develop/howto/fees-low-level)
52+
/// Same as [calculateForwardFee], but without lump price. [Docs about fees](https://docs.ton.org/develop/howto/fees-low-level)
5353
fun calculateForwardFeeWithoutLumpPrice(workchain: int8, bits: int, cells: int): coins
5454
asm(cells bits workchain) "GETFORWARDFEESIMPLE"
5555

crypto/smartcont/tolk-stdlib/lisp-lists.tolk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// A part of standard library for Tolk
2-
tolk 1.0
2+
tolk 1.1
33

44
/**
55
Lisp-style lists are nested 2-elements tuples: `[1, [2, [3, null]]]` represents list `[1, 2, 3]`.

crypto/smartcont/tolk-stdlib/tvm-dicts.tolk

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
// A part of standard library for Tolk
2-
tolk 1.0
2+
tolk 1.1
33

44
/**
5-
Dictionaries are represented as `cell` data type (cells can store anything, dicts in particular).
6-
Currently, they have very low-level API very close to TVM internals.
5+
Low-level API working with TVM dictionaries.
6+
Not recommended to use, since it's very complicated and error-prone.
7+
Use `map<K, V>` instead, it's even more efficient then low-level dict API.
8+
9+
Dictionaries are represented as `cell` data type.
710
Most of functions are duplicated for three common cases:
811
- iDict* - dicts with signed integer keys
912
- uDict* - dicts with unsigned integer keys
@@ -14,10 +17,12 @@ tolk 1.0
1417
*/
1518

1619
/// In @stdlib/common.tolk, there is a type alias:
17-
/// `type dict = cell?`
20+
/// ```
21+
/// type dict = cell?
22+
/// ```
1823
/// For clarity, we use "dict" instead of a "cell?" where a cell-dictionary is assumed.
1924

20-
/// Creates an empty dictionary, which is actually a null value. Equivalent to PUSHNULL
25+
/// Creates an empty dictionary, which is actually a null value. Equivalent to `PUSHNULL`
2126
@pure
2227
fun createEmptyDict(): dict
2328
asm "NEWDICT"
@@ -86,28 +91,28 @@ fun dict.uDictSetIfExists(mutate self, keyLen: int, key: int, value: slice): boo
8691

8792

8893
@pure
89-
fun dict.iDictGetRef(self, keyLen: int, key: int): (dict, bool)
94+
fun dict.iDictGetRef(self, keyLen: int, key: int): (cell?, bool)
9095
asm(key self keyLen) "DICTIGETREF" "NULLSWAPIFNOT"
9196

9297
@pure
93-
fun dict.uDictGetRef(self, keyLen: int, key: int): (dict, bool)
98+
fun dict.uDictGetRef(self, keyLen: int, key: int): (cell?, bool)
9499
asm(key self keyLen) "DICTUGETREF" "NULLSWAPIFNOT"
95100

96101
@pure
97-
fun dict.sDictGetRef(self, keyLen: int, key: slice): (dict, bool)
102+
fun dict.sDictGetRef(self, keyLen: int, key: slice): (cell?, bool)
98103
asm(key self keyLen) "DICTGETREF" "NULLSWAPIFNOT"
99104

100105

101106
@pure
102-
fun dict.iDictGetRefOrNull(self, keyLen: int, key: int): dict
107+
fun dict.iDictGetRefOrNull(self, keyLen: int, key: int): cell?
103108
asm(key self keyLen) "DICTIGETOPTREF"
104109

105110
@pure
106-
fun dict.uDictGetRefOrNull(self, keyLen: int, key: int): dict
111+
fun dict.uDictGetRefOrNull(self, keyLen: int, key: int): cell?
107112
asm(key self keyLen) "DICTUGETOPTREF"
108113

109114
@pure
110-
fun dict.sDictGetRefOrNull(self, keyLen: int, key: slice): dict
115+
fun dict.sDictGetRefOrNull(self, keyLen: int, key: slice): cell?
111116
asm(key self keyLen) "DICTGETOPTREF"
112117

113118

@@ -138,11 +143,11 @@ fun dict.sDictSetAndGet(mutate self, keyLen: int, key: slice, value: slice): (sl
138143

139144

140145
@pure
141-
fun dict.iDictSetAndGetRefOrNull(mutate self, keyLen: int, key: int, value: cell): dict
146+
fun dict.iDictSetAndGetRefOrNull(mutate self, keyLen: int, key: int, value: cell): cell?
142147
asm(value key self keyLen) "DICTISETGETOPTREF"
143148

144149
@pure
145-
fun dict.uDictSetAndGetRefOrNull(mutate self, keyLen: int, key: int, value: cell): dict
150+
fun dict.uDictSetAndGetRefOrNull(mutate self, keyLen: int, key: int, value: cell): cell?
146151
asm(value key self keyLen) "DICTUSETGETOPTREF"
147152

148153

@@ -228,15 +233,15 @@ fun dict.sDictGetFirst(self, keyLen: int): (slice?, slice?, bool)
228233
asm (-> 1 0 2) "DICTMIN" "NULLSWAPIFNOT2"
229234

230235
@pure
231-
fun dict.iDictGetFirstAsRef(self, keyLen: int): (int?, dict, bool)
236+
fun dict.iDictGetFirstAsRef(self, keyLen: int): (int?, cell?, bool)
232237
asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"
233238

234239
@pure
235-
fun dict.uDictGetFirstAsRef(self, keyLen: int): (int?, dict, bool)
240+
fun dict.uDictGetFirstAsRef(self, keyLen: int): (int?, cell?, bool)
236241
asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"
237242

238243
@pure
239-
fun dict.sDictGetFirstAsRef(self, keyLen: int): (slice?, dict, bool)
244+
fun dict.sDictGetFirstAsRef(self, keyLen: int): (slice?, cell?, bool)
240245
asm (-> 1 0 2) "DICTMINREF" "NULLSWAPIFNOT2"
241246

242247

@@ -253,15 +258,15 @@ fun dict.sDictGetLast(self, keyLen: int): (slice?, slice?, bool)
253258
asm (-> 1 0 2) "DICTMAX" "NULLSWAPIFNOT2"
254259

255260
@pure
256-
fun dict.iDictGetLastAsRef(self, keyLen: int): (int?, dict, bool)
261+
fun dict.iDictGetLastAsRef(self, keyLen: int): (int?, cell?, bool)
257262
asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"
258263

259264
@pure
260-
fun dict.uDictGetLastAsRef(self, keyLen: int): (int?, dict, bool)
265+
fun dict.uDictGetLastAsRef(self, keyLen: int): (int?, cell?, bool)
261266
asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"
262267

263268
@pure
264-
fun dict.sDictGetLastAsRef(self, keyLen: int): (slice?, dict, bool)
269+
fun dict.sDictGetLastAsRef(self, keyLen: int): (slice?, cell?, bool)
265270
asm (-> 1 0 2) "DICTMAXREF" "NULLSWAPIFNOT2"
266271

267272

@@ -273,6 +278,10 @@ fun dict.iDictGetNext(self, keyLen: int, pivot: int): (int?, slice?, bool)
273278
fun dict.uDictGetNext(self, keyLen: int, pivot: int): (int?, slice?, bool)
274279
asm(pivot self keyLen -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"
275280

281+
@pure
282+
fun dict.sDictGetNext(self, keyLen: int, pivot: slice): (slice?, slice?, bool)
283+
asm(pivot self keyLen -> 1 0 2) "DICTGETNEXT" "NULLSWAPIFNOT2"
284+
276285
@pure
277286
fun dict.iDictGetNextOrEqual(self, keyLen: int, pivot: int): (int?, slice?, bool)
278287
asm(pivot self keyLen -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"
@@ -281,6 +290,10 @@ fun dict.iDictGetNextOrEqual(self, keyLen: int, pivot: int): (int?, slice?, bool
281290
fun dict.uDictGetNextOrEqual(self, keyLen: int, pivot: int): (int?, slice?, bool)
282291
asm(pivot self keyLen -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"
283292

293+
@pure
294+
fun dict.sDictGetNextOrEqual(self, keyLen: int, pivot: slice): (slice?, slice?, bool)
295+
asm(pivot self keyLen -> 1 0 2) "DICTGETNEXTEQ" "NULLSWAPIFNOT2"
296+
284297

285298
@pure
286299
fun dict.iDictGetPrev(self, keyLen: int, pivot: int): (int?, slice?, bool)
@@ -290,6 +303,10 @@ fun dict.iDictGetPrev(self, keyLen: int, pivot: int): (int?, slice?, bool)
290303
fun dict.uDictGetPrev(self, keyLen: int, pivot: int): (int?, slice?, bool)
291304
asm(pivot self keyLen -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"
292305

306+
@pure
307+
fun dict.sDictGetPrev(self, keyLen: int, pivot: slice): (slice?, slice?, bool)
308+
asm(pivot self keyLen -> 1 0 2) "DICTGETPREV" "NULLSWAPIFNOT2"
309+
293310
@pure
294311
fun dict.iDictGetPrevOrEqual(self, keyLen: int, pivot: int): (int?, slice?, bool)
295312
asm(pivot self keyLen -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"
@@ -298,9 +315,13 @@ fun dict.iDictGetPrevOrEqual(self, keyLen: int, pivot: int): (int?, slice?, bool
298315
fun dict.uDictGetPrevOrEqual(self, keyLen: int, pivot: int): (int?, slice?, bool)
299316
asm(pivot self keyLen -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"
300317

318+
@pure
319+
fun dict.sDictGetPrevOrEqual(self, keyLen: int, pivot: slice): (slice?, slice?, bool)
320+
asm(pivot self keyLen -> 1 0 2) "DICTGETPREVEQ" "NULLSWAPIFNOT2"
321+
301322

302323
/**
303-
Prefix dictionary primitives.
324+
Prefix dictionary primitives.
304325
*/
305326

306327
@pure

crypto/smartcont/tolk-stdlib/tvm-lowlevel.tolk

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// A part of standard library for Tolk
2-
tolk 1.0
2+
tolk 1.1
33

44
/// Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls.
55
/// The primitive returns the current value of `c3`.
@@ -14,12 +14,12 @@ fun getTvmRegisterC3(): continuation
1414
fun setTvmRegisterC3(c: continuation): void
1515
asm "c3 POP"
1616

17-
/// Transforms a `slice` [s] into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist.
17+
/// Transforms a slice into a simple ordinary continuation, with `c.code = s` and an empty stack and savelist.
1818
@pure
1919
fun transformSliceToContinuation(s: slice): continuation
2020
asm "BLESS"
2121

22-
/// Moves a variable or a value [x] to the top of the stack.
22+
/// Moves a variable to the top of the stack.
2323
@pure
2424
fun T.stackMoveToTop(mutate self): void
2525
asm "NOP"

tolk-tester/tests/assignment-tests.tolk

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,32 @@ fun test119(a: int, b: int) {
257257
return (l, c, d);
258258
}
259259

260+
struct Point {
261+
x: int
262+
y: int
263+
}
264+
265+
struct ROLine {
266+
readonly from: Point
267+
readonly to: Point
268+
}
269+
270+
fun eq<T>(v: T) { return v }
271+
272+
@method_id(120)
273+
fun test120() {
274+
val p: Point = { x: 10, y: 20 };
275+
eq(p).x = 30;
276+
return p;
277+
}
278+
279+
@method_id(121)
280+
fun test121(l: ROLine) {
281+
eq(l.from).x = eq(l.to).y;
282+
eq(l.from).y += 10;
283+
return l
284+
}
285+
260286

261287

262288
fun main(value: int, ) {
@@ -288,6 +314,8 @@ fun main(value: int, ) {
288314
@testcase | 117 | | [ 20 ]
289315
@testcase | 118 | 3 | 10 3 0 1
290316
@testcase | 119 | 1 2 | 2 2 4
317+
@testcase | 120 | | 10 20
318+
@testcase | 121 | null | (null)
291319

292320

293321
@fif_codegen

tolk-tester/tests/calls-tests.tolk

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,11 @@ fun test11(a: int, b: int) {
179179
return ((b < a), (b <= a), (b > a), (b >= a));
180180
}
181181

182-
fun main() {}
182+
fun main() {
183+
// mark used to codegen them
184+
cmp1; cmp2; cmp3; cmp4;
185+
leq1; leq2; leq3; leq4;
186+
}
183187

184188
/**
185189
@testcase | 101 | 10 | 10 15 100 12 3 110 300

tolk-tester/tests/cells-slices.tolk

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ fun endCell(b: builder): cell
1616
fun beginParse(c: cell): slice
1717
asm "CTOS";
1818

19+
@noinline
20+
fun triggerOverflowIntConst() {
21+
return beginCell().storeInt(10, 4)
22+
}
23+
24+
@noinline
25+
fun triggerOverflowUintConst() {
26+
return beginCell().storeUint(123, 6)
27+
}
28+
1929
@method_id(101)
2030
fun test1(): [int,int,int,int,int] {
2131
var b: builder = beginCell().storeUint(1, 32);
@@ -249,6 +259,7 @@ fun test18() {
249259
return (s.loadUint(14), s.loadInt(8), s.loadUint(4));
250260
}
251261

262+
@method_id(119)
252263
fun test19() {
253264
// numbers with potential overflow for STU are not joined, check via codegen
254265
var b = beginCell();
@@ -267,6 +278,7 @@ fun test20() {
267278
return (s.loadBool(), s.loadBool(), s.loadBool(), s.loadUint(8), s.loadBool(), s.loadCoins());
268279
}
269280

281+
@method_id(121)
270282
fun test21(s: slice) {
271283
// successive skipBits are also joined
272284
var x = 8;
@@ -433,6 +445,30 @@ fun test34(p: int, n: int) {
433445
return b;
434446
}
435447

448+
@method_id(135)
449+
fun test35(overflowMode: int) {
450+
try {
451+
val b: builder = match (overflowMode) {
452+
1 => triggerOverflowIntConst(),
453+
2 => triggerOverflowUintConst(),
454+
3 => beginCell().storeUint(10, -4),
455+
4 => beginCell().storeInt(100, 1),
456+
5 => beginCell().storeInt(1, 0),
457+
6 => beginCell().storeInt(115792089237316195423570985008687907853269984665640564039457584007913129639935, 256),
458+
7 => beginCell().storeInt(15, 4),
459+
8 => beginCell().storeUint(1<<170, 169),
460+
else => beginCell(),
461+
};
462+
return b.endCell().beginParse().loadUint(1) * 1000
463+
}
464+
catch (ex) { return ex }
465+
}
466+
467+
@method_id(136)
468+
fun test36() {
469+
return beginCell().storeInt(0, 0)
470+
}
471+
436472
fun main(): int {
437473
return 0;
438474
}
@@ -467,6 +503,15 @@ fun main(): int {
467503
@testcase | 132 | 0 | BC{00080000000a}
468504
@testcase | 133 | 0 | BC{00020a}
469505
@testcase | 134 | 0 8 | BC{00020a}
506+
@testcase | 135 | 1 | 5
507+
@testcase | 135 | 2 | 5
508+
@testcase | 135 | 3 | 5
509+
@testcase | 135 | 4 | 5
510+
@testcase | 135 | 5 | 5
511+
@testcase | 135 | 6 | 5
512+
@testcase | 135 | 7 | 5
513+
@testcase | 135 | 8 | 5
514+
@testcase | 136 | | BC{0000}
470515

471516
We test that consequtive storeInt/storeUint with constants are joined into a single number
472517

@@ -628,4 +673,32 @@ We test that consequtive storeInt/storeUint with constants are joined into a sin
628673
}>
629674
"""
630675

676+
@fif_codegen
677+
"""
678+
triggerOverflowIntConst() PROC:<{
679+
10 PUSHINT
680+
NEWC
681+
4 STI
682+
}>
683+
"""
684+
685+
@fif_codegen
686+
"""
687+
triggerOverflowUintConst() PROC:<{
688+
123 PUSHINT
689+
NEWC
690+
6 STU
691+
}>
692+
"""
693+
694+
@fif_codegen
695+
"""
696+
test36() PROC:<{
697+
0 PUSHINT
698+
NEWC
699+
OVER
700+
STIX
701+
}>
702+
"""
703+
631704
*/

0 commit comments

Comments
 (0)