Skip to content

Commit d9dba32

Browse files
committed
[Tolk] Get rid of ~tilda with mutate and self methods
This is a very big change. If FunC has `.methods()` and `~methods()`, Tolk has only dot, one and only way to call a `.method()`. A method may mutate an object, or may not. It's a behavioral and semantic difference from FunC. - `cs.loadInt(32)` modifies a slice and returns an integer - `b.storeInt(x, 32)` modifies a builder - `b = b.storeInt()` also works, since it not only modifies, but returns - chained methods also work, they return `self` - everything works exactly as expected, similar to JS - no runtime overhead, exactly same Fift instructions - custom methods are created with ease - tilda `~` does not exist in Tolk at all
1 parent 12ff28a commit d9dba32

File tree

85 files changed

+2703
-1958
lines changed

Some content is hidden

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

85 files changed

+2703
-1958
lines changed

crypto/smartcont/tolk-stdlib/common.tolk

Lines changed: 59 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@ fun createEmptyTuple(): tuple
1717
/// Appends a value to tuple, resulting in `Tuple t' = (x1, ..., xn, value)`.
1818
/// If its size exceeds 255, throws a type check exception.
1919
@pure
20-
fun tuplePush<X>(t: tuple, value: X): tuple
21-
asm "TPUSH";
22-
23-
@pure
24-
fun ~tuplePush<X>(t: tuple, value: X): (tuple, ())
20+
fun tuplePush<X>(mutate self: tuple, value: X): void
2521
asm "TPUSH";
2622

2723
/// Returns the first element of a non-empty tuple.
@@ -336,118 +332,109 @@ fun beginParse(c: cell): slice
336332
asm "CTOS";
337333

338334
/// Checks if slice is empty. If not, throws an exception.
339-
fun assertEndOfSlice(s: slice): void
335+
fun assertEndOfSlice(self: slice): void
340336
asm "ENDS";
341337

342338
/// Loads the next reference from the slice.
343339
@pure
344-
fun loadRef(s: slice): (slice, cell)
340+
fun loadRef(mutate self: slice): cell
345341
asm( -> 1 0) "LDREF";
346342

347343
/// Preloads the next reference from the slice.
348344
@pure
349-
fun preloadRef(s: slice): cell
345+
fun preloadRef(self: slice): cell
350346
asm "PLDREF";
351347

352348
/// Loads a signed [len]-bit integer from a slice.
353349
@pure
354-
fun loadInt(s: slice, len: int): (slice, int)
350+
fun loadInt(mutate self: slice, len: int): int
355351
builtin;
356352

357353
/// Loads an unsigned [len]-bit integer from a slice.
358354
@pure
359-
fun loadUint(s: slice, len: int): (slice, int)
355+
fun loadUint(mutate self: slice, len: int): int
360356
builtin;
361357

362358
/// Loads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate slice `s''`.
363359
@pure
364-
fun loadBits(s: slice, len: int): (slice, slice)
360+
fun loadBits(mutate self: slice, len: int): slice
365361
builtin;
366362

367363
/// Preloads a signed [len]-bit integer from a slice.
368364
@pure
369-
fun preloadInt(s: slice, len: int): int
365+
fun preloadInt(self: slice, len: int): int
370366
builtin;
371367

372368
/// Preloads an unsigned [len]-bit integer from a slice.
373369
@pure
374-
fun preloadUint(s: slice, len: int): int
370+
fun preloadUint(self: slice, len: int): int
375371
builtin;
376372

377373
/// Preloads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate slice.
378374
@pure
379-
fun preloadBits(s: slice, len: int): slice
375+
fun preloadBits(self: slice, len: int): slice
380376
builtin;
381377

382378
/// Loads serialized amount of Toncoins (any unsigned integer up to `2^120 - 1`).
383379
@pure
384-
fun loadCoins(s: slice): (slice, int)
380+
fun loadCoins(mutate self: slice): int
385381
asm( -> 1 0) "LDGRAMS";
386382

387383
/// Loads bool (-1 or 0) from a slice
388384
@pure
389-
fun loadBool(s: slice): (slice, int)
385+
fun loadBool(mutate self: slice): int
390386
asm( -> 1 0) "1 LDI";
391387

392388
/// Shifts a slice pointer to [len] bits forward, mutating the slice.
393389
@pure
394-
fun skipBits(s: slice, len: int): slice
395-
asm "SDSKIPFIRST"; // todo make mutating
396-
@pure
397-
fun ~skipBits(s: slice, len: int): (slice, ())
390+
fun skipBits(mutate self: slice, len: int): self
398391
asm "SDSKIPFIRST";
399392

400393
/// Returns the first `0 ≤ len ≤ 1023` bits of a slice.
401394
@pure
402-
fun getFirstBits(s: slice, len: int): slice
395+
fun getFirstBits(self: slice, len: int): slice
403396
asm "SDCUTFIRST";
404397

405398
/// Returns all but the last `0 ≤ len ≤ 1023` bits of a slice.
406399
@pure
407-
fun removeLastBits(s: slice, len: int): slice
408-
asm "SDSKIPLAST"; // todo make mutating
409-
@pure
410-
fun ~removeLastBits(s: slice, len: int): (slice, ())
400+
fun removeLastBits(mutate self: slice, len: int): self
411401
asm "SDSKIPLAST";
412402

413403
/// Returns the last `0 ≤ len ≤ 1023` bits of a slice.
414404
@pure
415-
fun getLastBits(s: slice, len: int): slice
405+
fun getLastBits(self: slice, len: int): slice
416406
asm "SDCUTLAST";
417407

418408
/// Loads a dictionary (TL HashMapE structure, represented as TVM cell) from a slice.
419409
/// Returns `null` if `nothing` constructor is used.
420410
@pure
421-
fun loadDict(s: slice): (slice, cell)
411+
fun loadDict(mutate self: slice): cell
422412
asm( -> 1 0) "LDDICT";
423413

424414
/// Preloads a dictionary (cell) from a slice.
425415
@pure
426-
fun preloadDict(s: slice): cell
416+
fun preloadDict(self: slice): cell
427417
asm "PLDDICT";
428418

429419
/// Loads a dictionary as [loadDict], but returns only the remainder of the slice.
430420
@pure
431-
fun skipDict(s: slice): slice
432-
asm "SKIPDICT"; // todo make mutating
433-
@pure
434-
fun ~skipDict(s: slice): (slice, ())
421+
fun skipDict(mutate self: slice): self
435422
asm "SKIPDICT";
436423

437424
/// Loads (Maybe ^Cell) from a slice.
438425
/// In other words, loads 1 bit: if it's true, loads the first ref, otherwise returns `null`.
439426
@pure
440-
fun loadMaybeRef(s: slice): (slice, cell)
427+
fun loadMaybeRef(mutate self: slice): cell
441428
asm( -> 1 0) "LDOPTREF";
442429

443430
/// Preloads (Maybe ^Cell) from a slice.
444431
@pure
445-
fun preloadMaybeRef(s: slice): cell
432+
fun preloadMaybeRef(self: slice): cell
446433
asm "PLDOPTREF";
447434

448435
/// Loads (Maybe ^Cell), but returns only the remainder of the slice.
449436
@pure
450-
fun ~skipMaybeRef(s: slice): (slice, ())
437+
fun skipMaybeRef(mutate self: slice): self
451438
asm "SKIPOPTREF";
452439

453440
/**
@@ -464,62 +451,60 @@ fun beginCell(): builder
464451

465452
/// Converts a builder into an ordinary `cell`.
466453
@pure
467-
fun endCell(b: builder): cell
454+
fun endCell(self: builder): cell
468455
asm "ENDC";
469456

470457
/// Stores a reference to a cell into a builder.
471458
@pure
472-
fun storeRef(b: builder, c: cell): builder
473-
asm(c b) "STREF";
459+
fun storeRef(mutate self: builder, c: cell): self
460+
asm(c self) "STREF";
474461

475462
/// Stores a signed [len]-bit integer into a builder (`0 ≤ len ≤ 257`).
476463
@pure
477-
fun storeInt(b: builder, x: int, len: int): builder
464+
fun storeInt(mutate self: builder, x: int, len: int): self
478465
builtin;
479466

480467
/// Stores an unsigned [len]-bit integer into a builder (`0 ≤ len ≤ 256`).
481468
@pure
482-
fun storeUint(b: builder, x: int, len: int): builder
469+
fun storeUint(mutate self: builder, x: int, len: int): self
483470
builtin;
484471

485472
/// Stores a slice into a builder.
486473
@pure
487-
fun storeSlice(b: builder, s: slice): builder
474+
fun storeSlice(mutate self: builder, s: slice): self
488475
asm "STSLICER";
489476

490477
/// Stores amount of Toncoins into a builder.
491478
@pure
492-
fun storeCoins(b: builder, x: int): builder
479+
fun storeCoins(mutate self: builder, x: int): self
493480
asm "STGRAMS";
494481

495482
/// Stores bool (-1 or 0) into a builder.
496483
/// Attention: true value is `-1`, not 1! If you pass `1` here, TVM will throw an exception.
497484
@pure
498-
fun storeBool(b: builder, x: int): builder
499-
asm(x b) "1 STI";
485+
fun storeBool(mutate self: builder, x: int): self
486+
asm(x self) "1 STI";
500487

501488
/// Stores dictionary (represented by TVM `cell` or `null`) into a builder.
502489
/// In other words, stores a `1`-bit and a reference to [c] if [c] is not `null` and `0`-bit otherwise.
503490
@pure
504-
fun storeDict(b: builder, c: cell): builder
505-
asm(c b) "STDICT";
491+
fun storeDict(mutate self: builder, c: cell): self
492+
asm(c self) "STDICT";
506493

507494
/// Stores (Maybe ^Cell) into a builder.
508495
/// In other words, if cell is `null`, store '0' bit; otherwise, store '1' and a ref to [c].
509496
@pure
510-
fun storeMaybeRef(b: builder, c: cell): builder
511-
asm(c b) "STOPTREF";
497+
fun storeMaybeRef(mutate self: builder, c: cell): self
498+
asm(c self) "STOPTREF";
512499

513500
/// Concatenates two builders.
514501
@pure
515-
fun storeBuilder(to: builder, from: builder): builder
502+
fun storeBuilder(mutate self: builder, from: builder): self
516503
asm "STBR";
517504

505+
/// Stores a slice representing TL addr_none$00 (two `0` bits).
518506
@pure
519-
fun storeAddressNone(b: builder): builder
520-
asm "0 PUSHINT" "SWAP" "2 STU";
521-
@pure
522-
fun ~storeAddressNone(b: builder): (builder, ())
507+
fun storeAddressNone(mutate self: builder): self
523508
asm "b{00} STSLICECONST";
524509

525510

@@ -529,47 +514,47 @@ fun ~storeAddressNone(b: builder): (builder, ())
529514

530515
/// Returns the number of references in a slice.
531516
@pure
532-
fun getRemainingRefsCount(s: slice): int
517+
fun getRemainingRefsCount(self: slice): int
533518
asm "SREFS";
534519

535520
/// Returns the number of data bits in a slice.
536521
@pure
537-
fun getRemainingBitsCount(s: slice): int
522+
fun getRemainingBitsCount(self: slice): int
538523
asm "SBITS";
539524

540525
/// Returns both the number of data bits and the number of references in a slice.
541526
@pure
542-
fun getRemainingBitsAndRefsCount(s: slice): (int, int)
527+
fun getRemainingBitsAndRefsCount(self: slice): (int, int)
543528
asm "SBITREFS";
544529

545530
/// Checks whether a slice is empty (i.e., contains no bits of data and no cell references).
546531
@pure
547-
fun isEndOfSlice(s: slice): int
532+
fun isEndOfSlice(self: slice): int
548533
asm "SEMPTY";
549534

550535
/// Checks whether a slice has no bits of data.
551536
@pure
552-
fun isEndOfSliceBits(s: slice): int
537+
fun isEndOfSliceBits(self: slice): int
553538
asm "SDEMPTY";
554539

555540
/// Checks whether a slice has no references.
556541
@pure
557-
fun isEndOfSliceRefs(s: slice): int
542+
fun isEndOfSliceRefs(self: slice): int
558543
asm "SREMPTY";
559544

560545
/// Checks whether data parts of two slices coinside.
561546
@pure
562-
fun isSliceBitsEqual(a: slice, b: slice): int
547+
fun isSliceBitsEqual(self: slice, b: slice): int
563548
asm "SDEQ";
564549

565550
/// Returns the number of cell references already stored in a builder.
566551
@pure
567-
fun getBuilderRefsCount(b: builder): int
552+
fun getBuilderRefsCount(self: builder): int
568553
asm "BREFS";
569554

570555
/// Returns the number of data bits already stored in a builder.
571556
@pure
572-
fun getBuilderBitsCount(b: builder): int
557+
fun getBuilderBitsCount(self: builder): int
573558
asm "BBITS";
574559

575560

@@ -613,8 +598,8 @@ fun getBuilderBitsCount(b: builder): int
613598
/// Loads from slice [s] the only prefix that is a valid `MsgAddress`,
614599
/// and returns both this prefix `s'` and the remainder `s''` of [s] as slices.
615600
@pure
616-
fun loadAddress(s: slice): (slice, slice)
617-
asm( -> 1 0) "LDMSGADDR"; // todo make mutating
601+
fun loadAddress(mutate self: slice): slice
602+
asm( -> 1 0) "LDMSGADDR";
618603

619604
/// Decomposes slice [s] containing a valid `MsgAddress` into a `tuple t` with separate fields of this `MsgAddress`.
620605
/// If [s] is not a valid `MsgAddress`, a cell deserialization exception is thrown.
@@ -686,7 +671,7 @@ const NON_BOUNCEABLE = 0x10;
686671

687672
/// Load msgFlags from incoming message body (4 bits).
688673
@pure
689-
fun loadMessageFlags(s: slice): (slice, int)
674+
fun loadMessageFlags(mutate self: slice): int
690675
asm( -> 1 0) "4 LDU";
691676

692677
/// Having msgFlags (4 bits), check that a message is bounced.
@@ -697,38 +682,34 @@ fun isMessageBounced(msgFlags: int): int
697682

698683
/// Skip 0xFFFFFFFF prefix (when a message is bounced).
699684
@pure
700-
fun ~skipBouncedPrefix(s: slice): (slice, ())
685+
fun skipBouncedPrefix(mutate self: slice): self
701686
asm "32 PUSHINT" "SDSKIPFIRST";
702687

703688
/// The guideline recommends to start the body of an internal message with uint32 `op` and uint64 `queryId`.
704689
@pure
705-
fun loadMessageOp(s: slice): (slice, int)
690+
fun loadMessageOp(mutate self: slice): int
706691
asm( -> 1 0) "32 LDU";
707692

708693
@pure
709-
fun ~skipMessageOp(s: slice): (slice, ())
694+
fun skipMessageOp(mutate self: slice): self
710695
asm "32 PUSHINT" "SDSKIPFIRST";
711696

712697
@pure
713-
fun storeMessageOp(b: builder, op: int): builder
714-
asm(op b) "32 STU";
715-
fun ~storeMessageOp(b: builder, op: int): (builder, ())
716-
asm(op b) "32 STU";
698+
fun storeMessageOp(mutate self: builder, op: int): self
699+
asm(op self) "32 STU";
717700

718701
/// The guideline recommends that uint64 `queryId` should follow uint32 `op`.
719702
@pure
720-
fun loadMessageQueryId(s: slice): (slice, int)
703+
fun loadMessageQueryId(mutate self: slice): int
721704
asm( -> 1 0) "64 LDU";
722705

723706
@pure
724-
fun ~skipMessageQueryId(s: slice): (slice, ())
707+
fun skipMessageQueryId(mutate self: slice): self
725708
asm "64 PUSHINT" "SDSKIPFIRST";
726709

727710
@pure
728-
fun storeMessageQueryId(b: builder, queryId: int): builder
729-
asm(queryId b) "64 STU";
730-
fun ~storeMessageQueryId(b: builder, queryId: int): (builder, ())
731-
asm(queryId b) "64 STU";
711+
fun storeMessageQueryId(mutate self: builder, queryId: int): self
712+
asm(queryId self) "64 STU";
732713

733714
/// SEND MODES - https://docs.ton.org/tvm.pdf page 137, SENDRAWMSG
734715

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ fun listSplit<X>(list: tuple): (X, tuple)
2424

2525
/// Extracts the tail and the head of lisp-style list.
2626
@pure
27-
fun ~listNext<X>(list: tuple): (tuple, X)
27+
fun listNext<X>(mutate self: tuple): X
2828
asm( -> 1 0) "UNCONS";
2929

3030
/// Returns the head of lisp-style list.

0 commit comments

Comments
 (0)