1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-15 04:32:21 +00:00
ton/tolk-tester/tests/mutate-methods.tolk
tolk-vm 3540424aa1
[Tolk] AST-based semantic analysis, get rid of Expr
This is a huge refactoring focusing on untangling compiler internals
(previously forked from FunC).
The goal is to convert AST directly to Op (a kind of IR representation),
doing all code analysis at AST level.

Noteable changes:
- AST-based semantic kernel includes: registering global symbols,
  scope handling and resolving local/global identifiers,
  lvalue/rvalue calc and check, implicit return detection,
  mutability analysis, pure/impure validity checks,
  simple constant folding
- values of `const` variables are calculated NOT based on CodeBlob,
  but via a newly-introduced AST-based constant evaluator
- AST vertices are now inherited from expression/statement/other;
  expression vertices have common properties (TypeExpr, lvalue/rvalue)
- symbol table is rewritten completely, SymDef/SymVal no longer exist,
  lexer now doesn't need to register identifiers
- AST vertices have references to symbols, filled at different
  stages of pipeline
- the remaining "FunC legacy part" is almost unchanged besides Expr
  which was fully dropped; AST is converted to Ops (IR) directly
2025-01-13 20:28:44 +07:00

344 lines
7.9 KiB
Text

fun incrementInPlace(mutate self: int, byValue: int): void {
self = self + byValue;
}
fun incrementTwoInPlace(mutate self: int, mutate y: int, byValue: int): int {
self.incrementInPlace(byValue);
y += byValue;
return self + y;
}
@method_id(101)
fun testIncrement1() {
var x = 50;
var y = 30;
incrementInPlace(mutate x, 10);
incrementInPlace(mutate x, 10);
incrementInPlace(mutate y, 10);
y.incrementInPlace(10);
incrementInPlace(mutate y, 10);
return (x, y);
}
@method_id(102)
fun testIncrement2() {
var x = 50;
var y = 30;
val sum1 = incrementTwoInPlace(mutate x, mutate y, 10);
val sum2 = x.incrementTwoInPlace(mutate y, 10);
return (x, y, sum1, sum2);
}
fun load_next(mutate cs: slice): int {
return loadInt(mutate cs, 32);
}
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";
@inline_ref
fun unpack_utils_info(mutate utils_info_sl: slice): (int, int) {
return (
utils_info_sl.myLoadInt(32),
utils_info_sl.myLoadInt(32)
);
}
@method_id(103)
fun testSlices1() {
var b: builder = beginCell().storeInt(1, 32).myStoreInt(2, 32);
b.myStoreInt(3, 32);
var c: cell = b.myStoreInt(4, 32).storeInt(5, 32).endCell();
var cs = c.beginParse();
var first = cs.preloadInt(32);
unpack_utils_info(mutate cs);
return (first, cs.myLoadInt(32), cs.loadInt(32));
}
fun load_decimal_symbol(mutate self: slice): int {
// load decimal from bits using utf-8 table
var n: int = self.loadUint(8);
n = n - 48;
assert(n >= 0) throw 400;
assert(n <= 9) throw 400;
return n;
}
@method_id(104)
fun testSlices2() {
var cs = "123";
return (cs.load_decimal_symbol(), cs.load_decimal_symbol(), cs.load_decimal_symbol());
}
global v1: int;
global v2: int;
global v3: int;
@method_id(105)
fun testGlobals() {
v1 = 0;
v2 = 0;
v3 = 100;
v3 += incrementTwoInPlace(mutate v1, mutate v2, 5);
return (v1, v2, v3);
}
fun withNameShadowing(mutate x: int, pivot: int, extra: int) {
x += pivot;
if (pivot < 100) {
var x = 100 + extra;
if (pivot < 50) {
var x = 50 + extra;
return x + extra;
} else {
x += extra;
return x + extra;
}
} else {
x += extra;
return -100 + extra;
}
}
@method_id(106)
fun testNameShadowing() {
var x = 0;
var sum = 0;
sum += withNameShadowing(mutate x, 100, 10);
sum += withNameShadowing(mutate x, 50, 10);
sum += withNameShadowing(mutate x, 0, 10);
return (x, sum);
}
fun updateTwoItems(mutate self: (int, int), byValue: int) {
val (first, second) = self;
self = (first + byValue, second + byValue);
}
global t107_1: int;
global t107_2: int;
@method_id(107)
fun testMutableTensor() {
var t = (40, 50);
t.updateTwoItems(10);
updateTwoItems(mutate t, 10);
t107_1 = 1;
t107_2 = 2;
(t107_1, t107_2).updateTwoItems(10);
updateTwoItems(mutate (t107_1, t107_2), 10);
return (t, t107_1, t107_2);
}
@pure
fun myStoreUint(mutate self: builder, x: int, len: int): self
asm(x self len) "STIX";
@pure
fun myStoreU32(mutate self: builder, x: int): self {
return self.storeUint(x, 32);
}
fun getSumOfNumbersInCell(c: cell): int {
var sum = 0;
var s = c.beginParse();
var n_numbers = s.getRemainingBitsCount() / 32;
repeat (n_numbers) {
sum += s.loadUint(32);
}
return sum;
}
@method_id(110)
fun testStoreChaining() {
var b = beginCell().storeUint(1, 32).storeUint(2, 32).storeUint(3, 32);
b.storeUint(4, 32);
b.myStoreUint(5, 32).storeUint(6, 32);
storeUint(mutate b, 7, 32);
b = b.storeUint(8, 32);
b = b.storeUint(9, 32).storeUint(10, 32);
return getBuilderBitsCount(b);
}
@method_id(111)
fun testStoreChainingCustom() {
var b = beginCell().myStoreUint(1, 32).myStoreUint(2, 32).myStoreUint(3, 32);
b.myStoreUint(4, 32);
b.myStoreUint(5, 32).myStoreUint(6, 32);
myStoreUint(mutate b, 7, 32);
b = b.myStoreUint(8, 32);
b = b.myStoreUint(9, 32).myStoreUint(10, 32);
val sum1 = getSumOfNumbersInCell(b.endCell());
b = beginCell().myStoreU32(1).storeUint(2, 32).myStoreU32(3);
b.myStoreU32(4);
b.myStoreU32(5).myStoreU32(6);
myStoreU32(mutate b, 7);
b = b.myStoreU32(8);
b = b.storeUint(9, 32).myStoreU32(10);
val sum2 = getSumOfNumbersInCell(b.endCell());
return (sum1, sum2);
}
fun myStoreU32_and_mutate_x(mutate self: builder, mutate x: int): void {
return myStoreUint(mutate self, x += 10, 32);
}
@method_id(112)
fun testStoreAndMutateBoth() {
var x = 3;
var b: builder = beginCell().myStoreUint(1, 32);
b.myStoreU32_and_mutate_x(mutate x);
b.myStoreU32(3).myStoreU32_and_mutate_x(mutate x);
b.myStoreU32_and_mutate_x(mutate x);
var cs: slice = b.endCell().beginParse();
var (n1,n2,n3,n4,n5) = (cs.loadUint(32),cs.loadUint(32),cs.loadUint(32),cs.loadUint(32),cs.loadUint(32));
assert(n5 == x) throw 100;
return [n1,n2,n3,n4,n5];
}
global ccc: builder;
@method_id(113)
fun testStoreChainingForGlobal() {
ccc = beginCell().storeUint(1, 32).myStoreUint(2, 32).myStoreU32(3);
ccc.storeUint(4, 32);
ccc.storeUint(5, 32).myStoreU32(6);
storeUint(mutate ccc, 7, 32);
ccc = ccc.myStoreU32(8);
ccc = ccc.storeUint(9, 32).myStoreUint(10, 32);
return getBuilderBitsCount(ccc);
}
fun alwaysThrows(): int { throw 123; return 123; }
fun loadIntFromCell(c: cell, len: int) { return c.beginParse().loadUint(len); }
@method_id(114)
fun testLoadIntForTemporaryObject() {
val c0 = beginCell().storeUint(0, 32).endCell();
val c4 = beginCell().storeUint(4, 32).endCell();
return (
beginCell().storeUint(1, 32).endCell().beginParse().loadUint(32),
beginCell().storeUint(2, 32).endCell().beginParse().loadUint(32),
c0.beginParse().loadUint(32) ? alwaysThrows() : loadIntFromCell(c4, 32)
);
}
@pure
fun myStoreUint_pure(mutate self: builder): void
asm "STIX";
fun myStoreUint_impure(mutate self: builder): void
asm "STIX";
fun testStoreUintPureUnusedResult() {
var b = beginCell();
b.myStoreUint_pure();
var s = b.endCell().beginParse();
val ii = s.loadUint(32);
return 0;
}
fun testStoreUintImpureUnusedResult() {
var b = beginCell();
b.myStoreUint_impure();
var s = b.endCell().beginParse();
val ii = s.loadUint(32);
return 0;
}
global counter: int;
fun writeNext2(mutate self: builder): self {
return self.storeUint(counter += 1, 32).storeUint(counter += 1, 32);
}
fun resetCounter(mutate self: builder): self {
counter = 0;
return self;
}
@method_id(115)
fun testExplicitReturn() {
counter = 0;
return (
beginCell().writeNext2().writeNext2().resetCounter().writeNext2().endCell().getSumOfNumbersInCell(),
counter
);
}
fun main(){}
/**
@testcase | 101 | | 70 60
@testcase | 102 | | 70 50 100 120
@testcase | 103 | | 1 3 4
@testcase | 104 | | 1 2 3
@testcase | 105 | | 5 5 110
@testcase | 106 | | 160 110
@testcase | 107 | | 60 70 21 22
@testcase | 110 | | 320
@testcase | 111 | | 55 55
@testcase | 112 | | [ 1 13 3 23 33 ]
@testcase | 113 | | 320
@testcase | 114 | | 1 2 4
@testcase | 115 | | 13 2
@fif_codegen
"""
incrementInPlace PROC:<{
// self byValue
ADD // self
}>
"""
@fif_codegen
"""
testIncrement2 PROC:<{
...
incrementTwoInPlace CALLDICT // x y sum1
-ROT
10 PUSHINT // sum1 x y _8=10
incrementTwoInPlace CALLDICT // sum1 x y sum2
s1 s3 s0 XCHG3 // x y sum1 sum2
}>
"""
@fif_codegen
"""
load_next PROC:<{
// cs
32 LDI // _3 cs
SWAP // cs _3
}>
"""
@fif_codegen
"""
testStoreUintPureUnusedResult PROC:<{
//
0 PUSHINT // _11=0
}>
"""
@fif_codegen
"""
testStoreUintImpureUnusedResult PROC:<{
//
NEWC // b
STIX // _2
DROP //
0 PUSHINT // _11=0
}>
"""
*/