mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
[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
This commit is contained in:
parent
12ff28ac94
commit
d9dba320cc
85 changed files with 2710 additions and 1965 deletions
|
@ -1,121 +1,136 @@
|
|||
fun store_u32(b: builder, value: int): builder {
|
||||
return b.storeUint(value, 32);
|
||||
}
|
||||
fun ~store_u32(b: builder, value: int): (builder, ()) {
|
||||
return ~storeUint(b, value, 32);
|
||||
fun store_u32(mutate self: builder, value: int): self {
|
||||
return self.storeUint(value, 32);
|
||||
}
|
||||
|
||||
fun load_u32(cs: slice): (slice, int) {
|
||||
return cs.loadUint(32);
|
||||
fun load_u32(mutate self: slice): int {
|
||||
return self.loadUint(32);
|
||||
}
|
||||
|
||||
fun my_loadInt(s: slice, len: int): (slice, int)
|
||||
asm(s len -> 1 0) "LDIX"; // top is "value slice"
|
||||
fun my_storeInt(b: builder, x: int, len: int): builder
|
||||
asm(x b len) "STIX";
|
||||
fun ~my_storeInt(b: builder, x: int, len: int): (builder, ())
|
||||
asm(x b len) "STIX";
|
||||
fun myLoadInt(mutate self: slice, len: int): int
|
||||
asm(-> 1 0) "LDIX";
|
||||
fun myStoreInt(mutate self: builder, x: int, len: int): self
|
||||
asm(x self len) "STIX";
|
||||
|
||||
@method_id(101)
|
||||
fun test1(): [int,int,int,int,int] {
|
||||
var b: builder = beginCell().storeUint(1, 32);
|
||||
b = b.storeUint(2, 32);
|
||||
b~storeUint(3, 32);
|
||||
b.storeUint(3, 32);
|
||||
b = b.store_u32(4);
|
||||
b~store_u32(5);
|
||||
b.store_u32(5);
|
||||
|
||||
var cs: slice = b.endCell().beginParse();
|
||||
var (cs redef, one: int) = cs.loadUint(32);
|
||||
var (two: int, three: int) = (cs~loadUint(32), cs~load_u32());
|
||||
var (cs redef, four: int) = cs.load_u32();
|
||||
var five: int = cs~load_u32();
|
||||
var one: int = cs.loadUint(32);
|
||||
var (two: int, three: int) = (cs.loadUint(32), cs.load_u32());
|
||||
var four: int = cs.load_u32();
|
||||
var five: int = cs.load_u32();
|
||||
|
||||
return [one,two,three,four,five];
|
||||
}
|
||||
|
||||
@method_id(102)
|
||||
fun test2(): [int,int,int] {
|
||||
var b: builder = beginCell().my_storeInt(1, 32);
|
||||
b = b.my_storeInt(2, 32);
|
||||
b~my_storeInt(3, 32);
|
||||
var b: builder = beginCell().myStoreInt(1, 32);
|
||||
b = b.myStoreInt(2, 32);
|
||||
b.myStoreInt(3, 32);
|
||||
|
||||
var cs: slice = b.endCell().beginParse();
|
||||
var (cs redef, one: int) = cs.my_loadInt(32);
|
||||
var (two: int, three: int) = (cs~my_loadInt(32), cs~my_loadInt(32));
|
||||
var one: int = cs.myLoadInt(32);
|
||||
var (two: int, three: int) = (cs.myLoadInt(32), cs.myLoadInt(32));
|
||||
|
||||
return [one,two,three];
|
||||
}
|
||||
|
||||
@method_id(103)
|
||||
fun test3(ret: int): int {
|
||||
var (_, same: int) = beginCell().storeUint(ret,32).endCell().beginParse().loadUint(32);
|
||||
val same: int = beginCell().storeUint(ret,32).endCell().beginParse().loadUint(32);
|
||||
return same;
|
||||
}
|
||||
|
||||
@method_id(104)
|
||||
fun test4(): [int,int] {
|
||||
var b: builder = my_storeInt(beginCell(), 1, 32);
|
||||
b = storeInt(storeInt(b, 2, 32), 3, 32);
|
||||
var b: builder = beginCell().myStoreInt(1, 32);
|
||||
b = b.storeInt(2, 32).storeInt(3, 32);
|
||||
|
||||
var cs: slice = b.endCell().beginParse();
|
||||
var cs32: slice = cs.getFirstBits(32); // todo s.first_bits()~loadUint() doesn't work, 'lvalue expected'
|
||||
var (one, _, three) = (cs32~loadInt(32), cs~skipBits(64), cs~load_u32());
|
||||
var (one, _, three) = (cs.getFirstBits(32).loadUint(32), cs.skipBits(64), cs.load_u32());
|
||||
|
||||
return [one,three];
|
||||
}
|
||||
|
||||
@method_id(105)
|
||||
fun test5(): [int,int] {
|
||||
var cref: cell = endCell(store_u32(beginCell(), 105));
|
||||
var cref: cell = endCell(beginCell().store_u32(105));
|
||||
var c: cell = beginCell().storeRef(cref).storeRef(cref).store_u32(1).endCell();
|
||||
|
||||
var cs: slice = beginParse(c);
|
||||
// todo I want cs~loadRef().beginParse()~load_u32(), but 'lvalue expected'
|
||||
var ref1 = cs~loadRef().beginParse();
|
||||
var ref2 = cs~loadRef().beginParse();
|
||||
var sto5x2: int = ref1~load_u32() + ref2~loadUint(32);
|
||||
return [sto5x2, cs~load_u32()];
|
||||
}
|
||||
|
||||
|
||||
fun ~sumNumbersInSlice(s: slice): (slice, int) {
|
||||
var result = 0;
|
||||
while (!s.isEndOfSliceBits()) {
|
||||
result += s~loadUint(32);
|
||||
}
|
||||
return (s, result);
|
||||
var sto5x2: int = cs.loadRef().beginParse().load_u32() + cs.loadRef().beginParse().loadUint(32);
|
||||
return [sto5x2, cs.load_u32()];
|
||||
}
|
||||
|
||||
@method_id(106)
|
||||
fun test6() {
|
||||
var ref = beginCell().storeInt(100, 32).endCell();
|
||||
var s: slice = beginCell().storeInt(1, 32).storeInt(2, 32).storeRef(ref).endCell().beginParse();
|
||||
var result = (getRemainingBitsCount(s), s~sumNumbersInSlice(), getRemainingBitsCount(s), isEndOfSlice(s), isEndOfSliceBits(s), isEndOfSliceRefs(s));
|
||||
var ref2: cell = s~loadRef();
|
||||
var s2: slice = ref2.beginParse();
|
||||
s.assertEndOfSlice();
|
||||
return (result, s2~loadInt(32), s2.isEndOfSlice());
|
||||
return beginCell().storeUint(1, 32).storeUint(2, 32).storeUint(3, 32);
|
||||
}
|
||||
|
||||
@method_id(107)
|
||||
fun test7() {
|
||||
// since .store() methods now mutate, this piece of code works not as earlier (mutates uri_builder)
|
||||
var uri_builder = beginCell();
|
||||
var uri_slice = uri_builder.storeSlice(".json").endCell().beginParse();
|
||||
var image_slice = uri_builder.storeSlice(".png").endCell().beginParse();
|
||||
return (uri_builder.getBuilderBitsCount(), uri_slice.getRemainingBitsCount(), image_slice.getRemainingBitsCount());
|
||||
}
|
||||
|
||||
@method_id(108)
|
||||
fun test8() {
|
||||
var uri_builder = beginCell();
|
||||
var fresh = uri_builder;
|
||||
var uri_slice = fresh.storeSlice(".json").endCell().beginParse();
|
||||
var fresh redef = uri_builder;
|
||||
var image_slice = fresh.storeSlice(".png").endCell().beginParse();
|
||||
return (uri_builder.getBuilderBitsCount(), uri_slice.getRemainingBitsCount(), image_slice.getRemainingBitsCount());
|
||||
}
|
||||
|
||||
|
||||
fun sumNumbersInSlice(mutate self: slice): int {
|
||||
var result = 0;
|
||||
while (!self.isEndOfSliceBits()) {
|
||||
result += self.loadUint(32);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@method_id(110)
|
||||
fun test10() {
|
||||
var ref = beginCell().storeInt(100, 32).endCell();
|
||||
var s: slice = beginCell().storeInt(1, 32).storeInt(2, 32).storeRef(ref).endCell().beginParse();
|
||||
var result = (getRemainingBitsCount(s), s.sumNumbersInSlice(), getRemainingBitsCount(s), isEndOfSlice(s), isEndOfSliceBits(s), isEndOfSliceRefs(s));
|
||||
var ref2: cell = s.loadRef();
|
||||
var s2: slice = ref2.beginParse();
|
||||
s.assertEndOfSlice();
|
||||
return (result, s2.loadInt(32), s2.isEndOfSlice());
|
||||
}
|
||||
|
||||
@method_id(111)
|
||||
fun test11() {
|
||||
var s: slice = beginCell().storeInt(1, 32).storeInt(2, 32).storeInt(3, 32).storeInt(4, 32).storeInt(5, 32).storeInt(6, 32).storeInt(7, 32).endCell().beginParse();
|
||||
var size1 = getRemainingBitsCount(s);
|
||||
s~skipBits(32);
|
||||
s.skipBits(32);
|
||||
var s1: slice = s.getFirstBits(64);
|
||||
var n1 = s1~loadInt(32);
|
||||
var n1 = s1.loadInt(32);
|
||||
var size2 = getRemainingBitsCount(s);
|
||||
s~loadInt(32);
|
||||
s.loadInt(32);
|
||||
var size3 = getRemainingBitsCount(s);
|
||||
s~removeLastBits(32);
|
||||
s.removeLastBits(32);
|
||||
var size4 = getRemainingBitsCount(s);
|
||||
var n2 = s~loadInt(32);
|
||||
var n2 = s.loadInt(32);
|
||||
var size5 = getRemainingBitsCount(s);
|
||||
return (n1, n2, size1, size2, size3, size4, size5);
|
||||
}
|
||||
|
||||
@method_id(108)
|
||||
fun test108() {
|
||||
@method_id(112)
|
||||
fun test12() {
|
||||
var (result1, result2) = (0, 0);
|
||||
try {
|
||||
beginCell().storeRef(beginCell().endCell()).endCell().beginParse().assertEndOfSlice();
|
||||
|
@ -132,45 +147,45 @@ fun test108() {
|
|||
return (result1, result2);
|
||||
}
|
||||
|
||||
@method_id(109)
|
||||
fun test109() {
|
||||
@method_id(113)
|
||||
fun test13() {
|
||||
var ref2 = beginCell().storeInt(1, 32).endCell();
|
||||
var ref1 = beginCell().storeInt(1, 32).storeRef(ref2).endCell();
|
||||
var c = beginCell().storeInt(444, 32).storeRef(ref1).storeRef(ref1).storeRef(ref1).storeRef(ref2).storeInt(4, 32).endCell();
|
||||
var (n_cells1, n_bits1, n_refs1) = c.calculateCellSizeStrict(10);
|
||||
var s = c.beginParse();
|
||||
s~loadRef();
|
||||
s~loadRef();
|
||||
var n = s~loadInt(32);
|
||||
s.loadRef();
|
||||
s.loadRef();
|
||||
var n = s.loadInt(32);
|
||||
var (n_cells2, n_bits2, n_refs2) = s.calculateSliceSizeStrict(10);
|
||||
return ([n_cells1, n_bits1, n_refs1], [n_cells2, n_bits2, n_refs2], n);
|
||||
}
|
||||
|
||||
@method_id(110)
|
||||
@method_id(114)
|
||||
fun test110(x: int) {
|
||||
var s = beginCell().storeBool(x < 0).storeBool(0).storeBool(x).endCell().beginParse();
|
||||
return (s~loadBool(), s~loadBool(), s~loadBool());
|
||||
return (s.loadBool(), s.loadBool(), s.loadBool());
|
||||
}
|
||||
|
||||
@method_id(111)
|
||||
@method_id(115)
|
||||
fun test111() {
|
||||
var s = beginCell().storeMessageOp(123).storeMessageQueryId(456)
|
||||
.storeAddressNone().storeAddressNone()
|
||||
.storeUint(0, 32)
|
||||
.storeUint(123, 32).storeUint(456, 64).storeUint(789, 64)
|
||||
.endCell().beginParse();
|
||||
var op1 = s~loadUint(32);
|
||||
var q1 = s~loadUint(64);
|
||||
var op1 = s.loadUint(32);
|
||||
var q1 = s.loadUint(64);
|
||||
if (s.addressIsNone()) {
|
||||
s~skipBits(2);
|
||||
s.skipBits(2);
|
||||
}
|
||||
if (s~loadBool() == 0) {
|
||||
assert(s~loadBool() == 0) throw 444;
|
||||
s~skipBits(32);
|
||||
if (s.loadBool() == 0) {
|
||||
assert(s.loadBool() == 0) throw 444;
|
||||
s.skipBouncedPrefix();
|
||||
}
|
||||
var op2 = s~loadMessageOp();
|
||||
var q2 = s~loadMessageQueryId();
|
||||
s~skipBits(64);
|
||||
var op2 = s.loadMessageOp();
|
||||
var q2 = s.loadMessageQueryId();
|
||||
s.skipBits(64);
|
||||
s.assertEndOfSlice();
|
||||
assert(isMessageBounced(0x001)) throw 444;
|
||||
return (op1, q1, op2, q2);
|
||||
|
@ -186,11 +201,31 @@ fun main(): int {
|
|||
@testcase | 103 | 103 | 103
|
||||
@testcase | 104 | | [ 1 3 ]
|
||||
@testcase | 105 | | [ 210 1 ]
|
||||
@testcase | 106 | | 64 3 0 0 -1 0 100 -1
|
||||
@testcase | 107 | | 2 3 224 192 160 128 96
|
||||
@testcase | 108 | | 9 100
|
||||
@testcase | 109 | | [ 3 128 5 ] [ 2 96 3 ] 444
|
||||
@testcase | 110 | -1 | -1 0 -1
|
||||
@testcase | 110 | 0 | 0 0 0
|
||||
@testcase | 111 | | 123 456 123 456
|
||||
@testcase | 107 | | 72 40 72
|
||||
@testcase | 108 | | 0 40 32
|
||||
@testcase | 110 | | 64 3 0 0 -1 0 100 -1
|
||||
@testcase | 111 | | 2 3 224 192 160 128 96
|
||||
@testcase | 112 | | 9 100
|
||||
@testcase | 113 | | [ 3 128 5 ] [ 2 96 3 ] 444
|
||||
@testcase | 114 | -1 | -1 0 -1
|
||||
@testcase | 114 | 0 | 0 0 0
|
||||
@testcase | 115 | | 123 456 123 456
|
||||
|
||||
Note, that since 'compute-asm-ltr' became on be default, chaining methods codegen is not quite optimal.
|
||||
@fif_codegen
|
||||
"""
|
||||
test6 PROC:<{
|
||||
//
|
||||
NEWC // _1
|
||||
1 PUSHINT // _1 _2=1
|
||||
SWAP // _2=1 _1
|
||||
32 STU // _0
|
||||
2 PUSHINT // _0 _6=2
|
||||
SWAP // _6=2 _0
|
||||
32 STU // _0
|
||||
3 PUSHINT // _0 _10=3
|
||||
SWAP // _10=3 _0
|
||||
32 STU // _0
|
||||
}>
|
||||
"""
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue