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

[Tolk] Completely rework stdlib: multiple files and renaming

- split stdlib.tolk into multiple files (tolk-stdlib/ folder)
  (the "core" common.tolk is auto-imported, the rest are
  needed to be explicitly imported like "@stdlib/tvm-dicts.tolk")
- all functions were renamed to long and clear names
- new naming is camelCase
This commit is contained in:
tolk-vm 2024-10-31 11:16:19 +04:00
parent e2edadba92
commit 12ff28ac94
No known key found for this signature in database
GPG key ID: 7905DD7FE0324B12
48 changed files with 2966 additions and 2458 deletions

View file

@ -1,3 +1,5 @@
fun pair_first<X, Y>(p: [X, Y]): X asm "FIRST";
fun one(dummy: tuple) {
return 1;
}
@ -30,6 +32,29 @@ fun test88(x: int) {
}
}
@method_id(89)
fun test89(last: int) {
var t: tuple = createEmptyTuple();
t~tuplePush(1);
t~tuplePush(2);
t~tuplePush(3);
t~tuplePush(last);
return (t.tupleAt(0), t.tupleAt(t.tupleSize() - 1), t.tupleFirst(), t.tupleLast());
}
@method_id(93)
fun testStartBalanceCodegen1() {
var t = getMyOriginalBalanceWithExtraCurrencies();
var first = t.pair_first();
return first;
}
@method_id(94)
fun testStartBalanceCodegen2() {
var first = getMyOriginalBalance();
return first;
}
/**
method_id | in | out
@testcase | 0 | 101 15 | 100 1
@ -39,4 +64,24 @@ fun test88(x: int) {
@testcase | 0 | 100 10 | 100 0
@testcase | 88 | 5 | 234
@testcase | 88 | 50 | 0
@testcase | 89 | 4 | 1 4 1 4
@fif_codegen
"""
testStartBalanceCodegen1 PROC:<{
//
BALANCE // t
FIRST // first
}>
"""
@fif_codegen
"""
testStartBalanceCodegen2 PROC:<{
//
BALANCE
FIRST // first
}>
"""
*/

View file

@ -4,7 +4,7 @@ fun f(a: int, b: int, c: int, d: int, e: int, f: int): (int, int) {
return (Dx/D,Dy/D);
};;;;
fun mulDivR(x: int, y: int, z: int): int { return muldivr(x, y, z); }
fun mulDivR(x: int, y: int, z: int): int { return mulDivRound(x, y, z); }
fun calc_phi(): int {
var n = 1;

View file

@ -4,8 +4,8 @@ asm "NIL";
@pure
fun tpush2<X>(t: tuple, x: X): (tuple, ())
asm "TPUSH";
fun emptyTuple(): tuple { return empty_tuple2(); }
fun tuplePush<X>(t: tuple, value: X): (tuple, ()) { return tpush2(t, value); }
fun myEmptyTuple(): tuple { return empty_tuple2(); }
fun myTuplePush<X>(t: tuple, value: X): (tuple, ()) { return tpush2(t, value); }
@pure
fun asm_func_1(x: int, y: int, z: int): tuple
@ -31,7 +31,7 @@ fun asmFuncModify(a: tuple, b: int, c: int): (tuple, ()) { return asm_func_modif
global t: tuple;
fun foo(x: int): int {
t~tuplePush(x);
t~myTuplePush(x);
return x * 10;
}
@ -44,7 +44,7 @@ fun test_old_1(): (tuple, tuple) {
@method_id(12)
fun test_old_2(): (tuple, tuple) {
t = emptyTuple();
t = myEmptyTuple();
var t2: tuple = asm_func_2(foo(11), foo(22), foo(33));
return (t, t2);
}
@ -58,7 +58,7 @@ fun test_old_3(): (tuple, tuple) {
@method_id(14)
fun test_old_4(): (tuple, tuple) {
t = emptyTuple();
t = myEmptyTuple();
var t2: tuple = empty_tuple2();
// This actually computes left-to-right even without compute-asm-ltr
t2 = asm_func_4(foo(11), (foo(22), (foo(33), foo(44))), foo(55));

View file

@ -7,40 +7,45 @@
// without affecting performance and even bytecode hashes.
// This works with ~functions also. And even works with wrappers of wrappers.
// Moreover, such wrappers can reorder input parameters, see a separate test camel2.tolk.
import "@stdlib/tvm-dicts"
fun myBeginCell(): builder { return begin_cell(); }
fun myEndCell(b: builder): cell { return end_cell(b); }
fun myStoreRef(b: builder, c: cell): builder { return store_ref(b, c); }
fun myStoreUint(b: builder, i: int, bw: int): builder { return store_uint(b, i, bw); }
fun myBeginCell(): builder { return beginCell(); }
fun myEndCell(b: builder): cell { return endCell(b); }
fun myStoreRef(b: builder, c: cell): builder { return storeRef(b, c); }
fun myStoreUint(b: builder, i: int, bw: int): builder { return storeUint(b, i, bw); }
// 'inline' is not needed actually, but if it exists, it's just ignored
@inline
@pure
fun myBeginParse(c: cell): slice { return begin_parse(c); }
fun myBeginParse(c: cell): slice { return beginParse(c); }
@inline
@pure
fun mySkipBits(s: slice, len: int): slice { return skip_bits(s, len); }
fun mySkipBits(s: slice, len: int): slice { return skipBits(s, len); }
@inline
@pure
fun ~mySkipBits(s: slice, len: int): (slice, ()) { return ~skip_bits(s, len); }
fun ~mySkipBits(s: slice, len: int): (slice, ()) { return ~skipBits(s, len); }
@inline
@pure
fun ~myLoadUint(s: slice, len: int): (slice, int) { return load_uint(s, len); }
fun ~myLoadUint(s: slice, len: int): (slice, int) { return loadUint(s, len); }
fun myComputeDataSize(c: cell, maxCells: int): (int, int, int) { return compute_data_size(c, maxCells); }
fun myComputeDataSize(c: cell, maxCells: int): (int, int, int) { return calculateCellSizeStrict(c, maxCells); }
fun dict__new(): cell { return new_dict(); }
fun dict__iset(dict: cell, keyLen: int, index: int, value: slice): cell { return idict_set(dict, keyLen, index, value); }
fun ~dict__iset(dict: cell, keyLen: int, index: int, value: slice): (cell, ()) { return ~idict_set(dict, keyLen, index, value); }
fun dict__tryIGet(dict: cell, keyLen: int, index: int): (slice, int) { return idict_get?(dict, keyLen, index); }
fun dict__tryIGetMin(dict: cell, keyLen: int): (int, slice, int) { return idict_get_min?(dict, keyLen); }
fun dict__new(): cell { return createEmptyDict(); }
fun dict__iset(dict: cell, keyLen: int, index: int, value: slice): cell { return iDictSet(dict, keyLen, index, value); }
fun ~dict__iset(dict: cell, keyLen: int, index: int, value: slice): (cell, ()) { return ~iDictSet(dict, keyLen, index, value); }
fun dict__tryIGet(dict: cell, keyLen: int, index: int): (slice, int) { return iDictGet(dict, keyLen, index); }
fun dict__tryIGetMin(dict: cell, keyLen: int): (int, slice, int) { return iDictGetFirst(dict, keyLen); }
fun myEmptyTuple(): tuple { return empty_tuple(); }
@pure
fun triple_second<X, Y, Z>(p: [X, Y, Z]): Y
asm "SECOND";
fun myEmptyTuple(): tuple { return createEmptyTuple(); }
fun emptyTuple1(): tuple { return myEmptyTuple(); }
fun emptyTuple11(): tuple { return emptyTuple1(); }
fun myTuplePush<X>(t: tuple, value: X): tuple { return tpush(t, value); }
fun ~myTuplePush<X>(t: tuple, value: X): (tuple, ()) { return ~tpush(t, value); }
fun myTupleAt<X>(t: tuple, index: int): X { return at(t, index); }
fun myTuplePush<X>(t: tuple, value: X): tuple { return tuplePush(t, value); }
fun ~myTuplePush<X>(t: tuple, value: X): (tuple, ()) { return ~tuplePush(t, value); }
fun myTupleAt<X>(t: tuple, index: int): X { return tupleAt(t, index); }
fun tripleSecond<X1, Y2, Z3>(p: [X1, Y2, Z3]): Y2 { return triple_second(p); }
@pure
fun nullValue<X>(): X

View file

@ -5,15 +5,15 @@
// But swapping arguments may sometimes lead to bytecode changes (see test2),
// both with compute-asm-ltr and without it.
fun myBeginCell(): builder { return begin_cell(); }
fun myEndCell(b: builder): cell { return end_cell(b); }
fun myStoreRef1(b: builder, c: cell): builder { return store_ref(b, c); }
fun myStoreRef2(c: cell, b: builder): builder { return store_ref(b, c); }
fun myStoreUint1(b: builder, x: int, bw: int): builder { return store_uint(b, x, bw); }
fun myStoreUint2(b: builder, bw: int, x: int): builder { return store_uint(b, x, bw); }
fun myBeginCell(): builder { return beginCell(); }
fun myEndCell(b: builder): cell { return endCell(b); }
fun myStoreRef1(b: builder, c: cell): builder { return storeRef(b, c); }
fun myStoreRef2(c: cell, b: builder): builder { return storeRef(b, c); }
fun myStoreUint1(b: builder, x: int, bw: int): builder { return storeUint(b, x, bw); }
fun myStoreUint2(b: builder, bw: int, x: int): builder { return storeUint(b, x, bw); }
fun computeDataSize1(c: cell, maxCells: int): (int, int, int) { return compute_data_size(c, maxCells); }
fun computeDataSize2(maxCells: int, c: cell): (int, int, int) { return compute_data_size(c, maxCells); }
fun computeDataSize1(c: cell, maxCells: int): (int, int, int) { return calculateCellSizeStrict(c, maxCells); }
fun computeDataSize2(maxCells: int, c: cell): (int, int, int) { return calculateCellSizeStrict(c, maxCells); }
fun fake(a: int, b: int, c: int): void
asm "DROP DROP DROP";
@ -48,24 +48,24 @@ fun test2(): (int, int, int) {
fun test3(): (int, int, int) {
var x: int = 1;
var y: int = 1;
var to_be_ref: cell = begin_cell().end_cell();
var in_c: builder = begin_cell().store_uint(123, 8);
in_c = store_ref(in_c, to_be_ref);
var (a, b, c) = compute_data_size(in_c.end_cell(), 10);
var to_be_ref: cell = beginCell().endCell();
var in_c: builder = beginCell().storeUint(123, 8);
in_c = storeRef(in_c, to_be_ref);
var (a, b, c) = calculateCellSizeStrict(in_c.endCell(), 10);
return (a, b + x, c + y);
}
fun beginCell1(): builder { return begin_cell(); }
fun beginCell1(): builder { return beginCell(); }
fun beginCell11(): builder { return beginCell1(); }
fun beginCell111(): builder { return beginCell11(); }
fun endCell1(b: builder): cell { return end_cell(b); }
fun endCell1(b: builder): cell { return endCell(b); }
fun endCell11(b: builder): cell { return endCell1(b); }
fun beginParse1(c: cell): slice { return begin_parse(c); }
fun beginParse1(c: cell): slice { return beginParse(c); }
fun beginParse11(c: cell): slice { return beginParse1(c); }
fun storeInt1(b: builder, bw: int, x: int): builder { return store_int(b, x, bw); }
fun storeInt1(b: builder, bw: int, x: int): builder { return storeInt(b, x, bw); }
fun storeInt11(bw: int, x: int, b: builder): builder { return storeInt1(b, bw, x); }
fun storeInt111(b: builder, x: int, bw: int): builder { return storeInt11(bw, x, b); }

View file

@ -4,17 +4,17 @@
// (save to a variable, return from a function, etc.)
// it also works, since a function becomes codegenerated (though direct calls are expectedly inlined).
fun myBeginCell(): builder { return begin_cell(); }
fun myEndCell(b: builder): cell { return end_cell(b); }
fun myStoreRef(b: builder, c: cell): builder { return store_ref(b, c); }
fun myStoreUint3(i: int, bw: int, b: builder): builder { return store_uint(b, i, bw); }
fun myBeginCell(): builder { return beginCell(); }
fun myEndCell(b: builder): cell { return endCell(b); }
fun myStoreRef(b: builder, c: cell): builder { return storeRef(b, c); }
fun myStoreUint3(i: int, bw: int, b: builder): builder { return storeUint(b, i, bw); }
fun computeDataSize2(maxCells: int, c: cell): (int, int, int) { return compute_data_size(c, maxCells); }
fun computeDataSize2(maxCells: int, c: cell): (int, int, int) { return calculateCellSizeStrict(c, maxCells); }
fun myEmptyTuple(): tuple { return empty_tuple(); }
fun myTuplePush<X>(t: tuple, value: X): tuple { return tpush(t, value); }
fun ~myTuplePush<X>(t: tuple, value: X): (tuple, ()) { return ~tpush(t, value); }
fun tupleGetFirst<X>(t: tuple): X { return first(t); }
fun myEmptyTuple(): tuple { return createEmptyTuple(); }
fun myTuplePush<X>(t: tuple, value: X): tuple { return tuplePush(t, value); }
fun ~myTuplePush<X>(t: tuple, value: X): (tuple, ()) { return ~tuplePush(t, value); }
fun myTupleGetFirst<X>(t: tuple): X { return tupleFirst(t); }
@inline
@ -32,7 +32,7 @@ fun test1(): (int, int, int) {
var t: tuple = myEmptyTuple();
t~myTuplePush(myStoreRef);
var refStorer = tupleGetFirst(t);
var refStorer = myTupleGetFirst(t);
var x: int = 1;
var y: int = 1;

View file

@ -1,7 +1,7 @@
// Here we test that a just-return function is not a valid wrapper, it will not be inlined.
// (doesn't use all arguments, has different pureness, has method_id, etc.)
fun myStoreUint(b: builder, x: int, unused: int): builder { return store_uint(b, x, x); }
fun myStoreUint(b: builder, x: int, unused: int): builder { return storeUint(b, x, x); }
fun throwIf(excNo: int, cond: int) { assert(!cond) throw excNo; }
fun initial1(x: auto) { return x; }
@ -17,11 +17,11 @@ fun postpone_elections(): int {
}
fun setAndGetData(ret: int): int {
var c: cell = begin_cell().store_uint(ret, 8).end_cell();
set_data(c);
var s: slice = get_data().begin_parse();
var c: cell = beginCell().storeUint(ret, 8).endCell();
setContractData(c);
var s: slice = getContractData().beginParse();
throwIf(101, 0);
return s~load_uint(8);
return s~loadUint(8);
}
fun setAndGetDataWrapper(ret: int): int {
@ -30,9 +30,9 @@ fun setAndGetDataWrapper(ret: int): int {
@method_id(101)
fun test1(): int {
var c: cell = begin_cell().myStoreUint(32, 10000000).end_cell();
var s: slice = c.begin_parse();
return s~load_uint(32);
var c: cell = beginCell().myStoreUint(32, 10000000).endCell();
var s: slice = c.beginParse();
return s~loadUint(32);
}
get fun test2(ret: int): int {
@ -47,13 +47,13 @@ fun test3(): int {
global t: tuple;
fun foo(x: int): int {
t~tpush(x);
t~tuplePush(x);
return x * 10;
}
@method_id(104)
fun test4(): (tuple, tuple) {
t = empty_tuple();
t = createEmptyTuple();
var t2: tuple = asmFunc4(foo(11), (foo(22), (foo(33), foo(44))), foo(55));
return (t, t2);
}

View file

@ -1,32 +1,32 @@
fun store_u32(b: builder, value: int): builder {
return b.store_uint(value, 32);
return b.storeUint(value, 32);
}
fun ~store_u32(b: builder, value: int): (builder, ()) {
return ~store_uint(b, value, 32);
return ~storeUint(b, value, 32);
}
fun load_u32(cs: slice): (slice, int) {
return cs.load_uint(32);
return cs.loadUint(32);
}
fun my_load_int(s: slice, len: int): (slice, int)
fun my_loadInt(s: slice, len: int): (slice, int)
asm(s len -> 1 0) "LDIX"; // top is "value slice"
fun my_store_int(b: builder, x: int, len: int): builder
fun my_storeInt(b: builder, x: int, len: int): builder
asm(x b len) "STIX";
fun ~my_store_int(b: builder, x: int, len: int): (builder, ())
fun ~my_storeInt(b: builder, x: int, len: int): (builder, ())
asm(x b len) "STIX";
@method_id(101)
fun test1(): [int,int,int,int,int] {
var b: builder = begin_cell().store_uint(1, 32);
b = b.store_uint(2, 32);
b~store_uint(3, 32);
var b: builder = beginCell().storeUint(1, 32);
b = b.storeUint(2, 32);
b~storeUint(3, 32);
b = b.store_u32(4);
b~store_u32(5);
var cs: slice = b.end_cell().begin_parse();
var (cs redef, one: int) = cs.load_uint(32);
var (two: int, three: int) = (cs~load_uint(32), cs~load_u32());
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();
@ -35,82 +35,82 @@ fun test1(): [int,int,int,int,int] {
@method_id(102)
fun test2(): [int,int,int] {
var b: builder = begin_cell().my_store_int(1, 32);
b = b.my_store_int(2, 32);
b~my_store_int(3, 32);
var b: builder = beginCell().my_storeInt(1, 32);
b = b.my_storeInt(2, 32);
b~my_storeInt(3, 32);
var cs: slice = b.end_cell().begin_parse();
var (cs redef, one: int) = cs.my_load_int(32);
var (two: int, three: int) = (cs~my_load_int(32), cs~my_load_int(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));
return [one,two,three];
}
@method_id(103)
fun test3(ret: int): int {
var (_, same: int) = begin_cell().store_uint(ret,32).end_cell().begin_parse().load_uint(32);
var (_, same: int) = beginCell().storeUint(ret,32).endCell().beginParse().loadUint(32);
return same;
}
@method_id(104)
fun test4(): [int,int] {
var b: builder = my_store_int(begin_cell(), 1, 32);
b = store_int(store_int(b, 2, 32), 3, 32);
var b: builder = my_storeInt(beginCell(), 1, 32);
b = storeInt(storeInt(b, 2, 32), 3, 32);
var cs: slice = b.end_cell().begin_parse();
var cs32: slice = cs.first_bits(32); // todo s.first_bits()~load_uint() doesn't work, 'lvalue expected'
var (one, _, three) = (cs32~load_int(32), cs~skip_bits(64), cs~load_u32());
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());
return [one,three];
}
@method_id(105)
fun test5(): [int,int] {
var cref: cell = end_cell(store_u32(begin_cell(), 105));
var c: cell = begin_cell().store_ref(cref).store_ref(cref).store_u32(1).end_cell();
var cref: cell = endCell(store_u32(beginCell(), 105));
var c: cell = beginCell().storeRef(cref).storeRef(cref).store_u32(1).endCell();
var cs: slice = begin_parse(c);
// todo I want cs~load_ref().begin_parse()~load_u32(), but 'lvalue expected'
var ref1 = cs~load_ref().begin_parse();
var ref2 = cs~load_ref().begin_parse();
var sto5x2: int = ref1~load_u32() + ref2~load_uint(32);
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 (!slice_data_empty?(s)) {
result += s~load_uint(32);
while (!s.isEndOfSliceBits()) {
result += s~loadUint(32);
}
return (s, result);
}
@method_id(106)
fun test6() {
var ref = begin_cell().store_int(100, 32).end_cell();
var s: slice = begin_cell().store_int(1, 32).store_int(2, 32).store_ref(ref).end_cell().begin_parse();
var result = (slice_bits(s), s~sumNumbersInSlice(), slice_bits(s), slice_empty?(s), slice_data_empty?(s), slice_refs_empty?(s));
var ref2: cell = s~load_ref();
var s2: slice = ref2.begin_parse();
s.end_parse();
return (result, s2~load_int(32), s2.slice_empty?());
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(107)
fun test7() {
var s: slice = begin_cell().store_int(1, 32).store_int(2, 32).store_int(3, 32).store_int(4, 32).store_int(5, 32).store_int(6, 32).store_int(7, 32).end_cell().begin_parse();
var size1 = slice_bits(s);
s~skip_bits(32);
var s1: slice = s.first_bits(64);
var n1 = s1~load_int(32);
var size2 = slice_bits(s);
s~load_int(32);
var size3 = slice_bits(s);
s~skip_last_bits(32);
var size4 = slice_bits(s);
var n2 = s~load_int(32);
var size5 = slice_bits(s);
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);
var s1: slice = s.getFirstBits(64);
var n1 = s1~loadInt(32);
var size2 = getRemainingBitsCount(s);
s~loadInt(32);
var size3 = getRemainingBitsCount(s);
s~removeLastBits(32);
var size4 = getRemainingBitsCount(s);
var n2 = s~loadInt(32);
var size5 = getRemainingBitsCount(s);
return (n1, n2, size1, size2, size3, size4, size5);
}
@ -118,13 +118,13 @@ fun test7() {
fun test108() {
var (result1, result2) = (0, 0);
try {
begin_cell().store_ref(begin_cell().end_cell()).end_cell().begin_parse().end_parse();
beginCell().storeRef(beginCell().endCell()).endCell().beginParse().assertEndOfSlice();
result1 = 100;
} catch (code) {
result1 = code;
}
try {
begin_cell().end_cell().begin_parse().end_parse();
beginCell().endCell().beginParse().assertEndOfSlice();
result2 = 100;
} catch (code) {
result2 = code;
@ -134,18 +134,48 @@ fun test108() {
@method_id(109)
fun test109() {
var ref2 = begin_cell().store_int(1, 32).end_cell();
var ref1 = begin_cell().store_int(1, 32).store_ref(ref2).end_cell();
var c = begin_cell().store_int(444, 32).store_ref(ref1).store_ref(ref1).store_ref(ref1).store_ref(ref2).store_int(4, 32).end_cell();
var (n_cells1, n_bits1, n_refs1) = c.compute_data_size(10);
var s = c.begin_parse();
s~load_ref();
s~load_ref();
var n = s~load_int(32);
var (n_cells2, n_bits2, n_refs2) = s.slice_compute_data_size(10);
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);
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)
fun test110(x: int) {
var s = beginCell().storeBool(x < 0).storeBool(0).storeBool(x).endCell().beginParse();
return (s~loadBool(), s~loadBool(), s~loadBool());
}
@method_id(111)
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);
if (s.addressIsNone()) {
s~skipBits(2);
}
if (s~loadBool() == 0) {
assert(s~loadBool() == 0) throw 444;
s~skipBits(32);
}
var op2 = s~loadMessageOp();
var q2 = s~loadMessageQueryId();
s~skipBits(64);
s.assertEndOfSlice();
assert(isMessageBounced(0x001)) throw 444;
return (op1, q1, op2, q2);
}
fun main(): int {
return 0;
}
@ -160,4 +190,7 @@ fun main(): int {
@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
*/

View file

@ -43,7 +43,7 @@ asm "SDEQ";
fun stslicer(b: builder, s: slice): builder
asm "STSLICER";
fun storeUint(b: builder, x: int, len: int): builder { return store_uint(b, x, len); }
fun myStoreUint(b: builder, x: int, len: int): builder { return storeUint(b, x, len); }
fun endSlice(b: builder): slice { return endcs(b); }
fun main() {
@ -59,9 +59,9 @@ fun main() {
var s2: slice = sget2();
var s3: slice = newc().stslicer(str1).stslicer(str2r).endcs();
assert(sdeq(s1, newc().storeUint(str1int, 12 * nibbles).endcs())) throw int111;
assert(sdeq(s2, newc().store_uint(str2int, 6 * nibbles).endSlice())) throw 112;
assert(sdeq(s3, newc().store_uint(0x636f6e737431AABBCC, 18 * nibbles).endcs())) throw 113;
assert(sdeq(s1, newc().myStoreUint(str1int, 12 * nibbles).endcs())) throw int111;
assert(sdeq(s2, newc().storeUint(str2int, 6 * nibbles).endSlice())) throw 112;
assert(sdeq(s3, newc().storeUint(0x636f6e737431AABBCC, 18 * nibbles).endcs())) throw 113;
var i4: int = iget240();
assert(i4 == 240) throw ((104));

View file

@ -0,0 +1,106 @@
import "@stdlib/tvm-dicts"
fun ~addIntToIDict(iDict: cell, key: int, number: int): (cell, ()) {
iDict~iDictSetBuilder(32, key, beginCell().storeInt(number, 32));
return (iDict, ());
}
fun calculateDictLen(d: cell) {
var len = 0;
var (k, v, f) = d.uDictGetFirst(32);
while (f) {
len += 1;
(k, v, f) = d.uDictGetNext(32, k);
}
return len;
}
fun ~loadTwoDigitNumberFromSlice(s: slice): (slice, int) {
var n1 = s~loadInt(8);
var n2 = s~loadInt(8);
return (s, (n1 - 48) * 10 + (n2 - 48));
}
@method_id(101)
fun test101(getK1: int, getK2: int, getK3: int) {
var dict = createEmptyDict();
dict~uDictSetBuilder(32, 1, beginCell().storeUint(1, 32));
var (old1: slice, found1) = dict~uDictSetAndGet(32, getK1, beginCell().storeUint(2, 32).endCell().beginParse());
var (old2: slice, found2) = dict~uDictSetAndGet(32, getK2, beginCell().storeUint(3, 32).endCell().beginParse());
var (cur3: slice, found3) = dict.uDictGet(32, getK3);
return (
found1 ? old1~loadUint(32) : -1,
found2 ? old2~loadUint(32) : -1,
found3 ? cur3~loadUint(32) : -1
);
}
@method_id(102)
fun test102() {
var dict = createEmptyDict();
dict~addIntToIDict(2, 102);
dict~addIntToIDict(1, 101);
dict~addIntToIDict(4, 104);
dict~addIntToIDict(3, 103);
var deleted = createEmptyTuple();
var shouldBreak = false;
while (!shouldBreak) {
var (kDel, kVal, wasDel) = dict~iDictDeleteLastAndGet(32);
if (wasDel) {
deleted~tuplePush([kDel, kVal~loadInt(32)]);
} else {
shouldBreak = true;
}
}
return deleted;
}
@method_id(103)
fun test103() {
var dict = createEmptyDict();
dict~uDictSetBuilderIfNotExists(32, 1,beginCell().storeInt(1, 32));
dict~uDictSetBuilderIfNotExists(32, 1,beginCell().storeInt(1, 32));
var len1 = calculateDictLen(dict);
dict~uDictSetBuilderIfExists(32, 2,beginCell().storeInt(1, 32));
dict~uDictSetBuilderIfExists(32, 2,beginCell().storeInt(1, 32));
var len2 = calculateDictLen(dict);
dict~uDictSetBuilder(32, 3,beginCell().storeInt(1, 32));
dict~uDictSetBuilderIfExists(32, 3,beginCell().storeInt(1, 32));
var len3 = calculateDictLen(dict);
var (delK1, _, _) = dict~uDictDeleteFirstAndGet(32);
var (delK2, _, _) = dict~uDictDeleteFirstAndGet(32);
var (delK3, _, _) = dict~uDictDeleteFirstAndGet(32);
return (len1, len2, len3, delK1, delK2, delK3);
}
@method_id(104)
fun test104() {
var dict = createEmptyDict();
dict~sDictSetBuilder(32, "7800", beginCell().storeUint(5 + 48, 8).storeUint(6 + 48, 8));
dict~sDictSet(32, "key1", "12");
var (old1, _) = dict~sDictSetAndGet(32, "key1", "34");
var (old2, _) = dict~sDictDeleteAndGet(32, "key1");
var (restK, restV, _) = dict.sDictGetFirst(32);
var (restK1, restV1, _) = dict~sDictDeleteLastAndGet(32);
assert (restK.isSliceBitsEqual(restK1)) throw 123;
assert (restV.isSliceBitsEqual(restV1)) throw 123;
return (
old1~loadTwoDigitNumberFromSlice(),
old2~loadTwoDigitNumberFromSlice(),
restV~loadTwoDigitNumberFromSlice(),
restK~loadTwoDigitNumberFromSlice(),
restK~loadTwoDigitNumberFromSlice()
);
}
fun main() {}
/**
@testcase | 101 | 1 1 1 | 1 2 3
@testcase | 101 | 1 2 1 | 1 -1 2
@testcase | 101 | 1 2 3 | 1 -1 -1
@testcase | 102 | | [ [ 4 104 ] [ 3 103 ] [ 2 102 ] [ 1 101 ] ]
@testcase | 103 | | 1 1 2 1 3 (null)
@testcase | 104 | | 12 34 56 78 0
*/

View file

@ -0,0 +1,21 @@
fun prepareDict_3_30_4_40_5_x(valueAt5: int): cell {
var dict: cell = createEmptyDict();
dict~idict_set_builder(32, 3, begin_cell().store_int(30, 32));
dict~idict_set_builder(32, 4, begin_cell().store_int(40, 32));
dict~idict_set_builder(32, 5, begin_cell().store_int(valueAt5, 32));
return dict;
}
fun lookupIdxByValue(idict32: cell, value: int): int {
var cur_key = -1;
do {
var (cur_key redef, cs: slice, found: int) = idict32.idict_get_next?(32, cur_key);
// one-line condition (via &) doesn't work, since right side is calculated immediately
if (found) {
if (cs~load_int(32) == value) {
return cur_key;
}
}
} while (found);
return -1;
}

View file

@ -0,0 +1,23 @@
import "@stdlib/tvm-dicts"
fun prepareDict_3_30_4_40_5_x(valueAt5: int): cell {
var dict: cell = createEmptyDict();
dict~iDictSetBuilder(32, 3, beginCell().storeInt(30, 32));
dict~iDictSetBuilder(32, 4, beginCell().storeInt(40, 32));
dict~iDictSetBuilder(32, 5, beginCell().storeInt(valueAt5, 32));
return dict;
}
fun lookupIdxByValue(idict32: cell, value: int): int {
var cur_key = -1;
do {
var (cur_key redef, cs: slice, found: int) = idict32.iDictGetNext(32, cur_key);
// one-line condition (via &) doesn't work, since right side is calculated immediately
if (found) {
if (cs~loadInt(32) == value) {
return cur_key;
}
}
} while (found);
return -1;
}

View file

@ -4,6 +4,8 @@
/**
@compilation_should_fail
@stderr invalid-import.tolk:2:7: error: Failed to import: cannot find file
On Linux/Mac, `realpath()` returns an error, and the error message is `cannot find file`
On Windows, it fails after, on reading, with a message "cannot open file"
@stderr invalid-import.tolk:2:7: error: Failed to import: cannot
@stderr import "unexisting.tolk";
*/

View file

@ -0,0 +1,9 @@
import "@stdlib/tvm-dicts"
import "imports/use-dicts-err.tolk"
/**
@compilation_should_fail
@stderr imports/use-dicts-err.tolk:2:22
@stderr Using a non-imported symbol `createEmptyDict`
@stderr Forgot to import "@stdlib/tvm-dicts"?
*/

View file

@ -2,7 +2,7 @@ global g: int;
@pure
fun f_pure(): builder {
var b: builder = begin_cell();
var b: builder = beginCell();
g = g + 1;
return b;
}

View file

@ -1,12 +1,12 @@
@pure
fun validate_input(input: cell): (int, int) {
var (x, y, z, correct) = compute_data_size?(input, 10);
var (x, y, z, correct) = calculateCellSize(input, 10);
assert(correct) throw 102;
}
@pure
fun someF(): int {
var c: cell = begin_cell().end_cell();
var c: cell = beginCell().endCell();
validate_input(c);
return 0;
}

View file

@ -1,7 +1,7 @@
global moddiv: int;
global mulDivMod: int;
/**
@compilation_should_fail
@stderr global moddiv: int;
@stderr global mulDivMod: int;
@stderr redefinition of built-in symbol
*/

View file

@ -4,11 +4,11 @@ fun main(x: int): int {
} else {
var y: slice = "20";
}
~dump(y);
debugPrint(y);
}
/**
@compilation_should_fail
@stderr ~dump(y);
@stderr debugPrint(y);
@stderr undefined symbol `y`
*/

View file

@ -1,3 +1,5 @@
import "imports/use-dicts.tolk"
fun simpleAllConst() {
return (!0, !!0 & !false, !!!0, !1, !!1, !-1, !!-1, (!5 == 0) == !0, !0 == true);
}
@ -43,29 +45,10 @@ fun someSum(upto: int) {
return x;
}
fun lookupIdxByValue(idict32: cell, value: int) {
var cur_key = -1;
do {
var (cur_key redef, cs: slice, found: int) = idict32.idict_get_next?(32, cur_key);
// todo one-line condition (via &) doesn't work, since right side is calculated immediately
if (found) {
if (cs~load_int(32) == value) {
return cur_key;
}
}
} while (found);
return -1;
}
@method_id(104)
fun testDict(last: int) {
// prepare dict: [3 => 30, 4 => 40, 5 => 50]
var dict: cell = new_dict();
dict~idict_set_builder(32, 3, begin_cell().store_int(30, 32));
dict~idict_set_builder(32, 4, begin_cell().store_int(40, 32));
dict~idict_set_builder(32, 5, begin_cell().store_int(!last ? 100 : last, 32));
// 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));
}

View file

@ -50,14 +50,14 @@ fun add3(a: int, b: int, c: int) { return a+b+c; }
}
fun `load:u32`(cs: slice): (slice, int) {
return cs.load_uint(32);
return cs.loadUint(32);
}
@method_id(116) fun `call_~_via_backticks`():[int,int,int,int] {
var b:builder = begin_cell().store_uint(1, 32).store_uint(2, 32).store_uint(3, 32).store_uint(4, 32);
var `cs`:slice = b.end_cell().begin_parse();
var (`cs` redef,one:int) = `cs`.`load_uint`(32);
var (two:int,three:int) = (`cs`~`load_uint`(32), cs~`load:u32`());
var b:builder = beginCell().storeUint(1, 32).storeUint(2, 32).storeUint(3, 32).storeUint(4, 32);
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`();
return [one,two,three,four];
}

View file

@ -1,18 +1,19 @@
import "../../crypto/smartcont/stdlib.tolk"
import "@stdlib/lisp-lists"
@method_id(101)
fun test1() {
var numbers: tuple = null;
numbers = cons(1, numbers);
numbers = cons(2, numbers);
numbers = cons(3, numbers);
numbers = cons(4, numbers);
var (h, numbers redef) = uncons(numbers);
h += car(numbers);
var numbers: tuple = createEmptyList();
numbers = listPrepend(1, numbers);
numbers = listPrepend(2, numbers);
numbers = listPrepend(3, numbers);
numbers = listPrepend(4, numbers);
var (h, numbers redef) = listSplit(numbers);
h += listGetHead(numbers);
var t = empty_tuple();
var t = createEmptyTuple();
do {
var num = numbers~list_next();
t~tpush(num);
var num = numbers~listNext();
t~tuplePush(num);
} while (numbers != null);
return (h, numbers == null, t);
@ -52,7 +53,7 @@ fun getUntypedNull() {
@method_id(104)
fun test4() {
var (_, (_, untyped)) = (3, (empty_tuple, null));
var (_, (_, untyped)) = (3, (createEmptyTuple, null));
if (true) {
return untyped;
}
@ -62,7 +63,7 @@ fun test4() {
@method_id(105)
fun test5() {
var n = getUntypedNull();
return !(null == n) ? n~load_int(32) : 100;
return !(null == n) ? n~loadInt(32) : 100;
}
@method_id(106)
@ -72,9 +73,9 @@ fun test6(x: int) {
@method_id(107)
fun test7() {
var b = begin_cell().store_maybe_ref(null);
var s = b.end_cell().begin_parse();
var c = s~load_maybe_ref();
var b = beginCell().storeMaybeRef(null);
var s = b.endCell().beginParse();
var c = s~loadMaybeRef();
return (null == c) * 10 + (b != null);
}

View file

@ -11,16 +11,16 @@ fun f_pure2(): int {
@pure
fun get_contract_data(): (int, int) {
var c: cell = get_data();
var cs: slice = c.begin_parse();
cs~load_bits(32);
var value: int = cs~load_uint(16);
var c: cell = getContractData();
var cs: slice = c.beginParse();
cs~loadBits(32);
var value: int = cs~loadUint(16);
return (1, value);
}
fun save_contract_data(value: int) {
var b: builder = begin_cell().store_int(1, 32).store_uint(value, 16);
set_data(b.end_cell());
var b: builder = beginCell().storeInt(1, 32).storeUint(value, 16);
setContractData(b.endCell());
}
@pure

View file

@ -43,10 +43,10 @@ fun main() {
var i_mini: int = string_minihash();
var i_maxi: int = string_maxihash();
var i_crc: int = string_crc32();
assert(sdeq(s_ascii, newc().store_uint(0x737472696E67, 12 * 4).endcs())) throw 101;
assert(sdeq(s_raw, newc().store_uint(0xABCDEF, 6 * 4).endcs())) throw 102;
assert(sdeq(s_addr, newc().store_uint(4, 3).store_int(-1, 8)
.store_uint(0x3333333333333333333333333333333333333333333333333333333333333333, 256).endcs()), 103);
assert(sdeq(s_ascii, newc().storeUint(0x737472696E67, 12 * 4).endcs())) throw 101;
assert(sdeq(s_raw, newc().storeUint(0xABCDEF, 6 * 4).endcs())) throw 102;
assert(sdeq(s_addr, newc().storeUint(4, 3).storeInt(-1, 8)
.storeUint(0x3333333333333333333333333333333333333333333333333333333333333333, 256).endcs()), 103);
assert(i_hex == 0x4142434445464748494A4B4C4D4E4F505152535455565758595A303132333435) throw 104;
assert(i_mini == 0x7a62e8a8) throw 105;
assert(i_maxi == 0x7a62e8a8ebac41bd6de16c65e7be363bc2d2cbc6a0873778dead4795c13db979) throw 106;

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
fun main(): int {
var c: cell = my_begin_cell().store_int(demo_10, 32).my_end_cell();
var c: cell = my_begin_cell().storeInt(demo_10, 32).my_end_cell();
var cs: slice = my_begin_parse(c);
var ten: int = cs~load_int(32);
var ten: int = cs~loadInt(32);
return 1 + demo1(ten) + demo_var;
}

View file

@ -1,6 +1,6 @@
@method_id(101)
fun test1(cs: slice) {
return cs~load_uint(8)+cs~load_uint(8)+cs~load_uint(8)+cs~load_uint(8);
return cs~loadUint(8)+cs~loadUint(8)+cs~loadUint(8)+cs~loadUint(8);
}
@method_id(102)
@ -12,15 +12,15 @@ fun test2(cs: slice) {
}
fun main(cs: slice) {
return (cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8));
return (cs~loadUint(8), cs~loadUint(8), cs~loadUint(8), cs~loadUint(8));
}
fun f(cs: slice) {
return (cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8),
cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8),
cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8),
cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8),
cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8));
return (cs~loadUint(8), cs~loadUint(8), cs~loadUint(8), cs~loadUint(8),
cs~loadUint(8), cs~loadUint(8), cs~loadUint(8), cs~loadUint(8),
cs~loadUint(8), cs~loadUint(8), cs~loadUint(8), cs~loadUint(8),
cs~loadUint(8), cs~loadUint(8), cs~loadUint(8), cs~loadUint(8),
cs~loadUint(8), cs~loadUint(8), cs~loadUint(8), cs~loadUint(8));
}

View file

@ -27,6 +27,7 @@ const TOLKFIFTLIB_MODULE = getenv('TOLKFIFTLIB_MODULE')
const TOLKFIFTLIB_WASM = getenv('TOLKFIFTLIB_WASM')
const FIFT_EXECUTABLE = getenv('FIFT_EXECUTABLE')
const FIFT_LIBS_FOLDER = getenv('FIFTPATH') // this env is needed for fift to work properly
const STDLIB_FOLDER = __dirname + '/../crypto/smartcont/tolk-stdlib'
const TMP_DIR = os.tmpdir()
class CmdLineOptions {
@ -475,25 +476,33 @@ function copyToCStringPtr(mod, str, ptr) {
return allocated;
}
/** @return {string} */
function copyFromCString(mod, ptr) {
return mod.UTF8ToString(ptr);
}
/** @return {{status: string, message: string, fiftCode: string, codeBoc: string, codeHashHex: string}} */
function compileFile(mod, filename, experimentalOptions) {
// see tolk-wasm.cpp: typedef void (*CStyleReadFileCallback)(int, char const*, char**, char**)
// see tolk-wasm.cpp: typedef void (*WasmFsReadCallback)(int, char const*, char**, char**)
const callbackPtr = mod.addFunction((kind, dataPtr, destContents, destError) => {
if (kind === 0) { // realpath
try {
const relativeFilename = copyFromCString(mod, dataPtr)
copyToCStringPtr(mod, fs.realpathSync(relativeFilename), destContents);
let relative = copyFromCString(mod, dataPtr)
if (relative.startsWith('@stdlib/')) {
// import "@stdlib/filename" or import "@stdlib/filename.tolk"
relative = STDLIB_FOLDER + '/' + relative.substring(7)
if (!relative.endsWith('.tolk')) {
relative += '.tolk'
}
}
copyToCStringPtr(mod, fs.realpathSync(relative), destContents);
} catch (err) {
copyToCStringPtr(mod, 'cannot find file', destError);
}
} else if (kind === 1) { // read file
try {
const filename = copyFromCString(mod, dataPtr) // already normalized (as returned above)
copyToCStringPtr(mod, fs.readFileSync(filename).toString('utf-8'), destContents);
const absolute = copyFromCString(mod, dataPtr) // already normalized (as returned above)
copyToCStringPtr(mod, fs.readFileSync(absolute).toString('utf-8'), destContents);
} catch (err) {
copyToCStringPtr(mod, err.message || err.toString(), destError);
}
@ -506,7 +515,6 @@ function compileFile(mod, filename, experimentalOptions) {
optimizationLevel: 2,
withStackComments: true,
experimentalOptions: experimentalOptions || undefined,
stdlibLocation: __dirname + '/../crypto/smartcont/stdlib.tolk',
entrypointFileName: filename
};